i.MX31: Implement asynchronous version of I2C driver.
[maemo-rb.git] / apps / pcmbuf.c
blob32e1157132ea7ff673046f09d6e6c4509227f3ca
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 /* Number of bytes played per second:
62 (sample rate * 2 channels * 2 bytes/sample) */
63 #define BYTERATE (NATIVE_FREQUENCY * 4)
65 #if MEMORYSIZE > 2
66 /* Keep watermark high for large memory target - at least (2s) */
67 #define PCMBUF_WATERMARK (BYTERATE * 2)
68 #define MIN_BUFFER_SIZE (BYTERATE * 3)
69 #else
70 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
71 #define MIN_BUFFER_SIZE (BYTERATE * 1)
72 #endif
74 /* Describes each audio packet - keep it small since there are many of them */
75 struct chunkdesc
77 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */
78 uint8_t is_end; /* Flag indicating end of track */
79 uint8_t pos_key; /* Who put the position info in (0 = undefined) */
80 unsigned long elapsed; /* Elapsed time to use */
81 off_t offset; /* Offset to use */
84 /* General PCM buffer data */
85 #define INVALID_BUF_INDEX ((size_t)0 - (size_t)1)
87 static unsigned char *pcmbuf_buffer;
88 static unsigned char *pcmbuf_guardbuf;
89 static size_t pcmbuf_size;
90 static struct chunkdesc *pcmbuf_descriptors;
91 static unsigned int pcmbuf_desc_count;
92 static unsigned int position_key = 1;
94 static size_t chunk_ridx;
95 static size_t chunk_widx;
97 static size_t pcmbuf_bytes_waiting;
99 static size_t pcmbuf_watermark;
100 static struct chunkdesc *current_desc;
102 static bool low_latency_mode = false;
104 static bool pcmbuf_sync_position = false;
106 /* Fade effect */
107 static unsigned int fade_vol = MIX_AMP_UNITY;
108 static enum
110 PCM_NOT_FADING = 0,
111 PCM_FADING_IN,
112 PCM_FADING_OUT,
113 } fade_state = PCM_NOT_FADING;
114 static bool fade_out_complete = false;
116 /* Voice */
117 static bool soft_mode = false;
119 #ifdef HAVE_CROSSFADE
120 /* Crossfade buffer */
121 static unsigned char *crossfade_buffer;
123 /* Crossfade related state */
124 static int crossfade_setting;
125 static int crossfade_enable_request;
126 static bool crossfade_mixmode;
127 static bool crossfade_auto_skip;
129 static enum
131 CROSSFADE_INACTIVE = 0,
132 CROSSFADE_TRACK_CHANGE_STARTED,
133 CROSSFADE_ACTIVE,
134 } crossfade_status = CROSSFADE_INACTIVE;
136 /* Track the current location for processing crossfade */
137 static size_t crossfade_index;
139 /* Counters for fading in new data */
140 static size_t crossfade_fade_in_total;
141 static size_t crossfade_fade_in_rem;
143 /* Defines for operations on position info when mixing/fading -
144 passed in offset parameter */
145 enum
147 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */
148 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */
149 /* Positive values cause stamping/restamping */
152 static void crossfade_start(void);
153 static void write_to_crossfade(size_t size, unsigned long elapsed,
154 off_t offset);
155 static void pcmbuf_finish_crossfade_enable(void);
156 #endif /* HAVE_CROSSFADE */
158 /* Thread */
159 #ifdef HAVE_PRIORITY_SCHEDULING
160 static int codec_thread_priority = PRIORITY_PLAYBACK;
161 #endif
163 /* Helpful macros for use in conditionals this assumes some of the above
164 * static variable names */
165 #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs))
167 /* Callbacks into playback.c */
168 extern void audio_pcmbuf_position_callback(unsigned long elapsed,
169 off_t offset, unsigned int key);
170 extern void audio_pcmbuf_track_change(bool pcmbuf);
171 extern bool audio_pcmbuf_may_play(void);
172 extern void audio_pcmbuf_sync_position(void);
175 /**************************************/
177 /* Return number of commited bytes in buffer (committed chunks count as
178 a full chunk even if only partially filled) */
179 static size_t pcmbuf_unplayed_bytes(void)
181 size_t ridx = chunk_ridx;
182 size_t widx = chunk_widx;
184 if (ridx > widx)
185 widx += pcmbuf_size;
187 return widx - ridx;
190 /* Return the next PCM chunk in the PCM buffer given a byte index into it */
191 static size_t index_next(size_t index)
193 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE);
195 if (index >= pcmbuf_size)
196 index -= pcmbuf_size;
198 return index;
201 /* Convert a byte offset in the PCM buffer into a pointer in the buffer */
202 static FORCE_INLINE void * index_buffer(size_t index)
204 return pcmbuf_buffer + index;
207 /* Convert a pointer in the buffer into an index offset */
208 static FORCE_INLINE size_t buffer_index(void *p)
210 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer;
213 /* Return a chunk descriptor for a byte index in the buffer */
214 static struct chunkdesc * index_chunkdesc(size_t index)
216 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE];
219 /* Return a chunk descriptor for a byte index in the buffer, offset by 'offset'
220 chunks */
221 static struct chunkdesc * index_chunkdesc_offs(size_t index, int offset)
223 int i = index / PCMBUF_CHUNK_SIZE;
225 if (offset != 0)
227 i = (i + offset) % pcmbuf_desc_count;
229 /* remainder => modulus */
230 if (i < 0)
231 i += pcmbuf_desc_count;
234 return &pcmbuf_descriptors[i];
238 /** Accept new PCM data */
240 /* Split the uncommitted data as needed into chunks, stopping when uncommitted
241 data is below the threshold */
242 static void commit_chunks(size_t threshold)
244 size_t index = chunk_widx;
245 size_t end_index = index + pcmbuf_bytes_waiting;
247 /* Copy to the beginning of the buffer all data that must wrap */
248 if (end_index > pcmbuf_size)
249 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size);
251 struct chunkdesc *desc = index_chunkdesc(index);
255 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE);
256 pcmbuf_bytes_waiting -= size;
258 /* Fill in the values in the new buffer chunk */
259 desc->size = (uint16_t)size;
261 /* Advance the current write chunk and make it available to the
262 PCM callback */
263 chunk_widx = index = index_next(index);
264 desc = index_chunkdesc(index);
266 /* Reset it before using it */
267 desc->is_end = 0;
268 desc->pos_key = 0;
270 while (pcmbuf_bytes_waiting >= threshold);
273 /* If uncommitted data count is above or equal to the threshold, commit it */
274 static FORCE_INLINE void commit_if_needed(size_t threshold)
276 if (pcmbuf_bytes_waiting >= threshold)
277 commit_chunks(threshold);
280 /* Place positioning information in the chunk */
281 static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed,
282 off_t offset)
284 /* One-time stamping of a given chunk by the same track - new track may
285 overwrite */
286 unsigned int key = position_key;
288 if (desc->pos_key != key)
290 desc->pos_key = key;
291 desc->elapsed = elapsed;
292 desc->offset = offset;
296 /* Set priority of the codec thread */
297 #ifdef HAVE_PRIORITY_SCHEDULING
299 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */
300 static void boost_codec_thread(int pcm_fill_state)
302 static const int8_t prios[11] =
304 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */
305 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */
306 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */
307 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */
308 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */
309 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */
310 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */
311 /* raising priority above 70% shouldn't be needed */
312 PRIORITY_PLAYBACK, /* 70 - 80% */
313 PRIORITY_PLAYBACK, /* 80 - 90% */
314 PRIORITY_PLAYBACK, /* 90 -100% */
315 PRIORITY_PLAYBACK, /* 100% */
318 int new_prio = prios[pcm_fill_state];
320 /* Keep voice and codec threads at the same priority or else voice
321 * will starve if the codec thread's priority is boosted. */
322 if (new_prio != codec_thread_priority)
324 codec_thread_set_priority(new_prio);
325 voice_thread_set_priority(new_prio);
326 codec_thread_priority = new_prio;
329 #else
330 #define boost_codec_thread(pcm_fill_state) do{}while(0)
331 #endif /* HAVE_PRIORITY_SCHEDULING */
333 /* Get the next available buffer and size - assumes adequate space exists */
334 static void * get_write_buffer(size_t *size)
336 /* Obtain current chunk fill address */
337 size_t index = chunk_widx + pcmbuf_bytes_waiting;
338 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE;
340 /* Get count to the end of the buffer where a wrap will happen +
341 the guard */
342 size_t endsize = index_end - index;
344 /* Return available unwrapped space */
345 *size = MIN(*size, endsize);
347 return index_buffer(index);
350 /* Commit outstanding data leaving less than a chunk size remaining and
351 write position info to the first chunk */
352 static void commit_write_buffer(size_t size, unsigned long elapsed, off_t offset)
354 struct chunkdesc *desc = index_chunkdesc(chunk_widx);
355 stamp_chunk(desc, elapsed, offset);
357 /* Add this data and commit if one or more chunks are ready */
358 pcmbuf_bytes_waiting += size;
360 commit_if_needed(COMMIT_CHUNKS);
363 /* Request space in the buffer for writing output samples */
364 void * pcmbuf_request_buffer(int *count)
366 size_t size = *count * 4;
368 #ifdef HAVE_CROSSFADE
369 /* We're going to crossfade to a new track, which is now on its way */
370 if (crossfade_status == CROSSFADE_TRACK_CHANGE_STARTED)
371 crossfade_start();
373 /* If crossfade has begun, put the new track samples in crossfade_buffer */
374 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE)
375 size = CROSSFADE_BUFSIZE;
376 #endif
378 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
379 size_t remaining = pcmbuf_unplayed_bytes();
381 /* Need to have length bytes to prevent wrapping overwriting - leave one
382 descriptor free to guard so that 0 != full in ring buffer */
383 size_t freespace = pcmbuf_free();
385 if (pcmbuf_sync_position)
386 audio_pcmbuf_sync_position();
388 if (freespace < size + PCMBUF_CHUNK_SIZE)
389 return NULL;
391 /* Maintain the buffer level above the watermark */
392 if (status != CHANNEL_STOPPED)
394 if (low_latency_mode)
396 /* 1/4s latency. */
397 if (remaining > DATA_LEVEL(1))
398 return NULL;
401 /* Boost CPU if necessary */
402 size_t realrem = pcmbuf_size - freespace;
404 if (realrem < pcmbuf_watermark)
405 trigger_cpu_boost();
407 boost_codec_thread(realrem*10 / pcmbuf_size);
409 #ifdef HAVE_CROSSFADE
410 /* Disable crossfade if < .5s of audio */
411 if (remaining < DATA_LEVEL(2))
412 crossfade_status = CROSSFADE_INACTIVE;
413 #endif
415 else /* !playing */
417 /* Boost CPU for pre-buffer */
418 trigger_cpu_boost();
420 /* If pre-buffered to the watermark, start playback */
421 #if MEMORYSIZE > 2
422 if (remaining > DATA_LEVEL(4))
423 #else
424 if (remaining > pcmbuf_watermark)
425 #endif
427 if (audio_pcmbuf_may_play())
428 pcmbuf_play_start();
432 void *buf =
433 #ifdef HAVE_CROSSFADE
434 crossfade_status != CROSSFADE_INACTIVE ? crossfade_buffer :
435 #endif
436 get_write_buffer(&size);
438 *count = size / 4;
439 return buf;
442 /* Handle new samples to the buffer */
443 void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset)
445 size_t size = count * 4;
447 #ifdef HAVE_CROSSFADE
448 if (crossfade_status != CROSSFADE_INACTIVE)
450 write_to_crossfade(size, elapsed, offset);
452 else
453 #endif
455 commit_write_buffer(size, elapsed, offset);
458 /* Revert to position updates by PCM */
459 pcmbuf_sync_position = false;
463 /** Init */
464 static unsigned int get_next_required_pcmbuf_chunks(void)
466 size_t size = MIN_BUFFER_SIZE;
468 #ifdef HAVE_CROSSFADE
469 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
471 size_t seconds = global_settings.crossfade_fade_out_delay +
472 global_settings.crossfade_fade_out_duration;
473 size += seconds * BYTERATE;
475 #endif
477 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE));
478 return size / PCMBUF_CHUNK_SIZE;
481 /* Initialize the ringbuffer state */
482 static void init_buffer_state(void)
484 /* Reset counters */
485 chunk_ridx = chunk_widx = 0;
486 pcmbuf_bytes_waiting = 0;
488 /* Reset first descriptor */
489 struct chunkdesc *desc = pcmbuf_descriptors;
490 desc->is_end = 0;
491 desc->pos_key = 0;
494 /* Initialize the PCM buffer. The structure looks like this:
495 * ...[|FADEBUF]|---------PCMBUF---------|GUARDBUF|DESCS| */
496 size_t pcmbuf_init(unsigned char *bufend)
498 unsigned char *bufstart;
500 /* Set up the buffers */
501 pcmbuf_desc_count = get_next_required_pcmbuf_chunks();
502 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE;
503 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count;
505 pcmbuf_buffer = (void *)pcmbuf_descriptors -
506 pcmbuf_size - PCMBUF_GUARD_SIZE;
508 /* Mem-align buffer chunks for more efficient handling in lower layers */
509 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE);
511 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size;
512 bufstart = pcmbuf_buffer;
514 #ifdef HAVE_CROSSFADE
515 /* Allocate FADEBUF if it will be needed */
516 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
518 bufstart -= CROSSFADE_BUFSIZE;
519 crossfade_buffer = bufstart;
522 pcmbuf_finish_crossfade_enable();
523 #else /* !HAVE_CROSSFADE */
524 pcmbuf_watermark = PCMBUF_WATERMARK;
525 #endif /* HAVE_CROSSFADE */
527 init_buffer_state();
529 pcmbuf_soft_mode(false);
531 return bufend - bufstart;
535 /** Track change */
537 /* Place a track change notification in a specific descriptor or post it
538 immediately if the buffer is empty or the index is invalid */
539 static void pcmbuf_monitor_track_change_ex(size_t index, int offset)
541 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX)
543 /* If monitoring, set flag in specified chunk */
544 index_chunkdesc_offs(index, offset)->is_end = 1;
546 else
548 /* Post now if no outstanding buffers exist */
549 audio_pcmbuf_track_change(false);
553 /* Clear end of track and optionally the positioning info for all data */
554 static void pcmbuf_cancel_track_change(bool position)
556 size_t index = chunk_ridx;
558 while (1)
560 struct chunkdesc *desc = index_chunkdesc(index);
562 desc->is_end = 0;
564 if (position)
565 desc->pos_key = 0;
567 if (index == chunk_widx)
568 break;
570 index = index_next(index);
574 /* Place a track change notification at the end of the buffer or post it
575 immediately if the buffer is empty */
576 void pcmbuf_monitor_track_change(bool monitor)
578 pcm_play_lock();
580 if (monitor)
581 pcmbuf_monitor_track_change_ex(chunk_widx, -1);
582 else
583 pcmbuf_cancel_track_change(false);
585 pcm_play_unlock();
588 void pcmbuf_start_track_change(enum pcm_track_change_type type)
590 #ifdef HAVE_CROSSFADE
591 bool crossfade = false;
592 #endif
593 bool auto_skip = type != TRACK_CHANGE_MANUAL;
595 /* Commit all outstanding data before starting next track - tracks don't
596 comingle inside a single buffer chunk */
597 commit_if_needed(COMMIT_ALL_DATA);
599 /* Update position key so that:
600 1) Positions are keyed to the track to which they belong for sync
601 purposes
603 2) Buffers stamped with the outgoing track's positions are restamped
604 to the incoming track's positions when crossfading
606 if (++position_key > UINT8_MAX)
607 position_key = 1;
609 if (type == TRACK_CHANGE_END_OF_DATA)
611 /* If end of all data, force playback */
612 if (audio_pcmbuf_may_play())
613 pcmbuf_play_start();
615 #ifdef HAVE_CROSSFADE
616 /* Determine whether this track change needs to crossfaded and how */
617 else if (crossfade_setting != CROSSFADE_ENABLE_OFF &&
618 !pcmbuf_is_crossfade_active() &&
619 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) &&
620 !low_latency_mode)
622 switch (crossfade_setting)
624 case CROSSFADE_ENABLE_AUTOSKIP:
625 crossfade = auto_skip;
626 break;
627 case CROSSFADE_ENABLE_MANSKIP:
628 crossfade = !auto_skip;
629 break;
630 case CROSSFADE_ENABLE_SHUFFLE:
631 crossfade = global_settings.playlist_shuffle;
632 break;
633 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
634 crossfade = global_settings.playlist_shuffle || !auto_skip;
635 break;
636 case CROSSFADE_ENABLE_ALWAYS:
637 crossfade = true;
638 break;
641 /* else crossfade is off, crossfade is already active, not enough data,
642 * pcm is off now (implying low data), not crossfading or low latency mode
645 if (crossfade)
647 logf("crossfade track change");
649 /* Don't enable mix mode when skipping tracks manually */
650 crossfade_mixmode = auto_skip &&
651 global_settings.crossfade_fade_out_mixmode;
653 crossfade_auto_skip = auto_skip;
655 crossfade_status = CROSSFADE_TRACK_CHANGE_STARTED;
657 trigger_cpu_boost();
659 /* Cancel any pending automatic gapless transition and if a manual
660 skip, stop position updates */
661 pcm_play_lock();
662 pcmbuf_cancel_track_change(!auto_skip);
663 pcm_play_unlock();
665 else
666 #endif /* HAVE_CROSSFADE */
667 if (auto_skip)
669 /* The codec is moving on to the next track, but the current track will
670 * continue to play, so mark the last write chunk as the last one in
671 * the track */
672 logf("gapless track change");
673 #ifdef HAVE_CROSSFADE
674 if (crossfade_status != CROSSFADE_INACTIVE)
676 /* Crossfade is still active but crossfade is not happening - for
677 * now, chicken-out and clear out the buffer (just like before) to
678 * avoid fade pile-up on short tracks fading-in over long ones */
679 pcmbuf_play_stop();
681 #endif
682 pcmbuf_monitor_track_change(true);
684 else
686 /* Discard old data; caller needs no transition notification */
687 logf("manual track change");
688 pcmbuf_play_stop();
693 /** Playback */
695 /* PCM driver callback */
696 static void pcmbuf_pcm_callback(unsigned char **start, size_t *size)
698 /*- Process the chunk that just finished -*/
699 size_t index = chunk_ridx;
700 struct chunkdesc *desc = current_desc;
702 if (desc)
704 /* If last chunk in the track, notify of track change */
705 if (desc->is_end != 0)
706 audio_pcmbuf_track_change(true);
708 /* Free it for reuse */
709 chunk_ridx = index = index_next(index);
712 /*- Process the new one -*/
713 if (index != chunk_widx && !fade_out_complete)
715 current_desc = desc = index_chunkdesc(index);
717 *start = index_buffer(index);
718 *size = desc->size;
720 if (desc->pos_key != 0)
722 /* Positioning chunk - notify playback */
723 audio_pcmbuf_position_callback(desc->elapsed, desc->offset,
724 desc->pos_key);
729 /* Force playback */
730 void pcmbuf_play_start(void)
732 logf("pcmbuf_play_start");
734 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED &&
735 chunk_widx != chunk_ridx)
737 current_desc = NULL;
738 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
739 NULL, 0);
743 /* Stop channel, empty and reset buffer */
744 void pcmbuf_play_stop(void)
746 logf("pcmbuf_play_stop");
748 /* Reset channel */
749 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
751 /* Reset buffer */
752 init_buffer_state();
754 /* Revert to position updates by PCM */
755 pcmbuf_sync_position = false;
757 #ifdef HAVE_CROSSFADE
758 crossfade_status = CROSSFADE_INACTIVE;
759 #endif
761 /* Can unboost the codec thread here no matter who's calling,
762 * pretend full pcm buffer to unboost */
763 boost_codec_thread(10);
766 void pcmbuf_pause(bool pause)
768 logf("pcmbuf_pause: %s", pause?"pause":"play");
770 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED)
771 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
772 else if (!pause)
773 pcmbuf_play_start();
777 /** Crossfade */
779 #ifdef HAVE_CROSSFADE
780 /* Find the buffer index that's 'size' bytes away from 'index' */
781 static size_t crossfade_find_index(size_t index, size_t size)
783 if (index != INVALID_BUF_INDEX)
785 size_t i = ALIGN_DOWN(index, PCMBUF_CHUNK_SIZE);
786 size += index - i;
788 while (i != chunk_widx)
790 size_t desc_size = index_chunkdesc(i)->size;
792 if (size < desc_size)
793 return i + size;
795 size -= desc_size;
796 i = index_next(i);
800 return INVALID_BUF_INDEX;
803 /* Align the needed buffer area up to the end of existing data */
804 static size_t crossfade_find_buftail(size_t buffer_rem, size_t buffer_need)
806 crossfade_index = chunk_ridx;
808 if (buffer_rem > buffer_need)
810 size_t distance;
812 if (crossfade_auto_skip)
814 /* Automatic track changes only modify the last part of the buffer,
815 * so find the right chunk and sample to start the crossfade */
816 distance = buffer_rem - buffer_need;
817 buffer_rem = buffer_need;
819 else
821 /* Manual skips occur immediately, but give 1/5s to process */
822 distance = BYTERATE / 5;
823 buffer_rem -= BYTERATE / 5;
826 crossfade_index = crossfade_find_index(crossfade_index, distance);
829 return buffer_rem;
832 /* Returns the number of bytes _NOT_ mixed/faded */
833 static int crossfade_mix_fade(int factor, size_t size, void *buf, size_t *out_index,
834 unsigned long elapsed, off_t offset)
836 if (size == 0)
837 return 0;
839 size_t index = *out_index;
841 if (index == INVALID_BUF_INDEX)
842 return size;
844 const int16_t *input_buf = buf;
845 int16_t *output_buf = (int16_t *)index_buffer(index);
847 while (size)
849 struct chunkdesc *desc = index_chunkdesc(index);
851 switch (offset)
853 case MIXFADE_NULLIFY_POS:
854 /* Stop position updates for the chunk */
855 desc->pos_key = 0;
856 break;
857 case MIXFADE_KEEP_POS:
858 /* Keep position info as it is */
859 break;
860 default:
861 /* Replace position info */
862 stamp_chunk(desc, elapsed, offset);
865 size_t rem = desc->size - (index % PCMBUF_CHUNK_SIZE);
866 int16_t *chunk_end = SKIPBYTES(output_buf, rem);
868 if (size < rem)
869 rem = size;
871 size -= rem;
875 /* fade left and right channel at once to keep buffer alignment */
876 int32_t left = output_buf[0];
877 int32_t right = output_buf[1];
879 if (input_buf)
881 /* fade the input buffer and mix into the chunk */
882 left += *input_buf++ * factor >> 8;
883 right += *input_buf++ * factor >> 8;
884 left = clip_sample_16(left);
885 right = clip_sample_16(right);
887 else
889 /* fade the chunk only */
890 left = left * factor >> 8;
891 right = right * factor >> 8;
894 *output_buf++ = left;
895 *output_buf++ = right;
897 rem -= 4;
899 while (rem);
901 /* move to next chunk as needed */
902 if (output_buf >= chunk_end)
904 index = index_next(index);
906 if (index == chunk_widx)
908 /* End of existing data */
909 *out_index = INVALID_BUF_INDEX;
910 return size;
913 output_buf = (int16_t *)index_buffer(index);
917 *out_index = buffer_index(output_buf);
918 return 0;
921 /* Initializes crossfader, calculates all necessary parameters and performs
922 * fade-out with the PCM buffer. */
923 static void crossfade_start(void)
925 logf("crossfade_start");
927 pcm_play_lock();
929 /* Initialize the crossfade buffer size to all of the buffered data that
930 * has not yet been sent to the DMA */
931 size_t unplayed = pcmbuf_unplayed_bytes();
933 /* Reject crossfade if less than .5s of data */
934 if (unplayed < DATA_LEVEL(2))
936 logf("crossfade rejected");
938 crossfade_status = CROSSFADE_INACTIVE;
940 if (crossfade_auto_skip)
941 pcmbuf_monitor_track_change(true);
943 pcm_play_unlock();
944 return;
947 /* Fading will happen */
948 crossfade_status = CROSSFADE_ACTIVE;
950 /* Get fade info from settings. */
951 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
952 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
953 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
954 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE;
956 if (!crossfade_auto_skip)
958 /* Forego fade-in delay on manual skip - do the best to preserve auto skip
959 relationship */
960 if (fade_out_delay > fade_in_delay)
961 fade_out_delay -= fade_in_delay;
962 else
963 fade_out_delay = 0;
965 fade_in_delay = 0;
968 size_t fade_out_need = fade_out_delay + fade_out_rem;
970 if (!crossfade_mixmode)
972 size_t buffer_rem = crossfade_find_buftail(unplayed, fade_out_need);
974 pcm_play_unlock();
976 if (buffer_rem < fade_out_need)
978 /* Existing buffers are short */
979 size_t fade_out_short = fade_out_need - buffer_rem;
981 if (fade_out_rem >= fade_out_short)
983 /* Truncate fade-out duration */
984 fade_out_rem -= fade_out_short;
986 else
988 /* Truncate fade-out and fade-out delay */
989 fade_out_delay = fade_out_rem;
990 fade_out_rem = 0;
994 /* Completely process the crossfade fade-out effect with current PCM buffer */
996 /* Fade out the specified amount of the already processed audio */
997 size_t fade_out_total = fade_out_rem;
999 /* Find the right chunk and sample to start fading out */
1000 size_t fade_out_index = crossfade_find_index(crossfade_index, fade_out_delay);
1002 while (fade_out_rem > 0)
1004 /* Each 1/20 second of audio will have the same fade applied */
1005 size_t block_rem = MIN(BYTERATE / 20, fade_out_rem);
1006 int factor = (fade_out_rem << 8) / fade_out_total;
1008 fade_out_rem -= block_rem;
1010 crossfade_mix_fade(factor, block_rem, NULL, &fade_out_index,
1011 0, MIXFADE_KEEP_POS);
1014 /* zero out the rest of the buffer */
1015 crossfade_mix_fade(0, pcmbuf_size, NULL, &fade_out_index,
1016 0, MIXFADE_NULLIFY_POS);
1018 pcm_play_lock();
1021 /* Initialize fade-in counters */
1022 crossfade_fade_in_total = fade_in_duration;
1023 crossfade_fade_in_rem = fade_in_duration;
1025 /* Find the right chunk and sample to start fading in - redo from read
1026 chunk in case original position were/was overrun in callback - the
1027 track change event _must not_ ever fail to happen */
1028 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay;
1030 crossfade_find_buftail(unplayed, fade_out_need);
1032 if (crossfade_auto_skip)
1033 pcmbuf_monitor_track_change_ex(crossfade_index, 0);
1035 pcm_play_unlock();
1037 logf("crossfade_start done!");
1040 /* Perform fade-in of new track */
1041 static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset)
1043 unsigned char *buf = crossfade_buffer;
1045 if (crossfade_fade_in_rem)
1047 /* Fade factor for this packet */
1048 int factor =
1049 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
1050 crossfade_fade_in_total;
1051 /* Bytes to fade */
1052 size_t fade_rem = MIN(size, crossfade_fade_in_rem);
1054 /* We _will_ fade this many bytes */
1055 crossfade_fade_in_rem -= fade_rem;
1057 if (crossfade_index != INVALID_BUF_INDEX)
1059 /* Mix the data */
1060 size_t fade_total = fade_rem;
1061 fade_rem = crossfade_mix_fade(factor, fade_rem, buf, &crossfade_index,
1062 elapsed, offset);
1063 fade_total -= fade_rem;
1064 size -= fade_total;
1065 buf += fade_total;
1067 if (!size)
1068 return;
1071 /* Fade remaining samples in place */
1072 int samples = fade_rem / 4;
1073 int16_t *input_buf = (int16_t *)buf;
1075 while (samples--)
1077 int32_t left = input_buf[0];
1078 int32_t right = input_buf[1];
1079 *input_buf++ = left * factor >> 8;
1080 *input_buf++ = right * factor >> 8;
1084 if (crossfade_index != INVALID_BUF_INDEX)
1086 /* Mix the data */
1087 size_t mix_total = size;
1089 /* A factor of 256 means mix only, no fading */
1090 size = crossfade_mix_fade(256, size, buf, &crossfade_index,
1091 elapsed, offset);
1092 buf += mix_total - size;
1094 if (!size)
1095 return;
1098 /* Data might remain in the fade buffer yet the fade-in has run its
1099 course - finish it off as normal chunks */
1100 while (size > 0)
1102 size_t copy_n = size;
1103 unsigned char *outbuf = get_write_buffer(&copy_n);
1104 memcpy(outbuf, buf, copy_n);
1105 commit_write_buffer(copy_n, elapsed, offset);
1106 buf += copy_n;
1107 size -= copy_n;
1110 /* if no more fading-in to do, stop the crossfade */
1111 #if 0
1112 /* This way (the previous way) can cause a sudden volume jump if mixable
1113 data is used up before the fade-in completes and that just sounds wrong
1114 -- jethead71 */
1115 if (!crossfade_fade_in_rem || crossfade_index == INVALID_BUF_INDEX)
1116 #endif
1117 /* Let fade-in complete even if not fully overlapping the existing data */
1118 if (!crossfade_fade_in_rem)
1119 crossfade_status = CROSSFADE_INACTIVE;
1122 static void pcmbuf_finish_crossfade_enable(void)
1124 /* Copy the pending setting over now */
1125 crossfade_setting = crossfade_enable_request;
1127 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ?
1128 /* If crossfading, try to keep the buffer full other than 1 second */
1129 (pcmbuf_size - BYTERATE) :
1130 /* Otherwise, just use the default */
1131 PCMBUF_WATERMARK;
1134 bool pcmbuf_is_crossfade_active(void)
1136 return crossfade_status != CROSSFADE_INACTIVE;
1139 void pcmbuf_request_crossfade_enable(int setting)
1141 /* Next setting to be used, not applied now */
1142 crossfade_enable_request = setting;
1145 bool pcmbuf_is_same_size(void)
1147 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */
1148 bool same_size = pcmbuf_buffer ?
1149 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true;
1151 /* no buffer change needed, so finish crossfade setup now */
1152 if (same_size)
1153 pcmbuf_finish_crossfade_enable();
1155 return same_size;
1157 #endif /* HAVE_CROSSFADE */
1160 /** Debug menu, other metrics */
1162 /* Amount of bytes left in the buffer, accounting for uncommitted bytes */
1163 size_t pcmbuf_free(void)
1165 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting;
1168 /* Data bytes allocated for buffer */
1169 size_t pcmbuf_get_bufsize(void)
1171 return pcmbuf_size;
1174 /* Number of committed descriptors */
1175 int pcmbuf_used_descs(void)
1177 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE;
1180 /* Total number of descriptors allocated */
1181 int pcmbuf_descs(void)
1183 return pcmbuf_desc_count;
1187 /** Fading and channel volume control */
1189 /* Sync the channel amplitude to all states */
1190 static void pcmbuf_update_volume(void)
1192 unsigned int vol = fade_vol;
1194 if (soft_mode)
1195 vol >>= 2;
1197 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol);
1200 /* Tick that does the fade for the playback channel */
1201 static void pcmbuf_fade_tick(void)
1203 /* ~1/3 second for full range fade */
1204 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1206 if (fade_state == PCM_FADING_IN)
1207 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1208 else if (fade_state == PCM_FADING_OUT)
1209 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1211 pcmbuf_update_volume();
1213 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1215 /* Fade is complete */
1216 tick_remove_task(pcmbuf_fade_tick);
1217 if (fade_state == PCM_FADING_OUT)
1219 /* Tell PCM to stop at its earliest convenience */
1220 fade_out_complete = true;
1223 fade_state = PCM_NOT_FADING;
1227 /* Fade channel in or out in the background */
1228 void pcmbuf_fade(bool fade, bool in)
1230 /* Must pause any active fade */
1231 pcm_play_lock();
1233 if (fade_state != PCM_NOT_FADING)
1234 tick_remove_task(pcmbuf_fade_tick);
1236 fade_out_complete = false;
1238 pcm_play_unlock();
1240 if (!fade)
1242 /* Simply set the level */
1243 fade_state = PCM_NOT_FADING;
1244 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1245 pcmbuf_update_volume();
1247 else
1249 /* Set direction and resume fade from current point */
1250 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1251 tick_add_task(pcmbuf_fade_tick);
1255 /* Return 'true' if fade is in progress */
1256 bool pcmbuf_fading(void)
1258 return fade_state != PCM_NOT_FADING;
1261 /* Quiet-down the channel if 'shhh' is true or else play at normal level */
1262 void pcmbuf_soft_mode(bool shhh)
1264 /* Have to block the tick or improper order could leave volume in soft
1265 mode if fading reads the old value first but updates after us. */
1266 int res = fade_state != PCM_NOT_FADING ?
1267 tick_remove_task(pcmbuf_fade_tick) : -1;
1269 soft_mode = shhh;
1270 pcmbuf_update_volume();
1272 if (res == 0)
1273 tick_add_task(pcmbuf_fade_tick);
1277 /** Misc */
1279 bool pcmbuf_is_lowdata(void)
1281 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
1283 if (status != CHANNEL_PLAYING || pcmbuf_is_crossfade_active())
1284 return false;
1286 #if MEMORYSIZE > 2
1287 /* 1 seconds of buffer is low data */
1288 return pcmbuf_unplayed_bytes() < DATA_LEVEL(4);
1289 #else
1290 /* under watermark is low data */
1291 return pcmbuf_unplayed_bytes() < pcmbuf_watermark;
1292 #endif
1295 void pcmbuf_set_low_latency(bool state)
1297 low_latency_mode = state;
1300 /* Return the current position key value */
1301 unsigned int pcmbuf_get_position_key(void)
1303 return position_key;
1306 /* Set position updates to be synchronous and immediate in addition to during
1307 PCM frames - cancelled upon first codec insert or upon stopping */
1308 void pcmbuf_sync_position_update(void)
1310 pcmbuf_sync_position = true;