2 * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "pbd/compose.h"
24 #include "pbd/error.h"
25 #include "pbd/pthread_utils.h"
27 #include "alsa_slave.h"
31 using namespace ARDOUR;
33 AlsaAudioSlave::AlsaAudioSlave (
34 const char *play_name,
35 const char *capt_name,
36 unsigned int master_rate,
37 unsigned int master_samples_per_period,
38 unsigned int slave_rate,
39 unsigned int slave_samples_per_period,
40 unsigned int periods_per_cycle)
41 : _pcmi (play_name, capt_name, 0, slave_rate, slave_samples_per_period, periods_per_cycle, 2, /* Alsa_pcmi::DEBUG_ALL */ 0)
44 , _samples_since_dll_reset (0)
48 , _rb_capture (4 * /* AlsaAudioBackend::_max_buffer_size */ 8192 * _pcmi.ncapt ())
49 , _rb_playback (4 * /* AlsaAudioBackend::_max_buffer_size */ 8192 * _pcmi.nplay ())
50 , _samples_per_period (master_samples_per_period)
55 if (0 != _pcmi.state()) {
59 /* from alsa-slave to master */
60 _ratio = (double) master_rate / (double) _pcmi.fsamp();
63 fprintf (stdout, " --[[ ALSA Slave %s/%s ratio: %.4f\n", play_name, capt_name, _ratio);
65 fprintf (stdout, " --]]\n");
68 _src_capt.setup (_ratio, _pcmi.ncapt (), /*quality*/ 32); // save capture to master
69 _src_play.setup (1.0 / _ratio, _pcmi.nplay (), /*quality*/ 32); // master to slave play
71 _src_capt.set_rrfilt (100);
72 _src_play.set_rrfilt (100);
74 _capt_buff = (float*) malloc (sizeof(float) * _pcmi.ncapt () * _samples_per_period);
75 _play_buff = (float*) malloc (sizeof(float) * _pcmi.nplay () * _samples_per_period);
76 _src_buff = (float*) malloc (sizeof(float) * std::max (_pcmi.nplay (), _pcmi.ncapt ()));
79 AlsaAudioSlave::~AlsaAudioSlave ()
88 AlsaAudioSlave::reset_resampler (ArdourZita::VResampler& src)
91 src.inp_count = src.inpsize () - 1;
92 src.out_count = 200000;
97 AlsaAudioSlave::start ()
104 if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, -20, 100000,
105 &_thread, _process_thread, this))
107 if (pthread_create (&_thread, NULL, _process_thread, this)) {
109 PBD::error << _("AlsaAudioBackend: failed to create slave process thread.") << endmsg;
115 while (!_active && --timeout > 0) { Glib::usleep (1000); }
117 if (timeout == 0 || !_active) {
119 PBD::error << _("AlsaAudioBackend: failed to start slave process thread.") << endmsg;
127 AlsaAudioSlave::stop ()
135 if (pthread_join (_thread, &status)) {
136 PBD::error << _("AlsaAudioBackend: slave failed to terminate properly.") << endmsg;
142 AlsaAudioSlave::_process_thread (void* arg)
144 AlsaAudioSlave* aas = static_cast<AlsaAudioSlave*> (arg);
145 return aas->process_thread ();
149 AlsaAudioSlave::process_thread ()
153 bool reset_dll = true;
154 int last_n_periods = 0;
155 int no_proc_errors = 0;
156 const int bailout = 2 * _pcmi.fsamp () / _pcmi.fsize ();
158 double dll_dt = (double) _pcmi.fsize () / (double)_pcmi.fsamp ();
159 double dll_w1 = 2 * M_PI * 0.1 * dll_dt;
160 double dll_w2 = dll_w1 * dll_w1;
162 const double sr_norm = 1e-6 * (double) _pcmi.fsamp () / (double) _pcmi.fsize ();
168 long nr = _pcmi.pcm_wait ();
171 uint64_t clock0 = g_get_monotonic_time();
173 if (reset_dll || last_n_periods != 1) {
175 dll_dt = 1e6 * (double) _pcmi.fsize () / (double) _pcmi.fsamp();
177 _t1 = clock0 + dll_dt;
178 _samples_since_dll_reset = 0;
180 const double er = clock0 - _t1;
182 _t1 = _t1 + dll_w1 * er + dll_dt;
183 dll_dt += dll_w2 * er;
184 _samples_since_dll_reset += _pcmi.fsize ();
187 _slave_speed = (_t1 - _t0) * sr_norm; // XXX atomic
189 if (_pcmi.state () > 0) {
194 if (_pcmi.state () < 0) {
195 PBD::error << _("AlsaAudioBackend: Slave I/O error.") << endmsg;
199 if (no_proc_errors > bailout) {
200 PBD::error << _("AlsaAudioBackend: Slave terminated due to continuous x-runs.") << endmsg;
204 const size_t spp = _pcmi.fsize ();
205 const bool drain = g_atomic_int_get (&_draining);
208 while (nr >= (long)spp) {
211 _pcmi.capt_init (spp);
214 } else if (_rb_capture.write_space () >= _pcmi.ncapt () * spp) {
215 #if 0 // failsafe: write interleave sample by sample
216 for (uint32_t s = 0; s < spp; ++s) {
217 for (uint32_t c = 0; c < _pcmi.ncapt (); ++c) {
219 _pcmi.capt_chan (c, &d, 1);
220 _rb_capture.write (&d, 1);
224 unsigned int nchn = _pcmi.ncapt ();
225 PBD::RingBuffer<float>::rw_vector vec;
226 _rb_capture.get_write_vector (&vec);
227 if (vec.len[0] >= nchn * spp) {
228 for (uint32_t c = 0; c < nchn; ++c) {
229 _pcmi.capt_chan (c, vec.buf[0] + c, spp, nchn);
233 /* first copy continuous area */
234 uint32_t k = vec.len[0] / nchn;
235 for (c = 0; c < nchn; ++c) {
236 _pcmi.capt_chan (c, vec.buf[0] + c, k, nchn);
239 /* possible samples at end of first buffer chunk,
240 * incomplete audio-sample */
241 uint32_t s = vec.len[0] - k * nchn;
244 for (c = 0; c < s; ++c) {
245 _pcmi.capt_chan (c, vec.buf[0] + k * nchn + c, 1, nchn);
247 /* cont'd audio-sample at second ringbuffer chunk */
248 for (; c < nchn; ++c) {
249 _pcmi.capt_chan (c, vec.buf[1] + c - s, spp - k, nchn);
251 /* remaining data in 2nd area */
252 for (c = 0; c < s; ++c) {
253 _pcmi.capt_chan (c, vec.buf[1] + c + nchn - s, spp - k, nchn);
256 _rb_capture.increment_write_idx (spp * nchn);
259 g_atomic_int_set(&_draining, 1);
261 _pcmi.capt_done (spp);
265 _rb_playback.increment_read_idx (_rb_playback.read_space ());
268 _pcmi.play_init (spp);
269 if (_rb_playback.read_space () >= _pcmi.nplay () * spp) {
270 #if 0 // failsafe: read sample by sample de-interleave
271 for (uint32_t s = 0; s < spp; ++s) {
272 for (uint32_t c = 0; c < _pcmi.nplay (); ++c) {
274 _rb_playback.read (&d, 1);
275 _pcmi.play_chan (c, (const float*)&d, 1);
279 unsigned int nchn = _pcmi.nplay ();
280 PBD::RingBuffer<float>::rw_vector vec;
281 _rb_playback.get_read_vector (&vec);
282 if (vec.len[0] >= nchn * spp) {
283 for (uint32_t c = 0; c < nchn; ++c) {
284 _pcmi.play_chan (c, vec.buf[0] + c, spp, nchn);
288 uint32_t k = vec.len[0] / nchn;
289 for (c = 0; c < nchn; ++c) {
290 _pcmi.play_chan (c, vec.buf[0] + c, k, nchn);
293 uint32_t s = vec.len[0] - k * nchn;
296 for (c = 0; c < s; ++c) {
297 _pcmi.play_chan (c, vec.buf[0] + k * nchn + c, 1, nchn);
300 for (; c < nchn; ++c) {
301 _pcmi.play_chan (c, vec.buf[1] + c - s, spp - k, nchn);
303 for (c = 0; c < s; ++c) {
304 _pcmi.play_chan (c, vec.buf[1] + c + nchn - s, spp - k, nchn);
307 _rb_playback.increment_read_idx (spp * nchn);
311 printf ("Slave Process: Playback Buffer Underflow, have %u want %lu\n", _rb_playback.read_space (), _pcmi.nplay () * spp); // XXX DEBUG
312 _play_latency += spp * _ratio;
313 update_latencies (_play_latency, _capt_latency);
315 /* silence outputs */
316 for (uint32_t c = 0; c < _pcmi.nplay (); ++c) {
317 _pcmi.clear_chan (c, spp);
320 _pcmi.play_done (spp);
326 if (xrun && (_pcmi.capt_xrun() > 0 || _pcmi.play_xrun() > 0)) {
328 _samples_since_dll_reset = 0;
329 g_atomic_int_set(&_draining, 1);
337 Halted (); /* Emit Signal */
343 AlsaAudioSlave::cycle_start (double tme, double mst_speed, bool drain)
345 //printf ("SRC %f / %f = %f\n", mst_speed, _slave_speed, mst_speed / _slave_speed);
346 //printf ("DRIFT (mst) %11.1f - (slv) %11.1f = %.1f us = %.1f spl\n", tme, _t0, tme - _t0, (tme - _t0) * _pcmi.fsamp () * 1e-6);
347 //printf ("Slave capt: %u play: %u\n", _rb_capture.read_space (), _rb_playback.read_space ());
349 // TODO LPF filter ratios, atomic _slave_speed
350 const double slave_speed = _slave_speed;
352 _src_capt.set_rratio (mst_speed / slave_speed);
353 _src_play.set_rratio (slave_speed / mst_speed);
355 memset (_capt_buff, 0, sizeof(float) * _pcmi.ncapt () * _samples_per_period);
358 g_atomic_int_set(&_draining, 1);
362 if (g_atomic_int_get (&_draining)) {
363 _rb_capture.increment_read_idx (_rb_capture.read_space());
367 /* resample slave capture data from ringbuffer */
368 unsigned int nchn = _pcmi.ncapt ();
369 _src_capt.out_count = _samples_per_period;
370 _src_capt.out_data = _capt_buff;
372 /* estimate required samples */
373 const double rratio = _ratio * mst_speed / slave_speed;
374 if (_rb_capture.read_space() < ceil (nchn * _samples_per_period / rratio)) {
375 printf ("--- UNDERFLOW --- have %u want %.1f\n", _rb_capture.read_space(), ceil (nchn * _samples_per_period / rratio)); // XXX DEBUG
376 _capt_latency += _samples_per_period;
377 update_latencies (_play_latency, _capt_latency);
381 bool underflow = false;
382 while (_src_capt.out_count && _active) {
383 if (_rb_capture.read_space() < nchn) {
388 PBD::RingBuffer<float>::rw_vector vec;
389 _rb_capture.get_read_vector (&vec);
390 if (vec.len[0] < nchn) {
391 _rb_capture.read (_src_buff, nchn);
392 _src_capt.inp_count = 1;
393 _src_capt.inp_data = _src_buff;
394 _src_capt.process ();
396 _src_capt.inp_count = n = vec.len[0] / nchn;
397 _src_capt.inp_data = vec.buf[0];
398 _src_capt.process ();
399 n -= _src_capt.inp_count;
400 _rb_capture.increment_read_idx (n * _pcmi.ncapt ());
405 std::cerr << "ALSA Slave: Capture Ringbuffer Underflow\n"; // XXX
406 g_atomic_int_set(&_draining, 1);
409 if (!_active || underflow) {
410 memset (_capt_buff, 0, sizeof(float) * _pcmi.ncapt () * _samples_per_period);
413 memset (_play_buff, 0, sizeof(float) * _pcmi.nplay () * _samples_per_period);
417 AlsaAudioSlave::cycle_end ()
419 bool drain_done = false;
420 bool overflow = false;
422 if (g_atomic_int_get (&_draining)) {
423 if (_rb_capture.read_space() == 0 && _rb_playback.read_space() == 0 && _samples_since_dll_reset > _pcmi.fsamp ()) {
424 reset_resampler (_src_capt);
425 reset_resampler (_src_play);
426 memset (_src_buff, 0, sizeof (float) * _pcmi.nplay());
427 /* prefill ringbuffers, resampler variance */
428 for (int i = 0; i < 16; ++i) {
429 _rb_playback.write (_src_buff, _pcmi.nplay());
431 memset (_src_buff, 0, sizeof (float) * _pcmi.ncapt());
432 // It's safe to write here, process-thread NO-OPs while draining.
433 for (int i = 0; i < 16; ++i) {
434 _rb_capture.write (_src_buff, _pcmi.ncapt());
437 _play_latency = 16 + _ratio * _pcmi.fsize () * (_pcmi.play_nfrag () - 1);
438 update_latencies (_play_latency, _capt_latency);
445 /* resample collected playback data into ringbuffer */
446 unsigned int nchn = _pcmi.nplay ();
447 _src_play.inp_count = _samples_per_period;
448 _src_play.inp_data = _play_buff;
450 while (_src_play.inp_count && _active) {
452 PBD::RingBuffer<float>::rw_vector vec;
453 _rb_playback.get_write_vector (&vec);
454 if (vec.len[0] < nchn) {
455 _src_play.out_count = 1;
456 _src_play.out_data = _src_buff;
457 _src_play.process ();
458 if (_rb_playback.write_space() < nchn) {
461 } else if (_src_play.out_count == 0) {
462 _rb_playback.write (_src_buff, nchn);
465 _src_play.out_count = n = vec.len[0] / nchn;
466 _src_play.out_data = vec.buf[0];
467 _src_play.process ();
468 n -= _src_play.out_count;
469 if (_rb_playback.write_space() < n * nchn) {
473 _rb_playback.increment_write_idx (n * nchn);
478 std::cerr << "ALSA Slave: Playback Ringbuffer Overflow\n"; // XXX
479 g_atomic_int_set(&_draining, 1);
483 g_atomic_int_set(&_draining, 0);
488 AlsaAudioSlave::freewheel (bool onoff)
491 g_atomic_int_set(&_draining, 1);
495 /* master read slave's capture.
496 * resampled at cycle_start, before master can call this
499 AlsaAudioSlave::capt_chan (uint32_t chn, float* dst, uint32_t n_samples)
501 uint32_t nchn = _pcmi.ncapt ();
502 assert (chn < nchn && n_samples == _samples_per_period);
503 float* src = &_capt_buff[chn];
504 for (uint32_t s = 0; s < n_samples; ++s) {
505 dst[s] = src[s * nchn];
510 /* write from master to slave output,
511 * resampled at cycle_end, after master called this.
514 AlsaAudioSlave::play_chan (uint32_t chn, float* src, uint32_t n_samples)
516 uint32_t nchn = _pcmi.nplay ();
517 assert (chn < nchn && n_samples == _samples_per_period);
518 float* dst = &_play_buff[chn];
519 for (uint32_t s = 0; s < n_samples; ++s) {
520 dst[s * nchn] = src[s];