Browse Source

MIDI input working in juce drivers

tags/1.9.4
falkTX 11 years ago
parent
commit
ababc77459
2 changed files with 355 additions and 58 deletions
  1. +310
    -12
      source/backend/engine/CarlaEngineJuce.cpp
  2. +45
    -46
      source/backend/engine/CarlaEngineRtAudio.cpp

+ 310
- 12
source/backend/engine/CarlaEngineJuce.cpp View File

@@ -40,7 +40,7 @@ CARLA_BACKEND_START_NAMESPACE
static const char** gRetNames = nullptr;
static OwnedArray<AudioIODeviceType> gJuceDeviceTypes;

struct JuceCleanup {
struct JuceCleanup : public DeletedAtShutdown {
JuceCleanup() noexcept {}
~JuceCleanup()
{
@@ -62,7 +62,6 @@ struct JuceCleanup {

static void initJuceDevicesIfNeeded()
{
static const JuceCleanup sJuceCleanup;
static AudioDeviceManager sDeviceManager;
static bool needsInit = true;

@@ -70,6 +69,7 @@ static void initJuceDevicesIfNeeded()
return;

needsInit = false;
new JuceCleanup();

sDeviceManager.createAudioDeviceTypes(gJuceDeviceTypes);

@@ -87,7 +87,8 @@ static void initJuceDevicesIfNeeded()
// Juce Engine

class CarlaEngineJuce : public CarlaEngine,
public AudioIODeviceCallback
public AudioIODeviceCallback,
public MidiInputCallback
{
public:
CarlaEngineJuce(AudioIODeviceType* const devType)
@@ -211,6 +212,28 @@ public:
fDevice = nullptr;
}

for (LinkedList<MidiInPort>::Itenerator it = fMidiIns.begin(); it.valid(); it.next())
{
MidiInPort& inPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

inPort.port->stop();
delete inPort.port;
}

for (LinkedList<MidiOutPort>::Itenerator it = fMidiOuts.begin(); it.valid(); it.next())
{
MidiOutPort& outPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);

outPort.port->stopBackgroundThread();
delete outPort.port;
}

fMidiIns.clear();
fMidiOuts.clear();
fMidiInEvents.clear();

return !hasError;
}

@@ -307,7 +330,47 @@ public:
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, static_cast<int>(i), PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, outputNames[i].toRawUTF8());
}

// TODO - MIDI
// MIDI In
{
StringArray midiIns(MidiInput::getDevices());

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");

for (int i=0, count=midiIns.size(); i<count; ++i)
{
String portName(midiIns[i]);

std::snprintf(strBuf, STR_MAX, "Readable MIDI ports:%s", portName.toRawUTF8());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_IN, static_cast<uint>(i), portName.toRawUTF8(), strBuf);

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);

rack->midi.ins.append(portNameToId);
}
}

// MIDI Out
{
StringArray midiOuts(MidiOutput::getDevices());

callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");

for (int i=0, count=midiOuts.size(); i<count; ++i)
{
String portName(midiOuts[i]);

std::snprintf(strBuf, STR_MAX, "Writable MIDI ports:%s", portName.toRawUTF8());

PortNameToId portNameToId;
portNameToId.setData(RACK_GRAPH_GROUP_MIDI_OUT, static_cast<uint>(i), portName.toRawUTF8(), strBuf);

callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, portNameToId.group, static_cast<int>(portNameToId.port), PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);

rack->midi.outs.append(portNameToId);
}
}

// Connections
rack->audio.mutex.lock();
@@ -374,7 +437,39 @@ public:

rack->audio.mutex.unlock();

// TODO - MIDI
for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
const MidiInPort& inPort(it.getValue());

const uint portId(rack->midi.getPortId(true, inPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < rack->midi.ins.count());

ConnectionToId connectionToId;
connectionToId.setData(++(rack->connections.lastId), RACK_GRAPH_GROUP_MIDI_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_IN);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

rack->connections.list.append(connectionToId);
}

for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
const MidiOutPort& outPort(it.getValue());

