Browse Source

Add JACK (standalone) export support

gh-pages
falkTX 9 years ago
parent
commit
b4ac031105
6 changed files with 366 additions and 5 deletions
  1. +0
    -1
      dgl/Makefile.mk
  2. +2
    -0
      distrho/DistrhoPluginMain.cpp
  3. +2
    -0
      distrho/DistrhoUIMain.cpp
  4. +2
    -2
      distrho/src/DistrhoPluginCarla.cpp
  5. +344
    -0
      distrho/src/DistrhoPluginJack.cpp
  6. +16
    -2
      distrho/src/DistrhoUIInternal.hpp

+ 0
- 1
dgl/Makefile.mk View File

@@ -47,7 +47,6 @@ LINK_OPTS =
else
BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden
CXXFLAGS += -fvisibility-inlines-hidden
LINK_OPTS += -Wl,--strip-all
endif

BUILD_C_FLAGS = $(BASE_FLAGS) -std=c99 -std=gnu99 $(CFLAGS)


+ 2
- 0
distrho/DistrhoPluginMain.cpp View File

@@ -18,6 +18,8 @@

#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
# include "src/DistrhoPluginCarla.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_JACK)
# include "src/DistrhoPluginJack.cpp"
#elif (defined(DISTRHO_PLUGIN_TARGET_LADSPA) || defined(DISTRHO_PLUGIN_TARGET_DSSI))
# include "src/DistrhoPluginLADSPA+DSSI.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_LV2)


+ 2
- 0
distrho/DistrhoUIMain.cpp View File

@@ -18,6 +18,8 @@

#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
// nothing
#elif defined(DISTRHO_PLUGIN_TARGET_JACK)
// nothing
#elif defined(DISTRHO_PLUGIN_TARGET_DSSI)
# include "src/DistrhoUIDSSI.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_LV2)


+ 2
- 2
distrho/src/DistrhoPluginCarla.cpp View File

@@ -332,12 +332,12 @@ protected:
carla_copy<uint8_t>(realMidiEvent.buf, midiEvent.data, midiEvent.size);
}

fPlugin.run(inBuffer, outBuffer, frames, realMidiEvents, midiEventCount);
fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount);
}
#else
void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override
{
fPlugin.run(inBuffer, outBuffer, frames);
fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames);
}
#endif



+ 344
- 0
distrho/src/DistrhoPluginJack.cpp View File

@@ -0,0 +1,344 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* For a full copy of the license see the LGPL.txt file
*/

#include "DistrhoPluginInternal.hpp"

#if ! DISTRHO_PLUGIN_HAS_UI
# error JACK export requires an UI
#endif

#include "DistrhoUIInternal.hpp"

#include "jack/jack.h"
#include "jack/midiport.h"
#include "jack/transport.h"

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

START_NAMESPACE_DISTRHO

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

