Skip to content

Commit

Permalink
Export internal audio and midi players as LV2 plugins
Browse files Browse the repository at this point in the history
Signed-off-by: falkTX <falktx@falktx.com>
  • Loading branch information
falkTX committed Jun 21, 2019
1 parent c5338fa commit 9bee2ff
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 17 deletions.
6 changes: 4 additions & 2 deletions source/plugin/carla-base.cpp
Expand Up @@ -59,8 +59,10 @@ struct PluginListManager {
std::strcmp(desc->label, "carlapatchbay3s" ) == 0 ||
std::strcmp(desc->label, "carlapatchbay16" ) == 0 ||
std::strcmp(desc->label, "carlapatchbay32" ) == 0 ||
std::strcmp(desc->label, "bigmeter" ) == 0 /*||
std::strcmp(desc->label, "notes" ) == 0*/)
std::strcmp(desc->label, "bigmeter" ) == 0 ||
/*std::strcmp(desc->label, "notes" ) == 0*/
std::strcmp(desc->label, "audiofile" ) == 0 ||
std::strcmp(desc->label, "midifile" ) == 0)
{
descs.append(desc);
}
Expand Down
40 changes: 28 additions & 12 deletions source/plugin/carla-lv2-export.cpp
Expand Up @@ -24,6 +24,7 @@
#include "lv2/midi.h"
#include "lv2/options.h"
#include "lv2/parameters.h"
#include "lv2/patch.h"
#include "lv2/port-props.h"
#include "lv2/state.h"
#include "lv2/time.h"
Expand Down Expand Up @@ -111,6 +112,7 @@ static void writeManifestFile(PluginListManager& plm)
// -------------------------------------------------------------------
// Header

text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n";
text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
Expand Down Expand Up @@ -158,6 +160,15 @@ static void writeManifestFile(PluginListManager& plm)
# endif
#endif

// -------------------------------------------------------------------
// File handling

text += "<http://kxstudio.sf.net/carla/file>\n";
text += " a lv2:Parameter ;\n";
text += " rdfs:label \"file\" ;\n";
text += " rdfs:range atom:Path .\n";
text += "\n";

// -------------------------------------------------------------------
// Write file now

Expand Down Expand Up @@ -216,15 +227,16 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc)
// -------------------------------------------------------------------
// Header

text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
text += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
text += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n";
text += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n";
text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
text += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
text += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n";
text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
text += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
text += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n";
text += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n";
text += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n";
text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
text += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
text += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n";
text += "\n";

// -------------------------------------------------------------------
Expand Down Expand Up @@ -287,7 +299,7 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc)

text += " lv2:extensionData <" LV2_OPTIONS__interface "> ;\n";

if (pluginDesc->hints & NATIVE_PLUGIN_USES_STATE)
if ((pluginDesc->hints & NATIVE_PLUGIN_USES_STATE) || (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE))
text += " lv2:extensionData <" LV2_STATE__interface "> ;\n";

if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH)
Expand All @@ -310,7 +322,7 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc)
// UIs

#ifdef HAVE_PYQT
if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI)
if ((pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0 && (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) == 0)
{
text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ;\n";
text += "\n";
Expand All @@ -320,7 +332,8 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc)
// -------------------------------------------------------------------
// First input MIDI/Time/UI port

const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0 || (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0;
const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0
|| (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0;

if (pluginDesc->midiIns > 0 || hasEventInPort)
{
Expand Down Expand Up @@ -375,6 +388,9 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc)
text += " ] ;\n\n";
}

if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
text += " patch:writable <http://kxstudio.sf.net/carla/file> ;\n\n";

// -------------------------------------------------------------------
// MIDI inputs

Expand Down
74 changes: 71 additions & 3 deletions source/plugin/carla-lv2.cpp
Expand Up @@ -71,6 +71,7 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
#ifdef USING_JUCE
fJuceInitialiser(),
#endif
fLoadedFile(),
fWorkerUISignal(0)
{
carla_zeroStruct(fHost);
Expand Down Expand Up @@ -244,6 +245,8 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>

if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1)
{
CARLA_SAFE_ASSERT_CONTINUE((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) == 0);

if (fWorker != nullptr)
{
// worker is supported by the host, we can continue
Expand All @@ -260,6 +263,34 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
continue;
}

if (event->body.type == fURIs.atomObject)
{
const LV2_Atom_Object* const obj = (const LV2_Atom_Object*)(&event->body);

if (obj->body.otype == fURIs.patchSet) {
// Get property URI.
const LV2_Atom* property = NULL;
lv2_atom_object_get(obj, fURIs.patchProperty, &property, 0);
CARLA_SAFE_ASSERT_CONTINUE(property != nullptr);
CARLA_SAFE_ASSERT_CONTINUE(property->type == fURIs.atomURID);
CARLA_SAFE_ASSERT_CONTINUE(((const LV2_Atom_URID*)property)->body == fURIs.carlaFile);

// Get value.
const LV2_Atom* fileobj = NULL;
lv2_atom_object_get(obj, fURIs.patchValue, &fileobj, 0);
CARLA_SAFE_ASSERT_CONTINUE(fileobj != nullptr);
CARLA_SAFE_ASSERT_CONTINUE(fileobj->type == fURIs.atomPath);

const char* const filepath((const char*)(fileobj + 1));

fWorker->schedule_work(fWorker->handle,
static_cast<uint32_t>(std::strlen(filepath) + 1U),
filepath);
}

continue;
}

if (event->body.type != fURIs.midiEvent)
continue;
if (event->body.size > 4)
Expand Down Expand Up @@ -366,6 +397,17 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle,
const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const
{
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
{
store(handle,
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
fLoadedFile.buffer(),
fLoadedFile.length()+1,
fURIs.atomPath,
LV2_STATE_IS_POD);
return LV2_STATE_SUCCESS;
}

if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr)
return LV2_STATE_ERR_NO_FEATURE;

Expand All @@ -380,13 +422,31 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
}

LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle,
uint32_t flags, const LV2_Feature* const* const /*features*/) const
uint32_t flags, const LV2_Feature* const* const /*features*/)
{
size_t size = 0;
uint32_t type = 0;

if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
{
size = type = 0;
const void* const data = retrieve(handle,
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
&size, &type, &flags);

CARLA_SAFE_ASSERT_RETURN(type == fURIs.atomPath, LV2_STATE_ERR_UNKNOWN);

const char* const filename = (const char*)data;

fLoadedFile = filename;
fDescriptor->set_custom_data(fHandle, "file", filename);
return LV2_STATE_SUCCESS;
}

if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr)
return LV2_STATE_ERR_NO_FEATURE;