const uint portId(rack->midi.getPortId(false, outPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < rack->midi.outs.count());

ConnectionToId connectionToId;
connectionToId.setData(++(rack->connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, RACK_GRAPH_GROUP_MIDI_OUT, portId);

std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);

callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);

rack->connections.list.append(connectionToId);
}
}

void patchbayRefreshPatchbay() noexcept
@@ -395,6 +490,8 @@ protected:
if (! pData->audio.isReady)
return runPendingRtEvents();

const uint32_t nframes(static_cast<uint32_t>(numSamples));

// initialize juce output
for (int i=0; i < numOutputChannels; ++i)
FloatVectorOperations::clear(outputChannelData[i], numSamples);
@@ -402,7 +499,37 @@ protected:
// initialize input events
carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);

// TODO - get events from juce
if (fMidiInEvents.mutex.tryLock())
{
uint32_t engineEventIndex = 0;
fMidiInEvents.splice();

for (LinkedList<RtMidiEvent>::Itenerator it = fMidiInEvents.data.begin(); it.valid(); it.next())
{
const RtMidiEvent& midiEvent(it.getValue());
EngineEvent& engineEvent(pData->events.in[engineEventIndex++]);

if (midiEvent.time < pData->timeInfo.frame)
{
engineEvent.time = 0;
}
else if (midiEvent.time >= pData->timeInfo.frame + nframes)
{
carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent.time, pData->timeInfo.frame);
engineEvent.time = static_cast<uint32_t>(pData->timeInfo.frame) + nframes - 1;
}
else
engineEvent.time = static_cast<uint32_t>(midiEvent.time - pData->timeInfo.frame);

engineEvent.fillFromMidiData(midiEvent.size, midiEvent.data);

if (engineEventIndex >= kMaxEngineEventInternalCount)
break;
}

fMidiInEvents.data.clear();
fMidiInEvents.mutex.unlock();
}

if (pData->graph.isRack)
{
@@ -439,23 +566,135 @@ protected:

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

bool connectRackMidiInPort(const char* const /*portName*/) override
void handleIncomingMidiMessage(MidiInput* /*source*/, const MidiMessage& message) override
{
return false;
if (! pData->audio.isReady)
return;

const int messageSize(message.getRawDataSize());

if (messageSize <= 0 || messageSize > EngineMidiEvent::kDataSize)
return;

const uint8_t* const messageData(message.getRawData());

RtMidiEvent midiEvent;
midiEvent.time = 0; // TODO

midiEvent.size = static_cast<uint8_t>(messageSize);

int i=0;
for (; i < messageSize; ++i)
midiEvent.data[i] = messageData[i];
for (; i < EngineMidiEvent::kDataSize; ++i)
midiEvent.data[i] = 0;

fMidiInEvents.appendNonRT(midiEvent);
}

bool connectRackMidiOutPort(const char* const /*portName*/) override
// -------------------------------------------------------------------

bool connectRackMidiInPort(const char* const portName) override
{
return false;
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineJuce::connectRackMidiInPort(\"%s\")", portName);

RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.ins.count() > 0, false);

StringArray midiIns(MidiInput::getDevices());

if (! midiIns.contains(portName))
return false;

MidiInput* const juceMidiIn(MidiInput::openDevice(midiIns.indexOf(portName), this));
juceMidiIn->start();

MidiInPort midiPort;
midiPort.port = juceMidiIn;

std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';

fMidiIns.append(midiPort);
return true;
}

bool disconnectRackMidiInPort(const char* const /*portName*/) override
bool connectRackMidiOutPort(const char* const portName) override
{
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineJuce::connectRackMidiOutPort(\"%s\")", portName);

RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.ins.count() > 0, false);

StringArray midiOuts(MidiOutput::getDevices());

if (! midiOuts.contains(portName))
return false;

MidiOutput* const juceMidiOut(MidiOutput::openDevice(midiOuts.indexOf(portName)));
juceMidiOut->startBackgroundThread();

MidiOutPort midiPort;
midiPort.port = juceMidiOut;

std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';

fMidiOuts.append(midiPort);
return true;
}

