Browse Source

libjack: implement midi out channel buffer mixdown

tags/v2.1-rc1
falkTX 6 years ago
parent
commit
b511d21006
2 changed files with 70 additions and 5 deletions
  1. +2
    -0
      source/backend/plugin/CarlaPluginJack.cpp
  2. +68
    -5
      source/libjack/libjack.cpp

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

@@ -31,6 +31,8 @@


#ifdef HAVE_LIBLO #ifdef HAVE_LIBLO
# include "CarlaOscUtils.hpp" # include "CarlaOscUtils.hpp"
#else
# warning No liblo support, NSM (session state) will not be available
#endif #endif


#include "water/files/File.h" #include "water/files/File.h"


+ 68
- 5
source/libjack/libjack.cpp View File

@@ -187,6 +187,9 @@ public:
fSessionManager = static_cast<uint>(libjackSetup[4] - '0'); fSessionManager = static_cast<uint>(libjackSetup[4] - '0');
fSetupHints = static_cast<uint>(libjackSetup[5] - '0'); fSetupHints = static_cast<uint>(libjackSetup[5] - '0');


if (fSetupHints & LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN)
fServer.numMidiOuts = 16;

jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SET_HINTS_AND_CALLBACK, jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SET_HINTS_AND_CALLBACK,
fSetupHints, fSetupHints,
(void*)carla_interposed_callback); (void*)carla_interposed_callback);
@@ -655,7 +658,9 @@ bool CarlaJackAppClient::handleRtData()
CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr); CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);


// mixdown is default, do buffer addition (for multiple clients) if requested // mixdown is default, do buffer addition (for multiple clients) if requested
const bool doBufferAddition = fSetupHints & 0x10;
const bool doBufferAddition = fSetupHints & LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION;
// mixdown midi outputs based on channel if requested
const bool doMidiChanMixdown = fSetupHints & LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN;


// location to start of audio outputs (shm buffer) // location to start of audio outputs (shm buffer)
float* const fdataRealOuts = fShmAudioPool.data+(fServer.bufferSize*fServer.numAudioIns); float* const fdataRealOuts = fShmAudioPool.data+(fServer.bufferSize*fServer.numAudioIns);
@@ -668,6 +673,9 @@ bool CarlaJackAppClient::handleRtData()
// save transport for all clients // save transport for all clients
const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);


const bool transportChanged = fServer.playing != bridgeTimeInfo.playing ||
(bridgeTimeInfo.playing && fServer.position.frame + frames != bridgeTimeInfo.frame);

fServer.playing = bridgeTimeInfo.playing; fServer.playing = bridgeTimeInfo.playing;
fServer.position.frame = static_cast<jack_nframes_t>(bridgeTimeInfo.frame); fServer.position.frame = static_cast<jack_nframes_t>(bridgeTimeInfo.frame);
fServer.position.usecs = bridgeTimeInfo.usecs; fServer.position.usecs = bridgeTimeInfo.usecs;
@@ -702,8 +710,7 @@ bool CarlaJackAppClient::handleRtData()
JackClientState* const jclient(it.getValue(nullptr)); JackClientState* const jclient(it.getValue(nullptr));
CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr); CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);


// FIXME - lock if offline
const CarlaMutexTryLocker cmtl2(jclient->mutex);
const CarlaMutexTryLocker cmtl2(jclient->mutex, fIsOffline);


// check if we can process // check if we can process
if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated) if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated)
@@ -716,6 +723,14 @@ bool CarlaJackAppClient::handleRtData()
} }
else else
{ {
// report transport sync changes if needed
if (transportChanged && jclient->syncCb != nullptr)
{
jclient->syncCb(fServer.playing ? JackTransportRolling : JackTransportStopped,
&fServer.position,
jclient->syncCbPtr);
}

uint8_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;
@@ -871,7 +886,7 @@ bool CarlaJackAppClient::handleRtData()


if (fServer.numMidiOuts > 0) if (fServer.numMidiOuts > 0)
{ {
uint8_t* midiData(fShmRtClientControl.data->midiOut);
uint8_t* midiData = fShmRtClientControl.data->midiOut;
carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize); carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);
std::size_t curMidiDataPos = 0; std::size_t curMidiDataPos = 0;


@@ -886,12 +901,16 @@ bool CarlaJackAppClient::handleRtData()
if (curMidiDataPos + kBridgeBaseMidiOutHeaderSize + jmevent.size >= kBridgeRtClientDataMidiOutSize) if (curMidiDataPos + kBridgeBaseMidiOutHeaderSize + jmevent.size >= kBridgeRtClientDataMidiOutSize)
break; break;


if (doMidiChanMixdown && MIDI_IS_CHANNEL_MESSAGE(jmevent.buffer[0]))
jmevent.buffer[0] = static_cast<jack_midi_data_t>(
(jmevent.buffer[0] & MIDI_STATUS_BIT) | (i & MIDI_CHANNEL_BIT));

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


// set port // set port
*midiData++ = i;
*midiData++ = doMidiChanMixdown ? 0 : i;


// set size // set size
*midiData++ = static_cast<uint8_t>(jmevent.size); *midiData++ = static_cast<uint8_t>(jmevent.size);
@@ -904,10 +923,54 @@ bool CarlaJackAppClient::handleRtData()
} }
} }


// make last event null, so server stops when reaching it
if (curMidiDataPos != 0 && if (curMidiDataPos != 0 &&
curMidiDataPos + kBridgeBaseMidiOutHeaderSize < kBridgeRtClientDataMidiOutSize) curMidiDataPos + kBridgeBaseMidiOutHeaderSize < kBridgeRtClientDataMidiOutSize)
{
carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize); carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);


// sort events in case of mixdown
if (doMidiChanMixdown)
{
uint32_t time;
uint8_t size, *midiDataPtr = fShmRtClientControl.data->midiOut;
uint8_t tmp[kBridgeBaseMidiOutHeaderSize + JackMidiPortBufferBase::kMaxEventSize];
bool wasSorted = true;

for (; wasSorted;)
{
uint8_t prevSize, *prevData = midiDataPtr;
uint32_t prevTime = *(uint32_t*)midiDataPtr;
wasSorted = false;

for (;;)
{
time = *(uint32_t*)midiDataPtr;
size = *(midiDataPtr + 5); // time and port

if (size == 0)
break;

if (prevTime > time)
{
// copy previous data to a temporary place
std::memcpy(tmp, prevData, kBridgeBaseMidiOutHeaderSize + prevSize);
// override previous data with new one (shifting left)
std::memcpy(prevData, midiDataPtr, kBridgeBaseMidiOutHeaderSize + size);
// override new data with old one
std::memcpy(midiDataPtr, tmp, kBridgeBaseMidiOutHeaderSize + prevSize);
// done swapping, flag it
wasSorted = true;
}

prevTime = time;
prevSize = size;
prevData = midiDataPtr;
midiDataPtr += 6 + size;
}
}
}
}
} }
} }
else else


Loading…
Cancel
Save