Browse Source

Event-based MIDI API for jsusfx

pull/1490/head
Jean Pierre Cimalando 3 years ago
parent
commit
c3a6c9c641
2 changed files with 130 additions and 120 deletions
  1. +118
    -113
      source/modules/jsusfx/source/jsusfx.cpp
  2. +12
    -7
      source/modules/jsusfx/source/jsusfx.h

+ 118
- 113
source/modules/jsusfx/source/jsusfx.cpp View File

@@ -76,104 +76,85 @@ static EEL_F * NSEEL_CGEN_CALL _reaper_spl(void *opaque, EEL_F *n)
static EEL_F NSEEL_CGEN_CALL _midirecv(void *opaque, INT_PTR np, EEL_F **parms) static EEL_F NSEEL_CGEN_CALL _midirecv(void *opaque, INT_PTR np, EEL_F **parms)
{ {
JsusFx *ctx = REAPER_GET_INTERFACE(opaque); JsusFx *ctx = REAPER_GET_INTERFACE(opaque);
while (ctx->midiSize > 0) {
// peek the message type
const uint8_t b = ctx->midi[0];
if ((b & 0xf0) == 0xf0) {
// 0xf0 = system exclusive message
// consume the byte
ctx->midi++;
ctx->midiSize--;
// skip until we find a 0xf7 byte
for (;;) {
// end of data stream?
if (ctx->midiSize == 0)
break;
// consume the byte
const uint8_t b = ctx->midi[0];
ctx->midi++;
ctx->midiSize--;
// end of system exclusive message?
if (b == 0xf7)
break;
}
}
else if (b & 0x80) {
// status byte
const uint8_t event = b & 0xf0;
//const uint8_t channel = b & 0x0f;
// consume the byte
ctx->midi++;
ctx->midiSize--;
// data bytes
if (ctx->midiSize >= 2) {
*parms[0] = 0;
*parms[1] = event;
if (np >= 4) {
*parms[2] = ctx->midi[0];
*parms[3] = ctx->midi[1];
} else {
*parms[2] = ctx->midi[0] + ctx->midi[1] * 256;
}
ctx->midi += 2;
ctx->midiSize -= 2;
return 1;
} else {
ctx->midiSize = 0;
return 0;
}
} else {
// data byte without a preceeding status byte? something is wrong here
ctx->midiSize--; // decrement this otherwise it is an infinite loop
ctx->displayMsg("Inconsistent midi stream %x\n", b);
if (ctx->midiInputReadPos >= ctx->midiInput.size())
return 0;

JsusFx::EventHeader event;
const uint8_t *data = nullptr;

while (!data && ctx->midiInputReadPos < ctx->midiInput.size()) {
data = &ctx->midiInput[ctx->midiInputReadPos];
memcpy(&event, data, sizeof(event));
data += sizeof(event);
ctx->midiInputReadPos += sizeof(event) + event.length;
// pass through the sysex events
if (event.length > 3) {
ctx->addOutputEvent(event.offset, data, event.length);
data = nullptr;
} }
} }
return 0;
}


static EEL_F NSEEL_CGEN_CALL _midisend(void *opaque, INT_PTR np, EEL_F **parms)
{
JsusFx *ctx = REAPER_GET_INTERFACE(opaque);
if (ctx->midiSendBufferSize + 3 > ctx->midiSendBufferCapacity) {
if (!data)
return 0; return 0;
} else if (np == 3) {
const int offset = (int)*parms[0];
(void)offset; // sample offset into current block. not used
const uint8_t msg1 = (uint8_t)*parms[1];
const uint16_t msg23 = (uint16_t)*parms[2];
const uint8_t msg2 = (msg23 >> 0) & 0xff;
const uint8_t msg3 = (msg23 >> 8) & 0xff;


//printf("midi send. cmd=%x, msg2=%d, msg3=%x\n", msg1, msg2, msg3);
uint8_t msg1 = 0;
uint8_t msg2 = 0;
uint8_t msg3 = 0;


ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg1;
ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg2;
ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg3;
switch (event.length)
{
case 3:
msg3 = data[2];
// fall through
case 2:
msg2 = data[1];
// fall through
case 1:
msg1 = data[0];
break;
}


return msg1;
*parms[0] = event.offset;
*parms[1] = msg1;
if (np >= 4) {
*parms[2] = msg2;
*parms[3] = msg3;
} else {
*parms[2] = msg2 + msg3 * 256;
}

return 1;
}

static EEL_F NSEEL_CGEN_CALL _midisend(void *opaque, INT_PTR np, EEL_F **parms)
{
JsusFx *ctx = REAPER_GET_INTERFACE(opaque);
int offset;
uint8_t msg1;
uint8_t msg2;
uint8_t msg3;
if (np == 3) {
offset = (int)*parms[0];
msg1 = (uint8_t)*parms[1];
const unsigned msg23 = (unsigned)*parms[2];
msg2 = (uint8_t)(msg23 & 0xff);
msg3 = (uint8_t)(msg23 >> 8);
} else if (np == 4) { } else if (np == 4) {
const int offset = (int)*parms[0];
(void)offset; // sample offset into current block. not used
const uint8_t msg1 = (uint8_t)*parms[1];
const uint8_t msg2 = (uint8_t)*parms[2];
const uint8_t msg3 = (uint8_t)*parms[3];
ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg1;
ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg2;
ctx->midiSendBuffer[ctx->midiSendBufferSize++] = msg3;
return msg1;
offset = (int)*parms[0];
msg1 = (uint8_t)*parms[1];
msg2 = (uint8_t)*parms[2];
msg3 = (uint8_t)*parms[3];
} else { } else {
return 0; return 0;
} }
const uint8_t data[] = {msg1, msg2, msg3};
if (!ctx->addOutputEvent(offset, data, 3))
return 0;
return msg1;
} }


