add a Dummy Backend Loopback mode:
authorRobin Gareus <robin@gareus.org>
Sat, 11 Oct 2014 12:47:35 +0000 (14:47 +0200)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Oct 2014 09:34:43 +0000 (05:34 -0400)
Conflicts:
libs/backends/dummy/dummy_audiobackend.cc
libs/backends/dummy/dummy_audiobackend.h

libs/backends/dummy/dummy_audiobackend.cc
libs/backends/dummy/dummy_audiobackend.h

index ce78c96321a4229909e921b66e3ad8762676ee9a..6ba6a60bd87353a6f7be59b6d27ad20532bf09b6 100644 (file)
@@ -87,6 +87,9 @@ DummyAudioBackend::enumerate_devices () const
                _device_status.push_back (DeviceStatus (_("Gaussian White Noise"), true));
                _device_status.push_back (DeviceStatus (_("Pink Noise"), true));
                _device_status.push_back (DeviceStatus (_("Pink Noise (low CPU)"), true));
+               _device_status.push_back (DeviceStatus (_("Sine Sweep"), true));
+               _device_status.push_back (DeviceStatus (_("Sine Sweep Swell"), true));
+               _device_status.push_back (DeviceStatus (_("Loopback"), true));
        }
        return _device_status;
 }
@@ -173,6 +176,30 @@ DummyAudioBackend::set_buffer_size (uint32_t bs)
                return -1;
        }
        _samples_per_period = bs;
+
+       /* update port latencies
+        * with 'Loopback' there is exactly once cycle latency,
+        * divide it between In + Out;
+        */
+       const size_t l_in = _samples_per_period * .25;
+       const size_t l_out = _samples_per_period - l_in;
+       LatencyRange lr;
+       lr.min = lr.max = l_in + _systemic_input_latency;
+       for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
+               set_latency_range (*it, false, lr);
+       }
+       for (std::vector<DummyMidiPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
+               set_latency_range (*it, false, lr);
+       }
+
+       lr.min = lr.max = l_out + _systemic_output_latency;
+       for (std::vector<DummyAudioPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
+               set_latency_range (*it, true, lr);
+       }
+       for (std::vector<DummyMidiPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
+               set_latency_range (*it, true, lr);
+       }
+
        engine.buffer_size_change (bs);
        return 0;
 }
@@ -322,6 +349,9 @@ DummyAudioBackend::_start (bool /*for_latency_measurement*/)
                        PBD::info << _("DummyAudioBackend: port '") << (*it)->name () << "' exists." << endmsg;
                }
                _system_inputs.clear();
+               _system_outputs.clear();
+               _system_midi_in.clear();
+               _system_midi_out.clear();
                _ports.clear();
        }
 
@@ -666,6 +696,16 @@ DummyAudioBackend::register_system_ports()
                gt = DummyAudioPort::PonyNoise;
        } else if (_device == _("Sine Wave")) {
                gt = DummyAudioPort::SineWave;
+       } else if (_device == _("Square Wave")) {
+               gt = DummyAudioPort::SquareWave;
+       } else if (_device == _("Impulses")) {
+               gt = DummyAudioPort::KronekerDelta;
+       } else if (_device == _("Sine Sweep")) {
+               gt = DummyAudioPort::SineSweep;
+       } else if (_device == _("Sine Sweep Swell")) {
+               gt = DummyAudioPort::SineSweepSwell;
+       } else if (_device == _("Loopback")) {
+               gt = DummyAudioPort::Loopback;
        } else {
                gt = DummyAudioPort::Silence;
        }
@@ -675,8 +715,12 @@ DummyAudioBackend::register_system_ports()
        const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
        const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
 
+       /* with 'Loopback' there is exactly once cycle latency, divide it between In + Out; */
+       const size_t l_in = _samples_per_period * .25;
+       const size_t l_out = _samples_per_period - l_in;
+
        /* audio ports */
-       lr.min = lr.max = _samples_per_period + _systemic_input_latency;
+       lr.min = lr.max = l_in + _systemic_input_latency;
        for (int i = 1; i <= a_ins; ++i) {
                char tmp[64];
                snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
@@ -687,17 +731,18 @@ DummyAudioBackend::register_system_ports()
                static_cast<DummyAudioPort*>(p)->setup_generator (gt, _samplerate);
        }
 
-       lr.min = lr.max = _samples_per_period + _systemic_output_latency;
+       lr.min = lr.max = l_out + _systemic_output_latency;
        for (int i = 1; i <= a_out; ++i) {
                char tmp[64];
                snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
                PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
                if (!p) return -1;
                set_latency_range (p, true, lr);
+               _system_outputs.push_back (static_cast<DummyAudioPort*>(p));
        }
 
        /* midi ports */
-       lr.min = lr.max = _samples_per_period + _systemic_input_latency;
+       lr.min = lr.max = l_in + _systemic_input_latency;
        for (int i = 1; i <= m_ins; ++i) {
                char tmp[64];
                snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
@@ -706,13 +751,14 @@ DummyAudioBackend::register_system_ports()
                set_latency_range (p, false, lr);
        }
 
