add a midi->audio dummy backend mode.
this allows to easily debug latency compensation as well as visualize lost midi events.
This commit is contained in:
parent
c7affd79c2
commit
4d370b8942
|
@ -322,6 +322,7 @@ DummyAudioBackend::enumerate_midi_options () const
|
|||
_midi_options.push_back (_("8 in, 8 out, Silence"));
|
||||
_midi_options.push_back (_("Midi Event Generators"));
|
||||
_midi_options.push_back (_("8 in, 8 out, Loopback"));
|
||||
_midi_options.push_back (_("MIDI to Audio, Loopback"));
|
||||
}
|
||||
return _midi_options;
|
||||
}
|
||||
|
@ -347,6 +348,10 @@ DummyAudioBackend::set_midi_option (const std::string& opt)
|
|||
_n_midi_inputs = _n_midi_outputs = 8;
|
||||
_midi_mode = MidiLoopback;
|
||||
}
|
||||
else if (opt == _("MIDI to Audio, Loopback")) {
|
||||
_n_midi_inputs = _n_midi_outputs = UINT32_MAX;
|
||||
_midi_mode = MidiToAudio;
|
||||
}
|
||||
else {
|
||||
_n_midi_inputs = _n_midi_outputs = 0;
|
||||
}
|
||||
|
@ -748,10 +753,14 @@ DummyAudioBackend::register_system_ports()
|
|||
gt = DummyAudioPort::Silence;
|
||||
}
|
||||
|
||||
if (_midi_mode == MidiToAudio) {
|
||||
gt = DummyAudioPort::Loopback;
|
||||
}
|
||||
|
||||
const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
|
||||
const int a_out = _n_outputs > 0 ? _n_outputs : 8;
|
||||
const int m_ins = _n_midi_inputs;
|
||||
const int m_out = _n_midi_outputs;
|
||||
const int m_ins = _n_midi_inputs == UINT_MAX ? 0 : _n_midi_inputs;
|
||||
const int m_out = _n_midi_outputs == UINT_MAX ? a_ins : _n_midi_outputs;
|
||||
|
||||
/* with 'Loopback' there is exactly once cycle latency, divide it between In + Out; */
|
||||
const size_t l_in = _samples_per_period * .25;
|
||||
|
@ -1161,7 +1170,7 @@ DummyAudioBackend::main_process_thread ()
|
|||
}
|
||||
_processed_samples += _samples_per_period;
|
||||
|
||||
if (_device == _("Loopback")) {
|
||||
if (_device == _("Loopback") && _midi_mode != MidiToAudio) {
|
||||
int opn = 0;
|
||||
int opc = _system_outputs.size();
|
||||
for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++opn) {
|
||||
|
@ -1179,6 +1188,15 @@ DummyAudioBackend::main_process_thread ()
|
|||
(*it)->set_loopback (op->const_buffer());
|
||||
}
|
||||
}
|
||||
else if (_midi_mode == MidiToAudio) {
|
||||
int opn = 0;
|
||||
int opc = _system_midi_out.size();
|
||||
for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++opn) {
|
||||
DummyMidiPort* op = _system_midi_out[(opn % opc)];
|
||||
op->get_buffer(0); // mix-down
|
||||
(*it)->midi_to_wavetable (op->const_buffer(), _samples_per_period);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_freewheeling) {
|
||||
const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
|
||||
|
@ -1585,6 +1603,34 @@ void DummyAudioPort::setup_generator (GeneratorType const g, float const sampler
|
|||
}
|
||||
}
|
||||
|
||||
void DummyAudioPort::midi_to_wavetable (DummyMidiBuffer const * const src, size_t n_samples)
|
||||
{
|
||||
memset(_wavetable, 0, n_samples * sizeof(float));
|
||||
/* generate an audio spike for every midi message
|
||||
* to verify layency-compensation alignment
|
||||
* (here: midi-out playback-latency + audio-in capture-latency)
|
||||
*/
|
||||
for (DummyMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
|
||||
const pframes_t t = (*it)->timestamp();
|
||||
assert(t < n_samples);
|
||||
// somewhat arbitrary mapping for quick visual feedback
|
||||
float v = -.5f;
|
||||
if ((*it)->size() == 3) {
|
||||
const unsigned char *d = (*it)->const_data();
|
||||
if ((d[0] & 0xf0) == 0x90) { // note on
|
||||
v = .25f + d[2] / 512.f;
|
||||
}
|
||||
else if ((d[0] & 0xf0) == 0x80) { // note off
|
||||
v = .3f - d[2] / 640.f;
|
||||
}
|
||||
else if ((d[0] & 0xf0) == 0xb0) { // CC
|
||||
v = -.1f - d[2] / 256.f;
|
||||
}
|
||||
}
|
||||
_wavetable[t] += v;
|
||||
}
|
||||
}
|
||||
|
||||
float DummyAudioPort::grandf ()
|
||||
{
|
||||
// Gaussian White Noise
|
||||
|
|
|
@ -160,6 +160,7 @@ class DummyAudioPort : public DummyPort {
|
|||
};
|
||||
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)); }
|
||||
void midi_to_wavetable (DummyMidiBuffer const * const src, size_t n_samples);
|
||||
|
||||
private:
|
||||
Sample _buffer[8192];
|
||||
|
@ -368,6 +369,7 @@ class DummyAudioBackend : public AudioBackend {
|
|||
MidiNoEvents,
|
||||
MidiGenerator,
|
||||
MidiLoopback,
|
||||
MidiToAudio,
|
||||
};
|
||||
|
||||
std::string _instance_name;
|
||||
|
|
Loading…
Reference in New Issue
Block a user