size_t size = 0;
uint32_t type = 0;
size = type = 0;
const void* const data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags);

if (size == 0)
Expand All @@ -409,6 +469,13 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
{
const char* const msg = (const char*)data;

if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
{
fLoadedFile = msg;
fDescriptor->set_custom_data(fHandle, "file", msg);
return LV2_WORKER_SUCCESS;
}

/**/ if (std::strncmp(msg, "control ", 8) == 0)
{
if (fDescriptor->ui_set_parameter_value == nullptr)
Expand Down Expand Up @@ -767,6 +834,7 @@ class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
juce::SharedResourcePointer<juce::ScopedJuceInitialiser_GUI> fJuceInitialiser;
#endif

CarlaString fLoadedFile;
int fWorkerUISignal;

// -------------------------------------------------------------------
Expand Down
21 changes: 21 additions & 0 deletions source/utils/CarlaLv2Utils.hpp
Expand Up @@ -569,6 +569,7 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
fBufferSize(0),
fSampleRate(sampleRate),
fUridMap(nullptr),
fUridUnmap(nullptr),
fWorker(nullptr),
fTimeInfo(),
fLastPositionData(),
Expand Down Expand Up @@ -660,6 +661,7 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
fUridMap = uridMap;
fURIs.map(uridMap);

fUridUnmap = uridUnmap;
fWorker = worker;

clearTimeData();
Expand Down Expand Up @@ -1175,6 +1177,7 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat

// LV2 host features
const LV2_URID_Map* fUridMap;
const LV2_URID_Unmap* fUridUnmap;
const LV2_Worker_Schedule* fWorker;

// Time info stuff
Expand Down Expand Up @@ -1475,9 +1478,15 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
LV2_URID atomFloat;
LV2_URID atomInt;
LV2_URID atomLong;
LV2_URID atomPath;
LV2_URID atomSequence;
LV2_URID atomString;
LV2_URID atomURID;
LV2_URID carlaFile;
LV2_URID midiEvent;
LV2_URID patchProperty;
LV2_URID patchSet;
LV2_URID patchValue;
LV2_URID timePos;
LV2_URID timeBar;
LV2_URID timeBarBeat;
Expand All @@ -1496,9 +1505,15 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
atomFloat(0),
atomInt(0),
atomLong(0),
atomPath(0),
atomSequence(0),
atomString(0),
atomURID(0),
carlaFile(0),
midiEvent(0),
patchProperty(0),
patchSet(0),
patchValue(0),
timePos(0),
timeBar(0),
timeBarBeat(0),
Expand All @@ -1518,9 +1533,15 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);
atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long);
atomPath = uridMap->map(uridMap->handle, LV2_ATOM__Path);
atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence);
atomString = uridMap->map(uridMap->handle, LV2_ATOM__String);
atomURID = uridMap->map(uridMap->handle, LV2_ATOM__URID);
carlaFile = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file");
midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent);
patchProperty = uridMap->map(uridMap->handle, LV2_PATCH__property);
patchSet = uridMap->map(uridMap->handle, LV2_PATCH__Set);
patchValue = uridMap->map(uridMap->handle, LV2_PATCH__value);
timePos = uridMap->map(uridMap->handle, LV2_TIME__Position);
timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar);
timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat);
Expand Down

0 comments on commit 9bee2ff

Please sign in to comment.