mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-24 05:25:12 +00:00
kind of MIDI output
This commit is contained in:
parent
45ce940d66
commit
f689409f02
7 changed files with 126 additions and 9 deletions
|
@ -61,6 +61,10 @@ bool TAMidiIn::gather() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TAMidiOut::send(const TAMidiMessage& what) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TAMidiIn::isDeviceOpen() {
|
bool TAMidiIn::isDeviceOpen() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "rtmidi.h"
|
#include "rtmidi.h"
|
||||||
#include "../ta-log.h"
|
#include "../ta-log.h"
|
||||||
|
#include "taAudio.h"
|
||||||
|
|
||||||
// --- IN ---
|
// --- IN ---
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ bool TAMidiInRtMidi::openDevice(String name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isOpen=portOpen;
|
isOpen=portOpen;
|
||||||
|
if (!portOpen) logW("could not find MIDI in device...\n");
|
||||||
return portOpen;
|
return portOpen;
|
||||||
} catch (RtMidiError& e) {
|
} catch (RtMidiError& e) {
|
||||||
logW("could not open MIDI in device! %s\n",e.what());
|
logW("could not open MIDI in device! %s\n",e.what());
|
||||||
|
@ -120,9 +122,40 @@ bool TAMidiInRtMidi::quit() {
|
||||||
|
|
||||||
// --- OUT ---
|
// --- OUT ---
|
||||||
|
|
||||||
bool TAMidiOutRtMidi::send(TAMidiMessage& what) {
|
bool TAMidiOutRtMidi::send(const TAMidiMessage& what) {
|
||||||
// TODO
|
if (!isOpen) return false;
|
||||||
return false;
|
if (what.type<0x80) return false;
|
||||||
|
size_t len=0;
|
||||||
|
switch (what.type&0xf0) {
|
||||||
|
case TA_MIDI_NOTE_OFF:
|
||||||
|
case TA_MIDI_NOTE_ON:
|
||||||
|
case TA_MIDI_AFTERTOUCH:
|
||||||
|
case TA_MIDI_CONTROL:
|
||||||
|
case TA_MIDI_PITCH_BEND:
|
||||||
|
len=3;
|
||||||
|
break;
|
||||||
|
case TA_MIDI_PROGRAM:
|
||||||
|
case TA_MIDI_CHANNEL_AFTERTOUCH:
|
||||||
|
len=2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len==0) switch (what.type) {
|
||||||
|
case TA_MIDI_SYSEX: // currently not supported :<
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case TA_MIDI_MTC_FRAME:
|
||||||
|
case TA_MIDI_SONG_SELECT:
|
||||||
|
len=2;
|
||||||
|
break;
|
||||||
|
case TA_MIDI_POSITION:
|
||||||
|
len=3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
len=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
port->sendMessage((const unsigned char*)&what.type,len);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TAMidiOutRtMidi::isDeviceOpen() {
|
bool TAMidiOutRtMidi::isDeviceOpen() {
|
||||||
|
@ -143,6 +176,7 @@ bool TAMidiOutRtMidi::openDevice(String name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isOpen=portOpen;
|
isOpen=portOpen;
|
||||||
|
if (!portOpen) logW("could not find MIDI out device...\n");
|
||||||
return portOpen;
|
return portOpen;
|
||||||
} catch (RtMidiError& e) {
|
} catch (RtMidiError& e) {
|
||||||
logW("could not open MIDI out device! %s\n",e.what());
|
logW("could not open MIDI out device! %s\n",e.what());
|
||||||
|
|
|
@ -40,7 +40,7 @@ class TAMidiOutRtMidi: public TAMidiOut {
|
||||||
RtMidiOut* port;
|
RtMidiOut* port;
|
||||||
bool isOpen;
|
bool isOpen;
|
||||||
public:
|
public:
|
||||||
bool send(TAMidiMessage& what);
|
bool send(const TAMidiMessage& what);
|
||||||
bool isDeviceOpen();
|
bool isDeviceOpen();
|
||||||
bool openDevice(String name);
|
bool openDevice(String name);
|
||||||
bool closeDevice();
|
bool closeDevice();
|
||||||
|
|
|
@ -99,6 +99,16 @@ struct TAMidiMessage {
|
||||||
void submitSysEx(std::vector<unsigned char> data);
|
void submitSysEx(std::vector<unsigned char> data);
|
||||||
void done();
|
void done();
|
||||||
|
|
||||||
|
TAMidiMessage(unsigned char t, unsigned char d0, unsigned char d1):
|
||||||
|
time(0.0),
|
||||||
|
type(t),
|
||||||
|
sysExData(NULL),
|
||||||
|
sysExLen(0) {
|
||||||
|
memset(&data,0,sizeof(data));
|
||||||
|
data[0]=d0;
|
||||||
|
data[1]=d1;
|
||||||
|
}
|
||||||
|
|
||||||
TAMidiMessage():
|
TAMidiMessage():
|
||||||
time(0.0),
|
time(0.0),
|
||||||
type(0),
|
type(0),
|
||||||
|
@ -127,7 +137,7 @@ class TAMidiIn {
|
||||||
class TAMidiOut {
|
class TAMidiOut {
|
||||||
std::queue<TAMidiMessage> queue;
|
std::queue<TAMidiMessage> queue;
|
||||||
public:
|
public:
|
||||||
bool send(TAMidiMessage& what);
|
virtual bool send(const TAMidiMessage& what);
|
||||||
virtual bool isDeviceOpen();
|
virtual bool isDeviceOpen();
|
||||||
virtual bool openDevice(String name);
|
virtual bool openDevice(String name);
|
||||||
virtual bool closeDevice();
|
virtual bool closeDevice();
|
||||||
|
|
|
@ -790,13 +790,20 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
||||||
}
|
}
|
||||||
speedAB=false;
|
speedAB=false;
|
||||||
playing=true;
|
playing=true;
|
||||||
|
skipping=true;
|
||||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true);
|
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true);
|
||||||
while (playing && curOrder<goal) {
|
while (playing && curOrder<goal) {
|
||||||
if (nextTick(preserveDrift)) return;
|
if (nextTick(preserveDrift)) {
|
||||||
|
skipping=false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int oldOrder=curOrder;
|
int oldOrder=curOrder;
|
||||||
while (playing && curRow<goalRow) {
|
while (playing && curRow<goalRow) {
|
||||||
if (nextTick(preserveDrift)) return;
|
if (nextTick(preserveDrift)) {
|
||||||
|
skipping=false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (oldOrder!=curOrder) break;
|
if (oldOrder!=curOrder) break;
|
||||||
}
|
}
|
||||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
|
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
|
||||||
|
@ -816,6 +823,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
||||||
if (!preserveDrift) {
|
if (!preserveDrift) {
|
||||||
ticks=1;
|
ticks=1;
|
||||||
}
|
}
|
||||||
|
skipping=false;
|
||||||
cmdStream.clear();
|
cmdStream.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2864,6 +2872,16 @@ bool DivEngine::initAudioBackend() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (output->midiOut) {
|
||||||
|
String outName=getConfString("midiOutDevice","");
|
||||||
|
if (!outName.empty()) {
|
||||||
|
// try opening device
|
||||||
|
logI("opening MIDI output.\n");
|
||||||
|
if (!output->midiOut->openDevice(outName)) {
|
||||||
|
logW("could not open MIDI output device!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2876,6 +2894,12 @@ bool DivEngine::deinitAudioBackend() {
|
||||||
output->midiIn->closeDevice();
|
output->midiIn->closeDevice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (output->midiOut) {
|
||||||
|
if (output->midiOut->isDeviceOpen()) {
|
||||||
|
logI("closing MIDI output.\n");
|
||||||
|
output->midiOut->closeDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
output->quitMidi();
|
output->quitMidi();
|
||||||
output->quit();
|
output->quit();
|
||||||
delete output;
|
delete output;
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct DivChannelState {
|
||||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
|
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
|
||||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
|
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
|
||||||
|
|
||||||
int midiNote;
|
int midiNote, curMidiNote;
|
||||||
|
|
||||||
DivChannelState():
|
DivChannelState():
|
||||||
note(-1),
|
note(-1),
|
||||||
|
@ -129,7 +129,8 @@ struct DivChannelState {
|
||||||
shorthandPorta(false),
|
shorthandPorta(false),
|
||||||
noteOnInhibit(false),
|
noteOnInhibit(false),
|
||||||
resetArp(false),
|
resetArp(false),
|
||||||
midiNote(-1) {}
|
midiNote(-1),
|
||||||
|
curMidiNote(-1) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivNoteEvent {
|
struct DivNoteEvent {
|
||||||
|
@ -194,6 +195,7 @@ class DivEngine {
|
||||||
bool cmdStreamEnabled;
|
bool cmdStreamEnabled;
|
||||||
bool softLocked;
|
bool softLocked;
|
||||||
bool firstTick;
|
bool firstTick;
|
||||||
|
bool skipping;
|
||||||
int softLockCount;
|
int softLockCount;
|
||||||
int ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
int ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
||||||
double divider;
|
double divider;
|
||||||
|
@ -712,6 +714,7 @@ class DivEngine {
|
||||||
cmdStreamEnabled(false),
|
cmdStreamEnabled(false),
|
||||||
softLocked(false),
|
softLocked(false),
|
||||||
firstTick(false),
|
firstTick(false),
|
||||||
|
skipping(false),
|
||||||
softLockCount(0),
|
softLockCount(0),
|
||||||
ticks(0),
|
ticks(0),
|
||||||
curRow(0),
|
curRow(0),
|
||||||
|
|
|
@ -172,7 +172,49 @@ int DivEngine::dispatchCmd(DivCommand c) {
|
||||||
if (cmdStreamEnabled && cmdStream.size()<2000) {
|
if (cmdStreamEnabled && cmdStream.size()<2000) {
|
||||||
cmdStream.push_back(c);
|
cmdStream.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipping && output->midiOut!=NULL) {
|
||||||
|
if (output->midiOut->isDeviceOpen()) {
|
||||||
|
int scaledVol=(chan[c.chan].volume*127)/MAX(1,chan[c.chan].volMax);
|
||||||
|
if (scaledVol<0) scaledVol=0;
|
||||||
|
if (scaledVol>127) scaledVol=127;
|
||||||
|
switch (c.cmd) {
|
||||||
|
case DIV_CMD_NOTE_ON:
|
||||||
|
case DIV_CMD_LEGATO:
|
||||||
|
if (chan[c.chan].curMidiNote>=0) {
|
||||||
|
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
|
||||||
|
}
|
||||||
|
if (c.value!=DIV_NOTE_NULL) chan[c.chan].curMidiNote=c.value+12;
|
||||||
|
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
|
||||||
|
break;
|
||||||
|
case DIV_CMD_NOTE_OFF:
|
||||||
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
|
if (chan[c.chan].curMidiNote>=0) {
|
||||||
|
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
|
||||||
|
}
|
||||||
|
chan[c.chan].curMidiNote=-1;
|
||||||
|
break;
|
||||||
|
case DIV_CMD_INSTRUMENT:
|
||||||
|
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
|
||||||
|
break;
|
||||||
|
case DIV_CMD_VOLUME:
|
||||||
|
//output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x07,scaledVol));
|
||||||
|
break;
|
||||||
|
case DIV_CMD_PITCH: {
|
||||||
|
int pitchBend=8192+(c.value<<5);
|
||||||
|
if (pitchBend<0) pitchBend=0;
|
||||||
|
if (pitchBend>16383) pitchBend=16383;
|
||||||
|
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.chan=dispatchChanOfChan[c.dis];
|
c.chan=dispatchChanOfChan[c.dis];
|
||||||
|
|
||||||
return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c);
|
return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue