diff options
author | Jeffrey Goode <jeffg7@gmail.com> | 2009-11-04 03:58:33 +0000 |
---|---|---|
committer | Jeffrey Goode <jeffg7@gmail.com> | 2009-11-04 03:58:33 +0000 |
commit | 5ce8e2cb0d2361606f3646e9fa59a39393500ba8 (patch) | |
tree | a7e294dd9b06aaddec5f8d0e6372a9209cd74af2 | |
parent | 606a333a5f9701375b6efac55adf1c0d2e6e4b7e (diff) | |
download | rockbox-5ce8e2cb0d2361606f3646e9fa59a39393500ba8.tar.gz rockbox-5ce8e2cb0d2361606f3646e9fa59a39393500ba8.zip |
Clarify track transition code in pcmbuf and playback. No functional changes yet.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23506 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/codec_thread.c | 44 | ||||
-rw-r--r-- | apps/pcmbuf.c | 82 | ||||
-rw-r--r-- | apps/pcmbuf.h | 3 | ||||
-rw-r--r-- | apps/playback.c | 40 | ||||
-rw-r--r-- | apps/playback.h | 1 |
5 files changed, 85 insertions, 85 deletions
diff --git a/apps/codec_thread.c b/apps/codec_thread.c index d4217c3789..affb560183 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c | |||
@@ -416,46 +416,8 @@ void codec_init_codec_api(void) | |||
416 | } | 416 | } |
417 | 417 | ||
418 | 418 | ||
419 | /** pcmbuf track change callbacks */ | ||
420 | |||
421 | /* Between the codec and PCM track change, we need to keep updating the | ||
422 | "elapsed" value of the previous (to the codec, but current to the | ||
423 | user/PCM/WPS) track, so that the progressbar reaches the end. | ||
424 | During that transition, the WPS will display prevtrack_id3. */ | ||
425 | static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR; | ||
426 | static void codec_pcmbuf_position_callback(size_t size) | ||
427 | { | ||
428 | /* This is called from an ISR, so be quick */ | ||
429 | unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + | ||
430 | othertrack_id3->elapsed; | ||
431 | |||
432 | if (time >= othertrack_id3->length) | ||
433 | { | ||
434 | pcmbuf_set_position_callback(NULL); | ||
435 | othertrack_id3->elapsed = othertrack_id3->length; | ||
436 | } | ||
437 | else | ||
438 | othertrack_id3->elapsed = time; | ||
439 | } | ||
440 | |||
441 | static void codec_pcmbuf_track_changed_callback(void) | ||
442 | { | ||
443 | LOGFQUEUE("codec > pcmbuf/audio Q_AUDIO_TRACK_CHANGED"); | ||
444 | pcmbuf_set_position_callback(NULL); | ||
445 | audio_post_track_change(); | ||
446 | } | ||
447 | |||
448 | |||
449 | /** track change functions */ | 419 | /** track change functions */ |
450 | 420 | ||
451 | static inline void codec_gapless_track_change(void) | ||
452 | { | ||
453 | /* callback keeps the progress bar moving while the pcmbuf empties */ | ||
454 | pcmbuf_set_position_callback(codec_pcmbuf_position_callback); | ||
455 | /* set the pcmbuf callback for when the track really changes */ | ||
456 | pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback); | ||
457 | } | ||
458 | |||
459 | static inline void codec_crossfade_track_change(void) | 421 | static inline void codec_crossfade_track_change(void) |
460 | { | 422 | { |
461 | /* Initiate automatic crossfade mode */ | 423 | /* Initiate automatic crossfade mode */ |
@@ -484,8 +446,8 @@ static void codec_track_skip_done(bool was_manual) | |||
484 | /* shuffle mode is on, so crossfade: */ | 446 | /* shuffle mode is on, so crossfade: */ |
485 | codec_crossfade_track_change(); | 447 | codec_crossfade_track_change(); |
486 | else | 448 | else |
487 | /* shuffle mode is off, so do a gapless track change */ | 449 | /* shuffle mode is off, so normal gapless playback */ |
488 | codec_gapless_track_change(); | 450 | pcmbuf_start_track_change(); |
489 | } | 451 | } |
490 | else | 452 | else |
491 | /* normal crossfade: */ | 453 | /* normal crossfade: */ |
@@ -493,7 +455,7 @@ static void codec_track_skip_done(bool was_manual) | |||
493 | } | 455 | } |
494 | else | 456 | else |
495 | /* normal gapless playback. */ | 457 | /* normal gapless playback. */ |
496 | codec_gapless_track_change(); | 458 | pcmbuf_start_track_change(); |
497 | } | 459 | } |
498 | 460 | ||
499 | static bool codec_load_next_track(void) | 461 | static bool codec_load_next_track(void) |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 3ec0c114da..3b461ecdc1 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <kernel.h> | 25 | #include <kernel.h> |
26 | #include "pcmbuf.h" | 26 | #include "pcmbuf.h" |
27 | #include "pcm.h" | 27 | #include "pcm.h" |
28 | #include "playback.h" | ||
28 | 29 | ||
29 | /* Define LOGF_ENABLE to enable logf output in this file */ | 30 | /* Define LOGF_ENABLE to enable logf output in this file */ |
30 | /*#define LOGF_ENABLE*/ | 31 | /*#define LOGF_ENABLE*/ |
@@ -62,8 +63,8 @@ struct pcmbufdesc | |||
62 | void *addr; | 63 | void *addr; |
63 | size_t size; | 64 | size_t size; |
64 | struct pcmbufdesc* link; | 65 | struct pcmbufdesc* link; |
65 | /* Call this when the buffer has been played */ | 66 | /* true if last chunk in the track */ |
66 | void (*callback)(void); | 67 | bool end_of_track; |
67 | }; | 68 | }; |
68 | 69 | ||
69 | #define PCMBUF_DESCS(bufsize) \ | 70 | #define PCMBUF_DESCS(bufsize) \ |
@@ -82,8 +83,8 @@ static size_t audiobuffer_fillpos IDATA_ATTR; | |||
82 | static char *fadebuf IDATA_ATTR; | 83 | static char *fadebuf IDATA_ATTR; |
83 | static char *voicebuf IDATA_ATTR; | 84 | static char *voicebuf IDATA_ATTR; |
84 | 85 | ||
85 | static void (*pcmbuf_event_handler)(void) IDATA_ATTR; | 86 | static bool end_of_track IDATA_ATTR; |
86 | static void (*position_callback)(size_t size) IDATA_ATTR; | 87 | bool track_transition IDATA_ATTR; |
87 | 88 | ||
88 | /* Crossfade related state */ | 89 | /* Crossfade related state */ |
89 | static bool crossfade_enabled; | 90 | static bool crossfade_enabled; |
@@ -134,25 +135,57 @@ static bool prepare_insert(size_t length); | |||
134 | static void pcmbuf_under_watermark(bool under); | 135 | static void pcmbuf_under_watermark(bool under); |
135 | static bool pcmbuf_flush_fillpos(void); | 136 | static bool pcmbuf_flush_fillpos(void); |
136 | 137 | ||
137 | #define CALL_IF_EXISTS(function, args...) if (function) function(args) | 138 | |
138 | /* This function has 3 major logical parts (separated by brackets both for | 139 | /* Track change functions */ |
140 | |||
141 | /* The codec is moving on to the next track, but the current track is | ||
142 | * still playing. Set flags to make sure the elapsed time of the current | ||
143 | * track is updated properly, and mark the currently written chunk as the | ||
144 | * last one in the track. */ | ||
145 | void pcmbuf_start_track_change(void) | ||
146 | { | ||
147 | /* we're starting a track transition */ | ||
148 | track_transition = true; | ||
149 | |||
150 | /* mark the last chunk in the track */ | ||
151 | end_of_track = true; | ||
152 | } | ||
153 | |||
154 | /* Called when the last chunk in the track has been played */ | ||
155 | static void pcmbuf_finish_track_change(void) | ||
156 | { | ||
157 | /* not in a track transition anymore */ | ||
158 | if(track_transition){logf("pcmbuf: (finish change) track transition false");} | ||
159 | track_transition = false; | ||
160 | |||
161 | /* notify playback that the track has just finished */ | ||
162 | audio_post_track_change(); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** PCM driver callback | ||
167 | * This function has 3 major logical parts (separated by brackets both for | ||
139 | * readability and variable scoping). The first part performs the | 168 | * readability and variable scoping). The first part performs the |
140 | * operations related to finishing off the last buffer we fed to the DMA. | 169 | * operations related to finishing off the last buffer we fed to the DMA. |
141 | * The second part detects the end of playlist condition when the pcm | 170 | * The second part detects the end of playlist condition when the pcm |
142 | * buffer is empty except for uncommitted samples. Then they are committed. | 171 | * buffer is empty except for uncommitted samples. Then they are committed. |
143 | * The third part performs the operations involved in sending a new buffer | 172 | * The third part performs the operations involved in sending a new buffer |
144 | * to the DMA. */ | 173 | * to the DMA. */ |
145 | static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR; | 174 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; |
146 | static void pcmbuf_callback(unsigned char** start, size_t* size) | 175 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) |
147 | { | 176 | { |
148 | { | 177 | { |
149 | struct pcmbufdesc *pcmbuf_current = pcmbuf_read; | 178 | struct pcmbufdesc *pcmbuf_current = pcmbuf_read; |
150 | /* Take the finished buffer out of circulation */ | 179 | /* Take the finished buffer out of circulation */ |
151 | pcmbuf_read = pcmbuf_current->link; | 180 | pcmbuf_read = pcmbuf_current->link; |
152 | 181 | ||
153 | /* The buffer is finished, call the callback functions */ | 182 | /* if during a track transition, update the elapsed time */ |
154 | CALL_IF_EXISTS(position_callback, last_chunksize); | 183 | if (track_transition) |
155 | CALL_IF_EXISTS(pcmbuf_current->callback); | 184 | audio_pcmbuf_position_callback(last_chunksize); |
185 | |||
186 | /* if last buffer in the track, let the audio thread know */ | ||
187 | if (pcmbuf_current->end_of_track) | ||
188 | pcmbuf_finish_track_change(); | ||
156 | 189 | ||
157 | /* Put the finished buffer back into circulation */ | 190 | /* Put the finished buffer back into circulation */ |
158 | pcmbuf_write_end->link = pcmbuf_current; | 191 | pcmbuf_write_end->link = pcmbuf_current; |
@@ -170,7 +203,7 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) | |||
170 | /* Commit last samples at end of playlist */ | 203 | /* Commit last samples at end of playlist */ |
171 | if (audiobuffer_fillpos && !pcmbuf_read) | 204 | if (audiobuffer_fillpos && !pcmbuf_read) |
172 | { | 205 | { |
173 | logf("pcmbuf callback: commit last samples"); | 206 | logf("pcmbuf_pcm_callback: commit last samples"); |
174 | pcmbuf_flush_fillpos(); | 207 | pcmbuf_flush_fillpos(); |
175 | } | 208 | } |
176 | } | 209 | } |
@@ -195,16 +228,12 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) | |||
195 | last_chunksize = 0; | 228 | last_chunksize = 0; |
196 | *realsize = 0; | 229 | *realsize = 0; |
197 | *realstart = NULL; | 230 | *realstart = NULL; |
198 | CALL_IF_EXISTS(pcmbuf_event_handler); | 231 | if (end_of_track) |
232 | pcmbuf_finish_track_change(); | ||
199 | } | 233 | } |
200 | } | 234 | } |
201 | } | 235 | } |
202 | 236 | ||
203 | void pcmbuf_set_position_callback(void (*callback)(size_t size)) | ||
204 | { | ||
205 | position_callback = callback; | ||
206 | } | ||
207 | |||
208 | static void pcmbuf_set_watermark_bytes(void) | 237 | static void pcmbuf_set_watermark_bytes(void) |
209 | { | 238 | { |
210 | pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ? | 239 | pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ? |
@@ -225,10 +254,9 @@ static inline void pcmbuf_add_chunk(void) | |||
225 | /* Fill in the values in the new buffer chunk */ | 254 | /* Fill in the values in the new buffer chunk */ |
226 | pcmbuf_current->addr = &audiobuffer[audiobuffer_pos]; | 255 | pcmbuf_current->addr = &audiobuffer[audiobuffer_pos]; |
227 | pcmbuf_current->size = size; | 256 | pcmbuf_current->size = size; |
228 | pcmbuf_current->callback = pcmbuf_event_handler; | 257 | pcmbuf_current->end_of_track = end_of_track; |
229 | pcmbuf_current->link = NULL; | 258 | pcmbuf_current->link = NULL; |
230 | /* This is single use only */ | 259 | end_of_track = false; /* This is single use only */ |
231 | pcmbuf_event_handler = NULL; | ||
232 | if (pcmbuf_read != NULL) { | 260 | if (pcmbuf_read != NULL) { |
233 | if (pcmbuf_flush) | 261 | if (pcmbuf_flush) |
234 | { | 262 | { |
@@ -320,11 +348,6 @@ static void pcmbuf_under_watermark(bool under) | |||
320 | } | 348 | } |
321 | } | 349 | } |
322 | 350 | ||
323 | void pcmbuf_set_event_handler(void (*event_handler)(void)) | ||
324 | { | ||
325 | pcmbuf_event_handler = event_handler; | ||
326 | } | ||
327 | |||
328 | unsigned int pcmbuf_get_latency(void) | 351 | unsigned int pcmbuf_get_latency(void) |
329 | { | 352 | { |
330 | /* Be careful how this calculation is rearranged, it's easy to overflow */ | 353 | /* Be careful how this calculation is rearranged, it's easy to overflow */ |
@@ -493,8 +516,9 @@ size_t pcmbuf_init(unsigned char *bufend) | |||
493 | 516 | ||
494 | pcmbuf_init_pcmbuffers(); | 517 | pcmbuf_init_pcmbuffers(); |
495 | 518 | ||
496 | position_callback = NULL; | 519 | if(track_transition){logf("pcmbuf: (init) track transition false");} |
497 | pcmbuf_event_handler = NULL; | 520 | end_of_track = false; |
521 | track_transition = false; | ||
498 | 522 | ||
499 | pcmbuf_crossfade_enable_finished(); | 523 | pcmbuf_crossfade_enable_finished(); |
500 | 524 | ||
@@ -531,7 +555,7 @@ void pcmbuf_play_start(void) | |||
531 | { | 555 | { |
532 | last_chunksize = pcmbuf_read->size; | 556 | last_chunksize = pcmbuf_read->size; |
533 | pcmbuf_unplayed_bytes -= last_chunksize; | 557 | pcmbuf_unplayed_bytes -= last_chunksize; |
534 | pcm_play_data(pcmbuf_callback, | 558 | pcm_play_data(pcmbuf_pcm_callback, |
535 | (unsigned char *)pcmbuf_read->addr, last_chunksize); | 559 | (unsigned char *)pcmbuf_read->addr, last_chunksize); |
536 | } | 560 | } |
537 | } | 561 | } |
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index b4e551f74d..b6f0c767f2 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h | |||
@@ -57,8 +57,7 @@ void pcmbuf_set_boost_mode(bool state); | |||
57 | bool pcmbuf_is_lowdata(void); | 57 | bool pcmbuf_is_lowdata(void); |
58 | void pcmbuf_play_start(void); | 58 | void pcmbuf_play_start(void); |
59 | bool pcmbuf_crossfade_init(bool manual_skip); | 59 | bool pcmbuf_crossfade_init(bool manual_skip); |
60 | void pcmbuf_set_event_handler(void (*callback)(void)); | 60 | void pcmbuf_start_track_change(void); |
61 | void pcmbuf_set_position_callback(void (*callback)(size_t size)); | ||
62 | size_t pcmbuf_free(void); | 61 | size_t pcmbuf_free(void); |
63 | unsigned int pcmbuf_get_latency(void); | 62 | unsigned int pcmbuf_get_latency(void); |
64 | void pcmbuf_set_low_latency(bool state); | 63 | void pcmbuf_set_low_latency(bool state); |
diff --git a/apps/playback.c b/apps/playback.c index bebbfb1e43..d3c4b46a99 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -179,6 +179,7 @@ static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A | |||
179 | 179 | ||
180 | /* Track change controls */ | 180 | /* Track change controls */ |
181 | bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ | 181 | bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ |
182 | extern bool track_transition; /* Are we in a track transition? */ | ||
182 | static bool dir_skip = false; /* Is a directory skip pending? (A) */ | 183 | static bool dir_skip = false; /* Is a directory skip pending? (A) */ |
183 | static bool new_playlist = false; /* Are we starting a new playlist? (A) */ | 184 | static bool new_playlist = false; /* Are we starting a new playlist? (A) */ |
184 | static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ | 185 | static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ |
@@ -223,10 +224,31 @@ static void audio_stop_playback(void); | |||
223 | 224 | ||
224 | /**************************************/ | 225 | /**************************************/ |
225 | 226 | ||
226 | /* Post message from pcmbuf callback in the codec thread that | 227 | /* Between the codec and PCM track change, we need to keep updating the |
227 | * the end of the previous track has just been played. */ | 228 | "elapsed" value of the previous (to the codec, but current to the |
229 | user/PCM/WPS) track, so that the progressbar reaches the end. | ||
230 | During that transition, the WPS will display othertrack_id3. */ | ||
231 | void audio_pcmbuf_position_callback(size_t size) | ||
232 | { | ||
233 | /* This is called from an ISR, so be quick */ | ||
234 | unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + | ||
235 | othertrack_id3->elapsed; | ||
236 | |||
237 | if (time >= othertrack_id3->length) | ||
238 | { | ||
239 | if(track_transition){logf("playback: (callback) track transition false");} | ||
240 | track_transition = false; | ||
241 | othertrack_id3->elapsed = othertrack_id3->length; | ||
242 | } | ||
243 | else | ||
244 | othertrack_id3->elapsed = time; | ||
245 | } | ||
246 | |||
247 | /* Post message from pcmbuf that the end of the previous track | ||
248 | * has just been played. */ | ||
228 | void audio_post_track_change(void) | 249 | void audio_post_track_change(void) |
229 | { | 250 | { |
251 | LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED"); | ||
230 | queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0); | 252 | queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0); |
231 | } | 253 | } |
232 | 254 | ||
@@ -248,16 +270,6 @@ static bool pcmbuf_queue_scan(struct queue_event *ev) | |||
248 | return false; | 270 | return false; |
249 | } | 271 | } |
250 | 272 | ||
251 | /* Clear the pcmbuf queue of messages | ||
252 | * Permissible Context(s): Thread | ||
253 | */ | ||
254 | static void pcmbuf_queue_clear(void) | ||
255 | { | ||
256 | pcm_play_lock(); | ||
257 | queue_clear(&pcmbuf_queue); | ||
258 | pcm_play_unlock(); | ||
259 | } | ||
260 | |||
261 | /* --- Helper functions --- */ | 273 | /* --- Helper functions --- */ |
262 | 274 | ||
263 | static struct mp3entry *bufgetid3(int handle_id) | 275 | static struct mp3entry *bufgetid3(int handle_id) |
@@ -1617,7 +1629,9 @@ static void audio_stop_codec_flush(void) | |||
1617 | if (pcm_is_playing()) | 1629 | if (pcm_is_playing()) |
1618 | { | 1630 | { |
1619 | pcmbuf_play_stop(); | 1631 | pcmbuf_play_stop(); |
1620 | pcmbuf_queue_clear(); | 1632 | pcm_play_lock(); |
1633 | queue_clear(&pcmbuf_queue); | ||
1634 | pcm_play_unlock(); | ||
1621 | } | 1635 | } |
1622 | pcmbuf_pause(paused); | 1636 | pcmbuf_pause(paused); |
1623 | } | 1637 | } |
diff --git a/apps/playback.h b/apps/playback.h index 95b0bef0df..b168770361 100644 --- a/apps/playback.h +++ b/apps/playback.h | |||
@@ -69,6 +69,7 @@ enum | |||
69 | }; | 69 | }; |
70 | bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ | 70 | bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ |
71 | size_t audio_get_filebuflen(void); | 71 | size_t audio_get_filebuflen(void); |
72 | void audio_pcmbuf_position_callback(size_t size) ICODE_ATTR; | ||
72 | void audio_post_track_change(void); | 73 | void audio_post_track_change(void); |
73 | int get_audio_hid(void); | 74 | int get_audio_hid(void); |
74 | int *get_codec_hid(void); | 75 | int *get_codec_hid(void); |