furnace/src/gui/sysEx.cpp

159 lines
4.5 KiB
C++
Raw Normal View History

#include "gui.h"
#include "../ta-log.h"
bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) {
SafeReader reader(data,len);
2022-05-08 07:07:58 +00:00
if (!midiMap.yamahaFMResponse) return true;
try {
unsigned char isSysEx=reader.readC();
if (isSysEx!=0xf0) {
logW("but this isn't a SysEx! (%x)",isSysEx);
return false;
}
unsigned char vendor=reader.readC();
if (vendor!=0x43) {
logV("not Yamaha. skipping.");
return true;
}
unsigned char channel=reader.readC();
logV("channel: %d",channel);
if (channel>15) {
logV("not a valid one");
return true;
}
unsigned char msgType=reader.readC();
unsigned short msgLen=reader.readS_BE();
std::vector<DivInstrument*> instruments;
switch (msgType) {
case 0x03: { // VCED - voice data
logD("reading VCED...");
DivInstrument* ins=new DivInstrument;
ins->type=DIV_INS_FM;
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[i];
op.ar=reader.readC();
op.dr=reader.readC();
op.d2r=reader.readC();
op.rr=reader.readC();
op.sl=15-reader.readC();
reader.readC(); // LS - ignore
op.rs=reader.readC();
reader.readC(); // EBS - ignore
op.am=reader.readC();
reader.readC(); // KVS - ignore
op.tl=3+((99-reader.readC())*124)/99;
unsigned char freq=reader.readC();
logV("OP%d freq: %d",i,freq);
op.mult=freq>>2;
op.dt2=freq&3;
op.dt=reader.readC();
}
ins->fm.alg=reader.readC();
ins->fm.fb=reader.readC();
reader.readC(); // LFO speed - ignore
reader.readC(); // LFO delay - ignore
reader.readC(); // PMD
reader.readC(); // AMD
reader.readC(); // LFO sync
reader.readC(); // LFO shape
ins->fm.fms=reader.readC();
ins->fm.ams=reader.readC();
reader.readC(); // transpose
reader.readC(); // poly/mono
reader.readC(); // pitch bend range
reader.readC(); // porta mode
reader.readC(); // porta time
reader.readC(); // FC volume
reader.readC(); // sustain
reader.readC(); // portamento
reader.readC(); // chorus
reader.readC(); // mod wheel pitch
reader.readC(); // mod wheel amp
reader.readC(); // breath pitch
reader.readC(); // breath amp
reader.readC(); // breath pitch bias
reader.readC(); // breath EG bias
ins->name=reader.readString(10);
for (int i=0; i<7; i++) { // reserved (except the last one, which we don't support yet)
reader.readC();
}
// TX81Z-specific data
if (hasACED) {
hasACED=false;
ins->type=DIV_INS_OPZ;
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[i];
op.egt=acedData[(5*i)+0];
if (op.egt) {
op.dt=acedData[(5*i)+1];
}
op.dvb=acedData[(5*i)+2];
op.ws=acedData[(5*i)+3];
op.ksl=acedData[(5*i)+4];
op.dam=acedData[20];
}
}
instruments.push_back(ins);
break;
}
case 0x7e: { // ACED - TX81Z extended data
logD("reading ACED...");
String acedMagic=reader.readString(10);
if (acedMagic!="LM 8976AE") {
logD("not TX81Z ACED data");
break;
}
reader.read(acedData,23);
hasACED=true;
break;
}
}
if (!reader.seek(6+msgLen,SEEK_SET)) {
logW("couldn't seek for checksum!");
for (DivInstrument* i: instruments) delete i;
return false;
}
unsigned char checkSum=reader.readC();
unsigned char localCheckSum=0xff;
if (!reader.seek(6,SEEK_SET)) {
logW("couldn't seek for checksum!");
for (DivInstrument* i: instruments) delete i;
return false;
}
for (unsigned short i=0; i<msgLen; i++) {
localCheckSum+=reader.readC();
}
localCheckSum=(localCheckSum&0x7f)^0x7f;
logD("checksums: %.2x %.2x",checkSum,localCheckSum);
if (checkSum!=localCheckSum) {
logW("checksum invalid!");
return false;
}
for (DivInstrument* i: instruments) {
logI("got instrument from MIDI: %s",i->name);
e->addInstrumentPtr(i);
curIns=e->song.insLen-1;
}
} catch (EndOfFileException e) {
logW("end of data already?");
return false;
}
return true;
}