blob: ceba31962e834951c75e7662101e54a4ddb12f9d [file] [log] [blame]
Michael Sevakisa2b67032011-06-29 06:37:04 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "general.h"
24#include "kernel.h"
25#include "pcm.h"
Michael Sevakis22b6def2011-07-02 11:55:38 +000026#include "pcm-internal.h"
Michael Sevakisa2b67032011-06-29 06:37:04 +000027#include "pcm_mixer.h"
Michael Sevakisa2b67032011-06-29 06:37:04 +000028
29/* Channels use standard-style PCM callback interface but a latency of one
30 frame by double-buffering is introduced in order to facilitate mixing and
31 keep the hardware fed. There must be sufficient time to perform operations
32 before the last samples are sent to the codec and so things are done in
33 parallel (as much as possible) with sending-out data. */
34
Michael Sevakisd37bf242013-05-23 13:58:51 -040035static unsigned int mixer_sampr = HW_SAMPR_DEFAULT;
36
Michael Sevakisa2b67032011-06-29 06:37:04 +000037/* Define this to nonzero to add a marker pulse at each frame start */
38#define FRAME_BOUNDARY_MARKERS 0
39
40/* Descriptor for each channel */
41struct mixer_channel
42{
Michael Sevakis286a4c52012-02-23 08:14:46 -050043 const void *start; /* Buffer pointer */
Michael Sevakisa2b67032011-06-29 06:37:04 +000044 size_t size; /* Bytes remaining */
45 size_t last_size; /* Size of consumed data in prev. cycle */
46 pcm_play_callback_type get_more; /* Registered callback */
47 enum channel_status status; /* Playback status */
48 uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050049 chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */
Michael Sevakisa2b67032011-06-29 06:37:04 +000050};
51
52/* Forget about boost here for the moment */
53#define MIX_FRAME_SIZE (MIX_FRAME_SAMPLES*4)
54
55/* Because of the double-buffering, playback is always from here, otherwise a
56 mechanism for the channel callbacks not to free buffers too early would be
57 needed (if we _really_ want it and it's worth it, we _can_ do that ;-) ) */
58static uint32_t downmix_buf[2][MIX_FRAME_SAMPLES] DOWNMIX_BUF_IBSS MEM_ALIGN_ATTR;
59static int downmix_index = 0; /* Which downmix_buf? */
60static size_t next_size = 0; /* Size of buffer to play next time */
61
62/* Descriptors for all available channels */
63static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR;
64
65/* Packed pointer array of all playing (active) channels in "channels" array */
66static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
67
68/* Number of silence frames to play after all data has played */
Michael Sevakisd37bf242013-05-23 13:58:51 -040069#define MAX_IDLE_FRAMES (mixer_sampr*3 / MIX_FRAME_SAMPLES)
Michael Sevakisa2b67032011-06-29 06:37:04 +000070static unsigned int idle_counter = 0;
71
Thomas Martitz3c17f282012-01-06 06:26:48 +010072/** Mixing routines, CPU optmized **/
73#include "asm/pcm-mixer.c"
Michael Sevakisa2b67032011-06-29 06:37:04 +000074
75/** Private generic routines **/
76
77/* Mark channel active to mix its data */
78static void mixer_activate_channel(struct mixer_channel *chan)
79{
80 void **elem = find_array_ptr((void **)active_channels, chan);
81
82 if (!*elem)
83 {
84 idle_counter = 0;
85 *elem = chan;
86 }
87}
88
89/* Stop channel from mixing */
90static void mixer_deactivate_channel(struct mixer_channel *chan)
91{
92 remove_array_ptr((void **)active_channels, chan);
93}
94
95/* Deactivate channel and change it to stopped state */
96static void channel_stopped(struct mixer_channel *chan)
97{
98 mixer_deactivate_channel(chan);
99 chan->size = 0;
100 chan->start = NULL;
101 chan->status = CHANNEL_STOPPED;
102}
103
104/* Main PCM callback - sends the current prepared frame to play */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500105static void mixer_pcm_callback(const void **addr, size_t *size)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000106{
Michael Sevakis286a4c52012-02-23 08:14:46 -0500107 *addr = downmix_buf[downmix_index];
Michael Sevakisa2b67032011-06-29 06:37:04 +0000108 *size = next_size;
109}
110
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500111static inline void chan_call_buffer_hook(struct mixer_channel *chan)
112{
113 if (UNLIKELY(chan->buffer_hook))
114 chan->buffer_hook(chan->start, chan->size);
115}
116
Michael Sevakisa2b67032011-06-29 06:37:04 +0000117/* Buffering callback - calls sub-callbacks and mixes the data for next
118 buffer to be sent from mixer_pcm_callback() */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500119static enum pcm_dma_status MIXER_CALLBACK_ICODE
120mixer_buffer_callback(enum pcm_dma_status status)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000121{
Michael Sevakis286a4c52012-02-23 08:14:46 -0500122 if (status != PCM_DMAST_STARTED)
123 return status;
124
Michael Sevakisa2b67032011-06-29 06:37:04 +0000125 downmix_index ^= 1; /* Next buffer */
126
127 void *mixptr = downmix_buf[downmix_index];
128 size_t mixsize = MIX_FRAME_SIZE;
129 struct mixer_channel **chan_p;
130
131 next_size = 0;
132
133 /* "Loop" back here if one round wasn't enough to fill a frame */
134fill_frame:
135 chan_p = active_channels;
136
137 while (*chan_p)
138 {
139 /* Find the active channel with the least data remaining and call any
140 callbacks for channels that ran out - stopping whichever report
141 "no more" */
142 struct mixer_channel *chan = *chan_p;
143 chan->start += chan->last_size;
144 chan->size -= chan->last_size;
145
146 if (chan->size == 0)
147 {
148 if (chan->get_more)
149 {
150 chan->get_more(&chan->start, &chan->size);
Michael Sevakis906905a2011-12-05 13:58:35 +0000151 ALIGN_AUDIOBUF(chan->start, chan->size);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000152 }
153
154 if (!(chan->start && chan->size))
155 {
156 /* Channel is stopping */
157 channel_stopped(chan);
158 continue;
159 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500160
161 chan_call_buffer_hook(chan);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000162 }
163
164 /* Channel will play for at least part of this frame */
165
166 /* Channel with least amount of data remaining determines the downmix
167 size */
168 if (chan->size < mixsize)
169 mixsize = chan->size;
170
171 chan_p++;
172 }
173
174 /* Add all still-active channels to the downmix */
175 chan_p = active_channels;
176
177 if (LIKELY(*chan_p))
178 {
179 struct mixer_channel *chan = *chan_p++;
180
181 if (LIKELY(!*chan_p))
182 {
Michael Sevakis286a4c52012-02-23 08:14:46 -0500183 write_samples(mixptr, chan->start, chan->amplitude, mixsize);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000184 }
185 else
186 {
Michael Sevakis286a4c52012-02-23 08:14:46 -0500187 const void *src0, *src1;
Michael Sevakisa2b67032011-06-29 06:37:04 +0000188 unsigned int amp0, amp1;
189
190 /* Mix first two channels with each other as the downmix */
191 src0 = chan->start;
192 amp0 = chan->amplitude;
193 chan->last_size = mixsize;
194
195 chan = *chan_p++;
196 src1 = chan->start;
197 amp1 = chan->amplitude;
198
199 while (1)
200 {
201 mix_samples(mixptr, src0, amp0, src1, amp1, mixsize);
202
203 if (!*chan_p)
204 break;
205
206 /* More channels to mix - mix each with existing downmix */
207 chan->last_size = mixsize;
208 chan = *chan_p++;
209 src0 = mixptr;
210 amp0 = MIX_AMP_UNITY;
211 src1 = chan->start;
212 amp1 = chan->amplitude;
213 }
214 }
215
216 chan->last_size = mixsize;
217 next_size += mixsize;
218
219 if (next_size < MIX_FRAME_SIZE)
220 {
221 /* There is still space remaining in this frame */
222 mixptr += mixsize;
223 mixsize = MIX_FRAME_SIZE - next_size;
224 goto fill_frame;
225 }
226 }
227 else if (idle_counter++ < MAX_IDLE_FRAMES)
228 {
229 /* Pad incomplete frames with silence */
230 if (idle_counter <= 3)
231 memset(mixptr, 0, MIX_FRAME_SIZE - next_size);
232
233 next_size = MIX_FRAME_SIZE;
234 }
235 /* else silence period ran out - go to sleep */
236
237#if FRAME_BOUNDARY_MARKERS != 0
238 if (next_size)
239 *downmix_buf[downmix_index] = downmix_index ? 0x7fff7fff : 0x80008000;
240#endif
Michael Sevakis286a4c52012-02-23 08:14:46 -0500241
Michael Sevakis64bb7202012-03-09 21:00:49 -0500242 /* Certain SoC's have to do cleanup */
243 mixer_buffer_callback_exit();
244
Michael Sevakis286a4c52012-02-23 08:14:46 -0500245 return PCM_DMAST_OK;
Michael Sevakisa2b67032011-06-29 06:37:04 +0000246}
247
248/* Start PCM driver if it's not currently playing */
249static void mixer_start_pcm(void)
250{
251 if (pcm_is_playing())
252 return;
253
Michael Sevakis22b6def2011-07-02 11:55:38 +0000254#if defined(HAVE_RECORDING)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000255 if (pcm_is_recording())
256 return;
257#endif
258
Michael Sevakis22b6def2011-07-02 11:55:38 +0000259 /* Requires a shared global sample rate for all channels */
Michael Sevakisd37bf242013-05-23 13:58:51 -0400260 pcm_set_frequency(mixer_sampr);
Michael Sevakis22b6def2011-07-02 11:55:38 +0000261
Michael Sevakisa2b67032011-06-29 06:37:04 +0000262 /* Prepare initial frames and set up the double buffer */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500263 mixer_buffer_callback(PCM_DMAST_STARTED);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000264
265 /* Save the previous call's output */
266 void *start = downmix_buf[downmix_index];
267
Michael Sevakis286a4c52012-02-23 08:14:46 -0500268 mixer_buffer_callback(PCM_DMAST_STARTED);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000269
Michael Sevakis286a4c52012-02-23 08:14:46 -0500270 pcm_play_data(mixer_pcm_callback, mixer_buffer_callback,
271 start, MIX_FRAME_SIZE);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000272}
273
Michael Sevakis39eec732012-02-17 03:54:45 -0500274/** Public interfaces **/
275
276/* Start playback on a channel */
277void mixer_channel_play_data(enum pcm_mixer_channel channel,
278 pcm_play_callback_type get_more,
Michael Sevakis286a4c52012-02-23 08:14:46 -0500279 const void *start, size_t size)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000280{
Michael Sevakis39eec732012-02-17 03:54:45 -0500281 struct mixer_channel *chan = &channels[channel];
Michael Sevakisa2b67032011-06-29 06:37:04 +0000282
Michael Sevakis906905a2011-12-05 13:58:35 +0000283 ALIGN_AUDIOBUF(start, size);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000284
Michael Sevakis39eec732012-02-17 03:54:45 -0500285 if (!(start && size) && get_more)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000286 {
287 /* Initial buffer not passed - call the callback now */
Michael Sevakis39eec732012-02-17 03:54:45 -0500288 pcm_play_lock();
Michael Sevakis9a25a6f2012-02-19 00:33:04 -0500289 mixer_deactivate_channel(chan); /* Protect chan struct if active;
290 may also be same callback which
291 must not be reentered */
Michael Sevakis39eec732012-02-17 03:54:45 -0500292 pcm_play_unlock(); /* Allow playback while doing callback */
293
Michael Sevakisa2b67032011-06-29 06:37:04 +0000294 size = 0;
Michael Sevakis39eec732012-02-17 03:54:45 -0500295 get_more(&start, &size);
296 ALIGN_AUDIOBUF(start, size);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000297 }
298
Michael Sevakis39eec732012-02-17 03:54:45 -0500299 pcm_play_lock();
300
Michael Sevakisa2b67032011-06-29 06:37:04 +0000301 if (start && size)
302 {
303 /* We have data - start the channel */
304 chan->status = CHANNEL_PLAYING;
305 chan->start = start;
306 chan->size = size;
307 chan->last_size = 0;
308 chan->get_more = get_more;
309
Michael Sevakisa2b67032011-06-29 06:37:04 +0000310 mixer_activate_channel(chan);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500311 chan_call_buffer_hook(chan);
Michael Sevakisa2b67032011-06-29 06:37:04 +0000312 mixer_start_pcm();
313 }
314 else
315 {
316 /* Never had anything - stop it now */
Michael Sevakisa2b67032011-06-29 06:37:04 +0000317 channel_stopped(chan);
318 }
Michael Sevakisa2b67032011-06-29 06:37:04 +0000319
Michael Sevakisa2b67032011-06-29 06:37:04 +0000320 pcm_play_unlock();
321}
322
323/* Pause or resume a channel (when started) */
324void mixer_channel_play_pause(enum pcm_mixer_channel channel, bool play)
325{
326 struct mixer_channel *chan = &channels[channel];
327
328 pcm_play_lock();
329
330 if (play == (chan->status == CHANNEL_PAUSED) &&
331 chan->status != CHANNEL_STOPPED)
332 {
333 if (play)
334 {
335 chan->status = CHANNEL_PLAYING;
336 mixer_activate_channel(chan);
337 mixer_start_pcm();
338 }
339 else
340 {
341 mixer_deactivate_channel(chan);
342 chan->status = CHANNEL_PAUSED;
343 }
344 }
345
346 pcm_play_unlock();
347}
348
349/* Stop playback on a channel */
350void mixer_channel_stop(enum pcm_mixer_channel channel)
351{
352 struct mixer_channel *chan = &channels[channel];
353
354 pcm_play_lock();
355 channel_stopped(chan);
356 pcm_play_unlock();
357}
358
359/* Set channel's amplitude factor */
360void mixer_channel_set_amplitude(enum pcm_mixer_channel channel,
361 unsigned int amplitude)
362{
363 channels[channel].amplitude = MIN(amplitude, MIX_AMP_UNITY);
364}
365
366/* Return channel's playback status */
367enum channel_status mixer_channel_status(enum pcm_mixer_channel channel)
368{
369 return channels[channel].status;
370}
371
372/* Returns amount data remaining in channel before next callback */
373size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel)
374{
375 return channels[channel].size;
376}
377
378/* Return pointer to channel's playing audio data and the size remaining */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500379const void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
Michael Sevakisa2b67032011-06-29 06:37:04 +0000380{
381 struct mixer_channel *chan = &channels[channel];
Michael Sevakis286a4c52012-02-23 08:14:46 -0500382 const void * buf = *(const void * volatile *)&chan->start;
Michael Sevakisa2b67032011-06-29 06:37:04 +0000383 size_t size = *(size_t volatile *)&chan->size;
Michael Sevakis286a4c52012-02-23 08:14:46 -0500384 const void * buf2 = *(const void * volatile *)&chan->start;
Michael Sevakisa2b67032011-06-29 06:37:04 +0000385
386 /* Still same buffer? */
387 if (buf == buf2)
388 {
389 *count = size >> 2;
390 return buf;
391 }
392 /* else can't be sure buf and size are related */
393
394 *count = 0;
395 return NULL;
396}
397
Michael Sevakis22b6def2011-07-02 11:55:38 +0000398/* Calculate peak values for channel */
399void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
Michael Sevakise189b332012-05-02 20:53:07 -0400400 struct pcm_peaks *peaks)
Michael Sevakis22b6def2011-07-02 11:55:38 +0000401{
Michael Sevakis22b6def2011-07-02 11:55:38 +0000402 int count;
403 const void *addr = mixer_channel_get_buffer(channel, &count);
404
Michael Sevakise189b332012-05-02 20:53:07 -0400405 pcm_do_peak_calculation(peaks,
406 channels[channel].status == CHANNEL_PLAYING,
Michael Sevakis22b6def2011-07-02 11:55:38 +0000407 addr, count);
Michael Sevakis22b6def2011-07-02 11:55:38 +0000408}
409
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400410/* Adjust channel pointer by a given offset to support movable buffers */
411void mixer_adjust_channel_address(enum pcm_mixer_channel channel,
412 off_t offset)
413{
414 pcm_play_lock();
415 /* Makes no difference if it's stopped */
416 channels[channel].start += offset;
417 pcm_play_unlock();
418}
419
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500420/* Set a hook that is called upon getting a new source buffer for a channel
421 NOTE: Called for each buffer, not each mixer chunk */
422void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel,
423 chan_buffer_hook_fn_type fn)
424{
425 struct mixer_channel *chan = &channels[channel];
426
427 pcm_play_lock();
428 chan->buffer_hook = fn;
429 pcm_play_unlock();
430}
431
Michael Sevakisa2b67032011-06-29 06:37:04 +0000432/* Stop ALL channels and PCM and reset state */
433void mixer_reset(void)
434{
435 pcm_play_stop();
436
437 while (*active_channels)
438 channel_stopped(*active_channels);
439
440 idle_counter = 0;
441}
Michael Sevakisd37bf242013-05-23 13:58:51 -0400442
443/* Set output samplerate */
444void mixer_set_frequency(unsigned int samplerate)
445{
446 pcm_set_frequency(samplerate);
447 samplerate = pcm_get_frequency();
448
449 if (samplerate == mixer_sampr)
450 return;
451
452 /* All data is now invalid */
453 mixer_reset();
454 mixer_sampr = samplerate;
455}
456
457/* Get output samplerate */
458unsigned int mixer_get_frequency(void)
459{
460 return mixer_sampr;
461}