-       lr.min = lr.max = _samples_per_period + _systemic_output_latency;
+       lr.min = lr.max = l_out + _systemic_output_latency;
        for (int i = 1; i <= m_out; ++i) {
                char tmp[64];
                snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
                PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
                if (!p) return -1;
                set_latency_range (p, true, lr);
+               _system_midi_out.push_back (static_cast<DummyMidiPort*>(p));
        }
        return 0;
 }
@@ -722,6 +768,9 @@ DummyAudioBackend::unregister_ports (bool system_only)
 {
        size_t i = 0;
        _system_inputs.clear();
+       _system_outputs.clear();
+       _system_midi_in.clear();
+       _system_midi_out.clear();
        while (i <  _ports.size ()) {
                DummyPort* port = _ports[i];
                if (! system_only || (port->is_physical () && port->is_terminal ())) {
@@ -1066,6 +1115,17 @@ DummyAudioBackend::main_process_thread ()
                        return 0;
                }
                _processed_samples += _samples_per_period;
+
+               if (_device == _("Loopback")) {
+                       int opn = 0;
+                       int opc = _system_outputs.size();
+                       for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++opn) {
+                               DummyAudioPort* op = _system_outputs[(opn % opc)];
+                               (*it)->fill_wavetable ((const float*)op->get_buffer (_samples_per_period), _samples_per_period);
+                       }
+
+               }
+
                if (!_freewheeling) {
                        clock2 = g_get_monotonic_time();
                        const int64_t elapsed_time = clock2 - clock1;
@@ -1343,6 +1403,9 @@ void DummyAudioPort::setup_generator (GeneratorType const g, float const sampler
                                }
                        }
                        break;
+               case Loopback:
+                       _wavetable = (Sample*) malloc (DummyAudioBackend::max_buffer_size() * sizeof(Sample));
+                       break;
        }
 }
 
@@ -1406,6 +1469,42 @@ void DummyAudioPort::generate (const pframes_t n_samples)
                case Silence:
                        memset (_buffer, 0, n_samples * sizeof (Sample));
                        break;
+               case SquareWave:
+                       assert(_gen_period > 0);
+                       for (pframes_t i = 0 ; i < n_samples; ++i) {
+                               if (_gen_offset < _gen_period * .5f) {
+                                       _buffer[i] =  .40709f; // -6dBFS
+                               } else {
+                                       _buffer[i] = -.40709f;
+                               }
+                               _gen_offset = (_gen_offset + 1) % _gen_period;
+                       }
+                       break;
+               case KronekerDelta:
+                       assert(_gen_period > 0);
+                       memset (_buffer, 0, n_samples * sizeof (Sample));
+                       for (pframes_t i = 0; i < n_samples; ++i) {
+                               if (_gen_offset == 0) {
+                                       _buffer[i] = 1.0f;
+                               }
+                               _gen_offset = (_gen_offset + 1) % _gen_period;
+                       }
+                       break;
+               case SineSweepSwell:
+                       assert(_wavetable && _gen_period > 0);
+                       {
+                               const float vols = 2.f / (float)_gen_perio2;
+                               for (pframes_t i = 0; i < n_samples; ++i) {
+                                       const float g = fabsf (_gen_count2 * vols - 1.0);
+                                       _buffer[i] = g * _wavetable[_gen_offset];
+                                       _gen_offset = (_gen_offset + 1) % _gen_period;
+                                       _gen_count2 = (_gen_count2 + 1) % _gen_perio2;
+                               }
+                       }
+                       break;
+               case Loopback:
+                       _gen_period = n_samples; // XXX DummyBackend::_samples_per_period;
+>>>>>>> 8525a0b... add a Dummy Backend Loopback mode:
                case SineWave:
                        assert(_wavetable && _tbl_length > 0);
                        {
index b28a464e3c70cad57b10df2635463b7ec85e4cf5..abc0ab592754be02957928854526aa9729e84fad 100644 (file)
@@ -132,9 +132,15 @@ class DummyAudioPort : public DummyPort {
                        PinkNoise,
                        PonyNoise,
                        SineWave,
+                       SquareWave,
+                       KronekerDelta,
+                       SineSweep,
+                       SineSweepSwell,
+                       Loopback,
                };
                void next_period () { _gen_cycle = false; }
                void setup_generator (GeneratorType const, float const);
+               void fill_wavetable (const float* d, size_t n_samples) { assert(_wavetable != 0);  memcpy(_wavetable, d, n_samples * sizeof(float)); }
 
        private:
                Sample _buffer[8192];
@@ -326,6 +332,8 @@ class DummyAudioBackend : public AudioBackend {
 
                void* main_process_thread ();
 
+               static size_t max_buffer_size() {return _max_buffer_size;}
+
        private:
                std::string _instance_name;
                static std::vector<std::string> _midi_options;
@@ -373,6 +381,9 @@ class DummyAudioBackend : public AudioBackend {
                void unregister_ports (bool system_only = false);
 
                std::vector<DummyAudioPort *> _system_inputs;
+               std::vector<DummyAudioPort *> _system_outputs;
+               std::vector<DummyMidiPort *> _system_midi_in;
+               std::vector<DummyMidiPort *> _system_midi_out;
                std::vector<DummyPort *> _ports;