Move bin2c handling to libtools.make
[maemo-rb.git] / apps / pcmbuf.c
blobd36883fc5bf8db133ba98ac18dff5351f27ed8e0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Miika Pekkarinen
11 * Copyright (C) 2011 by Michael Sevakis
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdio.h>
23 #include "config.h"
24 #include "system.h"
25 #include "debug.h"
26 #include <kernel.h>
27 #include "pcm.h"
28 #include "pcm_mixer.h"
29 #include "pcmbuf.h"
30 #include "dsp-util.h"
31 #include "playback.h"
32 #include "codec_thread.h"
34 /* Define LOGF_ENABLE to enable logf output in this file */
35 /*#define LOGF_ENABLE*/
36 #include "logf.h"
37 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
38 #include "cpu.h"
39 #endif
40 #include "settings.h"
41 #include "audio.h"
42 #include "voice_thread.h"
43 #include "dsp.h"
45 /* This is the target fill size of chunks on the pcm buffer
46 Can be any number of samples but power of two sizes make for faster and
47 smaller math - must be < 65536 bytes */
48 #define PCMBUF_CHUNK_SIZE 8192u
50 /* Massive size is a nasty temp fix */
51 #define PCMBUF_GUARD_SIZE (1024u*12*((NATIVE_FREQUENCY+7999)/8000))
53 /* Mnemonics for common data commit thresholds */
54 #define COMMIT_CHUNKS PCMBUF_CHUNK_SIZE
55 #define COMMIT_ALL_DATA 1u
57 /* Size of the crossfade buffer where codec data is written to be faded
58 on commit */
59 #define CROSSFADE_BUFSIZE 8192u
61 /* Return data level in 1/4-second increments */
62 #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs))
64 /* Number of bytes played per second:
65 (sample rate * 2 channels * 2 bytes/sample) */
66 #define BYTERATE (NATIVE_FREQUENCY * 4)
68 #if MEMORYSIZE > 2
69 /* Keep watermark high for large memory target - at least (2s) */
70 #define PCMBUF_WATERMARK (BYTERATE * 2)
71 #define MIN_BUFFER_SIZE (BYTERATE * 3)
72 /* 1 seconds of buffer is low data */
73 #define LOW_DATA DATA_LEVEL(4)
74 #else
75 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
76 #define MIN_BUFFER_SIZE (BYTERATE * 1)
77 /* under watermark is low data */
78 #define LOW_DATA pcmbuf_watermark
79 #endif
81 /* Describes each audio packet - keep it small since there are many of them */
82 struct chunkdesc
84 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */
85 uint8_t is_end; /* Flag indicating end of track */
86 uint8_t pos_key; /* Who put the position info in (0 = undefined) */
87 unsigned long elapsed; /* Elapsed time to use */
88 off_t offset; /* Offset to use */
91 /* General PCM buffer data */
92 #define INVALID_BUF_INDEX ((size_t)0 - (size_t)1)
94 static void *pcmbuf_buffer;
95 static void *pcmbuf_guardbuf;
96 static size_t pcmbuf_size;
97 static struct chunkdesc *pcmbuf_descriptors;
98 static unsigned int pcmbuf_desc_count;
99 static unsigned int position_key = 1;
101 static size_t chunk_ridx;
102 static size_t chunk_widx;
104 static size_t pcmbuf_bytes_waiting;
105 static struct chunkdesc *current_desc;
107 /* Only written if HAVE_CROSSFADE */
108 static size_t pcmbuf_watermark = PCMBUF_WATERMARK;
110 static bool low_latency_mode = false;
112 static bool pcmbuf_sync_position = false;
114 /* Fade effect */
115 static unsigned int fade_vol = MIX_AMP_UNITY;
116 static enum
118 PCM_NOT_FADING = 0,
119 PCM_FADING_IN,
120 PCM_FADING_OUT,
121 } fade_state = PCM_NOT_FADING;
122 static bool fade_out_complete = false;
124 /* Voice */
125 static bool soft_mode = false;
127 #ifdef HAVE_CROSSFADE
128 /* Crossfade buffer */
129 static void *crossfade_buffer;
131 /* Crossfade related state */
132 static int crossfade_setting;
133 static int crossfade_enable_request;
134 static bool crossfade_mixmode;
135 static bool crossfade_auto_skip;
137 static enum
139 CROSSFADE_INACTIVE = 0,
140 CROSSFADE_TRACK_CHANGE_STARTED,
141 CROSSFADE_ACTIVE,
142 } crossfade_status = CROSSFADE_INACTIVE;
144 /* Track the current location for processing crossfade */
145 static size_t crossfade_index;
147 /* Counters for fading in new data */
148 static size_t crossfade_fade_in_total;
149 static size_t crossfade_fade_in_rem;
151 /* Defines for operations on position info when mixing/fading -
152 passed in offset parameter */
153 enum
155 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */
156 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */
157 /* Positive values cause stamping/restamping */
160 static void crossfade_start(void);
161 static void write_to_crossfade(size_t size, unsigned long elapsed,
162 off_t offset);
163 static void pcmbuf_finish_crossfade_enable(void);
164 #endif /* HAVE_CROSSFADE */
166 /* Thread */
167 #ifdef HAVE_PRIORITY_SCHEDULING
168 static int codec_thread_priority = PRIORITY_PLAYBACK;
169 #endif
171 /* Callbacks into playback.c */
172 extern void audio_pcmbuf_position_callback(unsigned long elapsed,
173 off_t offset, unsigned int key);
174 extern void audio_pcmbuf_track_change(bool pcmbuf);
175 extern bool audio_pcmbuf_may_play(void);
176 extern void audio_pcmbuf_sync_position(void);
179 /**************************************/
181 /* Return number of commited bytes in buffer (committed chunks count as
182 a full chunk even if only partially filled) */
183 static size_t pcmbuf_unplayed_bytes(void)
185 size_t ridx = chunk_ridx;
186 size_t widx = chunk_widx;
188 if (ridx > widx)
189 widx += pcmbuf_size;
191 return widx - ridx;
194 /* Returns TRUE if amount of data is under the target fill size */
195 static bool pcmbuf_data_critical(void)
197 return pcmbuf_unplayed_bytes() < LOW_DATA;
200 /* Return the next PCM chunk in the PCM buffer given a byte index into it */
201 static size_t index_next(size_t index)
203 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE);
205 if (index >= pcmbuf_size)
206 index -= pcmbuf_size;
208 return index;
211 /* Convert a byte offset in the PCM buffer into a pointer in the buffer */
212 static FORCE_INLINE void * index_buffer(size_t index)
214 return pcmbuf_buffer + index;
217 /* Convert a pointer in the buffer into an index offset */
218 static FORCE_INLINE size_t buffer_index(void *p)
220 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer;
223 /* Return a chunk descriptor for a byte index in the buffer */
224 static struct chunkdesc * index_chunkdesc(size_t index)
226 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE];
229 /* Return a chunk descriptor for a byte index in the buffer, offset by 'offset'
230 chunks */
231 static struct chunkdesc * index_chunkdesc_offs(size_t index, int offset)
233 int i = index / PCMBUF_CHUNK_SIZE;
235 if (offset != 0)
237 i = (i + offset) % pcmbuf_desc_count;
239 /* remainder => modulus */
240 if (i < 0)
241 i += pcmbuf_desc_count;
244 return &pcmbuf_descriptors[i];
248 /** Accept new PCM data */
250 /* Split the uncommitted data as needed into chunks, stopping when uncommitted
251 data is below the threshold */
252 static void commit_chunks(size_t threshold)
254 size_t index = chunk_widx;
255 size_t end_index = index + pcmbuf_bytes_waiting;
257 /* Copy to the beginning of the buffer all data that must wrap */
258 if (end_index > pcmbuf_size)
259 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size);
261 struct chunkdesc *desc = index_chunkdesc(index);
265 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE);
266 pcmbuf_bytes_waiting -= size;
268 /* Fill in the values in the new buffer chunk */
269 desc->size = (uint16_t)size;
271 /* Advance the current write chunk and make it available to the
272 PCM callback */
273 chunk_widx = index = index_next(index);
274 desc = index_chunkdesc(index);
276 /* Reset it before using it */
277 desc->is_end = 0;
278 desc->pos_key = 0;
280 while (pcmbuf_bytes_waiting >= threshold);
283 /* If uncommitted data count is above or equal to the threshold, commit it */
284 static FORCE_INLINE void commit_if_needed(size_t threshold)
286 if (pcmbuf_bytes_waiting >= threshold)
287 commit_chunks(threshold);
290 /* Place positioning information in the chunk */
291 static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed,
292 off_t offset)
294 /* One-time stamping of a given chunk by the same track - new track may
295 overwrite */
296 unsigned int key = position_key;
298 if (desc->pos_key != key)
300 desc->pos_key = key;
301 desc->elapsed = elapsed;
302 desc->offset = offset;
306 /* Set priority of the codec thread */
307 #ifdef HAVE_PRIORITY_SCHEDULING
309 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */
310 static void boost_codec_thread(int pcm_fill_state)
312 static const int8_t prios[11] =
314 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */
315 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */
316 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */
317 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */
318 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */
319 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */
320 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */
321 /* raising priority above 70% shouldn't be needed */
322 PRIORITY_PLAYBACK, /* 70 - 80% */
323 PRIORITY_PLAYBACK, /* 80 - 90% */
324 PRIORITY_PLAYBACK, /* 90 -100% */
325 PRIORITY_PLAYBACK, /* 100% */
328 int new_prio = prios[pcm_fill_state];
330 /* Keep voice and codec threads at the same priority or else voice
331 * will starve if the codec thread's priority is boosted. */
332 if (new_prio != codec_thread_priority)
334 codec_thread_set_priority(new_prio);
335 voice_thread_set_priority(new_prio);
336 codec_thread_priority = new_prio;
339 #else
340 #define boost_codec_thread(pcm_fill_state) do{}while(0)
341 #endif /* HAVE_PRIORITY_SCHEDULING */
343 /* Get the next available buffer and size - assumes adequate space exists */
344 static void * get_write_buffer(size_t *size)
346 /* Obtain current chunk fill address */
347 size_t index = chunk_widx + pcmbuf_bytes_waiting;
348 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE;
350 /* Get count to the end of the buffer where a wrap will happen +
351 the guard */
352 size_t endsize = index_end - index;
354 /* Return available unwrapped space */
355 *size = MIN(*size, endsize);
357 return index_buffer(index);
360 /* Commit outstanding data leaving less than a chunk size remaining and
361 write position info to the first chunk */
362 static void commit_write_buffer(size_t size, unsigned long elapsed, off_t offset)
364 struct chunkdesc *desc = index_chunkdesc(chunk_widx);
365 stamp_chunk(desc, elapsed, offset);
367 /* Add this data and commit if one or more chunks are ready */
368 pcmbuf_bytes_waiting += size;
370 commit_if_needed(COMMIT_CHUNKS);
373 /* Request space in the buffer for writing output samples */
374 void * pcmbuf_request_buffer(int *count)
376 size_t size = *count * 4;
378 #ifdef HAVE_CROSSFADE
379 /* We're going to crossfade to a new track, which is now on its way */
380 if (crossfade_status == CROSSFADE_TRACK_CHANGE_STARTED)
381 crossfade_start();
383 /* If crossfade has begun, put the new track samples in crossfade_buffer */
384 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE)
385 size = CROSSFADE_BUFSIZE;
386 #endif
388 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
389 size_t remaining = pcmbuf_unplayed_bytes();
391 /* Need to have length bytes to prevent wrapping overwriting - leave one
392 descriptor free to guard so that 0 != full in ring buffer */
393 size_t freespace = pcmbuf_free();
395 if (pcmbuf_sync_position)
396 audio_pcmbuf_sync_position();
398 if (freespace < size + PCMBUF_CHUNK_SIZE)
399 return NULL;
401 /* Maintain the buffer level above the watermark */
402 if (status != CHANNEL_STOPPED)
404 if (low_latency_mode)
406 /* 1/4s latency. */
407 if (remaining > DATA_LEVEL(1))
408 return NULL;
411 /* Boost CPU if necessary */
412 size_t realrem = pcmbuf_size - freespace;
414 if (realrem < pcmbuf_watermark)
415 trigger_cpu_boost();
417 boost_codec_thread(realrem*10 / pcmbuf_size);
419 #ifdef HAVE_CROSSFADE
420 /* Disable crossfade if < .5s of audio */
421 if (remaining < DATA_LEVEL(2))
422 crossfade_status = CROSSFADE_INACTIVE;
423 #endif
425 else /* !playing */
427 /* Boost CPU for pre-buffer */
428 trigger_cpu_boost();
430 /* If pre-buffered to the watermark, start playback */
431 if (!pcmbuf_data_critical() && audio_pcmbuf_may_play())
432 pcmbuf_play_start();
435 void *buf =
436 #ifdef HAVE_CROSSFADE
437 crossfade_status != CROSSFADE_INACTIVE ? crossfade_buffer :
438 #endif
439 get_write_buffer(&size);
441 *count = size / 4;
442 return buf;
445 /* Handle new samples to the buffer */
446 void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset)
448 size_t size = count * 4;
450 #ifdef HAVE_CROSSFADE
451 if (crossfade_status != CROSSFADE_INACTIVE)
453 write_to_crossfade(size, elapsed, offset);
455 else
456 #endif
458 commit_write_buffer(size, elapsed, offset);
461 /* Revert to position updates by PCM */
462 pcmbuf_sync_position = false;
466 /** Init */
467 static unsigned int get_next_required_pcmbuf_chunks(void)
469 size_t size = MIN_BUFFER_SIZE;
471 #ifdef HAVE_CROSSFADE
472 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
474 size_t seconds = global_settings.crossfade_fade_out_delay +
475 global_settings.crossfade_fade_out_duration;
476 size += seconds * BYTERATE;
478 #endif
480 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE));
481 return size / PCMBUF_CHUNK_SIZE;
484 /* Initialize the ringbuffer state */
485 static void init_buffer_state(void)
487 /* Reset counters */
488 chunk_ridx = chunk_widx = 0;
489 pcmbuf_bytes_waiting = 0;
491 /* Reset first descriptor */
492 struct chunkdesc *desc = pcmbuf_descriptors;
493 desc->is_end = 0;
494 desc->pos_key = 0;
497 /* Initialize the PCM buffer. The structure looks like this:
498 * ...[|FADEBUF]|---------PCMBUF---------|GUARDBUF|DESCS| */
499 size_t pcmbuf_init(void *bufend)
501 void *bufstart;
503 /* Set up the buffers */
504 pcmbuf_desc_count = get_next_required_pcmbuf_chunks();
505 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE;
506 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count;
508 pcmbuf_buffer = (void *)pcmbuf_descriptors -
509 pcmbuf_size - PCMBUF_GUARD_SIZE;
511 /* Mem-align buffer chunks for more efficient handling in lower layers */
512 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE);
514 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size;
515 bufstart = pcmbuf_buffer;
517 #ifdef HAVE_CROSSFADE
518 /* Allocate FADEBUF if it will be needed */
519 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
521 bufstart -= CROSSFADE_BUFSIZE;
522 crossfade_buffer = bufstart;
525 pcmbuf_finish_crossfade_enable();
526 #endif /* HAVE_CROSSFADE */
528 init_buffer_state();
530 pcmbuf_soft_mode(false);
532 return bufend - bufstart;
536 /** Track change */
538 /* Place a track change notification in a specific descriptor or post it
539 immediately if the buffer is empty or the index is invalid */
540 static void pcmbuf_monitor_track_change_ex(size_t index, int offset)
542 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX)
544 /* If monitoring, set flag in specified chunk */
545 index_chunkdesc_offs(index, offset)->is_end = 1;
547 else
549 /* Post now if no outstanding buffers exist */
550 audio_pcmbuf_track_change(false);
554 /* Clear end of track and optionally the positioning info for all data */
555 static void pcmbuf_cancel_track_change(bool position)
557 size_t index = chunk_ridx;
559 while (1)
561 struct chunkdesc *desc = index_chunkdesc(index);
563 desc->is_end = 0;
565 if (position)
566 desc->pos_key = 0;
568 if (index == chunk_widx)
569 break;
571 index = index_next(index);
575 /* Place a track change notification at the end of the buffer or post it
576 immediately if the buffer is empty */
577 void pcmbuf_monitor_track_change(bool monitor)
579 pcm_play_lock();
581 if (monitor)
582 pcmbuf_monitor_track_change_ex(chunk_widx, -1);
583 else
584 pcmbuf_cancel_track_change(false);
586 pcm_play_unlock();
589 void pcmbuf_start_track_change(enum pcm_track_change_type type)
591 #ifdef HAVE_CROSSFADE
592 bool crossfade = false;
593 #endif
594 bool auto_skip = type != TRACK_CHANGE_MANUAL;
596 /* Commit all outstanding data before starting next track - tracks don't
597 comingle inside a single buffer chunk */
598 commit_if_needed(COMMIT_ALL_DATA);
600 /* Update position key so that:
601 1) Positions are keyed to the track to which they belong for sync
602 purposes
604 2) Buffers stamped with the outgoing track's positions are restamped
605 to the incoming track's positions when crossfading
607 if (++position_key > UINT8_MAX)
608 position_key = 1;
610 if (type == TRACK_CHANGE_END_OF_DATA)
612 /* If end of all data, force playback */
613 if (audio_pcmbuf_may_play())
614 pcmbuf_play_start();
616 #ifdef HAVE_CROSSFADE
617 /* Determine whether this track change needs to crossfaded and how */
618 else if (crossfade_setting != CROSSFADE_ENABLE_OFF &&
619 !pcmbuf_is_crossfade_active() &&
620 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) &&
621 !low_latency_mode)
623 switch (crossfade_setting)
625 case CROSSFADE_ENABLE_AUTOSKIP:
626 crossfade = auto_skip;
627 break;
628 case CROSSFADE_ENABLE_MANSKIP:
629 crossfade = !auto_skip;
630 break;
631 case CROSSFADE_ENABLE_SHUFFLE:
632 crossfade = global_settings.playlist_shuffle;
633 break;
634 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
635 crossfade = global_settings.playlist_shuffle || !auto_skip;
636 break;
637 case CROSSFADE_ENABLE_ALWAYS:
638 crossfade = true;
639 break;
642 /* else crossfade is off, crossfade is already active, not enough data,
643 * pcm is off now (implying low data), not crossfading or low latency mode
646 if (crossfade)
648 logf("crossfade track change");
650 /* Don't enable mix mode when skipping tracks manually */
651 crossfade_mixmode = auto_skip &&
652 global_settings.crossfade_fade_out_mixmode;
654 crossfade_auto_skip = auto_skip;
656 crossfade_status = CROSSFADE_TRACK_CHANGE_STARTED;
658 trigger_cpu_boost();
660 /* Cancel any pending automatic gapless transition and if a manual
661 skip, stop position updates */
662 pcm_play_lock();
663 pcmbuf_cancel_track_change(!auto_skip);
664 pcm_play_unlock();
666 else
667 #endif /* HAVE_CROSSFADE */
668 if (auto_skip)
670 /* The codec is moving on to the next track, but the current track will
671 * continue to play, so mark the last write chunk as the last one in
672 * the track */
673 logf("gapless track change");
674 #ifdef HAVE_CROSSFADE
675 if (crossfade_status != CROSSFADE_INACTIVE)
677 /* Crossfade is still active but crossfade is not happening - for
678 * now, chicken-out and clear out the buffer (just like before) to
679 * avoid fade pile-up on short tracks fading-in over long ones */
680 pcmbuf_play_stop();
682 #endif
683 pcmbuf_monitor_track_change(true);
685 else
687 /* Discard old data; caller needs no transition notification */
688 logf("manual track change");
689 pcmbuf_play_stop();
694 /** Playback */
696 /* PCM driver callback */
697 static void pcmbuf_pcm_callback(const void **start, size_t *size)
699 /*- Process the chunk that just finished -*/
700 size_t index = chunk_ridx;
701 struct chunkdesc *desc = current_desc;
703 if (desc)
705 /* If last chunk in the track, notify of track change */
706 if (desc->is_end != 0)
707 audio_pcmbuf_track_change(true);
709 /* Free it for reuse */
710 chunk_ridx = index = index_next(index);
713 /*- Process the new one -*/
714 if (index != chunk_widx && !fade_out_complete)
716 current_desc = desc = index_chunkdesc(index);
718 *start = index_buffer(index);
719 *size = desc->size;
721 if (desc->pos_key != 0)
723 /* Positioning chunk - notify playback */
724 audio_pcmbuf_position_callback(desc->elapsed, desc->offset,
725 desc->pos_key);
730 /* Force playback */
731 void pcmbuf_play_start(void)
733 logf("pcmbuf_play_start");
735 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED &&
736 chunk_widx != chunk_ridx)
738 current_desc = NULL;
739 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
740 NULL, 0);
744 /* Stop channel, empty and reset buffer */
745 void pcmbuf_play_stop(void)
747 logf("pcmbuf_play_stop");
749 /* Reset channel */
750 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
752 /* Reset buffer */
753 init_buffer_state();
755 /* Revert to position updates by PCM */
756 pcmbuf_sync_position = false;
758 #ifdef HAVE_CROSSFADE
759 crossfade_status = CROSSFADE_INACTIVE;
760 #endif
762 /* Can unboost the codec thread here no matter who's calling,
763 * pretend full pcm buffer to unboost */
764 boost_codec_thread(10);
767 void pcmbuf_pause(bool pause)
769 logf("pcmbuf_pause: %s", pause?"pause":"play");
771 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED)
772 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
773 else if (!pause)
774 pcmbuf_play_start();
778 /** Crossfade */
780 #ifdef HAVE_CROSSFADE
781 /* Find the buffer index that's 'size' bytes away from 'index' */
782 static size_t crossfade_find_index(size_t index, size_t size)
784 if (index != INVALID_BUF_INDEX)
786 size_t i = ALIGN_DOWN(index, PCMBUF_CHUNK_SIZE);
787 size += index - i;
789 while (i != chunk_widx)
791 size_t desc_size = index_chunkdesc(i)->size;
793 if (size < desc_size)
794 return i + size;
796 size -= desc_size;
797 i = index_next(i);
801 return INVALID_BUF_INDEX;
804 /* Align the needed buffer area up to the end of existing data */
805 static size_t crossfade_find_buftail(size_t buffer_rem, size_t buffer_need)
807 crossfade_index = chunk_ridx;
809 if (buffer_rem > buffer_need)
811 size_t distance;
813 if (crossfade_auto_skip)
815 /* Automatic track changes only modify the last part of the buffer,
816 * so find the right chunk and sample to start the crossfade */
817 distance = buffer_rem - buffer_need;
818 buffer_rem = buffer_need;
820 else
822 /* Manual skips occur immediately, but give 1/5s to process */
823 distance = BYTERATE / 5;
824 buffer_rem -= BYTERATE / 5;
827 crossfade_index = crossfade_find_index(crossfade_index, distance);
830 return buffer_rem;
833 /* Returns the number of bytes _NOT_ mixed/faded */
834 static size_t crossfade_mix_fade(int factor, size_t size, void *buf,
835 size_t *out_index, unsigned long elapsed,
836 off_t offset)
838 if (size == 0)
839 return 0;
841 size_t index = *out_index;
843 if (index == INVALID_BUF_INDEX)
844 return size;
846 const int16_t *input_buf = buf;
847 int16_t *output_buf = index_buffer(index);
849 while (size)
851 struct chunkdesc *desc = index_chunkdesc(index);
853 switch (offset)
855 case MIXFADE_NULLIFY_POS:
856 /* Stop position updates for the chunk */
857 desc->pos_key = 0;
858 break;
859 case MIXFADE_KEEP_POS:
860 /* Keep position info as it is */
861 break;
862 default:
863 /* Replace position info */
864 stamp_chunk(desc, elapsed, offset);
867 size_t rem = desc->size - (index % PCMBUF_CHUNK_SIZE);
868 int16_t *chunk_end = SKIPBYTES(output_buf, rem);
870 if (size < rem)
871 rem = size;
873 size -= rem;
877 /* fade left and right channel at once to keep buffer alignment */
878 int32_t left = output_buf[0];
879 int32_t right = output_buf[1];
881 if (input_buf)
883 /* fade the input buffer and mix into the chunk */
884 left += *input_buf++ * factor >> 8;
885 right += *input_buf++ * factor >> 8;
886 left = clip_sample_16(left);
887 right = clip_sample_16(right);
889 else
891 /* fade the chunk only */
892 left = left * factor >> 8;
893 right = right * factor >> 8;
896 *output_buf++ = left;
897 *output_buf++ = right;
899 rem -= 4;
901 while (rem);
903 /* move to next chunk as needed */
904 if (output_buf >= chunk_end)
906 index = index_next(index);
908 if (index == chunk_widx)
910 /* End of existing data */
911 *out_index = INVALID_BUF_INDEX;
912 return size;
915 output_buf = index_buffer(index);
919 *out_index = buffer_index(output_buf);
920 return 0;
923 /* Initializes crossfader, calculates all necessary parameters and performs
924 * fade-out with the PCM buffer. */
925 static void crossfade_start(void)
927 logf("crossfade_start");
929 pcm_play_lock();
931 /* Initialize the crossfade buffer size to all of the buffered data that
932 * has not yet been sent to the DMA */
933 size_t unplayed = pcmbuf_unplayed_bytes();
935 /* Reject crossfade if less than .5s of data */
936 if (unplayed < DATA_LEVEL(2))
938 logf("crossfade rejected");
940 crossfade_status = CROSSFADE_INACTIVE;
942 if (crossfade_auto_skip)
943 pcmbuf_monitor_track_change(true);
945 pcm_play_unlock();
946 return;
949 /* Fading will happen */
950 crossfade_status = CROSSFADE_ACTIVE;
952 /* Get fade info from settings. */
953 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
954 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
955 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
956 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE;
958 if (!crossfade_auto_skip)
960 /* Forego fade-in delay on manual skip - do the best to preserve auto skip
961 relationship */
962 if (fade_out_delay > fade_in_delay)
963 fade_out_delay -= fade_in_delay;
964 else
965 fade_out_delay = 0;
967 fade_in_delay = 0;
970 size_t fade_out_need = fade_out_delay + fade_out_rem;
972 if (!crossfade_mixmode)
974 size_t buffer_rem = crossfade_find_buftail(unplayed, fade_out_need);
976 pcm_play_unlock();
978 if (buffer_rem < fade_out_need)
980 /* Existing buffers are short */
981 size_t fade_out_short = fade_out_need - buffer_rem;
983 if (fade_out_rem >= fade_out_short)
985 /* Truncate fade-out duration */
986 fade_out_rem -= fade_out_short;
988 else
990 /* Truncate fade-out and fade-out delay */
991 fade_out_delay = fade_out_rem;
992 fade_out_rem = 0;
996 /* Completely process the crossfade fade-out effect with current PCM buffer */
998 /* Fade out the specified amount of the already processed audio */
999 size_t fade_out_total = fade_out_rem;
1001 /* Find the right chunk and sample to start fading out */
1002 size_t fade_out_index = crossfade_find_index(crossfade_index, fade_out_delay);
1004 while (fade_out_rem > 0)
1006 /* Each 1/20 second of audio will have the same fade applied */
1007 size_t block_rem = MIN(BYTERATE / 20, fade_out_rem);
1008 int factor = (fade_out_rem << 8) / fade_out_total;
1010 fade_out_rem -= block_rem;
1012 crossfade_mix_fade(factor, block_rem, NULL, &fade_out_index,
1013 0, MIXFADE_KEEP_POS);
1016 /* zero out the rest of the buffer */
1017 crossfade_mix_fade(0, pcmbuf_size, NULL, &fade_out_index,
1018 0, MIXFADE_NULLIFY_POS);
1020 pcm_play_lock();
1023 /* Initialize fade-in counters */
1024 crossfade_fade_in_total = fade_in_duration;
1025 crossfade_fade_in_rem = fade_in_duration;
1027 /* Find the right chunk and sample to start fading in - redo from read
1028 chunk in case original position were/was overrun in callback - the
1029 track change event _must not_ ever fail to happen */
1030 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay;
1032 crossfade_find_buftail(unplayed, fade_out_need);
1034 if (crossfade_auto_skip)
1035 pcmbuf_monitor_track_change_ex(crossfade_index, 0);
1037 pcm_play_unlock();
1039 logf("crossfade_start done!");
1042 /* Perform fade-in of new track */
1043 static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset)
1045 void *buf = crossfade_buffer;
1047 if (crossfade_fade_in_rem)
1049 /* Fade factor for this packet */
1050 int factor =
1051 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
1052 crossfade_fade_in_total;
1053 /* Bytes to fade */
1054 size_t fade_rem = MIN(size, crossfade_fade_in_rem);
1056 /* We _will_ fade this many bytes */
1057 crossfade_fade_in_rem -= fade_rem;
1059 if (crossfade_index != INVALID_BUF_INDEX)
1061 /* Mix the data */
1062 size_t fade_total = fade_rem;
1063 fade_rem = crossfade_mix_fade(factor, fade_rem, buf, &crossfade_index,
1064 elapsed, offset);
1065 fade_total -= fade_rem;
1066 size -= fade_total;
1067 buf += fade_total;
1069 if (!size)
1070 return;
1073 /* Fade remaining samples in place */
1074 int samples = fade_rem / 4;
1075 int16_t *input_buf = buf;
1077 while (samples--)
1079 int32_t left = input_buf[0];
1080 int32_t right = input_buf[1];
1081 *input_buf++ = left * factor >> 8;
1082 *input_buf++ = right * factor >> 8;
1086 if (crossfade_index != INVALID_BUF_INDEX)
1088 /* Mix the data */
1089 size_t mix_total = size;
1091 /* A factor of 256 means mix only, no fading */
1092 size = crossfade_mix_fade(256, size, buf, &crossfade_index,
1093 elapsed, offset);
1094 buf += mix_total - size;
1096 if (!size)
1097 return;
1100 /* Data might remain in the fade buffer yet the fade-in has run its
1101 course - finish it off as normal chunks */
1102 while (size > 0)
1104 size_t copy_n = size;
1105 void *outbuf = get_write_buffer(&copy_n);
1106 memcpy(outbuf, buf, copy_n);
1107 commit_write_buffer(copy_n, elapsed, offset);
1108 buf += copy_n;
1109 size -= copy_n;
1112 /* if no more fading-in to do, stop the crossfade */
1113 #if 0
1114 /* This way (the previous way) can cause a sudden volume jump if mixable
1115 data is used up before the fade-in completes and that just sounds wrong
1116 -- jethead71 */
1117 if (!crossfade_fade_in_rem || crossfade_index == INVALID_BUF_INDEX)
1118 #endif
1119 /* Let fade-in complete even if not fully overlapping the existing data */
1120 if (!crossfade_fade_in_rem)
1121 crossfade_status = CROSSFADE_INACTIVE;
1124 static void pcmbuf_finish_crossfade_enable(void)
1126 /* Copy the pending setting over now */
1127 crossfade_setting = crossfade_enable_request;
1129 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ?
1130 /* If crossfading, try to keep the buffer full other than 1 second */
1131 (pcmbuf_size - BYTERATE) :
1132 /* Otherwise, just use the default */
1133 PCMBUF_WATERMARK;
1136 bool pcmbuf_is_crossfade_active(void)
1138 return crossfade_status != CROSSFADE_INACTIVE;
1141 void pcmbuf_request_crossfade_enable(int setting)
1143 /* Next setting to be used, not applied now */
1144 crossfade_enable_request = setting;
1147 bool pcmbuf_is_same_size(void)
1149 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */
1150 bool same_size = pcmbuf_buffer ?
1151 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true;
1153 /* no buffer change needed, so finish crossfade setup now */
1154 if (same_size)
1155 pcmbuf_finish_crossfade_enable();
1157 return same_size;
1159 #endif /* HAVE_CROSSFADE */
1162 /** Debug menu, other metrics */
1164 /* Amount of bytes left in the buffer, accounting for uncommitted bytes */
1165 size_t pcmbuf_free(void)
1167 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting;
1170 /* Data bytes allocated for buffer */
1171 size_t pcmbuf_get_bufsize(void)
1173 return pcmbuf_size;
1176 /* Number of committed descriptors */
1177 int pcmbuf_used_descs(void)
1179 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE;
1182 /* Total number of descriptors allocated */
1183 int pcmbuf_descs(void)
1185 return pcmbuf_desc_count;
1189 /** Fading and channel volume control */
1191 /* Sync the channel amplitude to all states */
1192 static void pcmbuf_update_volume(void)
1194 unsigned int vol = fade_vol;
1196 if (soft_mode)
1197 vol >>= 2;
1199 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol);
1202 /* Tick that does the fade for the playback channel */
1203 static void pcmbuf_fade_tick(void)
1205 /* ~1/3 second for full range fade */
1206 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1208 if (fade_state == PCM_FADING_IN)
1209 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1210 else if (fade_state == PCM_FADING_OUT)
1211 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1213 pcmbuf_update_volume();
1215 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1217 /* Fade is complete */
1218 tick_remove_task(pcmbuf_fade_tick);
1219 if (fade_state == PCM_FADING_OUT)
1221 /* Tell PCM to stop at its earliest convenience */
1222 fade_out_complete = true;
1225 fade_state = PCM_NOT_FADING;
1229 /* Fade channel in or out in the background */
1230 void pcmbuf_fade(bool fade, bool in)
1232 /* Must pause any active fade */
1233 pcm_play_lock();
1235 if (fade_state != PCM_NOT_FADING)
1236 tick_remove_task(pcmbuf_fade_tick);
1238 fade_out_complete = false;
1240 pcm_play_unlock();
1242 if (!fade)
1244 /* Simply set the level */
1245 fade_state = PCM_NOT_FADING;
1246 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1247 pcmbuf_update_volume();
1249 else
1251 /* Set direction and resume fade from current point */
1252 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1253 tick_add_task(pcmbuf_fade_tick);
1257 /* Return 'true' if fade is in progress */
1258 bool pcmbuf_fading(void)
1260 return fade_state != PCM_NOT_FADING;
1263 /* Quiet-down the channel if 'shhh' is true or else play at normal level */
1264 void pcmbuf_soft_mode(bool shhh)
1266 /* Have to block the tick or improper order could leave volume in soft
1267 mode if fading reads the old value first but updates after us. */
1268 int res = fade_state != PCM_NOT_FADING ?
1269 tick_remove_task(pcmbuf_fade_tick) : -1;
1271 soft_mode = shhh;
1272 pcmbuf_update_volume();
1274 if (res == 0)
1275 tick_add_task(pcmbuf_fade_tick);
1279 /** Time and position */
1281 /* Return the current position key value */
1282 unsigned int pcmbuf_get_position_key(void)
1284 return position_key;
1287 /* Set position updates to be synchronous and immediate in addition to during
1288 PCM frames - cancelled upon first codec insert or upon stopping */
1289 void pcmbuf_sync_position_update(void)
1291 pcmbuf_sync_position = true;
1296 /** Misc */
1298 bool pcmbuf_is_lowdata(void)
1300 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
1302 if (status != CHANNEL_PLAYING || pcmbuf_is_crossfade_active())
1303 return false;
1305 return pcmbuf_data_critical();
1308 void pcmbuf_set_low_latency(bool state)
1310 low_latency_mode = state;