Browse Source

More plugin-bridge work, implement MIDI-in

tags/1.9.4
falkTX 11 years ago
parent
commit
8a27851bc6
8 changed files with 351 additions and 39 deletions
  1. +5
    -0
      source/backend/CarlaEngine.hpp
  2. +8
    -0
      source/backend/CarlaPlugin.hpp
  3. +16
    -1
      source/backend/engine/CarlaEngine.cpp
  4. +38
    -5
      source/backend/engine/CarlaEngineBridge.cpp
  5. +223
    -26
      source/backend/plugin/BridgePlugin.cpp
  6. +8
    -0
      source/backend/plugin/CarlaPlugin.cpp
  7. +8
    -0
      source/backend/plugin/Lv2Plugin.cpp
  8. +45
    -7
      source/utils/CarlaBridgeUtils.hpp

+ 5
- 0
source/backend/CarlaEngine.hpp View File

@@ -492,6 +492,11 @@ public:
*/
virtual void initBuffer(CarlaEngine* const engine) override;

/*!
* Clear the port's internal buffer.
*/
virtual void clearBuffer();

/*!
* Get the number of events present in the buffer.
* \note You must only call this for input ports.


+ 8
- 0
source/backend/CarlaPlugin.hpp View File

@@ -30,6 +30,10 @@ typedef struct _PluginDescriptor PluginDescriptor;

CARLA_BACKEND_START_NAMESPACE

#ifndef DOXYGEN
class CarlaEngineEventPort;
#endif

/*!
* @defgroup CarlaPluginAPI Carla Plugin API
*
@@ -838,12 +842,16 @@ protected:
CarlaString fName; //!< Plugin name
CarlaString fFilename; //!< Plugin filename, if applicable

friend class CarlaEngineBridge;
friend struct CarlaPluginProtectedData;
CarlaPluginProtectedData* const kData; //!< Internal data, for CarlaPlugin subclasses only.

// -------------------------------------------------------------------
// Helper classes

// Get default event input port
virtual CarlaEngineEventPort* getDefaultEventInPort() const;

// Fully disable plugin in scope and also its engine client
// May wait-block on constructor for plugin process to end
class ScopedDisabler


+ 16
- 1
source/backend/engine/CarlaEngine.cpp View File

@@ -137,6 +137,17 @@ void CarlaEngineEventPort::initBuffer(CarlaEngine* const engine)
carla_zeroStruct<EngineEvent>(fBuffer, kMaxEventCount);
}

void CarlaEngineEventPort::clearBuffer()
{
CARLA_ASSERT(fBuffer != nullptr);

if (fBuffer == nullptr)
return;

if (kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE)
carla_zeroStruct<EngineEvent>(fBuffer, kMaxEventCount);
}

uint32_t CarlaEngineEventPort::getEventCount()
{
CARLA_ASSERT(kIsInput);
@@ -226,15 +237,19 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t

void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t channel, const uint8_t port, const uint8_t* const data, const uint8_t size)
{
#ifndef BUILD_BRIDGE
CARLA_ASSERT(! kIsInput);
#endif
CARLA_ASSERT(fBuffer != nullptr);
CARLA_ASSERT(kProcessMode == PROCESS_MODE_CONTINUOUS_RACK || kProcessMode == PROCESS_MODE_PATCHBAY || kProcessMode == PROCESS_MODE_BRIDGE);
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS);
CARLA_ASSERT(data != nullptr);
CARLA_ASSERT(size > 0);

#ifndef BUILD_BRIDGE
if (kIsInput)
return;
#endif
if (fBuffer == nullptr)
return;
if (kProcessMode != PROCESS_MODE_CONTINUOUS_RACK && kProcessMode != PROCESS_MODE_PATCHBAY && kProcessMode != PROCESS_MODE_BRIDGE)
@@ -2052,7 +2067,7 @@ void CarlaEngine::osc_send_control_set_parameter_value(const int32_t pluginId, c
void CarlaEngine::osc_send_control_set_default_value(const int32_t pluginId, const int32_t index, const float value)
{
CARLA_ASSERT(kData->oscData != nullptr);
CARLA_ASSERT(pluginId >= 0 && pluginId < static_cast<int32_t>(kData->curPluginCount));
CARLA_ASSERT(pluginId >= 0 && pluginId < static_cast<int32_t>(kData->maxPluginNumber));
CARLA_ASSERT(index >= 0);
carla_debug("CarlaEngine::osc_send_control_set_default_value(%i, %i, %f)", pluginId, index, value);



+ 38
- 5
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -34,7 +34,7 @@ CARLA_BACKEND_START_NAMESPACE
} // Fix editor indentation
#endif

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

class CarlaEngineBridge : public CarlaEngine,
public QThread
@@ -43,7 +43,8 @@ public:
CarlaEngineBridge(const char* const audioBaseName, const char* const controlBaseName)
: CarlaEngine(),
fIsRunning(false),
fQuitNow(false)
fQuitNow(false),
fEventsInPort(nullptr)
{
carla_debug("CarlaEngineBridge::CarlaEngineBridge()");

@@ -179,10 +180,18 @@ public:
case kPluginBridgeOpcodeNull:
break;

case kPluginBridgeOpcodeReadyWait:
case kPluginBridgeOpcodeSetAudioPool:
{
const int size(rdwr_readInt(&fShmControl.data->ringBuffer));
fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, size);
const int poolSize(rdwr_readInt(&fShmControl.data->ringBuffer));
fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, poolSize);

fEventsInPort = nullptr;

CarlaPlugin* const plugin(getPluginUnchecked(0));

if (plugin != nullptr && plugin->enabled())
fEventsInPort = plugin->getDefaultEventInPort();

break;
}

@@ -246,6 +255,25 @@ public:
break;
}

case kPluginBridgeOpcodeMidiEvent:
{
uint8_t data[4] = { 0 };
const long time(rdwr_readLong(&fShmControl.data->ringBuffer));
const int dataSize(rdwr_readInt(&fShmControl.data->ringBuffer));

CARLA_ASSERT_INT(dataSize >= 1 && dataSize <= 4, dataSize);

for (int i=0; i < dataSize && i < 4; ++i)
data[i] = rdwr_readChar(&fShmControl.data->ringBuffer);

CARLA_ASSERT(fEventsInPort != nullptr);

if (fEventsInPort != nullptr)
fEventsInPort->writeMidiEvent(time, data, dataSize);

break;
}

case kPluginBridgeOpcodeProcess:
{
CARLA_ASSERT(fShmAudioPool.data != nullptr);
@@ -267,6 +295,9 @@ public:
plugin->initBuffers();
plugin->process(inBuffer, outBuffer, fBufferSize);
plugin->unlock();

if (fEventsInPort != nullptr)
fEventsInPort->clearBuffer();
}
break;
}
@@ -313,6 +344,8 @@ private:
bool fIsRunning;
bool fQuitNow;

CarlaEngineEventPort* fEventsInPort;

void _cleanup()
{
if (fShmAudioPool.filename.isNotEmpty())


+ 223
- 26
source/backend/plugin/BridgePlugin.cpp View File

@@ -88,7 +88,7 @@ shm_t shm_mkstemp(char* const fileBase)

while (true)
{
for (int c = size - 6; c < size; c++)
for (int c = size - 6; c < size; ++c)
{
// Note the -1 to avoid the trailing '\0' in charSet.
fileBase[c] = charSet[std::rand() % (sizeof(charSet) - 1)];
@@ -110,6 +110,8 @@ struct BridgeParamInfo {

BridgeParamInfo()
: value(0.0f) {}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(BridgeParamInfo)
};

class BridgePlugin : public CarlaPlugin
@@ -332,10 +334,12 @@ public:
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, parameterId);
rdwr_writeFloat(&fShmControl.data->ringBuffer, value);
rdwr_commitWrite(&fShmControl.data->ringBuffer);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
kData->singleMutex.unlock();
}

CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
}
@@ -356,10 +360,12 @@ public:

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetProgram);
rdwr_writeInt(&fShmControl.data->ringBuffer, index);
rdwr_commitWrite(&fShmControl.data->ringBuffer);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
kData->singleMutex.unlock();
}

CarlaPlugin::setProgram(index, sendGui, sendOsc, sendCallback);
}
@@ -380,10 +386,12 @@ public:

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetMidiProgram);
rdwr_writeInt(&fShmControl.data->ringBuffer, index);
rdwr_commitWrite(&fShmControl.data->ringBuffer);

if (doLock)
{
rdwr_commitWrite(&fShmControl.data->ringBuffer);
kData->singleMutex.unlock();
}

CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback);
}
@@ -583,6 +591,7 @@ public:

void activate() override
{
// already locked before
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE);
rdwr_writeFloat(&fShmControl.data->ringBuffer, 1.0f);
@@ -592,6 +601,7 @@ public:

void deactivate() override
{
// already locked before
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetParameter);
rdwr_writeInt(&fShmControl.data->ringBuffer, PARAMETER_ACTIVE);
rdwr_writeFloat(&fShmControl.data->ringBuffer, 0.0f);
@@ -601,7 +611,7 @@ public:

void process(float** const inBuffer, float** const outBuffer, const uint32_t frames) override
{
uint32_t i/*, k*/;
uint32_t i, k;