class PluginJack
{
public:
PluginJack(jack_client_t* client)
: fPlugin(),
fUI(this, 0, nullptr, nullptr, nullptr, nullptr, uiResizeCallback, fPlugin.getInstancePointer()),
fClient(client)
{
char strBuf[0xff+1];
strBuf[0xff] = '\0';

#if DISTRHO_PLUGIN_NUM_INPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
{
std::snprintf(strBuf, 0xff, "in%i", i+1);
fPortAudioIns[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
}
#endif

#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
{
std::snprintf(strBuf, 0xff, "out%i", i+1);
fPortAudioOuts[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
fPortMidiIn = jack_port_register(fClient, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
#endif

jack_set_buffer_size_callback(fClient, jackBufferSizeCallback, this);
jack_set_sample_rate_callback(fClient, jackSampleRateCallback, this);
jack_set_process_callback(fClient, jackProcessCallback, this);
jack_on_shutdown(fClient, jackShutdownCallback, this);

jack_activate(fClient);

if (const char* const name = jack_get_client_name(fClient))
fUI.setTitle(name);
else
fUI.setTitle(DISTRHO_PLUGIN_NAME);

fUI.exec();
}

~PluginJack()
{
if (fClient == nullptr)
return;

jack_deactivate(fClient);

#if DISTRHO_PLUGIN_IS_SYNTH
jack_port_unregister(fClient, fPortMidiIn);
fPortMidiIn = nullptr;
#endif

#if DISTRHO_PLUGIN_NUM_INPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
{
jack_port_unregister(fClient, fPortAudioIns[i]);
fPortAudioIns[i] = nullptr;
}
#endif

#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
{
jack_port_unregister(fClient, fPortAudioOuts[i]);
fPortAudioOuts[i] = nullptr;
}
#endif

jack_client_close(fClient);
}

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

protected:
void jackBufferSize(const jack_nframes_t nframes)
{
fPlugin.setBufferSize(nframes, true);
}

void jackSampleRate(const jack_nframes_t nframes)
{
fPlugin.setSampleRate(nframes, true);
}

void jackProcess(const jack_nframes_t nframes)
{
#if DISTRHO_PLUGIN_NUM_INPUTS > 0
const float* audioIns[DISTRHO_PLUGIN_NUM_INPUTS];

for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
audioIns[i] = (const float*)jack_port_get_buffer(fPortAudioIns[i], nframes);
#else
static const float** audioIns = nullptr;
#endif

#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
float* audioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];

for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
audioOuts[i] = (float*)jack_port_get_buffer(fPortAudioOuts[i], nframes);
#else
static float** audioOuts = nullptr;
#endif

#if DISTRHO_PLUGIN_WANT_TIMEPOS
jack_position_t pos;
fTimePos.playing = (jack_transport_query(fClient, &pos) == JackTransportRolling);

if (pos.unique_1 == pos.unique_2)
{
if (pos.valid & JackTransportPosition)
fTimePos.frame = pos.frame;
else
fTimePos.frame = 0;

if (pos.valid & JackTransportBBT)
{
fTimePos.bbt.valid = true;

fTimePos.bbt.bar = pos.bar;
fTimePos.bbt.beat = pos.beat;
fTimePos.bbt.tick = pos.tick;
fTimePos.bbt.barStartTick = pos.bar_start_tick;

fTimePos.bbt.beatsPerBar = pos.beats_per_bar;
fTimePos.bbt.beatType = pos.beat_type;

fTimePos.bbt.ticksPerBeat = pos.ticks_per_beat;
fTimePos.bbt.beatsPerMinute = pos.beats_per_minute;
}
else
fTimePos.bbt.valid = false;
}

fPlugin.setTimePos(fTimePos);
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void* const midiBuf = jack_port_get_buffer(fPortMidiIn, nframes);

if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf))
{
uint32_t midiEventCount = 0;
MidiEvent midiEvents[eventCount];

jack_midi_event_t jevent;

for (uint32_t i=0; i < eventCount; ++i)
{
if (jack_midi_event_get(&jevent, midiBuf, i) != 0)
break;
if (jevent.size > 4)
continue;

MidiEvent& midiEvent(midiEvents[midiEventCount++]);

midiEvent.frame = jevent.time;
midiEvent.size = jevent.size;
std::memcpy(midiEvent.buf, jevent.buffer, jevent.size);
}

fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount);
}
else
{
fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0);
}
#else
fPlugin.run(audioIns, audioOuts, nframes);
#endif
}

void jackShutdown()
{
d_stderr("jack has shutdown, quitting now...");
fClient = nullptr;
fUI.quit();
}

void uiResize(const uint width, const uint height)
{
fUI.setSize(width, height);
}

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

private:
PluginExporter fPlugin;
UIExporter fUI;

jack_client_t* fClient;

#if DISTRHO_PLUGIN_NUM_INPUTS > 0
jack_port_t* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
#endif
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
#endif
#if DISTRHO_PLUGIN_IS_SYNTH
jack_port_t* fPortMidiIn;
#endif
#if DISTRHO_PLUGIN_WANT_TIMEPOS
TimePos fTimePos;
#endif