static EEL_F NSEEL_CGEN_CALL _midisend_buf(void *opaque, INT_PTR np, EEL_F **parms) static EEL_F NSEEL_CGEN_CALL _midisend_buf(void *opaque, INT_PTR np, EEL_F **parms)
@@ -181,21 +162,11 @@ static EEL_F NSEEL_CGEN_CALL _midisend_buf(void *opaque, INT_PTR np, EEL_F **par
JsusFx *ctx = REAPER_GET_INTERFACE(opaque); JsusFx *ctx = REAPER_GET_INTERFACE(opaque);
if (np == 3) { if (np == 3) {
const int offset = (int)*parms[0]; const int offset = (int)*parms[0];
(void)offset; // sample offset into current block. not used
void *buf = (void*)parms[1];
const uint8_t *buf = (const uint8_t*)parms[1];
const int len = (int)*parms[2]; const int len = (int)*parms[2];
// note : should we auto-detect SysEx messages? Reaper does it, but it seems like a bad idea..
// auto-detection would automagically determine the message's length here by parsing the message stream
if (len < 0 || ctx->midiSendBufferSize + len > ctx->midiSendBufferCapacity) {
if (!ctx->addOutputEvent(offset, buf, len))
return 0; return 0;
} else {
memcpy(&ctx->midiSendBuffer[ctx->midiSendBufferSize], buf, len);
ctx->midiSendBufferSize += len;
return len;
}
return len;
} else { } else {
return 0; return 0;
} }
@@ -479,12 +450,9 @@ JsusFx::JsusFx(JsusFxPathLibrary &_pathLibrary)
fileAPI = nullptr; fileAPI = nullptr;
midi = nullptr;
midiSize = 0;
midiSendBuffer = nullptr;
midiSendBufferCapacity = 0;
midiSendBufferSize = 0;
midiInput.reserve(8192);
midiOutput.reserve(8192);
midiInputReadPos = 0;
gfx = nullptr; gfx = nullptr;
gfx_w = 0; gfx_w = 0;
@@ -1021,15 +989,42 @@ void JsusFx::moveSlider(int idx, float value, int normalizeSlider) {
computeSlider |= sliders[idx].setValue(value); computeSlider |= sliders[idx].setValue(value);
} }


void JsusFx::setMidi(const void * _midi, int numBytes) {
midi = (uint8_t*)_midi;
midiSize = numBytes;
bool JsusFx::addInputEvent(int offset, const uint8_t *data, int length)
{
EventHeader event;
event.offset = offset;
event.length = length;
std::copy((char*)&event, (char*)&event + sizeof(event), std::back_inserter(midiInput));
std::copy(data, data + length, std::back_inserter(midiInput));
return true;
}

bool JsusFx::addOutputEvent(int offset, const uint8_t *data, int length)
{
EventHeader event;
event.offset = offset;
event.length = length;
std::copy((char*)&event, (char*)&event + sizeof(event), std::back_inserter(midiOutput));
std::copy(data, data + length, std::back_inserter(midiOutput));
return true;
} }