bool disconnectRackMidiInPort(const char* const portName) override
{
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::disconnectRackMidiInPort(\"%s\")", portName);

RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.ins.count() > 0, false);

for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
MidiInPort& inPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

if (std::strcmp(inPort.name, portName) != 0)
continue;

inPort.port->stop();
delete inPort.port;

fMidiIns.remove(it);
return true;
}

return false;
}

bool disconnectRackMidiOutPort(const char* const /*portName*/) override
bool disconnectRackMidiOutPort(const char* const portName) override
{
CARLA_SAFE_ASSERT_RETURN(portName != nullptr && portName[0] != '\0', false);
carla_debug("CarlaEngineRtAudio::disconnectRackMidiOutPort(\"%s\")", portName);

RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.outs.count() > 0, false);

for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
MidiOutPort& outPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);

if (std::strcmp(outPort.name, portName) != 0)
continue;

outPort.port->stopBackgroundThread();
delete outPort.port;

fMidiOuts.remove(it);
return true;
}

return false;
}

@@ -465,6 +704,65 @@ private:
ScopedPointer<AudioIODevice> fDevice;
AudioIODeviceType* const fDeviceType;

struct MidiInPort {
MidiInput* port;
char name[STR_MAX+1];
};

struct MidiOutPort {
MidiOutput* port;
char name[STR_MAX+1];
};

LinkedList<MidiInPort> fMidiIns;
LinkedList<MidiOutPort> fMidiOuts;

struct RtMidiEvent {
uint64_t time; // needs to compare to internal time
uint8_t size;
uint8_t data[EngineMidiEvent::kDataSize];
};

struct RtMidiEvents {
CarlaMutex mutex;
RtLinkedList<RtMidiEvent>::Pool dataPool;
RtLinkedList<RtMidiEvent> data;
RtLinkedList<RtMidiEvent> dataPending;

// FIXME - 32, 512 + append_sleepy? check plugin code
RtMidiEvents()
: dataPool(512, 512),
data(dataPool),
dataPending(dataPool) {}

~RtMidiEvents()
{
clear();
}

void appendNonRT(const RtMidiEvent& event)
{
mutex.lock();
dataPending.append(event);
mutex.unlock();
}

void clear()
{
mutex.lock();
data.clear();
dataPending.clear();
mutex.unlock();
}

void splice()
{
dataPending.spliceAppendTo(data);
}
};

RtMidiEvents fMidiInEvents;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJuce)
};



+ 45
- 46
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -192,8 +192,6 @@ public:
CARLA_SAFE_ASSERT(fAudioOutCount == 0);
CARLA_SAFE_ASSERT(fLastEventTime == 0);
carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");

fUsedMidiPorts.clear();
}

// -------------------------------------
@@ -343,21 +341,23 @@ public:
fAudio.closeStream();
}

for (LinkedList<MidiPort>::Itenerator it = fMidiIns.begin(); it.valid(); it.next())
for (LinkedList<MidiInPort>::Itenerator it = fMidiIns.begin(); it.valid(); it.next())
{
MidiPort& port(it.getValue());
RtMidiIn* const midiInPort((RtMidiIn*)port.rtmidi);
MidiInPort& inPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

midiInPort->cancelCallback();
delete midiInPort;
inPort.port->cancelCallback();
inPort.port->closePort();
delete inPort.port;
}

for (LinkedList<MidiPort>::Itenerator it = fMidiOuts.begin(); it.valid(); it.next())
for (LinkedList<MidiOutPort>::Itenerator it = fMidiOuts.begin(); it.valid(); it.next())
{
MidiPort& port(it.getValue());
RtMidiOut* const midiOutPort((RtMidiOut*)port.rtmidi);
MidiOutPort& outPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);

delete midiOutPort;
outPort.port->closePort();
delete outPort.port;
}

fAudioInCount = 0;
@@ -365,12 +365,10 @@ public:
fLastEventTime = 0;

fDeviceName.clear();
fUsedMidiPorts.clear();
fMidiInEvents.clear();
//fMidiOutEvents.clear();

fMidiIns.clear();
fMidiOuts.clear();
fMidiInEvents.clear();
//fMidiOutEvents.clear();

