@@ -6,7 +6,7 @@ | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>414</width> | |||
<width>418</width> | |||
<height>306</height> | |||
</rect> | |||
</property> | |||
@@ -314,9 +314,6 @@ | |||
</item> | |||
<item row="0" column="6"> | |||
<widget class="QLabel" name="label_7"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="text"> | |||
<string>MIDI inputs:</string> | |||
</property> | |||
@@ -327,9 +324,6 @@ | |||
</item> | |||
<item row="0" column="7"> | |||
<widget class="QSpinBox" name="sb_midi_ins"> | |||
<property name="enabled"> | |||
<bool>false</bool> | |||
</property> | |||
<property name="maximum"> | |||
<number>1</number> | |||
</property> | |||
@@ -1094,6 +1094,7 @@ protected: | |||
const uint8_t size(fShmRtClientControl.readByte()); | |||
CARLA_SAFE_ASSERT_BREAK(size > 0); | |||
// FIXME variable-size stack | |||
uint8_t data[size]; | |||
for (uint8_t i=0; i<size; ++i) | |||
@@ -89,6 +89,8 @@ public: | |||
: fServer(this), | |||
fAudioPoolCopy(nullptr), | |||
fAudioTmpBuf(nullptr), | |||
fMidiBufferIn(true), | |||
fMidiBufferOut(false), | |||
fIsOffline(false), | |||
fLastPingTime(-1), | |||
fRealtimeThread(this), | |||
@@ -198,6 +200,9 @@ private: | |||
float* fAudioPoolCopy; | |||
float* fAudioTmpBuf; | |||
JackMidiPortBuffer fMidiBufferIn; | |||
JackMidiPortBuffer fMidiBufferOut; | |||
char fBaseNameAudioPool[6+1]; | |||
char fBaseNameRtClientControl[6+1]; | |||
char fBaseNameNonRtClientControl[6+1]; | |||
@@ -448,9 +453,42 @@ bool CarlaJackAppClient::handleRtData() | |||
case kPluginBridgeRtClientControlEventMidiProgram: | |||
case kPluginBridgeRtClientControlEventAllSoundOff: | |||
case kPluginBridgeRtClientControlEventAllNotesOff: | |||
case kPluginBridgeRtClientMidiEvent: | |||
break; | |||
case kPluginBridgeRtClientMidiEvent: { | |||
const uint32_t time(fShmRtClientControl.readUInt()); | |||
const uint8_t port(fShmRtClientControl.readByte()); | |||
const uint8_t size(fShmRtClientControl.readByte()); | |||
CARLA_SAFE_ASSERT_BREAK(size > 0); | |||
if (size > JackMidiPortBuffer::kMaxEventSize || ! fRealtimeThreadMutex.tryLock()) | |||
{ | |||
for (uint8_t i=0; i<size; ++i) | |||
fShmRtClientControl.readByte(); | |||
break; | |||
} | |||
if (fMidiBufferIn.count < JackMidiPortBuffer::kMaxEventCount && | |||
fMidiBufferIn.bufferPoolPos + size < JackMidiPortBuffer::kBufferPoolSize) | |||
{ | |||
jack_midi_event_t& ev(fMidiBufferIn.events[fMidiBufferIn.count++]); | |||
ev.time = time; | |||
ev.size = size; | |||
ev.buffer = fMidiBufferIn.bufferPool + fMidiBufferIn.bufferPoolPos; | |||
fMidiBufferIn.bufferPoolPos += size; | |||
for (uint8_t i=0; i<size; ++i) | |||
ev.buffer[i] = fShmRtClientControl.readByte(); | |||
} | |||
fRealtimeThreadMutex.unlock(true); | |||
// TODO multiple midi ports | |||
(void)port; | |||
break; | |||
} | |||
case kPluginBridgeRtClientProcess: { | |||
// FIXME - lock if offline | |||
const CarlaMutexTryLocker cmtl(fRealtimeThreadMutex); | |||
@@ -578,6 +616,19 @@ bool CarlaJackAppClient::handleRtData() | |||
if (needsTmpBufClear) | |||
FloatVectorOperations::clear(fAudioTmpBuf, fServer.bufferSize); | |||
// set midi buffers | |||
if (jclient->midiIns.count() > 0) | |||
{ | |||
if (JackPortState* const jport = jclient->midiIns.getFirst(nullptr)) | |||
jport->buffer = &fMidiBufferIn; | |||
} | |||
if (jclient->midiOuts.count() > 0) | |||
{ | |||
if (JackPortState* const jport = jclient->midiOuts.getFirst(nullptr)) | |||
jport->buffer = &fMidiBufferOut; | |||
} | |||
jclient->processCb(fServer.bufferSize, jclient->processCbPtr); | |||
if (fNumPorts.audioOuts > 0) | |||
@@ -612,6 +663,9 @@ bool CarlaJackAppClient::handleRtData() | |||
FloatVectorOperations::clear(fdataRealOuts, fServer.bufferSize*fNumPorts.audioOuts); | |||
} | |||
fMidiBufferIn.count = 0; | |||
fMidiBufferIn.bufferPoolPos = 0; | |||
if (fNumPorts.midiOuts > 0) | |||
carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize); | |||
} | |||
@@ -59,6 +59,32 @@ class CarlaJackAppClient; | |||
struct JackClientState; | |||
struct JackServerState; | |||
struct JackMidiPortBuffer { | |||
static const size_t kMaxEventSize = 128; | |||
static const size_t kMaxEventCount = 512; | |||
static const size_t kBufferPoolSize = kMaxEventCount*8; | |||
uint16_t count; | |||
bool isInput; | |||
jack_midi_event_t* events; | |||
size_t bufferPoolPos; | |||
jack_midi_data_t* bufferPool; | |||
JackMidiPortBuffer(const bool input) | |||
: count(0), | |||
isInput(input), | |||
events(new jack_midi_event_t[kMaxEventCount]), | |||
bufferPoolPos(0), | |||
bufferPool(new jack_midi_data_t[kBufferPoolSize]) {} | |||
~JackMidiPortBuffer() | |||
{ | |||
delete[] events; | |||
delete[] bufferPool; | |||
} | |||
}; | |||
struct JackPortState { | |||
char* name; | |||
char* fullname; | |||
@@ -15,7 +15,6 @@ | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
// need to include this first | |||
#include "libjack.hpp" | |||
CARLA_BACKEND_USE_NAMESPACE | |||
@@ -23,43 +22,90 @@ CARLA_BACKEND_USE_NAMESPACE | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
jack_nframes_t jack_midi_get_event_count(void*) | |||
jack_nframes_t jack_midi_get_event_count(void* buf) | |||
{ | |||
return 0; | |||
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, 0); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, 0); | |||
return jmidibuf->count; | |||
} | |||
CARLA_EXPORT | |||
int jack_midi_event_get(jack_midi_event_t*, void*, uint32_t) | |||
int jack_midi_event_get(jack_midi_event_t* ev, void* buf, uint32_t index) | |||
{ | |||
return ENODATA; | |||
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, EFAULT); | |||
CARLA_SAFE_ASSERT_RETURN(index < jmidibuf->count, ENODATA); | |||
std::memcpy(ev, &jmidibuf->events[index], sizeof(jack_midi_event_t)); | |||
return 0; | |||
} | |||
CARLA_EXPORT | |||
void jack_midi_clear_buffer(void*) | |||
void jack_midi_clear_buffer(void* buf) | |||
{ | |||
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput,); | |||
jmidibuf->count = 0; | |||
jmidibuf->bufferPoolPos = 0; | |||
std::memset(jmidibuf->bufferPool, 0, JackMidiPortBuffer::kBufferPoolSize); | |||
} | |||
CARLA_EXPORT | |||
void jack_midi_reset_buffer(void*) | |||
void jack_midi_reset_buffer(void* buf) | |||
{ | |||
jack_midi_clear_buffer(buf); | |||
} | |||
CARLA_EXPORT | |||
size_t jack_midi_max_event_size(void*) | |||
{ | |||
return 0; | |||
return JackMidiPortBuffer::kMaxEventSize; | |||
} | |||
CARLA_EXPORT | |||
jack_midi_data_t* jack_midi_event_reserve(void*, jack_nframes_t, size_t) | |||
jack_midi_data_t* jack_midi_event_reserve(void* buf, jack_nframes_t frame, size_t size) | |||
{ | |||
return nullptr; | |||
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(size > 0, nullptr); | |||
if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) | |||
return nullptr; | |||
if (jmidibuf->bufferPoolPos + size >= JackMidiPortBuffer::kBufferPoolSize) | |||
return nullptr; | |||
jack_midi_data_t* const jmdata = jmidibuf->bufferPool + jmidibuf->bufferPoolPos; | |||
jmidibuf->bufferPoolPos += size; | |||
jmidibuf->events[jmidibuf->count++] = { frame, size, jmdata }; | |||
std::memset(jmdata, 0, size); | |||
return jmdata; | |||
} | |||
CARLA_EXPORT | |||
int jack_midi_event_write(void*, jack_nframes_t, const jack_midi_data_t*, size_t) | |||
int jack_midi_event_write(void* buf, jack_nframes_t frame, const jack_midi_data_t* data, size_t size) | |||
{ | |||
return ENOBUFS; | |||
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); | |||
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); | |||
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, EFAULT); | |||
if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) | |||
return ENOBUFS; | |||
if (jmidibuf->bufferPoolPos + size >= JackMidiPortBuffer::kBufferPoolSize) | |||
return ENOBUFS; | |||
jack_midi_data_t* const jmdata = jmidibuf->bufferPool + jmidibuf->bufferPoolPos; | |||
jmidibuf->bufferPoolPos += size; | |||
jmidibuf->events[jmidibuf->count++] = { frame, size, jmdata }; | |||
std::memcpy(jmdata, data, size); | |||
return 0; | |||
} | |||
CARLA_EXPORT | |||