void JsusFx::setMidiSendBuffer(void * buffer, int numBytes) {
midiSendBuffer = (uint8_t*)buffer;
midiSendBufferCapacity = numBytes;
midiSendBufferSize = 0;
bool JsusFx::iterateOutputEvents(size_t &iterPos, int &offset, const uint8_t *&data, int &length)
{
if (iterPos < midiOutput.size()) {
EventHeader event;
data = &midiOutput[iterPos];
memcpy(&event, data, sizeof(event));
data += sizeof(event);
iterPos += sizeof(event) + event.length;
offset = event.offset;
length = event.length;
return true;
}
else {
return false;
}
} }


void JsusFx::setTransportValues( void JsusFx::setTransportValues(
@@ -1049,6 +1044,9 @@ void JsusFx::setTransportValues(
} }


bool JsusFx::process(const float **input, float **output, int size, int numInputChannels, int numOutputChannels) { bool JsusFx::process(const float **input, float **output, int size, int numInputChannels, int numOutputChannels) {
midiInputReadPos = 0;
midiOutput.clear();
if ( codeSample == NULL ) if ( codeSample == NULL )
return false; return false;


@@ -1070,10 +1068,15 @@ bool JsusFx::process(const float **input, float **output, int size, int numInput
output[c][i] = *spl[c]; output[c][i] = *spl[c];
} }
midiInput.clear();
return true; return true;
} }


bool JsusFx::process64(const double **input, double **output, int size, int numInputChannels, int numOutputChannels) { bool JsusFx::process64(const double **input, double **output, int size, int numInputChannels, int numOutputChannels) {
midiInputReadPos = 0;
midiOutput.clear();
if ( codeSample == NULL ) if ( codeSample == NULL )
return false; return false;


@@ -1095,6 +1098,8 @@ bool JsusFx::process64(const double **input, double **output, int size, int numI
output[c][i] = *spl[c]; output[c][i] = *spl[c];
} }
midiInput.clear();
return true; return true;
} }




+ 12
- 7
source/modules/jsusfx/source/jsusfx.h View File

@@ -205,14 +205,18 @@ public:
JsusFxFileAPI *fileAPI; JsusFxFileAPI *fileAPI;
JsusFx_FileInfo fileInfos[kMaxFileInfos]; JsusFx_FileInfo fileInfos[kMaxFileInfos];

struct EventHeader {
int offset;
int length;
};

// midi receive buffer. pointer is incremented and the size decremented by the appropriate number of bytes whenever midirecv is called from within the script // midi receive buffer. pointer is incremented and the size decremented by the appropriate number of bytes whenever midirecv is called from within the script
uint8_t *midi;
int midiSize;
std::vector<uint8_t> midiInput;
size_t midiInputReadPos;
// midi send buffer. the pointer and capacity stay the same. size is incremented by the number of bytes written by midisend or midisend_buf // midi send buffer. the pointer and capacity stay the same. size is incremented by the number of bytes written by midisend or midisend_buf
uint8_t * midiSendBuffer;
int midiSendBufferCapacity;
int midiSendBufferSize;
std::vector<uint8_t> midiOutput;
JsusFxGfx *gfx; JsusFxGfx *gfx;
int gfx_w; int gfx_w;
@@ -230,8 +234,9 @@ public:
// move slider, normalizeSlider is used to normalize the value to a constant (0 means no normalization) // move slider, normalizeSlider is used to normalize the value to a constant (0 means no normalization)
void moveSlider(int idx, float value, int normalizeSlider = 0); void moveSlider(int idx, float value, int normalizeSlider = 0);
void setMidi(const void * midi, int numBytes);
void setMidiSendBuffer(void * buffer, int maxBytes);
bool addInputEvent(int offset, const uint8_t *data, int length);
bool addOutputEvent(int offset, const uint8_t *data, int length);
bool iterateOutputEvents(size_t &iterPos, int &offset, const uint8_t *&data, int &length);
void setTransportValues( void setTransportValues(
const double tempo, const double tempo,


Loading…
Cancel
Save