copy the classic_statusbar and rockbox_none .sbs's to .rsbs's also so remote displays...
[kugel-rb.git] / apps / pcmbuf.c
bloba75c1106949fd234c663fb3bef8c910a32f3f419
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 ****************************************************************************/
21 #include <stdio.h>
22 #include "config.h"
23 #include "system.h"
24 #include "debug.h"
25 #include <kernel.h>
26 #include "pcmbuf.h"
27 #include "pcm.h"
28 #include "playback.h"
30 /* Define LOGF_ENABLE to enable logf output in this file */
31 /*#define LOGF_ENABLE*/
32 #include "logf.h"
33 #ifndef SIMULATOR
34 #include "cpu.h"
35 #endif
36 #include <string.h>
37 #include "settings.h"
38 #include "audio.h"
39 #include "voice_thread.h"
40 #include "dsp.h"
42 #define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
43 on the pcm buffer */
44 #define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
45 chunks on the pcm buffer (or we run out
46 of buffer descriptors, which is
47 non-fatal) */
48 #define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
49 this to the DMA */
50 #define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet
51 for mixing (crossfade or voice) */
53 /* number of bytes played per second (sample rate * 2 channels * 2 bytes/sample) */
54 #define BYTERATE (NATIVE_FREQUENCY * 4)
56 #if MEMORYSIZE > 2
57 /* Keep watermark high for iPods at least (2s) */
58 #define PCMBUF_WATERMARK (BYTERATE * 2)
59 #else
60 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
61 #endif
63 /* Structure we can use to queue pcm chunks in memory to be played
64 * by the driver code. */
65 struct chunkdesc
67 void *addr;
68 size_t size;
69 struct chunkdesc* link;
70 /* true if last chunk in the track */
71 bool end_of_track;
74 #define NUM_CHUNK_DESCS(bufsize) \
75 ((bufsize) / PCMBUF_MINAVG_CHUNK)
77 /* Size of the PCM buffer. */
78 static size_t pcmbuf_size IDATA_ATTR = 0;
79 static char *pcmbuf_bufend IDATA_ATTR;
80 static char *pcmbuffer IDATA_ATTR;
81 /* Current PCM buffer write index. */
82 static size_t pcmbuffer_pos IDATA_ATTR;
83 /* Amount pcmbuffer_pos will be increased.*/
84 static size_t pcmbuffer_fillpos IDATA_ATTR;
86 /* Gapless playback */
87 static bool end_of_track IDATA_ATTR;
88 bool track_transition IDATA_ATTR;
90 #ifdef HAVE_CROSSFADE
91 /* Crossfade buffer */
92 static char *fadebuf IDATA_ATTR;
94 /* Crossfade related state */
95 static bool crossfade_enabled;
96 static bool crossfade_enable_request;
97 static bool crossfade_mixmode;
98 static bool crossfade_auto_skip;
99 static bool crossfade_active IDATA_ATTR;
100 static bool crossfade_track_change_started IDATA_ATTR;
102 /* Track the current location for processing crossfade */
103 static struct chunkdesc *crossfade_chunk IDATA_ATTR;
104 static size_t crossfade_sample IDATA_ATTR;
106 /* Counters for fading in new data */
107 static size_t crossfade_fade_in_total IDATA_ATTR;
108 static size_t crossfade_fade_in_rem IDATA_ATTR;
109 #endif
111 static struct chunkdesc *read_chunk IDATA_ATTR;
112 static struct chunkdesc *read_end_chunk IDATA_ATTR;
113 static struct chunkdesc *write_chunk IDATA_ATTR;
114 static struct chunkdesc *write_end_chunk IDATA_ATTR;
115 static size_t last_chunksize IDATA_ATTR;
117 static size_t pcmbuf_unplayed_bytes IDATA_ATTR;
118 static size_t pcmbuf_watermark IDATA_ATTR;
120 /* Voice */
121 static char *voicebuf IDATA_ATTR;
122 static struct chunkdesc *mix_chunk IDATA_ATTR;
123 static size_t pcmbuf_mix_sample IDATA_ATTR;
125 static bool low_latency_mode = false;
126 static bool flush_pcmbuf = false;
128 #ifdef HAVE_PRIORITY_SCHEDULING
129 static int codec_thread_priority = PRIORITY_PLAYBACK;
130 #endif
132 extern unsigned int codec_thread_id;
134 /* Helpful macros for use in conditionals this assumes some of the above
135 * static variable names */
136 #define COMMIT_IF_NEEDED if(pcmbuffer_fillpos > PCMBUF_TARGET_CHUNK || \
137 (pcmbuffer_pos + pcmbuffer_fillpos) >= pcmbuf_size) commit_chunk(false)
138 #define LOW_DATA(quarter_secs) \
139 (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs)
141 #ifdef HAVE_CROSSFADE
142 static void crossfade_start(void);
143 static void write_to_crossfade(size_t length);
144 static void pcmbuf_finish_crossfade_enable(void);
145 #endif
148 /**************************************/
150 /* define this to show detailed chunkdesc usage information on the sim console */
151 /*#define DESC_DEBUG*/
153 #ifndef SIMULATOR
154 #undef DESC_DEBUG
155 #endif
156 #ifdef DESC_DEBUG
157 static struct chunkdesc *first_desc;
158 static bool show_desc_in_use = false;
159 #define DISPLAY_DESC(caller) while(!show_desc(caller))
160 #define DESC_IDX(desc) (desc ? desc - first_desc : -1)
161 #define DESCL_IDX(desc) (desc && desc->link ? desc->link - first_desc : -1)
162 #define SHOW_1ST(desc) if(DESC_IDX (desc)==-1) DEBUGF(" -- "); \
163 else DEBUGF(" %02d ", DESC_IDX(desc))
164 #define SHOW_2ND(desc) if(DESCL_IDX(desc)==-1) DEBUGF("l -- "); \
165 else DEBUGF("l %02d ", DESCL_IDX(desc))
166 #define DESC_SHOW(tag, desc) DEBUGF(tag);SHOW_1ST(desc); \
167 DEBUGF(tag);SHOW_2ND(desc)
169 static bool show_desc(char *caller)
171 if (show_desc_in_use) return false;
172 show_desc_in_use = true;
173 DEBUGF("%-14s\t", caller);
174 DESC_SHOW("r", read_chunk);
175 DESC_SHOW("re", read_end_chunk);
176 DEBUGF(" ");
177 DESC_SHOW("w", write_chunk);
178 DESC_SHOW("we", write_end_chunk);
179 DEBUGF("\n");
180 show_desc_in_use = false;
181 return true;
183 #else
184 #define DISPLAY_DESC(caller) do{}while(0)
185 #endif
188 /** Accept new PCM data */
190 /* Commit PCM buffer samples as a new chunk for playback */
191 static void commit_chunk(bool flush_next_time)
193 if (!pcmbuffer_fillpos)
194 return;
196 /* Never use the last buffer descriptor */
197 while (write_chunk == write_end_chunk) {
198 /* If this happens, something is being stupid */
199 if (!pcm_is_playing()) {
200 logf("commit_chunk error");
201 pcmbuf_play_start();
203 /* Let approximately one chunk of data playback */
204 sleep(HZ * PCMBUF_TARGET_CHUNK / BYTERATE);
207 /* commit the chunk */
209 register size_t size = pcmbuffer_fillpos;
210 /* Grab the next description to write, and change the write pointer */
211 register struct chunkdesc *pcmbuf_current = write_chunk;
212 write_chunk = pcmbuf_current->link;
213 /* Fill in the values in the new buffer chunk */
214 pcmbuf_current->addr = &pcmbuffer[pcmbuffer_pos];
215 pcmbuf_current->size = size;
216 pcmbuf_current->end_of_track = end_of_track;
217 pcmbuf_current->link = NULL;
218 end_of_track = false; /* This is single use only */
220 if (read_chunk != NULL)
222 if (flush_pcmbuf)
224 /* Flush! Discard all data after the currently playing chunk,
225 and make the current chunk play next */
226 write_end_chunk->link = read_chunk->link;
227 read_chunk->link = pcmbuf_current;
228 while (write_end_chunk->link)
230 write_end_chunk = write_end_chunk->link;
231 pcmbuf_unplayed_bytes -= write_end_chunk->size;
234 /* If there is already a read buffer setup, add to it */
235 else
236 read_end_chunk->link = pcmbuf_current;
238 else
240 /* Otherwise create the buffer */
241 read_chunk = pcmbuf_current;
244 /* If flush_next_time is true, then the current chunk will be thrown out
245 * and the next chunk to be committed will be the next to be played.
246 * This is used to empty the PCM buffer for a track change. */
247 flush_pcmbuf = flush_next_time;
249 /* This is now the last buffer to read */
250 read_end_chunk = pcmbuf_current;
252 /* Update bytes counters */
253 pcmbuf_unplayed_bytes += size;
255 pcmbuffer_pos += size;
256 if (pcmbuffer_pos >= pcmbuf_size)
257 pcmbuffer_pos -= pcmbuf_size;
259 pcmbuffer_fillpos = 0;
260 DISPLAY_DESC("commit_chunk");
263 /* Set priority of the codec thread */
264 #ifdef HAVE_PRIORITY_SCHEDULING
265 static void boost_codec_thread(bool boost)
267 /* Keep voice and codec threads at the same priority or else voice
268 * will starve if the codec thread's priority is boosted. */
269 if (boost)
271 int priority = (PRIORITY_PLAYBACK - PRIORITY_PLAYBACK_MAX)*pcmbuf_unplayed_bytes
272 / (2*NATIVE_FREQUENCY) + PRIORITY_PLAYBACK_MAX;
274 if (priority != codec_thread_priority)
276 codec_thread_priority = priority;
277 thread_set_priority(codec_thread_id, priority);
278 voice_thread_set_priority(priority);
281 else if (codec_thread_priority != PRIORITY_PLAYBACK)
283 thread_set_priority(codec_thread_id, PRIORITY_PLAYBACK);
284 voice_thread_set_priority(PRIORITY_PLAYBACK);
285 codec_thread_priority = PRIORITY_PLAYBACK;
288 #else
289 #define boost_codec_thread(boost) do{}while(0)
290 #endif /* HAVE_PRIORITY_SCHEDULING */
292 /* Return true if the PCM buffer is able to receive new data.
293 * Also maintain buffer level above the watermark. */
294 static bool prepare_insert(size_t length)
296 if (low_latency_mode)
298 /* 1/4s latency. */
299 if (!LOW_DATA(1) && pcm_is_playing())
300 return false;
303 /* Need to save PCMBUF_MIN_CHUNK to prevent wrapping overwriting */
304 if (pcmbuf_free() < length + PCMBUF_MIN_CHUNK)
305 return false;
307 /* Maintain the buffer level above the watermark */
308 if (pcm_is_playing())
310 /* Only codec thread initiates boost - voice boosts the cpu when playing
311 a clip */
312 #ifndef SIMULATOR
313 if (thread_get_current() == codec_thread_id)
314 #endif /* SIMULATOR */
316 if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
318 /* Fill PCM buffer by boosting cpu */
319 trigger_cpu_boost();
320 /* If buffer is critically low, override UI priority, else
321 set back to the original priority. */
322 boost_codec_thread(LOW_DATA(2));
324 else
326 boost_codec_thread(false);
330 #ifdef HAVE_CROSSFADE
331 /* Disable crossfade if < .5s of audio */
332 if (LOW_DATA(2))
334 crossfade_active = false;
336 #endif
338 else /* pcm_is_playing */
340 /* Boost CPU for pre-buffer */
341 trigger_cpu_boost();
343 /* If pre-buffered to the watermark, start playback */
344 #if MEMORYSIZE > 2
345 if (!LOW_DATA(4))
346 #else
347 if (pcmbuf_unplayed_bytes > pcmbuf_watermark)
348 #endif
350 logf("pcm starting");
351 if (!(audio_status() & AUDIO_STATUS_PAUSE))
352 pcmbuf_play_start();
356 return true;
359 /* Request space in the buffer for writing output samples */
360 void *pcmbuf_request_buffer(int *count)
362 #ifdef HAVE_CROSSFADE
363 /* we're going to crossfade to a new track, which is now on its way */
364 if (crossfade_track_change_started)
365 crossfade_start();
367 /* crossfade has begun, put the new track samples in fadebuf */
368 if (crossfade_active)
370 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
371 return fadebuf;
373 else
374 #endif
375 /* if possible, reserve room in the PCM buffer for new samples */
377 if(prepare_insert(*count << 2))
379 size_t pcmbuffer_index = pcmbuffer_pos + pcmbuffer_fillpos;
380 if (pcmbuf_size - pcmbuffer_index >= PCMBUF_MIN_CHUNK)
382 /* Usual case, there's space here */
383 return &pcmbuffer[pcmbuffer_index];
385 else
387 /* Wrap the buffer, the new samples go at the beginning */
388 commit_chunk(false);
389 pcmbuffer_pos = 0;
390 return &pcmbuffer[0];
394 /* PCM buffer not ready to receive new data yet */
395 return NULL;
398 /* Handle new samples to the buffer */
399 void pcmbuf_write_complete(int count)
401 size_t length = (size_t)(unsigned int)count << 2;
402 #ifdef HAVE_CROSSFADE
403 if (crossfade_active)
404 write_to_crossfade(length);
405 else
406 #endif
408 pcmbuffer_fillpos += length;
409 COMMIT_IF_NEEDED;
414 /** Init */
416 static inline void init_pcmbuffers(void)
418 #ifdef DESC_DEBUG
419 first_desc = write_chunk;
420 #endif
421 struct chunkdesc *next = write_chunk;
422 next++;
423 write_end_chunk = write_chunk;
424 while ((void *)next < (void *)pcmbuf_bufend) {
425 write_end_chunk->link=next;
426 write_end_chunk=next;
427 next++;
429 DISPLAY_DESC("init");
432 static size_t get_next_required_pcmbuf_size(void)
434 size_t seconds = 1;
436 #ifdef HAVE_CROSSFADE
437 if (crossfade_enable_request)
438 seconds += global_settings.crossfade_fade_out_delay +
439 global_settings.crossfade_fade_out_duration;
440 #endif
442 #if MEMORYSIZE > 2
443 /* Buffer has to be at least 2s long. */
444 seconds += 2;
445 #endif
446 logf("pcmbuf len: %ld", (long)seconds);
447 return seconds * BYTERATE;
450 /* Initialize the pcmbuffer the structure looks like this:
451 * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
452 size_t pcmbuf_init(unsigned char *bufend)
454 pcmbuf_bufend = bufend;
455 pcmbuf_size = get_next_required_pcmbuf_size();
456 write_chunk = (struct chunkdesc *)pcmbuf_bufend -
457 NUM_CHUNK_DESCS(pcmbuf_size);
458 voicebuf = (char *)write_chunk - PCMBUF_MIX_CHUNK;
459 #ifdef HAVE_CROSSFADE
460 fadebuf = voicebuf - PCMBUF_MIX_CHUNK;
461 pcmbuffer = fadebuf - pcmbuf_size;
462 #else
463 pcmbuffer = voicebuf - pcmbuf_size;
464 #endif
466 init_pcmbuffers();
468 #ifdef HAVE_CROSSFADE
469 pcmbuf_finish_crossfade_enable();
470 #else
471 pcmbuf_watermark = PCMBUF_WATERMARK;
472 #endif
474 pcmbuf_play_stop();
476 return pcmbuf_bufend - pcmbuffer;
480 /** Track change */
482 void pcmbuf_start_track_change(bool auto_skip)
484 bool crossfade = false;
485 #ifdef HAVE_CROSSFADE
486 /* Determine whether this track change needs to crossfade */
487 if(crossfade_enabled && !pcmbuf_is_crossfade_active())
489 switch(global_settings.crossfade)
491 case CROSSFADE_ENABLE_AUTOSKIP:
492 crossfade = auto_skip;
493 break;
494 case CROSSFADE_ENABLE_MANSKIP:
495 crossfade = !auto_skip;
496 break;
497 case CROSSFADE_ENABLE_SHUFFLE:
498 crossfade = global_settings.playlist_shuffle;
499 break;
500 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
501 crossfade = global_settings.playlist_shuffle || !auto_skip;
502 break;
503 case CROSSFADE_ENABLE_ALWAYS:
504 crossfade = true;
505 break;
508 #endif
510 if (!auto_skip || crossfade)
511 /* manual skip or crossfade */
513 if (crossfade)
514 { logf(" crossfade track change"); }
515 else
516 { logf(" manual track change"); }
518 /* Notify the wps that the track change starts now */
519 audio_post_track_change(false);
521 /* Can't do two crossfades at once and, no fade if pcm is off now */
522 if (
523 #ifdef HAVE_CROSSFADE
524 pcmbuf_is_crossfade_active() ||
525 #endif
526 !pcm_is_playing())
528 pcmbuf_play_stop();
529 return;
532 trigger_cpu_boost();
534 /* Not enough data, or not crossfading, flush the old data instead */
535 if (LOW_DATA(2) || !crossfade || low_latency_mode)
537 commit_chunk(true);
538 return;
541 #ifdef HAVE_CROSSFADE
542 /* Don't enable mix mode when skipping tracks manually. */
543 crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode;
545 crossfade_auto_skip = auto_skip;
547 crossfade_track_change_started = crossfade;
548 #endif
550 else /* automatic and not crossfading, so do gapless track change */
552 /* The codec is moving on to the next track, but the current track will
553 * continue to play. Set a flag to make sure the elapsed time of the
554 * current track will be updated properly, and mark the current chunk
555 * as the last one in the track. */
556 logf(" gapless track change");
557 track_transition = true;
558 end_of_track = true;
563 /** Playback */
565 /* PCM driver callback
566 * This function has 3 major logical parts (separated by brackets both for
567 * readability and variable scoping). The first part performs the
568 * operations related to finishing off the last chunk we fed to the DMA.
569 * The second part detects the end of playlist condition when the PCM
570 * buffer is empty except for uncommitted samples. Then they are committed
571 * and sent to the PCM driver for playback. The third part performs the
572 * operations involved in sending a new chunk to the DMA. */
573 static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR;
574 static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
577 struct chunkdesc *pcmbuf_current = read_chunk;
578 /* Take the finished chunk out of circulation */
579 read_chunk = pcmbuf_current->link;
581 /* if during a track transition, update the elapsed time in ms */
582 if (track_transition)
583 audio_pcmbuf_position_callback(last_chunksize * 1000 / BYTERATE);
585 /* if last chunk in the track, stop updates and notify audio thread */
586 if (pcmbuf_current->end_of_track)
588 track_transition = false;
589 audio_post_track_change(true);
592 /* Put the finished chunk back into circulation */
593 write_end_chunk->link = pcmbuf_current;
594 write_end_chunk = pcmbuf_current;
596 /* If we've read over the mix chunk while it's still mixing there */
597 if (pcmbuf_current == mix_chunk)
598 mix_chunk = NULL;
600 #ifdef HAVE_CROSSFADE
601 /* If we've read over the crossfade chunk while it's still fading */
602 if (pcmbuf_current == crossfade_chunk)
603 crossfade_chunk = read_chunk;
604 #endif
608 /* Commit last samples at end of playlist */
609 if (pcmbuffer_fillpos && !read_chunk)
611 logf("pcmbuf_pcm_callback: commit last samples");
612 commit_chunk(false);
617 /* Send the new chunk to the PCM */
618 if(read_chunk)
620 size_t current_size = read_chunk->size;
622 pcmbuf_unplayed_bytes -= current_size;
623 last_chunksize = current_size;
624 *size = current_size;
625 *start = read_chunk->addr;
627 else
629 /* No more chunks */
630 logf("pcmbuf_pcm_callback: no more chunks");
631 last_chunksize = 0;
632 *size = 0;
633 *start = NULL;
636 DISPLAY_DESC("callback");
639 /* Force playback */
640 void pcmbuf_play_start(void)
642 if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL)
644 logf("pcmbuf_play_start");
645 last_chunksize = read_chunk->size;
646 pcmbuf_unplayed_bytes -= last_chunksize;
647 pcm_play_data(pcmbuf_pcm_callback,
648 (unsigned char *)read_chunk->addr, last_chunksize);
652 void pcmbuf_play_stop(void)
654 logf("pcmbuf_play_stop");
655 pcm_play_stop();
657 pcmbuf_unplayed_bytes = 0;
658 mix_chunk = NULL;
659 if (read_chunk) {
660 write_end_chunk->link = read_chunk;
661 write_end_chunk = read_end_chunk;
662 read_chunk = read_end_chunk = NULL;
664 pcmbuffer_pos = 0;
665 pcmbuffer_fillpos = 0;
666 #ifdef HAVE_CROSSFADE
667 crossfade_track_change_started = false;
668 crossfade_active = false;
669 #endif
670 end_of_track = false;
671 track_transition = false;
672 DISPLAY_DESC("play_stop");
674 /* Can unboost the codec thread here no matter who's calling */
675 boost_codec_thread(false);
678 void pcmbuf_pause(bool pause)
680 logf("pcmbuf_pause: %s", pause?"pause":"play");
681 if (pcm_is_playing())
682 pcm_play_pause(!pause);
683 else if (!pause)
684 pcmbuf_play_start();
688 /** Crossfade */
690 /* Clip sample to signed 16 bit range */
691 static inline int32_t clip_sample_16(int32_t sample)
693 if ((int16_t)sample != sample)
694 sample = 0x7fff ^ (sample >> 31);
695 return sample;
698 #ifdef HAVE_CROSSFADE
699 /* Find the chunk that's (length) deep in the list. Return the position within
700 * the chunk, and leave the chunkdesc pointer pointing to the chunk. */
701 static size_t find_chunk(size_t length, struct chunkdesc **chunk)
703 while (*chunk && length >= (*chunk)->size)
705 length -= (*chunk)->size;
706 *chunk = (*chunk)->link;
708 return length / 2;
711 /* Returns the number of bytes _NOT_ mixed/faded */
712 static size_t crossfade_mix_fade(int factor, size_t length, const char *buf,
713 size_t *out_sample, struct chunkdesc **out_chunk)
715 const int16_t *input_buf = (const int16_t *)buf;
716 int16_t *output_buf = (int16_t *)((*out_chunk)->addr);
717 int16_t *chunk_end = SKIPBYTES(output_buf, (*out_chunk)->size);
718 output_buf = &output_buf[*out_sample];
719 int32_t sample;
721 while (length)
723 /* fade left and right channel at once to keep buffer alignment */
724 int i;
725 for (i = 0; i < 2; i++)
727 if (input_buf)
728 /* fade the input buffer and mix into the chunk */
730 sample = *input_buf++;
731 sample = ((sample * factor) >> 8) + *output_buf;
732 *output_buf++ = clip_sample_16(sample);
734 else
735 /* fade the chunk only */
737 sample = *output_buf;
738 *output_buf++ = (sample * factor) >> 8;
742 length -= 4; /* 2 samples, each 16 bit -> 4 bytes */
744 /* move to next chunk as needed */
745 if (output_buf >= chunk_end)
747 *out_chunk = (*out_chunk)->link;
748 if (!(*out_chunk))
749 return length;
750 output_buf = (int16_t *)((*out_chunk)->addr);
751 chunk_end = SKIPBYTES(output_buf, (*out_chunk)->size);
754 *out_sample = output_buf - (int16_t *)((*out_chunk)->addr);
755 return 0;
758 /* Initializes crossfader, calculates all necessary parameters and performs
759 * fade-out with the PCM buffer. */
760 static void crossfade_start(void)
762 size_t crossfade_rem;
763 size_t crossfade_need;
764 size_t fade_out_rem;
765 size_t fade_out_delay;
766 size_t fade_in_delay;
768 crossfade_track_change_started = false;
769 /* Reject crossfade if less than .5s of data */
770 if (LOW_DATA(2)) {
771 logf("crossfade rejected");
772 pcmbuf_play_stop();
773 return ;
776 logf("crossfade_start");
777 commit_chunk(false);
778 crossfade_active = true;
780 /* Initialize the crossfade buffer size to all of the buffered data that
781 * has not yet been sent to the DMA */
782 crossfade_rem = pcmbuf_unplayed_bytes;
783 crossfade_chunk = read_chunk->link;
784 crossfade_sample = 0;
786 /* Get fade out info from settings. */
787 fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
788 fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
790 crossfade_need = fade_out_delay + fade_out_rem;
791 if (crossfade_rem > crossfade_need)
793 if (crossfade_auto_skip)
794 /* Automatic track changes only modify the last part of the buffer,
795 * so find the right chunk and sample to start the crossfade */
797 crossfade_sample = find_chunk(crossfade_rem - crossfade_need,
798 &crossfade_chunk);
799 crossfade_rem = crossfade_need;
801 else
802 /* Manual skips occur immediately, but give time to process */
804 crossfade_rem -= crossfade_chunk->size;
805 crossfade_chunk = crossfade_chunk->link;
808 /* Truncate fade out duration if necessary. */
809 if (crossfade_rem < crossfade_need)
811 size_t crossfade_short = crossfade_need - crossfade_rem;
812 if (fade_out_rem >= crossfade_short)
813 fade_out_rem -= crossfade_short;
814 else
816 fade_out_delay -= crossfade_short - fade_out_rem;
817 fade_out_rem = 0;
820 crossfade_rem -= fade_out_delay + fade_out_rem;
822 /* Completely process the crossfade fade-out effect with current PCM buffer */
823 if (!crossfade_mixmode)
825 /* Fade out the specified amount of the already processed audio */
826 size_t total_fade_out = fade_out_rem;
827 size_t fade_out_sample;
828 struct chunkdesc *fade_out_chunk = crossfade_chunk;
830 /* Find the right chunk and sample to start fading out */
831 fade_out_delay += crossfade_sample * 2;
832 fade_out_sample = find_chunk(fade_out_delay, &fade_out_chunk);
834 while (fade_out_rem > 0)
836 /* Each 1/10 second of audio will have the same fade applied */
837 size_t block_rem = MIN(BYTERATE / 10, fade_out_rem);
838 int factor = (fade_out_rem << 8) / total_fade_out;
840 fade_out_rem -= block_rem;
842 crossfade_mix_fade(factor, block_rem, NULL,
843 &fade_out_sample, &fade_out_chunk);
846 /* zero out the rest of the buffer */
847 crossfade_mix_fade(0, crossfade_rem, NULL,
848 &fade_out_sample, &fade_out_chunk);
851 /* Initialize fade-in counters */
852 crossfade_fade_in_total = global_settings.crossfade_fade_in_duration * BYTERATE;
853 crossfade_fade_in_rem = crossfade_fade_in_total;
855 fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
857 /* Find the right chunk and sample to start fading in */
858 fade_in_delay += crossfade_sample * 2;
859 crossfade_sample = find_chunk(fade_in_delay, &crossfade_chunk);
860 logf("crossfade_start done!");
863 /* Perform fade-in of new track */
864 static void write_to_crossfade(size_t length)
866 if (length)
868 char *buf = fadebuf;
869 if (crossfade_fade_in_rem)
871 size_t samples;
872 int16_t *input_buf;
874 /* Fade factor for this packet */
875 int factor =
876 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
877 crossfade_fade_in_total;
878 /* Bytes to fade */
879 size_t fade_rem = MIN(length, crossfade_fade_in_rem);
881 /* We _will_ fade this many bytes */
882 crossfade_fade_in_rem -= fade_rem;
884 if (crossfade_chunk)
886 /* Mix the data */
887 size_t fade_total = fade_rem;
888 fade_rem = crossfade_mix_fade(factor, fade_rem, buf,
889 &crossfade_sample, &crossfade_chunk);
890 length -= fade_total - fade_rem;
891 buf += fade_total - fade_rem;
892 if (!length)
893 return;
896 samples = fade_rem / 2;
897 input_buf = (int16_t *)buf;
898 /* Fade remaining samples in place */
899 while (samples--)
901 int32_t sample = *input_buf;
902 *input_buf++ = (sample * factor) >> 8;
906 if (crossfade_chunk)
908 /* Mix the data */
909 size_t mix_total = length;
910 /* A factor of 256 means mix only, no fading */
911 length = crossfade_mix_fade(256, length, buf,
912 &crossfade_sample, &crossfade_chunk);
913 buf += mix_total - length;
914 if (!length)
915 return;
918 /* Commit samples to the buffer */
919 while (!prepare_insert(length))
920 sleep(1);
921 while (length > 0)
923 COMMIT_IF_NEEDED;
924 size_t pcmbuffer_index = pcmbuffer_pos + pcmbuffer_fillpos;
925 size_t copy_n = MIN(length, pcmbuf_size - pcmbuffer_index);
926 memcpy(&pcmbuffer[pcmbuffer_index], buf, copy_n);
927 buf += copy_n;
928 pcmbuffer_fillpos += copy_n;
929 length -= copy_n;
932 /* if no more fading-in to do, stop the crossfade */
933 if (!(crossfade_fade_in_rem || crossfade_chunk))
934 crossfade_active = false;
937 static void pcmbuf_finish_crossfade_enable(void)
939 /* Copy the pending setting over now */
940 crossfade_enabled = crossfade_enable_request;
942 pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
943 /* If crossfading, try to keep the buffer full other than 1 second */
944 (pcmbuf_size - BYTERATE) :
945 /* Otherwise, just use the default */
946 PCMBUF_WATERMARK;
949 bool pcmbuf_is_crossfade_active(void)
951 return crossfade_active || crossfade_track_change_started;
954 void pcmbuf_request_crossfade_enable(bool on_off)
956 /* Next setting to be used, not applied now */
957 crossfade_enable_request = on_off;
960 bool pcmbuf_is_same_size(void)
962 /* if pcmbuffer is NULL, then not set up yet even once so always */
963 bool same_size = pcmbuffer ?
964 (get_next_required_pcmbuf_size() == pcmbuf_size) : true;
966 /* no buffer change needed, so finish crossfade setup now */
967 if (same_size)
968 pcmbuf_finish_crossfade_enable();
970 return same_size;
972 #endif /* HAVE_CROSSFADE */
975 /** Voice */
977 /* Returns pcm buffer usage in percents (0 to 100). */
978 static int pcmbuf_usage(void)
980 return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
983 static int pcmbuf_mix_free(void)
985 if (mix_chunk)
987 size_t my_mix_end =
988 (size_t)&((int16_t *)mix_chunk->addr)[pcmbuf_mix_sample];
989 size_t my_write_pos = (size_t)&pcmbuffer[pcmbuffer_pos];
990 if (my_write_pos < my_mix_end)
991 my_write_pos += pcmbuf_size;
992 return (my_write_pos - my_mix_end) * 100 / pcmbuf_unplayed_bytes;
994 return 100;
997 void *pcmbuf_request_voice_buffer(int *count)
999 /* A get-it-to-work-for-now hack (audio status could change by
1000 completion) */
1001 if (audio_status() & AUDIO_STATUS_PLAY)
1003 if (read_chunk == NULL)
1005 return NULL;
1007 else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 &&
1008 (mix_chunk || read_chunk->link))
1010 *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
1011 return voicebuf;
1013 else
1015 return NULL;
1018 else
1020 return pcmbuf_request_buffer(count);
1024 void pcmbuf_write_voice_complete(int count)
1026 /* A get-it-to-work-for-now hack (audio status could have changed) */
1027 if (!(audio_status() & AUDIO_STATUS_PLAY))
1029 pcmbuf_write_complete(count);
1030 return;
1033 int16_t *ibuf = (int16_t *)voicebuf;
1034 int16_t *obuf;
1035 size_t chunk_samples;
1037 if (mix_chunk == NULL && read_chunk != NULL)
1039 mix_chunk = read_chunk->link;
1040 /* Start 1/8s into the next chunk */
1041 pcmbuf_mix_sample = BYTERATE / 16;
1044 if (!mix_chunk)
1045 return;
1047 obuf = (int16_t *)mix_chunk->addr;
1048 chunk_samples = mix_chunk->size / sizeof (int16_t);
1050 count <<= 1;
1052 while (count-- > 0)
1054 int32_t sample = *ibuf++;
1056 if (pcmbuf_mix_sample >= chunk_samples)
1058 mix_chunk = mix_chunk->link;
1059 if (!mix_chunk)
1060 return;
1061 pcmbuf_mix_sample = 0;
1062 obuf = mix_chunk->addr;
1063 chunk_samples = mix_chunk->size / 2;
1065 sample += obuf[pcmbuf_mix_sample] >> 2;
1066 obuf[pcmbuf_mix_sample++] = clip_sample_16(sample);
1071 /** Debug menu, other metrics */
1073 /* Amount of bytes left in the buffer. */
1074 size_t pcmbuf_free(void)
1076 if (read_chunk != NULL)
1078 void *read = read_chunk->addr;
1079 void *write = &pcmbuffer[pcmbuffer_pos + pcmbuffer_fillpos];
1080 if (read < write)
1081 return (size_t)(read - write) + pcmbuf_size;
1082 else
1083 return (size_t) (read - write);
1085 return pcmbuf_size - pcmbuffer_fillpos;
1088 size_t pcmbuf_get_bufsize(void)
1090 return pcmbuf_size;
1093 int pcmbuf_used_descs(void)
1095 struct chunkdesc *temp = read_chunk;
1096 unsigned int i = 0;
1097 while (temp) {
1098 temp = temp->link;
1099 i++;
1101 return i;
1104 int pcmbuf_descs(void)
1106 return NUM_CHUNK_DESCS(pcmbuf_size);
1109 #ifdef ROCKBOX_HAS_LOGF
1110 unsigned char *pcmbuf_get_meminfo(size_t *length)
1112 *length = pcmbuf_bufend - pcmbuffer;
1113 return pcmbuffer;
1115 #endif
1118 /** Misc */
1120 bool pcmbuf_is_lowdata(void)
1122 if (!pcm_is_playing() || pcm_is_paused()
1123 #ifdef HAVE_CROSSFADE
1124 || pcmbuf_is_crossfade_active()
1125 #endif
1127 return false;
1129 #if MEMORYSIZE > 2
1130 /* 1 seconds of buffer is low data */
1131 return LOW_DATA(4);
1132 #else
1133 /* under watermark is low data */
1134 return (pcmbuf_unplayed_bytes < pcmbuf_watermark);
1135 #endif
1138 void pcmbuf_set_low_latency(bool state)
1140 low_latency_mode = state;
1143 unsigned long pcmbuf_get_latency(void)
1145 return (pcmbuf_unplayed_bytes + pcm_get_bytes_waiting()) * 1000 / BYTERATE;
1148 #ifndef HAVE_HARDWARE_BEEP
1149 #define MINIBUF_SAMPLES (NATIVE_FREQUENCY / 1000 * KEYCLICK_DURATION)
1150 #define MINIBUF_SIZE (MINIBUF_SAMPLES*4)
1152 /* Generates a constant square wave sound with a given frequency
1153 in Hertz for a duration in milliseconds. */
1154 void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
1156 unsigned int step = 0xffffffffu / NATIVE_FREQUENCY * frequency;
1157 int32_t phase = 0;
1158 int16_t *bufptr, *bufstart, *bufend;
1159 int32_t sample;
1160 int nsamples = NATIVE_FREQUENCY / 1000 * duration;
1161 bool mix = read_chunk != NULL && read_chunk->link != NULL;
1162 int i;
1164 bufend = SKIPBYTES((int16_t *)pcmbuffer, pcmbuf_size);
1166 /* Find the insertion point and set bufstart to the start of it */
1167 if (mix)
1169 /* Get the currently playing chunk at the current position. */
1170 bufstart = (int16_t *)pcm_play_dma_get_peak_buffer(&i);
1172 /* If above isn't implemented or pcm is stopped, no beepeth. */
1173 if (!bufstart || !pcm_is_playing())
1174 return;
1176 /* Give 5ms clearance. */
1177 bufstart += BYTERATE / 200;
1179 #ifdef HAVE_PCM_DMA_ADDRESS
1180 /* Returned peak addresses are DMA addresses */
1181 bufend = pcm_dma_addr(bufend);
1182 #endif
1184 /* Wrapped above? */
1185 if (bufstart >= bufend)
1186 bufstart -= pcmbuf_size;
1188 /* NOTE: On some targets using hardware DMA, cache range flushing may
1189 * be required or the writes may not be picked up by the controller.
1190 * An incremental flush should be done periodically during the mixdown. */
1192 else if (nsamples <= MINIBUF_SAMPLES)
1194 static int16_t minibuf[MINIBUF_SAMPLES*2] __attribute__((aligned(4)));
1195 /* Use mini buffer */
1196 bufstart = minibuf;
1197 bufend = SKIPBYTES(bufstart, MINIBUF_SIZE);
1199 else if (!audio_buffer_state_trashed())
1201 /* Use pcmbuffer */
1202 bufstart = (int16_t *)pcmbuffer;
1204 else
1206 /* No place */
1207 return;
1210 bufptr = bufstart;
1212 /* Mix square wave into buffer */
1213 for (i = 0; i < nsamples; ++i)
1215 int32_t amp = (phase >> 31) ^ (int32_t)amplitude;
1216 sample = mix ? *bufptr : 0;
1217 *bufptr++ = clip_sample_16(sample + amp);
1218 if (bufptr >= bufend)
1219 bufptr = (int16_t *)pcmbuffer;
1220 sample = mix ? *bufptr : 0;
1221 *bufptr++ = clip_sample_16(sample + amp);
1222 if (bufptr >= bufend)
1223 bufptr = (int16_t *)pcmbuffer;
1225 phase += step;
1228 pcm_play_lock();
1229 #ifdef HAVE_RECORDING
1230 pcm_rec_lock();
1231 #endif
1233 /* Kick off playback if required and it won't interfere */
1234 if (!pcm_is_playing()
1235 #ifdef HAVE_RECORDING
1236 && !pcm_is_recording()
1237 #endif
1240 pcm_play_data(NULL, (unsigned char *)bufstart, nsamples * 4);
1243 pcm_play_unlock();
1244 #ifdef HAVE_RECORDING
1245 pcm_rec_unlock();
1246 #endif
1248 #endif /* HAVE_HARDWARE_BEEP */