2010-01-24 20:46:33 +00:00
|
|
|
#include <jack/jack.h>
|
|
|
|
#include <jack/midiport.h>
|
|
|
|
#include "cvout.h"
|
|
|
|
|
|
|
|
void CVOut::shutdown()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int CVOut::process(jack_nframes_t nframes)
|
|
|
|
{
|
|
|
|
if (!m_ready) return 0;
|
|
|
|
|
|
|
|
void *midi_in = jack_port_get_buffer(m_midi_in, nframes);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < m_mapping_list.size(); i++) {
|
|
|
|
m_buffers[i] = static_cast<sample_t *>(jack_port_get_buffer(m_ports[i], nframes));
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t event_count = jack_midi_get_event_count(midi_in);
|
|
|
|
jack_nframes_t event_index = 0;
|
|
|
|
jack_midi_event_t ev;
|
|
|
|
|
|
|
|
if (0 < event_count) jack_midi_event_get(&ev, midi_in, event_index);
|
|
|
|
|
|
|
|
for (jack_nframes_t f = 0; f < nframes; f++) {
|
|
|
|
while (ev.time == f && event_index < event_count) {
|
2010-01-24 23:05:34 +00:00
|
|
|
int channel = ev.buffer[0] & 0x0F;
|
|
|
|
MappingList::iterator it;
|
2010-01-24 20:46:33 +00:00
|
|
|
|
2010-01-24 23:05:34 +00:00
|
|
|
switch (ev.buffer[0] & 0xF0) {
|
|
|
|
case 0xB0:
|
|
|
|
if (ev.buffer[1] == 99) {
|
|
|
|
m_nrpn_msb[channel] = ev.buffer[2];
|
|
|
|
m_nrpn[channel] = true;
|
|
|
|
} else if (ev.buffer[1] == 98) {
|
|
|
|
m_nrpn_lsb[channel] = ev.buffer[2];
|
|
|
|
m_nrpn[channel] = true;
|
|
|
|
} else if (ev.buffer[1] == 101) {
|
|
|
|
m_nrpn_msb[channel] = ev.buffer[2];
|
|
|
|
m_nrpn[channel] = false;
|
|
|
|
} else if (ev.buffer[1] == 100) {
|
|
|
|
m_nrpn_lsb[channel] = ev.buffer[2];
|
|
|
|
m_nrpn[channel] = false;
|
|
|
|
} else {
|
|
|
|
if (ev.buffer[1] == 6 || ev.buffer[1] == 38) {
|
|
|
|
ControllerType type = m_nrpn[channel] ? TYPE_NRPN : TYPE_RPN;
|
|
|
|
bool msb = ev.buffer[1] == 6;
|
|
|
|
|
|
|
|
for (it = m_it_begin; it != m_it_end; ++it) {
|
|
|
|
Mapping *m = &(*it);
|
|
|
|
if (!m->match(type, channel)) continue;
|
|
|
|
if (m_nrpn_msb[channel] != m->ccmsb) continue;
|
|
|
|
if (m_nrpn_lsb[channel] != m->cclsb) continue;
|
|
|
|
|
|
|
|
if (msb) {
|
|
|
|
if (m->has_lsb) {
|
|
|
|
m->cur_mv = ev.buffer[2] << 7;
|
|
|
|
} else {
|
|
|
|
m->cur_mv = ev.buffer[2];
|
|
|
|
m->interp_cvout(m_tick);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m->cur_mv &= ~0x7F;
|
|
|
|
m->cur_mv |= ev.buffer[2];
|
|
|
|
m->interp_cvout(m_tick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (it = m_it_begin; it != m_it_end; ++it) {
|
|
|
|
Mapping *m = &(*it);
|
|
|
|
if (!m->match(TYPE_CC, channel)) continue;
|
|
|
|
|
|
|
|
if (ev.buffer[1] == m->ccmsb) {
|
|
|
|
if (m->has_lsb) {
|
|
|
|
m->cur_mv = ev.buffer[2] << 7;
|
|
|
|
} else {
|
|
|
|
m->cur_mv = ev.buffer[2];
|
|
|
|
m->interp_cvout(m_tick);
|
|
|
|
}
|
|
|
|
} else if (ev.buffer[1] == m->cclsb) {
|
|
|
|
m->cur_mv &= ~0x7F;
|
|
|
|
m->cur_mv |= ev.buffer[2];
|
|
|
|
m->interp_cvout(m_tick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xE0:
|
2010-01-24 20:46:33 +00:00
|
|
|
for (it = m_it_begin; it != m_it_end; ++it) {
|
|
|
|
Mapping *m = &(*it);
|
2010-01-24 23:05:34 +00:00
|
|
|
if (!m->match(TYPE_PB, channel)) continue;
|
|
|
|
|
|
|
|
m->cur_mv = ev.buffer[1] | (ev.buffer[2] << 7);
|
|
|
|
m->interp_cvout(m_tick);
|
2010-01-24 20:46:33 +00:00
|
|
|
}
|
2010-01-24 23:05:34 +00:00
|
|
|
break;
|
2010-01-24 20:46:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
event_index++;
|
|
|
|
if (event_index < event_count) jack_midi_event_get(&ev, midi_in, event_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int port = 0;
|
|
|
|
MappingList::iterator it;
|
|
|
|
for (it = m_it_begin; it != m_it_end; ++it, port++) {
|
|
|
|
const Mapping *m = &(*it);
|
|
|
|
|
|
|
|
*m_buffers[port]++ = m->last_cv;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tick++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVOut::start()
|
|
|
|
{
|
|
|
|
m_ready = false;
|
|
|
|
m_tick = 0;
|
|
|
|
|
|
|
|
if (m_mapping_list.size() == 0) return;
|
|
|
|
|
|
|
|
m_ports = new jack_port_t *[m_mapping_list.size()];
|
|
|
|
m_buffers = new sample_t *[m_mapping_list.size()];
|
|
|
|
|
2010-01-26 13:31:34 +00:00
|
|
|
if (!open(m_config_name.empty() ? "m2cv_out" : m_config_name.c_str())) exit(EXIT_FAILURE);
|
2010-01-24 20:46:33 +00:00
|
|
|
|
|
|
|
m_midi_in = port_register("midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
|
|
|
|
|
|
|
|
MappingList::iterator it_begin = m_mapping_list.begin();
|
|
|
|
MappingList::iterator it_end = m_mapping_list.end();
|
|
|
|
|
|
|
|
int port = 0;
|
|
|
|
MappingList::iterator it;
|
|
|
|
for (it = it_begin; it != it_end; ++it, port++) {
|
|
|
|
Mapping *m = &(*it);
|
|
|
|
m_ports[port] = port_register(m->name.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
|
|
|
|
|
|
|
m->latency_ticks = m_sample_rate * m->latency / 1000.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_it_end = it_end;
|
|
|
|
m_it_begin = it_begin;
|
|
|
|
m_ready = true;
|
|
|
|
}
|