Fix exit/return behavior in the id3 info screen.Fixes returning immediately on touchs...
[maemo-rb.git] / apps / pcmbuf.c
blob8135a30a3693752f676be3d02cc17dcf2a2bf7e1
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
49 /* Massive size is a nasty temp fix */
50 #define PCMBUF_GUARD_SIZE (1024u*12*((NATIVE_FREQUENCY+7999)/8000))
52 /* Mnemonics for common data commit thresholds */
53 #define COMMIT_CHUNKS PCMBUF_CHUNK_SIZE
54 #define COMMIT_ALL_DATA 1u
56 /* Size of the crossfade buffer where codec data is written to be faded
57 on commit */
58 #define CROSSFADE_BUFSIZE 8192u
60 /* Number of bytes played per second:
61 (sample rate * 2 channels * 2 bytes/sample) */
62 #define BYTERATE (NATIVE_FREQUENCY * 4)
64 #if MEMORYSIZE > 2
65 /* Keep watermark high for large memory target - at least (2s) */
66 #define PCMBUF_WATERMARK (BYTERATE * 2)
67 #define MIN_BUFFER_SIZE (BYTERATE * 3)
68 #else
69 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
70 #define MIN_BUFFER_SIZE (BYTERATE * 1)
71 #endif
73 /* Describes each audio packet - keep it small since there are many of them */
74 struct chunkdesc
76 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */
77 uint8_t is_end; /* Flag indicating end of track */
78 uint8_t pos_key; /* Who put the position info in (0 = undefined) */
79 unsigned long elapsed; /* Elapsed time to use */
80 off_t offset; /* Offset to use */
83 /* General PCM buffer data */
84 #define INVALID_BUF_INDEX ((size_t)0 - (size_t)1)
86 static unsigned char *pcmbuf_buffer;
87 static unsigned char *pcmbuf_guardbuf;
88 static size_t pcmbuf_size;
89 static struct chunkdesc *pcmbuf_descriptors;
90 static unsigned int pcmbuf_desc_count;
91 static unsigned int position_key = 1;
93 static size_t chunk_ridx;
94 static size_t chunk_widx;
96 static size_t pcmbuf_bytes_waiting;
98 static size_t pcmbuf_watermark;
99 static struct chunkdesc *current_desc;
101 static bool low_latency_mode = false;
103 static bool pcmbuf_sync_position = false;
105 /* Fade effect */
106 static unsigned int fade_vol = MIX_AMP_UNITY;
107 static enum
109 PCM_NOT_FADING = 0,
110 PCM_FADING_IN,
111 PCM_FADING_OUT,
112 } fade_state = PCM_NOT_FADING;
113 static bool fade_out_complete = false;
115 /* Voice */
116 static bool soft_mode = false;
118 #ifdef HAVE_CROSSFADE
119 /* Crossfade buffer */
120 static unsigned char *crossfade_buffer;
122 /* Crossfade related state */
123 static int crossfade_setting;
124 static int crossfade_enable_request;
125 static bool crossfade_mixmode;
126 static bool crossfade_auto_skip;
128 static enum
130 CROSSFADE_INACTIVE = 0,
131 CROSSFADE_TRACK_CHANGE_STARTED,
132 CROSSFADE_ACTIVE,
133 } crossfade_status = CROSSFADE_INACTIVE;
135 /* Track the current location for processing crossfade */
136 static size_t crossfade_index;
138 /* Counters for fading in new data */
139 static size_t crossfade_fade_in_total;
140 static size_t crossfade_fade_in_rem;
142 /* Defines for operations on position info when mixing/fading -
143 passed in offset parameter */
144 enum
146 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */
147 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */
148 /* Positive values cause stamping/restamping */
151 static void crossfade_start(void);
152 static void write_to_crossfade(size_t size, unsigned long elapsed,
153 off_t offset);
154 static void pcmbuf_finish_crossfade_enable(void);
155 #endif /* HAVE_CROSSFADE */
157 /* Thread */
158 #ifdef HAVE_PRIORITY_SCHEDULING
159 static int codec_thread_priority = PRIORITY_PLAYBACK;
160 #endif
162 /* Helpful macros for use in conditionals this assumes some of the above
163 * static variable names */
164 #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs))
166 /* Callbacks into playback.c */
167 extern void audio_pcmbuf_position_callback(unsigned long elapsed,
168 off_t offset, unsigned int key);
169 extern void audio_pcmbuf_track_change(bool pcmbuf);
170 extern bool audio_pcmbuf_may_play(void);
171 extern void audio_pcmbuf_sync_position(void);
174 /**************************************/
176 /* Return number of commited bytes in buffer (committed chunks count as
177 a full chunk even if only partially filled) */
178 static size_t pcmbuf_unplayed_bytes(void)
180 size_t ridx = chunk_ridx;
181 size_t widx = chunk_widx;
183 if (ridx > widx)
184 widx += pcmbuf_size;
186 return widx - ridx;
189 /* Return the next PCM chunk in the PCM buffer given a byte index into it */
190 static size_t index_next(size_t index)
192 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE);
194 if (index >= pcmbuf_size)
195 index -= pcmbuf_size;
197 return index;
200 /* Convert a byte offset in the PCM buffer into a pointer in the buffer */
201 static FORCE_INLINE void * index_buffer(size_t index)
203 return pcmbuf_buffer + index;
206 /* Convert a pointer in the buffer into an index offset */
207 static FORCE_INLINE size_t buffer_index(void *p)
209 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer;
212 /* Return a chunk descriptor for a byte index in the buffer */
213 static struct chunkdesc * index_chunkdesc(size_t index)
215 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE];
218 /* Return a chunk descriptor for a byte index in the buffer, offset by 'offset'
219 chunks */
220 static struct chunkdesc * index_chunkdesc_offs(size_t index, int offset)
222 int i = index / PCMBUF_CHUNK_SIZE;
224 if (offset != 0)
226 i = (i + offset) % pcmbuf_desc_count;
228 /* remainder => modulus */
229 if (i < 0)
230 i += pcmbuf_desc_count;
233 return &pcmbuf_descriptors[i];
237 /** Accept new PCM data */
239 /* Split the uncommitted data as needed into chunks, stopping when uncommitted
240 data is below the threshold */
241 static void commit_chunks(size_t threshold)
243 size_t index = chunk_widx;
244 size_t end_index = index + pcmbuf_bytes_waiting;
246 /* Copy to the beginning of the buffer all data that must wrap */
247 if (end_index > pcmbuf_size)
248 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size);
250 struct chunkdesc *desc = index_chunkdesc(index);
254 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE);
255 pcmbuf_bytes_waiting -= size;
257 /* Fill in the values in the new buffer chunk */
258 desc->size = (uint16_t)size;
260 /* Advance the current write chunk and make it available to the
261 PCM callback */
262 chunk_widx = index = index_next(index);
263 desc = index_chunkdesc(index);
265 /* Reset it before using it */
266 desc->is_end = 0;
267 desc->pos_key = 0;
269 while (pcmbuf_bytes_waiting >= threshold);
272 /* If uncommitted data count is above or equal to the threshold, commit it */
273 static FORCE_INLINE void commit_if_needed(size_t threshold)
275 if (pcmbuf_bytes_waiting >= threshold)
276 commit_chunks(threshold);
279 /* Place positioning information in the chunk */
280 static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed,
281 off_t offset)
283 /* One-time stamping of a given chunk by the same track - new track may
284 overwrite */
285 unsigned int key = position_key;
287 if (desc->pos_key != key)
289 desc->pos_key = key;
290 desc->elapsed = elapsed;
291 desc->offset = offset;
295 /* Set priority of the codec thread */
296 #ifdef HAVE_PRIORITY_SCHEDULING
298 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */
299 static void boost_codec_thread(int pcm_fill_state)
301 static const int8_t prios[11] =
303 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */
304 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */
305 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */
306 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */
307 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */
308 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */
309 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */
310 /* raising priority above 70% shouldn't be needed */
311 PRIORITY_PLAYBACK, /* 70 - 80% */
312 PRIORITY_PLAYBACK, /* 80 - 90% */
313 PRIORITY_PLAYBACK, /* 90 -100% */
314 PRIORITY_PLAYBACK, /* 100% */
317 int new_prio = prios[pcm_fill_state];
319 /* Keep voice and codec threads at the same priority or else voice
320 * will starve if the codec thread's priority is boosted. */
321 if (new_prio != codec_thread_priority)
323 codec_thread_set_priority(new_prio);
324 voice_thread_set_priority(new_prio);
325 codec_thread_priority = new_prio;
328 #else
329 #define boost_codec_thread(pcm_fill_state) do{}while(0)
330 #endif /* HAVE_PRIORITY_SCHEDULING */
332 /* Get the next available buffer and size - assumes adequate space exists */
333 static void * get_write_buffer(size_t *size)
335 /* Obtain current chunk fill address */
336 size_t index = chunk_widx + pcmbuf_bytes_waiting;
337 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE;
339 /* Get count to the end of the buffer where a wrap will happen +
340 the guard */
341 size_t endsize = index_end - index;
343 /* Return available unwrapped space */
344 *size = MIN(*size, endsize);
346 return index_buffer(index);
349 /* Commit outstanding data leaving less than a chunk size remaining and
350 write position info to the first chunk */
351 static void commit_write_buffer(size_t size, unsigned long elapsed, off_t offset)
353 struct chunkdesc *desc = index_chunkdesc(chunk_widx);
354 stamp_chunk(desc, elapsed, offset);
356 /* Add this data and commit if one or more chunks are ready */
357 pcmbuf_bytes_waiting += size;
359 commit_if_needed(COMMIT_CHUNKS);
362 /* Request space in the buffer for writing output samples */
363 void * pcmbuf_request_buffer(int *count)
365 size_t size = *count * 4;
367 #ifdef HAVE_CROSSFADE
368 /* We're going to crossfade to a new track, which is now on its way */
369 if (crossfade_status == CROSSFADE_TRACK_CHANGE_STARTED)
370 crossfade_start();
372 /* If crossfade has begun, put the new track samples in crossfade_buffer */
373 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE)
374 size = CROSSFADE_BUFSIZE;
375 #endif
377 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
378 size_t remaining = pcmbuf_unplayed_bytes();
380 /* Need to have length bytes to prevent wrapping overwriting - leave one
381 descriptor free to guard so that 0 != full in ring buffer */
382 size_t freespace = pcmbuf_free();
384 if (pcmbuf_sync_position)
385 audio_pcmbuf_sync_position();
387 if (freespace < size + PCMBUF_CHUNK_SIZE)
388 return NULL;
390 /* Maintain the buffer level above the watermark */
391 if (status != CHANNEL_STOPPED)
393 if (low_latency_mode)
395 /* 1/4s latency. */
396 if (remaining > DATA_LEVEL(1))
397 return NULL;
400 /* Boost CPU if necessary */
401 size_t realrem = pcmbuf_size - freespace;
403 if (realrem < pcmbuf_watermark)
404 trigger_cpu_boost();
406 boost_codec_thread(realrem*10 / pcmbuf_size);
408 #ifdef HAVE_CROSSFADE
409 /* Disable crossfade if < .5s of audio */
410 if (remaining < DATA_LEVEL(2))
411 crossfade_status = CROSSFADE_INACTIVE;
412 #endif
414 else /* !playing */
416 /* Boost CPU for pre-buffer */
417 trigger_cpu_boost();
419 /* If pre-buffered to the watermark, start playback */
420 #if MEMORYSIZE > 2
421 if (remaining > DATA_LEVEL(4))
422 #else
423 if (remaining > pcmbuf_watermark)
424 #endif
426 if (audio_pcmbuf_may_play())
427 pcmbuf_play_start();
431 void *buf =
432 #ifdef HAVE_CROSSFADE
433 crossfade_status != CROSSFADE_INACTIVE ? crossfade_buffer :
434 #endif
435 get_write_buffer(&size);
437 *count = size / 4;
438 return buf;
441 /* Handle new samples to the buffer */
442 void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset)
444 size_t size = count * 4;
446 #ifdef HAVE_CROSSFADE
447 if (crossfade_status != CROSSFADE_INACTIVE)
449 write_to_crossfade(size, elapsed, offset);
451 else
452 #endif
454 commit_write_buffer(size, elapsed, offset);
457 /* Revert to position updates by PCM */
458 pcmbuf_sync_position = false;
462 /** Init */
463 static unsigned int get_next_required_pcmbuf_chunks(void)
465 size_t size = MIN_BUFFER_SIZE;
467 #ifdef HAVE_CROSSFADE
468 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
470 size_t seconds = global_settings.crossfade_fade_out_delay +
471 global_settings.crossfade_fade_out_duration;
472 size += seconds * BYTERATE;
474 #endif
476 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE));
477 return size / PCMBUF_CHUNK_SIZE;
480 /* Initialize the ringbuffer state */
481 static void init_buffer_state(void)
483 /* Reset counters */
484 chunk_ridx = chunk_widx = 0;
485 pcmbuf_bytes_waiting = 0;
487 /* Reset first descriptor */
488 struct chunkdesc *desc = pcmbuf_descriptors;
489 desc->is_end = 0;
490 desc->pos_key = 0;
493 /* Initialize the PCM buffer. The structure looks like this:
494 * ...[|FADEBUF]|---------PCMBUF---------|GUARDBUF|DESCS| */
495 size_t pcmbuf_init(unsigned char *bufend)
497 unsigned char *bufstart;
499 /* Set up the buffers */
500 pcmbuf_desc_count = get_next_required_pcmbuf_chunks();
501 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE;
502 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count;
504 pcmbuf_buffer = (void *)pcmbuf_descriptors -
505 pcmbuf_size - PCMBUF_GUARD_SIZE;
507 /* Mem-align buffer chunks for more efficient handling in lower layers */
508 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE);
510 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size;
511 bufstart = pcmbuf_buffer;
513 #ifdef HAVE_CROSSFADE
514 /* Allocate FADEBUF if it will be needed */
515 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
517 bufstart -= CROSSFADE_BUFSIZE;
518 crossfade_buffer = bufstart;
521 pcmbuf_finish_crossfade_enable();
522 #else /* !HAVE_CROSSFADE */
523 pcmbuf_watermark = PCMBUF_WATERMARK;
524 #endif /* HAVE_CROSSFADE */
526 init_buffer_state();
528 pcmbuf_soft_mode(false);
530 return bufend - bufstart;
534 /** Track change */
536 /* Place a track change notification in a specific descriptor or post it
537 immediately if the buffer is empty or the index is invalid */
538 static void pcmbuf_monitor_track_change_ex(size_t index, int offset)
540 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX)
542 /* If monitoring, set flag in specified chunk */
543 index_chunkdesc_offs(index, offset)->is_end = 1;
545 else
547 /* Post now if no outstanding buffers exist */
548 audio_pcmbuf_track_change(false);
552 /* Clear end of track and optionally the positioning info for all data */
553 static void pcmbuf_cancel_track_change(bool position)
555 size_t index = chunk_ridx;
557 while (1)
559 struct chunkdesc *desc = index_chunkdesc(index);
561 desc->is_end = 0;
563 if (position)
564 desc->pos_key = 0;
566 if (index == chunk_widx)
567 break;
569 index = index_next(index);
573 /* Place a track change notification at the end of the buffer or post it
574 immediately if the buffer is empty */
575 void pcmbuf_monitor_track_change(bool monitor)
577 pcm_play_lock();
579 if (monitor)
580 pcmbuf_monitor_track_change_ex(chunk_widx, -1);
581 else
582 pcmbuf_cancel_track_change(false);
584 pcm_play_unlock();
587 void pcmbuf_start_track_change(enum pcm_track_change_type type)
589 #ifdef HAVE_CROSSFADE
590 bool crossfade = false;
591 #endif
592 bool auto_skip = type != TRACK_CHANGE_MANUAL;
594 /* Commit all outstanding data before starting next track - tracks don't
595 comingle inside a single buffer chunk */
596 commit_if_needed(COMMIT_ALL_DATA);
598 /* Update position key so that:
599 1) Positions are keyed to the track to which they belong for sync
600 purposes
602 2) Buffers stamped with the outgoing track's positions are restamped
603 to the incoming track's positions when crossfading
605 if (++position_key > UINT8_MAX)
606 position_key = 1;
608 if (type == TRACK_CHANGE_END_OF_DATA)
610 /* If end of all data, force playback */
611 if (audio_pcmbuf_may_play())
612 pcmbuf_play_start();
614 #ifdef HAVE_CROSSFADE
615 /* Determine whether this track change needs to crossfaded and how */
616 else if (crossfade_setting != CROSSFADE_ENABLE_OFF &&
617 !pcmbuf_is_crossfade_active() &&
618 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) &&
619 !low_latency_mode)
621 switch (crossfade_setting)
623 case CROSSFADE_ENABLE_AUTOSKIP:
624 crossfade = auto_skip;
625 break;
626 case CROSSFADE_ENABLE_MANSKIP:
627 crossfade = !auto_skip;
628 break;
629 case CROSSFADE_ENABLE_SHUFFLE:
630 crossfade = global_settings.playlist_shuffle;
631 break;
632 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
633 crossfade = global_settings.playlist_shuffle || !auto_skip;
634 break;
635 case CROSSFADE_ENABLE_ALWAYS:
636 crossfade = true;
637 break;
640 /* else crossfade is off, crossfade is already active, not enough data,
641 * pcm is off now (implying low data), not crossfading or low latency mode
644 if (crossfade)
646 logf("crossfade track change");
648 /* Don't enable mix mode when skipping tracks manually */
649 crossfade_mixmode = auto_skip &&
650 global_settings.crossfade_fade_out_mixmode;
652 crossfade_auto_skip = auto_skip;
654 crossfade_status = CROSSFADE_TRACK_CHANGE_STARTED;
656 trigger_cpu_boost();
658 /* Cancel any pending automatic gapless transition and if a manual
659 skip, stop position updates */
660 pcm_play_lock();
661 pcmbuf_cancel_track_change(!auto_skip);
662 pcm_play_unlock();
664 else
665 #endif /* HAVE_CROSSFADE */
666 if (auto_skip)
668 /* The codec is moving on to the next track, but the current track will
669 * continue to play, so mark the last write chunk as the last one in
670 * the track */
671 logf("gapless track change");
672 #ifdef HAVE_CROSSFADE
673 if (crossfade_status != CROSSFADE_INACTIVE)
675 /* Crossfade is still active but crossfade is not happening - for
676 * now, chicken-out and clear out the buffer (just like before) to
677 * avoid fade pile-up on short tracks fading-in over long ones */
678 pcmbuf_play_stop();
680 #endif
681 pcmbuf_monitor_track_change(true);
683 else
685 /* Discard old data; caller needs no transition notification */
686 logf("manual track change");
687 pcmbuf_play_stop();
692 /** Playback */
694 /* PCM driver callback */
695 static void pcmbuf_pcm_callback(unsigned char **start, size_t *size)
697 /*- Process the chunk that just finished -*/
698 size_t index = chunk_ridx;
699 struct chunkdesc *desc = current_desc;
701 if (desc)
703 /* If last chunk in the track, notify of track change */
704 if (desc->is_end != 0)
705 audio_pcmbuf_track_change(true);
707 /* Free it for reuse */
708 chunk_ridx = index = index_next(index);
711 /*- Process the new one -*/
712 if (index != chunk_widx && !fade_out_complete)
714 current_desc = desc = index_chunkdesc(index);
716 *start = index_buffer(index);
717 *size = desc->size;
719 if (desc->pos_key != 0)
721 /* Positioning chunk - notify playback */
722 audio_pcmbuf_position_callback(desc->elapsed, desc->offset,
723 desc->pos_key);
728 /* Force playback */
729 void pcmbuf_play_start(void)
731 logf("pcmbuf_play_start");
733 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED &&
734 chunk_widx != chunk_ridx)
736 current_desc = NULL;
737 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
738 NULL, 0);
742 /* Stop channel, empty and reset buffer */
743 void pcmbuf_play_stop(void)
745 logf("pcmbuf_play_stop");
747 /* Reset channel */
748 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
750 /* Reset buffer */
751 init_buffer_state();
753 /* Revert to position updates by PCM */
754 pcmbuf_sync_position = false;
756 #ifdef HAVE_CROSSFADE
757 crossfade_status = CROSSFADE_INACTIVE;
758 #endif
760 /* Can unboost the codec thread here no matter who's calling,
761 * pretend full pcm buffer to unboost */
762 boost_codec_thread(10);
765 void pcmbuf_pause(bool pause)
767 logf("pcmbuf_pause: %s", pause?"pause":"play");
769 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED)
770 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
771 else if (!pause)
772 pcmbuf_play_start();
776 /** Crossfade */
778 #ifdef HAVE_CROSSFADE
779 /* Find the buffer index that's 'size' bytes away from 'index' */
780 static size_t crossfade_find_index(size_t index, size_t size)
782 if (index != INVALID_BUF_INDEX)
784 size_t i = ALIGN_DOWN(index, PCMBUF_CHUNK_SIZE);
785 size += index - i;
787 while (i != chunk_widx)
789 size_t desc_size = index_chunkdesc(i)->size;
791 if (size < desc_size)
792 return i + size;
794 size -= desc_size;
795 i = index_next(i);
799 return INVALID_BUF_INDEX;
802 /* Align the needed buffer area up to the end of existing data */
803 static size_t crossfade_find_buftail(size_t buffer_rem, size_t buffer_need)
805 crossfade_index = chunk_ridx;
807 if (buffer_rem > buffer_need)
809 size_t distance;
811 if (crossfade_auto_skip)
813 /* Automatic track changes only modify the last part of the buffer,
814 * so find the right chunk and sample to start the crossfade */
815 distance = buffer_rem - buffer_need;
816 buffer_rem = buffer_need;
818 else
820 /* Manual skips occur immediately, but give 1/5s to process */
821 distance = BYTERATE / 5;
822 buffer_rem -= BYTERATE / 5;
825 crossfade_index = crossfade_find_index(crossfade_index, distance);
828 return buffer_rem;
831 /* Clip sample to signed 16 bit range */
832 static FORCE_INLINE int32_t clip_sample_16(int32_t sample)
834 if ((int16_t)sample != sample)
835 sample = 0x7fff ^ (sample >> 31);
836 return sample;
839 /* Returns the number of bytes _NOT_ mixed/faded */
840 static int crossfade_mix_fade(int factor, size_t size, void *buf, size_t *out_index,
841 unsigned long elapsed, off_t offset)
843 if (size == 0)
844 return 0;
846 size_t index = *out_index;
848 if (index == INVALID_BUF_INDEX)
849 return size;
851 const int16_t *input_buf = buf;
852 int16_t *output_buf = (int16_t *)index_buffer(index);
854 while (size)
856 struct chunkdesc *desc = index_chunkdesc(index);
858 switch (offset)
860 case MIXFADE_NULLIFY_POS:
861 /* Stop position updates for the chunk */
862 desc->pos_key = 0;
863 break;
864 case MIXFADE_KEEP_POS:
865 /* Keep position info as it is */
866 break;
867 default:
868 /* Replace position info */
869 stamp_chunk(desc, elapsed, offset);
872 size_t rem = desc->size - (index % PCMBUF_CHUNK_SIZE);
873 int16_t *chunk_end = SKIPBYTES(output_buf, rem);
875 if (size < rem)
876 rem = size;
878 size -= rem;
882 /* fade left and right channel at once to keep buffer alignment */
883 int32_t left = output_buf[0];
884 int32_t right = output_buf[1];
886 if (input_buf)
888 /* fade the input buffer and mix into the chunk */
889 left += *input_buf++ * factor >> 8;
890 right += *input_buf++ * factor >> 8;
891 left = clip_sample_16(left);
892 right = clip_sample_16(right);
894 else
896 /* fade the chunk only */
897 left = left * factor >> 8;
898 right = right * factor >> 8;
901 *output_buf++ = left;
902 *output_buf++ = right;
904 rem -= 4;
906 while (rem);
908 /* move to next chunk as needed */
909 if (output_buf >= chunk_end)
911 index = index_next(index);
913 if (index == chunk_widx)
915 /* End of existing data */
916 *out_index = INVALID_BUF_INDEX;
917 return size;
920 output_buf = (int16_t *)index_buffer(index);
924 *out_index = buffer_index(output_buf);
925 return 0;
928 /* Initializes crossfader, calculates all necessary parameters and performs
929 * fade-out with the PCM buffer. */
930 static void crossfade_start(void)
932 logf("crossfade_start");
934 pcm_play_lock();
936 /* Initialize the crossfade buffer size to all of the buffered data that
937 * has not yet been sent to the DMA */
938 size_t unplayed = pcmbuf_unplayed_bytes();
940 /* Reject crossfade if less than .5s of data */
941 if (unplayed < DATA_LEVEL(2))
943 logf("crossfade rejected");
945 crossfade_status = CROSSFADE_INACTIVE;
947 if (crossfade_auto_skip)
948 pcmbuf_monitor_track_change(true);
950 pcm_play_unlock();
951 return;
954 /* Fading will happen */
955 crossfade_status = CROSSFADE_ACTIVE;
957 /* Get fade info from settings. */
958 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
959 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
960 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
961 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE;
963 if (!crossfade_auto_skip)
965 /* Forego fade-in delay on manual skip - do the best to preserve auto skip
966 relationship */
967 if (fade_out_delay > fade_in_delay)
968 fade_out_delay -= fade_in_delay;
969 else
970 fade_out_delay = 0;
972 fade_in_delay = 0;
975 size_t fade_out_need = fade_out_delay + fade_out_rem;
977 if (!crossfade_mixmode)
979 size_t buffer_rem = crossfade_find_buftail(unplayed, fade_out_need);
981 pcm_play_unlock();
983 if (buffer_rem < fade_out_need)
985 /* Existing buffers are short */
986 size_t fade_out_short = fade_out_need - buffer_rem;
988 if (fade_out_rem >= fade_out_short)
990 /* Truncate fade-out duration */
991 fade_out_rem -= fade_out_short;
993 else
995 /* Truncate fade-out and fade-out delay */
996 fade_out_delay = fade_out_rem;
997 fade_out_rem = 0;
1001 /* Completely process the crossfade fade-out effect with current PCM buffer */
1003 /* Fade out the specified amount of the already processed audio */
1004 size_t fade_out_total = fade_out_rem;
1006 /* Find the right chunk and sample to start fading out */
1007 size_t fade_out_index = crossfade_find_index(crossfade_index, fade_out_delay);
1009 while (fade_out_rem > 0)
1011 /* Each 1/20 second of audio will have the same fade applied */
1012 size_t block_rem = MIN(BYTERATE / 20, fade_out_rem);
1013 int factor = (fade_out_rem << 8) / fade_out_total;
1015 fade_out_rem -= block_rem;
1017 crossfade_mix_fade(factor, block_rem, NULL, &fade_out_index,
1018 0, MIXFADE_KEEP_POS);
1021 /* zero out the rest of the buffer */
1022 crossfade_mix_fade(0, pcmbuf_size, NULL, &fade_out_index,
1023 0, MIXFADE_NULLIFY_POS);
1025 pcm_play_lock();
1028 /* Initialize fade-in counters */
1029 crossfade_fade_in_total = fade_in_duration;
1030 crossfade_fade_in_rem = fade_in_duration;
1032 /* Find the right chunk and sample to start fading in - redo from read
1033 chunk in case original position were/was overrun in callback - the
1034 track change event _must not_ ever fail to happen */
1035 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay;
1037 crossfade_find_buftail(unplayed, fade_out_need);
1039 if (crossfade_auto_skip)
1040 pcmbuf_monitor_track_change_ex(crossfade_index, 0);
1042 pcm_play_unlock();
1044 logf("crossfade_start done!");
1047 /* Perform fade-in of new track */
1048 static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset)
1050 unsigned char *buf = crossfade_buffer;
1052 if (crossfade_fade_in_rem)
1054 /* Fade factor for this packet */
1055 int factor =
1056 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
1057 crossfade_fade_in_total;
1058 /* Bytes to fade */
1059 size_t fade_rem = MIN(size, crossfade_fade_in_rem);
1061 /* We _will_ fade this many bytes */
1062 crossfade_fade_in_rem -= fade_rem;
1064 if (crossfade_index != INVALID_BUF_INDEX)
1066 /* Mix the data */
1067 size_t fade_total = fade_rem;
1068 fade_rem = crossfade_mix_fade(factor, fade_rem, buf, &crossfade_index,
1069 elapsed, offset);
1070 fade_total -= fade_rem;
1071 size -= fade_total;
1072 buf += fade_total;
1074 if (!size)
1075 return;
1078 /* Fade remaining samples in place */
1079 int samples = fade_rem / 4;
1080 int16_t *input_buf = (int16_t *)buf;
1082 while (samples--)
1084 int32_t left = input_buf[0];
1085 int32_t right = input_buf[1];
1086 *input_buf++ = left * factor >> 8;
1087 *input_buf++ = right * factor >> 8;
1091 if (crossfade_index != INVALID_BUF_INDEX)
1093 /* Mix the data */
1094 size_t mix_total = size;
1096 /* A factor of 256 means mix only, no fading */
1097 size = crossfade_mix_fade(256, size, buf, &crossfade_index,
1098 elapsed, offset);
1099 buf += mix_total - size;
1101 if (!size)
1102 return;
1105 /* Data might remain in the fade buffer yet the fade-in has run its
1106 course - finish it off as normal chunks */
1107 while (size > 0)
1109 size_t copy_n = size;
1110 unsigned char *outbuf = get_write_buffer(&copy_n);
1111 memcpy(outbuf, buf, copy_n);
1112 commit_write_buffer(copy_n, elapsed, offset);
1113 buf += copy_n;
1114 size -= copy_n;
1117 /* if no more fading-in to do, stop the crossfade */
1118 #if 0
1119 /* This way (the previous way) can cause a sudden volume jump if mixable
1120 data is used up before the fade-in completes and that just sounds wrong
1121 -- jethead71 */
1122 if (!crossfade_fade_in_rem || crossfade_index == INVALID_BUF_INDEX)
1123 #endif
1124 /* Let fade-in complete even if not fully overlapping the existing data */
1125 if (!crossfade_fade_in_rem)
1126 crossfade_status = CROSSFADE_INACTIVE;
1129 static void pcmbuf_finish_crossfade_enable(void)
1131 /* Copy the pending setting over now */
1132 crossfade_setting = crossfade_enable_request;
1134 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ?
1135 /* If crossfading, try to keep the buffer full other than 1 second */
1136 (pcmbuf_size - BYTERATE) :
1137 /* Otherwise, just use the default */
1138 PCMBUF_WATERMARK;
1141 bool pcmbuf_is_crossfade_active(void)
1143 return crossfade_status != CROSSFADE_INACTIVE;
1146 void pcmbuf_request_crossfade_enable(int setting)
1148 /* Next setting to be used, not applied now */
1149 crossfade_enable_request = setting;
1152 bool pcmbuf_is_same_size(void)
1154 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */
1155 bool same_size = pcmbuf_buffer ?
1156 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true;
1158 /* no buffer change needed, so finish crossfade setup now */
1159 if (same_size)
1160 pcmbuf_finish_crossfade_enable();
1162 return same_size;
1164 #endif /* HAVE_CROSSFADE */
1167 /** Debug menu, other metrics */
1169 /* Amount of bytes left in the buffer, accounting for uncommitted bytes */
1170 size_t pcmbuf_free(void)
1172 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting;
1175 /* Data bytes allocated for buffer */
1176 size_t pcmbuf_get_bufsize(void)
1178 return pcmbuf_size;
1181 /* Number of committed descriptors */
1182 int pcmbuf_used_descs(void)
1184 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE;
1187 /* Total number of descriptors allocated */
1188 int pcmbuf_descs(void)
1190 return pcmbuf_desc_count;
1194 /** Fading and channel volume control */
1196 /* Sync the channel amplitude to all states */
1197 static void pcmbuf_update_volume(void)
1199 unsigned int vol = fade_vol;
1201 if (soft_mode)
1202 vol >>= 2;
1204 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol);
1207 /* Tick that does the fade for the playback channel */
1208 static void pcmbuf_fade_tick(void)
1210 /* ~1/3 second for full range fade */
1211 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1213 if (fade_state == PCM_FADING_IN)
1214 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1215 else if (fade_state == PCM_FADING_OUT)
1216 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1218 pcmbuf_update_volume();
1220 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1222 /* Fade is complete */
1223 tick_remove_task(pcmbuf_fade_tick);
1224 if (fade_state == PCM_FADING_OUT)
1226 /* Tell PCM to stop at its earliest convenience */
1227 fade_out_complete = true;
1230 fade_state = PCM_NOT_FADING;
1234 /* Fade channel in or out in the background */
1235 void pcmbuf_fade(bool fade, bool in)
1237 /* Must pause any active fade */
1238 pcm_play_lock();
1240 if (fade_state != PCM_NOT_FADING)
1241 tick_remove_task(pcmbuf_fade_tick);
1243 fade_out_complete = false;
1245 pcm_play_unlock();
1247 if (!fade)
1249 /* Simply set the level */
1250 fade_state = PCM_NOT_FADING;
1251 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1252 pcmbuf_update_volume();
1254 else
1256 /* Set direction and resume fade from current point */
1257 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1258 tick_add_task(pcmbuf_fade_tick);
1262 /* Return 'true' if fade is in progress */
1263 bool pcmbuf_fading(void)
1265 return fade_state != PCM_NOT_FADING;
1268 /* Quiet-down the channel if 'shhh' is true or else play at normal level */
1269 void pcmbuf_soft_mode(bool shhh)
1271 /* Have to block the tick or improper order could leave volume in soft
1272 mode if fading reads the old value first but updates after us. */
1273 int res = fade_state != PCM_NOT_FADING ?
1274 tick_remove_task(pcmbuf_fade_tick) : -1;
1276 soft_mode = shhh;
1277 pcmbuf_update_volume();
1279 if (res == 0)
1280 tick_add_task(pcmbuf_fade_tick);
1284 /** Misc */
1286 bool pcmbuf_is_lowdata(void)
1288 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
1290 if (status != CHANNEL_PLAYING || pcmbuf_is_crossfade_active())
1291 return false;
1293 #if MEMORYSIZE > 2
1294 /* 1 seconds of buffer is low data */
1295 return pcmbuf_unplayed_bytes() < DATA_LEVEL(4);
1296 #else
1297 /* under watermark is low data */
1298 return pcmbuf_unplayed_bytes() < pcmbuf_watermark;
1299 #endif
1302 void pcmbuf_set_low_latency(bool state)
1304 low_latency_mode = state;
1307 /* Return the current position key value */
1308 unsigned int pcmbuf_get_position_key(void)
1310 return position_key;
1313 /* Set position updates to be synchronous and immediate in addition to during
1314 PCM frames - cancelled upon first codec insert or upon stopping */
1315 void pcmbuf_sync_position_update(void)
1317 pcmbuf_sync_position = true;