X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fbackends%2Fdummy%2Fdummy_audiobackend.cc;h=28d73d462ed16f214676a62f8341b110852dc56c;hb=8fff1f290a5d3f457b734721a7afc63d5f8b3205;hp=50cc88b0f52a2c6d57ccb4fab61c79389b4e52c1;hpb=93eac8b068f2bcd14bfc538ee2df937b66b18504;p=ardour.git diff --git a/libs/backends/dummy/dummy_audiobackend.cc b/libs/backends/dummy/dummy_audiobackend.cc index 50cc88b0f5..28d73d462e 100644 --- a/libs/backends/dummy/dummy_audiobackend.cc +++ b/libs/backends/dummy/dummy_audiobackend.cc @@ -17,6 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -33,7 +34,7 @@ #include "pbd/error.h" #include "ardour/port_manager.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; @@ -112,7 +113,10 @@ DummyAudioBackend::enumerate_devices () const { if (_device_status.empty()) { _device_status.push_back (DeviceStatus (_("Silence"), true)); + _device_status.push_back (DeviceStatus (_("DC -6dBFS (+.5)"), true)); + _device_status.push_back (DeviceStatus (_("Demolition"), true)); _device_status.push_back (DeviceStatus (_("Sine Wave"), true)); + _device_status.push_back (DeviceStatus (_("Sine Wave 1K, 1/3 Oct"), true)); _device_status.push_back (DeviceStatus (_("Square Wave"), true)); _device_status.push_back (DeviceStatus (_("Impulses"), true)); _device_status.push_back (DeviceStatus (_("Uniform White Noise"), true)); @@ -805,7 +809,7 @@ DummyAudioBackend::unregister_port (PortEngine::PortHandle port_handle) return; } DummyPort* port = static_cast(port_handle); - PortIndex::iterator i = _ports.find (static_cast(port_handle)); + PortIndex::iterator i = std::find (_ports.begin(), _ports.end(), static_cast(port_handle)); if (i == _ports.end ()) { PBD::error << _("DummyBackend::unregister_port: Failed to find port") << endmsg; return; @@ -831,6 +835,8 @@ DummyAudioBackend::register_system_ports() gt = DummyAudioPort::PonyNoise; } else if (_device == _("Sine Wave")) { gt = DummyAudioPort::SineWave; + } else if (_device == _("Sine Wave 1K, 1/3 Oct")) { + gt = DummyAudioPort::SineWaveOctaves; } else if (_device == _("Square Wave")) { gt = DummyAudioPort::SquareWave; } else if (_device == _("Impulses")) { @@ -845,6 +851,10 @@ DummyAudioBackend::register_system_ports() gt = DummyAudioPort::SquareSweepSwell; } else if (_device == _("Loopback")) { gt = DummyAudioPort::Loopback; + } else if (_device == _("Demolition")) { + gt = DummyAudioPort::Demolition; + } else if (_device == _("DC -6dBFS (+.5)")) { + gt = DummyAudioPort::DC05; } else { gt = DummyAudioPort::Silence; } @@ -868,7 +878,10 @@ DummyAudioBackend::register_system_ports() if (!p) return -1; set_latency_range (p, false, lr); _system_inputs.push_back (static_cast(p)); - static_cast(p)->setup_generator (gt, _samplerate); + std::string name = static_cast(p)->setup_generator (gt, _samplerate, i - 1, a_ins); + if (!name.empty ()) { + static_cast(p)->set_pretty_name (name); + } } lr.min = lr.max = _systemic_output_latency; @@ -891,8 +904,10 @@ DummyAudioBackend::register_system_ports() set_latency_range (p, false, lr); _system_midi_in.push_back (static_cast(p)); if (_midi_mode == MidiGenerator) { - static_cast(p)->setup_generator (i % NUM_MIDI_EVENT_GENERATORS, _samplerate); - static_cast(p)->set_pretty_name (DummyMidiData::sequence_names[i % NUM_MIDI_EVENT_GENERATORS]); + std::string name = static_cast(p)->setup_generator (i % NUM_MIDI_EVENT_GENERATORS, _samplerate); + if (!name.empty ()) { + static_cast(p)->set_pretty_name (name); + } } } @@ -1649,8 +1664,42 @@ DummyAudioPort::~DummyAudioPort () { _wavetable = 0; } -void DummyAudioPort::setup_generator (GeneratorType const g, float const samplerate) +static std::string format_hz (float freq) { + std::stringstream ss; + if (freq >= 10000) { + ss << std::setprecision (1) << std::fixed << freq / 1000 << "kHz"; + } else if (freq >= 1000) { + ss << std::setprecision (2) << std::fixed << freq / 1000 << "kHz"; + } else { + ss << std::setprecision (1) << std::fixed << freq << "Hz"; + } + return ss.str (); +} + +static size_t fit_wave (float freq, float rate, float precision = 0.001) { + const size_t max_mult = floor (freq * rate); + float minErr = 2; + size_t fact = 1; + for (size_t i = 1; i < max_mult; ++i) { + const float isc = rate * (float)i / freq; // ideal sample count + const float rsc = rintf (isc); // rounded sample count + const float err = fabsf (isc - rsc); + if (err < minErr) { + minErr = err; + fact = i; + } + if (err < precision) { + break; + } + } + //printf(" FIT %8.1f Hz / %8.1f Hz * %ld = %.0f (err: %e)\n", freq, rate, fact, fact * rate / freq, minErr); + return fact; +} + +std::string +DummyAudioPort::setup_generator (GeneratorType const g, float const samplerate, int c, int total) { + std::string name; DummyPort::setup_random_number_generator(); _gen_type = g; @@ -1659,16 +1708,37 @@ void DummyAudioPort::setup_generator (GeneratorType const g, float const sampler case PonyNoise: case UniformWhiteNoise: case GaussianWhiteNoise: + case DC05: case Silence: break; + case Demolition: + _gen_period = 3 * samplerate; + break; case KronekerDelta: _gen_period = (5 + randi() % (int)(samplerate / 20.f)); + name = "Delta " + format_hz (samplerate / _gen_period); break; case SquareWave: _gen_period = (5 + randi() % (int)(samplerate / 20.f)) & ~1; + name = "Square " + format_hz (samplerate / _gen_period); + break; + case SineWaveOctaves: + { + const int x = c - floor (((float)total / 2)); + float f = powf (2.f, x / 3.f) * 1000.f; + f = std::max (10.f, std::min (samplerate *.5f, f)); + const size_t mult = fit_wave (f, samplerate); + _gen_period = rintf ((float)mult * samplerate / f); + name = "Sine " + format_hz (samplerate * mult / (float)_gen_period); + _wavetable = (Sample*) malloc (_gen_period * sizeof(Sample)); + for (uint32_t i = 0 ; i < _gen_period; ++i) { + _wavetable[i] = .12589f * sinf(2.0f * M_PI * (float)mult * (float)i / (float)(_gen_period)); // -18dBFS + } + } break; case SineWave: _gen_period = 5 + randi() % (int)(samplerate / 20.f); + name = "Sine " + format_hz (samplerate / _gen_period); _wavetable = (Sample*) malloc (_gen_period * sizeof(Sample)); for (uint32_t i = 0 ; i < _gen_period; ++i) { _wavetable[i] = .12589f * sinf(2.0f * M_PI * (float)i / (float)_gen_period); // -18dBFS @@ -1727,6 +1797,7 @@ void DummyAudioPort::setup_generator (GeneratorType const g, float const sampler _wavetable = (Sample*) malloc (DummyAudioBackend::max_buffer_size() * sizeof(Sample)); break; } + return name; } void DummyAudioPort::midi_to_wavetable (DummyMidiBuffer const * const src, size_t n_samples) @@ -1781,6 +1852,23 @@ float DummyAudioPort::grandf () return r * x1; } +/* inspired by jack-demolition by Steve Harris */ +static const float _demolition[] = { + 0.0f, /* special case - 0dbFS white noise */ + 0.0f, /* zero, may cause denomrals following a signal */ + 0.73 / 1e45, /* very small - should be denormal when floated */ + 3.7f, /* arbitrary number > 0dBFS */ + -4.3f, /* arbitrary negative number > 0dBFS */ + 4294967395.0f, /* 2^16 + 100 */ + -4294967395.0f, + HUGE, /* Big, non-inf number */ + INFINITY, /* +inf */ + -INFINITY, /* -inf */ + -NAN, /* -nan */ + NAN, /* nan */ + 0.0f, /* some silence to check for recovery */ +}; + void DummyAudioPort::generate (const pframes_t n_samples) { Glib::Threads::Mutex::Lock lm (generator_lock); @@ -1792,6 +1880,30 @@ void DummyAudioPort::generate (const pframes_t n_samples) case Silence: memset (_buffer, 0, n_samples * sizeof (Sample)); break; + case DC05: + for (pframes_t i = 0 ; i < n_samples; ++i) { + _buffer[i] = 0.5f; + } + break; + case Demolition: + switch (_gen_count2) { + case 0: // noise + for (pframes_t i = 0 ; i < n_samples; ++i) { + _buffer[i] = randf(); + } + break; + default: + for (pframes_t i = 0 ; i < n_samples; ++i) { + _buffer[i] = _demolition [_gen_count2]; + } + break; + } + _gen_offset += n_samples; + if (_gen_offset > _gen_period) { + _gen_offset = 0; + _gen_count2 = (_gen_count2 + 1) % (sizeof (_demolition) / sizeof (float)); + } + break; case SquareWave: assert(_gen_period > 0); for (pframes_t i = 0 ; i < n_samples; ++i) { @@ -1829,6 +1941,7 @@ void DummyAudioPort::generate (const pframes_t n_samples) case Loopback: _gen_period = n_samples; // XXX DummyBackend::_samples_per_period; case SineWave: + case SineWaveOctaves: case SineSweep: case SquareSweep: assert(_wavetable && _gen_period > 0); @@ -1952,13 +2065,15 @@ void DummyMidiPort::set_loopback (DummyMidiBuffer const * const src) } } -void DummyMidiPort::setup_generator (int seq_id, const float sr) +std::string +DummyMidiPort::setup_generator (int seq_id, const float sr) { DummyPort::setup_random_number_generator(); _midi_seq_dat = DummyMidiData::sequences[seq_id % NUM_MIDI_EVENT_GENERATORS]; _midi_seq_spb = sr * .5f; // 120 BPM, beat_time 1.0 per beat. _midi_seq_pos = 0; _midi_seq_time = 0; + return DummyMidiData::sequence_names[seq_id]; } void DummyMidiPort::midi_generate (const pframes_t n_samples)