Fix FS#9507 - video audio is not played if song is paused. Audio was not being unmute...
[kugel-rb.git] / apps / pcmbuf.c
bloba25723a299bccc590350e38fec6302617a8d689a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Miika Pekkarinen
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include "config.h"
25 #include "debug.h"
26 #include "panic.h"
27 #include <kernel.h>
28 #include "pcmbuf.h"
29 #include "pcm.h"
30 #include "logf.h"
31 #ifndef SIMULATOR
32 #include "cpu.h"
33 #endif
34 #include "system.h"
35 #include <string.h>
36 #include "buffer.h"
37 #include "settings.h"
38 #include "audio.h"
39 #include "voice_thread.h"
40 #include "dsp.h"
41 #include "thread.h"
43 /* Clip sample to signed 16 bit range */
44 static inline int32_t clip_sample_16(int32_t sample)
46 if ((int16_t)sample != sample)
47 sample = 0x7fff ^ (sample >> 31);
48 return sample;
51 /* Keep watermark high for iPods at least (2s) */
52 #define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 4 * 2)
54 /* Structure we can use to queue pcm chunks in memory to be played
55 * by the driver code. */
56 struct pcmbufdesc
58 void *addr;
59 size_t size;
60 struct pcmbufdesc* link;
61 /* Call this when the buffer has been played */
62 void (*callback)(void);
65 #define PCMBUF_DESCS(bufsize) \
66 ((bufsize) / PCMBUF_MINAVG_CHUNK)
67 #define PCMBUF_DESCS_SIZE(bufsize) \
68 (PCMBUF_DESCS(bufsize)*sizeof(struct pcmbufdesc))
70 /* Size of the PCM buffer. */
71 static size_t pcmbuf_size IDATA_ATTR = 0;
72 static char *pcmbuf_bufend IDATA_ATTR;
73 static char *audiobuffer IDATA_ATTR;
74 /* Current audio buffer write index. */
75 static size_t audiobuffer_pos IDATA_ATTR;
76 /* Amount audiobuffer_pos will be increased.*/
77 static size_t audiobuffer_fillpos IDATA_ATTR;
78 static char *fadebuf IDATA_ATTR;
79 static char *voicebuf IDATA_ATTR;
81 static void (*pcmbuf_event_handler)(void) IDATA_ATTR;
82 static void (*position_callback)(size_t size) IDATA_ATTR;
84 /* Crossfade related state */
85 static bool crossfade_enabled;
86 static bool crossfade_enabled_pending;
87 static bool crossfade_mixmode;
88 static bool crossfade_active IDATA_ATTR;
89 static bool crossfade_init IDATA_ATTR;
91 /* Track the current location for processing crossfade */
92 static struct pcmbufdesc *crossfade_chunk IDATA_ATTR;
93 static size_t crossfade_sample IDATA_ATTR;
95 /* Counters for fading in new data */
96 static size_t crossfade_fade_in_total IDATA_ATTR;
97 static size_t crossfade_fade_in_rem IDATA_ATTR;
99 static struct pcmbufdesc *pcmbuf_read IDATA_ATTR;
100 static struct pcmbufdesc *pcmbuf_read_end IDATA_ATTR;
101 static struct pcmbufdesc *pcmbuf_write IDATA_ATTR;
102 static struct pcmbufdesc *pcmbuf_write_end IDATA_ATTR;
103 static size_t last_chunksize IDATA_ATTR;
105 static size_t pcmbuf_unplayed_bytes IDATA_ATTR;
106 static size_t pcmbuf_watermark IDATA_ATTR;
108 static struct pcmbufdesc *pcmbuf_mix_chunk IDATA_ATTR;
109 static size_t pcmbuf_mix_sample IDATA_ATTR;
111 static bool low_latency_mode = false;
112 static bool pcmbuf_flush;
114 #ifdef HAVE_PRIORITY_SCHEDULING
115 static int codec_thread_priority = PRIORITY_PLAYBACK;
116 #endif
118 extern struct thread_entry *codec_thread_p;
120 /* Helpful macros for use in conditionals this assumes some of the above
121 * static variable names */
122 #define NEED_FLUSH(position) \
123 (audiobuffer_fillpos > PCMBUF_TARGET_CHUNK || position >= pcmbuf_size)
124 #define LOW_DATA(quarter_secs) \
125 (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs)
127 static bool prepare_insert(size_t length);
128 static void pcmbuf_under_watermark(void);
129 static bool pcmbuf_flush_fillpos(void);
131 #define CALL_IF_EXISTS(function, args...) if (function) function(args)
132 /* This function has 2 major logical parts (separated by brackets both for
133 * readability and variable scoping). The first part performs the
134 * operastions related to finishing off the last buffer we fed to the DMA.
135 * The second part performs the operations involved in sending a new buffer
136 * to the DMA. Finally the function checks the status of the buffer and
137 * boosts if necessary */
138 static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR;
139 static void pcmbuf_callback(unsigned char** start, size_t* size)
142 struct pcmbufdesc *pcmbuf_current = pcmbuf_read;
143 /* Take the finished buffer out of circulation */
144 pcmbuf_read = pcmbuf_current->link;
146 /* The buffer is finished, call the callback functions */
147 CALL_IF_EXISTS(position_callback, last_chunksize);
148 CALL_IF_EXISTS(pcmbuf_current->callback);
150 /* Put the finished buffer back into circulation */
151 pcmbuf_write_end->link = pcmbuf_current;
152 pcmbuf_write_end = pcmbuf_current;
154 /* If we've read over the mix chunk while it's still mixing there */
155 if (pcmbuf_current == pcmbuf_mix_chunk)
156 pcmbuf_mix_chunk = NULL;
157 /* If we've read over the crossfade chunk while it's still fading */
158 if (pcmbuf_current == crossfade_chunk)
159 crossfade_chunk = pcmbuf_read;
163 /* Send the new buffer to the pcm */
164 struct pcmbufdesc *pcmbuf_new = pcmbuf_read;
165 size_t *realsize = size;
166 unsigned char** realstart = start;
167 if(pcmbuf_new)
169 size_t current_size = pcmbuf_new->size;
171 pcmbuf_unplayed_bytes -= current_size;
172 last_chunksize = current_size;
173 *realsize = current_size;
174 *realstart = pcmbuf_new->addr;
176 else
178 /* No more buffers */
179 last_chunksize = 0;
180 *realsize = 0;
181 *realstart = NULL;
182 CALL_IF_EXISTS(pcmbuf_event_handler);
187 void pcmbuf_set_position_callback(void (*callback)(size_t size))
189 position_callback = callback;
192 static void pcmbuf_set_watermark_bytes(void)
194 pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
195 /* If crossfading, try to keep the buffer full other than 1 second */
196 (pcmbuf_size - (NATIVE_FREQUENCY * 4 * 1)) :
197 /* Otherwise, just keep it above 2 second */
198 PCMBUF_WATERMARK;
201 /* This is really just part of pcmbuf_flush_fillpos, but is easier to keep
202 * in a separate function for the moment */
203 static inline void pcmbuf_add_chunk(void)
205 register size_t size = audiobuffer_fillpos;
206 /* Grab the next description to write, and change the write pointer */
207 register struct pcmbufdesc *pcmbuf_current = pcmbuf_write;
208 pcmbuf_write = pcmbuf_current->link;
209 /* Fill in the values in the new buffer chunk */
210 pcmbuf_current->addr = &audiobuffer[audiobuffer_pos];
211 pcmbuf_current->size = size;
212 pcmbuf_current->callback = pcmbuf_event_handler;
213 pcmbuf_current->link = NULL;
214 /* This is single use only */
215 pcmbuf_event_handler = NULL;
216 if (pcmbuf_read != NULL) {
217 if (pcmbuf_flush)
219 pcmbuf_write_end->link = pcmbuf_read->link;
220 pcmbuf_read->link = pcmbuf_current;
221 while (pcmbuf_write_end->link)
223 pcmbuf_write_end = pcmbuf_write_end->link;
224 pcmbuf_unplayed_bytes -= pcmbuf_write_end->size;
226 pcmbuf_flush = false;
228 /* If there is already a read buffer setup, add to it */
229 else
230 pcmbuf_read_end->link = pcmbuf_current;
231 } else {
232 /* Otherwise create the buffer */
233 pcmbuf_read = pcmbuf_current;
235 /* This is now the last buffer to read */
236 pcmbuf_read_end = pcmbuf_current;
238 /* Update bytes counters */
239 pcmbuf_unplayed_bytes += size;
241 audiobuffer_pos += size;
242 if (audiobuffer_pos >= pcmbuf_size)
243 audiobuffer_pos -= pcmbuf_size;
245 audiobuffer_fillpos = 0;
248 #ifdef HAVE_PRIORITY_SCHEDULING
249 static void boost_codec_thread(bool boost)
251 /* Keep voice and codec threads at the same priority or else voice
252 * will starve if the codec thread's priority is boosted. */
253 if (boost)
255 int priority = (PRIORITY_PLAYBACK - PRIORITY_PLAYBACK_MAX)*pcmbuf_unplayed_bytes
256 / (2*NATIVE_FREQUENCY) + PRIORITY_PLAYBACK_MAX;
258 if (priority != codec_thread_priority)
260 codec_thread_priority = priority;
261 thread_set_priority(codec_thread_p, priority);
262 voice_thread_set_priority(priority);
265 else if (codec_thread_priority != PRIORITY_PLAYBACK)
267 thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK);
268 voice_thread_set_priority(PRIORITY_PLAYBACK);
269 codec_thread_priority = PRIORITY_PLAYBACK;
272 #endif /* HAVE_PRIORITY_SCHEDULING */
274 static void pcmbuf_under_watermark(void)
276 /* Only codec thread initiates boost - voice boosts the cpu when playing
277 a clip */
278 #ifndef SIMULATOR
279 if (thread_get_current() == codec_thread_p)
280 #endif /* SIMULATOR */
282 #ifdef HAVE_PRIORITY_SCHEDULING
283 /* If buffer is critically low, override UI priority, else
284 set back to the original priority. */
285 boost_codec_thread(LOW_DATA(2) && pcm_is_playing());
286 #endif
287 /* Fill audio buffer by boosting cpu */
288 trigger_cpu_boost();
291 /* Disable crossfade if < .5s of audio */
292 if (LOW_DATA(2))
294 crossfade_active = false;
298 void pcmbuf_set_event_handler(void (*event_handler)(void))
300 pcmbuf_event_handler = event_handler;
303 unsigned int pcmbuf_get_latency(void)
305 /* Be careful how this calculation is rearranged, it's easy to overflow */
306 size_t bytes = pcmbuf_unplayed_bytes + pcm_get_bytes_waiting();
307 return bytes / 4 / (NATIVE_FREQUENCY/1000);
310 void pcmbuf_set_low_latency(bool state)
312 low_latency_mode = state;
315 bool pcmbuf_is_lowdata(void)
317 if (!pcm_is_playing() || pcm_is_paused() ||
318 crossfade_init || crossfade_active)
319 return false;
321 /* 1 seconds of buffer is low data */
322 return LOW_DATA(4);
325 /* Amount of bytes left in the buffer. */
326 inline size_t pcmbuf_free(void)
328 if (pcmbuf_read != NULL)
330 void *read = pcmbuf_read->addr;
331 void *write = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
332 if (read < write)
333 return (size_t)(read - write) + pcmbuf_size;
334 else
335 return (size_t) (read - write);
337 return pcmbuf_size;
340 bool pcmbuf_crossfade_init(bool manual_skip)
342 /* Can't do two crossfades at once and, no fade if pcm is off now */
343 if (crossfade_init || crossfade_active || !pcm_is_playing())
345 pcmbuf_play_stop();
346 return false;
349 trigger_cpu_boost();
351 /* Not enough data, or crossfade disabled, flush the old data instead */
352 if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode)
354 pcmbuf_flush_fillpos();
355 pcmbuf_flush = true;
356 return false;
359 /* Don't enable mix mode when skipping tracks manually. */
360 if (manual_skip)
361 crossfade_mixmode = false;
362 else
363 crossfade_mixmode = global_settings.crossfade_fade_out_mixmode;
365 crossfade_init = true;
367 return true;
371 void pcmbuf_play_stop(void)
373 pcm_play_stop();
375 pcmbuf_unplayed_bytes = 0;
376 pcmbuf_mix_chunk = NULL;
377 if (pcmbuf_read) {
378 pcmbuf_write_end->link = pcmbuf_read;
379 pcmbuf_write_end = pcmbuf_read_end;
380 pcmbuf_read = pcmbuf_read_end = NULL;
382 audiobuffer_pos = 0;
383 audiobuffer_fillpos = 0;
384 crossfade_init = false;
385 crossfade_active = false;
386 pcmbuf_flush = false;
388 #ifdef HAVE_PRIORITY_SCHEDULING
389 /* Can unboost the codec thread here no matter who's calling */
390 boost_codec_thread(false);
391 #endif
394 int pcmbuf_used_descs(void) {
395 struct pcmbufdesc *pcmbuf_temp = pcmbuf_read;
396 unsigned int i = 0;
397 while (pcmbuf_temp) {
398 pcmbuf_temp = pcmbuf_temp->link;
399 i++;
401 return i;
404 int pcmbuf_descs(void) {
405 return PCMBUF_DESCS(pcmbuf_size);
408 static void pcmbuf_init_pcmbuffers(void) {
409 struct pcmbufdesc *next = pcmbuf_write;
410 next++;
411 pcmbuf_write_end = pcmbuf_write;
412 while ((void *)next < (void *)pcmbuf_bufend) {
413 pcmbuf_write_end->link=next;
414 pcmbuf_write_end=next;
415 next++;
419 static size_t pcmbuf_get_next_required_pcmbuf_size(void)
421 #if MEM > 1
422 size_t seconds = 1;
424 if (crossfade_enabled_pending)
425 seconds += global_settings.crossfade_fade_out_delay
426 + global_settings.crossfade_fade_out_duration;
428 /* Buffer has to be at least 2s long. */
429 seconds += 2;
430 logf("pcmbuf len: %ld", seconds);
431 return seconds * (NATIVE_FREQUENCY*4);
432 #else
433 return NATIVE_FREQUENCY*2;
434 #endif
437 static char *pcmbuf_calc_audiobuffer_ptr(size_t bufsize)
439 return pcmbuf_bufend - (bufsize + PCMBUF_MIX_CHUNK * 2 +
440 PCMBUF_DESCS_SIZE(bufsize));
443 bool pcmbuf_is_same_size(void)
445 if (audiobuffer == NULL)
446 return true; /* Not set up yet even once so always */
448 size_t bufsize = pcmbuf_get_next_required_pcmbuf_size();
449 return pcmbuf_calc_audiobuffer_ptr(bufsize) == audiobuffer;
452 /* Initialize the pcmbuffer the structure looks like this:
453 * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
454 size_t pcmbuf_init(unsigned char *bufend)
456 pcmbuf_bufend = bufend;
457 pcmbuf_size = pcmbuf_get_next_required_pcmbuf_size();
458 audiobuffer = pcmbuf_calc_audiobuffer_ptr(pcmbuf_size);
459 fadebuf = &audiobuffer[pcmbuf_size];
460 voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
461 pcmbuf_write = (struct pcmbufdesc *)&voicebuf[PCMBUF_MIX_CHUNK];
463 pcmbuf_init_pcmbuffers();
465 position_callback = NULL;
466 pcmbuf_event_handler = NULL;
468 pcmbuf_crossfade_enable_finished();
470 pcmbuf_play_stop();
472 return pcmbuf_bufend - audiobuffer;
475 size_t pcmbuf_get_bufsize(void)
477 return pcmbuf_size;
480 #ifdef ROCKBOX_HAS_LOGF
481 unsigned char * pcmbuf_get_meminfo(size_t *length)
483 *length = pcmbuf_bufend - audiobuffer;
484 return audiobuffer;
486 #endif
488 void pcmbuf_pause(bool pause)
490 if (pcm_is_playing())
491 pcm_play_pause(!pause);
492 else if (!pause)
493 pcmbuf_play_start();
496 /* Force playback. */
497 void pcmbuf_play_start(void)
499 if (!pcm_is_playing() && pcmbuf_unplayed_bytes && pcmbuf_read != NULL)
501 last_chunksize = pcmbuf_read->size;
502 pcmbuf_unplayed_bytes -= last_chunksize;
503 pcm_play_data(pcmbuf_callback,
504 (unsigned char *)pcmbuf_read->addr, last_chunksize);
509 * Commit samples waiting to the pcm buffer.
511 static bool pcmbuf_flush_fillpos(void)
513 if (audiobuffer_fillpos) {
514 /* Never use the last buffer descriptor */
515 while (pcmbuf_write == pcmbuf_write_end) {
516 /* If this happens, something is being stupid */
517 if (!pcm_is_playing()) {
518 logf("pcmbuf_flush_fillpos error");
519 pcmbuf_play_start();
521 /* Let approximately one chunk of data playback */
522 sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
524 pcmbuf_add_chunk();
525 return true;
527 return false;
531 * Completely process the crossfade fade out effect with current pcm buffer.
533 static void crossfade_process_buffer(size_t fade_in_delay,
534 size_t fade_out_delay, size_t fade_out_rem)
536 if (!crossfade_mixmode)
538 /* Fade out the specified amount of the already processed audio */
539 size_t total_fade_out = fade_out_rem;
540 size_t fade_out_sample;
541 struct pcmbufdesc *fade_out_chunk = crossfade_chunk;
543 /* Find the right chunk to start fading out */
544 fade_out_delay += crossfade_sample * 2;
545 while (fade_out_delay != 0 && fade_out_delay >= fade_out_chunk->size)
547 fade_out_delay -= fade_out_chunk->size;
548 fade_out_chunk = fade_out_chunk->link;
550 /* The start sample within the chunk */
551 fade_out_sample = fade_out_delay / 2;
553 while (fade_out_rem > 0)
555 /* Each 1/10 second of audio will have the same fade applied */
556 size_t block_rem = MIN(NATIVE_FREQUENCY * 4 / 10, fade_out_rem);
557 int factor = (fade_out_rem << 8) / total_fade_out;
559 fade_out_rem -= block_rem;
561 /* Fade this block */
562 while (block_rem > 0 && fade_out_chunk != NULL)
564 /* Fade one sample */
565 int16_t *buf = (int16_t *)fade_out_chunk->addr;
566 int32_t sample = buf[fade_out_sample];
567 buf[fade_out_sample++] = (sample * factor) >> 8;
569 block_rem -= 2;
570 /* Move to the next chunk as needed */
571 if (fade_out_sample * 2 >= fade_out_chunk->size)
573 fade_out_chunk = fade_out_chunk->link;
574 fade_out_sample = 0;
580 /* Find the right chunk and sample to start fading in */
581 fade_in_delay += crossfade_sample * 2;
582 while (fade_in_delay != 0 && fade_in_delay >= crossfade_chunk->size)
584 fade_in_delay -= crossfade_chunk->size;
585 crossfade_chunk = crossfade_chunk->link;
587 crossfade_sample = fade_in_delay / 2;
588 logf("process done!");
591 /* Initializes crossfader, calculates all necessary parameters and
592 * performs fade-out with the pcm buffer. */
593 static void crossfade_start(void)
595 size_t crossfade_rem;
596 size_t crossfade_need;
597 size_t fade_out_rem;
598 size_t fade_out_delay;
599 size_t fade_in_delay;
601 crossfade_init = false;
602 /* Reject crossfade if less than .5s of data */
603 if (LOW_DATA(2)) {
604 logf("crossfade rejected");
605 pcmbuf_play_stop();
606 return ;
609 logf("crossfade_start");
610 pcmbuf_flush_fillpos();
611 crossfade_active = true;
613 /* Initialize the crossfade buffer size to all of the buffered data that
614 * has not yet been sent to the DMA */
615 crossfade_rem = pcmbuf_unplayed_bytes;
616 crossfade_chunk = pcmbuf_read->link;
617 crossfade_sample = 0;
619 /* Get fade out delay from settings. */
620 fade_out_delay =
621 NATIVE_FREQUENCY * global_settings.crossfade_fade_out_delay * 4;
623 /* Get fade out duration from settings. */
624 fade_out_rem =
625 NATIVE_FREQUENCY * global_settings.crossfade_fade_out_duration * 4;
627 crossfade_need = fade_out_delay + fade_out_rem;
628 /* We want only to modify the last part of the buffer. */
629 if (crossfade_rem > crossfade_need)
631 size_t crossfade_extra = crossfade_rem - crossfade_need;
632 while (crossfade_extra > crossfade_chunk->size)
634 crossfade_extra -= crossfade_chunk->size;
635 crossfade_chunk = crossfade_chunk->link;
637 crossfade_sample = crossfade_extra / 2;
639 /* Truncate fade out duration if necessary. */
640 else if (crossfade_rem < crossfade_need)
642 size_t crossfade_short = crossfade_need - crossfade_rem;
643 if (fade_out_rem >= crossfade_short)
644 fade_out_rem -= crossfade_short;
645 else
647 fade_out_delay -= crossfade_short - fade_out_rem;
648 fade_out_rem = 0;
652 /* Get also fade in duration and delays from settings. */
653 crossfade_fade_in_total =
654 NATIVE_FREQUENCY * global_settings.crossfade_fade_in_duration * 4;
655 crossfade_fade_in_rem = crossfade_fade_in_total;
657 fade_in_delay =
658 NATIVE_FREQUENCY * global_settings.crossfade_fade_in_delay * 4;
660 crossfade_process_buffer(fade_in_delay, fade_out_delay, fade_out_rem);
663 /* Returns the number of bytes _NOT_ mixed */
664 static size_t crossfade_fade_mix(int factor, const char *buf, size_t fade_rem)
666 const int16_t *input_buf = (const int16_t *)buf;
667 int16_t *output_buf = (int16_t *)(crossfade_chunk->addr);
668 int16_t *chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
669 output_buf = &output_buf[crossfade_sample];
670 int32_t sample;
672 while (fade_rem)
674 /* fade left and right channel at once to keep buffer alignment */
675 sample = *input_buf++;
676 sample = ((sample * factor) >> 8) + *output_buf;
677 *output_buf++ = clip_sample_16(sample);
679 sample = *input_buf++;
680 sample = ((sample * factor) >> 8) + *output_buf;
681 *output_buf++ = clip_sample_16(sample);
683 fade_rem -= 4; /* 2 samples, each 16 bit -> 4 bytes */
685 if (output_buf >= chunk_end)
687 crossfade_chunk = crossfade_chunk->link;
688 if (!crossfade_chunk)
689 return fade_rem;
690 output_buf = (int16_t *)crossfade_chunk->addr;
691 chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
694 crossfade_sample = output_buf - (int16_t *)crossfade_chunk->addr;
695 return 0;
698 /* Returns the number of bytes _NOT_ mixed */
699 static size_t crossfade_mix(const char *buf, size_t length)
701 const int16_t *input_buf = (const int16_t *)buf;
702 int16_t *output_buf = (int16_t *)crossfade_chunk->addr;
703 int16_t *chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
704 output_buf = &output_buf[crossfade_sample];
705 int32_t sample;
707 while (length)
709 /* fade left and right channel at once to keep buffer alignment */
710 sample = *input_buf++ + *output_buf;
711 *output_buf++ = clip_sample_16(sample);
713 sample = *input_buf++ + *output_buf;
714 *output_buf++ = clip_sample_16(sample);
716 length -= 4; /* 2 samples, each 16 bit -> 4 bytes */
718 if (output_buf >= chunk_end)
720 crossfade_chunk = crossfade_chunk->link;
721 if (!crossfade_chunk)
722 return length;
724 output_buf = (int16_t *)crossfade_chunk->addr;
725 chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
728 crossfade_sample = output_buf - (int16_t *)crossfade_chunk->addr;
729 return 0;
732 static void pcmbuf_flush_buffer(const char *buf, size_t length)
734 size_t copy_n;
735 while (length > 0) {
736 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
737 if (NEED_FLUSH(audiobuffer_index))
739 pcmbuf_flush_fillpos();
740 audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
742 copy_n = MIN(length, pcmbuf_size - audiobuffer_index);
743 memcpy(&audiobuffer[audiobuffer_index], buf, copy_n);
744 buf += copy_n;
745 audiobuffer_fillpos += copy_n;
746 length -= copy_n;
750 static void flush_crossfade(char *buf, size_t length)
752 if (length)
754 if (crossfade_fade_in_rem)
756 size_t samples;
757 int16_t *input_buf;
759 /* Fade factor for this packet */
760 int factor =
761 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
762 crossfade_fade_in_total;
763 /* Bytes to fade */
764 size_t fade_rem = MIN(length, crossfade_fade_in_rem);
766 /* We _will_ fade this many bytes */
767 crossfade_fade_in_rem -= fade_rem;
769 if (crossfade_chunk)
771 /* Mix the data */
772 size_t fade_total = fade_rem;
773 fade_rem = crossfade_fade_mix(factor, buf, fade_rem);
774 length -= fade_total - fade_rem;
775 buf += fade_total - fade_rem;
776 if (!length)
777 return;
778 if (!fade_rem)
779 goto fade_done;
782 samples = fade_rem / 2;
783 input_buf = (int16_t *)buf;
784 /* Fade remaining samples in place */
785 while (samples)
787 int32_t sample = *input_buf;
788 *input_buf++ = (sample * factor) >> 8;
789 samples--;
793 fade_done:
794 if (crossfade_chunk)
796 /* Mix the data */
797 size_t mix_total = length;
798 length = crossfade_mix(buf, length);
799 buf += mix_total - length;
800 if (!length)
801 return;
804 /* Flush samples to the buffer */
805 while (!prepare_insert(length))
806 sleep(1);
807 pcmbuf_flush_buffer(buf, length);
812 static bool prepare_insert(size_t length)
814 if (low_latency_mode)
816 /* 1/4s latency. */
817 if (pcmbuf_unplayed_bytes > NATIVE_FREQUENCY * 4 / 2
818 && pcm_is_playing())
819 return false;
822 /* Need to save PCMBUF_MIN_CHUNK to prevent wrapping overwriting */
823 if (pcmbuf_free() < length + PCMBUF_MIN_CHUNK)
824 return false;
826 if (!pcm_is_playing())
828 trigger_cpu_boost();
830 /* Pre-buffer 1s. */
831 #if MEM <= 1
832 if (!LOW_DATA(1))
833 #else
834 if (!LOW_DATA(4))
835 #endif
837 logf("pcm starting");
838 if (!(audio_status() & AUDIO_STATUS_PAUSE))
839 pcmbuf_play_start();
842 else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
843 pcmbuf_under_watermark();
845 return true;
848 void* pcmbuf_request_buffer(int *count)
850 if (crossfade_init)
851 crossfade_start();
853 if (crossfade_active) {
854 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
855 return fadebuf;
857 else
859 if(prepare_insert(*count << 2))
861 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
862 if (pcmbuf_size - audiobuffer_index >= PCMBUF_MIN_CHUNK)
864 /* Usual case, there's space here */
865 return &audiobuffer[audiobuffer_index];
867 else
869 /* Flush and wrap the buffer */
870 pcmbuf_flush_fillpos();
871 audiobuffer_pos = 0;
872 return &audiobuffer[0];
875 else
877 return NULL;
882 void * pcmbuf_request_voice_buffer(int *count)
884 /* A get-it-to-work-for-now hack (audio status could change by
885 completion) */
886 if (audio_status() & AUDIO_STATUS_PLAY)
888 if (pcmbuf_read == NULL)
890 return NULL;
892 else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 &&
893 (pcmbuf_mix_chunk || pcmbuf_read->link))
895 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
896 return voicebuf;
898 else
900 return NULL;
903 else
905 return pcmbuf_request_buffer(count);
909 bool pcmbuf_is_crossfade_active(void)
911 return crossfade_active || crossfade_init;
914 void pcmbuf_write_complete(int count)
916 size_t length = (size_t)(unsigned int)count << 2;
918 if (crossfade_active)
920 flush_crossfade(fadebuf, length);
921 if (!(crossfade_fade_in_rem || crossfade_chunk))
922 crossfade_active = false;
924 else
926 audiobuffer_fillpos += length;
928 if (NEED_FLUSH(audiobuffer_pos + audiobuffer_fillpos))
929 pcmbuf_flush_fillpos();
933 #if 0
934 bool pcmbuf_insert_buffer(char *buf, int count)
936 size_t length = (size_t)(unsigned int)count << 2;
938 if (crossfade_active)
940 flush_crossfade(buf, length);
941 if (!(crossfade_fade_in_rem || crossfade_chunk))
942 crossfade_active = false;
944 else
946 if (!prepare_insert(length))
947 return false;
948 pcmbuf_flush_buffer(buf, length);
950 return true;
952 #endif
954 /* Generates a constant square wave sound with a given frequency
955 in Hertz for a duration in milliseconds. */
956 void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
958 unsigned int count = 0;
959 unsigned int i;
960 unsigned int interval = NATIVE_FREQUENCY / frequency;
961 unsigned int samples = NATIVE_FREQUENCY / 1000 * duration;
962 int32_t sample;
963 int16_t *bufstart;
964 int16_t *bufptr;
965 int16_t *pcmbuf_end = (int16_t *)fadebuf;
966 bool mix = pcmbuf_read != NULL && pcmbuf_read->link != NULL;
968 /* Find the insertion point and set bufstart to the start of it */
969 if (mix)
971 /* Get the next chunk */
972 char *pcmbuf_mix_buf = pcmbuf_read->link->addr;
973 /* Give 1/8s clearance. */
974 bufstart = (int16_t *)&pcmbuf_mix_buf[NATIVE_FREQUENCY * 4 / 8];
976 else
978 /* Use audiobuffer */
979 bufstart = (int16_t *)audiobuffer;
982 /* Mix square wave into buffer */
983 bufptr = bufstart;
984 for (i = 0; i < samples; ++i)
986 sample = mix ? *bufptr : 0;
987 *bufptr++ = clip_sample_16(sample + amplitude);
988 if (bufptr > pcmbuf_end)
989 bufptr = (int16_t *)audiobuffer;
990 sample = mix ? *bufptr : 0;
991 *bufptr++ = clip_sample_16(sample + amplitude);
992 if (bufptr > pcmbuf_end)
993 bufptr = (int16_t *)audiobuffer;
995 /* Toggle square wave edge */
996 if (++count >= interval)
998 count = 0;
999 amplitude = -amplitude;
1003 /* Kick off playback if required */
1004 if (!pcm_is_playing())
1006 pcm_play_data(NULL, (unsigned char *)bufstart, samples * 4);
1011 /* Returns pcm buffer usage in percents (0 to 100). */
1012 int pcmbuf_usage(void)
1014 return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
1017 int pcmbuf_mix_free(void)
1019 if (pcmbuf_mix_chunk)
1021 size_t my_mix_end =
1022 (size_t)&((int16_t *)pcmbuf_mix_chunk->addr)[pcmbuf_mix_sample];
1023 size_t my_write_pos = (size_t)&audiobuffer[audiobuffer_pos];
1024 if (my_write_pos < my_mix_end)
1025 my_write_pos += pcmbuf_size;
1026 return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes;
1028 return 100;
1031 void pcmbuf_write_voice_complete(int count)
1033 /* A get-it-to-work-for-now hack (audio status could have changed) */
1034 if (!(audio_status() & AUDIO_STATUS_PLAY))
1036 pcmbuf_write_complete(count);
1037 return;
1040 int16_t *ibuf = (int16_t *)voicebuf;
1041 int16_t *obuf;
1042 size_t chunk_samples;
1044 if (pcmbuf_mix_chunk == NULL && pcmbuf_read != NULL)
1046 pcmbuf_mix_chunk = pcmbuf_read->link;
1047 /* Start 1/8s into the next chunk */
1048 pcmbuf_mix_sample = NATIVE_FREQUENCY * 4 / 16;
1051 if (!pcmbuf_mix_chunk)
1052 return;
1054 obuf = (int16_t *)pcmbuf_mix_chunk->addr;
1055 chunk_samples = pcmbuf_mix_chunk->size / sizeof (int16_t);
1057 count <<= 1;
1059 while (count-- > 0)
1061 int32_t sample = *ibuf++;
1063 if (pcmbuf_mix_sample >= chunk_samples)
1065 pcmbuf_mix_chunk = pcmbuf_mix_chunk->link;
1066 if (!pcmbuf_mix_chunk)
1067 return;
1068 pcmbuf_mix_sample = 0;
1069 obuf = pcmbuf_mix_chunk->addr;
1070 chunk_samples = pcmbuf_mix_chunk->size / 2;
1072 sample += obuf[pcmbuf_mix_sample] >> 2;
1073 obuf[pcmbuf_mix_sample++] = clip_sample_16(sample);
1077 void pcmbuf_crossfade_enable(bool on_off)
1079 #if MEM > 1
1080 /* Next setting to be used, not applied now */
1081 crossfade_enabled_pending = on_off;
1082 #endif
1083 (void)on_off;
1086 void pcmbuf_crossfade_enable_finished(void)
1088 /* Copy the pending setting over now */
1089 crossfade_enabled = crossfade_enabled_pending;
1090 pcmbuf_set_watermark_bytes();
1093 bool pcmbuf_is_crossfade_enabled(void)
1095 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE)
1096 return global_settings.playlist_shuffle;
1098 return crossfade_enabled;