add signal generator modules to Dummy Backend.
This commit is contained in:
parent
67eaa62ee9
commit
185f06e7f7
@ -19,6 +19,7 @@
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <regex.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glibmm.h>
|
||||
|
||||
@ -39,6 +40,7 @@ DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||
: AudioBackend (e, info)
|
||||
, _running (false)
|
||||
, _freewheeling (false)
|
||||
, _device ("")
|
||||
, _samplerate (48000)
|
||||
, _samples_per_period (1024)
|
||||
, _dsp_load (0)
|
||||
@ -78,7 +80,11 @@ std::vector<AudioBackend::DeviceStatus>
|
||||
DummyAudioBackend::enumerate_devices () const
|
||||
{
|
||||
if (_device_status.empty()) {
|
||||
_device_status.push_back (DeviceStatus (_("Dummy"), true));
|
||||
_device_status.push_back (DeviceStatus (_("Silence"), true));
|
||||
_device_status.push_back (DeviceStatus (_("Sine Wave"), true));
|
||||
_device_status.push_back (DeviceStatus (_("White Noise"), true));
|
||||
_device_status.push_back (DeviceStatus (_("Pink Noise"), true));
|
||||
_device_status.push_back (DeviceStatus (_("Pink Noise (low CPU)"), true));
|
||||
}
|
||||
return _device_status;
|
||||
}
|
||||
@ -143,8 +149,9 @@ DummyAudioBackend::can_change_buffer_size_when_running () const
|
||||
}
|
||||
|
||||
int
|
||||
DummyAudioBackend::set_device_name (const std::string&)
|
||||
DummyAudioBackend::set_device_name (const std::string& d)
|
||||
{
|
||||
_device = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -207,7 +214,7 @@ DummyAudioBackend::set_systemic_output_latency (uint32_t sl)
|
||||
std::string
|
||||
DummyAudioBackend::device_name () const
|
||||
{
|
||||
return _("Dummy Device");
|
||||
return _device;
|
||||
}
|
||||
|
||||
float
|
||||
@ -309,6 +316,7 @@ DummyAudioBackend::_start (bool /*for_latency_measurement*/)
|
||||
|
||||
if (_ports.size()) {
|
||||
PBD::warning << _("DummyAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
|
||||
_system_inputs.clear();
|
||||
_ports.clear();
|
||||
}
|
||||
|
||||
@ -637,6 +645,18 @@ int
|
||||
DummyAudioBackend::register_system_ports()
|
||||
{
|
||||
LatencyRange lr;
|
||||
enum DummyAudioPort::GeneratorType gt;
|
||||
if (_device == _("White Noise")) {
|
||||
gt = DummyAudioPort::WhiteNoise;
|
||||
} else if (_device == _("Pink Noise")) {
|
||||
gt = DummyAudioPort::PinkNoise;
|
||||
} else if (_device == _("Pink Noise (low CPU)")) {
|
||||
gt = DummyAudioPort::PonyNoise;
|
||||
} else if (_device == _("Sine Wave")) {
|
||||
gt = DummyAudioPort::SineWave;
|
||||
} else {
|
||||
gt = DummyAudioPort::Silence;
|
||||
}
|
||||
|
||||
const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
|
||||
const int a_out = _n_outputs > 0 ? _n_outputs : 8;
|
||||
@ -651,6 +671,8 @@ DummyAudioBackend::register_system_ports()
|
||||
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
||||
if (!p) return -1;
|
||||
set_latency_range (p, false, lr);
|
||||
_system_inputs.push_back (static_cast<DummyAudioPort*>(p));
|
||||
static_cast<DummyAudioPort*>(p)->setup_generator (gt, _samplerate);
|
||||
}
|
||||
|
||||
lr.min = lr.max = _samples_per_period + _systemic_output_latency;
|
||||
@ -687,6 +709,7 @@ void
|
||||
DummyAudioBackend::unregister_system_ports()
|
||||
{
|
||||
size_t i = 0;
|
||||
_system_inputs.clear();
|
||||
while (i < _ports.size ()) {
|
||||
DummyPort* port = _ports[i];
|
||||
if (port->is_physical () && port->is_terminal ()) {
|
||||
@ -1020,6 +1043,12 @@ DummyAudioBackend::main_process_thread ()
|
||||
uint64_t clock1, clock2;
|
||||
clock1 = g_get_monotonic_time();
|
||||
while (_running) {
|
||||
|
||||
// re-set input buffers, generate on demand.
|
||||
for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
|
||||
(*it)->next_period();
|
||||
}
|
||||
|
||||
if (engine.process_callback (_samples_per_period)) {
|
||||
return 0;
|
||||
}
|
||||
@ -1257,12 +1286,133 @@ bool DummyPort::is_physically_connected () const
|
||||
|
||||
DummyAudioPort::DummyAudioPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
|
||||
: DummyPort (b, name, flags)
|
||||
, _gen_type (Silence)
|
||||
, _gen_cycle (false)
|
||||
, _pass (false)
|
||||
{
|
||||
memset (_buffer, 0, sizeof (_buffer));
|
||||
}
|
||||
|
||||
DummyAudioPort::~DummyAudioPort () { }
|
||||
|
||||
void DummyAudioPort::setup_generator (GeneratorType const g, float const samplerate)
|
||||
{
|
||||
_gen_type = g;
|
||||
_rseed = g_get_monotonic_time() % UINT_MAX;
|
||||
_pass = false;
|
||||
|
||||
switch (_gen_type) {
|
||||
case Silence:
|
||||
break;
|
||||
case SineWave:
|
||||
_b1 = 0;
|
||||
{
|
||||
#ifdef COMPILER_MSVC
|
||||
srand (_rseed);
|
||||
const unsigned int k = rand () % 128;
|
||||
#else
|
||||
const unsigned int k = rand_r (&_rseed) % 128;
|
||||
#endif
|
||||
// midi note, chromatic scale
|
||||
_b0 = (440.f / 32.f) * powf(2, (k - 9.0) / 12.0) / samplerate;
|
||||
assert (_b0 < M_PI/2); // fine when samplerate >= 8K
|
||||
}
|
||||
break;
|
||||
case PinkNoise:
|
||||
case PonyNoise:
|
||||
_b0 = _b1 = _b2 = _b3 = _b4 = _b5 = _b6 = 0.f;
|
||||
// fall trhu, no break
|
||||
case WhiteNoise:
|
||||
#ifdef COMPILER_MSVC
|
||||
srand (_rseed);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline float randf (unsigned int *seedp) {
|
||||
static const float rmf = RAND_MAX / 2.0;
|
||||
// TODO this should use a better uniform random generator
|
||||
#ifdef COMPILER_MSVC
|
||||
return ((float)rand () / rmf) - 1.f;
|
||||
#else
|
||||
return ((float)rand_r (seedp) / rmf) - 1.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
float DummyAudioPort::grandf ()
|
||||
{
|
||||
// Gaussian White Noise
|
||||
// http://www.musicdsp.org/archive.php?classid=0#109
|
||||
float x1, x2, r;
|
||||
|
||||
if (_pass) {
|
||||
_pass = false;
|
||||
return _rn1;
|
||||
}
|
||||
|
||||
do {
|
||||
x1 = randf (&_rseed);
|
||||
x2 = randf (&_rseed);
|
||||
r = x1 * x1 + x2 * x2;
|
||||
} while ((r >= 1.0f) || (r < 1e-22f));
|
||||
|
||||
r = sqrtf (-2.f * logf (r) / r);
|
||||
|
||||
_pass = true;
|
||||
_rn1 = r * x2;
|
||||
return r * x1;
|
||||
}
|
||||
|
||||
void DummyAudioPort::generate (pframes_t n_samples)
|
||||
{
|
||||
switch (_gen_type) {
|
||||
case Silence:
|
||||
memset (_buffer, 0, n_samples * sizeof (Sample));
|
||||
break;
|
||||
case SineWave:
|
||||
for (pframes_t i = 0 ; i < n_samples; ++i) {
|
||||
_buffer[i] = .12589f * sinf(2.0 * M_PI * _b1);
|
||||
_b1 += _b0;
|
||||
if (_b1 > 1.0) _b1 -= 2.0;
|
||||
}
|
||||
break;
|
||||
case WhiteNoise:
|
||||
for (pframes_t i = 0 ; i < n_samples; ++i) {
|
||||
_buffer[i] = .089125f * grandf();
|
||||
}
|
||||
break;
|
||||
case PinkNoise:
|
||||
for (pframes_t i = 0 ; i < n_samples; ++i) {
|
||||
// Paul Kellet's refined method
|
||||
// http://www.musicdsp.org/files/pink.txt
|
||||
// NB. If 'white' consists of uniform random numbers,
|
||||
// the pink noise will have an almost gaussian distribution.
|
||||
const float white = .0498f * randf(&_rseed);
|
||||
_b0 = .99886f * _b0 + white * .0555179f;
|
||||
_b1 = .99332f * _b1 + white * .0750759f;
|
||||
_b2 = .96900f * _b2 + white * .1538520f;
|
||||
_b3 = .86650f * _b3 + white * .3104856f;
|
||||
_b4 = .55000f * _b4 + white * .5329522f;
|
||||
_b5 = -.7616f * _b5 - white * .0168980f;
|
||||
_buffer[i] = _b0 + _b1 + _b2 + _b3 + _b4 + _b5 + _b6 + white * 0.5362;
|
||||
_b6 = white * 0.115926;
|
||||
}
|
||||
break;
|
||||
case PonyNoise:
|
||||
for (pframes_t i = 0 ; i < n_samples; ++i) {
|
||||
const float white = 0.0498f * randf(&_rseed);
|
||||
// Paul Kellet's economy method
|
||||
// http://www.musicdsp.org/files/pink.txt
|
||||
_b0 = 0.99765 * _b0 + white * 0.0990460;
|
||||
_b1 = 0.96300 * _b1 + white * 0.2965164;
|
||||
_b2 = 0.57000 * _b2 + white * 1.0526913;
|
||||
_buffer[i] = _b0 + _b1 + _b2 + white * 0.1848;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void* DummyAudioPort::get_buffer (pframes_t n_samples)
|
||||
{
|
||||
if (is_input ()) {
|
||||
@ -1270,13 +1420,19 @@ void* DummyAudioPort::get_buffer (pframes_t n_samples)
|
||||
if (it == get_connections ().end ()) {
|
||||
memset (_buffer, 0, n_samples * sizeof (Sample));
|
||||
} else {
|
||||
DummyAudioPort const * source = static_cast<const DummyAudioPort*>(*it);
|
||||
DummyAudioPort * source = static_cast<DummyAudioPort*>(*it);
|
||||
assert (source && source->is_output ());
|
||||
if (source->is_physical() && source->is_terminal()) {
|
||||
source->get_buffer(n_samples); // generate signal.
|
||||
}
|
||||
memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
|
||||
while (++it != get_connections ().end ()) {
|
||||
source = static_cast<const DummyAudioPort*>(*it);
|
||||
source = static_cast<DummyAudioPort*>(*it);
|
||||
assert (source && source->is_output ());
|
||||
Sample* dst = buffer ();
|
||||
if (source->is_physical() && source->is_terminal()) {
|
||||
source->get_buffer(n_samples); // generate signal.
|
||||
}
|
||||
const Sample* src = source->const_buffer ();
|
||||
for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
|
||||
*dst += *src;
|
||||
@ -1284,7 +1440,10 @@ void* DummyAudioPort::get_buffer (pframes_t n_samples)
|
||||
}
|
||||
}
|
||||
} else if (is_output () && is_physical () && is_terminal()) {
|
||||
memset (_buffer, 0, n_samples * sizeof (Sample));
|
||||
if (!_gen_cycle) {
|
||||
_gen_cycle = true;
|
||||
generate(n_samples);
|
||||
}
|
||||
}
|
||||
return _buffer;
|
||||
}
|
||||
|
@ -125,8 +125,36 @@ class DummyAudioPort : public DummyPort {
|
||||
const Sample* const_buffer () const { return _buffer; }
|
||||
void* get_buffer (pframes_t nframes);
|
||||
|
||||
enum GeneratorType {
|
||||
Silence,
|
||||
WhiteNoise,
|
||||
PinkNoise,
|
||||
PonyNoise,
|
||||
SineWave,
|
||||
};
|
||||
void next_period () { _gen_cycle = false; }
|
||||
void setup_generator (GeneratorType const, float const);
|
||||
|
||||
private:
|
||||
Sample _buffer[8192];
|
||||
|
||||
// signal generator ('fake' physical inputs)
|
||||
void generate (pframes_t n_samples);
|
||||
GeneratorType _gen_type;
|
||||
bool _gen_cycle;
|
||||
|
||||
// generator buffers
|
||||
// (used for pink-noise filters and sine-phase)
|
||||
float _b0, _b1, _b2, _b3, _b4, _b5, _b6;
|
||||
|
||||
// (per thread) random seed
|
||||
unsigned int _rseed;
|
||||
|
||||
// gaussian noise generator
|
||||
float grandf ();
|
||||
bool _pass;
|
||||
float _rn1;
|
||||
|
||||
}; // class DummyAudioPort
|
||||
|
||||
class DummyMidiPort : public DummyPort {
|
||||
@ -298,6 +326,8 @@ class DummyAudioBackend : public AudioBackend {
|
||||
bool _running;
|
||||
bool _freewheeling;
|
||||
|
||||
std::string _device;
|
||||
|
||||
float _samplerate;
|
||||
size_t _samples_per_period;
|
||||
float _dsp_load;
|
||||
@ -334,6 +364,7 @@ class DummyAudioBackend : public AudioBackend {
|
||||
int register_system_ports ();
|
||||
void unregister_system_ports ();
|
||||
|
||||
std::vector<DummyAudioPort *> _system_inputs;
|
||||
std::vector<DummyPort *> _ports;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user