Skip to content

Commit c65c5aa

Browse files
committed
trigger PUP scenes from outside
1 parent f43423c commit c65c5aa

File tree

5 files changed

+105
-41
lines changed

5 files changed

+105
-41
lines changed

include/DMDUtil/DMD.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class PixelcadeDMD;
6868
class LevelDMD;
6969
class RGB24DMD;
7070
class ConsoleDMD;
71-
71+
class SceneGenerator;
7272
class DMDServerConnector;
7373

7474
class DMDUTILAPI DMD
@@ -152,6 +152,13 @@ class DMDUTILAPI DMD
152152
void convertToHostByteOrder() {}
153153
void convertToNetworkByteOrder() {}
154154
};
155+
156+
struct PUPTrigger
157+
{
158+
char source = 0;
159+
uint16_t id = 0;
160+
uint8_t value = 1;
161+
};
155162
#pragma pack(pop) // Reset to default packing
156163

157164
void FindDisplays();
@@ -161,6 +168,7 @@ class DMDUTILAPI DMD
161168
void SetRomName(const char* name);
162169
void SetAltColorPath(const char* path);
163170
void SetPUPVideosPath(const char* path);
171+
void SetPUPTrigger(const char source, const uint16_t id, const uint8_t value = 1);
164172
void DumpDMDTxt();
165173
void DumpDMDRaw();
166174
LevelDMD* CreateLevelDMD(uint16_t width, uint16_t height, bool sam);
@@ -213,6 +221,7 @@ class DMDUTILAPI DMD
213221
SerumFrameStruct* m_pSerum;
214222
ZeDMD* m_pZeDMD;
215223
PUPDMD::DMD* m_pPUPDMD;
224+
SceneGenerator* m_pGenerator;
216225
std::vector<LevelDMD*> m_levelDMDs;
217226
std::vector<RGB24DMD*> m_rgb24DMDs;
218227
std::vector<ConsoleDMD*> m_consoleDMDs;
@@ -233,6 +242,7 @@ class DMDUTILAPI DMD
233242
std::atomic<bool> m_dmdFrameReady;
234243
std::atomic<bool> m_stopFlag;
235244
std::atomic<uint8_t> m_updateBufferQueuePosition;
245+
std::atomic<PUPTrigger> m_pupTrigger;
236246

237247
bool m_hasUpdateBuffered = false;
238248
static bool m_finding;

include/DMDUtil/SceneGenerator.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ namespace DMDUtil
1717

