Browse Source

libjack: support for midi out

tags/1.9.8
falkTX 8 years ago
parent
commit
99fe119177
7 changed files with 169 additions and 84 deletions
  1. +0
    -6
      resources/ui/carla_add_jack.ui
  2. +1
    -1
      source/backend/engine/CarlaEngineBridge.cpp
  3. +2
    -2
      source/backend/plugin/CarlaPluginJack.cpp
  4. +7
    -5
      source/bridges-plugin/CarlaBridgeLV2.cpp
  5. +141
    -63
      source/libjack/libjack.cpp
  6. +13
    -5
      source/libjack/libjack.hpp
  7. +5
    -2
      source/libjack/libjack_midi.cpp

+ 0
- 6
resources/ui/carla_add_jack.ui View File

@@ -351,9 +351,6 @@
</item> </item>
<item row="1" column="6"> <item row="1" column="6">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>MIDI outputs:</string> <string>MIDI outputs:</string>
</property> </property>
@@ -364,9 +361,6 @@
</item> </item>
<item row="1" column="7"> <item row="1" column="7">
<widget class="QSpinBox" name="sb_midi_outs"> <widget class="QSpinBox" name="sb_midi_outs">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum"> <property name="maximum">
<number>1</number> <number>1</number>
</property> </property>


+ 1
- 1
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -1238,7 +1238,7 @@ protected:


// set time // set time
*(uint32_t*)midiData = event.time; *(uint32_t*)midiData = event.time;
midiData = midiData + 4;
midiData += 4;


// set data // set data
*midiData++ = uint8_t(_midiData[0] | (event.channel & MIDI_CHANNEL_BIT)); *midiData++ = uint8_t(_midiData[0] | (event.channel & MIDI_CHANNEL_BIT));


+ 2
- 2
source/backend/plugin/CarlaPluginJack.cpp View File

@@ -1222,8 +1222,8 @@ public:


fInfo.aIns = label[0] - '0'; fInfo.aIns = label[0] - '0';
fInfo.aOuts = label[1] - '0'; fInfo.aOuts = label[1] - '0';
fInfo.mIns = carla_minPositive(label[4] - '0', 1);
fInfo.mOuts = carla_minPositive(label[5] - '0', 1);
fInfo.mIns = carla_minPositive(label[2] - '0', 1);
fInfo.mOuts = carla_minPositive(label[3] - '0', 1);


fInfo.setupLabel = label; fInfo.setupLabel = label;




+ 7
- 5
source/bridges-plugin/CarlaBridgeLV2.cpp View File

@@ -113,7 +113,7 @@ public:
close(); close();
} }


bool hasPlugin()
bool hasPlugin() noexcept
{ {
return fPlugin != nullptr; return fPlugin != nullptr;
} }
@@ -121,12 +121,12 @@ public:
// ----------------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------------
// LV2 functions // LV2 functions


void lv2_connect_port(const uint32_t port, void* const dataLocation)
void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept
{ {
fPorts.connectPort(port, dataLocation); fPorts.connectPort(port, dataLocation);
} }


void lv2_activate()
void lv2_activate() noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(! fIsActive,); CARLA_SAFE_ASSERT_RETURN(! fIsActive,);


@@ -134,7 +134,7 @@ public:
fIsActive = true; fIsActive = true;
} }


