Index: apps/pcmbuf.c =================================================================== --- apps/pcmbuf.c (revision 25767) +++ apps/pcmbuf.c (working copy) @@ -28,7 +28,7 @@ #include "playback.h" /* Define LOGF_ENABLE to enable logf output in this file */ -/*#define LOGF_ENABLE*/ +#define LOGF_ENABLE #include "logf.h" #ifndef SIMULATOR #include "cpu.h" @@ -47,8 +47,9 @@ non-fatal) */ #define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than this to the DMA */ -#define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet - for mixing (crossfade or voice) */ +#define CROSSFADE_BUFSIZE 8192 /* Size of the crossfade buffer */ +#define AUX_BUFSIZE 512 /* Size of the aux buffer */ +#define PCMBUF_MIX_CHUNK 4096 /* Size of just-in-time mixing chunks */ /* number of bytes played per second (sample rate * 2 channels * 2 bytes/sample) */ #define BYTERATE (NATIVE_FREQUENCY * 4) @@ -64,7 +65,7 @@ * by the driver code. */ struct chunkdesc { - void *addr; + unsigned char *addr; size_t size; struct chunkdesc* link; /* true if last chunk in the track */ @@ -117,11 +118,38 @@ static size_t pcmbuf_unplayed_bytes IDATA_ATTR; static size_t pcmbuf_watermark IDATA_ATTR; -/* Voice */ -static char *voicebuf IDATA_ATTR; -static struct chunkdesc *mix_chunk IDATA_ATTR; -static size_t pcmbuf_mix_sample IDATA_ATTR; +/* Aux playback */ +static char *auxbuf IDATA_ATTR; +static bool auxbuf_in_use; +/* Mixer */ +struct mixdesc +{ + unsigned char *addr; + size_t size; + size_t pcmoffset; +}; + +enum { + MIXER_OFF = 0, + MIXER_FADEOUT_PCM, + MIXER_FADEIN_PCM, + MIXER_ON, +}; + +/* currently filling buffer */ +#define FILL_BUF mixchunk[mixbuf] +/* currently playing buffer */ +#define PLAY_BUF mixchunk[1 - mixbuf] + +static struct mixdesc *mixchunk[2] IDATA_ATTR; +static int mixbuf; +static int mixer_state; +static int fade_step; +static bool pcmbuf_playing; +static bool pcmbuf_paused; +static bool aux_playing; + static bool low_latency_mode = false; static bool flush_pcmbuf = false; @@ -143,6 +171,7 @@ static void write_to_crossfade(size_t length); static void pcmbuf_finish_crossfade_enable(void); #endif +static bool mixer_interrupt_handler(unsigned char** start, size_t* size) ICODE_ATTR; /**************************************/ @@ -204,7 +233,7 @@ /* Never use the last buffer descriptor */ while (write_chunk == write_end_chunk) { /* If this happens, something is being stupid */ - if (!pcm_is_playing()) { + if (!pcmbuf_is_playing()) { logf("commit_chunk error"); pcmbuf_play_start(); } @@ -305,7 +334,7 @@ if (low_latency_mode) { /* 1/4s latency. */ - if (!LOW_DATA(1) && pcm_is_playing()) + if (!LOW_DATA(1) && pcmbuf_is_playing()) return false; } @@ -314,7 +343,7 @@ return false; /* Maintain the buffer level above the watermark */ - if (pcm_is_playing()) + if (pcmbuf_is_playing()) { /* Only codec thread initiates boost - voice boosts the cpu when playing a clip */ @@ -344,7 +373,7 @@ } #endif } - else /* pcm_is_playing */ + else /* pcmbuf_is_playing */ { /* Boost CPU for pre-buffer */ trigger_cpu_boost(); @@ -357,7 +386,7 @@ #endif { logf("pcm starting"); - if (!(audio_status() & AUDIO_STATUS_PAUSE)) + if (!pcmbuf_paused) pcmbuf_play_start(); } } @@ -376,7 +405,7 @@ /* crossfade has begun, put the new track samples in fadebuf */ if (crossfade_active) { - *count = MIN(*count, PCMBUF_MIX_CHUNK/4); + *count = MIN(*count, CROSSFADE_BUFSIZE/4); return fadebuf; } else @@ -457,20 +486,24 @@ } /* Initialize the pcmbuffer the structure looks like this: - * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ + * ...|---------PCMBUF---------|FADEBUF|MIXBUF0|MIXBUF1|AUXBUF|DESCS|... */ size_t pcmbuf_init(unsigned char *bufend) { pcmbuf_bufend = bufend; - pcmbuf_size = get_next_required_pcmbuf_size(); - write_chunk = (struct chunkdesc *)pcmbuf_bufend - + pcmbuf_size = get_next_required_pcmbuf_size(); + write_chunk = (struct chunkdesc *)pcmbuf_bufend - NUM_CHUNK_DESCS(pcmbuf_size); - voicebuf = (char *)write_chunk - PCMBUF_MIX_CHUNK; + mixchunk[1] = (struct mixdesc *)write_chunk - 1; + mixchunk[0] = (struct mixdesc *)mixchunk[1] - 1; + auxbuf = (char *)mixchunk[0] - AUX_BUFSIZE; #ifdef HAVE_CROSSFADE - fadebuf = voicebuf - PCMBUF_MIX_CHUNK; - pcmbuffer = fadebuf - pcmbuf_size; + fadebuf = auxbuf - CROSSFADE_BUFSIZE; + mixchunk[1]->addr = fadebuf - PCMBUF_MIX_CHUNK; #else - pcmbuffer = voicebuf - pcmbuf_size; + mixchunk[1]->addr = auxbuf - PCMBUF_MIX_CHUNK; #endif + mixchunk[0]->addr = mixchunk[1]->addr - PCMBUF_MIX_CHUNK; + pcmbuffer = mixchunk[0]->addr - pcmbuf_size; init_pcmbuffers(); @@ -480,6 +513,11 @@ pcmbuf_watermark = PCMBUF_WATERMARK; #endif + mixer_state = MIXER_OFF; + aux_playing = false; + auxbuf_in_use = false; + fade_step = 256; + pcmbuf_play_stop(); return pcmbuf_bufend - pcmbuffer; @@ -532,7 +570,7 @@ #ifdef HAVE_CROSSFADE pcmbuf_is_crossfade_active() || #endif - !pcm_is_playing()) + !pcmbuf_is_playing()) { pcmbuf_play_stop(); return; @@ -582,6 +620,10 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) { + /* Service the mixer before handling pcm chunks */ + if (mixer_state && mixer_interrupt_handler(start, size)) + return; + { struct chunkdesc *pcmbuf_current = read_chunk; /* Take the finished chunk out of circulation */ @@ -602,10 +644,6 @@ 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; - #ifdef HAVE_CROSSFADE /* If we've read over the crossfade chunk while it's still fading */ if (pcmbuf_current == crossfade_chunk) @@ -623,48 +661,79 @@ } { - /* Send the new chunk to the PCM */ + /* Send the new chunk to the DMA */ 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; + last_chunksize = read_chunk->size; + pcmbuf_unplayed_bytes -= last_chunksize; + /* if mixing, don't update DMA pointers */ + if (mixer_state == MIXER_OFF) + { + *size = last_chunksize; + *start = read_chunk->addr; + } } else { /* No more chunks */ logf("pcmbuf_pcm_callback: no more chunks"); last_chunksize = 0; - *size = 0; - *start = NULL; + pcmbuf_playing = false; + if (mixer_state == MIXER_OFF) + { + *size = 0; + *start = NULL; + } } } DISPLAY_DESC("callback"); } +bool pcmbuf_is_playing(void) +{ + return pcmbuf_playing && pcm_is_playing(); +} + +bool pcmbuf_is_paused(void) +{ + return pcmbuf_paused; +} + +static inline bool pcmbuf_playing_now(void) +{ + return pcmbuf_playing && !pcmbuf_paused; +} + /* Force playback */ void pcmbuf_play_start(void) { - if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) + if (!pcmbuf_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) { logf("pcmbuf_play_start"); last_chunksize = read_chunk->size; pcmbuf_unplayed_bytes -= last_chunksize; - pcm_play_data(pcmbuf_pcm_callback, - (unsigned char *)read_chunk->addr, last_chunksize); + pcmbuf_playing = true; + pcmbuf_paused = false; + if (!aux_playing) + { + pcm_play_data(pcmbuf_pcm_callback, + read_chunk->addr, last_chunksize); + } } } void pcmbuf_play_stop(void) { logf("pcmbuf_play_stop"); - pcm_play_stop(); + pcmbuf_playing = false; + pcmbuf_paused = false; + if (!aux_playing) + { + /* stop all playback */ + 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; @@ -688,10 +757,34 @@ void pcmbuf_pause(bool pause) { logf("pcmbuf_pause: %s", pause?"pause":"play"); - if (pcm_is_playing()) - pcm_play_pause(!pause); + if (pcmbuf_is_playing()) + { + pcmbuf_paused = pause; + if (aux_playing) + { + if (pause) + { + /* TODO: save pcmbuf state and play only aux */ + } + else + { + /* TODO: resume pcmbuf and mix with aux */ + } + } + else + /* can use pcm function to perform pause */ + pcm_play_pause(!pause); + } else if (!pause) - pcmbuf_play_start(); + { + if (aux_playing) + { + /* TODO: start pcmbuf and mix with aux */ + } + else + /* start only pcmbuf */ + pcmbuf_play_start(); + } } @@ -705,7 +798,6 @@ return sample; } -#ifdef HAVE_CROSSFADE /* Find the chunk that's (length) deep in the list. Return the position within * the chunk, and leave the chunkdesc pointer pointing to the chunk. */ static size_t find_chunk(size_t length, struct chunkdesc **chunk) @@ -718,6 +810,7 @@ return length / 2; } +#ifdef HAVE_CROSSFADE /* Returns the number of bytes _NOT_ mixed/faded */ static size_t crossfade_mix_fade(int factor, size_t length, const char *buf, size_t *out_sample, struct chunkdesc **out_chunk) @@ -985,99 +1078,239 @@ #endif /* HAVE_CROSSFADE */ -/** Voice */ +/** Aux playback */ -/* Returns pcm buffer usage in percents (0 to 100). */ -static int pcmbuf_usage(void) +void *pcmbuf_request_aux_buffer(int *count) { - return pcmbuf_unplayed_bytes * 100 / pcmbuf_size; -} - -static int pcmbuf_mix_free(void) -{ - if (mix_chunk) + if (!auxbuf_in_use) { - size_t my_mix_end = - (size_t)&((int16_t *)mix_chunk->addr)[pcmbuf_mix_sample]; - size_t my_write_pos = (size_t)&pcmbuffer[pcmbuffer_pos]; - if (my_write_pos < my_mix_end) - my_write_pos += pcmbuf_size; - return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes; + *count = MIN(*count, AUX_BUFSIZE/4); + return auxbuf; } - return 100; + + return NULL; } -void *pcmbuf_request_voice_buffer(int *count) +/* Commit aux buffer for playback */ +void pcmbuf_write_aux_complete(int count) { - /* A get-it-to-work-for-now hack (audio status could change by - completion) */ - if (audio_status() & AUDIO_STATUS_PLAY) + size_t bytes = (unsigned int)count << 2; + auxbuf_in_use = true; + + if (aux_playing) { - if (read_chunk == NULL) + /* if no room in mix buffer, wait for mixer to switch buffers */ + while ((bytes + FILL_BUF->size) > PCMBUF_MIX_CHUNK) + sleep(1); + } + else + { + /* new aux insert, start with mix buffer 0 */ + logf("pcmbuf: new aux insert"); + mixbuf = 0; + FILL_BUF->size = 0; + FILL_BUF->pcmoffset = 0; + if (pcmbuf_playing) { - return NULL; + /* update pcm chunk with current location */ + pcm_play_pause(false); + size_t chunk_played = read_chunk->size - pcm_get_bytes_waiting(); + read_chunk->addr += chunk_played; + read_chunk->size -= chunk_played; } - else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 && - (mix_chunk || read_chunk->link)) + + if (pcmbuf_playing_now()) { - *count = MIN(*count, PCMBUF_MIX_CHUNK/4); - return voicebuf; + /* we're already playing something, so resume playback right away, + we'll be adding to the aux buffer in the meantime */ + logf("MIXER_FADEOUT"); + mixer_state = MIXER_FADEOUT_PCM; + pcmbuf_aux_play(); } else { - return NULL; + /* we're going to add to the aux buffer before starting playback */ + logf("MIXER_ON"); + mixer_state = MIXER_ON; } } - else + + /* Start mixing */ + pcm_play_lock(); + + if (pcmbuf_playing_now()) { - return pcmbuf_request_buffer(count); + /* mix pcm + aux */ + while (bytes && read_chunk) + { + /* only mix until end of pcm chunk or end of buffer */ + struct chunkdesc *this_chunk = read_chunk; + size_t this_size = MIN(this_chunk->size - FILL_BUF->pcmoffset, + PCMBUF_MIX_CHUNK - FILL_BUF->size); + if (this_size > bytes) + this_size = bytes; + size_t this_count = this_size >> 2; + + int16_t *inbuf1 = (int16_t *)(this_chunk->addr + FILL_BUF->pcmoffset); + int16_t *inbuf2 = (int16_t *)auxbuf; + int16_t *outbuf = (int16_t *)(FILL_BUF->addr + FILL_BUF->size); + + /* aux always played at full volume, pcm is played at -6db */ + while (this_count--) + { + *outbuf++ = clip_sample_16((*inbuf1++ >> 2) + *inbuf2++); + *outbuf++ = clip_sample_16((*inbuf1++ >> 2) + *inbuf2++); + } + FILL_BUF->size += this_size; + FILL_BUF->pcmoffset += this_size; + bytes -= this_size; + + /* test for end of chunk */ + if (this_chunk->size == FILL_BUF->pcmoffset) + { + logf("pcmbuf: mixed end of chunk"); + /* need to wait for this chunk to be played back */ + pcm_play_unlock(); + while (this_chunk == read_chunk) + sleep(1); + pcm_play_lock(); + } + } } + + /* separate test in case the mix above ran out of pcm chunks */ + if (bytes && !pcmbuf_playing_now()) + { + /* only play aux */ + memcpy(FILL_BUF->addr + FILL_BUF->size, auxbuf, bytes); + FILL_BUF->size += bytes; + } + /* start playing if buffer full */ + if (FILL_BUF->size == PCMBUF_MIX_CHUNK) + pcmbuf_aux_play(); + + pcm_play_unlock(); + auxbuf_in_use = false; } -void pcmbuf_write_voice_complete(int count) +/* start aux playback */ +void pcmbuf_aux_play(void) { - /* A get-it-to-work-for-now hack (audio status could have changed) */ - if (!(audio_status() & AUDIO_STATUS_PLAY)) + /* start aux playback by forcing an immediate DMA ISR callback */ + if (!aux_playing) { - pcmbuf_write_complete(count); - return; + logf("pcmbuf_aux_play"); + pcm_play_data(pcmbuf_pcm_callback, NULL, 0); } +} - int16_t *ibuf = (int16_t *)voicebuf; - int16_t *obuf; - size_t chunk_samples; +/* stop aux playback */ +void pcmbuf_aux_stop(void) +{ + mixer_state = pcmbuf_playing_now() ? MIXER_FADEIN_PCM : MIXER_OFF; + logf("pcmbuf_aux_stop: %s", mixer_state ? "FADEIN" : "OFF"); + aux_playing = false; +} - if (mix_chunk == NULL && read_chunk != NULL) - { - mix_chunk = read_chunk->link; - /* Start 1/8s into the next chunk */ - pcmbuf_mix_sample = BYTERATE / 16; - } +bool pcmbuf_aux_is_playing(void) +{ + return aux_playing; +} - if (!mix_chunk) - return; - - obuf = (int16_t *)mix_chunk->addr; - chunk_samples = mix_chunk->size / sizeof (int16_t); - - count <<= 1; - - while (count-- > 0) +/* Operate the mixer during DMA ISR callback + Returns true if pcm chunk processing isn't needed */ +static bool mixer_interrupt_handler(unsigned char** start, size_t* size) +{ + switch (mixer_state) { - int32_t sample = *ibuf++; - - if (pcmbuf_mix_sample >= chunk_samples) + case MIXER_FADEOUT_PCM: + fade_step -= 12; + /* fade_step -6, fall through */ +mixer_fadein: + case MIXER_FADEIN_PCM: + fade_step += 6; + if ((fade_step > 64) && (fade_step < 256)) + { + /* fade a small chunk of pcmbuf and put into mix buffer 1 */ + size_t chunk_size = MIN(read_chunk->size, AUX_BUFSIZE); + int count = chunk_size >> 2; + int16_t *inbuf = (int16_t *)read_chunk->addr; + int16_t *outbuf = (int16_t *)mixchunk[1]->addr; + while (count--) + { + *outbuf++ = (int16_t)((int32_t)(*inbuf++ * fade_step) >> 8); + *outbuf++ = (int16_t)((int32_t)(*inbuf++ * fade_step) >> 8); + } + /* play mix buffer 1 */ + *size = chunk_size; + *start = mixchunk[1]->addr; + /* update the pcm chunk to show that part has been played */ + read_chunk->addr += chunk_size; + read_chunk->size -= chunk_size; + /* process next pcm chunk if this one has played out */ + return (read_chunk->size > 0); + } + + if (fade_step >= 256) + { + /* done fading in, stop mixing */ + logf ("FADE_IN -> OFF"); + fade_step = 256; + break; + } + + /* done fading out, start mixer */ + fade_step = 64; + mixer_state = MIXER_ON; + /* always start from mix buffer 0 */ + mixbuf = 0; + logf("FADE_OUT -> ON"); + /* fall through */ + case MIXER_ON: { - mix_chunk = mix_chunk->link; - if (!mix_chunk) - return; - pcmbuf_mix_sample = 0; - obuf = mix_chunk->addr; - chunk_samples = mix_chunk->size / 2; + /* switch mix buffers & init next buffer */ + mixbuf = 1 - mixbuf; + FILL_BUF->size = 0; + FILL_BUF->pcmoffset = 0; + aux_playing = true; + + /* play buffered mix */ + size_t chunk_size = PLAY_BUF->size; + if (chunk_size) + { + /* feed new buffer to DMA */ + *size = PLAY_BUF->size; + *start = PLAY_BUF->addr; + if (pcmbuf_playing_now()) + { + /* update pcm chunk */ + read_chunk->addr += chunk_size; + read_chunk->size -= chunk_size; + return (read_chunk->size > 0); + } + return true; + } + + /* nothing buffered */ + break; } - sample += obuf[pcmbuf_mix_sample] >> 2; - obuf[pcmbuf_mix_sample++] = clip_sample_16(sample); + } /* switch */ + + /* done mixing */ + aux_playing = false; + if (pcmbuf_playing_now() && (fade_step != 256)) + { + /* continue pcmbuf playback */ + logf("ON -> FADE_IN"); + mixer_state = MIXER_FADEIN_PCM; + goto mixer_fadein; } + /* stop all playback */ + logf("MIXER_OFF"); + mixer_state = MIXER_OFF; + *size = 0; + *start = NULL; + return true; } @@ -1088,7 +1321,7 @@ { if (read_chunk != NULL) { - void *read = read_chunk->addr; + void *read = (void *)read_chunk->addr; void *write = &pcmbuffer[pcmbuffer_pos + pcmbuffer_fillpos]; if (read < write) return (size_t)(read - write) + pcmbuf_size; @@ -1132,7 +1365,7 @@ bool pcmbuf_is_lowdata(void) { - if (!pcm_is_playing() || pcm_is_paused() + if (!pcmbuf_is_playing() || pcmbuf_paused #ifdef HAVE_CROSSFADE || pcmbuf_is_crossfade_active() #endif @@ -1259,3 +1492,7 @@ #endif } #endif /* HAVE_HARDWARE_BEEP */ + + +/** Mixer */ + Index: apps/pcmbuf.h =================================================================== --- apps/pcmbuf.h (revision 25767) +++ apps/pcmbuf.h (working copy) @@ -32,7 +32,9 @@ void pcmbuf_play_start(void); void pcmbuf_play_stop(void); void pcmbuf_pause(bool pause); -void pcmbuf_start_track_change(bool manual_skip); +void pcmbuf_start_track_change(bool auto_skip); +bool pcmbuf_is_playing(void); +bool pcmbuf_is_paused(void); /* Crossfade */ #ifdef HAVE_CROSSFADE @@ -41,9 +43,12 @@ bool pcmbuf_is_same_size(void); #endif -/* Voice */ -void *pcmbuf_request_voice_buffer(int *count); -void pcmbuf_write_voice_complete(int count); +/* Aux playback */ +void *pcmbuf_request_aux_buffer(int *count); +void pcmbuf_write_aux_complete(int count); +void pcmbuf_aux_play(void); +void pcmbuf_aux_stop(void); +bool pcmbuf_aux_is_playing(void); /* Debug menu, other metrics */ size_t pcmbuf_free(void); Index: apps/codec_thread.c =================================================================== --- apps/codec_thread.c (revision 25767) +++ apps/codec_thread.c (working copy) @@ -332,11 +332,11 @@ static void codec_seek_complete_callback(void) { logf("seek_complete"); - /* If seeking-while-playing, pcm_is_paused() is true. + /* If seeking-while-playing, pcmbuf_is_paused() is true. * If seeking-while-paused, audio_status PAUSE is true. * A seamless seek skips this section. */ bool audio_paused = audio_status() & AUDIO_STATUS_PAUSE; - if (pcm_is_paused() || audio_paused) + if (pcmbuf_is_paused() || audio_paused) { /* Clear the buffer */ pcmbuf_play_stop(); @@ -498,7 +498,7 @@ if (*get_codec_hid() < 0) { logf("Codec slot is empty!"); /* Wait for the pcm buffer to go empty */ - while (pcm_is_playing()) + while (pcmbuf_is_playing()) yield(); /* This must be set to prevent an infinite loop */ ci.stop_codec = true; @@ -580,7 +580,7 @@ { /* Wait for the audio to stop playing before * triggering the WPS exit */ - while(pcm_is_playing()) + while(pcmbuf_is_playing()) { /* There has been one too many struct pointer swaps by now * so even though it says othertrack_id3, its the correct one! */ Index: apps/playback.c =================================================================== --- apps/playback.c (revision 25767) +++ apps/playback.c (working copy) @@ -1656,7 +1656,7 @@ /* If the audio codec is not loaded any more, and the audio is still * playing, it is now and _only_ now safe to call this function from the * audio thread */ - if (pcm_is_playing()) + if (pcmbuf_is_playing()) { pcmbuf_play_stop(); pcm_play_lock(); Index: apps/voice_thread.c =================================================================== --- apps/voice_thread.c (revision 25767) +++ apps/voice_thread.c (working copy) @@ -105,12 +105,6 @@ int count; /* Count of samples remaining to send to PCM */ }; -/* Audio playback is in a playing state? */ -static inline bool playback_is_playing(void) -{ - return (audio_status() & AUDIO_STATUS_PLAY) != 0; -} - /* Stop any current clip and start playing a new one */ void mp3_play_data(const unsigned char* start, int size, pcm_more_callback_type get_more) @@ -190,8 +184,7 @@ * new clip by the time we wait. This should be resolvable if conditions * ever require knowing the very clip you requested has finished. */ - /* Wait for PCM buffer to be exhausted. Works only if not playing. */ - while(!voice_done || (!playback_is_playing() && pcm_is_playing())) + while(!voice_done || pcmbuf_aux_is_playing()) sleep(1); } @@ -235,10 +228,10 @@ /* Boost CPU now */ trigger_cpu_boost(); } - else if (!playback_is_playing()) + else { - /* Just voice, stop any clip still playing */ - pcmbuf_play_stop(); + /* Stop any clip still playing */ + pcmbuf_aux_stop(); } /* Clean-start the decoder */ @@ -254,10 +247,9 @@ case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP: %d", ev.data); - if (td->ev.data != 0 && !playback_is_playing()) + if (td->ev.data != 0) { - /* If not playing, it's just voice so stop pcm playback */ - pcmbuf_play_stop(); + pcmbuf_aux_stop(); } /* Cancel boost */ @@ -356,10 +348,6 @@ goto voice_decode; } - /* If all clips are done and not playing, force pcm playback. */ - if (!pcm_is_playing()) - pcmbuf_play_start(); - /* Synthesize a stop request */ /* NOTE: We have no way to know when the pcm data placed in the * buffer is actually consumed and playback has reached the end @@ -396,7 +384,7 @@ if (!queue_empty(&voice_queue)) goto message_wait; - if ((dest = pcmbuf_request_voice_buffer(&out_count)) != NULL) + if ((dest = pcmbuf_request_aux_buffer(&out_count)) != NULL) break; yield(); @@ -419,10 +407,11 @@ if (out_count <= 0) break; - pcmbuf_write_voice_complete(out_count); + pcmbuf_write_aux_complete(out_count); td.count -= inp_count; } - + + pcmbuf_aux_play(); yield(); } /* end while */ } /* voice_thread */ Index: firmware/pcm.c =================================================================== --- firmware/pcm.c (revision 25767) +++ firmware/pcm.c (working copy) @@ -23,7 +23,7 @@ #include "kernel.h" /* Define LOGF_ENABLE to enable logf output in this file */ -/*#define LOGF_ENABLE*/ +#define LOGF_ENABLE #include "logf.h" #include "audio.h" #include "sound.h"