1818
struct SceneData
1919
{
20+
char source;
2021
int sceneId;
22+
int value;
2123
int frameCount;
2224
int durationPerFrame;
2325
bool interruptable = false;
@@ -39,8 +41,9 @@ class DMDUTILAPI SceneGenerator
3941

4042
bool parseCSV(const std::string& csv_filename);
4143
bool generateDump(const std::string& dump_filename, int id = -1);
42-
bool getSceneInfo(int sceneId, int& frameCount, int& durationPerFrame, bool& interruptable, bool& startImmediately,
43-
int& repeat, int& endFrame) const;
44+
bool getSceneExists(char source, int sceneId, int value) const;
45+
bool getSceneInfo(char source, int sceneId, int value, int& frameCount, int& durationPerFrame, bool& interruptable,
46+
bool& startImmediately, int& repeat, int& endFrame) const;
4447
bool generateFrame(int sceneId, int frameIndex, uint8_t* buffer, int group = -1);
4548
void setDepth(int depth);
4649
void Reset()

scene_test.csv

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
# Format of a PUP scene line:
22
#
3-
# 1: PUP trigger ID,
4-
# 2: number of frames,
5-
# 3: duration of each frame,
6-
# 4: 0 - not interruptable, 1 - interruptable by frame match or PUP trigger
7-
# 5: 0 - start immediately, replacing triggering frame, 1 - start after frame duration (see 3)
8-
# 6: 0 - play once, 1 - loop, >= 2 - repeat x times
9-
# 7: 0 - no frame groups, >= 2 - create x frame groups (you get x times the number of frames entered in 2 to play changing scenes)
10-
# 8: 0 - play frame group in order, 1 - play random frame group
11-
# 9: 0 - no autostart, >= 1 - start this scene after x seconds of inactivity (no new frames), only use once, could be combined with frame groups
12-
# 10: 0 - when scene is finished, show last frame of the scene until a new frame is matched, 1 - black screen, 2 - show last frame before scene started
3+
# 1: PUP trigger source (D - DMD, W - Switch, S - Solenoid, L - Light),
4+
# 2: PUP trigger ID,
5+
# 3: PUP trigger value,
6+
# 4: number of frames,
7+
# 5: duration of each frame,
8+
# 6: 0 - not interruptable, 1 - interruptable by frame match or PUP trigger
9+
# 7: 0 - start immediately, replacing triggering frame, 1 - start after frame duration (see 5)
10+
# 8: 0 - play once, 1 - loop, >= 2 - repeat x times
11+
# 9: 0 - no frame groups, >= 2 - create x frame groups (you get x times the number of frames entered in 2 to play changing scenes)
12+
# 10: 0 - play frame group in order, 1 - play random frame group
13+
# 11: 0 - no autostart, >= 1 - start this scene after x seconds of inactivity (no new frames), only use once, could be combined with frame groups
14+
# 12: 0 - when scene is finished, show last frame of the scene until a new frame is matched, 1 - black screen, 2 - show last frame before scene started
1315
#
1416
# Postions 4 - 10 are optional. If not provided, the default is 0.
1517

1618
# Scene 60001
17-
60001,38,16
19+
D,60001,1,38,16
1820

1921
# Scene 61479, interruptable
20-
61479,52,20,1
22+
D,61479,1,52,20,1
2123

2224
# Scene 63500, interruptable, starting delayed by frame duration, loop
23-
63500,40,20,1,1,1
25+
D,63500,1,40,20,1,1,1
2426

2527
# Scene 63511, interruptable, starting delayed by frame duration, play once, 3 frame groups
2628
# This will generate 3 groups of 75 frames, so 225 frames in total.
2729
# Every time the PUP ID 63511 get triggered, only one of the three groups gets played (75 frames).
2830
# First occurrence of the PUP ID will play group 1, the second group 2. After the third group, it will start again with group 1.
29-
63511,75,20,1,1,0,3
31+
D,63511,1,75,20,1,1,0,3
3032

3133
# This will generate 4 groups of 200 frames, so 800 frames in total.
3234
# If no frame is matched for 5 seconds, randomly one of the 4 groups gets played once.
@@ -37,4 +39,4 @@
3739
# Normally, the last scores are shown until someone starts a new game.
3840
# Now the scores are displayed for 5 seconds, than a random short video scene out of four gets played for 4 seconds.
3941
# Then the scores are shown again and so on until someone starts a game.
40-
63600,200,20,1,1,0,4,1,5,2
42+
D,63600,1,200,20,1,1,0,4,1,5,2

src/DMD.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ DMD::DMD()
146146
m_updateBuffered = std::make_shared<Update>();
147147

148148
m_pAlphaNumeric = new AlphaNumeric();
149+
m_pGenerator = new SceneGenerator();
149150
m_pSerum = nullptr;
150151
m_pZeDMD = nullptr;
151152
m_pPUPDMD = nullptr;
@@ -247,6 +248,7 @@ DMD::~DMD()
247248
}
248249
#endif
249250
delete m_pAlphaNumeric;
251+
delete m_pGenerator;
250252
delete m_pZeDMD;
251253
delete m_pPUPDMD;
252254
#if !( \
@@ -873,7 +875,6 @@ void DMD::SerumThread()
873875
bool showNotColorizedFrames = pConfig->IsShowNotColorizedFrames();
874876
bool dumpNotColorizedFrames = pConfig->IsDumpNotColorizedFrames();
875877