void lv2_deactivate()
void lv2_deactivate() noexcept
{ {
CARLA_SAFE_ASSERT_RETURN(fIsActive,); CARLA_SAFE_ASSERT_RETURN(fIsActive,);


@@ -358,7 +358,9 @@ protected:


void handleUiRun() const void handleUiRun() const
{ {
fPlugin->uiIdle();
try {
fPlugin->uiIdle();
} CARLA_SAFE_EXCEPTION("fPlugin->uiIdle()")
} }


void handleUiShow() void handleUiShow()


+ 141
- 63
source/libjack/libjack.cpp View File

@@ -26,7 +26,7 @@ using juce::Time;


CARLA_BACKEND_START_NAMESPACE CARLA_BACKEND_START_NAMESPACE


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------


class CarlaJackRealtimeThread : public Thread class CarlaJackRealtimeThread : public Thread
{ {
@@ -76,7 +76,7 @@ private:
Callback* const fCallback; Callback* const fCallback;
}; };


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------


class CarlaJackAppClient : public CarlaJackRealtimeThread::Callback, class CarlaJackAppClient : public CarlaJackRealtimeThread::Callback,
public CarlaJackNonRealtimeThread::Callback public CarlaJackNonRealtimeThread::Callback
@@ -89,8 +89,10 @@ public:
: fServer(this), : fServer(this),
fAudioPoolCopy(nullptr), fAudioPoolCopy(nullptr),
fAudioTmpBuf(nullptr), fAudioTmpBuf(nullptr),
fMidiBufferIn(true),
fMidiBufferOut(false),
fDummyMidiInBuffer(true, "ignored"),
fDummyMidiOutBuffer(true, "ignored"),
fMidiInBuffers(nullptr),
fMidiOutBuffers(nullptr),
fIsOffline(false), fIsOffline(false),
fLastPingTime(-1), fLastPingTime(-1),
fRealtimeThread(this), fRealtimeThread(this),
@@ -200,8 +202,10 @@ private:
float* fAudioPoolCopy; float* fAudioPoolCopy;
float* fAudioTmpBuf; float* fAudioTmpBuf;


JackMidiPortBuffer fMidiBufferIn;
JackMidiPortBuffer fMidiBufferOut;
JackMidiPortBuffer fDummyMidiInBuffer;
JackMidiPortBuffer fDummyMidiOutBuffer;
JackMidiPortBuffer* fMidiInBuffers;
JackMidiPortBuffer* fMidiOutBuffers;


char fBaseNameAudioPool[6+1]; char fBaseNameAudioPool[6+1];
char fBaseNameRtClientControl[6+1]; char fBaseNameRtClientControl[6+1];
@@ -212,10 +216,10 @@ private:
int64_t fLastPingTime; int64_t fLastPingTime;


struct NumPorts { struct NumPorts {
uint32_t audioIns;
uint32_t audioOuts;
uint32_t midiIns;
uint32_t midiOuts;
uint8_t audioIns;
uint8_t audioOuts;
uint8_t midiIns;
uint8_t midiOuts;


NumPorts() NumPorts()
: audioIns(0), : audioIns(0),
@@ -232,7 +236,7 @@ private:
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient) CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient)
}; };


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------


bool CarlaJackAppClient::initSharedMemmory() bool CarlaJackAppClient::initSharedMemmory()
{ {
@@ -348,6 +352,18 @@ void CarlaJackAppClient::clearSharedMemory() noexcept
fAudioTmpBuf = nullptr; fAudioTmpBuf = nullptr;
} }


if (fMidiInBuffers != nullptr)
{
delete[] fMidiInBuffers;
fMidiInBuffers = nullptr;
}

if (fMidiOutBuffers != nullptr)
{
delete[] fMidiOutBuffers;
fMidiOutBuffers = nullptr;
}

fShmAudioPool.clear(); fShmAudioPool.clear();
fShmRtClientControl.clear(); fShmRtClientControl.clear();
fShmNonRtClientControl.clear(); fShmNonRtClientControl.clear();
@@ -461,31 +477,30 @@ bool CarlaJackAppClient::handleRtData()
const uint8_t size(fShmRtClientControl.readByte()); const uint8_t size(fShmRtClientControl.readByte());
CARLA_SAFE_ASSERT_BREAK(size > 0); CARLA_SAFE_ASSERT_BREAK(size > 0);


if (size > JackMidiPortBuffer::kMaxEventSize || ! fRealtimeThreadMutex.tryLock())
if (port >= fNumPorts.midiIns || size > JackMidiPortBuffer::kMaxEventSize || ! fRealtimeThreadMutex.tryLock())
{ {
for (uint8_t i=0; i<size; ++i) for (uint8_t i=0; i<size; ++i)
fShmRtClientControl.readByte(); fShmRtClientControl.readByte();
break; break;
} }


if (fMidiBufferIn.count < JackMidiPortBuffer::kMaxEventCount &&
fMidiBufferIn.bufferPoolPos + size < JackMidiPortBuffer::kBufferPoolSize)
JackMidiPortBuffer& midiPortBuf(fMidiInBuffers[port]);