// --------------------------------------------------------------------------------------------------------
// Check if active
@@ -626,13 +636,204 @@ public:
}

// --------------------------------------------------------------------------------------------------------
// Plugin processing (no events)
// Event Input

//else
if (kData->event.portIn != nullptr)
{
processSingle(inBuffer, outBuffer, frames);
// ----------------------------------------------------------------------------------------------------
// MIDI Input (External)

if (kData->extNotes.mutex.tryLock())
{
while (! kData->extNotes.data.isEmpty())
{
const ExternalMidiNote& note(kData->extNotes.data.getFirst(true));

CARLA_ASSERT(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

char data1, data2, data3;
data1 = (note.velo > 0) ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF;
data1 += note.channel;
data2 = note.note;
data3 = note.velo;

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent);
rdwr_writeLong(&fShmControl.data->ringBuffer, 0);
rdwr_writeInt(&fShmControl.data->ringBuffer, 3);
rdwr_writeChar(&fShmControl.data->ringBuffer, data1);
rdwr_writeChar(&fShmControl.data->ringBuffer, data2);
rdwr_writeChar(&fShmControl.data->ringBuffer, data3);
}

kData->extNotes.mutex.unlock();

} // End of MIDI Input (External)

// ----------------------------------------------------------------------------------------------------
// Event Input (System)

bool allNotesOffSent = false;

uint32_t nEvents = kData->event.portIn->getEventCount();
uint32_t nextBankId = 0;

if (kData->midiprog.current >= 0 && kData->midiprog.count > 0)
nextBankId = kData->midiprog.data[kData->midiprog.current].bank;

for (i=0; i < nEvents; ++i)
{
const EngineEvent& event(kData->event.portIn->getEvent(i));

// Control change
switch (event.type)
{
case kEngineEventTypeNull:
break;

case kEngineEventTypeControl:
{
const EngineControlEvent& ctrlEvent = event.ctrl;

switch (ctrlEvent.type)
{
case kEngineControlEventTypeNull:
break;

case kEngineControlEventTypeParameter:
{
// Control plugin parameters
for (k=0; k < kData->param.count; ++k)
{
if (kData->param.data[k].midiChannel != event.channel)
continue;
if (kData->param.data[k].midiCC != ctrlEvent.param)
continue;
if (kData->param.data[k].type != PARAMETER_INPUT)
continue;
if ((kData->param.data[k].hints & PARAMETER_IS_AUTOMABLE) == 0)
continue;

float value;

if (kData->param.data[k].hints & PARAMETER_IS_BOOLEAN)
{
value = (ctrlEvent.value < 0.5f) ? kData->param.ranges[k].min : kData->param.ranges[k].max;
}
else
{
value = kData->param.ranges[i].unnormalizeValue(ctrlEvent.value);

if (kData->param.data[k].hints & PARAMETER_IS_INTEGER)
value = std::rint(value);
}

setParameterValue(k, value, false, false, false);
postponeRtEvent(kPluginPostRtEventParameterChange, static_cast<int32_t>(k), 0, value);
}

break;
}

} // End of Plugin processing (no events)
case kEngineControlEventTypeMidiBank:
if (event.channel == kData->ctrlChannel && (fOptions & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
nextBankId = ctrlEvent.param;
break;

case kEngineControlEventTypeMidiProgram:
if (event.channel == kData->ctrlChannel && (fOptions & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
{
const uint32_t nextProgramId(ctrlEvent.param);

if (kData->midiprog.count > 0)
{
for (k=0; k < kData->midiprog.count; ++k)
{
if (kData->midiprog.data[k].bank == nextBankId && kData->midiprog.data[k].program == nextProgramId)
{
setMidiProgram(k, false, false, false);
postponeRtEvent(kPluginPostRtEventMidiProgramChange, k, 0, 0.0f);
break;
}
}
}
else
{
}
}
break;

case kEngineControlEventTypeAllSoundOff:
if (fOptions & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
{
// TODO
}
break;

case kEngineControlEventTypeAllNotesOff:
if (fOptions & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
{
if (event.channel == kData->ctrlChannel && ! allNotesOffSent)
{
allNotesOffSent = true;
sendMidiAllNotesOffToCallback();
}

// TODO
}
break;
}

break;
}

case kEngineEventTypeMidi:
{
const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
uint8_t channel = event.channel;

if (MIDI_IS_STATUS_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
continue;
if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
continue;
if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (fOptions & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
status -= 0x10;

char data[4];
data[0] = status + channel;
data[1] = midiEvent.data[1];
data[2] = midiEvent.data[2];
data[3] = midiEvent.data[3];

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeMidiEvent);
rdwr_writeLong(&fShmControl.data->ringBuffer, event.time);
rdwr_writeInt(&fShmControl.data->ringBuffer, midiEvent.size);

for (uint8_t j=0; j < midiEvent.size && j < 4; ++j)
rdwr_writeChar(&fShmControl.data->ringBuffer, data[j]);

if (status == MIDI_STATUS_NOTE_ON)
postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);

break;
}
}
}

kData->postRtEvents.trySplice();

} // End of Event Input

processSingle(inBuffer, outBuffer, frames);
}

bool processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames)
@@ -684,7 +885,11 @@ public:
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeProcess);
rdwr_commitWrite(&fShmControl.data->ringBuffer);

waitForServer();
if (! waitForServer())
{
kData->singleMutex.unlock();
return true;
}

for (i=0; i < fInfo.aOuts; ++i)
carla_copyFloat(outBuffer[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), frames);
@@ -1385,7 +1590,7 @@ public:
carla_msleep(50);
}

if (! fInitiated)
if (fInitError || ! fInitiated)
{
// unregister so it gets handled properly
registerEnginePlugin(kData->engine, fId, nullptr);
@@ -1395,20 +1600,9 @@ public:
if (kData->osc.thread.isRunning())
kData->osc.thread.terminate();

kData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)");
return false;
}
else if (fInitError)
{
// unregister so it gets handled properly
registerEnginePlugin(kData->engine, fId, nullptr);

kData->osc.thread.quit();
if (! fInitError)
kData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)");

