From 874c91146402df8a47718e327558e8ceab0b482c Mon Sep 17 00:00:00 2001 From: Jeffrey Goode Date: Mon, 9 Nov 2009 18:12:20 +0000 Subject: [PATCH] pcmbuf: refactoring git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23592 a1c6a512-1295-4272-9138-f99709370657 --- apps/pcmbuf.c | 253 ++++++++++++++++++++++++-------------------------- 1 file changed, 121 insertions(+), 132 deletions(-) diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index cda20d9f48..02c307df72 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -68,10 +68,8 @@ struct chunkdesc bool end_of_track; }; -#define CHUNK_DESCS(bufsize) \ +#define NUM_CHUNK_DESCS(bufsize) \ ((bufsize) / PCMBUF_MINAVG_CHUNK) -#define CHUNK_DESCS_SIZE(bufsize) \ - (CHUNK_DESCS(bufsize)*sizeof(struct chunkdesc)) /* Size of the PCM buffer. */ static size_t pcmbuf_size IDATA_ATTR = 0; @@ -132,7 +130,6 @@ extern unsigned int codec_thread_id; #define LOW_DATA(quarter_secs) \ (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs) -static void finish_gapless_track_change(void); #ifdef HAVE_CROSSFADE static void crossfade_start(void); static void flush_crossfade(char *buf, size_t length); @@ -432,22 +429,17 @@ static size_t get_next_required_pcmbuf_size(void) return seconds * (NATIVE_FREQUENCY*4); /* 2 channels + 2 bytes/sample */ } -static char *pcmbuf_calc_pcmbuffer_ptr(size_t bufsize) -{ - return pcmbuf_bufend - (bufsize + PCMBUF_MIX_CHUNK * 2 + - CHUNK_DESCS_SIZE(bufsize)); -} - /* Initialize the pcmbuffer the structure looks like this: * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ size_t pcmbuf_init(unsigned char *bufend) { pcmbuf_bufend = bufend; pcmbuf_size = get_next_required_pcmbuf_size(); - pcmbuffer = pcmbuf_calc_pcmbuffer_ptr(pcmbuf_size); - fadebuf = &pcmbuffer[pcmbuf_size]; - voicebuf = &fadebuf[PCMBUF_MIX_CHUNK]; - write_chunk = (struct chunkdesc *)&voicebuf[PCMBUF_MIX_CHUNK]; + write_chunk = (struct chunkdesc *)pcmbuf_bufend - + NUM_CHUNK_DESCS(pcmbuf_size); + voicebuf = (char *)write_chunk - PCMBUF_MIX_CHUNK; + fadebuf = voicebuf - PCMBUF_MIX_CHUNK; + pcmbuffer = fadebuf - pcmbuf_size; init_pcmbuffers(); @@ -463,123 +455,6 @@ size_t pcmbuf_init(unsigned char *bufend) } -/* Playback */ - -/** PCM driver callback - * This function has 3 major logical parts (separated by brackets both for - * readability and variable scoping). The first part performs the - * operations related to finishing off the last buffer we fed to the DMA. - * The second part detects the end of playlist condition when the pcm - * buffer is empty except for uncommitted samples. Then they are committed. - * The third part performs the operations involved in sending a new buffer - * to the DMA. */ -static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; -static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) -{ - { - struct chunkdesc *pcmbuf_current = read_chunk; - /* Take the finished buffer out of circulation */ - read_chunk = pcmbuf_current->link; - - /* if during a track transition, update the elapsed time */ - if (track_transition) - audio_pcmbuf_position_callback(last_chunksize); - - /* if last buffer in the track, let the audio thread know */ - if (pcmbuf_current->end_of_track) - finish_gapless_track_change(); - - /* Put the finished buffer back into circulation */ - write_end_chunk->link = pcmbuf_current; - write_end_chunk = pcmbuf_current; - - /* If we've read over the mix chunk while it's still mixing there */ - if (pcmbuf_current == mix_chunk) - mix_chunk = NULL; - /* If we've read over the crossfade chunk while it's still fading */ - if (pcmbuf_current == crossfade_chunk) - crossfade_chunk = read_chunk; - } - - { - /* Commit last samples at end of playlist */ - if (pcmbuffer_fillpos && !read_chunk) - { - logf("pcmbuf_pcm_callback: commit last samples"); - commit_chunk(); - } - } - - { - /* Send the new buffer to the pcm */ - struct chunkdesc *pcmbuf_new = read_chunk; - size_t *realsize = size; - unsigned char** realstart = start; - if(pcmbuf_new) - { - size_t current_size = pcmbuf_new->size; - - pcmbuf_unplayed_bytes -= current_size; - last_chunksize = current_size; - *realsize = current_size; - *realstart = pcmbuf_new->addr; - } - else - { - /* No more buffers */ - last_chunksize = 0; - *realsize = 0; - *realstart = NULL; - if (end_of_track) - finish_gapless_track_change(); - } - } - DISPLAY_DESC("callback"); -} - -/* Force playback. */ -void pcmbuf_play_start(void) -{ - if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) - { - last_chunksize = read_chunk->size; - pcmbuf_unplayed_bytes -= last_chunksize; - pcm_play_data(pcmbuf_pcm_callback, - (unsigned char *)read_chunk->addr, last_chunksize); - } -} - -void pcmbuf_play_stop(void) -{ - pcm_play_stop(); - - pcmbuf_unplayed_bytes = 0; - mix_chunk = NULL; - if (read_chunk) { - write_end_chunk->link = read_chunk; - write_end_chunk = read_end_chunk; - read_chunk = read_end_chunk = NULL; - } - pcmbuffer_pos = 0; - pcmbuffer_fillpos = 0; - crossfade_track_change_started = false; - crossfade_active = false; - flush_pcmbuf = false; - DISPLAY_DESC("play_stop"); - - /* Can unboost the codec thread here no matter who's calling */ - boost_codec_thread(false); -} - -void pcmbuf_pause(bool pause) -{ - if (pcm_is_playing()) - pcm_play_pause(!pause); - else if (!pause) - pcmbuf_play_start(); -} - - /* Track change */ /* The codec is moving on to the next track, but the current track is @@ -665,6 +540,120 @@ static void finish_gapless_track_change(void) } +/* Playback */ + +/** PCM driver callback + * This function has 3 major logical parts (separated by brackets both for + * readability and variable scoping). The first part performs the + * operations related to finishing off the last buffer we fed to the DMA. + * The second part detects the end of playlist condition when the pcm + * buffer is empty except for uncommitted samples. Then they are committed. + * The third part performs the operations involved in sending a new buffer + * to the DMA. */ +static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; +static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) +{ + { + struct chunkdesc *pcmbuf_current = read_chunk; + /* Take the finished buffer out of circulation */ + read_chunk = pcmbuf_current->link; + + /* if during a track transition, update the elapsed time */ + if (track_transition) + audio_pcmbuf_position_callback(last_chunksize); + + /* if last buffer in the track, let the audio thread know */ + if (pcmbuf_current->end_of_track) + finish_gapless_track_change(); + + /* Put the finished buffer back into circulation */ + write_end_chunk->link = pcmbuf_current; + write_end_chunk = pcmbuf_current; + + /* If we've read over the mix chunk while it's still mixing there */ + if (pcmbuf_current == mix_chunk) + mix_chunk = NULL; + /* If we've read over the crossfade chunk while it's still fading */ + if (pcmbuf_current == crossfade_chunk) + crossfade_chunk = read_chunk; + } + + { + /* Commit last samples at end of playlist */ + if (pcmbuffer_fillpos && !read_chunk) + { + logf("pcmbuf_pcm_callback: commit last samples"); + commit_chunk(); + } + } + + { + /* Send the new buffer to the pcm */ + if(read_chunk) + { + size_t current_size = read_chunk->size; + + pcmbuf_unplayed_bytes -= current_size; + last_chunksize = current_size; + *size = current_size; + *start = read_chunk->addr; + } + else + { + /* No more buffers */ + last_chunksize = 0; + *size = 0; + *start = NULL; + if (end_of_track) + finish_gapless_track_change(); + } + } + DISPLAY_DESC("callback"); +} + +/* Force playback. */ +void pcmbuf_play_start(void) +{ + if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) + { + last_chunksize = read_chunk->size; + pcmbuf_unplayed_bytes -= last_chunksize; + pcm_play_data(pcmbuf_pcm_callback, + (unsigned char *)read_chunk->addr, last_chunksize); + } +} + +void pcmbuf_play_stop(void) +{ + pcm_play_stop(); + + pcmbuf_unplayed_bytes = 0; + mix_chunk = NULL; + if (read_chunk) { + write_end_chunk->link = read_chunk; + write_end_chunk = read_end_chunk; + read_chunk = read_end_chunk = NULL; + } + pcmbuffer_pos = 0; + pcmbuffer_fillpos = 0; + crossfade_track_change_started = false; + crossfade_active = false; + flush_pcmbuf = false; + DISPLAY_DESC("play_stop"); + + /* Can unboost the codec thread here no matter who's calling */ + boost_codec_thread(false); +} + +void pcmbuf_pause(bool pause) +{ + if (pcm_is_playing()) + pcm_play_pause(!pause); + else if (!pause) + pcmbuf_play_start(); +} + + /* Crossfade */ /* Clip sample to signed 16 bit range */ @@ -1095,7 +1084,7 @@ int pcmbuf_used_descs(void) int pcmbuf_descs(void) { - return CHUNK_DESCS(pcmbuf_size); + return NUM_CHUNK_DESCS(pcmbuf_size); } #ifdef ROCKBOX_HAS_LOGF