if (midiPortBuf.count < JackMidiPortBuffer::kMaxEventCount &&
midiPortBuf.bufferPoolPos + size < JackMidiPortBuffer::kBufferPoolSize)
{ {
jack_midi_event_t& ev(fMidiBufferIn.events[fMidiBufferIn.count++]);
jack_midi_event_t& ev(midiPortBuf.events[midiPortBuf.count++]);


ev.time = time; ev.time = time;
ev.size = size; ev.size = size;
ev.buffer = fMidiBufferIn.bufferPool + fMidiBufferIn.bufferPoolPos;
fMidiBufferIn.bufferPoolPos += size;
ev.buffer = midiPortBuf.bufferPool + midiPortBuf.bufferPoolPos;
midiPortBuf.bufferPoolPos += size;


for (uint8_t i=0; i<size; ++i) for (uint8_t i=0; i<size; ++i)
ev.buffer[i] = fShmRtClientControl.readByte(); ev.buffer[i] = fShmRtClientControl.readByte();
} }


fRealtimeThreadMutex.unlock(true); fRealtimeThreadMutex.unlock(true);

// TODO multiple midi ports
(void)port;
break; break;
} }


@@ -551,7 +566,7 @@ bool CarlaJackAppClient::handleRtData()
} }
else else
{ {
uint32_t i;
uint8_t i;
// direct access to shm buffer, used only for inputs // direct access to shm buffer, used only for inputs
float* fdataReal = fShmAudioPool.data; float* fdataReal = fShmAudioPool.data;
// safe temp location for output, mixed down to shm buffer later on // safe temp location for output, mixed down to shm buffer later on
@@ -559,23 +574,23 @@ bool CarlaJackAppClient::handleRtData()
// wherever we're using fAudioTmpBuf // wherever we're using fAudioTmpBuf
bool needsTmpBufClear = false; bool needsTmpBufClear = false;


// set inputs
// set audio inputs
i = 0; i = 0;
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next()) for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next())
{ {
if (JackPortState* const jport = it.getValue(nullptr))
JackPortState* const jport = it.getValue(nullptr);
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);

if (i++ < fNumPorts.audioIns)
{
jport->buffer = fdataReal;
fdataReal += fServer.bufferSize;
fdataCopy += fServer.bufferSize;
}
else
{ {
if (i++ < fNumPorts.audioIns)
{
jport->buffer = fdataReal;
fdataReal += fServer.bufferSize;
fdataCopy += fServer.bufferSize;
}
else
{
jport->buffer = fAudioTmpBuf;
needsTmpBufClear = true;
}
jport->buffer = fAudioTmpBuf;
needsTmpBufClear = true;
} }
} }
// FIXME one single "if" // FIXME one single "if"
@@ -588,22 +603,22 @@ bool CarlaJackAppClient::handleRtData()
// location to start of audio outputs // location to start of audio outputs
float* const fdataCopyOuts = fdataCopy; float* const fdataCopyOuts = fdataCopy;


// set ouputs
// set audio ouputs
i = 0; i = 0;
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next()) for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next())
{ {
if (JackPortState* const jport = it.getValue(nullptr))
JackPortState* const jport = it.getValue(nullptr);
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);

if (i++ < fNumPorts.audioOuts)
{
jport->buffer = fdataCopy;
fdataCopy += fServer.bufferSize;
}
else
{ {
if (i++ < fNumPorts.audioOuts)
{
jport->buffer = fdataCopy;
fdataCopy += fServer.bufferSize;
}
else
{
jport->buffer = fAudioTmpBuf;
needsTmpBufClear = true;
}
jport->buffer = fAudioTmpBuf;
needsTmpBufClear = true;
} }
} }
// FIXME one single "if" // FIXME one single "if"
@@ -613,22 +628,35 @@ bool CarlaJackAppClient::handleRtData()
fdataCopy += fServer.bufferSize; fdataCopy += fServer.bufferSize;
} }


if (needsTmpBufClear)
FloatVectorOperations::clear(fAudioTmpBuf, fServer.bufferSize);

// set midi buffers
if (jclient->midiIns.count() > 0)
// set midi inputs
i = 0;
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiIns.begin2(); it.valid(); it.next())
{ {
if (JackPortState* const jport = jclient->midiIns.getFirst(nullptr))
jport->buffer = &fMidiBufferIn;
JackPortState* const jport = it.getValue(nullptr);
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);

if (i++ < fNumPorts.midiIns)
jport->buffer = &fMidiInBuffers[i-1];
else
jport->buffer = &fDummyMidiInBuffer;
} }