if (kData->osc.thread.isRunning())
kData->osc.thread.terminate();

// last error was set before
return false;
}

@@ -1526,14 +1720,14 @@ private:

fShmAudioPool.data = (float*)carla_shm_map(fShmAudioPool.shm, fShmAudioPool.size);

rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeReadyWait);
rdwr_writeOpcode(&fShmControl.data->ringBuffer, kPluginBridgeOpcodeSetAudioPool);
rdwr_writeInt(&fShmControl.data->ringBuffer, fShmAudioPool.size);
rdwr_commitWrite(&fShmControl.data->ringBuffer);

waitForServer();
}

void waitForServer()
bool waitForServer()
{
sem_post(&fShmControl.data->runServer);

@@ -1541,7 +1735,10 @@ private:
{
carla_stderr("waitForServer() timeout");
kData->active = false; // TODO
return false;
}

return true;
}

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BridgePlugin)


+ 8
- 0
source/backend/plugin/CarlaPlugin.cpp View File

@@ -2102,6 +2102,14 @@ void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note)
(void)note;
}

// -------------------------------------------------------------------
// Helpers

CarlaEngineEventPort* CarlaPlugin::getDefaultEventInPort() const
{
return kData->event.portIn;
}

// -------------------------------------------------------------------
// Scoped Disabler



