Fixed m200v4 red build.
[kugel-rb.git] / apps / pcmbuf.c
blob095b5209eb55e1a67150a42804bf3dd1dcf1d02d
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 unsigned int codec_thread_id;
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_id, priority);
262 voice_thread_set_priority(priority);
265 else if (codec_thread_priority != PRIORITY_PLAYBACK)
267 thread_set_priority(codec_thread_id, 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_id)
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)
396 struct pcmbufdesc *pcmbuf_temp = pcmbuf_read;
397 unsigned int i = 0;
398 while (pcmbuf_temp) {
399 pcmbuf_temp = pcmbuf_temp->link;
400 i++;
402 return i;
405 int pcmbuf_descs(void)
407 return PCMBUF_DESCS(pcmbuf_size);
410 static void pcmbuf_init_pcmbuffers(void)
412 struct pcmbufdesc *next = pcmbuf_write;
413 next++;
414 pcmbuf_write_end = pcmbuf_write;
415 while ((void *)next < (void *)pcmbuf_bufend) {
416 pcmbuf_write_end->link=next;
417 pcmbuf_write_end=next;
418 next++;
422 static size_t pcmbuf_get_next_required_pcmbuf_size(void)
424 #if MEM > 1
425 size_t seconds = 1;
427 if (crossfade_enabled_pending)
428 seconds += global_settings.crossfade_fade_out_delay
429 + global_settings.crossfade_fade_out_duration;
431 /* Buffer has to be at least 2s long. */
432 seconds += 2;
433 logf("pcmbuf len: %ld", seconds);
434 return seconds * (NATIVE_FREQUENCY*4);
435 #else
436 return NATIVE_FREQUENCY*2;
437 #endif
440 static char *pcmbuf_calc_audiobuffer_ptr(size_t bufsize)
442 return pcmbuf_bufend - (bufsize + PCMBUF_MIX_CHUNK * 2 +
443 PCMBUF_DESCS_SIZE(bufsize));
446 bool pcmbuf_is_same_size(void)
448 if (audiobuffer == NULL)
449 return true; /* Not set up yet even once so always */
451 size_t bufsize = pcmbuf_get_next_required_pcmbuf_size();
452 return pcmbuf_calc_audiobuffer_ptr(bufsize) == audiobuffer;
455 /* Initialize the pcmbuffer the structure looks like this:
456 * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
457 size_t pcmbuf_init(unsigned char *bufend)
459 pcmbuf_bufend = bufend;
460 pcmbuf_size = pcmbuf_get_next_required_pcmbuf_size();
461 audiobuffer = pcmbuf_calc_audiobuffer_ptr(pcmbuf_size);
462 fadebuf = &audiobuffer[pcmbuf_size];
463 voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
464 pcmbuf_write = (struct pcmbufdesc *)&voicebuf[PCMBUF_MIX_CHUNK];
466 pcmbuf_init_pcmbuffers();
468 position_callback = NULL;
469 pcmbuf_event_handler = NULL;
471 pcmbuf_crossfade_enable_finished();
473 pcmbuf_play_stop();
475 return pcmbuf_bufend - audiobuffer;
478 size_t pcmbuf_get_bufsize(void)
480 return pcmbuf_size;
483 #ifdef ROCKBOX_HAS_LOGF
484 unsigned char * pcmbuf_get_meminfo(size_t *length)
486 *length = pcmbuf_bufend - audiobuffer;
487 return audiobuffer;
489 #endif
491 void pcmbuf_pause(bool pause)
493 if (pcm_is_playing())
494 pcm_play_pause(!pause);
495 else if (!pause)
496 pcmbuf_play_start();
499 /* Force playback. */
500 void pcmbuf_play_start(void)
502 if (!pcm_is_playing() && pcmbuf_unplayed_bytes && pcmbuf_read != NULL)
504 last_chunksize = pcmbuf_read->size;
505 pcmbuf_unplayed_bytes -= last_chunksize;
506 pcm_play_data(pcmbuf_callback,
507 (unsigned char *)pcmbuf_read->addr, last_chunksize);
512 * Commit samples waiting to the pcm buffer.
514 static bool pcmbuf_flush_fillpos(void)
516 if (audiobuffer_fillpos) {
517 /* Never use the last buffer descriptor */
518 while (pcmbuf_write == pcmbuf_write_end) {
519 /* If this happens, something is being stupid */
520 if (!pcm_is_playing()) {
521 logf("pcmbuf_flush_fillpos error");
522 pcmbuf_play_start();
524 /* Let approximately one chunk of data playback */
525 sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
527 pcmbuf_add_chunk();
528 return true;
530 return false;
534 * Completely process the crossfade fade out effect with current pcm buffer.
536 static void crossfade_process_buffer(size_t fade_in_delay,
537 size_t fade_out_delay, size_t fade_out_rem)
539 if (!crossfade_mixmode)
541 /* Fade out the specified amount of the already processed audio */
542 size_t total_fade_out = fade_out_rem;
543 size_t fade_out_sample;
544 struct pcmbufdesc *fade_out_chunk = crossfade_chunk;
546 /* Find the right chunk to start fading out */
547 fade_out_delay += crossfade_sample * 2;
548 while (fade_out_delay != 0 && fade_out_delay >= fade_out_chunk->size)
550 fade_out_delay -= fade_out_chunk->size;
551 fade_out_chunk = fade_out_chunk->link;
553 /* The start sample within the chunk */
554 fade_out_sample = fade_out_delay / 2;
556 while (fade_out_rem > 0)
558 /* Each 1/10 second of audio will have the same fade applied */
559 size_t block_rem = MIN(NATIVE_FREQUENCY * 4 / 10, fade_out_rem);
560 int factor = (fade_out_rem << 8) / total_fade_out;
562 fade_out_rem -= block_rem;
564 /* Fade this block */
565 while (block_rem > 0 && fade_out_chunk != NULL)
567 /* Fade one sample */
568 int16_t *buf = (int16_t *)fade_out_chunk->addr;
569 int32_t sample = buf[fade_out_sample];
570 buf[fade_out_sample++] = (sample * factor) >> 8;
572 block_rem -= 2;
573 /* Move to the next chunk as needed */
574 if (fade_out_sample * 2 >= fade_out_chunk->size)
576 fade_out_chunk = fade_out_chunk->link;
577 fade_out_sample = 0;
583 /* Find the right chunk and sample to start fading in */
584 fade_in_delay += crossfade_sample * 2;
585 while (fade_in_delay != 0 && fade_in_delay >= crossfade_chunk->size)
587 fade_in_delay -= crossfade_chunk->size;
588 crossfade_chunk = crossfade_chunk->link;
590 crossfade_sample = fade_in_delay / 2;
591 logf("process done!");
594 /* Initializes crossfader, calculates all necessary parameters and
595 * performs fade-out with the pcm buffer. */
596 static void crossfade_start(void)
598 size_t crossfade_rem;
599 size_t crossfade_need;
600 size_t fade_out_rem;
601 size_t fade_out_delay;
602 size_t fade_in_delay;
604 crossfade_init = false;
605 /* Reject crossfade if less than .5s of data */
606 if (LOW_DATA(2)) {
607 logf("crossfade rejected");
608 pcmbuf_play_stop();
609 return ;
612 logf("crossfade_start");
613 pcmbuf_flush_fillpos();
614 crossfade_active = true;
616 /* Initialize the crossfade buffer size to all of the buffered data that
617 * has not yet been sent to the DMA */
618 crossfade_rem = pcmbuf_unplayed_bytes;
619 crossfade_chunk = pcmbuf_read->link;
620 crossfade_sample = 0;
622 /* Get fade out delay from settings. */
623 fade_out_delay =
624 NATIVE_FREQUENCY * global_settings.crossfade_fade_out_delay * 4;
626 /* Get fade out duration from settings. */
627 fade_out_rem =
628 NATIVE_FREQUENCY * global_settings.crossfade_fade_out_duration * 4;
630 crossfade_need = fade_out_delay + fade_out_rem;
631 /* We want only to modify the last part of the buffer. */
632 if (crossfade_rem > crossfade_need)
634 size_t crossfade_extra = crossfade_rem - crossfade_need;
635 while (crossfade_extra > crossfade_chunk->size)
637 crossfade_extra -= crossfade_chunk->size;
638 crossfade_chunk = crossfade_chunk->link;
640 crossfade_sample = crossfade_extra / 2;
642 /* Truncate fade out duration if necessary. */
643 else if (crossfade_rem < crossfade_need)
645 size_t crossfade_short = crossfade_need - crossfade_rem;
646 if (fade_out_rem >= crossfade_short)
647 fade_out_rem -= crossfade_short;
648 else
650 fade_out_delay -= crossfade_short - fade_out_rem;
651 fade_out_rem = 0;
655 /* Get also fade in duration and delays from settings. */
656 crossfade_fade_in_total =
657 NATIVE_FREQUENCY * global_settings.crossfade_fade_in_duration * 4;
658 crossfade_fade_in_rem = crossfade_fade_in_total;
660 fade_in_delay =
661 NATIVE_FREQUENCY * global_settings.crossfade_fade_in_delay * 4;
663 crossfade_process_buffer(fade_in_delay, fade_out_delay, fade_out_rem);
666 /* Returns the number of bytes _NOT_ mixed */
667 static size_t crossfade_fade_mix(int factor, const char *buf, size_t fade_rem)
669 const int16_t *input_buf = (const int16_t *)buf;
670 int16_t *output_buf = (int16_t *)(crossfade_chunk->addr);
671 int16_t *chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
672 output_buf = &output_buf[crossfade_sample];
673 int32_t sample;
675 while (fade_rem)
677 /* fade left and right channel at once to keep buffer alignment */
678 sample = *input_buf++;
679 sample = ((sample * factor) >> 8) + *output_buf;
680 *output_buf++ = clip_sample_16(sample);
682 sample = *input_buf++;
683 sample = ((sample * factor) >> 8) + *output_buf;
684 *output_buf++ = clip_sample_16(sample);
686 fade_rem -= 4; /* 2 samples, each 16 bit -> 4 bytes */
688 if (output_buf >= chunk_end)
690 crossfade_chunk = crossfade_chunk->link;
691 if (!crossfade_chunk)
692 return fade_rem;
693 output_buf = (int16_t *)crossfade_chunk->addr;
694 chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
697 crossfade_sample = output_buf - (int16_t *)crossfade_chunk->addr;
698 return 0;
701 /* Returns the number of bytes _NOT_ mixed */
702 static size_t crossfade_mix(const char *buf, size_t length)
704 const int16_t *input_buf = (const int16_t *)buf;
705 int16_t *output_buf = (int16_t *)crossfade_chunk->addr;
706 int16_t *chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
707 output_buf = &output_buf[crossfade_sample];
708 int32_t sample;
710 while (length)
712 /* fade left and right channel at once to keep buffer alignment */
713 sample = *input_buf++ + *output_buf;
714 *output_buf++ = clip_sample_16(sample);
716 sample = *input_buf++ + *output_buf;
717 *output_buf++ = clip_sample_16(sample);
719 length -= 4; /* 2 samples, each 16 bit -> 4 bytes */
721 if (output_buf >= chunk_end)
723 crossfade_chunk = crossfade_chunk->link;
724 if (!crossfade_chunk)
725 return length;
727 output_buf = (int16_t *)crossfade_chunk->addr;
728 chunk_end = SKIPBYTES(output_buf, crossfade_chunk->size);
731 crossfade_sample = output_buf - (int16_t *)crossfade_chunk->addr;
732 return 0;
735 static void pcmbuf_flush_buffer(const char *buf, size_t length)
737 size_t copy_n;
738 while (length > 0) {
739 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
740 if (NEED_FLUSH(audiobuffer_index))
742 pcmbuf_flush_fillpos();
743 audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
745 copy_n = MIN(length, pcmbuf_size - audiobuffer_index);
746 memcpy(&audiobuffer[audiobuffer_index], buf, copy_n);
747 buf += copy_n;
748 audiobuffer_fillpos += copy_n;
749 length -= copy_n;
753 static void flush_crossfade(char *buf, size_t length)
755 if (length)
757 if (crossfade_fade_in_rem)
759 size_t samples;
760 int16_t *input_buf;
762 /* Fade factor for this packet */
763 int factor =
764 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
765 crossfade_fade_in_total;
766 /* Bytes to fade */
767 size_t fade_rem = MIN(length, crossfade_fade_in_rem);
769 /* We _will_ fade this many bytes */
770 crossfade_fade_in_rem -= fade_rem;
772 if (crossfade_chunk)
774 /* Mix the data */
775 size_t fade_total = fade_rem;
776 fade_rem = crossfade_fade_mix(factor, buf, fade_rem);
777 length -= fade_total - fade_rem;
778 buf += fade_total - fade_rem;
779 if (!length)
780 return;
781 if (!fade_rem)
782 goto fade_done;
785 samples = fade_rem / 2;
786 input_buf = (int16_t *)buf;
787 /* Fade remaining samples in place */
788 while (samples)
790 int32_t sample = *input_buf;
791 *input_buf++ = (sample * factor) >> 8;
792 samples--;
796 fade_done:
797 if (crossfade_chunk)
799 /* Mix the data */
800 size_t mix_total = length;
801 length = crossfade_mix(buf, length);
802 buf += mix_total - length;
803 if (!length)
804 return;
807 /* Flush samples to the buffer */
808 while (!prepare_insert(length))
809 sleep(1);
810 pcmbuf_flush_buffer(buf, length);
815 static bool prepare_insert(size_t length)
817 if (low_latency_mode)
819 /* 1/4s latency. */
820 if (pcmbuf_unplayed_bytes > NATIVE_FREQUENCY * 4 / 2
821 && pcm_is_playing())
822 return false;
825 /* Need to save PCMBUF_MIN_CHUNK to prevent wrapping overwriting */
826 if (pcmbuf_free() < length + PCMBUF_MIN_CHUNK)
827 return false;
829 if (!pcm_is_playing())
831 trigger_cpu_boost();
833 /* Pre-buffer 1s. */
834 #if MEM <= 1
835 if (!LOW_DATA(1))
836 #else
837 if (!LOW_DATA(4))
838 #endif
840 logf("pcm starting");
841 if (!(audio_status() & AUDIO_STATUS_PAUSE))
842 pcmbuf_play_start();
845 else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
846 pcmbuf_under_watermark();
848 return true;
851 void* pcmbuf_request_buffer(int *count)
853 if (crossfade_init)
854 crossfade_start();
856 if (crossfade_active) {
857 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
858 return fadebuf;
860 else
862 if(prepare_insert(*count << 2))
864 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
865 if (pcmbuf_size - audiobuffer_index >= PCMBUF_MIN_CHUNK)
867 /* Usual case, there's space here */
868 return &audiobuffer[audiobuffer_index];
870 else
872 /* Flush and wrap the buffer */
873 pcmbuf_flush_fillpos();
874 audiobuffer_pos = 0;
875 return &audiobuffer[0];
878 else
880 return NULL;
885 void * pcmbuf_request_voice_buffer(int *count)
887 /* A get-it-to-work-for-now hack (audio status could change by
888 completion) */
889 if (audio_status() & AUDIO_STATUS_PLAY)
891 if (pcmbuf_read == NULL)
893 return NULL;
895 else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 &&
896 (pcmbuf_mix_chunk || pcmbuf_read->link))
898 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
899 return voicebuf;
901 else
903 return NULL;
906 else
908 return pcmbuf_request_buffer(count);
912 bool pcmbuf_is_crossfade_active(void)
914 return crossfade_active || crossfade_init;
917 void pcmbuf_write_complete(int count)
919 size_t length = (size_t)(unsigned int)count << 2;
921 if (crossfade_active)
923 flush_crossfade(fadebuf, length);
924 if (!(crossfade_fade_in_rem || crossfade_chunk))
925 crossfade_active = false;
927 else
929 audiobuffer_fillpos += length;
931 if (NEED_FLUSH(audiobuffer_pos + audiobuffer_fillpos))
932 pcmbuf_flush_fillpos();
936 #if 0
937 bool pcmbuf_insert_buffer(char *buf, int count)
939 size_t length = (size_t)(unsigned int)count << 2;
941 if (crossfade_active)
943 flush_crossfade(buf, length);
944 if (!(crossfade_fade_in_rem || crossfade_chunk))
945 crossfade_active = false;
947 else
949 if (!prepare_insert(length))
950 return false;
951 pcmbuf_flush_buffer(buf, length);
953 return true;
955 #endif
957 #ifndef HAVE_HARDWARE_BEEP
958 #define MINIBUF_SAMPLES (NATIVE_FREQUENCY / 1000 * KEYCLICK_DURATION)
959 #define MINIBUF_SIZE (MINIBUF_SAMPLES*4)
961 /* Generates a constant square wave sound with a given frequency
962 in Hertz for a duration in milliseconds. */
963 void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
965 unsigned int step = 0xffffffffu / NATIVE_FREQUENCY * frequency;
966 int32_t phase = 0;
967 int16_t *bufptr, *bufstart, *bufend;
968 int32_t sample;
969 int nsamples = NATIVE_FREQUENCY / 1000 * duration;
970 bool mix = pcmbuf_read != NULL && pcmbuf_read->link != NULL;
971 int i;
973 bufend = SKIPBYTES((int16_t *)audiobuffer, pcmbuf_size);
975 /* Find the insertion point and set bufstart to the start of it */
976 if (mix)
978 /* Get the currently playing chunk at the current position. */
979 bufstart = (int16_t *)pcm_play_dma_get_peak_buffer(&i);
981 /* If above isn't implemented or pcm is stopped, no beepeth. */
982 if (!bufstart || !pcm_is_playing())
983 return;
985 /* Give 5ms clearance. */
986 bufstart += NATIVE_FREQUENCY * 4 / 200;
988 /* Wrapped above? */
989 if (bufstart >= bufend)
990 bufstart -= pcmbuf_size;
992 /* NOTE: On some targets using hardware DMA, cache range flushing may
993 * be required or the writes may not be picked up by the controller.
994 * An incremental flush should be done periodically during the mixdown. */
996 else if (nsamples <= MINIBUF_SAMPLES)
998 static int16_t minibuf[MINIBUF_SAMPLES*2];
999 /* Use mini buffer */
1000 bufstart = minibuf;
1001 bufend = SKIPBYTES(bufstart, MINIBUF_SIZE);
1003 else if (audio_buffer_state() != AUDIOBUF_STATE_TRASHED)
1005 /* Use audiobuffer */
1006 bufstart = (int16_t *)audiobuffer;
1008 else
1010 /* No place */
1011 return;
1014 bufptr = bufstart;
1016 /* Mix square wave into buffer */
1017 for (i = 0; i < nsamples; ++i)
1019 int32_t amp = (phase >> 31) ^ (int32_t)amplitude;
1020 sample = mix ? *bufptr : 0;
1021 *bufptr++ = clip_sample_16(sample + amp);
1022 if (bufptr >= bufend)
1023 bufptr = (int16_t *)audiobuffer;
1024 sample = mix ? *bufptr : 0;
1025 *bufptr++ = clip_sample_16(sample + amp);
1026 if (bufptr >= bufend)
1027 bufptr = (int16_t *)audiobuffer;
1029 phase += step;
1032 pcm_play_lock();
1033 #ifdef HAVE_RECORDING
1034 pcm_rec_lock();
1035 #endif
1037 /* Kick off playback if required and it won't interfere */
1038 if (!pcm_is_playing()
1039 #ifdef HAVE_RECORDING
1040 && !pcm_is_recording()
1041 #endif
1044 pcm_play_data(NULL, (unsigned char *)bufstart, nsamples * 4);
1047 pcm_play_unlock();
1048 #ifdef HAVE_RECORDING
1049 pcm_rec_unlock();
1050 #endif
1052 #endif /* HAVE_HARDWARE_BEEP */
1054 /* Returns pcm buffer usage in percents (0 to 100). */
1055 int pcmbuf_usage(void)
1057 return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
1060 int pcmbuf_mix_free(void)
1062 if (pcmbuf_mix_chunk)
1064 size_t my_mix_end =
1065 (size_t)&((int16_t *)pcmbuf_mix_chunk->addr)[pcmbuf_mix_sample];
1066 size_t my_write_pos = (size_t)&audiobuffer[audiobuffer_pos];
1067 if (my_write_pos < my_mix_end)
1068 my_write_pos += pcmbuf_size;
1069 return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes;
1071 return 100;
1074 void pcmbuf_write_voice_complete(int count)
1076 /* A get-it-to-work-for-now hack (audio status could have changed) */
1077 if (!(audio_status() & AUDIO_STATUS_PLAY))
1079 pcmbuf_write_complete(count);
1080 return;
1083 int16_t *ibuf = (int16_t *)voicebuf;
1084 int16_t *obuf;
1085 size_t chunk_samples;
1087 if (pcmbuf_mix_chunk == NULL && pcmbuf_read != NULL)
1089 pcmbuf_mix_chunk = pcmbuf_read->link;
1090 /* Start 1/8s into the next chunk */
1091 pcmbuf_mix_sample = NATIVE_FREQUENCY * 4 / 16;
1094 if (!pcmbuf_mix_chunk)
1095 return;
1097 obuf = (int16_t *)pcmbuf_mix_chunk->addr;
1098 chunk_samples = pcmbuf_mix_chunk->size / sizeof (int16_t);
1100 count <<= 1;
1102 while (count-- > 0)
1104 int32_t sample = *ibuf++;
1106 if (pcmbuf_mix_sample >= chunk_samples)
1108 pcmbuf_mix_chunk = pcmbuf_mix_chunk->link;
1109 if (!pcmbuf_mix_chunk)
1110 return;
1111 pcmbuf_mix_sample = 0;
1112 obuf = pcmbuf_mix_chunk->addr;
1113 chunk_samples = pcmbuf_mix_chunk->size / 2;
1115 sample += obuf[pcmbuf_mix_sample] >> 2;
1116 obuf[pcmbuf_mix_sample++] = clip_sample_16(sample);
1120 void pcmbuf_crossfade_enable(bool on_off)
1122 #if MEM > 1
1123 /* Next setting to be used, not applied now */
1124 crossfade_enabled_pending = on_off;
1125 #endif
1126 (void)on_off;
1129 void pcmbuf_crossfade_enable_finished(void)
1131 /* Copy the pending setting over now */
1132 crossfade_enabled = crossfade_enabled_pending;
1133 pcmbuf_set_watermark_bytes();
1136 bool pcmbuf_is_crossfade_enabled(void)
1138 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE)
1139 return global_settings.playlist_shuffle;
1141 return crossfade_enabled;