return !hasError;
}
@@ -402,8 +400,6 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(pData->audio.isReady, false);

fUsedMidiPorts.clear();

if (pData->graph.isRack)
patchbayRefreshRack();
else
@@ -572,11 +568,11 @@ public:

rack->audio.mutex.unlock();

for (LinkedList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
const MidiPort& midiPort(it.getValue());
const MidiInPort& inPort(it.getValue());

const uint portId(rack->midi.getPortId(true, midiPort.name));
const uint portId(rack->midi.getPortId(true, inPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < rack->midi.ins.count());

ConnectionToId connectionToId;
@@ -589,11 +585,11 @@ public:
rack->connections.list.append(connectionToId);
}

for (LinkedList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
const MidiPort& midiPort(it.getValue());
const MidiOutPort& outPort(it.getValue());

const uint portId(rack->midi.getPortId(false, midiPort.name));
const uint portId(rack->midi.getPortId(false, outPort.name));
CARLA_SAFE_ASSERT_CONTINUE(portId < rack->midi.outs.count());

ConnectionToId connectionToId;
@@ -780,8 +776,8 @@ protected:
return false;
};

MidiPort midiPort;
midiPort.rtmidi = rtMidiIn;
MidiInPort midiPort;
midiPort.port = rtMidiIn;

std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';
@@ -826,8 +822,8 @@ protected:

rtMidiOut->openPort(rtMidiPortIndex, portName);

MidiPort midiPort;
midiPort.rtmidi = rtMidiOut;
MidiOutPort midiPort;
midiPort.port = rtMidiOut;

std::strncpy(midiPort.name, portName, STR_MAX);
midiPort.name[STR_MAX] = '\0';
@@ -844,17 +840,17 @@ protected:
RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.ins.count() > 0, false);

for (LinkedList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
for (LinkedList<MidiInPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
{
MidiPort& midiPort(it.getValue());
MidiInPort& inPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(inPort.port != nullptr);

if (std::strcmp(midiPort.name, portName) != 0)
if (std::strcmp(inPort.name, portName) != 0)
continue;

RtMidiIn* const midiInPort((RtMidiIn*)midiPort.rtmidi);

midiInPort->cancelCallback();
delete midiInPort;
inPort.port->cancelCallback();
inPort.port->closePort();
delete inPort.port;

fMidiIns.remove(it);
return true;
@@ -869,18 +865,18 @@ protected:
carla_debug("CarlaEngineRtAudio::disconnectRackMidiOutPort(\"%s\")", portName);

RackGraph* const rack(pData->graph.rack);
CARLA_SAFE_ASSERT_RETURN(rack->midi.ins.count() > 0, false);
CARLA_SAFE_ASSERT_RETURN(rack->midi.outs.count() > 0, false);

for (LinkedList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
for (LinkedList<MidiOutPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
{
MidiPort& midiPort(it.getValue());
MidiOutPort& outPort(it.getValue());
CARLA_SAFE_ASSERT_CONTINUE(outPort.port != nullptr);

if (std::strcmp(midiPort.name, portName) != 0)
if (std::strcmp(outPort.name, portName) != 0)
continue;

RtMidiOut* const midiOutPort((RtMidiOut*)midiPort.rtmidi);

delete midiOutPort;
outPort.port->closePort();
delete outPort.port;

fMidiOuts.remove(it);
return true;
@@ -902,15 +898,18 @@ private:
// current device name
CarlaString fDeviceName;

PatchbayPortList fUsedMidiPorts;
struct MidiInPort {
RtMidiIn* port;
char name[STR_MAX+1];
};

struct MidiPort {
RtMidi* rtmidi;
struct MidiOutPort {
RtMidiOut* port;
char name[STR_MAX+1];
};

LinkedList<MidiPort> fMidiIns;
LinkedList<MidiPort> fMidiOuts;
LinkedList<MidiInPort> fMidiIns;
LinkedList<MidiOutPort> fMidiOuts;

struct RtMidiEvent {
uint64_t time; // needs to compare to internal time


Loading…
Cancel
Save