+ 8
- 0
source/backend/plugin/Lv2Plugin.cpp View File

@@ -3443,6 +3443,14 @@ public:
}

// -------------------------------------------------------------------
// Helpers

CarlaEngineEventPort* getDefaultEventInPort() const override
{
return (fEventsIn.ctrl != nullptr) ? fEventsIn.ctrl->port : nullptr;
}

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

protected:
void guiClosedCallback() override


+ 45
- 7
source/utils/CarlaBridgeUtils.hpp View File

@@ -53,13 +53,13 @@ enum PluginBridgeInfoType {

enum PluginBridgeOpcode {
kPluginBridgeOpcodeNull = 0,
kPluginBridgeOpcodeReadyWait = 1,
kPluginBridgeOpcodeSetAudioPool = 1, // int
kPluginBridgeOpcodeSetBufferSize = 2, // int
kPluginBridgeOpcodeSetSampleRate = 3, // float
kPluginBridgeOpcodeSetParameter = 4, // int, float
kPluginBridgeOpcodeSetProgram = 5, // int
kPluginBridgeOpcodeSetMidiProgram = 6, // int
kPluginBridgeOpcodeMidiEvent = 7, // int, char, ... (int = size, max 4)
kPluginBridgeOpcodeMidiEvent = 7, // long, int, char, ... (long = timeFrame, int = size max 4)
kPluginBridgeOpcodeProcess = 8,
kPluginBridgeOpcodeQuit = 9
};
@@ -102,11 +102,11 @@ struct BridgeShmControl {
// Let's make sure there's plenty of room for either one.
union {
sem_t runServer;
char _alignServer[32];
char _alignServer[128];
};
union {
sem_t runClient;
char _alignClient[32];
char _alignClient[128];
};
BridgeRingBuffer ringBuffer;
};
@@ -167,6 +167,11 @@ const char* PluginBridgeInfoType2str(const PluginBridgeInfoType type)
static inline
void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t size)
{
CARLA_ASSERT(buf != nullptr);

if (buf == nullptr)
return;

char* const charbuf(static_cast<char*>(buf));

size_t tail = ringbuf->tail;
@@ -200,6 +205,11 @@ void rdwr_tryRead(BridgeRingBuffer* const ringbuf, void* const buf, const size_t
static inline
void rdwr_tryWrite(BridgeRingBuffer* const ringbuf, const void* const buf, const size_t size)
{
CARLA_ASSERT(buf != nullptr);

if (buf == nullptr)
return;

const char* const charbuf(static_cast<const char*>(buf));

size_t written = ringbuf->written;
@@ -259,11 +269,19 @@ bool rdwr_dataAvailable(BridgeRingBuffer* const ringbuf)
static inline
PluginBridgeOpcode rdwr_readOpcode(BridgeRingBuffer* const ringbuf)
{
int i = kPluginBridgeOpcodeNull;
int i = static_cast<int>(kPluginBridgeOpcodeNull);
rdwr_tryRead(ringbuf, &i, sizeof(int));
return static_cast<PluginBridgeOpcode>(i);
}

static inline
char rdwr_readChar(BridgeRingBuffer* const ringbuf)
{
char c = 0;
rdwr_tryRead(ringbuf, &c, sizeof(char));
return c;
}

static inline
int rdwr_readInt(BridgeRingBuffer* const ringbuf)
{
@@ -272,6 +290,14 @@ int rdwr_readInt(BridgeRingBuffer* const ringbuf)
return i;
}

static inline
long rdwr_readLong(BridgeRingBuffer* const ringbuf)
{
long l = 0;
rdwr_tryRead(ringbuf, &l, sizeof(long));
return l;
}

static inline
float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
{
@@ -285,8 +311,14 @@ float rdwr_readFloat(BridgeRingBuffer* const ringbuf)
static inline
void rdwr_writeOpcode(BridgeRingBuffer* const ringbuf, const PluginBridgeOpcode opcode)
{
const int i = opcode;
rdwr_tryWrite(ringbuf, &i, sizeof(int));
const int intcode(static_cast<int>(opcode));
rdwr_tryWrite(ringbuf, &intcode, sizeof(int));
}

static inline
void rdwr_writeChar(BridgeRingBuffer* const ringbuf, const char value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(char));
}

static inline
@@ -295,6 +327,12 @@ void rdwr_writeInt(BridgeRingBuffer* const ringbuf, const int value)
rdwr_tryWrite(ringbuf, &value, sizeof(int));
}

static inline
void rdwr_writeLong(BridgeRingBuffer* const ringbuf, const long value)
{
rdwr_tryWrite(ringbuf, &value, sizeof(long));
}

static inline
void rdwr_writeFloat(BridgeRingBuffer* const ringbuf, const float value)
{


Loading…
Cancel
Save