if (jclient->midiOuts.count() > 0)
// set midi outputs
i = 0;
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiOuts.begin2(); it.valid(); it.next())
{ {
if (JackPortState* const jport = jclient->midiOuts.getFirst(nullptr))
jport->buffer = &fMidiBufferOut;
JackPortState* const jport = it.getValue(nullptr);
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);

if (i++ < fNumPorts.midiOuts)
jport->buffer = &fMidiOutBuffers[i-1];
else
jport->buffer = &fDummyMidiOutBuffer;
} }


if (needsTmpBufClear)
FloatVectorOperations::clear(fAudioTmpBuf, fServer.bufferSize);

jclient->processCb(fServer.bufferSize, jclient->processCbPtr); jclient->processCb(fServer.bufferSize, jclient->processCbPtr);


if (fNumPorts.audioOuts > 0) if (fNumPorts.audioOuts > 0)
@@ -663,11 +691,44 @@ bool CarlaJackAppClient::handleRtData()
FloatVectorOperations::clear(fdataRealOuts, fServer.bufferSize*fNumPorts.audioOuts); FloatVectorOperations::clear(fdataRealOuts, fServer.bufferSize*fNumPorts.audioOuts);
} }


fMidiBufferIn.count = 0;
fMidiBufferIn.bufferPoolPos = 0;
for (uint8_t i=0; i<fNumPorts.midiIns; ++i)
{
fMidiInBuffers[i].count = 0;
fMidiInBuffers[i].bufferPoolPos = 0;
}


if (fNumPorts.midiOuts > 0) if (fNumPorts.midiOuts > 0)
carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize);
{
uint8_t* midiData(fShmRtClientControl.data->midiOut);
carla_zeroBytes(midiData, kBridgeRtClientDataMidiOutSize);
std::size_t curMidiDataPos = 0;

for (uint8_t i=0; i<fNumPorts.midiOuts; ++i)
{
JackMidiPortBuffer& midiPortBuf(fMidiOutBuffers[i]);

for (uint16_t j=0; j<midiPortBuf.count; ++j)
{
jack_midi_event_t& jmevent(midiPortBuf.events[j]);

if (curMidiDataPos + 1U /* size*/ + 4U /* time */ + jmevent.size >= kBridgeRtClientDataMidiOutSize)
break;

// set size
*midiData++ = static_cast<uint8_t>(jmevent.size);

// set time
*(uint32_t*)midiData = jmevent.time;
midiData += 4;

// set data
std::memcpy(midiData, jmevent.buffer, jmevent.size);
midiData += jmevent.size;

curMidiDataPos += 1U /* size*/ + 4U /* time */ + jmevent.size;
}
}
}
} }
else else
{ {
@@ -834,6 +895,22 @@ void CarlaJackAppClient::runNonRealtimeThread()
if (! initSharedMemmory()) if (! initSharedMemmory())
return; return;


if (fNumPorts.midiIns > 0)
{
fMidiInBuffers = new JackMidiPortBuffer[fNumPorts.midiIns];

for (uint8_t i=0; i<fNumPorts.midiIns; ++i)
fMidiInBuffers[i].isInput = true;
}

if (fNumPorts.midiOuts > 0)
{
fMidiOutBuffers = new JackMidiPortBuffer[fNumPorts.midiOuts];

for (uint8_t i=0; i<fNumPorts.midiOuts; ++i)
fMidiOutBuffers[i].isInput = false;
}

fRealtimeThread.startThread(Thread::realtimeAudioPriority); fRealtimeThread.startThread(Thread::realtimeAudioPriority);


fLastPingTime = Time::currentTimeMillis(); fLastPingTime = Time::currentTimeMillis();
@@ -935,6 +1012,7 @@ void CarlaJackAppClient::runNonRealtimeThread()
} }


fRealtimeThread.signalThreadShouldExit(); fRealtimeThread.signalThreadShouldExit();

clearSharedMemory(); clearSharedMemory();


