11#include " fseq_player.h"
2- #include < Arduino.h >
2+ #include " usermod_fseq.h "
33#include " wled.h"
4+ #include < Arduino.h>
45
56#ifdef WLED_USE_SD_SPI
6- #include < SPI .h>
7- #include < SD .h>
7+ #include < SD .h>
8+ #include < SPI .h>
89#elif defined(WLED_USE_SD_MMC)
9- #include " SD_MMC.h"
10+ #include " SD_MMC.h"
11+ #endif
12+
13+ // Static member definitions moved from header to avoid multiple definition
14+ // errors
15+ const char UsermodFseq::_name[] PROGMEM = " usermod FSEQ sd card" ;
16+
17+ #ifdef WLED_USE_SD_SPI
18+ int8_t UsermodFseq::configPinSourceSelect = 5 ;
19+ int8_t UsermodFseq::configPinSourceClock = 18 ;
20+ int8_t UsermodFseq::configPinPoci = 19 ;
21+ int8_t UsermodFseq::configPinPico = 23 ;
1022#endif
1123
1224File FSEQPlayer::recordingFile;
13- uint8_t FSEQPlayer::colorChannels = 3 ;
14- int32_t FSEQPlayer::recordingRepeats = RECORDING_REPEAT_DEFAULT;
25+ String FSEQPlayer::currentFileName = " " ;
26+ float FSEQPlayer::secondsElapsed = 0 ;
27+
28+ uint8_t FSEQPlayer::colorChannels = 3 ;
29+ int32_t FSEQPlayer::recordingRepeats = RECORDING_REPEAT_DEFAULT;
1530uint32_t FSEQPlayer::now = 0 ;
1631uint32_t FSEQPlayer::next_time = 0 ;
1732uint16_t FSEQPlayer::playbackLedStart = 0 ;
@@ -22,37 +37,42 @@ FSEQPlayer::FileHeader FSEQPlayer::file_header;
2237
2338inline uint32_t FSEQPlayer::readUInt32 () {
2439 char buffer[4 ];
25- if (recordingFile.readBytes (buffer, 4 ) < 4 ) return 0 ;
26- return (uint32_t )buffer[0 ] | ((uint32_t )buffer[1 ] << 8 ) | ((uint32_t )buffer[2 ] << 16 ) | ((uint32_t )buffer[3 ] << 24 );
40+ if (recordingFile.readBytes (buffer, 4 ) < 4 )
41+ return 0 ;
42+ return (uint32_t )buffer[0 ] | ((uint32_t )buffer[1 ] << 8 ) |
43+ ((uint32_t )buffer[2 ] << 16 ) | ((uint32_t )buffer[3 ] << 24 );
2744}
2845
2946inline uint32_t FSEQPlayer::readUInt24 () {
3047 char buffer[3 ];
31- if (recordingFile.readBytes (buffer, 3 ) < 3 ) return 0 ;
32- return (uint32_t )buffer[0 ] | ((uint32_t )buffer[1 ] << 8 ) | ((uint32_t )buffer[2 ] << 16 );
48+ if (recordingFile.readBytes (buffer, 3 ) < 3 )
49+ return 0 ;
50+ return (uint32_t )buffer[0 ] | ((uint32_t )buffer[1 ] << 8 ) |
51+ ((uint32_t )buffer[2 ] << 16 );
3352}
3453
3554inline uint16_t FSEQPlayer::readUInt16 () {
3655 char buffer[2 ];
37- if (recordingFile.readBytes (buffer, 2 ) < 2 ) return 0 ;
56+ if (recordingFile.readBytes (buffer, 2 ) < 2 )
57+ return 0 ;
3858 return (uint16_t )buffer[0 ] | ((uint16_t )buffer[1 ] << 8 );
3959}
4060
4161inline uint8_t FSEQPlayer::readUInt8 () {
4262 char buffer[1 ];
43- if (recordingFile.readBytes (buffer, 1 ) < 1 ) return 0 ;
63+ if (recordingFile.readBytes (buffer, 1 ) < 1 )
64+ return 0 ;
4465 return (uint8_t )buffer[0 ];
4566}
4667
47- bool FSEQPlayer::fileOnSD (const char * filepath) {
68+ bool FSEQPlayer::fileOnSD (const char * filepath) {
4869 uint8_t cardType = SD_ADAPTER.cardType ();
49- if (cardType == CARD_NONE) return false ;
70+ if (cardType == CARD_NONE)
71+ return false ;
5072 return SD_ADAPTER.exists (filepath);
5173}
5274
53- bool FSEQPlayer::fileOnFS (const char * filepath) {
54- return false ;
55- }
75+ bool FSEQPlayer::fileOnFS (const char *filepath) { return false ; }
5676
5777void FSEQPlayer::printHeaderInfo () {
5878 DEBUG_PRINTLN (" FSEQ file header:" );
@@ -68,18 +88,21 @@ void FSEQPlayer::printHeaderInfo() {
6888
6989void FSEQPlayer::processFrameData () {
7090 uint16_t packetLength = file_header.channel_count ;
71- uint16_t lastLed = min (playbackLedStop, uint16_t (playbackLedStart + (packetLength / 3 )));
91+ uint16_t lastLed =
92+ min (playbackLedStop, uint16_t (playbackLedStart + (packetLength / 3 )));
7293 char frame_data[buffer_size];
73- CRGB* crgb = reinterpret_cast <CRGB*>(frame_data);
94+ CRGB * crgb = reinterpret_cast <CRGB *>(frame_data);
7495 uint16_t bytes_remaining = packetLength;
7596 uint16_t index = playbackLedStart;
7697 while (index < lastLed && bytes_remaining > 0 ) {
7798 uint16_t length = min (bytes_remaining, buffer_size);
7899 recordingFile.readBytes (frame_data, length);
79100 bytes_remaining -= length;
80101 for (uint16_t offset = 0 ; offset < length / 3 ; offset++) {
81- setRealtimePixel (index, crgb[offset].r , crgb[offset].g , crgb[offset].b , 0 );
82- if (++index > lastLed) break ;
102+ setRealtimePixel (index, crgb[offset].r , crgb[offset].g , crgb[offset].b ,
103+ 0 );
104+ if (++index > lastLed)
105+ break ;
83106 }
84107 }
85108 strip.show ();
@@ -110,7 +133,8 @@ bool FSEQPlayer::stopBecauseAtTheEnd() {
110133}
111134
112135void FSEQPlayer::playNextRecordingFrame () {
113- if (stopBecauseAtTheEnd ()) return ;
136+ if (stopBecauseAtTheEnd ())
137+ return ;
114138 uint32_t offset = file_header.channel_count * frame++;
115139 offset += file_header.channel_data_offset ;
116140 if (!recordingFile.seek (offset)) {
@@ -124,12 +148,15 @@ void FSEQPlayer::playNextRecordingFrame() {
124148
125149void FSEQPlayer::handlePlayRecording () {
126150 now = millis ();
127- if (realtimeMode != REALTIME_MODE_FSEQ) return ;
128- if (now < next_time) return ;
151+ if (realtimeMode != REALTIME_MODE_FSEQ)
152+ return ;
153+ if (now < next_time)
154+ return ;
129155 playNextRecordingFrame ();
130156}
131157
132- void FSEQPlayer::loadRecording (const char * filepath, uint16_t startLed, uint16_t stopLed, float secondsElapsed) {
158+ void FSEQPlayer::loadRecording (const char *filepath, uint16_t startLed,
159+ uint16_t stopLed, float secondsElapsed) {
133160 if (recordingFile.available ()) {
134161 clearLastPlayback ();
135162 recordingFile.close ();
@@ -141,14 +168,19 @@ void FSEQPlayer::loadRecording(const char* filepath, uint16_t startLed, uint16_t
141168 playbackLedStart = sg.start ;
142169 playbackLedStop = sg.stop ;
143170 }
144- DEBUG_PRINTF (" FSEQ load animation on LED %d to %d\n " , playbackLedStart, playbackLedStop);
171+ DEBUG_PRINTF (" FSEQ load animation on LED %d to %d\n " , playbackLedStart,
172+ playbackLedStop);
145173 if (fileOnSD (filepath)) {
146174 DEBUG_PRINTF (" Read file from SD: %s\n " , filepath);
147175 recordingFile = SD_ADAPTER.open (filepath, " rb" );
176+ currentFileName = String (filepath);
177+ if (currentFileName.startsWith (" /" ))
178+ currentFileName = currentFileName.substring (1 );
148179 } else if (fileOnFS (filepath)) {
149180 DEBUG_PRINTF (" Read file from FS: %s\n " , filepath);
150181 } else {
151- DEBUG_PRINTF (" File %s not found (%s)\n " , filepath, USED_STORAGE_FILESYSTEMS);
182+ DEBUG_PRINTF (" File %s not found (%s)\n " , filepath,
183+ USED_STORAGE_FILESYSTEMS);
152184 return ;
153185 }
154186 if ((uint64_t )recordingFile.available () < sizeof (file_header)) {
@@ -170,17 +202,23 @@ void FSEQPlayer::loadRecording(const char* filepath, uint16_t startLed, uint16_t
170202 printHeaderInfo ();
171203 if (file_header.identifier [0 ] != ' P' || file_header.identifier [1 ] != ' S' ||
172204 file_header.identifier [2 ] != ' E' || file_header.identifier [3 ] != ' Q' ) {
173- DEBUG_PRINTF (" Error reading FSEQ file %s header, invalid identifier\n " , filepath);
205+ DEBUG_PRINTF (" Error reading FSEQ file %s header, invalid identifier\n " ,
206+ filepath);
174207 recordingFile.close ();
175208 return ;
176209 }
177- if (((uint64_t )file_header.channel_count * (uint64_t )file_header.frame_count ) + file_header.header_length > UINT32_MAX) {
178- DEBUG_PRINTF (" Error reading FSEQ file %s header, file too long (max 4gb)\n " , filepath);
210+ if (((uint64_t )file_header.channel_count *
211+ (uint64_t )file_header.frame_count ) +
212+ file_header.header_length >
213+ UINT32_MAX) {
214+ DEBUG_PRINTF (" Error reading FSEQ file %s header, file too long (max 4gb)\n " ,
215+ filepath);
179216 recordingFile.close ();
180217 return ;
181218 }
182219 if (file_header.step_time < 1 ) {
183- DEBUG_PRINTF (" Invalid step time %d, using default %d instead\n " , file_header.step_time , FSEQ_DEFAULT_STEP_TIME);
220+ DEBUG_PRINTF (" Invalid step time %d, using default %d instead\n " ,
221+ file_header.step_time , FSEQ_DEFAULT_STEP_TIME);
184222 file_header.step_time = FSEQ_DEFAULT_STEP_TIME;
185223 }
186224 if (realtimeOverride == REALTIME_OVERRIDE_ONCE) {
@@ -197,37 +235,59 @@ void FSEQPlayer::loadRecording(const char* filepath, uint16_t startLed, uint16_t
197235 recordingRepeats = RECORDING_REPEAT_DEFAULT;
198236 }
199237 playNextRecordingFrame ();
238+ playNextRecordingFrame ();
200239}
201240
202241void FSEQPlayer::clearLastPlayback () {
203242 for (uint16_t i = playbackLedStart; i < playbackLedStop; i++) {
204243 setRealtimePixel (i, 0 , 0 , 0 , 0 );
205244 }
206245 frame = 0 ;
246+ currentFileName = " " ;
207247}
208248
209249bool FSEQPlayer::isPlaying () {
210250 return recordingFile && recordingFile.available ();
211251}
212252
253+ String FSEQPlayer::getFileName () { return currentFileName; }
254+
255+ float FSEQPlayer::getElapsedSeconds () {
256+ if (!isPlaying ())
257+ return 0 ;
258+ // Calculate approximate elapsed seconds based on frame and step time
259+ // Or if secondsElapsed is updated elsewhere, return it.
260+ // Ideally secondsElapsed should be updated during playback.
261+ // But for now, let's just calculate it from frame count
262+ return (float )frame * (float )file_header.step_time / 1000 .0f ;
263+ }
264+
213265void FSEQPlayer::syncPlayback (float secondsElapsed) {
214266 if (!isPlaying ()) {
215267 DEBUG_PRINTLN (" [FSEQ] Sync: Playback not active, cannot sync." );
216268 return ;
217269 }
218-
219- uint32_t expectedFrame = (uint32_t )((secondsElapsed * 1000 .0f ) / file_header.step_time );
270+
271+ // Update internal secondsElapsed if we were tracking it
272+ // FSEQPlayer::secondsElapsed = secondsElapsed; // If we were tracking it
273+
274+ uint32_t expectedFrame =
275+ (uint32_t )((secondsElapsed * 1000 .0f ) / file_header.step_time );
220276 int32_t diff = (int32_t )expectedFrame - (int32_t )frame;
221-
277+
222278 if (abs (diff) > 2 ) {
223279 frame = expectedFrame;
224- uint32_t offset = file_header.channel_data_offset + file_header.channel_count * frame;
280+ uint32_t offset =
281+ file_header.channel_data_offset + file_header.channel_count * frame;
225282 if (recordingFile.seek (offset)) {
226- DEBUG_PRINTF (" [FSEQ] Sync: Adjusted frame to %lu (diff=%ld)\n " , expectedFrame, diff);
283+ DEBUG_PRINTF (" [FSEQ] Sync: Adjusted frame to %lu (diff=%ld)\n " ,
284+ expectedFrame, diff);
227285 } else {
228286 DEBUG_PRINTLN (" [FSEQ] Sync: Failed to seek to new frame" );
229287 }
230288 } else {
231- DEBUG_PRINTF (" [FSEQ] Sync: No adjustment needed (current frame: %lu, expected: %lu)\n " , frame, expectedFrame);
289+ DEBUG_PRINTF (" [FSEQ] Sync: No adjustment needed (current frame: %lu, "
290+ " expected: %lu)\n " ,
291+ frame, expectedFrame);
232292 }
233293}
0 commit comments