// -------------------------------------------------------------------
// Callbacks

#define uiPtr ((PluginJack*)ptr)

static int jackBufferSizeCallback(jack_nframes_t nframes, void* ptr)
{
uiPtr->jackBufferSize(nframes);
return 0;
}

static int jackSampleRateCallback(jack_nframes_t nframes, void* ptr)
{
uiPtr->jackSampleRate(nframes);
return 0;
}

static int jackProcessCallback(jack_nframes_t nframes, void* ptr)
{
uiPtr->jackProcess(nframes);
return 0;
}

static void jackShutdownCallback(void* ptr)
{
uiPtr->jackShutdown();
}

static void uiResizeCallback(void* ptr, uint width, uint height)
{
uiPtr->uiResize(width, height);
}

#undef uiPtr
};

END_NAMESPACE_DISTRHO

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

int main()
{
jack_status_t status = jack_status_t(0x0);
jack_client_t* client = jack_client_open(DISTRHO_PLUGIN_NAME, JackNoStartServer, &status);

if (client == nullptr)
{
d_string errorString;

if (status & JackFailure)
errorString += "Overall operation failed;\n";
if (status & JackInvalidOption)
errorString += "The operation contained an invalid or unsupported option;\n";
if (status & JackNameNotUnique)
errorString += "The desired client name was not unique;\n";
if (status & JackServerStarted)
errorString += "The JACK server was started as a result of this operation;\n";
if (status & JackServerFailed)
errorString += "Unable to connect to the JACK server;\n";
if (status & JackServerError)
errorString += "Communication error with the JACK server;\n";
if (status & JackNoSuchClient)
errorString += "Requested client does not exist;\n";
if (status & JackLoadFailure)
errorString += "Unable to load internal client;\n";
if (status & JackInitFailure)
errorString += "Unable to initialize client;\n";
if (status & JackShmFailure)
errorString += "Unable to access shared memory;\n";
if (status & JackVersionError)
errorString += "Client's protocol version does not match;\n";
if (status & JackBackendError)
errorString += "Backend Error;\n";
if (status & JackClientZombie)
errorString += "Client is being shutdown against its will;\n";

if (errorString.isNotEmpty())
{
errorString[errorString.length()-2] = '.';
d_stderr("Failed to create jack client, reason was:\n%s", errorString.buffer());
}
else
d_stderr("Failed to create jack client, cannot continue!");

return 1;
}

USE_NAMESPACE_DISTRHO;

d_lastBufferSize = jack_get_buffer_size(client);
d_lastSampleRate = jack_get_sample_rate(client);
d_lastUiSampleRate = d_lastSampleRate;

const PluginJack p(client);

return 0;
}

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

+ 16
- 2
distrho/src/DistrhoUIInternal.hpp View File

@@ -123,7 +123,7 @@ struct UI::PrivateData {
// -----------------------------------------------------------------------
// UI exporter class

class UIExporter
class UIExporter : public DGL::IdleCallback
{
public:
UIExporter(void* const ptr, const intptr_t winId,
@@ -223,6 +223,15 @@ public:

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

void exec()
{
DISTRHO_SAFE_ASSERT_RETURN(fUi != nullptr,);

glWindow.addIdleCallback(this);
glWindow.setVisible(true);
glApp.exec();
}

bool idle()
{
DISTRHO_SAFE_ASSERT_RETURN(fUi != nullptr, false);
@@ -266,6 +275,12 @@ public:
return ! glApp.isQuiting();
}

protected:
void idleCallback() override
{
fUi->d_uiIdle();
}

private:
// -------------------------------------------------------------------
// DGL Application and Window for this plugin
@@ -280,7 +295,6 @@ private:
UI::PrivateData* const fData;

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
DISTRHO_PREVENT_HEAP_ALLOCATION
};

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


Loading…
Cancel
Save