876-
SceneGenerator generator;
877878
int sceneFrameCount = 0;
878879
int sceneCurrentFrame = 0;
879880
int sceneDurationPerFrame = 0;
@@ -895,7 +896,28 @@ void DMD::SerumThread()
895896
}
896897
else
897898
{
898-
std::this_thread::sleep_for(std::chrono::milliseconds(2));
899+
PUPTrigger pupTrigger = m_pupTrigger.load(std::memory_order_relaxed);
900+
if (pupTrigger.source != 0)
901+
{
902+
if (m_pGenerator->getSceneInfo(pupTrigger.source, pupTrigger.id, pupTrigger.value, sceneFrameCount,
903+
sceneDurationPerFrame, sceneInterruptable, sceneStartImmediately,
904+
sceneRepeatCount, sceneEndFrame))
905+
{
906+
Log(DMDUtil_LogLevel_DEBUG, "Serum: trigger ID %lu found in scenes, frame count=%d, duration=%dms",
907+
pupTrigger.id, sceneFrameCount, sceneDurationPerFrame);
908+
sceneCurrentFrame = 0;
909+
nextSceneFrame = std::chrono::duration_cast<std::chrono::milliseconds>(
910+
std::chrono::system_clock::now().time_since_epoch())
911+
.count() +
912+
(sceneStartImmediately ? 0 : sceneDurationPerFrame);
913+
}
914+
pupTrigger.source = 0; // Reset the trigger after processing
915+
m_pupTrigger.store(pupTrigger, std::memory_order_release);
916+
}
917+
else
918+
{
919+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
920+
}
899921
}
900922

901923
if (m_stopFlag.load(std::memory_order_acquire))
@@ -923,7 +945,7 @@ void DMD::SerumThread()
923945
sceneUpdate->r = 0;
924946
sceneUpdate->g = 0;
925947
sceneUpdate->b = 0;
926-
if (generator.generateFrame(prevTriggerId, sceneCurrentFrame++, sceneUpdate->data))
948+
if (m_pGenerator->generateFrame(prevTriggerId, sceneCurrentFrame++, sceneUpdate->data))
927949
{
928950
uint32_t result = Serum_Colorize(sceneUpdate->data);
929951

@@ -994,7 +1016,7 @@ void DMD::SerumThread()
9941016
Serum_Dispose();
9951017
m_pSerum = nullptr;
9961018
lastDmdUpdate = nullptr;
997-
generator.Reset();
1019+
m_pGenerator->Reset();
9981020
sceneFrameCount = 0;
9991021
}
10001022

@@ -1020,9 +1042,9 @@ void DMD::SerumThread()
10201042
}
10211043
Log(DMDUtil_LogLevel_INFO, "Check for PUP scenes for %s at %s", m_romName, csvPath);
10221044

1023-
if (generator.parseCSV(csvPath))
1045+
if (m_pGenerator->parseCSV(csvPath))
10241046
{
1025-
generator.setDepth(m_pUpdateBufferQueue[bufferPosition]->depth);
1047+
m_pGenerator->setDepth(m_pUpdateBufferQueue[bufferPosition]->depth);
10261048
Log(DMDUtil_LogLevel_INFO, "Loaded PUP scenes for %s, bit depth %d", m_romName,
10271049
m_pUpdateBufferQueue[bufferPosition]->depth);
10281050
}
@@ -1047,13 +1069,13 @@ void DMD::SerumThread()
10471069

10481070
if (m_pSerum->triggerID < 0xffffffff)
10491071
{
1050-
if (generator.getSceneInfo(m_pSerum->triggerID, sceneFrameCount, sceneDurationPerFrame,
1051-
sceneInterruptable, sceneStartImmediately, sceneRepeatCount, sceneEndFrame))
1072+
if (m_pGenerator->getSceneInfo('D', m_pSerum->triggerID, 1, sceneFrameCount, sceneDurationPerFrame,
1073+
sceneInterruptable, sceneStartImmediately, sceneRepeatCount,
1074+
sceneEndFrame))
10521075
{
10531076
Log(DMDUtil_LogLevel_DEBUG, "Serum: trigger ID %lu found in scenes, frame count=%d, duration=%dms",
10541077
m_pSerum->triggerID, sceneFrameCount, sceneDurationPerFrame);
10551078
sceneCurrentFrame = 0;
1056-
nextSceneFrame = now + (sceneStartImmediately ? 0 : sceneDurationPerFrame);
10571079
if (sceneStartImmediately)
10581080
{
10591081
nextSceneFrame = now;
@@ -2040,4 +2062,16 @@ void DMD::HandleTrigger(uint16_t id)
20402062
}
20412063
}
20422064

2065+
void DMD::SetPUPTrigger(const char source, const uint16_t id, const uint8_t value)
2066+
{
2067+
if (m_pSerum && m_pGenerator->getSceneExists(source, id, value))
2068+
{
2069+
while (m_pupTrigger.load(std::memory_order_acquire).source != 0)
2070+
{
2071+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2072+
}
2073+
m_pupTrigger.store({source, id, value}, std::memory_order_release);
2074+
}
2075+
}
2076+
20432077
} // namespace DMDUtil

