Fix silly mistake
[maemo-rb.git] / apps / pcmbuf.c
blob928f6035da8e76fa25a419f682a56f6ead6eb822
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 "playback.h"
31 #include "codec_thread.h"
33 /* Define LOGF_ENABLE to enable logf output in this file */
34 /*#define LOGF_ENABLE*/
35 #include "logf.h"
36 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
37 #include "cpu.h"
38 #endif
39 #include "settings.h"
40 #include "audio.h"
41 #include "voice_thread.h"
42 #include "dsp.h"
44 /* This is the target fill size of chunks on the pcm buffer
45 Can be any number of samples but power of two sizes make for faster and
46 smaller math - must be < 65536 bytes */
47 #define PCMBUF_CHUNK_SIZE 8192u
48 #define PCMBUF_GUARD_SIZE 1024u
50 /* Mnemonics for common data commit thresholds */
51 #define COMMIT_CHUNKS PCMBUF_CHUNK_SIZE
52 #define COMMIT_ALL_DATA 1u
54 /* Size of the crossfade buffer where codec data is written to be faded
55 on commit */
56 #define CROSSFADE_BUFSIZE 8192u
58 /* Number of bytes played per second:
59 (sample rate * 2 channels * 2 bytes/sample) */
60 #define BYTERATE (NATIVE_FREQUENCY * 4)
62 #if MEMORYSIZE > 2
63 /* Keep watermark high for large memory target - at least (2s) */
64 #define PCMBUF_WATERMARK (BYTERATE * 2)
65 #define MIN_BUFFER_SIZE (BYTERATE * 3)
66 #else
67 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
68 #define MIN_BUFFER_SIZE (BYTERATE * 1)
69 #endif
71 /* Describes each audio packet - keep it small since there are many of them */
72 struct chunkdesc
74 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */
75 uint8_t is_end; /* Flag indicating end of track */
76 uint8_t pos_key; /* Who put the position info in (0 = undefined) */
77 unsigned long elapsed; /* Elapsed time to use */
78 off_t offset; /* Offset to use */
81 /* General PCM buffer data */
82 #define INVALID_BUF_INDEX ((size_t)0 - (size_t)1)
84 static unsigned char *pcmbuf_buffer;
85 static unsigned char *pcmbuf_guardbuf;
86 static size_t pcmbuf_size;
87 static struct chunkdesc *pcmbuf_descriptors;
88 static unsigned int pcmbuf_desc_count;
89 static unsigned int position_key = 1;
91 static size_t chunk_ridx;
92 static size_t chunk_widx;
94 static size_t pcmbuf_bytes_waiting;
96 static size_t pcmbuf_watermark;
97 static struct chunkdesc *current_desc;
99 static bool low_latency_mode = false;
101 static bool pcmbuf_sync_position = false;
103 /* Fade effect */
104 static unsigned int fade_vol = MIX_AMP_UNITY;
105 static enum
107 PCM_NOT_FADING = 0,
108 PCM_FADING_IN,
109 PCM_FADING_OUT,
110 } fade_state = PCM_NOT_FADING;
111 static bool fade_out_complete = false;
113 /* Voice */
114 static bool soft_mode = false;
116 #ifdef HAVE_CROSSFADE
117 /* Crossfade buffer */
118 static unsigned char *crossfade_buffer;
120 /* Crossfade related state */
121 static int crossfade_setting;
122 static int crossfade_enable_request;
123 static bool crossfade_mixmode;
124 static bool crossfade_auto_skip;
126 static enum
128 CROSSFADE_INACTIVE = 0,
129 CROSSFADE_TRACK_CHANGE_STARTED,
130 CROSSFADE_ACTIVE,
131 } crossfade_status = CROSSFADE_INACTIVE;
133 /* Track the current location for processing crossfade */
134 static size_t crossfade_index;
136 /* Counters for fading in new data */
137 static size_t crossfade_fade_in_total;
138 static size_t crossfade_fade_in_rem;
140 /* Defines for operations on position info when mixing/fading -
141 passed in offset parameter */
142 enum
144 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */
145 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */
146 /* Positive values cause stamping/restamping */
149 static void crossfade_start(void);
150 static void write_to_crossfade(size_t size, unsigned long elapsed,
151 off_t offset);
152 static void pcmbuf_finish_crossfade_enable(void);
153 #endif /* HAVE_CROSSFADE */
155 /* Thread */
156 #ifdef HAVE_PRIORITY_SCHEDULING
157 static int codec_thread_priority = PRIORITY_PLAYBACK;
158 #endif
160 /* Helpful macros for use in conditionals this assumes some of the above
161 * static variable names */
162 #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs))
164 /* Callbacks into playback.c */
165 extern void audio_pcmbuf_position_callback(unsigned long elapsed,
166 off_t offset, unsigned int key);
167 extern void audio_pcmbuf_track_change(bool pcmbuf);
168 extern bool audio_pcmbuf_may_play(void);
169 extern void audio_pcmbuf_sync_position(void);
172 /**************************************/
174 /* Return number of commited bytes in buffer (committed chunks count as
175 a full chunk even if only partially filled) */
176 static size_t pcmbuf_unplayed_bytes(void)
178 size_t ridx = chunk_ridx;
179 size_t widx = chunk_widx;
181 if (ridx > widx)
182 widx += pcmbuf_size;
184 return widx - ridx;
187 /* Return the next PCM chunk in the PCM buffer given a byte index into it */
188 static size_t index_next(size_t index)
190 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE);
192 if (index >= pcmbuf_size)
193 index -= pcmbuf_size;
195 return index;
198 /* Convert a byte offset in the PCM buffer into a pointer in the buffer */
199 static FORCE_INLINE void * index_buffer(size_t index)
201 return pcmbuf_buffer + index;
204 /* Convert a pointer in the buffer into an index offset */
205 static FORCE_INLINE size_t buffer_index(void *p)
207 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer;
210 /* Return a chunk descriptor for a byte index in the buffer */
211 static struct chunkdesc * index_chunkdesc(size_t index)
213 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE];
216 /* Return a chunk descriptor for a byte index in the buffer, offset by 'offset'
217 chunks */
218 static struct chunkdesc * index_chunkdesc_offs(size_t index, int offset)
220 int i = index / PCMBUF_CHUNK_SIZE;
222 if (offset != 0)
224 i = (i + offset) % pcmbuf_desc_count;
226 /* remainder => modulus */
227 if (i < 0)
228 i += pcmbuf_desc_count;
231 return &pcmbuf_descriptors[i];
235 /** Accept new PCM data */
237 /* Split the uncommitted data as needed into chunks, stopping when uncommitted
238 data is below the threshold */
239 static void commit_chunks(size_t threshold)
241 size_t index = chunk_widx;
242 size_t end_index = index + pcmbuf_bytes_waiting;
244 /* Copy to the beginning of the buffer all data that must wrap */
245 if (end_index > pcmbuf_size)
246 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size);
248 struct chunkdesc *desc = index_chunkdesc(index);
252 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE);
253 pcmbuf_bytes_waiting -= size;
255 /* Fill in the values in the new buffer chunk */
256 desc->size = (uint16_t)size;
258 /* Advance the current write chunk and make it available to the
259 PCM callback */
260 chunk_widx = index = index_next(index);
261 desc = index_chunkdesc(index);
263 /* Reset it before using it */
264 desc->is_end = 0;
265 desc->pos_key = 0;
267 while (pcmbuf_bytes_waiting >= threshold);
270 /* If uncommitted data count is above or equal to the threshold, commit it */
271 static FORCE_INLINE void commit_if_needed(size_t threshold)
273 if (pcmbuf_bytes_waiting >= threshold)
274 commit_chunks(threshold);
277 /* Place positioning information in the chunk */
278 static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed,
279 off_t offset)
281 /* One-time stamping of a given chunk by the same track - new track may
282 overwrite */
283 unsigned int key = position_key;
285 if (desc->pos_key != key)
287 desc->pos_key = key;
288 desc->elapsed = elapsed;
289 desc->offset = offset;
293 /* Set priority of the codec thread */
294 #ifdef HAVE_PRIORITY_SCHEDULING
296 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */
297 static void boost_codec_thread(int pcm_fill_state)
299 static const int8_t prios[11] =
301 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */
302 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */
303 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */
304 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */
305 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */
306 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */
307 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */
308 /* raising priority above 70% shouldn't be needed */
309 PRIORITY_PLAYBACK, /* 70 - 80% */
310 PRIORITY_PLAYBACK, /* 80 - 90% */
311 PRIORITY_PLAYBACK, /* 90 -100% */
312 PRIORITY_PLAYBACK, /* 100% */
315 int new_prio = prios[pcm_fill_state];
317 /* Keep voice and codec threads at the same priority or else voice
318 * will starve if the codec thread's priority is boosted. */
319 if (new_prio != codec_thread_priority)
321 codec_thread_set_priority(new_prio);
322 voice_thread_set_priority(new_prio);
323 codec_thread_priority = new_prio;
326 #else
327 #define boost_codec_thread(pcm_fill_state) do{}while(0)
328 #endif /* HAVE_PRIORITY_SCHEDULING */
330 /* Get the next available buffer and size - assumes adequate space exists */
331 static void * get_write_buffer(size_t *size)
333 /* Obtain current chunk fill address */
334 size_t index = chunk_widx + pcmbuf_bytes_waiting;
335 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE;
337 /* Get count to the end of the buffer where a wrap will happen +
338 the guard */
339 size_t endsize = index_end - index;
341 /* Return available unwrapped space */
342 *size = MIN(*size, endsize);
344 return index_buffer(index);
347 /* Commit outstanding data leaving less than a chunk size remaining and
348 write position info to the first chunk */
349 static void commit_write_buffer(size_t size, unsigned long elapsed, off_t offset)
351 struct chunkdesc *desc = index_chunkdesc(chunk_widx);
352 stamp_chunk(desc, elapsed, offset);
354 /* Add this data and commit if one or more chunks are ready */
355 pcmbuf_bytes_waiting += size;
357 commit_if_needed(COMMIT_CHUNKS);
360 /* Request space in the buffer for writing output samples */
361 void * pcmbuf_request_buffer(int *count)
363 size_t size = *count * 4;
365 #ifdef HAVE_CROSSFADE
366 /* We're going to crossfade to a new track, which is now on its way */
367 if (crossfade_status == CROSSFADE_TRACK_CHANGE_STARTED)
368 crossfade_start();
370 /* If crossfade has begun, put the new track samples in crossfade_buffer */
371 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE)
372 size = CROSSFADE_BUFSIZE;
373 #endif
375 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
376 size_t remaining = pcmbuf_unplayed_bytes();
378 /* Need to have length bytes to prevent wrapping overwriting - leave one
379 descriptor free to guard so that 0 != full in ring buffer */
380 size_t freespace = pcmbuf_free();
382 if (pcmbuf_sync_position)
383 audio_pcmbuf_sync_position();
385 if (freespace < size + PCMBUF_CHUNK_SIZE)
386 return NULL;
388 /* Maintain the buffer level above the watermark */
389 if (status != CHANNEL_STOPPED)
391 if (low_latency_mode)
393 /* 1/4s latency. */
394 if (remaining > DATA_LEVEL(1))
395 return NULL;
398 /* Boost CPU if necessary */
399 size_t realrem = pcmbuf_size - freespace;
401 if (realrem < pcmbuf_watermark)
402 trigger_cpu_boost();
404 boost_codec_thread(realrem*10 / pcmbuf_size);
406 #ifdef HAVE_CROSSFADE
407 /* Disable crossfade if < .5s of audio */
408 if (remaining < DATA_LEVEL(2))
409 crossfade_status = CROSSFADE_INACTIVE;
410 #endif
412 else /* !playing */
414 /* Boost CPU for pre-buffer */
415 trigger_cpu_boost();
417 /* If pre-buffered to the watermark, start playback */
418 #if MEMORYSIZE > 2
419 if (remaining > DATA_LEVEL(4))
420 #else
421 if (remaining > pcmbuf_watermark)
422 #endif
424 if (audio_pcmbuf_may_play())
425 pcmbuf_play_start();
429 void *buf =
430 #ifdef HAVE_CROSSFADE
431 crossfade_status != CROSSFADE_INACTIVE ? crossfade_buffer :
432 #endif
433 get_write_buffer(&size);
435 *count = size / 4;
436 return buf;
439 /* Handle new samples to the buffer */
440 void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset)
442 size_t size = count * 4;
444 #ifdef HAVE_CROSSFADE
445 if (crossfade_status != CROSSFADE_INACTIVE)
447 write_to_crossfade(size, elapsed, offset);
449 else
450 #endif
452 commit_write_buffer(size, elapsed, offset);
455 /* Revert to position updates by PCM */
456 pcmbuf_sync_position = false;
460 /** Init */
461 static unsigned int get_next_required_pcmbuf_chunks(void)
463 size_t size = MIN_BUFFER_SIZE;
465 #ifdef HAVE_CROSSFADE
466 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
468 size_t seconds = global_settings.crossfade_fade_out_delay +
469 global_settings.crossfade_fade_out_duration;
470 size += seconds * BYTERATE;
472 #endif
474 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE));
475 return size / PCMBUF_CHUNK_SIZE;
478 /* Initialize the ringbuffer state */
479 static void init_buffer_state(void)
481 /* Reset counters */
482 chunk_ridx = chunk_widx = 0;
483 pcmbuf_bytes_waiting = 0;
485 /* Reset first descriptor */
486 struct chunkdesc *desc = pcmbuf_descriptors;
487 desc->is_end = 0;
488 desc->pos_key = 0;
491 /* Initialize the PCM buffer. The structure looks like this:
492 * ...[|FADEBUF]|---------PCMBUF---------|GUARDBUF|DESCS| */
493 size_t pcmbuf_init(unsigned char *bufend)
495 unsigned char *bufstart;
497 /* Set up the buffers */
498 pcmbuf_desc_count = get_next_required_pcmbuf_chunks();
499 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE;
500 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count;
502 pcmbuf_buffer = (void *)pcmbuf_descriptors -
503 pcmbuf_size - PCMBUF_GUARD_SIZE;
505 /* Mem-align buffer chunks for more efficient handling in lower layers */
506 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE);
508 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size;
509 bufstart = pcmbuf_buffer;
511 #ifdef HAVE_CROSSFADE
512 /* Allocate FADEBUF if it will be needed */
513 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
515 bufstart -= CROSSFADE_BUFSIZE;
516 crossfade_buffer = bufstart;
519 pcmbuf_finish_crossfade_enable();
520 #else /* !HAVE_CROSSFADE */
521 pcmbuf_watermark = PCMBUF_WATERMARK;
522 #endif /* HAVE_CROSSFADE */
524 init_buffer_state();
526 pcmbuf_soft_mode(false);
528 return bufend - bufstart;
532 /** Track change */
534 /* Place a track change notification in a specific descriptor or post it
535 immediately if the buffer is empty or the index is invalid */
536 static void pcmbuf_monitor_track_change_ex(size_t index, int offset)
538 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX)
540 /* If monitoring, set flag in specified chunk */
541 index_chunkdesc_offs(index, offset)->is_end = 1;
543 else
545 /* Post now if no outstanding buffers exist */
546 audio_pcmbuf_track_change(false);
550 /* Clear end of track and optionally the positioning info for all data */
551 static void pcmbuf_cancel_track_change(bool position)
553 size_t index = chunk_ridx;
555 while (1)
557 struct chunkdesc *desc = index_chunkdesc(index);
559 desc->is_end = 0;
561 if (position)
562 desc->pos_key = 0;
564 if (index == chunk_widx)
565 break;
567 index = index_next(index);
571 /* Place a track change notification at the end of the buffer or post it
572 immediately if the buffer is empty */
573 void pcmbuf_monitor_track_change(bool monitor)
575 pcm_play_lock();
577 if (monitor)
578 pcmbuf_monitor_track_change_ex(chunk_widx, -1);
579 else
580 pcmbuf_cancel_track_change(false);
582 pcm_play_unlock();
585 void pcmbuf_start_track_change(enum pcm_track_change_type type)
587 #ifdef HAVE_CROSSFADE
588 bool crossfade = false;
589 #endif
590 bool auto_skip = type != TRACK_CHANGE_MANUAL;
592 /* Commit all outstanding data before starting next track - tracks don't
593 comingle inside a single buffer chunk */
594 commit_if_needed(COMMIT_ALL_DATA);
596 /* Update position key so that:
597 1) Positions are keyed to the track to which they belong for sync
598 purposes
600 2) Buffers stamped with the outgoing track's positions are restamped
601 to the incoming track's positions when crossfading
603 if (++position_key > UINT8_MAX)
604 position_key = 1;
606 if (type == TRACK_CHANGE_END_OF_DATA)
608 /* If end of all data, force playback */
609 if (audio_pcmbuf_may_play())
610 pcmbuf_play_start();
612 #ifdef HAVE_CROSSFADE
613 /* Determine whether this track change needs to crossfaded and how */
614 else if (crossfade_setting != CROSSFADE_ENABLE_OFF &&
615 !pcmbuf_is_crossfade_active() &&
616 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) &&
617 !low_latency_mode)
619 switch (crossfade_setting)
621 case CROSSFADE_ENABLE_AUTOSKIP:
622 crossfade = auto_skip;
623 break;
624 case CROSSFADE_ENABLE_MANSKIP:
625 crossfade = !auto_skip;
626 break;
627 case CROSSFADE_ENABLE_SHUFFLE:
628 crossfade = global_settings.playlist_shuffle;
629 break;
630 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
631 crossfade = global_settings.playlist_shuffle || !auto_skip;
632 break;
633 case CROSSFADE_ENABLE_ALWAYS:
634 crossfade = true;
635 break;
638 /* else crossfade is off, crossfade is already active, not enough data,
639 * pcm is off now (implying low data), not crossfading or low latency mode
642 if (crossfade)
644 logf("crossfade track change");
646 /* Don't enable mix mode when skipping tracks manually */
647 crossfade_mixmode = auto_skip &&
648 global_settings.crossfade_fade_out_mixmode;
650 crossfade_auto_skip = auto_skip;
652 crossfade_status = CROSSFADE_TRACK_CHANGE_STARTED;
654 trigger_cpu_boost();
656 /* Cancel any pending automatic gapless transition and if a manual
657 skip, stop position updates */
658 pcm_play_lock();
659 pcmbuf_cancel_track_change(!auto_skip);
660 pcm_play_unlock();
662 else
663 #endif /* HAVE_CROSSFADE */
664 if (auto_skip)
666 /* The codec is moving on to the next track, but the current track will
667 * continue to play, so mark the last write chunk as the last one in
668 * the track */
669 logf("gapless track change");
670 #ifdef HAVE_CROSSFADE
671 if (crossfade_status != CROSSFADE_INACTIVE)
673 /* Crossfade is still active but crossfade is not happening - for
674 * now, chicken-out and clear out the buffer (just like before) to
675 * avoid fade pile-up on short tracks fading-in over long ones */
676 pcmbuf_play_stop();
678 #endif
679 pcmbuf_monitor_track_change(true);
681 else
683 /* Discard old data; caller needs no transition notification */
684 logf("manual track change");
685 pcmbuf_play_stop();
690 /** Playback */
692 /* PCM driver callback */
693 static void pcmbuf_pcm_callback(unsigned char **start, size_t *size)
695 /*- Process the chunk that just finished -*/
696 size_t index = chunk_ridx;
697 struct chunkdesc *desc = current_desc;
699 if (desc)
701 /* If last chunk in the track, notify of track change */
702 if (desc->is_end != 0)
703 audio_pcmbuf_track_change(true);
705 /* Free it for reuse */
706 chunk_ridx = index = index_next(index);
709 /*- Process the new one -*/
710 if (index != chunk_widx && !fade_out_complete)
712 current_desc = desc = index_chunkdesc(index);
714 *start = index_buffer(index);
715 *size = desc->size;
717 if (desc->pos_key != 0)
719 /* Positioning chunk - notify playback */
720 audio_pcmbuf_position_callback(desc->elapsed, desc->offset,
721 desc->pos_key);
726 /* Force playback */
727 void pcmbuf_play_start(void)
729 logf("pcmbuf_play_start");
731 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED &&
732 chunk_widx != chunk_ridx)
734 current_desc = NULL;
735 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
736 NULL, 0);
740 /* Stop channel, empty and reset buffer */
741 void pcmbuf_play_stop(void)
743 logf("pcmbuf_play_stop");
745 /* Reset channel */
746 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
748 /* Reset buffer */
749 init_buffer_state();
751 /* Revert to position updates by PCM */
752 pcmbuf_sync_position = false;
754 #ifdef HAVE_CROSSFADE
755 crossfade_status = CROSSFADE_INACTIVE;
756 #endif
758 /* Can unboost the codec thread here no matter who's calling,
759 * pretend full pcm buffer to unboost */
760 boost_codec_thread(10);
763 void pcmbuf_pause(bool pause)
765 logf("pcmbuf_pause: %s", pause?"pause":"play");
767 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED)
768 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
769 else if (!pause)
770 pcmbuf_play_start();
774 /** Crossfade */
776 #ifdef HAVE_CROSSFADE
777 /* Find the buffer index that's 'size' bytes away from 'index' */
778 static size_t crossfade_find_index(size_t index, size_t size)
780 if (index != INVALID_BUF_INDEX)
782 size_t i = ALIGN_DOWN(index, PCMBUF_CHUNK_SIZE);
783 size += index - i;
785 while (i != chunk_widx)
787 size_t desc_size = index_chunkdesc(i)->size;
789 if (size < desc_size)
790 return i + size;
792 size -= desc_size;
793 i = index_next(i);
797 return INVALID_BUF_INDEX;
800 /* Align the needed buffer area up to the end of existing data */
801 static size_t crossfade_find_buftail(size_t buffer_rem, size_t buffer_need)
803 crossfade_index = chunk_ridx;
805 if (buffer_rem > buffer_need)
807 size_t distance;
809 if (crossfade_auto_skip)
811 /* Automatic track changes only modify the last part of the buffer,
812 * so find the right chunk and sample to start the crossfade */
813 distance = buffer_rem - buffer_need;
814 buffer_rem = buffer_need;
816 else
818 /* Manual skips occur immediately, but give 1/5s to process */
819 distance = BYTERATE / 5;
820 buffer_rem -= BYTERATE / 5;
823 crossfade_index = crossfade_find_index(crossfade_index, distance);
826 return buffer_rem;
829 /* Clip sample to signed 16 bit range */
830 static FORCE_INLINE int32_t clip_sample_16(int32_t sample)
832 if ((int16_t)sample != sample)
833 sample = 0x7fff ^ (sample >> 31);
834 return sample;
837 /* Returns the number of bytes _NOT_ mixed/faded */
838 static int crossfade_mix_fade(int factor, size_t size, void *buf, size_t *out_index,
839 unsigned long elapsed, off_t offset)
841 if (size == 0)
842 return 0;
844 size_t index = *out_index;
846 if (index == INVALID_BUF_INDEX)
847 return size;
849 const int16_t *input_buf = buf;
850 int16_t *output_buf = (int16_t *)index_buffer(index);
852 while (size)
854 struct chunkdesc *desc = index_chunkdesc(index);
856 switch (offset)
858 case MIXFADE_NULLIFY_POS:
859 /* Stop position updates for the chunk */
860 desc->pos_key = 0;
861 break;
862 case MIXFADE_KEEP_POS:
863 /* Keep position info as it is */
864 break;
865 default:
866 /* Replace position info */
867 stamp_chunk(desc, elapsed, offset);
870 size_t rem = desc->size - (index % PCMBUF_CHUNK_SIZE);
871 int16_t *chunk_end = SKIPBYTES(output_buf, rem);
873 if (size < rem)
874 rem = size;
876 size -= rem;
880 /* fade left and right channel at once to keep buffer alignment */
881 int32_t left = output_buf[0];
882 int32_t right = output_buf[1];
884 if (input_buf)
886 /* fade the input buffer and mix into the chunk */
887 left += *input_buf++ * factor >> 8;
888 right += *input_buf++ * factor >> 8;
889 left = clip_sample_16(left);
890 right = clip_sample_16(right);
892 else
894 /* fade the chunk only */
895 left = left * factor >> 8;
896 right = right * factor >> 8;
899 *output_buf++ = left;
900 *output_buf++ = right;
902 rem -= 4;
904 while (rem);
906 /* move to next chunk as needed */
907 if (output_buf >= chunk_end)
909 index = index_next(index);
911 if (index == chunk_widx)
913 /* End of existing data */
914 *out_index = INVALID_BUF_INDEX;
915 return size;
918 output_buf = (int16_t *)index_buffer(index);
922 *out_index = buffer_index(output_buf);
923 return 0;
926 /* Initializes crossfader, calculates all necessary parameters and performs
927 * fade-out with the PCM buffer. */
928 static void crossfade_start(void)
930 logf("crossfade_start");
932 pcm_play_lock();
934 /* Initialize the crossfade buffer size to all of the buffered data that
935 * has not yet been sent to the DMA */
936 size_t unplayed = pcmbuf_unplayed_bytes();
938 /* Reject crossfade if less than .5s of data */
939 if (unplayed < DATA_LEVEL(2))
941 logf("crossfade rejected");
943 crossfade_status = CROSSFADE_INACTIVE;
945 if (crossfade_auto_skip)
946 pcmbuf_monitor_track_change(true);
948 pcm_play_unlock();
949 return;
952 /* Fading will happen */
953 crossfade_status = CROSSFADE_ACTIVE;
955 /* Get fade info from settings. */
956 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
957 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
958 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
959 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE;
961 if (!crossfade_auto_skip)
963 /* Forego fade-in delay on manual skip - do the best to preserve auto skip
964 relationship */
965 if (fade_out_delay > fade_in_delay)
966 fade_out_delay -= fade_in_delay;
967 else
968 fade_out_delay = 0;
970 fade_in_delay = 0;
973 size_t fade_out_need = fade_out_delay + fade_out_rem;
975 if (!crossfade_mixmode)
977 size_t buffer_rem = crossfade_find_buftail(unplayed, fade_out_need);
979 pcm_play_unlock();
981 if (buffer_rem < fade_out_need)
983 /* Existing buffers are short */
984 size_t fade_out_short = fade_out_need - buffer_rem;
986 if (fade_out_rem >= fade_out_short)
988 /* Truncate fade-out duration */
989 fade_out_rem -= fade_out_short;
991 else
993 /* Truncate fade-out and fade-out delay */
994 fade_out_delay = fade_out_rem;
995 fade_out_rem = 0;
999 /* Completely process the crossfade fade-out effect with current PCM buffer */
1001 /* Fade out the specified amount of the already processed audio */
1002 size_t fade_out_total = fade_out_rem;
1004 /* Find the right chunk and sample to start fading out */
1005 size_t fade_out_index = crossfade_find_index(crossfade_index, fade_out_delay);
1007 while (fade_out_rem > 0)
1009 /* Each 1/20 second of audio will have the same fade applied */
1010 size_t block_rem = MIN(BYTERATE / 20, fade_out_rem);
1011 int factor = (fade_out_rem << 8) / fade_out_total;
1013 fade_out_rem -= block_rem;
1015 crossfade_mix_fade(factor, block_rem, NULL, &fade_out_index,
1016 0, MIXFADE_KEEP_POS);
1019 /* zero out the rest of the buffer */
1020 crossfade_mix_fade(0, pcmbuf_size, NULL, &fade_out_index,
1021 0, MIXFADE_NULLIFY_POS);
1023 pcm_play_lock();
1026 /* Initialize fade-in counters */
1027 crossfade_fade_in_total = fade_in_duration;
1028 crossfade_fade_in_rem = fade_in_duration;
1030 /* Find the right chunk and sample to start fading in - redo from read
1031 chunk in case original position were/was overrun in callback - the
1032 track change event _must not_ ever fail to happen */
1033 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay;
1035 crossfade_find_buftail(unplayed, fade_out_need);
1037 if (crossfade_auto_skip)
1038 pcmbuf_monitor_track_change_ex(crossfade_index, 0);
1040 pcm_play_unlock();
1042 logf("crossfade_start done!");
1045 /* Perform fade-in of new track */
1046 static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset)
1048 unsigned char *buf = crossfade_buffer;
1050 if (crossfade_fade_in_rem)
1052 /* Fade factor for this packet */
1053 int factor =
1054 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
1055 crossfade_fade_in_total;
1056 /* Bytes to fade */
1057 size_t fade_rem = MIN(size, crossfade_fade_in_rem);
1059 /* We _will_ fade this many bytes */
1060 crossfade_fade_in_rem -= fade_rem;
1062 if (crossfade_index != INVALID_BUF_INDEX)
1064 /* Mix the data */
1065 size_t fade_total = fade_rem;
1066 fade_rem = crossfade_mix_fade(factor, fade_rem, buf, &crossfade_index,
1067 elapsed, offset);
1068 fade_total -= fade_rem;
1069 size -= fade_total;
1070 buf += fade_total;
1072 if (!size)
1073 return;
1076 /* Fade remaining samples in place */
1077 int samples = fade_rem / 4;
1078 int16_t *input_buf = (int16_t *)buf;
1080 while (samples--)
1082 int32_t left = input_buf[0];
1083 int32_t right = input_buf[1];
1084 *input_buf++ = left * factor >> 8;
1085 *input_buf++ = right * factor >> 8;
1089 if (crossfade_index != INVALID_BUF_INDEX)
1091 /* Mix the data */
1092 size_t mix_total = size;
1094 /* A factor of 256 means mix only, no fading */
1095 size = crossfade_mix_fade(256, size, buf, &crossfade_index,
1096 elapsed, offset);
1097 buf += mix_total - size;
1099 if (!size)
1100 return;
1103 /* Data might remain in the fade buffer yet the fade-in has run its
1104 course - finish it off as normal chunks */
1105 while (size > 0)
1107 size_t copy_n = size;
1108 unsigned char *outbuf = get_write_buffer(&copy_n);
1109 memcpy(outbuf, buf, copy_n);
1110 commit_write_buffer(copy_n, elapsed, offset);
1111 buf += copy_n;
1112 size -= copy_n;
1115 /* if no more fading-in to do, stop the crossfade */
1116 #if 0
1117 /* This way (the previous way) can cause a sudden volume jump if mixable
1118 data is used up before the fade-in completes and that just sounds wrong
1119 -- jethead71 */
1120 if (!crossfade_fade_in_rem || crossfade_index == INVALID_BUF_INDEX)
1121 #endif
1122 /* Let fade-in complete even if not fully overlapping the existing data */
1123 if (!crossfade_fade_in_rem)
1124 crossfade_status = CROSSFADE_INACTIVE;
1127 static void pcmbuf_finish_crossfade_enable(void)
1129 /* Copy the pending setting over now */
1130 crossfade_setting = crossfade_enable_request;
1132 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ?
1133 /* If crossfading, try to keep the buffer full other than 1 second */
1134 (pcmbuf_size - BYTERATE) :
1135 /* Otherwise, just use the default */
1136 PCMBUF_WATERMARK;
1139 bool pcmbuf_is_crossfade_active(void)
1141 return crossfade_status != CROSSFADE_INACTIVE;
1144 void pcmbuf_request_crossfade_enable(int setting)
1146 /* Next setting to be used, not applied now */
1147 crossfade_enable_request = setting;
1150 bool pcmbuf_is_same_size(void)
1152 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */
1153 bool same_size = pcmbuf_buffer ?
1154 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true;
1156 /* no buffer change needed, so finish crossfade setup now */
1157 if (same_size)
1158 pcmbuf_finish_crossfade_enable();
1160 return same_size;
1162 #endif /* HAVE_CROSSFADE */
1165 /** Debug menu, other metrics */
1167 /* Amount of bytes left in the buffer, accounting for uncommitted bytes */
1168 size_t pcmbuf_free(void)
1170 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting;
1173 /* Data bytes allocated for buffer */
1174 size_t pcmbuf_get_bufsize(void)
1176 return pcmbuf_size;
1179 /* Number of committed descriptors */
1180 int pcmbuf_used_descs(void)
1182 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE;
1185 /* Total number of descriptors allocated */
1186 int pcmbuf_descs(void)
1188 return pcmbuf_desc_count;
1192 /** Fading and channel volume control */
1194 /* Sync the channel amplitude to all states */
1195 static void pcmbuf_update_volume(void)
1197 unsigned int vol = fade_vol;
1199 if (soft_mode)
1200 vol >>= 2;
1202 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol);
1205 /* Tick that does the fade for the playback channel */
1206 static void pcmbuf_fade_tick(void)
1208 /* ~1/3 second for full range fade */
1209 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1211 if (fade_state == PCM_FADING_IN)
1212 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1213 else if (fade_state == PCM_FADING_OUT)
1214 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1216 pcmbuf_update_volume();
1218 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1220 /* Fade is complete */
1221 tick_remove_task(pcmbuf_fade_tick);
1222 if (fade_state == PCM_FADING_OUT)
1224 /* Tell PCM to stop at its earliest convenience */
1225 fade_out_complete = true;
1228 fade_state = PCM_NOT_FADING;
1232 /* Fade channel in or out in the background */
1233 void pcmbuf_fade(bool fade, bool in)
1235 /* Must pause any active fade */
1236 pcm_play_lock();
1238 if (fade_state != PCM_NOT_FADING)
1239 tick_remove_task(pcmbuf_fade_tick);
1241 fade_out_complete = false;
1243 pcm_play_unlock();
1245 if (!fade)
1247 /* Simply set the level */
1248 fade_state = PCM_NOT_FADING;
1249 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1250 pcmbuf_update_volume();
1252 else
1254 /* Set direction and resume fade from current point */
1255 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1256 tick_add_task(pcmbuf_fade_tick);
1260 /* Return 'true' if fade is in progress */
1261 bool pcmbuf_fading(void)
1263 return fade_state != PCM_NOT_FADING;
1266 /* Quiet-down the channel if 'shhh' is true or else play at normal level */
1267 void pcmbuf_soft_mode(bool shhh)
1269 /* Have to block the tick or improper order could leave volume in soft
1270 mode if fading reads the old value first but updates after us. */
1271 int res = fade_state != PCM_NOT_FADING ?
1272 tick_remove_task(pcmbuf_fade_tick) : -1;
1274 soft_mode = shhh;
1275 pcmbuf_update_volume();
1277 if (res == 0)
1278 tick_add_task(pcmbuf_fade_tick);
1282 /** Misc */
1284 bool pcmbuf_is_lowdata(void)
1286 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
1288 if (status != CHANNEL_PLAYING || pcmbuf_is_crossfade_active())
1289 return false;
1291 #if MEMORYSIZE > 2
1292 /* 1 seconds of buffer is low data */
1293 return pcmbuf_unplayed_bytes() < DATA_LEVEL(4);
1294 #else
1295 /* under watermark is low data */
1296 return pcmbuf_unplayed_bytes() < pcmbuf_watermark;
1297 #endif
1300 void pcmbuf_set_low_latency(bool state)
1302 low_latency_mode = state;
1305 /* Return the current position key value */
1306 unsigned int pcmbuf_get_position_key(void)
1308 return position_key;
1311 /* Set position updates to be synchronous and immediate in addition to during
1312 PCM frames - cancelled upon first codec insert or upon stopping */
1313 void pcmbuf_sync_position_update(void)
1315 pcmbuf_sync_position = true;