fRealtimeThread.stopThread(5000); fRealtimeThread.stopThread(5000);
@@ -942,7 +1020,7 @@ void CarlaJackAppClient::runNonRealtimeThread()
carla_stderr("CarlaJackAppClient run FINISHED"); carla_stderr("CarlaJackAppClient run FINISHED");
} }


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------


static CarlaJackAppClient gClient; static CarlaJackAppClient gClient;


@@ -994,12 +1072,12 @@ pthread_t jack_client_thread_id(jack_client_t* client)


CARLA_BACKEND_END_NAMESPACE CARLA_BACKEND_END_NAMESPACE


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------


#include "jackbridge/JackBridge2.cpp" #include "jackbridge/JackBridge2.cpp"
#include "CarlaBridgeUtils.cpp" #include "CarlaBridgeUtils.cpp"


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
// TODO // TODO


CARLA_BACKEND_USE_NAMESPACE CARLA_BACKEND_USE_NAMESPACE
@@ -1022,4 +1100,4 @@ int jack_set_session_callback(jack_client_t* client, JackSessionCallback callbac
return 0; return 0;
} }


// --------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

+ 13
- 5
source/libjack/libjack.hpp View File

@@ -60,9 +60,9 @@ struct JackClientState;
struct JackServerState; struct JackServerState;


struct JackMidiPortBuffer { struct JackMidiPortBuffer {
static const size_t kMaxEventSize = 128;
static const size_t kMaxEventCount = 512;
static const size_t kBufferPoolSize = kMaxEventCount*8;
static const uint8_t kMaxEventSize = 128;
static const size_t kMaxEventCount = 512;
static const size_t kBufferPoolSize = kMaxEventCount*8;


uint16_t count; uint16_t count;
bool isInput; bool isInput;
@@ -71,13 +71,21 @@ struct JackMidiPortBuffer {
size_t bufferPoolPos; size_t bufferPoolPos;
jack_midi_data_t* bufferPool; jack_midi_data_t* bufferPool;


JackMidiPortBuffer(const bool input)
JackMidiPortBuffer()
: count(0), : count(0),
isInput(input),
isInput(true),
events(new jack_midi_event_t[kMaxEventCount]), events(new jack_midi_event_t[kMaxEventCount]),
bufferPoolPos(0), bufferPoolPos(0),
bufferPool(new jack_midi_data_t[kBufferPoolSize]) {} bufferPool(new jack_midi_data_t[kBufferPoolSize]) {}


// for unused ports
JackMidiPortBuffer(const bool input, const char*)
: count(0),
isInput(input),
events(nullptr),
bufferPoolPos(0),
bufferPool(nullptr) {}

~JackMidiPortBuffer() ~JackMidiPortBuffer()
{ {
delete[] events; delete[] events;


+ 5
- 2
source/libjack/libjack_midi.cpp View File

@@ -37,7 +37,9 @@ int jack_midi_event_get(jack_midi_event_t* ev, void* buf, uint32_t index)
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT);
CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, EFAULT); CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, EFAULT);
CARLA_SAFE_ASSERT_RETURN(index < jmidibuf->count, ENODATA);

if (index >= jmidibuf->count)
return ENODATA;


std::memcpy(ev, &jmidibuf->events[index], sizeof(jack_midi_event_t)); std::memcpy(ev, &jmidibuf->events[index], sizeof(jack_midi_event_t));
return 0; return 0;
@@ -73,7 +75,7 @@ jack_midi_data_t* jack_midi_event_reserve(void* buf, jack_nframes_t frame, size_
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, nullptr);
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, nullptr); CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, nullptr);
CARLA_SAFE_ASSERT_RETURN(size > 0, nullptr);
CARLA_SAFE_ASSERT_RETURN(size > 0 && size < JackMidiPortBuffer::kMaxEventSize, nullptr);


if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount)
return nullptr; return nullptr;
@@ -94,6 +96,7 @@ int jack_midi_event_write(void* buf, jack_nframes_t frame, const jack_midi_data_
JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT);
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, EFAULT); CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, EFAULT);
CARLA_SAFE_ASSERT_RETURN(size > 0 && size < JackMidiPortBuffer::kMaxEventSize, ENOBUFS);


if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount)
return ENOBUFS; return ENOBUFS;


Loading…
Cancel
Save