Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/src/jackbridge/NativeBridge.hpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/distrho/src/jackbridge/NativeBridge.hpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,329 @@ +/* + * Native Bridge for DPF + * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef NATIVE_BRIDGE_HPP_INCLUDED +#define NATIVE_BRIDGE_HPP_INCLUDED + +#include "JackBridge.hpp" + +#include "../../extra/RingBuffer.hpp" + +#if DISTRHO_PLUGIN_NUM_INPUTS > 2 +# define DISTRHO_PLUGIN_NUM_INPUTS_2 2 +#else +# define DISTRHO_PLUGIN_NUM_INPUTS_2 DISTRHO_PLUGIN_NUM_INPUTS +#endif + +#if DISTRHO_PLUGIN_NUM_OUTPUTS > 2 +# define DISTRHO_PLUGIN_NUM_OUTPUTS_2 2 +#else +# define DISTRHO_PLUGIN_NUM_OUTPUTS_2 DISTRHO_PLUGIN_NUM_OUTPUTS +#endif + +using DISTRHO_NAMESPACE::HeapRingBuffer; + +struct NativeBridge { + // Current status information + uint bufferSize; + uint sampleRate; + + // Port caching information + uint numAudioIns; + uint numAudioOuts; + uint numCvIns; + uint numCvOuts; + uint numMidiIns; + uint numMidiOuts; + + // JACK callbacks + JackProcessCallback jackProcessCallback = nullptr; + JackBufferSizeCallback bufferSizeCallback = nullptr; + void* jackProcessArg = nullptr; + void* jackBufferSizeArg = nullptr; + + // Runtime buffers + enum PortMask { + kPortMaskAudio = 0x1000, + kPortMaskCV = 0x2000, + kPortMaskMIDI = 0x4000, + kPortMaskInput = 0x10000, + kPortMaskOutput = 0x20000, + kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, + kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, + }; +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; + float* audioBufferStorage; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + bool midiAvailable; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + static constexpr const uint32_t kMaxMIDIInputMessageSize = 3; + uint8_t midiDataStorage[kMaxMIDIInputMessageSize]; + HeapRingBuffer midiInBufferCurrent; + HeapRingBuffer midiInBufferPending; +#endif +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + HeapRingBuffer midiOutBuffer; +#endif + + NativeBridge() + : bufferSize(0), + sampleRate(0), + numAudioIns(0), + numAudioOuts(0), + numCvIns(0), + numCvOuts(0), + numMidiIns(0), + numMidiOuts(0), + jackProcessCallback(nullptr), + bufferSizeCallback(nullptr), + jackProcessArg(nullptr), + jackBufferSizeArg(nullptr) + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + , audioBuffers() + , audioBufferStorage(nullptr) + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + , midiAvailable(false) + #endif + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + std::memset(audioBuffers, 0, sizeof(audioBuffers)); + #endif + } + + virtual ~NativeBridge() {} + virtual bool open(const char* const clientName) = 0; + virtual bool close() = 0; + virtual bool activate() = 0; + virtual bool deactivate() = 0; + + virtual bool supportsAudioInput() const + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return true; + #else + return false; + #endif + } + + virtual bool isAudioInputEnabled() const + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + return true; + #else + return false; + #endif + } + + virtual bool supportsBufferSizeChanges() const { return false; } + virtual bool isMIDIEnabled() const { return false; } + virtual bool requestAudioInput() { return false; } + virtual bool requestBufferSizeChange(uint32_t) { return false; } + virtual bool requestMIDI() { return false; } + + uint32_t getBufferSize() const noexcept + { + return bufferSize; + } + + bool supportsMIDI() const noexcept + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + return midiAvailable; + #else + return false; + #endif + } + + uint32_t getEventCount() + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + if (midiAvailable) + { + // NOTE: this function is only called once per run + midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending); + return midiInBufferCurrent.getReadableDataSize() / (kMaxMIDIInputMessageSize + 1u); + } + #endif + + return 0; + } + + bool getEvent(jack_midi_event_t* const event) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // NOTE: this function is called for all events in index succession + if (midiAvailable && midiInBufferCurrent.getReadableDataSize() >= (kMaxMIDIInputMessageSize + 1u)) + { + event->time = 0; // TODO + event->size = midiInBufferCurrent.readByte(); + event->buffer = midiDataStorage; + return midiInBufferCurrent.readCustomData(midiDataStorage, kMaxMIDIInputMessageSize); + } + #endif + return false; + // maybe unused + (void)event; + } + + void clearEventBuffer() + { + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + midiOutBuffer.clearData(); + #endif + } + + bool writeEvent(const jack_nframes_t time, const jack_midi_data_t* const data, const uint32_t size) + { + if (size > 3) + return false; + + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if (midiAvailable) + { + if (midiOutBuffer.writeByte(size) && midiOutBuffer.writeCustomData(data, size)) + { + bool fail = false; + // align + switch (size) + { + case 1: fail |= !midiOutBuffer.writeByte(0); + // fall-through + case 2: fail |= !midiOutBuffer.writeByte(0); + } + fail |= !midiOutBuffer.writeUInt(time); + midiOutBuffer.commitWrite(); + return !fail; + } + midiOutBuffer.commitWrite(); + } + #endif + + return false; + // maybe unused + (void)data; + (void)time; + } + + void allocBuffers(const bool audio, const bool midi) + { + DISTRHO_SAFE_ASSERT_RETURN(bufferSize != 0,); + + if (audio) + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; + + for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + audioBuffers[i] = audioBufferStorage + (bufferSize * i); + #endif + + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS); + #endif + } + + if (midi) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512); + midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.createBuffer(2048); + #endif + } + } + + void freeBuffers() + { + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + delete[] audioBufferStorage; + audioBufferStorage = nullptr; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + midiInBufferCurrent.deleteBuffer(); + midiInBufferPending.deleteBuffer(); + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + midiOutBuffer.deleteBuffer(); + #endif + } + + jack_port_t* registerPort(const char* const type, const ulong flags) + { + uintptr_t ret = 0; + + /**/ if (flags & JackPortIsInput) + ret |= kPortMaskInput; + else if (flags & JackPortIsOutput) + ret |= kPortMaskOutput; + else + return nullptr; + + /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0) + { + if (flags & JackPortIsControlVoltage) + { + ret |= kPortMaskAudio; + ret += flags & JackPortIsInput ? numAudioIns++ : numAudioOuts++; + } + else + { + ret |= kPortMaskCV; + ret += flags & JackPortIsInput ? numCvIns++ : numCvOuts++; + } + } + else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0) + { + ret |= kPortMaskMIDI; + ret += flags & JackPortIsInput ? numMidiIns++ : numMidiOuts++; + } + else + { + return nullptr; + } + + return (jack_port_t*)ret; + } + + void* getPortBuffer(jack_port_t* const port) + { + const uintptr_t portMask = (uintptr_t)port; + DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr); + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (portMask & (kPortMaskAudio|kPortMaskCV)) + return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)]; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI) + return (void*)0x1; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI) + return (void*)0x2; + #endif + + return nullptr; + } +}; + +#endif // NATIVE_BRIDGE_HPP_INCLUDED