Use server timestamp for development build fonts.
[maemo-rb.git] / apps / pcmbuf.c
blob9754f13bd99c630b2507d0ed9ba66c886e355153
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_core.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 /* Small guard buf to give decent space near end */
51 #define PCMBUF_GUARD_SIZE (PCMBUF_CHUNK_SIZE / 8)
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 PCMBUF_CHUNK_SIZE
61 /* Maximum contiguous space that PCM buffer will allow (to avoid excessive
62 draining between inserts and observe low-latency mode) */
63 #define PCMBUF_MAX_BUFFER (PCMBUF_CHUNK_SIZE * 4)
65 /* Forced buffer insert constraint can thus be from 1KB to 32KB using 8KB
66 chunks */
68 /* Return data level in 1/4-second increments */
69 #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs))
71 /* Number of bytes played per second:
72 (sample rate * 2 channels * 2 bytes/sample) */
73 #define BYTERATE (NATIVE_FREQUENCY * 4)
75 #if MEMORYSIZE > 2
76 /* Keep watermark high for large memory target - at least (2s) */
77 #define PCMBUF_WATERMARK (BYTERATE * 2)
78 #define MIN_BUFFER_SIZE (BYTERATE * 3)
79 /* 1 seconds of buffer is low data */
80 #define LOW_DATA DATA_LEVEL(4)
81 #else
82 #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
83 #define MIN_BUFFER_SIZE (BYTERATE * 1)
84 /* under watermark is low data */
85 #define LOW_DATA pcmbuf_watermark
86 #endif
88 /* Describes each audio packet - keep it small since there are many of them */
89 struct chunkdesc
91 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */
92 uint8_t is_end; /* Flag indicating end of track */
93 uint8_t pos_key; /* Who put the position info in (0 = undefined) */
94 unsigned long elapsed; /* Elapsed time to use */
95 off_t offset; /* Offset to use */
98 /* General PCM buffer data */
99 #define INVALID_BUF_INDEX ((size_t)0 - (size_t)1)
101 static void *pcmbuf_buffer;
102 static void *pcmbuf_guardbuf;
103 static size_t pcmbuf_size;
104 static struct chunkdesc *pcmbuf_descriptors;
105 static unsigned int pcmbuf_desc_count;
106 static unsigned int position_key = 1;
108 static size_t chunk_ridx;
109 static size_t chunk_widx;
111 static size_t pcmbuf_bytes_waiting;
112 static struct chunkdesc *current_desc;
114 /* Only written if HAVE_CROSSFADE */
115 static size_t pcmbuf_watermark = PCMBUF_WATERMARK;
117 static bool low_latency_mode = false;
119 static bool pcmbuf_sync_position = false;
121 /* Fade effect */
122 static unsigned int fade_vol = MIX_AMP_UNITY;
123 static enum
125 PCM_NOT_FADING = 0,
126 PCM_FADING_IN,
127 PCM_FADING_OUT,
128 } fade_state = PCM_NOT_FADING;
129 static bool fade_out_complete = false;
131 /* Voice */
132 static bool soft_mode = false;
134 #ifdef HAVE_CROSSFADE
135 /* Crossfade buffer */
136 static void *crossfade_buffer;
138 /* Crossfade related state */
139 static int crossfade_setting;
140 static int crossfade_enable_request;
141 static bool crossfade_mixmode;
142 static bool crossfade_auto_skip;
144 static enum
146 CROSSFADE_INACTIVE = 0,
147 CROSSFADE_TRACK_CHANGE_STARTED,
148 CROSSFADE_ACTIVE,
149 } crossfade_status = CROSSFADE_INACTIVE;
151 /* Track the current location for processing crossfade */
152 static size_t crossfade_index;
154 /* Counters for fading in new data */
155 static size_t crossfade_fade_in_total;
156 static size_t crossfade_fade_in_rem;
158 /* Defines for operations on position info when mixing/fading -
159 passed in offset parameter */
160 enum
162 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */
163 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */
164 /* Positive values cause stamping/restamping */
167 static void crossfade_start(void);
168 static void write_to_crossfade(size_t size, unsigned long elapsed,
169 off_t offset);
170 static void pcmbuf_finish_crossfade_enable(void);
171 #endif /* HAVE_CROSSFADE */
173 /* Thread */
174 #ifdef HAVE_PRIORITY_SCHEDULING
175 static int codec_thread_priority = PRIORITY_PLAYBACK;
176 #endif
178 /* Callbacks into playback.c */
179 extern void audio_pcmbuf_position_callback(unsigned long elapsed,
180 off_t offset, unsigned int key);
181 extern void audio_pcmbuf_track_change(bool pcmbuf);
182 extern bool audio_pcmbuf_may_play(void);
183 extern void audio_pcmbuf_sync_position(void);
186 /**************************************/
188 /* Return number of commited bytes in buffer (committed chunks count as
189 a full chunk even if only partially filled) */
190 static size_t pcmbuf_unplayed_bytes(void)
192 size_t ridx = chunk_ridx;
193 size_t widx = chunk_widx;
195 if (ridx > widx)
196 widx += pcmbuf_size;
198 return widx - ridx;
201 /* Returns TRUE if amount of data is under the target fill size */
202 static bool pcmbuf_data_critical(void)
204 return pcmbuf_unplayed_bytes() < LOW_DATA;
207 /* Return the next PCM chunk in the PCM buffer given a byte index into it */
208 static size_t index_next(size_t index)
210 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE);
212 if (index >= pcmbuf_size)
213 index -= pcmbuf_size;
215 return index;
218 /* Convert a byte offset in the PCM buffer into a pointer in the buffer */
219 static FORCE_INLINE void * index_buffer(size_t index)
221 return pcmbuf_buffer + index;
224 /* Convert a pointer in the buffer into an index offset */
225 static FORCE_INLINE size_t buffer_index(void *p)
227 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer;
230 /* Return a chunk descriptor for a byte index in the buffer */
231 static struct chunkdesc * index_chunkdesc(size_t index)
233 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE];
236 /* Return a chunk descriptor for a byte index in the buffer, offset by 'offset'
237 chunks */
238 static struct chunkdesc * index_chunkdesc_offs(size_t index, int offset)
240 int i = index / PCMBUF_CHUNK_SIZE;
242 if (offset != 0)
244 i = (i + offset) % pcmbuf_desc_count;
246 /* remainder => modulus */
247 if (i < 0)
248 i += pcmbuf_desc_count;
251 return &pcmbuf_descriptors[i];
255 /** Accept new PCM data */
257 /* Split the uncommitted data as needed into chunks, stopping when uncommitted
258 data is below the threshold */
259 static void commit_chunks(size_t threshold)
261 size_t index = chunk_widx;
262 size_t end_index = index + pcmbuf_bytes_waiting;
264 /* Copy to the beginning of the buffer all data that must wrap */
265 if (end_index > pcmbuf_size)
266 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size);
268 struct chunkdesc *desc = index_chunkdesc(index);
272 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE);
273 pcmbuf_bytes_waiting -= size;
275 /* Fill in the values in the new buffer chunk */
276 desc->size = (uint16_t)size;
278 /* Advance the current write chunk and make it available to the
279 PCM callback */
280 chunk_widx = index = index_next(index);
281 desc = index_chunkdesc(index);
283 /* Reset it before using it */
284 desc->is_end = 0;
285 desc->pos_key = 0;
287 while (pcmbuf_bytes_waiting >= threshold);
290 /* If uncommitted data count is above or equal to the threshold, commit it */
291 static FORCE_INLINE void commit_if_needed(size_t threshold)
293 if (pcmbuf_bytes_waiting >= threshold)
294 commit_chunks(threshold);
297 /* Place positioning information in the chunk */
298 static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed,
299 off_t offset)
301 /* One-time stamping of a given chunk by the same track - new track may
302 overwrite */
303 unsigned int key = position_key;
305 if (desc->pos_key != key)
307 desc->pos_key = key;
308 desc->elapsed = elapsed;
309 desc->offset = offset;
313 /* Set priority of the codec thread */
314 #ifdef HAVE_PRIORITY_SCHEDULING
316 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */
317 static void boost_codec_thread(int pcm_fill_state)
319 static const int8_t prios[11] =
321 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */
322 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */
323 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */
324 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */
325 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */
326 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */
327 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */
328 /* raising priority above 70% shouldn't be needed */
329 PRIORITY_PLAYBACK, /* 70 - 80% */
330 PRIORITY_PLAYBACK, /* 80 - 90% */
331 PRIORITY_PLAYBACK, /* 90 -100% */
332 PRIORITY_PLAYBACK, /* 100% */
335 int new_prio = prios[pcm_fill_state];
337 /* Keep voice and codec threads at the same priority or else voice
338 * will starve if the codec thread's priority is boosted. */
339 if (new_prio != codec_thread_priority)
341 codec_thread_set_priority(new_prio);
342 voice_thread_set_priority(new_prio);
343 codec_thread_priority = new_prio;
346 #else
347 #define boost_codec_thread(pcm_fill_state) do{}while(0)
348 #endif /* HAVE_PRIORITY_SCHEDULING */
350 /* Get the next available buffer and size - assumes adequate space exists */
351 static void * get_write_buffer(size_t *size)
353 /* Obtain current chunk fill address */
354 size_t index = chunk_widx + pcmbuf_bytes_waiting;
355 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE;
357 /* Get count to the end of the buffer where a wrap will happen +
358 the guard */
359 size_t endsize = index_end - index;
361 /* Return available unwrapped space */
362 *size = MIN(*size, endsize);
364 return index_buffer(index);
367 /* Commit outstanding data leaving less than a chunk size remaining and
368 write position info to the first chunk */
369 static void commit_write_buffer(size_t size, unsigned long elapsed, off_t offset)
371 struct chunkdesc *desc = index_chunkdesc(chunk_widx);
372 stamp_chunk(desc, elapsed, offset);
374 /* Add this data and commit if one or more chunks are ready */
375 pcmbuf_bytes_waiting += size;
377 commit_if_needed(COMMIT_CHUNKS);
380 /* Request space in the buffer for writing output samples */
381 void * pcmbuf_request_buffer(int *count)
383 size_t size = *count * 4;
385 #ifdef HAVE_CROSSFADE
386 /* We're going to crossfade to a new track, which is now on its way */
387 if (crossfade_status == CROSSFADE_TRACK_CHANGE_STARTED)
388 crossfade_start();
390 /* If crossfade has begun, put the new track samples in crossfade_buffer */
391 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE)
392 size = CROSSFADE_BUFSIZE;
393 else
394 #endif /* HAVE_CROSSFADE */
396 if (size > PCMBUF_MAX_BUFFER)
397 size = PCMBUF_MAX_BUFFER; /* constrain */
399 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
400 size_t remaining = pcmbuf_unplayed_bytes();
402 /* Need to have length bytes to prevent wrapping overwriting - leave one
403 descriptor free to guard so that 0 != full in ring buffer */
404 size_t freespace = pcmbuf_free();
406 if (pcmbuf_sync_position)
407 audio_pcmbuf_sync_position();
409 if (freespace < size + PCMBUF_CHUNK_SIZE)
410 return NULL;
412 /* Maintain the buffer level above the watermark */
413 if (status != CHANNEL_STOPPED)
415 if (low_latency_mode)
417 /* 1/4s latency. */
418 if (remaining > DATA_LEVEL(1))
419 return NULL;
422 /* Boost CPU if necessary */
423 size_t realrem = pcmbuf_size - freespace;
425 if (realrem < pcmbuf_watermark)
426 trigger_cpu_boost();
428 boost_codec_thread(realrem*10 / pcmbuf_size);
430 #ifdef HAVE_CROSSFADE
431 /* Disable crossfade if < .5s of audio */
432 if (remaining < DATA_LEVEL(2))
433 crossfade_status = CROSSFADE_INACTIVE;
434 #endif
436 else /* !playing */
438 /* Boost CPU for pre-buffer */
439 trigger_cpu_boost();
441 /* If pre-buffered to the watermark, start playback */
442 if (!pcmbuf_data_critical() && audio_pcmbuf_may_play())
443 pcmbuf_play_start();
446 void *buf;
448 #ifdef HAVE_CROSSFADE
449 if (crossfade_status != CROSSFADE_INACTIVE)
451 buf = crossfade_buffer; /* always CROSSFADE_BUFSIZE */
453 else
454 #endif
456 /* Give the maximum amount available if there's more */
457 if (size + PCMBUF_CHUNK_SIZE < freespace)
458 size = freespace - PCMBUF_CHUNK_SIZE;
460 buf = get_write_buffer(&size);
463 *count = size / 4;
464 return buf;
467 /* Handle new samples to the buffer */
468 void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset)
470 size_t size = count * 4;
472 #ifdef HAVE_CROSSFADE
473 if (crossfade_status != CROSSFADE_INACTIVE)
475 write_to_crossfade(size, elapsed, offset);
477 else
478 #endif
480 commit_write_buffer(size, elapsed, offset);
483 /* Revert to position updates by PCM */
484 pcmbuf_sync_position = false;
488 /** Init */
489 static unsigned int get_next_required_pcmbuf_chunks(void)
491 size_t size = MIN_BUFFER_SIZE;
493 #ifdef HAVE_CROSSFADE
494 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
496 size_t seconds = global_settings.crossfade_fade_out_delay +
497 global_settings.crossfade_fade_out_duration;
498 size += seconds * BYTERATE;
500 #endif
502 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE));
503 return size / PCMBUF_CHUNK_SIZE;
506 /* Initialize the ringbuffer state */
507 static void init_buffer_state(void)
509 /* Reset counters */
510 chunk_ridx = chunk_widx = 0;
511 pcmbuf_bytes_waiting = 0;
513 /* Reset first descriptor */
514 struct chunkdesc *desc = pcmbuf_descriptors;
515 desc->is_end = 0;
516 desc->pos_key = 0;
519 /* Initialize the PCM buffer. The structure looks like this:
520 * ...[|FADEBUF]|---------PCMBUF---------|GUARDBUF|DESCS| */
521 size_t pcmbuf_init(void *bufend)
523 void *bufstart;
525 /* Set up the buffers */
526 pcmbuf_desc_count = get_next_required_pcmbuf_chunks();
527 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE;
528 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count;
530 pcmbuf_buffer = (void *)pcmbuf_descriptors -
531 pcmbuf_size - PCMBUF_GUARD_SIZE;
533 /* Mem-align buffer chunks for more efficient handling in lower layers */
534 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE);
536 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size;
537 bufstart = pcmbuf_buffer;
539 #ifdef HAVE_CROSSFADE
540 /* Allocate FADEBUF if it will be needed */
541 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF)
543 bufstart -= CROSSFADE_BUFSIZE;
544 crossfade_buffer = bufstart;
547 pcmbuf_finish_crossfade_enable();
548 #endif /* HAVE_CROSSFADE */
550 init_buffer_state();
552 pcmbuf_soft_mode(false);
554 return bufend - bufstart;
558 /** Track change */
560 /* Place a track change notification in a specific descriptor or post it
561 immediately if the buffer is empty or the index is invalid */
562 static void pcmbuf_monitor_track_change_ex(size_t index, int offset)
564 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX)
566 /* If monitoring, set flag in specified chunk */
567 index_chunkdesc_offs(index, offset)->is_end = 1;
569 else
571 /* Post now if no outstanding buffers exist */
572 audio_pcmbuf_track_change(false);
576 /* Clear end of track and optionally the positioning info for all data */
577 static void pcmbuf_cancel_track_change(bool position)
579 size_t index = chunk_ridx;
581 while (1)
583 struct chunkdesc *desc = index_chunkdesc(index);
585 desc->is_end = 0;
587 if (position)
588 desc->pos_key = 0;
590 if (index == chunk_widx)
591 break;
593 index = index_next(index);
597 /* Place a track change notification at the end of the buffer or post it
598 immediately if the buffer is empty */
599 void pcmbuf_monitor_track_change(bool monitor)
601 pcm_play_lock();
603 if (monitor)
604 pcmbuf_monitor_track_change_ex(chunk_widx, -1);
605 else
606 pcmbuf_cancel_track_change(false);
608 pcm_play_unlock();
611 void pcmbuf_start_track_change(enum pcm_track_change_type type)
613 #ifdef HAVE_CROSSFADE
614 bool crossfade = false;
615 #endif
616 bool auto_skip = type != TRACK_CHANGE_MANUAL;
618 /* Commit all outstanding data before starting next track - tracks don't
619 comingle inside a single buffer chunk */
620 commit_if_needed(COMMIT_ALL_DATA);
622 /* Update position key so that:
623 1) Positions are keyed to the track to which they belong for sync
624 purposes
626 2) Buffers stamped with the outgoing track's positions are restamped
627 to the incoming track's positions when crossfading
629 if (++position_key > UINT8_MAX)
630 position_key = 1;
632 if (type == TRACK_CHANGE_END_OF_DATA)
634 /* If end of all data, force playback */
635 if (audio_pcmbuf_may_play())
636 pcmbuf_play_start();
638 #ifdef HAVE_CROSSFADE
639 /* Determine whether this track change needs to crossfaded and how */
640 else if (crossfade_setting != CROSSFADE_ENABLE_OFF &&
641 !pcmbuf_is_crossfade_active() &&
642 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) &&
643 !low_latency_mode)
645 switch (crossfade_setting)
647 case CROSSFADE_ENABLE_AUTOSKIP:
648 crossfade = auto_skip;
649 break;
650 case CROSSFADE_ENABLE_MANSKIP:
651 crossfade = !auto_skip;
652 break;
653 case CROSSFADE_ENABLE_SHUFFLE:
654 crossfade = global_settings.playlist_shuffle;
655 break;
656 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP:
657 crossfade = global_settings.playlist_shuffle || !auto_skip;
658 break;
659 case CROSSFADE_ENABLE_ALWAYS:
660 crossfade = true;
661 break;
664 /* else crossfade is off, crossfade is already active, not enough data,
665 * pcm is off now (implying low data), not crossfading or low latency mode
668 if (crossfade)
670 logf("crossfade track change");
672 /* Don't enable mix mode when skipping tracks manually */
673 crossfade_mixmode = auto_skip &&
674 global_settings.crossfade_fade_out_mixmode;
676 crossfade_auto_skip = auto_skip;
678 crossfade_status = CROSSFADE_TRACK_CHANGE_STARTED;
680 trigger_cpu_boost();
682 /* Cancel any pending automatic gapless transition and if a manual
683 skip, stop position updates */
684 pcm_play_lock();
685 pcmbuf_cancel_track_change(!auto_skip);
686 pcm_play_unlock();
688 else
689 #endif /* HAVE_CROSSFADE */
690 if (auto_skip)
692 /* The codec is moving on to the next track, but the current track will
693 * continue to play, so mark the last write chunk as the last one in
694 * the track */
695 logf("gapless track change");
696 #ifdef HAVE_CROSSFADE
697 if (crossfade_status != CROSSFADE_INACTIVE)
699 /* Crossfade is still active but crossfade is not happening - for
700 * now, chicken-out and clear out the buffer (just like before) to
701 * avoid fade pile-up on short tracks fading-in over long ones */
702 pcmbuf_play_stop();
704 #endif
705 pcmbuf_monitor_track_change(true);
707 else
709 /* Discard old data; caller needs no transition notification */
710 logf("manual track change");
711 pcmbuf_play_stop();
716 /** Playback */
718 /* PCM driver callback */
719 static void pcmbuf_pcm_callback(const void **start, size_t *size)
721 /*- Process the chunk that just finished -*/
722 size_t index = chunk_ridx;
723 struct chunkdesc *desc = current_desc;
725 if (desc)
727 /* If last chunk in the track, notify of track change */
728 if (desc->is_end != 0)
729 audio_pcmbuf_track_change(true);
731 /* Free it for reuse */
732 chunk_ridx = index = index_next(index);
735 /*- Process the new one -*/
736 if (index != chunk_widx && !fade_out_complete)
738 current_desc = desc = index_chunkdesc(index);
740 *start = index_buffer(index);
741 *size = desc->size;
743 if (desc->pos_key != 0)
745 /* Positioning chunk - notify playback */
746 audio_pcmbuf_position_callback(desc->elapsed, desc->offset,
747 desc->pos_key);
752 /* Force playback */
753 void pcmbuf_play_start(void)
755 logf("pcmbuf_play_start");
757 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED &&
758 chunk_widx != chunk_ridx)
760 current_desc = NULL;
761 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
762 NULL, 0);
766 /* Stop channel, empty and reset buffer */
767 void pcmbuf_play_stop(void)
769 logf("pcmbuf_play_stop");
771 /* Reset channel */
772 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
774 /* Reset buffer */
775 init_buffer_state();
777 /* Revert to position updates by PCM */
778 pcmbuf_sync_position = false;
780 #ifdef HAVE_CROSSFADE
781 crossfade_status = CROSSFADE_INACTIVE;
782 #endif
784 /* Can unboost the codec thread here no matter who's calling,
785 * pretend full pcm buffer to unboost */
786 boost_codec_thread(10);
789 void pcmbuf_pause(bool pause)
791 logf("pcmbuf_pause: %s", pause?"pause":"play");
793 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED)
794 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
795 else if (!pause)
796 pcmbuf_play_start();
800 /** Crossfade */
802 #ifdef HAVE_CROSSFADE
803 /* Find the buffer index that's 'size' bytes away from 'index' */
804 static size_t crossfade_find_index(size_t index, size_t size)
806 if (index != INVALID_BUF_INDEX)
808 size_t i = ALIGN_DOWN(index, PCMBUF_CHUNK_SIZE);
809 size += index - i;
811 while (i != chunk_widx)
813 size_t desc_size = index_chunkdesc(i)->size;
815 if (size < desc_size)
816 return i + size;
818 size -= desc_size;
819 i = index_next(i);
823 return INVALID_BUF_INDEX;
826 /* Align the needed buffer area up to the end of existing data */
827 static size_t crossfade_find_buftail(size_t buffer_rem, size_t buffer_need)
829 crossfade_index = chunk_ridx;
831 if (buffer_rem > buffer_need)
833 size_t distance;
835 if (crossfade_auto_skip)
837 /* Automatic track changes only modify the last part of the buffer,
838 * so find the right chunk and sample to start the crossfade */
839 distance = buffer_rem - buffer_need;
840 buffer_rem = buffer_need;
842 else
844 /* Manual skips occur immediately, but give 1/5s to process */
845 distance = BYTERATE / 5;
846 buffer_rem -= BYTERATE / 5;
849 crossfade_index = crossfade_find_index(crossfade_index, distance);
852 return buffer_rem;
855 /* Returns the number of bytes _NOT_ mixed/faded */
856 static size_t crossfade_mix_fade(int factor, size_t size, void *buf,
857 size_t *out_index, unsigned long elapsed,
858 off_t offset)
860 if (size == 0)
861 return 0;
863 size_t index = *out_index;
865 if (index == INVALID_BUF_INDEX)
866 return size;
868 const int16_t *input_buf = buf;
869 int16_t *output_buf = index_buffer(index);
871 while (size)
873 struct chunkdesc *desc = index_chunkdesc(index);
875 switch (offset)
877 case MIXFADE_NULLIFY_POS:
878 /* Stop position updates for the chunk */
879 desc->pos_key = 0;
880 break;
881 case MIXFADE_KEEP_POS:
882 /* Keep position info as it is */
883 break;
884 default:
885 /* Replace position info */
886 stamp_chunk(desc, elapsed, offset);
889 size_t rem = desc->size - (index % PCMBUF_CHUNK_SIZE);
890 int16_t *chunk_end = SKIPBYTES(output_buf, rem);
892 if (size < rem)
893 rem = size;
895 size -= rem;
899 /* fade left and right channel at once to keep buffer alignment */
900 int32_t left = output_buf[0];
901 int32_t right = output_buf[1];
903 if (input_buf)
905 /* fade the input buffer and mix into the chunk */
906 left += *input_buf++ * factor >> 8;
907 right += *input_buf++ * factor >> 8;
908 left = clip_sample_16(left);
909 right = clip_sample_16(right);
911 else
913 /* fade the chunk only */
914 left = left * factor >> 8;
915 right = right * factor >> 8;
918 *output_buf++ = left;
919 *output_buf++ = right;
921 rem -= 4;
923 while (rem);
925 /* move to next chunk as needed */
926 if (output_buf >= chunk_end)
928 index = index_next(index);
930 if (index == chunk_widx)
932 /* End of existing data */
933 *out_index = INVALID_BUF_INDEX;
934 return size;
937 output_buf = index_buffer(index);
941 *out_index = buffer_index(output_buf);
942 return 0;
945 /* Initializes crossfader, calculates all necessary parameters and performs
946 * fade-out with the PCM buffer. */
947 static void crossfade_start(void)
949 logf("crossfade_start");
951 pcm_play_lock();
953 /* Initialize the crossfade buffer size to all of the buffered data that
954 * has not yet been sent to the DMA */
955 size_t unplayed = pcmbuf_unplayed_bytes();
957 /* Reject crossfade if less than .5s of data */
958 if (unplayed < DATA_LEVEL(2))
960 logf("crossfade rejected");
962 crossfade_status = CROSSFADE_INACTIVE;
964 if (crossfade_auto_skip)
965 pcmbuf_monitor_track_change(true);
967 pcm_play_unlock();
968 return;
971 /* Fading will happen */
972 crossfade_status = CROSSFADE_ACTIVE;
974 /* Get fade info from settings. */
975 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE;
976 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE;
977 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE;
978 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE;
980 if (!crossfade_auto_skip)
982 /* Forego fade-in delay on manual skip - do the best to preserve auto skip
983 relationship */
984 if (fade_out_delay > fade_in_delay)
985 fade_out_delay -= fade_in_delay;
986 else
987 fade_out_delay = 0;
989 fade_in_delay = 0;
992 size_t fade_out_need = fade_out_delay + fade_out_rem;
994 if (!crossfade_mixmode)
996 size_t buffer_rem = crossfade_find_buftail(unplayed, fade_out_need);
998 pcm_play_unlock();
1000 if (buffer_rem < fade_out_need)
1002 /* Existing buffers are short */
1003 size_t fade_out_short = fade_out_need - buffer_rem;
1005 if (fade_out_rem >= fade_out_short)
1007 /* Truncate fade-out duration */
1008 fade_out_rem -= fade_out_short;
1010 else
1012 /* Truncate fade-out and fade-out delay */
1013 fade_out_delay = fade_out_rem;
1014 fade_out_rem = 0;
1018 /* Completely process the crossfade fade-out effect with current PCM buffer */
1020 /* Fade out the specified amount of the already processed audio */
1021 size_t fade_out_total = fade_out_rem;
1023 /* Find the right chunk and sample to start fading out */
1024 size_t fade_out_index = crossfade_find_index(crossfade_index, fade_out_delay);
1026 while (fade_out_rem > 0)
1028 /* Each 1/20 second of audio will have the same fade applied */
1029 size_t block_rem = MIN(BYTERATE / 20, fade_out_rem);
1030 int factor = (fade_out_rem << 8) / fade_out_total;
1032 fade_out_rem -= block_rem;
1034 crossfade_mix_fade(factor, block_rem, NULL, &fade_out_index,
1035 0, MIXFADE_KEEP_POS);
1038 /* zero out the rest of the buffer */
1039 crossfade_mix_fade(0, pcmbuf_size, NULL, &fade_out_index,
1040 0, MIXFADE_NULLIFY_POS);
1042 pcm_play_lock();
1045 /* Initialize fade-in counters */
1046 crossfade_fade_in_total = fade_in_duration;
1047 crossfade_fade_in_rem = fade_in_duration;
1049 /* Find the right chunk and sample to start fading in - redo from read
1050 chunk in case original position were/was overrun in callback - the
1051 track change event _must not_ ever fail to happen */
1052 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay;
1054 crossfade_find_buftail(unplayed, fade_out_need);
1056 if (crossfade_auto_skip)
1057 pcmbuf_monitor_track_change_ex(crossfade_index, 0);
1059 pcm_play_unlock();
1061 logf("crossfade_start done!");
1064 /* Perform fade-in of new track */
1065 static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset)
1067 void *buf = crossfade_buffer;
1069 if (crossfade_fade_in_rem)
1071 /* Fade factor for this packet */
1072 int factor =
1073 ((crossfade_fade_in_total - crossfade_fade_in_rem) << 8) /
1074 crossfade_fade_in_total;
1075 /* Bytes to fade */
1076 size_t fade_rem = MIN(size, crossfade_fade_in_rem);
1078 /* We _will_ fade this many bytes */
1079 crossfade_fade_in_rem -= fade_rem;
1081 if (crossfade_index != INVALID_BUF_INDEX)
1083 /* Mix the data */
1084 size_t fade_total = fade_rem;
1085 fade_rem = crossfade_mix_fade(factor, fade_rem, buf, &crossfade_index,
1086 elapsed, offset);
1087 fade_total -= fade_rem;
1088 size -= fade_total;
1089 buf += fade_total;
1091 if (!size)
1092 return;
1095 /* Fade remaining samples in place */
1096 int samples = fade_rem / 4;
1097 int16_t *input_buf = buf;
1099 while (samples--)
1101 int32_t left = input_buf[0];
1102 int32_t right = input_buf[1];
1103 *input_buf++ = left * factor >> 8;
1104 *input_buf++ = right * factor >> 8;
1108 if (crossfade_index != INVALID_BUF_INDEX)
1110 /* Mix the data */
1111 size_t mix_total = size;
1113 /* A factor of 256 means mix only, no fading */
1114 size = crossfade_mix_fade(256, size, buf, &crossfade_index,
1115 elapsed, offset);
1116 buf += mix_total - size;
1118 if (!size)
1119 return;
1122 /* Data might remain in the fade buffer yet the fade-in has run its
1123 course - finish it off as normal chunks */
1124 while (size > 0)
1126 size_t copy_n = size;
1127 void *outbuf = get_write_buffer(&copy_n);
1128 memcpy(outbuf, buf, copy_n);
1129 commit_write_buffer(copy_n, elapsed, offset);
1130 buf += copy_n;
1131 size -= copy_n;
1134 /* if no more fading-in to do, stop the crossfade */
1135 #if 0
1136 /* This way (the previous way) can cause a sudden volume jump if mixable
1137 data is used up before the fade-in completes and that just sounds wrong
1138 -- jethead71 */
1139 if (!crossfade_fade_in_rem || crossfade_index == INVALID_BUF_INDEX)
1140 #endif
1141 /* Let fade-in complete even if not fully overlapping the existing data */
1142 if (!crossfade_fade_in_rem)
1143 crossfade_status = CROSSFADE_INACTIVE;
1146 static void pcmbuf_finish_crossfade_enable(void)
1148 /* Copy the pending setting over now */
1149 crossfade_setting = crossfade_enable_request;
1151 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ?
1152 /* If crossfading, try to keep the buffer full other than 1 second */
1153 (pcmbuf_size - BYTERATE) :
1154 /* Otherwise, just use the default */
1155 PCMBUF_WATERMARK;
1158 bool pcmbuf_is_crossfade_active(void)
1160 return crossfade_status != CROSSFADE_INACTIVE;
1163 void pcmbuf_request_crossfade_enable(int setting)
1165 /* Next setting to be used, not applied now */
1166 crossfade_enable_request = setting;
1169 bool pcmbuf_is_same_size(void)
1171 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */
1172 bool same_size = pcmbuf_buffer ?
1173 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true;
1175 /* no buffer change needed, so finish crossfade setup now */
1176 if (same_size)
1177 pcmbuf_finish_crossfade_enable();
1179 return same_size;
1181 #endif /* HAVE_CROSSFADE */
1184 /** Debug menu, other metrics */
1186 /* Amount of bytes left in the buffer, accounting for uncommitted bytes */
1187 size_t pcmbuf_free(void)
1189 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting;
1192 /* Data bytes allocated for buffer */
1193 size_t pcmbuf_get_bufsize(void)
1195 return pcmbuf_size;
1198 /* Number of committed descriptors */
1199 int pcmbuf_used_descs(void)
1201 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE;
1204 /* Total number of descriptors allocated */
1205 int pcmbuf_descs(void)
1207 return pcmbuf_desc_count;
1211 /** Fading and channel volume control */
1213 /* Sync the channel amplitude to all states */
1214 static void pcmbuf_update_volume(void)
1216 unsigned int vol = fade_vol;
1218 if (soft_mode)
1219 vol >>= 2;
1221 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol);
1224 /* Tick that does the fade for the playback channel */
1225 static void pcmbuf_fade_tick(void)
1227 /* ~1/3 second for full range fade */
1228 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1230 if (fade_state == PCM_FADING_IN)
1231 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1232 else if (fade_state == PCM_FADING_OUT)
1233 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1235 pcmbuf_update_volume();
1237 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1239 /* Fade is complete */
1240 tick_remove_task(pcmbuf_fade_tick);
1241 if (fade_state == PCM_FADING_OUT)
1243 /* Tell PCM to stop at its earliest convenience */
1244 fade_out_complete = true;
1247 fade_state = PCM_NOT_FADING;
1251 /* Fade channel in or out in the background */
1252 void pcmbuf_fade(bool fade, bool in)
1254 /* Must pause any active fade */
1255 pcm_play_lock();
1257 if (fade_state != PCM_NOT_FADING)
1258 tick_remove_task(pcmbuf_fade_tick);
1260 fade_out_complete = false;
1262 pcm_play_unlock();
1264 if (!fade)
1266 /* Simply set the level */
1267 fade_state = PCM_NOT_FADING;
1268 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1269 pcmbuf_update_volume();
1271 else
1273 /* Set direction and resume fade from current point */
1274 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1275 tick_add_task(pcmbuf_fade_tick);
1279 /* Return 'true' if fade is in progress */
1280 bool pcmbuf_fading(void)
1282 return fade_state != PCM_NOT_FADING;
1285 /* Quiet-down the channel if 'shhh' is true or else play at normal level */
1286 void pcmbuf_soft_mode(bool shhh)
1288 /* Have to block the tick or improper order could leave volume in soft
1289 mode if fading reads the old value first but updates after us. */
1290 int res = fade_state != PCM_NOT_FADING ?
1291 tick_remove_task(pcmbuf_fade_tick) : -1;
1293 soft_mode = shhh;
1294 pcmbuf_update_volume();
1296 if (res == 0)
1297 tick_add_task(pcmbuf_fade_tick);
1301 /** Time and position */
1303 /* Return the current position key value */
1304 unsigned int pcmbuf_get_position_key(void)
1306 return position_key;
1309 /* Set position updates to be synchronous and immediate in addition to during
1310 PCM frames - cancelled upon first codec insert or upon stopping */
1311 void pcmbuf_sync_position_update(void)
1313 pcmbuf_sync_position = true;
1318 /** Misc */
1320 bool pcmbuf_is_lowdata(void)
1322 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK);
1324 if (status != CHANNEL_PLAYING || pcmbuf_is_crossfade_active())
1325 return false;
1327 return pcmbuf_data_critical();
1330 void pcmbuf_set_low_latency(bool state)
1332 low_latency_mode = state;