summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Goode <jeffg7@gmail.com>2009-11-04 03:58:33 +0000
committerJeffrey Goode <jeffg7@gmail.com>2009-11-04 03:58:33 +0000
commit5ce8e2cb0d2361606f3646e9fa59a39393500ba8 (patch)
treea7e294dd9b06aaddec5f8d0e6372a9209cd74af2
parent606a333a5f9701375b6efac55adf1c0d2e6e4b7e (diff)
downloadrockbox-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.c44
-rw-r--r--apps/pcmbuf.c82
-rw-r--r--apps/pcmbuf.h3
-rw-r--r--apps/playback.c40
-rw-r--r--apps/playback.h1
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. */
425static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
426static 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
441static 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
451static 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
459static inline void codec_crossfade_track_change(void) 421static 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
499static bool codec_load_next_track(void) 461static 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;
82static char *fadebuf IDATA_ATTR; 83static char *fadebuf IDATA_ATTR;
83static char *voicebuf IDATA_ATTR; 84static char *voicebuf IDATA_ATTR;
84 85
85static void (*pcmbuf_event_handler)(void) IDATA_ATTR; 86static bool end_of_track IDATA_ATTR;
86static void (*position_callback)(size_t size) IDATA_ATTR; 87bool track_transition IDATA_ATTR;
87 88
88/* Crossfade related state */ 89/* Crossfade related state */
89static bool crossfade_enabled; 90static bool crossfade_enabled;
@@ -134,25 +135,57 @@ static bool prepare_insert(size_t length);
134static void pcmbuf_under_watermark(bool under); 135static void pcmbuf_under_watermark(bool under);
135static bool pcmbuf_flush_fillpos(void); 136static 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. */
145void 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 */
155static 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. */
145static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR; 174static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR;
146static void pcmbuf_callback(unsigned char** start, size_t* size) 175static 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
203void pcmbuf_set_position_callback(void (*callback)(size_t size))
204{
205 position_callback = callback;
206}
207
208static void pcmbuf_set_watermark_bytes(void) 237static 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
323void pcmbuf_set_event_handler(void (*event_handler)(void))
324{
325 pcmbuf_event_handler = event_handler;
326}
327
328unsigned int pcmbuf_get_latency(void) 351unsigned 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);
57bool pcmbuf_is_lowdata(void); 57bool pcmbuf_is_lowdata(void);
58void pcmbuf_play_start(void); 58void pcmbuf_play_start(void);
59bool pcmbuf_crossfade_init(bool manual_skip); 59bool pcmbuf_crossfade_init(bool manual_skip);
60void pcmbuf_set_event_handler(void (*callback)(void)); 60void pcmbuf_start_track_change(void);
61void pcmbuf_set_position_callback(void (*callback)(size_t size));
62size_t pcmbuf_free(void); 61size_t pcmbuf_free(void);
63unsigned int pcmbuf_get_latency(void); 62unsigned int pcmbuf_get_latency(void);
64void pcmbuf_set_low_latency(bool state); 63void 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 */
181bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ 181bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
182extern bool track_transition; /* Are we in a track transition? */
182static bool dir_skip = false; /* Is a directory skip pending? (A) */ 183static bool dir_skip = false; /* Is a directory skip pending? (A) */
183static bool new_playlist = false; /* Are we starting a new playlist? (A) */ 184static bool new_playlist = false; /* Are we starting a new playlist? (A) */
184static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ 185static 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. */
231void 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. */
228void audio_post_track_change(void) 249void 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 */
254static 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
263static struct mp3entry *bufgetid3(int handle_id) 275static 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};
70bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ 70bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
71size_t audio_get_filebuflen(void); 71size_t audio_get_filebuflen(void);
72void audio_pcmbuf_position_callback(size_t size) ICODE_ATTR;
72void audio_post_track_change(void); 73void audio_post_track_change(void);
73int get_audio_hid(void); 74int get_audio_hid(void);
74int *get_codec_hid(void); 75int *get_codec_hid(void);