Browse Source

libjack: support for midi out

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


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

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

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

// set data
*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.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;



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

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

bool hasPlugin()
bool hasPlugin() noexcept
{
return fPlugin != nullptr;
}
@@ -121,12 +121,12 @@ public:
// -----------------------------------------------------------------------------------------------------------------
// 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);
}

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

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

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

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

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

void handleUiShow()


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

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

CARLA_BACKEND_START_NAMESPACE

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

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

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

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

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

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

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()
: audioIns(0),
@@ -232,7 +236,7 @@ private:
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient)
};

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

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

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

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

fShmAudioPool.clear();
fShmRtClientControl.clear();
fShmNonRtClientControl.clear();
@@ -461,31 +477,30 @@ bool CarlaJackAppClient::handleRtData()
const uint8_t size(fShmRtClientControl.readByte());
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)
fShmRtClientControl.readByte();
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.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)
ev.buffer[i] = fShmRtClientControl.readByte();
}

fRealtimeThreadMutex.unlock(true);

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

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

// set inputs
// set audio inputs
i = 0;
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"
@@ -588,22 +603,22 @@ bool CarlaJackAppClient::handleRtData()
// location to start of audio outputs
float* const fdataCopyOuts = fdataCopy;

// set ouputs
// set audio ouputs
i = 0;
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"
@@ -613,22 +628,35 @@ bool CarlaJackAppClient::handleRtData()
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);

if (fNumPorts.audioOuts > 0)
@@ -663,11 +691,44 @@ bool CarlaJackAppClient::handleRtData()
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)
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
{
@@ -834,6 +895,22 @@ void CarlaJackAppClient::runNonRealtimeThread()
if (! initSharedMemmory())
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);

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

fRealtimeThread.signalThreadShouldExit();

clearSharedMemory();

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

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

static CarlaJackAppClient gClient;

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

CARLA_BACKEND_END_NAMESPACE

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

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

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

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

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

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

@@ -60,9 +60,9 @@ 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;
static const uint8_t kMaxEventSize = 128;
static const size_t kMaxEventCount = 512;
static const size_t kBufferPoolSize = kMaxEventCount*8;

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

JackMidiPortBuffer(const bool input)
JackMidiPortBuffer()
: count(0),
isInput(input),
isInput(true),
events(new jack_midi_event_t[kMaxEventCount]),
bufferPoolPos(0),
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()
{
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);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, 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));
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);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, 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)
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);
CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT);
CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, EFAULT);
CARLA_SAFE_ASSERT_RETURN(size > 0 && size < JackMidiPortBuffer::kMaxEventSize, ENOBUFS);

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


Loading…
Cancel
Save