src/SceneGenerator.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,18 @@ bool SceneGenerator::parseCSV(const std::string& csv_filename)
9494
try
9595
{
9696
SceneData data;
97-
data.sceneId = std::stoi(row[0]);
98-
data.frameCount = std::stoi(row[1]);
99-
data.durationPerFrame = std::stoi(row[2]);
100-
if (row.size() >= 4) data.interruptable = (std::stoi(row[3]) == 1);
101-
if (row.size() >= 5) data.immediateStart = (std::stoi(row[4]) == 1);
102-
if (row.size() >= 6) data.repeat = std::stoi(row[5]);
103-
if (row.size() >= 7) data.frameGroups = std::stoi(row[6]) == 0 ? 1 : std::stoi(row[6]);
104-
if (row.size() >= 8) data.random = (std::stoi(row[7]) == 1);
105-
if (row.size() >= 9) data.autoStart = std::stoi(row[8]);
106-
if (row.size() >= 10) data.endFrame = std::stoi(row[9]);
97+
data.source = row[0][0]; // First character of the first column
98+
data.sceneId = std::stoi(row[1]);
99+
data.value = std::stoi(row[2]);
100+
data.frameCount = std::stoi(row[3]);
101+
data.durationPerFrame = std::stoi(row[4]);
102+
if (row.size() >= 6) data.interruptable = (std::stoi(row[5]) == 1);
103+
if (row.size() >= 7) data.immediateStart = (std::stoi(row[6]) == 1);
104+
if (row.size() >= 8) data.repeat = std::stoi(row[7]);
105+
if (row.size() >= 9) data.frameGroups = std::stoi(row[8]) == 0 ? 1 : std::stoi(row[8]);
106+
if (row.size() >= 10) data.random = (std::stoi(row[9]) == 1);
107+
if (row.size() >= 11) data.autoStart = std::stoi(row[10]);
108+
if (row.size() >= 12) data.endFrame = std::stoi(row[11]);
107109

108110
m_sceneData.push_back(data);
109111
}
@@ -171,11 +173,24 @@ bool SceneGenerator::generateDump(const std::string& dump_filename, int id)
171173
return true;
172174
}
173175

174-
bool SceneGenerator::getSceneInfo(int sceneId, int& frameCount, int& durationPerFrame, bool& interruptable,
175-
bool& startImmediately, int& repeat, int& endFrame) const
176+
bool SceneGenerator::getSceneExists(char source, int sceneId, int value) const
176177
{
177-
auto it = std::find_if(m_sceneData.begin(), m_sceneData.end(),
178-
[sceneId](const SceneData& data) { return data.sceneId == sceneId; });
178+
auto it = std::find_if(m_sceneData.begin(), m_sceneData.end(), [source, sceneId, value](const SceneData& data)
179+
{ return data.source == source && data.sceneId == sceneId && data.value == value; });
180+
181+
if (it == m_sceneData.end())
182+
{
183+
return false;
184+
}
185+
186+
return true;
187+
}
188+
189+
bool SceneGenerator::getSceneInfo(char source, int sceneId, int value, int& frameCount, int& durationPerFrame,
190+
bool& interruptable, bool& startImmediately, int& repeat, int& endFrame) const
191+
{
192+
auto it = std::find_if(m_sceneData.begin(), m_sceneData.end(), [source, sceneId, value](const SceneData& data)
193+
{ return data.source == source && data.sceneId == sceneId && data.value == value; });
179194

180195
if (it == m_sceneData.end())
181196
{

0 commit comments

Comments
 (0)