@@ -0,0 +1,19 @@ | |||||
.directory | |||||
.fuse-* | |||||
.*.kate-swp | |||||
*~ | |||||
*.o | |||||
*.a | |||||
*.exe | |||||
*.so | |||||
*.dll | |||||
*.pyc | |||||
ui_*.py | |||||
icons_rc.py | |||||
carla-discovery-* | |||||
aeffect.h | |||||
aeffectx.h |
@@ -0,0 +1,55 @@ | |||||
#!/usr/bin/make -f | |||||
# Makefile for Carla-Discovery # | |||||
# ----------------------------------------- # | |||||
# Created by falkTX | |||||
# | |||||
CXX ?= g++ | |||||
BUILD_FLAGS = -ffast-math -fomit-frame-pointer -mtune=generic -msse -O2 -Wall -I../carla-includes $(CXXFLAGS) | |||||
BUILD_FLAGS += -DVESTIGE_HEADER -I../carla-includes/vestige # Comment this line to not use vestige header | |||||
LINK_FLAGS = $(LDFLAGS) | |||||
32BIT_FLAGS = -m32 | |||||
64BIT_FLAGS = -m64 #-fPIC | |||||
UNIX_32BIT_FLAGS = -L/usr/lib32 -L/usr/lib/i386-linux-gnu $(32BIT_FLAGS) | |||||
UNIX_64BIT_FLAGS = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu $(64BIT_FLAGS) | |||||
UNIX_LINK_FLAGS = -ldl $(LINK_FLAGS) | |||||
WIN32_FLAGS = $(32BIT_FLAGS) -static | |||||
WIN64_FLAGS = $(64BIT_FLAGS) -static | |||||
ifeq ($(FLUIDSYNTH),) | |||||
else | |||||
BUILD_FLAGS += `pkg-config --cflags fluidsynth` -DWANT_FLUIDSYNTH | |||||
LINK_FLAGS += `pkg-config --libs fluidsynth` | |||||
endif | |||||
all: | |||||
@echo "Build type must be unix32, unix64, win32 or win64" | |||||
unix32: carla-discovery-unix32 | |||||
unix64: carla-discovery-unix64 | |||||
win32: carla-discovery-win32.exe | |||||
win64: carla-discovery-win64.exe | |||||
carla-discovery-unix32: carla-discovery.cpp | |||||
$(CXX) carla-discovery.cpp $(BUILD_FLAGS) $(UNIX_32BIT_FLAGS) $(UNIX_LINK_FLAGS) -o $@ | |||||
carla-discovery-unix64: carla-discovery.cpp | |||||
$(CXX) carla-discovery.cpp $(BUILD_FLAGS) $(UNIX_64BIT_FLAGS) $(UNIX_LINK_FLAGS) -o $@ | |||||
carla-discovery-win32.exe: carla-discovery.cpp | |||||
$(CXX) carla-discovery.cpp $(BUILD_FLAGS) $(WIN32_FLAGS) $(LINK_FLAGS) -o $@ | |||||
carla-discovery-win64.exe: carla-discovery.cpp | |||||
$(CXX) carla-discovery.cpp $(BUILD_FLAGS) $(WIN64_FLAGS) $(LINK_FLAGS) -o $@ | |||||
clean: | |||||
rm -f carla-discovery-* |
@@ -0,0 +1,895 @@ | |||||
/* Carla Plugin discovery code */ | |||||
#ifndef nullptr | |||||
const class { | |||||
public: | |||||
template<class T> operator T*() const | |||||
{ | |||||
return 0; | |||||
} | |||||
template<class C, class T> operator T C::*() const | |||||
{ | |||||
return 0; | |||||
} | |||||
private: | |||||
void operator&() const; | |||||
} nullptr_ = {}; | |||||
#define nullptr nullptr_ | |||||
#endif | |||||
#if defined(__WIN32__) || defined(__WIN64__) | |||||
#include <windows.h> | |||||
#ifndef __WINDOWS__ | |||||
#define __WINDOWS__ | |||||
#endif | |||||
#else | |||||
#include <dlfcn.h> | |||||
#ifndef __cdecl | |||||
#define __cdecl | |||||
#endif | |||||
#endif | |||||
#include <stdio.h> | |||||
#include <stdint.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <iostream> | |||||
#include "ladspa/ladspa.h" | |||||
#include "dssi/dssi.h" | |||||
#define VST_FORCE_DEPRECATED 0 | |||||
#include "aeffectx.h" | |||||
#if VESTIGE_HEADER | |||||
#warning Using vestige header | |||||
#define kVstVersion 2400 | |||||
#define effGetPlugCategory 35 | |||||
#define effSetBlockSizeAndSampleRate 43 | |||||
#define effShellGetNextPlugin 70 | |||||
#define effStartProcess 71 | |||||
#define effStopProcess 72 | |||||
#define effSetProcessPrecision 77 | |||||
#define kVstProcessPrecision32 0 | |||||
#define kPlugCategUnknown 0 | |||||
#define kPlugCategSynth 2 | |||||
#define kPlugCategAnalysis 3 | |||||
#define kPlugCategMastering 4 | |||||
#define kPlugCategRoomFx 6 | |||||
#define kPlugCategRestoration 8 | |||||
#define kPlugCategShell 10 | |||||
#define kPlugCategGenerator 11 | |||||
#endif | |||||
// we don't need to support SoundFonts in 32bit or Wine builds | |||||
#ifdef WANT_FLUIDSYNTH | |||||
#include <fluidsynth.h> | |||||
#endif | |||||
#define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl; | |||||
// fake values to test plugins with | |||||
const unsigned int bufferSize = 512; | |||||
const unsigned int sampleRate = 44100; | |||||
// ------------------------------ Carla main defs ------------------------------ | |||||
// plugin hints | |||||
const unsigned int PLUGIN_HAS_GUI = 0x01; | |||||
const unsigned int PLUGIN_IS_BRIDGE = 0x02; | |||||
const unsigned int PLUGIN_IS_SYNTH = 0x04; | |||||
const unsigned int PLUGIN_USES_CHUNKS = 0x08; | |||||
const unsigned int PLUGIN_CAN_DRYWET = 0x10; | |||||
const unsigned int PLUGIN_CAN_VOL = 0x20; | |||||
const unsigned int PLUGIN_CAN_BALANCE = 0x40; | |||||
enum PluginType { | |||||
PLUGIN_NONE = 0, | |||||
PLUGIN_LADSPA = 1, | |||||
PLUGIN_DSSI = 2, | |||||
PLUGIN_LV2 = 3, | |||||
PLUGIN_VST = 4, | |||||
PLUGIN_SF2 = 5 | |||||
}; | |||||
enum PluginInfoCategory { | |||||
PLUGIN_CATEGORY_NONE = 0, | |||||
PLUGIN_CATEGORY_SYNTH = 1, | |||||
PLUGIN_CATEGORY_DELAY = 2, // also Reverb | |||||
PLUGIN_CATEGORY_EQ = 3, | |||||
PLUGIN_CATEGORY_FILTER = 4, | |||||
PLUGIN_CATEGORY_DYNAMICS = 5, // Amplifier, Compressor, Gate | |||||
PLUGIN_CATEGORY_MODULATOR = 6, // Chorus, Flanger, Phaser | |||||
PLUGIN_CATEGORY_UTILITY = 7, // Analyzer, Converter, Mixer | |||||
PLUGIN_CATEGORY_OUTRO = 8 // used to check if a plugin has a category | |||||
}; | |||||
// ------------------------------ library functions ------------------------------ | |||||
void* lib_open(const char* filename) | |||||
{ | |||||
#ifdef __WINDOWS__ | |||||
return LoadLibraryA(filename); | |||||
#else | |||||
return dlopen(filename, RTLD_LAZY); | |||||
#endif | |||||
} | |||||
int lib_close(void* lib) | |||||
{ | |||||
#ifdef __WINDOWS__ | |||||
return FreeLibrary((HMODULE)lib); | |||||
#else | |||||
return dlclose(lib); | |||||
#endif | |||||
} | |||||
void* lib_symbol(void* lib, const char* symbol) | |||||
{ | |||||
#ifdef __WINDOWS__ | |||||
return (void*)GetProcAddress((HMODULE)lib, symbol); | |||||
#else | |||||
return dlsym(lib, symbol); | |||||
#endif | |||||
} | |||||
const char* lib_error(const char* filename) | |||||
{ | |||||
#ifdef __WINDOWS__ | |||||
static char libError[2048]; | |||||
memset(libError, 0, sizeof(char)*2048); | |||||
LPVOID winErrorString; | |||||
DWORD winErrorCode = GetLastError(); | |||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, winErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&winErrorString, 0, nullptr); | |||||
snprintf(libError, 2048, "%s: error code %li: %s", filename, winErrorCode, (const char*)winErrorString); | |||||
LocalFree(winErrorString); | |||||
return libError; | |||||
#else | |||||
(void)filename; | |||||
return dlerror(); | |||||
#endif | |||||
} | |||||
// ------------------------------ VST Stuff ------------------------------ | |||||
typedef AEffect* (*VST_Function)(audioMasterCallback); | |||||
intptr_t VstCurrentUniqueId = 0; | |||||
bool VstPluginCanDo(AEffect* effect, const char* feature) | |||||
{ | |||||
return (effect->dispatcher(effect, effCanDo, 0, 0, (void*)feature, 0.0f) == 1); | |||||
} | |||||
intptr_t VstHostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | |||||
{ | |||||
std::cout << "VstHostCallback(" << effect << ", " << opcode << ", " << index << ", " << value << ", " << ptr << ", " << opt << ")" << std::endl; | |||||
switch (opcode) | |||||
{ | |||||
case audioMasterAutomate: | |||||
if (effect) | |||||
effect->setParameter(effect, index, opt); | |||||
break; | |||||
case audioMasterVersion: | |||||
return kVstVersion; | |||||
case audioMasterCurrentId: | |||||
return VstCurrentUniqueId; | |||||
case audioMasterGetTime: | |||||
static VstTimeInfo timeInfo; | |||||
memset(&timeInfo, 0, sizeof(VstTimeInfo)); | |||||
timeInfo.sampleRate = sampleRate; | |||||
return (intptr_t)&timeInfo; | |||||
case audioMasterGetSampleRate: | |||||
return sampleRate; | |||||
case audioMasterGetBlockSize: | |||||
return bufferSize; | |||||
case audioMasterGetVendorString: | |||||
if (ptr) | |||||
strcpy((char*)ptr, "falkTX"); | |||||
break; | |||||
case audioMasterGetProductString: | |||||
if (ptr) | |||||
strcpy((char*)ptr, "Carla-Discovery"); | |||||
break; | |||||
case audioMasterGetVendorVersion: | |||||
return 0x05; // 0.5 | |||||
case audioMasterCanDo: | |||||
std::cout << "VstHostCallback:audioMasterCanDo - " << (char*)ptr << std::endl; | |||||
if (strcmp((char*)ptr, "sendVstEvents") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "sendVstMidiEvent") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "sendVstTimeInfo") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "receiveVstEvents") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "receiveVstMidiEvent") == 0) | |||||
return 1; | |||||
#if !VST_FORCE_DEPRECATED | |||||
else if (strcmp((char*)ptr, "receiveVstTimeInfo") == 0) | |||||
return -1; | |||||
#endif | |||||
else if (strcmp((char*)ptr, "reportConnectionChanges") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "acceptIOChanges") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "sizeWindow") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "offline") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "openFileSelector") == 0) | |||||
return -1; | |||||
else if (strcmp((char*)ptr, "closeFileSelector") == 0) | |||||
return -1; | |||||
else if (strcmp((char*)ptr, "startStopProcess") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "shellCategory") == 0) | |||||
return 1; | |||||
else if (strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime") == 0) | |||||
return -1; | |||||
else | |||||
{ | |||||
std::cerr << "VstHostCallback:audioMasterCanDo - Got uninplemented feature request '" << (char*)ptr << "'" << std::endl; | |||||
return 0; | |||||
} | |||||
case audioMasterGetLanguage: | |||||
return kVstLangEnglish; | |||||
default: | |||||
break; | |||||
} | |||||
return 0; | |||||
} | |||||
// ------------------------------ Plugin Check ------------------------------ | |||||
void do_ladspa_check(void* lib_handle) | |||||
{ | |||||
LADSPA_Handle handle; | |||||
const LADSPA_Descriptor* descriptor; | |||||
LADSPA_Descriptor_Function descfn = (LADSPA_Descriptor_Function)lib_symbol(lib_handle, "ladspa_descriptor"); | |||||
if (descfn == nullptr) | |||||
{ | |||||
DISCOVERY_OUT("error", "Not a LADSPA plugin"); | |||||
return; | |||||
} | |||||
unsigned long i = 0; | |||||
while ((descriptor = descfn(i++))) | |||||
{ | |||||
handle = descriptor->instantiate(descriptor, sampleRate); | |||||
if (handle) | |||||
{ | |||||
DISCOVERY_OUT("init", "-----------"); | |||||
DISCOVERY_OUT("name", descriptor->Name); | |||||
DISCOVERY_OUT("label", descriptor->Label); | |||||
DISCOVERY_OUT("maker", descriptor->Maker); | |||||
DISCOVERY_OUT("copyright", descriptor->Copyright); | |||||
DISCOVERY_OUT("id", descriptor->UniqueID); | |||||
int hints = 0; | |||||
PluginInfoCategory category = PLUGIN_CATEGORY_NONE; | |||||
int audio_ins = 0; | |||||
int audio_outs = 0; | |||||
int audio_total = 0; | |||||
int midi_ins = 0; | |||||
int midi_outs = 0; | |||||
int midi_total = 0; | |||||
int parameters_ins = 0; | |||||
int parameters_outs = 0; | |||||
int parameters_total = 0; | |||||
int programs_total = 0; | |||||
for (unsigned long j=0; j < descriptor->PortCount; j++) | |||||
{ | |||||
const LADSPA_PortDescriptor PortDescriptor = descriptor->PortDescriptors[j]; | |||||
if (PortDescriptor & LADSPA_PORT_AUDIO) | |||||
{ | |||||
if (PortDescriptor & LADSPA_PORT_INPUT) | |||||
audio_ins += 1; | |||||
else if (PortDescriptor & LADSPA_PORT_OUTPUT) | |||||
audio_outs += 1; | |||||
audio_total += 1; | |||||
} | |||||
else if (PortDescriptor & LADSPA_PORT_CONTROL) | |||||
{ | |||||
if (PortDescriptor & LADSPA_PORT_INPUT) | |||||
parameters_ins += 1; | |||||
else if (PortDescriptor & LADSPA_PORT_OUTPUT) | |||||
{ | |||||
if (strcmp(descriptor->PortNames[j], "latency") != 0 && strcmp(descriptor->PortNames[j], "_latency") != 0) | |||||
parameters_outs += 1; | |||||
} | |||||
parameters_total += 1; | |||||
} | |||||
} | |||||
// small crash-free plugin test | |||||
float bufferAudio[bufferSize][audio_total]; | |||||
memset(&bufferAudio, 0, sizeof(float)*bufferSize*audio_total); | |||||
float bufferParams[parameters_total]; | |||||
memset(&bufferParams, 0, sizeof(float)*parameters_total); | |||||
for (unsigned long j=0, iA=0, iP=0; j < descriptor->PortCount; j++) | |||||
{ | |||||
const LADSPA_PortDescriptor PortDescriptor = descriptor->PortDescriptors[j]; | |||||
if (PortDescriptor & LADSPA_PORT_AUDIO) | |||||
descriptor->connect_port(handle, j, bufferAudio[iA++]); | |||||
else if (PortDescriptor & LADSPA_PORT_CONTROL) | |||||
descriptor->connect_port(handle, j, &bufferParams[iP++]); | |||||
} | |||||
if (descriptor->activate) | |||||
descriptor->activate(handle); | |||||
descriptor->run(handle, bufferSize); | |||||
if (descriptor->deactivate) | |||||
descriptor->deactivate(handle); | |||||
DISCOVERY_OUT("hints", hints); | |||||
DISCOVERY_OUT("category", category); | |||||
DISCOVERY_OUT("audio.ins", audio_ins); | |||||
DISCOVERY_OUT("audio.outs", audio_outs); | |||||
DISCOVERY_OUT("audio.total", audio_total); | |||||
DISCOVERY_OUT("midi.ins", midi_ins); | |||||
DISCOVERY_OUT("midi.outs", midi_outs); | |||||
DISCOVERY_OUT("midi.total", midi_total); | |||||
DISCOVERY_OUT("parameters.ins", parameters_ins); | |||||
DISCOVERY_OUT("parameters.outs", parameters_outs); | |||||
DISCOVERY_OUT("parameters.total", parameters_total); | |||||
DISCOVERY_OUT("programs.total", programs_total); | |||||
DISCOVERY_OUT("end", "------------"); | |||||
if (descriptor->cleanup) | |||||
descriptor->cleanup(handle); | |||||
} | |||||
else | |||||
DISCOVERY_OUT("error", "Failed to init LADSPA plugin"); | |||||
} | |||||
} | |||||
void do_dssi_check(void* lib_handle) | |||||
{ | |||||
LADSPA_Handle handle; | |||||
const LADSPA_Descriptor* ldescriptor; | |||||
const DSSI_Descriptor* descriptor; | |||||
DSSI_Descriptor_Function descfn = (DSSI_Descriptor_Function)lib_symbol(lib_handle, "dssi_descriptor"); | |||||
if (descfn == nullptr) | |||||
{ | |||||
DISCOVERY_OUT("error", "Not a DSSI plugin"); | |||||
return; | |||||
} | |||||
unsigned long i = 0; | |||||
while ((descriptor = descfn(i++))) | |||||
{ | |||||
ldescriptor = descriptor->LADSPA_Plugin; | |||||
handle = ldescriptor->instantiate(ldescriptor, sampleRate); | |||||
if (handle) | |||||
{ | |||||
DISCOVERY_OUT("init", "-----------"); | |||||
DISCOVERY_OUT("name", ldescriptor->Name); | |||||
DISCOVERY_OUT("label", ldescriptor->Label); | |||||
DISCOVERY_OUT("maker", ldescriptor->Maker); | |||||
DISCOVERY_OUT("copyright", ldescriptor->Copyright); | |||||
DISCOVERY_OUT("id", ldescriptor->UniqueID); | |||||
int hints = 0; | |||||
PluginInfoCategory category = PLUGIN_CATEGORY_NONE; | |||||
int audio_ins = 0; | |||||
int audio_outs = 0; | |||||
int audio_total = 0; | |||||
int midi_ins = 0; | |||||
int midi_outs = 0; | |||||
int midi_total = 0; | |||||
int parameters_ins = 0; | |||||
int parameters_outs = 0; | |||||
int parameters_total = 0; | |||||
int programs_total = 0; | |||||
for (unsigned long j=0; j < ldescriptor->PortCount; j++) | |||||
{ | |||||
const LADSPA_PortDescriptor PortDescriptor = ldescriptor->PortDescriptors[j]; | |||||
if (PortDescriptor & LADSPA_PORT_AUDIO) | |||||
{ | |||||
if (PortDescriptor & LADSPA_PORT_INPUT) | |||||
audio_ins += 1; | |||||
else if (PortDescriptor & LADSPA_PORT_OUTPUT) | |||||
audio_outs += 1; | |||||
audio_total += 1; | |||||
} | |||||
else if (PortDescriptor & LADSPA_PORT_CONTROL) | |||||
{ | |||||
if (PortDescriptor & LADSPA_PORT_INPUT) | |||||
parameters_ins += 1; | |||||
else if (PortDescriptor & LADSPA_PORT_OUTPUT) | |||||
{ | |||||
if (strcmp(ldescriptor->PortNames[j], "latency") != 0 && strcmp(ldescriptor->PortNames[j], "_latency") != 0) | |||||
parameters_outs += 1; | |||||
} | |||||
parameters_total += 1; | |||||
} | |||||
} | |||||
if (descriptor->run_synth || descriptor->run_multiple_synths) | |||||
{ | |||||
midi_ins = 1; | |||||
midi_total = 1; | |||||
} | |||||
if (midi_ins > 0 && audio_outs > 0) | |||||
hints |= PLUGIN_IS_SYNTH; | |||||
if (descriptor->get_program) | |||||
{ | |||||
while ((descriptor->get_program(handle, programs_total))) | |||||
programs_total += 1; | |||||
} | |||||
// small crash-free plugin test | |||||
float bufferAudio[bufferSize][audio_total]; | |||||
memset(&bufferAudio, 0, sizeof(float)*bufferSize*audio_total); | |||||
float bufferParams[parameters_total]; | |||||
memset(&bufferParams, 0, sizeof(float)*parameters_total); | |||||
snd_seq_event_t midiEvents[2]; | |||||
memset(&midiEvents, 0, sizeof(snd_seq_event_t)*2); | |||||
unsigned long midiEventCount = 2; | |||||
midiEvents[0].type = SND_SEQ_EVENT_NOTEON; | |||||
midiEvents[0].data.note.note = 64; | |||||
midiEvents[0].data.note.velocity = 100; | |||||
midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF; | |||||
midiEvents[1].data.note.note = 64; | |||||
midiEvents[1].data.note.velocity = 0; | |||||
midiEvents[1].time.tick = bufferSize/2; | |||||
for (unsigned long j=0, iA=0, iP=0; j < ldescriptor->PortCount; j++) | |||||
{ | |||||
const LADSPA_PortDescriptor PortDescriptor = ldescriptor->PortDescriptors[j]; | |||||
if (PortDescriptor & LADSPA_PORT_AUDIO) | |||||
ldescriptor->connect_port(handle, j, bufferAudio[iA++]); | |||||
else if (PortDescriptor & LADSPA_PORT_CONTROL) | |||||
ldescriptor->connect_port(handle, j, &bufferParams[iP++]); | |||||
} | |||||
if (ldescriptor->activate) | |||||
ldescriptor->activate(handle); | |||||
if (descriptor->run_synth) | |||||
descriptor->run_synth(handle, bufferSize, midiEvents, midiEventCount); | |||||
else if (descriptor->run_multiple_synths) | |||||
{ | |||||
snd_seq_event_t* midiEventsPtr[] = { midiEvents, nullptr }; | |||||
descriptor->run_multiple_synths(1, &handle, bufferSize, midiEventsPtr, &midiEventCount); | |||||
} | |||||
else | |||||
ldescriptor->run(handle, bufferSize); | |||||
if (ldescriptor->deactivate) | |||||
ldescriptor->deactivate(handle); | |||||
DISCOVERY_OUT("hints", hints); | |||||
DISCOVERY_OUT("category", category); | |||||
DISCOVERY_OUT("audio.ins", audio_ins); | |||||
DISCOVERY_OUT("audio.outs", audio_outs); | |||||
DISCOVERY_OUT("audio.total", audio_total); | |||||
DISCOVERY_OUT("midi.ins", midi_ins); | |||||
DISCOVERY_OUT("midi.outs", midi_outs); | |||||
DISCOVERY_OUT("midi.total", midi_total); | |||||
DISCOVERY_OUT("parameters.ins", parameters_ins); | |||||
DISCOVERY_OUT("parameters.outs", parameters_outs); | |||||
DISCOVERY_OUT("parameters.total", parameters_total); | |||||
DISCOVERY_OUT("programs.total", programs_total); | |||||
DISCOVERY_OUT("end", "------------"); | |||||
if (ldescriptor->cleanup) | |||||
ldescriptor->cleanup(handle); | |||||
} | |||||
else | |||||
DISCOVERY_OUT("error", "Failed to init DSSI plugin"); | |||||
} | |||||
} | |||||
void do_lv2_check(const char* bundle) | |||||
{ | |||||
// TODO | |||||
(void)bundle; | |||||
} | |||||
void do_vst_check(void* lib_handle) | |||||
{ | |||||
VST_Function vstfn = (VST_Function)lib_symbol(lib_handle, "VSTPluginMain"); | |||||
if (vstfn == nullptr) | |||||
{ | |||||
if (vstfn == nullptr) | |||||
{ | |||||
#ifdef TARGET_API_MAC_CARBON | |||||
vstfn = (VST_Function)lib_symbol(lib_handle, "main_macho"); | |||||
if (vstfn == nullptr) | |||||
#endif | |||||
vstfn = (VST_Function)lib_symbol(lib_handle, "main"); | |||||
} | |||||
} | |||||
if (vstfn == nullptr) | |||||
{ | |||||
DISCOVERY_OUT("error", "Not a VST plugin"); | |||||
return; | |||||
} | |||||
AEffect* effect = vstfn(VstHostCallback); | |||||
if (effect && effect->magic == kEffectMagic) | |||||
{ | |||||
const char* c_name; | |||||
const char* c_product; | |||||
const char* c_vendor; | |||||
char buf_str[255] = { 0 }; | |||||
effect->dispatcher(effect, effGetEffectName, 0, 0, buf_str, 0.0f); | |||||
c_name = strdup((buf_str[0] != 0) ? buf_str : ""); | |||||
buf_str[0] = 0; | |||||
effect->dispatcher(effect, effGetProductString, 0, 0, buf_str, 0.0f); | |||||
c_product = strdup((buf_str[0] != 0) ? buf_str : ""); | |||||
buf_str[0] = 0; | |||||
effect->dispatcher(effect, effGetVendorString, 0, 0, buf_str, 0.0f); | |||||
c_vendor = strdup((buf_str[0] != 0) ? buf_str : ""); | |||||
VstCurrentUniqueId = effect->uniqueID; | |||||
intptr_t VstCategory = effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f); | |||||
while (true) | |||||
{ | |||||
DISCOVERY_OUT("init", "-----------"); | |||||
effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f); | |||||
DISCOVERY_OUT("name", c_name); | |||||
DISCOVERY_OUT("label", c_product); | |||||
DISCOVERY_OUT("maker", c_vendor); | |||||
DISCOVERY_OUT("copyright", c_vendor); | |||||
DISCOVERY_OUT("id", VstCurrentUniqueId); | |||||
int hints = 0; | |||||
PluginInfoCategory category = PLUGIN_CATEGORY_NONE; | |||||
switch (VstCategory) | |||||
{ | |||||
case kPlugCategUnknown: | |||||
category = PLUGIN_CATEGORY_NONE; | |||||
break; | |||||
case kPlugCategSynth: | |||||
category = PLUGIN_CATEGORY_SYNTH; | |||||
break; | |||||
case kPlugCategAnalysis: | |||||
category = PLUGIN_CATEGORY_UTILITY; | |||||
break; | |||||
case kPlugCategMastering: | |||||
category = PLUGIN_CATEGORY_DYNAMICS; | |||||
break; | |||||
case kPlugCategRoomFx: | |||||
category = PLUGIN_CATEGORY_DELAY; | |||||
break; | |||||
case kPlugCategRestoration: | |||||
category = PLUGIN_CATEGORY_UTILITY; | |||||
break; | |||||
case kPlugCategGenerator: | |||||
category = PLUGIN_CATEGORY_SYNTH; | |||||
break; | |||||
default: | |||||
category = PLUGIN_CATEGORY_OUTRO; | |||||
} | |||||
if (effect->flags & effFlagsHasEditor) | |||||
hints |= PLUGIN_HAS_GUI; | |||||
if (effect->flags & effFlagsIsSynth) | |||||
{ | |||||
hints |= PLUGIN_IS_SYNTH; | |||||
if (category == PLUGIN_CATEGORY_NONE) | |||||
category = PLUGIN_CATEGORY_SYNTH; | |||||
} | |||||
int audio_ins = effect->numInputs; | |||||
int audio_outs = effect->numOutputs; | |||||
int audio_total = audio_ins + audio_outs; | |||||
int midi_ins = 0; | |||||
int midi_outs = 0; | |||||
int midi_total = 0; | |||||
int parameters_ins = effect->numParams; | |||||
int parameters_outs = 0; | |||||
int parameters_total = parameters_ins; | |||||
int programs_total = effect->numPrograms; | |||||
if (VstPluginCanDo(effect, "receiveVstEvents") || VstPluginCanDo(effect, "receiveVstMidiEvent") || effect->flags & effFlagsIsSynth) | |||||
midi_ins = 1; | |||||
if (VstPluginCanDo(effect, "sendVstEvents") || VstPluginCanDo(effect, "sendVstMidiEvent")) | |||||
midi_outs = 1; | |||||
midi_total = midi_ins + midi_outs; | |||||
// small crash-free plugin test | |||||
float** bufferAudioIn = new float* [audio_ins]; | |||||
for (int j=0; j < audio_ins; j++) | |||||
{ | |||||
bufferAudioIn[j] = new float [bufferSize]; | |||||
memset(bufferAudioIn[j], 0, sizeof(float)*bufferSize); | |||||
} | |||||
float** bufferAudioOut = new float* [audio_outs]; | |||||
for (int j=0; j < audio_outs; j++) | |||||
{ | |||||
bufferAudioOut[j] = new float [bufferSize]; | |||||
memset(bufferAudioOut[j], 0, sizeof(float)*bufferSize); | |||||
} | |||||
struct { | |||||
int32_t numEvents; | |||||
intptr_t reserved; | |||||
VstEvent* data[2]; | |||||
} events; | |||||
VstMidiEvent midiEvents[2]; | |||||
memset(&midiEvents, 0, sizeof(VstMidiEvent)*2); | |||||
midiEvents[0].type = kVstMidiType; | |||||
midiEvents[0].byteSize = sizeof(VstMidiEvent); | |||||
midiEvents[0].midiData[0] = 0x90; | |||||
midiEvents[0].midiData[1] = 64; | |||||
midiEvents[0].midiData[2] = 100; | |||||
midiEvents[1].type = kVstMidiType; | |||||
midiEvents[1].byteSize = sizeof(VstMidiEvent); | |||||
midiEvents[1].midiData[0] = 0x90; | |||||
midiEvents[1].midiData[1] = 64; | |||||
midiEvents[1].deltaFrames = bufferSize/2; | |||||
events.numEvents = 2; | |||||
events.reserved = 0; | |||||
events.data[0] = (VstEvent*)&midiEvents[0]; | |||||
events.data[1] = (VstEvent*)&midiEvents[1]; | |||||
#if !VST_FORCE_DEPRECATED | |||||
effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, bufferSize, nullptr, sampleRate); | |||||
#endif | |||||
effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, sampleRate); | |||||
effect->dispatcher(effect, effSetBlockSize, 0, bufferSize, nullptr, 0.0f); | |||||
effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f); | |||||
effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f); | |||||
effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f); | |||||
if (midi_ins == 1) | |||||
effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f); | |||||
if (effect->flags & effFlagsCanReplacing) | |||||
effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, bufferSize); | |||||
#if !VST_FORCE_DEPRECATED | |||||
else | |||||
effect->process(effect, bufferAudioIn, bufferAudioOut, bufferSize); | |||||
#endif | |||||
effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f); | |||||
effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f); | |||||
for (int j=0; j < audio_ins; j++) | |||||
delete[] bufferAudioIn[j]; | |||||
for (int j=0; j < audio_outs; j++) | |||||
delete[] bufferAudioOut[j]; | |||||
delete[] bufferAudioIn; | |||||
delete[] bufferAudioOut; | |||||
DISCOVERY_OUT("hints", hints); | |||||
DISCOVERY_OUT("category", category); | |||||
DISCOVERY_OUT("audio.ins", audio_ins); | |||||
DISCOVERY_OUT("audio.outs", audio_outs); | |||||
DISCOVERY_OUT("audio.total", audio_total); | |||||
DISCOVERY_OUT("midi.ins", midi_ins); | |||||
DISCOVERY_OUT("midi.outs", midi_outs); | |||||
DISCOVERY_OUT("midi.total", midi_total); | |||||
DISCOVERY_OUT("parameters.ins", parameters_ins); | |||||
DISCOVERY_OUT("parameters.outs", parameters_outs); | |||||
DISCOVERY_OUT("parameters.total", parameters_total); | |||||
DISCOVERY_OUT("programs.total", programs_total); | |||||
effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f); | |||||
DISCOVERY_OUT("end", "------------"); | |||||
if (VstCategory == kPlugCategShell) | |||||
{ | |||||
buf_str[0] = 0; | |||||
VstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, buf_str, 0.0f); | |||||
if (VstCurrentUniqueId != 0) | |||||
{ | |||||
free((void*)c_name); | |||||
c_name = strdup((buf_str[0] != 0) ? buf_str : ""); | |||||
} | |||||
else | |||||
break; | |||||
} | |||||
else | |||||
break; | |||||
} | |||||
free((void*)c_name); | |||||
free((void*)c_product); | |||||
free((void*)c_vendor); | |||||
} | |||||
else | |||||
DISCOVERY_OUT("error", "Failed to init VST plugin"); | |||||
} | |||||
void do_sf2_check(const char* filename) | |||||
{ | |||||
#ifdef WANT_FLUIDSYNTH | |||||
if (fluid_is_soundfont(filename)) | |||||
{ | |||||
fluid_settings_t* f_settings = new_fluid_settings(); | |||||
fluid_synth_t* f_synth = new_fluid_synth(f_settings); | |||||
int f_id = fluid_synth_sfload(f_synth, filename, 0); | |||||
if (f_id >= 0) | |||||
{ | |||||
int programs = 0; | |||||
fluid_sfont_t* f_sfont; | |||||
fluid_preset_t f_preset; | |||||
f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id); | |||||
// initial check to know how much midi-programs we get | |||||
f_sfont->iteration_start(f_sfont); | |||||
while (f_sfont->iteration_next(f_sfont, &f_preset)) | |||||
programs += 1; | |||||
DISCOVERY_OUT("init", "-----------"); | |||||
DISCOVERY_OUT("name", ""); | |||||
DISCOVERY_OUT("label", ""); | |||||
DISCOVERY_OUT("maker", ""); | |||||
DISCOVERY_OUT("copyright", ""); | |||||
DISCOVERY_OUT("id", 0); | |||||
DISCOVERY_OUT("hints", 0); | |||||
DISCOVERY_OUT("category", PLUGIN_CATEGORY_SYNTH); | |||||
DISCOVERY_OUT("audio.ins", 0); | |||||
DISCOVERY_OUT("audio.outs", 2); | |||||
DISCOVERY_OUT("audio.total", 2); | |||||
DISCOVERY_OUT("midi.ins", 1); | |||||
DISCOVERY_OUT("midi.outs", 0); | |||||
DISCOVERY_OUT("midi.total", 1); | |||||
DISCOVERY_OUT("programs.total", programs); | |||||
// defined in Carla | |||||
DISCOVERY_OUT("parameters.ins", 13); | |||||
DISCOVERY_OUT("parameters.outs", 1); | |||||
DISCOVERY_OUT("parameters.total", 14); | |||||
DISCOVERY_OUT("end", "------------"); | |||||
} | |||||
else | |||||
DISCOVERY_OUT("error", "Failed to load SF2 file"); | |||||
delete_fluid_synth(f_synth); | |||||
delete_fluid_settings(f_settings); | |||||
} | |||||
else | |||||
DISCOVERY_OUT("error", "Not a SF2 file"); | |||||
#else | |||||
(void)filename; | |||||
DISCOVERY_OUT("error", "SF2 support not available"); | |||||
#endif | |||||
} | |||||
// ------------------------------ main entry point ------------------------------ | |||||
int main(int argc, char* argv[]) | |||||
{ | |||||
if (argc != 3) | |||||
return 1; | |||||
const char* type_str = argv[1]; | |||||
const char* filename = argv[2]; | |||||
bool open_lib; | |||||
PluginType type; | |||||
void* handle = 0; | |||||
if (strcmp(type_str, "LADSPA") == 0) | |||||
{ | |||||
open_lib = true; | |||||
type = PLUGIN_LADSPA; | |||||
} | |||||
else if (strcmp(type_str, "DSSI") == 0) | |||||
{ | |||||
open_lib = true; | |||||
type = PLUGIN_DSSI; | |||||
} | |||||
else if (strcmp(type_str, "LV2") == 0) | |||||
{ | |||||
open_lib = false; | |||||
type = PLUGIN_LV2; | |||||
} | |||||
else if (strcmp(type_str, "VST") == 0) | |||||
{ | |||||
open_lib = true; | |||||
type = PLUGIN_VST; | |||||
} | |||||
else if (strcmp(type_str, "SF2") == 0) | |||||
{ | |||||
open_lib = false; | |||||
type = PLUGIN_SF2; | |||||
} | |||||
else | |||||
{ | |||||
open_lib = false; | |||||
type = PLUGIN_NONE; | |||||
} | |||||
if (open_lib) | |||||
{ | |||||
handle = lib_open(filename); | |||||
if (handle == nullptr) | |||||
{ | |||||
const char* error = lib_error(filename); | |||||
// Since discovery can find multi-architecture binaries, don't print ELF related errors | |||||
if (error && (strstr(error, "wrong ELF class") == nullptr || strstr(error, "Bad EXE format") == nullptr)) | |||||
DISCOVERY_OUT("error", error); | |||||
return 1; | |||||
} | |||||
} | |||||
switch (type) | |||||
{ | |||||
case PLUGIN_LADSPA: | |||||
do_ladspa_check(handle); | |||||
break; | |||||
case PLUGIN_DSSI: | |||||
do_dssi_check(handle); | |||||
break; | |||||
case PLUGIN_LV2: | |||||
do_lv2_check(filename); | |||||
break; | |||||
case PLUGIN_VST: | |||||
do_vst_check(handle); | |||||
break; | |||||
case PLUGIN_SF2: | |||||
do_sf2_check(filename); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
if (open_lib) | |||||
lib_close(handle); | |||||
return 0; | |||||
} |
@@ -0,0 +1,437 @@ | |||||
/* -*- c-basic-offset: 4 -*- */ | |||||
/* dssi.h | |||||
DSSI version 1.0 | |||||
Copyright (c) 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton | |||||
This library 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; either version 2.1 of | |||||
the License, or (at your option) any later version. | |||||
This library 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. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |||||
MA 02110-1301 USA | |||||
*/ | |||||
#ifndef DSSI_INCLUDED | |||||
#define DSSI_INCLUDED | |||||
#include "../ladspa/ladspa.h" | |||||
#include "seq_event-compat.h" | |||||
#define DSSI_VERSION "1.0" | |||||
#define DSSI_VERSION_MAJOR 1 | |||||
#define DSSI_VERSION_MINOR 0 | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/* | |||||
There is a need for an API that supports hosted MIDI soft synths | |||||
with GUIs in Linux audio applications. In time the GMPI initiative | |||||
should comprehensively address this need, but the requirement for | |||||
Linux applications to be able to support simple hosted synths is | |||||
here now, and GMPI is not. This proposal (the "DSSI Soft Synth | |||||
Interface" or DSSI, pronounced "dizzy") aims to provide a simple | |||||
solution in a way that we hope will prove complete and compelling | |||||
enough to support now, yet not so compelling as to supplant GMPI or | |||||
any other comprehensive future proposal. | |||||
For simplicity and familiarity, this API is based as far as | |||||
possible on existing work -- the LADSPA plugin API for control | |||||
values and audio processing, and the ALSA sequencer event types for | |||||
MIDI event communication. The GUI part of the proposal is quite | |||||
new, but may also be applicable retroactively to LADSPA plugins | |||||
that do not otherwise support this synth interface. | |||||
*/ | |||||
typedef struct _DSSI_Program_Descriptor { | |||||
/** Bank number for this program. Note that DSSI does not support | |||||
MIDI-style separation of bank LSB and MSB values. There is no | |||||
restriction on the set of available banks: the numbers do not | |||||
need to be contiguous, there does not need to be a bank 0, etc. */ | |||||
unsigned long Bank; | |||||
/** Program number (unique within its bank) for this program. | |||||
There is no restriction on the set of available programs: the | |||||
numbers do not need to be contiguous, there does not need to | |||||
be a program 0, etc. */ | |||||
unsigned long Program; | |||||
/** Name of the program. */ | |||||
const char * Name; | |||||
} DSSI_Program_Descriptor; | |||||
typedef struct _DSSI_Descriptor { | |||||
/** | |||||
* DSSI_API_Version | |||||
* | |||||
* This member indicates the DSSI API level used by this plugin. | |||||
* If we're lucky, this will never be needed. For now all plugins | |||||
* must set it to 1. | |||||
*/ | |||||
int DSSI_API_Version; | |||||
/** | |||||
* LADSPA_Plugin | |||||
* | |||||
* A DSSI synth plugin consists of a LADSPA plugin plus an | |||||
* additional framework for controlling program settings and | |||||
* transmitting MIDI events. A plugin must fully implement the | |||||
* LADSPA descriptor fields as well as the required LADSPA | |||||
* functions including instantiate() and (de)activate(). It | |||||
* should also implement run(), with the same behaviour as if | |||||
* run_synth() (below) were called with no synth events. | |||||
* | |||||
* In order to instantiate a synth the host calls the LADSPA | |||||
* instantiate function, passing in this LADSPA_Descriptor | |||||
* pointer. The returned LADSPA_Handle is used as the argument | |||||
* for the DSSI functions below as well as for the LADSPA ones. | |||||
*/ | |||||
const LADSPA_Descriptor *LADSPA_Plugin; | |||||
/** | |||||
* configure() | |||||
* | |||||
* This member is a function pointer that sends a piece of | |||||
* configuration data to the plugin. The key argument specifies | |||||
* some aspect of the synth's configuration that is to be changed, | |||||
* and the value argument specifies a new value for it. A plugin | |||||
* that does not require this facility at all may set this member | |||||
* to NULL. | |||||
* | |||||
* This call is intended to set some session-scoped aspect of a | |||||
* plugin's behaviour, for example to tell the plugin to load | |||||
* sample data from a particular file. The plugin should act | |||||
* immediately on the request. The call should return NULL on | |||||
* success, or an error string that may be shown to the user. The | |||||
* host will free the returned value after use if it is non-NULL. | |||||
* | |||||
* Calls to configure() are not automated as timed events. | |||||
* Instead, a host should remember the last value associated with | |||||
* each key passed to configure() during a given session for a | |||||
* given plugin instance, and should call configure() with the | |||||
* correct value for each key the next time it instantiates the | |||||
* "same" plugin instance, for example on reloading a project in | |||||
* which the plugin was used before. Plugins should note that a | |||||
* host may typically instantiate a plugin multiple times with the | |||||
* same configuration values, and should share data between | |||||
* instances where practical. | |||||
* | |||||
* Calling configure() completely invalidates the program and bank | |||||
* information last obtained from the plugin. | |||||
* | |||||
* Reserved and special key prefixes | |||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||||
* The DSSI: prefix | |||||
* ---------------- | |||||
* Configure keys starting with DSSI: are reserved for particular | |||||
* purposes documented in the DSSI specification. At the moment, | |||||
* there is one such key: DSSI:PROJECT_DIRECTORY. A host may call | |||||
* configure() passing this key and a directory path value. This | |||||
* indicates to the plugin and its UI that a directory at that | |||||
* path exists and may be used for project-local data. Plugins | |||||
* may wish to use the project directory as a fallback location | |||||
* when looking for other file data, or as a base for relative | |||||
* paths in other configuration values. | |||||
* | |||||
* The GLOBAL: prefix | |||||
* ------------------ | |||||
* Configure keys starting with GLOBAL: may be used by the plugin | |||||
* and its UI for any purpose, but are treated specially by the | |||||
* host. When one of these keys is used in a configure OSC call | |||||
* from the plugin UI, the host makes the corresponding configure | |||||
* call (preserving the GLOBAL: prefix) not only to the target | |||||
* plugin but also to all other plugins in the same instance | |||||
* group, as well as their UIs. Note that if any instance | |||||
* returns non-NULL from configure to indicate error, the host | |||||
* may stop there (and the set of plugins on which configure has | |||||
* been called will thus depend on the host implementation). | |||||
* See also the configure OSC call documentation in RFC.txt. | |||||
*/ | |||||
char *(*configure)(LADSPA_Handle Instance, | |||||
const char *Key, | |||||
const char *Value); | |||||
#define DSSI_RESERVED_CONFIGURE_PREFIX "DSSI:" | |||||
#define DSSI_GLOBAL_CONFIGURE_PREFIX "GLOBAL:" | |||||
#define DSSI_PROJECT_DIRECTORY_KEY \ | |||||
DSSI_RESERVED_CONFIGURE_PREFIX "PROJECT_DIRECTORY" | |||||
/** | |||||
* get_program() | |||||
* | |||||
* This member is a function pointer that provides a description | |||||
* of a program (named preset sound) available on this synth. A | |||||
* plugin that does not support programs at all should set this | |||||
* member to NULL. | |||||
* | |||||
* The Index argument is an index into the plugin's list of | |||||
* programs, not a program number as represented by the Program | |||||
* field of the DSSI_Program_Descriptor. (This distinction is | |||||
* needed to support synths that use non-contiguous program or | |||||
* bank numbers.) | |||||
* | |||||
* This function returns a DSSI_Program_Descriptor pointer that is | |||||
* guaranteed to be valid only until the next call to get_program, | |||||
* deactivate, or configure, on the same plugin instance. This | |||||
* function must return NULL if passed an Index argument out of | |||||
* range, so that the host can use it to query the number of | |||||
* programs as well as their properties. | |||||
*/ | |||||
const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance, | |||||
unsigned long Index); | |||||
/** | |||||
* select_program() | |||||
* | |||||
* This member is a function pointer that selects a new program | |||||
* for this synth. The program change should take effect | |||||
* immediately at the start of the next run_synth() call. (This | |||||
* means that a host providing the capability of changing programs | |||||
* between any two notes on a track must vary the block size so as | |||||
* to place the program change at the right place. A host that | |||||
* wanted to avoid this would probably just instantiate a plugin | |||||
* for each program.) | |||||
* | |||||
* A plugin that does not support programs at all should set this | |||||
* member NULL. Plugins should ignore a select_program() call | |||||
* with an invalid bank or program. | |||||
* | |||||
* A plugin is not required to select any particular default | |||||
* program on activate(): it's the host's duty to set a program | |||||
* explicitly. The current program is invalidated by any call to | |||||
* configure(). | |||||
* | |||||
* A plugin is permitted to re-write the values of its input | |||||
* control ports when select_program is called. The host should | |||||
* re-read the input control port values and update its own | |||||
* records appropriately. (This is the only circumstance in | |||||
* which a DSSI plugin is allowed to modify its own input ports.) | |||||
*/ | |||||
void (*select_program)(LADSPA_Handle Instance, | |||||
unsigned long Bank, | |||||
unsigned long Program); | |||||
/** | |||||
* get_midi_controller_for_port() | |||||
* | |||||
* This member is a function pointer that returns the MIDI | |||||
* controller number or NRPN that should be mapped to the given | |||||
* input control port. If the given port should not have any MIDI | |||||
* controller mapped to it, the function should return DSSI_NONE. | |||||
* The behaviour of this function is undefined if the given port | |||||
* number does not correspond to an input control port. A plugin | |||||
* that does not want MIDI controllers mapped to ports at all may | |||||
* set this member NULL. | |||||
* | |||||
* Correct values can be got using the macros DSSI_CC(num) and | |||||
* DSSI_NRPN(num) as appropriate, and values can be combined using | |||||
* bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port | |||||
* should respond to CC #23 and NRPN #1069. | |||||
* | |||||
* The host is responsible for doing proper scaling from MIDI | |||||
* controller and NRPN value ranges to port ranges according to | |||||
* the plugin's LADSPA port hints. Hosts should not deliver | |||||
* through run_synth any MIDI controller events that have already | |||||
* been mapped to control port values. | |||||
* | |||||
* A plugin should not attempt to request mappings from | |||||
* controllers 0 or 32 (MIDI Bank Select MSB and LSB). | |||||
*/ | |||||
int (*get_midi_controller_for_port)(LADSPA_Handle Instance, | |||||
unsigned long Port); | |||||
/** | |||||
* run_synth() | |||||
* | |||||
* This member is a function pointer that runs a synth for a | |||||
* block. This is identical in function to the LADSPA run() | |||||
* function, except that it also supplies events to the synth. | |||||
* | |||||
* A plugin may provide this function, run_multiple_synths() (see | |||||
* below), both, or neither (if it is not in fact a synth). A | |||||
* plugin that does not provide this function must set this member | |||||
* to NULL. Authors of synth plugins are encouraged to provide | |||||
* this function if at all possible. | |||||
* | |||||
* The Events pointer points to a block of EventCount ALSA | |||||
* sequencer events, which is used to communicate MIDI and related | |||||
* events to the synth. Each event is timestamped relative to the | |||||
* start of the block, (mis)using the ALSA "tick time" field as a | |||||
* frame count. The host is responsible for ensuring that events | |||||
* with differing timestamps are already ordered by time. | |||||
* | |||||
* See also the notes on activation, port connection etc in | |||||
* ladpsa.h, in the context of the LADSPA run() function. | |||||
* | |||||
* Note Events | |||||
* ~~~~~~~~~~~ | |||||
* There are two minor requirements aimed at making the plugin | |||||
* writer's life as simple as possible: | |||||
* | |||||
* 1. A host must never send events of type SND_SEQ_EVENT_NOTE. | |||||
* Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON | |||||
* and NOTE_OFF events. A plugin should discard any one-point | |||||
* NOTE events it sees. | |||||
* | |||||
* 2. A host must not attempt to switch notes off by sending | |||||
* zero-velocity NOTE_ON events. It should always send true | |||||
* NOTE_OFFs. It is the host's responsibility to remap events in | |||||
* cases where an external MIDI source has sent it zero-velocity | |||||
* NOTE_ONs. | |||||
* | |||||
* Bank and Program Events | |||||
* ~~~~~~~~~~~~~~~~~~~~~~~ | |||||
* Hosts must map MIDI Bank Select MSB and LSB (0 and 32) | |||||
* controllers and MIDI Program Change events onto the banks and | |||||
* programs specified by the plugin, using the DSSI select_program | |||||
* call. No host should ever deliver a program change or bank | |||||
* select controller to a plugin via run_synth. | |||||
*/ | |||||
void (*run_synth)(LADSPA_Handle Instance, | |||||
unsigned long SampleCount, | |||||
snd_seq_event_t *Events, | |||||
unsigned long EventCount); | |||||
/** | |||||
* run_synth_adding() | |||||
* | |||||
* This member is a function pointer that runs an instance of a | |||||
* synth for a block, adding its outputs to the values already | |||||
* present at the output ports. This is provided for symmetry | |||||
* with LADSPA run_adding(), and is equally optional. A plugin | |||||
* that does not provide it must set this member to NULL. | |||||
*/ | |||||
void (*run_synth_adding)(LADSPA_Handle Instance, | |||||
unsigned long SampleCount, | |||||
snd_seq_event_t *Events, | |||||
unsigned long EventCount); | |||||
/** | |||||
* run_multiple_synths() | |||||
* | |||||
* This member is a function pointer that runs multiple synth | |||||
* instances for a block. This is very similar to run_synth(), | |||||
* except that Instances, Events, and EventCounts each point to | |||||
* arrays that hold the LADSPA handles, event buffers, and | |||||
* event counts for each of InstanceCount instances. That is, | |||||
* Instances points to an array of InstanceCount pointers to | |||||
* DSSI plugin instantiations, Events points to an array of | |||||
* pointers to each instantiation's respective event list, and | |||||
* EventCounts points to an array containing each instantiation's | |||||
* respective event count. | |||||
* | |||||
* A host using this function must guarantee that ALL active | |||||
* instances of the plugin are represented in each call to the | |||||
* function -- that is, a host may not call run_multiple_synths() | |||||
* for some instances of a given plugin and then call run_synth() | |||||
* as well for others. 'All .. instances of the plugin' means | |||||
* every instance sharing the same LADSPA label and shared object | |||||
* (*.so) file (rather than every instance sharing the same *.so). | |||||
* 'Active' means any instance for which activate() has been called | |||||
* but deactivate() has not. | |||||
* | |||||
* A plugin may provide this function, run_synths() (see above), | |||||
* both, or neither (if it not in fact a synth). A plugin that | |||||
* does not provide this function must set this member to NULL. | |||||
* Plugin authors implementing run_multiple_synths are strongly | |||||
* encouraged to implement run_synth as well if at all possible, | |||||
* to aid simplistic hosts, even where it would be less efficient | |||||
* to use it. | |||||
*/ | |||||
void (*run_multiple_synths)(unsigned long InstanceCount, | |||||
LADSPA_Handle *Instances, | |||||
unsigned long SampleCount, | |||||
snd_seq_event_t **Events, | |||||
unsigned long *EventCounts); | |||||
/** | |||||
* run_multiple_synths_adding() | |||||
* | |||||
* This member is a function pointer that runs multiple synth | |||||
* instances for a block, adding each synth's outputs to the | |||||
* values already present at the output ports. This is provided | |||||
* for symmetry with both the DSSI run_multiple_synths() and LADSPA | |||||
* run_adding() functions, and is equally optional. A plugin | |||||
* that does not provide it must set this member to NULL. | |||||
*/ | |||||
void (*run_multiple_synths_adding)(unsigned long InstanceCount, | |||||
LADSPA_Handle *Instances, | |||||
unsigned long SampleCount, | |||||
snd_seq_event_t **Events, | |||||
unsigned long *EventCounts); | |||||
/** | |||||
* set_custom_data() | |||||
*/ | |||||
int (*set_custom_data)(LADSPA_Handle Instance, void *Data, unsigned long DataLength); | |||||
/** | |||||
* get_custom_data() | |||||
*/ | |||||
int (*get_custom_data)(LADSPA_Handle Instance, void **Data, unsigned long *DataLength); | |||||
} DSSI_Descriptor; | |||||
/** | |||||
* DSSI supports a plugin discovery method similar to that of LADSPA: | |||||
* | |||||
* - DSSI hosts may wish to locate DSSI plugin shared object files by | |||||
* searching the paths contained in the DSSI_PATH and LADSPA_PATH | |||||
* environment variables, if they are present. Both are expected | |||||
* to be colon-separated lists of directories to be searched (in | |||||
* order), and DSSI_PATH should be searched first if both variables | |||||
* are set. | |||||
* | |||||
* - Each shared object file containing DSSI plugins must include a | |||||
* function dssi_descriptor(), with the following function prototype | |||||
* and C-style linkage. Hosts may enumerate the plugin types | |||||
* available in the shared object file by repeatedly calling | |||||
* this function with successive Index values (beginning from 0), | |||||
* until a return value of NULL indicates no more plugin types are | |||||
* available. Each non-NULL return is the DSSI_Descriptor | |||||
* of a distinct plugin type. | |||||
*/ | |||||
const DSSI_Descriptor *dssi_descriptor(unsigned long Index); | |||||
typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index); | |||||
/* | |||||
* Macros to specify particular MIDI controllers in return values from | |||||
* get_midi_controller_for_port() | |||||
*/ | |||||
#define DSSI_CC_BITS 0x20000000 | |||||
#define DSSI_NRPN_BITS 0x40000000 | |||||
#define DSSI_NONE -1 | |||||
#define DSSI_CONTROLLER_IS_SET(n) (DSSI_NONE != (n)) | |||||
#define DSSI_CC(n) (DSSI_CC_BITS | (n)) | |||||
#define DSSI_IS_CC(n) (DSSI_CC_BITS & (n)) | |||||
#define DSSI_CC_NUMBER(n) ((n) & 0x7f) | |||||
#define DSSI_NRPN(n) (DSSI_NRPN_BITS | ((n) << 7)) | |||||
#define DSSI_IS_NRPN(n) (DSSI_NRPN_BITS & (n)) | |||||
#define DSSI_NRPN_NUMBER(n) (((n) >> 7) & 0x3fff) | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* DSSI_INCLUDED */ |
@@ -0,0 +1,272 @@ | |||||
/* | |||||
* This library 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; either version 2.1 of | |||||
* the License, or (at your option) any later version. | |||||
* | |||||
* 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. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with this library; if not, write to the Free Software | |||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
* | |||||
*/ | |||||
#ifndef __ALSA_SEQ_EVENT_COMPAT_H | |||||
#define __ALSA_SEQ_EVENT_COMPAT_H | |||||
/** | |||||
* Sequencer event data type | |||||
*/ | |||||
typedef unsigned char snd_seq_event_type_t; | |||||
/** Sequencer event type */ | |||||
enum snd_seq_event_type { | |||||
/** system status; event data type = #snd_seq_result_t */ | |||||
SND_SEQ_EVENT_SYSTEM = 0, | |||||
/** returned result status; event data type = #snd_seq_result_t */ | |||||
SND_SEQ_EVENT_RESULT, | |||||
/** note on and off with duration; event data type = #snd_seq_ev_note_t */ | |||||
SND_SEQ_EVENT_NOTE = 5, | |||||
/** note on; event data type = #snd_seq_ev_note_t */ | |||||
SND_SEQ_EVENT_NOTEON, | |||||
/** note off; event data type = #snd_seq_ev_note_t */ | |||||
SND_SEQ_EVENT_NOTEOFF, | |||||
/** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */ | |||||
SND_SEQ_EVENT_KEYPRESS, | |||||
/** controller; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_CONTROLLER = 10, | |||||
/** program change; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_PGMCHANGE, | |||||
/** channel pressure; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_CHANPRESS, | |||||
/** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */ | |||||
SND_SEQ_EVENT_PITCHBEND, | |||||
/** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_CONTROL14, | |||||
/** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_NONREGPARAM, | |||||
/** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_REGPARAM, | |||||
/** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_SONGPOS = 20, | |||||
/** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_SONGSEL, | |||||
/** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_QFRAME, | |||||
/** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_TIMESIGN, | |||||
/** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */ | |||||
SND_SEQ_EVENT_KEYSIGN, | |||||
/** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_START = 30, | |||||
/** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_CONTINUE, | |||||
/** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_STOP, | |||||
/** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_SETPOS_TICK, | |||||
/** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_SETPOS_TIME, | |||||
/** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_TEMPO, | |||||
/** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_CLOCK, | |||||
/** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_TICK, | |||||
/** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_QUEUE_SKEW, | |||||
/** Sync position changed; event data type = #snd_seq_ev_queue_control_t */ | |||||
SND_SEQ_EVENT_SYNC_POS, | |||||
/** Tune request; event data type = none */ | |||||
SND_SEQ_EVENT_TUNE_REQUEST = 40, | |||||
/** Reset to power-on state; event data type = none */ | |||||
SND_SEQ_EVENT_RESET, | |||||
/** Active sensing event; event data type = none */ | |||||
SND_SEQ_EVENT_SENSING, | |||||
/** Echo-back event; event data type = any type */ | |||||
SND_SEQ_EVENT_ECHO = 50, | |||||
/** OSS emulation raw event; event data type = any type */ | |||||
SND_SEQ_EVENT_OSS, | |||||
/** New client has connected; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_CLIENT_START = 60, | |||||
/** Client has left the system; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_CLIENT_EXIT, | |||||
/** Client status/info has changed; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_CLIENT_CHANGE, | |||||
/** New port was created; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_PORT_START, | |||||
/** Port was deleted from system; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_PORT_EXIT, | |||||
/** Port status/info has changed; event data type = #snd_seq_addr_t */ | |||||
SND_SEQ_EVENT_PORT_CHANGE, | |||||
/** Ports connected; event data type = #snd_seq_connect_t */ | |||||
SND_SEQ_EVENT_PORT_SUBSCRIBED, | |||||
/** Ports disconnected; event data type = #snd_seq_connect_t */ | |||||
SND_SEQ_EVENT_PORT_UNSUBSCRIBED, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR0 = 90, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR1, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR2, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR3, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR4, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR5, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR6, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR7, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR8, | |||||
/** user-defined event; event data type = any (fixed size) */ | |||||
SND_SEQ_EVENT_USR9, | |||||
/** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_SYSEX = 130, | |||||
/** error event; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_BOUNCE, | |||||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_USR_VAR0 = 135, | |||||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_USR_VAR1, | |||||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_USR_VAR2, | |||||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_USR_VAR3, | |||||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||||
SND_SEQ_EVENT_USR_VAR4, | |||||
/** NOP; ignored in any case */ | |||||
SND_SEQ_EVENT_NONE = 255 | |||||
}; | |||||
/** Sequencer event address */ | |||||
typedef struct snd_seq_addr { | |||||
unsigned char client; /**< Client id */ | |||||
unsigned char port; /**< Port id */ | |||||
} snd_seq_addr_t; | |||||
/** Connection (subscription) between ports */ | |||||
typedef struct snd_seq_connect { | |||||
snd_seq_addr_t sender; /**< sender address */ | |||||
snd_seq_addr_t dest; /**< destination address */ | |||||
} snd_seq_connect_t; | |||||
/** Real-time data record */ | |||||
typedef struct snd_seq_real_time { | |||||
unsigned int tv_sec; /**< seconds */ | |||||
unsigned int tv_nsec; /**< nanoseconds */ | |||||
} snd_seq_real_time_t; | |||||
/** (MIDI) Tick-time data record */ | |||||
typedef unsigned int snd_seq_tick_time_t; | |||||
/** unioned time stamp */ | |||||
typedef union snd_seq_timestamp { | |||||
snd_seq_tick_time_t tick; /**< tick-time */ | |||||
struct snd_seq_real_time time; /**< real-time */ | |||||
} snd_seq_timestamp_t; | |||||
/** Note event */ | |||||
typedef struct snd_seq_ev_note { | |||||
unsigned char channel; /**< channel number */ | |||||
unsigned char note; /**< note */ | |||||
unsigned char velocity; /**< velocity */ | |||||
unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */ | |||||
unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */ | |||||
} snd_seq_ev_note_t; | |||||
/** Controller event */ | |||||
typedef struct snd_seq_ev_ctrl { | |||||
unsigned char channel; /**< channel number */ | |||||
unsigned char unused[3]; /**< reserved */ | |||||
unsigned int param; /**< control parameter */ | |||||
signed int value; /**< control value */ | |||||
} snd_seq_ev_ctrl_t; | |||||
/** generic set of bytes (12x8 bit) */ | |||||
typedef struct snd_seq_ev_raw8 { | |||||
unsigned char d[12]; /**< 8 bit value */ | |||||
} snd_seq_ev_raw8_t; | |||||
/** generic set of integers (3x32 bit) */ | |||||
typedef struct snd_seq_ev_raw32 { | |||||
unsigned int d[3]; /**< 32 bit value */ | |||||
} snd_seq_ev_raw32_t; | |||||
/** external stored data */ | |||||
typedef struct snd_seq_ev_ext { | |||||
unsigned int len; /**< length of data */ | |||||
void *ptr; /**< pointer to data (note: can be 64-bit) */ | |||||
} __attribute__((packed)) snd_seq_ev_ext_t; | |||||
/** Result events */ | |||||
typedef struct snd_seq_result { | |||||
int event; /**< processed event type */ | |||||
int result; /**< status */ | |||||
} snd_seq_result_t; | |||||
/** Queue skew values */ | |||||
typedef struct snd_seq_queue_skew { | |||||
unsigned int value; /**< skew value */ | |||||
unsigned int base; /**< skew base */ | |||||
} snd_seq_queue_skew_t; | |||||
/** queue timer control */ | |||||
typedef struct snd_seq_ev_queue_control { | |||||
unsigned char queue; /**< affected queue */ | |||||
unsigned char unused[3]; /**< reserved */ | |||||
union { | |||||
signed int value; /**< affected value (e.g. tempo) */ | |||||
snd_seq_timestamp_t time; /**< time */ | |||||
unsigned int position; /**< sync position */ | |||||
snd_seq_queue_skew_t skew; /**< queue skew */ | |||||
unsigned int d32[2]; /**< any data */ | |||||
unsigned char d8[8]; /**< any data */ | |||||
} param; /**< data value union */ | |||||
} snd_seq_ev_queue_control_t; | |||||
/** Sequencer event */ | |||||
typedef struct snd_seq_event { | |||||
snd_seq_event_type_t type; /**< event type */ | |||||
unsigned char flags; /**< event flags */ | |||||
unsigned char tag; /**< tag */ | |||||
unsigned char queue; /**< schedule queue */ | |||||
snd_seq_timestamp_t time; /**< schedule time */ | |||||
snd_seq_addr_t source; /**< source address */ | |||||
snd_seq_addr_t dest; /**< destination address */ | |||||
union { | |||||
snd_seq_ev_note_t note; /**< note information */ | |||||
snd_seq_ev_ctrl_t control; /**< MIDI control information */ | |||||
snd_seq_ev_raw8_t raw8; /**< raw8 data */ | |||||
snd_seq_ev_raw32_t raw32; /**< raw32 data */ | |||||
snd_seq_ev_ext_t ext; /**< external data */ | |||||
snd_seq_ev_queue_control_t queue; /**< queue control */ | |||||
snd_seq_timestamp_t time; /**< timestamp */ | |||||
snd_seq_addr_t addr; /**< address */ | |||||
snd_seq_connect_t connect; /**< connect information */ | |||||
snd_seq_result_t result; /**< operation result code */ | |||||
} data; /**< event data... */ | |||||
} snd_seq_event_t; | |||||
#endif /* __ALSA_SEQ_EVENT_COMPAT_H */ | |||||
@@ -0,0 +1,603 @@ | |||||
/* ladspa.h | |||||
Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. | |||||
Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, | |||||
Stefan Westerfeld. | |||||
This library 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; either version 2.1 of | |||||
the License, or (at your option) any later version. | |||||
This library 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. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |||||
USA. */ | |||||
#ifndef LADSPA_INCLUDED | |||||
#define LADSPA_INCLUDED | |||||
#define LADSPA_VERSION "1.1" | |||||
#define LADSPA_VERSION_MAJOR 1 | |||||
#define LADSPA_VERSION_MINOR 1 | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/*****************************************************************************/ | |||||
/* Overview: | |||||
There is a large number of synthesis packages in use or development | |||||
on the Linux platform at this time. This API (`The Linux Audio | |||||
Developer's Simple Plugin API') attempts to give programmers the | |||||
ability to write simple `plugin' audio processors in C/C++ and link | |||||
them dynamically (`plug') into a range of these packages (`hosts'). | |||||
It should be possible for any host and any plugin to communicate | |||||
completely through this interface. | |||||
This API is deliberately short and simple. To achieve compatibility | |||||
with a range of promising Linux sound synthesis packages it | |||||
attempts to find the `greatest common divisor' in their logical | |||||
behaviour. Having said this, certain limiting decisions are | |||||
implicit, notably the use of a fixed type (LADSPA_Data) for all | |||||
data transfer and absence of a parameterised `initialisation' | |||||
phase. See below for the LADSPA_Data typedef. | |||||
Plugins are expected to distinguish between control and audio | |||||
data. Plugins have `ports' that are inputs or outputs for audio or | |||||
control data and each plugin is `run' for a `block' corresponding | |||||
to a short time interval measured in samples. Audio data is | |||||
communicated using arrays of LADSPA_Data, allowing a block of audio | |||||
to be processed by the plugin in a single pass. Control data is | |||||
communicated using single LADSPA_Data values. Control data has a | |||||
single value at the start of a call to the `run()' or `run_adding()' | |||||
function, and may be considered to remain this value for its | |||||
duration. The plugin may assume that all its input and output ports | |||||
have been connected to the relevant data location (see the | |||||
`connect_port()' function below) before it is asked to run. | |||||
Plugins will reside in shared object files suitable for dynamic | |||||
linking by dlopen() and family. The file will provide a number of | |||||
`plugin types' that can be used to instantiate actual plugins | |||||
(sometimes known as `plugin instances') that can be connected | |||||
together to perform tasks. | |||||
This API contains very limited error-handling. */ | |||||
/*****************************************************************************/ | |||||
/* Fundamental data type passed in and out of plugin. This data type | |||||
is used to communicate audio samples and control values. It is | |||||
assumed that the plugin will work sensibly given any numeric input | |||||
value although it may have a preferred range (see hints below). | |||||
For audio it is generally assumed that 1.0f is the `0dB' reference | |||||
amplitude and is a `normal' signal level. */ | |||||
typedef float LADSPA_Data; | |||||
/*****************************************************************************/ | |||||
/* Special Plugin Properties: | |||||
Optional features of the plugin type are encapsulated in the | |||||
LADSPA_Properties type. This is assembled by ORing individual | |||||
properties together. */ | |||||
typedef int LADSPA_Properties; | |||||
/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a | |||||
real-time dependency (e.g. listens to a MIDI device) and so its | |||||
output must not be cached or subject to significant latency. */ | |||||
#define LADSPA_PROPERTY_REALTIME 0x1 | |||||
/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin | |||||
may cease to work correctly if the host elects to use the same data | |||||
location for both input and output (see connect_port()). This | |||||
should be avoided as enabling this flag makes it impossible for | |||||
hosts to use the plugin to process audio `in-place.' */ | |||||
#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 | |||||
/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin | |||||
is capable of running not only in a conventional host but also in a | |||||
`hard real-time' environment. To qualify for this the plugin must | |||||
satisfy all of the following: | |||||
(1) The plugin must not use malloc(), free() or other heap memory | |||||
management within its run() or run_adding() functions. All new | |||||
memory used in run() must be managed via the stack. These | |||||
restrictions only apply to the run() function. | |||||
(2) The plugin will not attempt to make use of any library | |||||
functions with the exceptions of functions in the ANSI standard C | |||||
and C maths libraries, which the host is expected to provide. | |||||
(3) The plugin will not access files, devices, pipes, sockets, IPC | |||||
or any other mechanism that might result in process or thread | |||||
blocking. | |||||
(4) The plugin will take an amount of time to execute a run() or | |||||
run_adding() call approximately of form (A+B*SampleCount) where A | |||||
and B depend on the machine and host in use. This amount of time | |||||
may not depend on input signals or plugin state. The host is left | |||||
the responsibility to perform timings to estimate upper bounds for | |||||
A and B. */ | |||||
#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 | |||||
#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) | |||||
#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) | |||||
#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) | |||||
/*****************************************************************************/ | |||||
/* Plugin Ports: | |||||
Plugins have `ports' that are inputs or outputs for audio or | |||||
data. Ports can communicate arrays of LADSPA_Data (for audio | |||||
inputs/outputs) or single LADSPA_Data values (for control | |||||
input/outputs). This information is encapsulated in the | |||||
LADSPA_PortDescriptor type which is assembled by ORing individual | |||||
properties together. | |||||
Note that a port must be an input or an output port but not both | |||||
and that a port must be a control or audio port but not both. */ | |||||
typedef int LADSPA_PortDescriptor; | |||||
/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ | |||||
#define LADSPA_PORT_INPUT 0x1 | |||||
/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ | |||||
#define LADSPA_PORT_OUTPUT 0x2 | |||||
/* Property LADSPA_PORT_CONTROL indicates that the port is a control | |||||
port. */ | |||||
#define LADSPA_PORT_CONTROL 0x4 | |||||
/* Property LADSPA_PORT_AUDIO indicates that the port is a audio | |||||
port. */ | |||||
#define LADSPA_PORT_AUDIO 0x8 | |||||
#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) | |||||
#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) | |||||
#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) | |||||
#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) | |||||
/*****************************************************************************/ | |||||
/* Plugin Port Range Hints: | |||||
The host may wish to provide a representation of data entering or | |||||
leaving a plugin (e.g. to generate a GUI automatically). To make | |||||
this more meaningful, the plugin should provide `hints' to the host | |||||
describing the usual values taken by the data. | |||||
Note that these are only hints. The host may ignore them and the | |||||
plugin must not assume that data supplied to it is meaningful. If | |||||
the plugin receives invalid input data it is expected to continue | |||||
to run without failure and, where possible, produce a sensible | |||||
output (e.g. a high-pass filter given a negative cutoff frequency | |||||
might switch to an all-pass mode). | |||||
Hints are meaningful for all input and output ports but hints for | |||||
input control ports are expected to be particularly useful. | |||||
More hint information is encapsulated in the | |||||
LADSPA_PortRangeHintDescriptor type which is assembled by ORing | |||||
individual hint types together. Hints may require further | |||||
LowerBound and UpperBound information. | |||||
All the hint information for a particular port is aggregated in the | |||||
LADSPA_PortRangeHint structure. */ | |||||
typedef int LADSPA_PortRangeHintDescriptor; | |||||
/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field | |||||
of the LADSPA_PortRangeHint should be considered meaningful. The | |||||
value in this field should be considered the (inclusive) lower | |||||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also | |||||
specified then the value of LowerBound should be multiplied by the | |||||
sample rate. */ | |||||
#define LADSPA_HINT_BOUNDED_BELOW 0x1 | |||||
/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field | |||||
of the LADSPA_PortRangeHint should be considered meaningful. The | |||||
value in this field should be considered the (inclusive) upper | |||||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also | |||||
specified then the value of UpperBound should be multiplied by the | |||||
sample rate. */ | |||||
#define LADSPA_HINT_BOUNDED_ABOVE 0x2 | |||||
/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be | |||||
considered a Boolean toggle. Data less than or equal to zero should | |||||
be considered `off' or `false,' and data above zero should be | |||||
considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in | |||||
conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or | |||||
LADSPA_HINT_DEFAULT_1. */ | |||||
#define LADSPA_HINT_TOGGLED 0x4 | |||||
/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified | |||||
should be interpreted as multiples of the sample rate. For | |||||
instance, a frequency range from 0Hz to the Nyquist frequency (half | |||||
the sample rate) could be requested by this hint in conjunction | |||||
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds | |||||
at all must support this hint to retain meaning. */ | |||||
#define LADSPA_HINT_SAMPLE_RATE 0x8 | |||||
/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the | |||||
user will find it more intuitive to view values using a logarithmic | |||||
scale. This is particularly useful for frequencies and gains. */ | |||||
#define LADSPA_HINT_LOGARITHMIC 0x10 | |||||
/* Hint LADSPA_HINT_INTEGER indicates that a user interface would | |||||
probably wish to provide a stepped control taking only integer | |||||
values. Any bounds set should be slightly wider than the actual | |||||
integer range required to avoid floating point rounding errors. For | |||||
instance, the integer set {0,1,2,3} might be described as [-0.1, | |||||
3.1]. */ | |||||
#define LADSPA_HINT_INTEGER 0x20 | |||||
/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' | |||||
value for the port that is sensible as a default. For instance, | |||||
this value is suitable for use as an initial value in a user | |||||
interface or as a value the host might assign to a control port | |||||
when the user has not provided one. Defaults are encoded using a | |||||
mask so only one default may be specified for a port. Some of the | |||||
hints make use of lower and upper bounds, in which case the | |||||
relevant bound or bounds must be available and | |||||
LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting | |||||
default must be rounded if LADSPA_HINT_INTEGER is present. Default | |||||
values were introduced in LADSPA v1.1. */ | |||||
#define LADSPA_HINT_DEFAULT_MASK 0x3C0 | |||||
/* This default values indicates that no default is provided. */ | |||||
#define LADSPA_HINT_DEFAULT_NONE 0x0 | |||||
/* This default hint indicates that the suggested lower bound for the | |||||
port should be used. */ | |||||
#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 | |||||
/* This default hint indicates that a low value between the suggested | |||||
lower and upper bounds should be chosen. For ports with | |||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + | |||||
log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper | |||||
* 0.25). */ | |||||
#define LADSPA_HINT_DEFAULT_LOW 0x80 | |||||
/* This default hint indicates that a middle value between the | |||||
suggested lower and upper bounds should be chosen. For ports with | |||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + | |||||
log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * | |||||
0.5). */ | |||||
#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 | |||||
/* This default hint indicates that a high value between the suggested | |||||
lower and upper bounds should be chosen. For ports with | |||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + | |||||
log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper | |||||
* 0.75). */ | |||||
#define LADSPA_HINT_DEFAULT_HIGH 0x100 | |||||
/* This default hint indicates that the suggested upper bound for the | |||||
port should be used. */ | |||||
#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 | |||||
/* This default hint indicates that the number 0 should be used. Note | |||||
that this default may be used in conjunction with | |||||
LADSPA_HINT_TOGGLED. */ | |||||
#define LADSPA_HINT_DEFAULT_0 0x200 | |||||
/* This default hint indicates that the number 1 should be used. Note | |||||
that this default may be used in conjunction with | |||||
LADSPA_HINT_TOGGLED. */ | |||||
#define LADSPA_HINT_DEFAULT_1 0x240 | |||||
/* This default hint indicates that the number 100 should be used. */ | |||||
#define LADSPA_HINT_DEFAULT_100 0x280 | |||||
/* This default hint indicates that the Hz frequency of `concert A' | |||||
should be used. This will be 440 unless the host uses an unusual | |||||
tuning convention, in which case it may be within a few Hz. */ | |||||
#define LADSPA_HINT_DEFAULT_440 0x2C0 | |||||
#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) | |||||
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) | |||||
#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) | |||||
#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) | |||||
#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) | |||||
#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) | |||||
#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) | |||||
#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_MINIMUM) | |||||
#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_LOW) | |||||
#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_MIDDLE) | |||||
#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_HIGH) | |||||
#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_MAXIMUM) | |||||
#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_0) | |||||
#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_1) | |||||
#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_100) | |||||
#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||||
== LADSPA_HINT_DEFAULT_440) | |||||
typedef struct _LADSPA_PortRangeHint { | |||||
/* Hints about the port. */ | |||||
LADSPA_PortRangeHintDescriptor HintDescriptor; | |||||
/* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When | |||||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be | |||||
multiplied by the relevant sample rate. */ | |||||
LADSPA_Data LowerBound; | |||||
/* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When | |||||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be | |||||
multiplied by the relevant sample rate. */ | |||||
LADSPA_Data UpperBound; | |||||
} LADSPA_PortRangeHint; | |||||
/*****************************************************************************/ | |||||
/* Plugin Handles: | |||||
This plugin handle indicates a particular instance of the plugin | |||||
concerned. It is valid to compare this to NULL (0 for C++) but | |||||
otherwise the host should not attempt to interpret it. The plugin | |||||
may use it to reference internal instance data. */ | |||||
typedef void * LADSPA_Handle; | |||||
/*****************************************************************************/ | |||||
/* Descriptor for a Type of Plugin: | |||||
This structure is used to describe a plugin type. It provides a | |||||
number of functions to examine the type, instantiate it, link it to | |||||
buffers and workspaces and to run it. */ | |||||
typedef struct _LADSPA_Descriptor { | |||||
/* This numeric identifier indicates the plugin type | |||||
uniquely. Plugin programmers may reserve ranges of IDs from a | |||||
central body to avoid clashes. Hosts may assume that IDs are | |||||
below 0x1000000. */ | |||||
unsigned long UniqueID; | |||||
/* This identifier can be used as a unique, case-sensitive | |||||
identifier for the plugin type within the plugin file. Plugin | |||||
types should be identified by file and label rather than by index | |||||
or plugin name, which may be changed in new plugin | |||||
versions. Labels must not contain white-space characters. */ | |||||
const char * Label; | |||||
/* This indicates a number of properties of the plugin. */ | |||||
LADSPA_Properties Properties; | |||||
/* This member points to the null-terminated name of the plugin | |||||
(e.g. "Sine Oscillator"). */ | |||||
const char * Name; | |||||
/* This member points to the null-terminated string indicating the | |||||
maker of the plugin. This can be an empty string but not NULL. */ | |||||
const char * Maker; | |||||
/* This member points to the null-terminated string indicating any | |||||
copyright applying to the plugin. If no Copyright applies the | |||||
string "None" should be used. */ | |||||
const char * Copyright; | |||||
/* This indicates the number of ports (input AND output) present on | |||||
the plugin. */ | |||||
unsigned long PortCount; | |||||
/* This member indicates an array of port descriptors. Valid indices | |||||
vary from 0 to PortCount-1. */ | |||||
const LADSPA_PortDescriptor * PortDescriptors; | |||||
/* This member indicates an array of null-terminated strings | |||||
describing ports (e.g. "Frequency (Hz)"). Valid indices vary from | |||||
0 to PortCount-1. */ | |||||
const char * const * PortNames; | |||||
/* This member indicates an array of range hints for each port (see | |||||
above). Valid indices vary from 0 to PortCount-1. */ | |||||
const LADSPA_PortRangeHint * PortRangeHints; | |||||
/* This may be used by the plugin developer to pass any custom | |||||
implementation data into an instantiate call. It must not be used | |||||
or interpreted by the host. It is expected that most plugin | |||||
writers will not use this facility as LADSPA_Handle should be | |||||
used to hold instance data. */ | |||||
void * ImplementationData; | |||||
/* This member is a function pointer that instantiates a plugin. A | |||||
handle is returned indicating the new plugin instance. The | |||||
instantiation function accepts a sample rate as a parameter. The | |||||
plugin descriptor from which this instantiate function was found | |||||
must also be passed. This function must return NULL if | |||||
instantiation fails. | |||||
Note that instance initialisation should generally occur in | |||||
activate() rather than here. */ | |||||
LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, | |||||
unsigned long SampleRate); | |||||
/* This member is a function pointer that connects a port on an | |||||
instantiated plugin to a memory location at which a block of data | |||||
for the port will be read/written. The data location is expected | |||||
to be an array of LADSPA_Data for audio ports or a single | |||||
LADSPA_Data value for control ports. Memory issues will be | |||||
managed by the host. The plugin must read/write the data at these | |||||
locations every time run() or run_adding() is called and the data | |||||
present at the time of this connection call should not be | |||||
considered meaningful. | |||||
connect_port() may be called more than once for a plugin instance | |||||
to allow the host to change the buffers that the plugin is | |||||
reading or writing. These calls may be made before or after | |||||
activate() or deactivate() calls. | |||||
connect_port() must be called at least once for each port before | |||||
run() or run_adding() is called. When working with blocks of | |||||
LADSPA_Data the plugin should pay careful attention to the block | |||||
size passed to the run function as the block allocated may only | |||||
just be large enough to contain the block of samples. | |||||
Plugin writers should be aware that the host may elect to use the | |||||
same buffer for more than one port and even use the same buffer | |||||
for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). | |||||
However, overlapped buffers or use of a single buffer for both | |||||
audio and control data may result in unexpected behaviour. */ | |||||
void (*connect_port)(LADSPA_Handle Instance, | |||||
unsigned long Port, | |||||
LADSPA_Data * DataLocation); | |||||
/* This member is a function pointer that initialises a plugin | |||||
instance and activates it for use. This is separated from | |||||
instantiate() to aid real-time support and so that hosts can | |||||
reinitialise a plugin instance by calling deactivate() and then | |||||
activate(). In this case the plugin instance must reset all state | |||||
information dependent on the history of the plugin instance | |||||
except for any data locations provided by connect_port() and any | |||||
gain set by set_run_adding_gain(). If there is nothing for | |||||
activate() to do then the plugin writer may provide a NULL rather | |||||
than an empty function. | |||||
When present, hosts must call this function once before run() (or | |||||
run_adding()) is called for the first time. This call should be | |||||
made as close to the run() call as possible and indicates to | |||||
real-time plugins that they are now live. Plugins should not rely | |||||
on a prompt call to run() after activate(). activate() may not be | |||||
called again unless deactivate() is called first. Note that | |||||
connect_port() may be called before or after a call to | |||||
activate(). */ | |||||
void (*activate)(LADSPA_Handle Instance); | |||||
/* This method is a function pointer that runs an instance of a | |||||
plugin for a block. Two parameters are required: the first is a | |||||
handle to the particular instance to be run and the second | |||||
indicates the block size (in samples) for which the plugin | |||||
instance may run. | |||||
Note that if an activate() function exists then it must be called | |||||
before run() or run_adding(). If deactivate() is called for a | |||||
plugin instance then the plugin instance may not be reused until | |||||
activate() has been called again. | |||||
If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE | |||||
then there are various things that the plugin should not do | |||||
within the run() or run_adding() functions (see above). */ | |||||
void (*run)(LADSPA_Handle Instance, | |||||
unsigned long SampleCount); | |||||
/* This method is a function pointer that runs an instance of a | |||||
plugin for a block. This has identical behaviour to run() except | |||||
in the way data is output from the plugin. When run() is used, | |||||
values are written directly to the memory areas associated with | |||||
the output ports. However when run_adding() is called, values | |||||
must be added to the values already present in the memory | |||||
areas. Furthermore, output values written must be scaled by the | |||||
current gain set by set_run_adding_gain() (see below) before | |||||
addition. | |||||
run_adding() is optional. When it is not provided by a plugin, | |||||
this function pointer must be set to NULL. When it is provided, | |||||
the function set_run_adding_gain() must be provided also. */ | |||||
void (*run_adding)(LADSPA_Handle Instance, | |||||
unsigned long SampleCount); | |||||
/* This method is a function pointer that sets the output gain for | |||||
use when run_adding() is called (see above). If this function is | |||||
never called the gain is assumed to default to 1. Gain | |||||
information should be retained when activate() or deactivate() | |||||
are called. | |||||
This function should be provided by the plugin if and only if the | |||||
run_adding() function is provided. When it is absent this | |||||
function pointer must be set to NULL. */ | |||||
void (*set_run_adding_gain)(LADSPA_Handle Instance, | |||||
LADSPA_Data Gain); | |||||
/* This is the counterpart to activate() (see above). If there is | |||||
nothing for deactivate() to do then the plugin writer may provide | |||||
a NULL rather than an empty function. | |||||
Hosts must deactivate all activated units after they have been | |||||
run() (or run_adding()) for the last time. This call should be | |||||
made as close to the last run() call as possible and indicates to | |||||
real-time plugins that they are no longer live. Plugins should | |||||
not rely on prompt deactivation. Note that connect_port() may be | |||||
called before or after a call to deactivate(). | |||||
Deactivation is not similar to pausing as the plugin instance | |||||
will be reinitialised when activate() is called to reuse it. */ | |||||
void (*deactivate)(LADSPA_Handle Instance); | |||||
/* Once an instance of a plugin has been finished with it can be | |||||
deleted using the following function. The instance handle passed | |||||
ceases to be valid after this call. | |||||
If activate() was called for a plugin instance then a | |||||
corresponding call to deactivate() must be made before cleanup() | |||||
is called. */ | |||||
void (*cleanup)(LADSPA_Handle Instance); | |||||
} LADSPA_Descriptor; | |||||
/**********************************************************************/ | |||||
/* Accessing a Plugin: */ | |||||
/* The exact mechanism by which plugins are loaded is host-dependent, | |||||
however all most hosts will need to know is the name of shared | |||||
object file containing the plugin types. To allow multiple hosts to | |||||
share plugin types, hosts may wish to check for environment | |||||
variable LADSPA_PATH. If present, this should contain a | |||||
colon-separated path indicating directories that should be searched | |||||
(in order) when loading plugin types. | |||||
A plugin programmer must include a function called | |||||
"ladspa_descriptor" with the following function prototype within | |||||
the shared object file. This function will have C-style linkage (if | |||||
you are using C++ this is taken care of by the `extern "C"' clause | |||||
at the top of the file). | |||||
A host will find the plugin shared object file by one means or | |||||
another, find the ladspa_descriptor() function, call it, and | |||||
proceed from there. | |||||
Plugin types are accessed by index (not ID) using values from 0 | |||||
upwards. Out of range indexes must result in this function | |||||
returning NULL, so the plugin count can be determined by checking | |||||
for the least index that results in NULL being returned. */ | |||||
const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); | |||||
/* Datatype corresponding to the ladspa_descriptor() function. */ | |||||
typedef const LADSPA_Descriptor * | |||||
(*LADSPA_Descriptor_Function)(unsigned long Index); | |||||
/**********************************************************************/ | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* LADSPA_INCLUDED */ | |||||
/* EOF */ |
@@ -0,0 +1,279 @@ | |||||
/* | |||||
* aeffectx.h - simple header to allow VeSTige compilation and eventually work | |||||
* | |||||
* Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | |||||
* | |||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2 of the License, or (at your option) any later version. | |||||
* | |||||
* 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 | |||||
* General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program (see COPYING); if not, write to the | |||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |||||
* Boston, MA 02110-1301 USA. | |||||
* | |||||
*/ | |||||
#include <stdint.h> | |||||
#ifndef _AEFFECTX_H | |||||
#define _AEFFECTX_H | |||||
#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ | |||||
( ( (int) b ) << 16 ) | \ | |||||
( ( (int) c ) << 8 ) | \ | |||||
( ( (int) d ) << 0 ) ) | |||||
#define audioMasterAutomate 0 | |||||
#define audioMasterVersion 1 | |||||
#define audioMasterCurrentId 2 | |||||
#define audioMasterIdle 3 | |||||
#define audioMasterPinConnected 4 | |||||
// unsupported? 5 | |||||
#define audioMasterWantMidi 6 | |||||
#define audioMasterGetTime 7 | |||||
#define audioMasterProcessEvents 8 | |||||
#define audioMasterSetTime 9 | |||||
#define audioMasterTempoAt 10 | |||||
#define audioMasterGetNumAutomatableParameters 11 | |||||
#define audioMasterGetParameterQuantization 12 | |||||
#define audioMasterIOChanged 13 | |||||
#define audioMasterNeedIdle 14 | |||||
#define audioMasterSizeWindow 15 | |||||
#define audioMasterGetSampleRate 16 | |||||
#define audioMasterGetBlockSize 17 | |||||
#define audioMasterGetInputLatency 18 | |||||
#define audioMasterGetOutputLatency 19 | |||||
#define audioMasterGetPreviousPlug 20 | |||||
#define audioMasterGetNextPlug 21 | |||||
#define audioMasterWillReplaceOrAccumulate 22 | |||||
#define audioMasterGetCurrentProcessLevel 23 | |||||
#define audioMasterGetAutomationState 24 | |||||
#define audioMasterOfflineStart 25 | |||||
#define audioMasterOfflineRead 26 | |||||
#define audioMasterOfflineWrite 27 | |||||
#define audioMasterOfflineGetCurrentPass 28 | |||||
#define audioMasterOfflineGetCurrentMetaPass 29 | |||||
#define audioMasterSetOutputSampleRate 30 | |||||
// unsupported? 31 | |||||
#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4? | |||||
#define audioMasterGetVendorString 32 | |||||
#define audioMasterGetProductString 33 | |||||
#define audioMasterGetVendorVersion 34 | |||||
#define audioMasterVendorSpecific 35 | |||||
#define audioMasterSetIcon 36 | |||||
#define audioMasterCanDo 37 | |||||
#define audioMasterGetLanguage 38 | |||||
#define audioMasterOpenWindow 39 | |||||
#define audioMasterCloseWindow 40 | |||||
#define audioMasterGetDirectory 41 | |||||
#define audioMasterUpdateDisplay 42 | |||||
#define audioMasterBeginEdit 43 | |||||
#define audioMasterEndEdit 44 | |||||
#define audioMasterOpenFileSelector 45 | |||||
#define audioMasterCloseFileSelector 46 // currently unused | |||||
#define audioMasterEditFile 47 // currently unused | |||||
#define audioMasterGetChunkFile 48 // currently unused | |||||
#define audioMasterGetInputSpeakerArrangement 49 // currently unused | |||||
#define effFlagsHasEditor 1 | |||||
#define effFlagsCanReplacing (1 << 4) // very likely | |||||
#define effFlagsIsSynth (1 << 8) // currently unused | |||||
#define effOpen 0 | |||||
#define effClose 1 // currently unused | |||||
#define effSetProgram 2 // currently unused | |||||
#define effGetProgram 3 // currently unused | |||||
#define effGetProgramName 5 // currently unused | |||||
#define effGetParamName 8 // currently unused | |||||
#define effSetSampleRate 10 | |||||
#define effSetBlockSize 11 | |||||
#define effMainsChanged 12 | |||||
#define effEditGetRect 13 | |||||
#define effEditOpen 14 | |||||
#define effEditClose 15 | |||||
#define effEditIdle 19 | |||||
#define effEditTop 20 | |||||
#define effProcessEvents 25 | |||||
#define effGetEffectName 45 | |||||
#define effGetVendorString 47 | |||||
#define effGetProductString 48 | |||||
#define effGetVendorVersion 49 | |||||
#define effCanDo 51 // currently unused | |||||
/* from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
#define effGetParameterProperties 56 | |||||
#define effGetVstVersion 58 // currently unused | |||||
#define kEffectMagic (CCONST( 'V', 's', 't', 'P' )) | |||||
#define kVstLangEnglish 1 | |||||
#define kVstMidiType 1 | |||||
#define kVstTempoValid (1 << 10) | |||||
#define kVstTransportPlaying (1 << 1) | |||||
struct RemoteVstPlugin; | |||||
#define kVstNanosValid (1 << 8) | |||||
#define kVstPpqPosValid (1 << 9) | |||||
#define kVstTempoValid (1 << 10) | |||||
#define kVstBarsValid (1 << 11) | |||||
#define kVstCyclePosValid (1 << 12) | |||||
#define kVstTimeSigValid (1 << 13) | |||||
#define kVstSmpteValid (1 << 14) | |||||
#define kVstClockValid (1 << 15) | |||||
struct _VstMidiEvent | |||||
{ | |||||
// 00 | |||||
int type; | |||||
// 04 | |||||
int byteSize; | |||||
// 08 | |||||
int deltaFrames; | |||||
// 0c? | |||||
int flags; | |||||
// 10? | |||||
int noteLength; | |||||
// 14? | |||||
int noteOffset; | |||||
// 18 | |||||
char midiData[4]; | |||||
// 1c? | |||||
char detune; | |||||
// 1d? | |||||
char noteOffVelocity; | |||||
// 1e? | |||||
char reserved1; | |||||
// 1f? | |||||
char reserved2; | |||||
}; | |||||
typedef struct _VstMidiEvent VstMidiEvent; | |||||
struct _VstEvent | |||||
{ | |||||
char dump[sizeof (VstMidiEvent)]; | |||||
}; | |||||
typedef struct _VstEvent VstEvent; | |||||
struct _VstEvents | |||||
{ | |||||
// 00 | |||||
int numEvents; | |||||
// 04 | |||||
void *reserved; | |||||
// 08 | |||||
VstEvent * events[]; | |||||
}; | |||||
typedef struct _VstEvents VstEvents; | |||||
/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
struct _VstParameterProperties | |||||
{ | |||||
float stepFloat; | |||||
float smallStepFloat; | |||||
float largeStepFloat; | |||||
char label[64]; | |||||
int32_t flags; | |||||
int32_t minInteger; | |||||
int32_t maxInteger; | |||||
int32_t stepInteger; | |||||
int32_t largeStepInteger; | |||||
char shortLabel[8]; | |||||
}; | |||||
typedef struct _VstParameterProperties VstParameterProperties; | |||||
/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
enum VstParameterFlags | |||||
{ | |||||
kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ | |||||
kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */ | |||||
kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */ | |||||
kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */ | |||||
kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */ | |||||
kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */ | |||||
kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */ | |||||
}; | |||||
struct _AEffect | |||||
{ | |||||
// Never use virtual functions!!! | |||||
// 00-03 | |||||
int magic; | |||||
// dispatcher 04-07 | |||||
intptr_t (* dispatcher) (struct _AEffect *, int, int, intptr_t, void *, float); | |||||
// process, quite sure 08-0b | |||||
void (* process) (struct _AEffect *, float **, float **, int); | |||||
// setParameter 0c-0f | |||||
void (* setParameter) (struct _AEffect *, int, float); | |||||
// getParameter 10-13 | |||||
float (* getParameter) (struct _AEffect *, int); | |||||
// programs 14-17 | |||||
int numPrograms; | |||||
// Params 18-1b | |||||
int numParams; | |||||
// Input 1c-1f | |||||
int numInputs; | |||||
// Output 20-23 | |||||
int numOutputs; | |||||
// flags 24-27 | |||||
int flags; | |||||
// Fill somewhere 28-2b | |||||
void *ptr1; | |||||
void *ptr2; | |||||
// Zeroes 2c-2f 30-33 34-37 38-3b | |||||
char empty3[4 + 4 + 4]; | |||||
// 1.0f 3c-3f | |||||
float unkown_float; | |||||
// An object? pointer 40-43 | |||||
void *ptr3; | |||||
// Zeroes 44-47 | |||||
void *user; | |||||
// Id 48-4b | |||||
int32_t uniqueID; | |||||
// Don't know 4c-4f | |||||
char unknown1[4]; | |||||
// processReplacing 50-53 | |||||
void (* processReplacing) (struct _AEffect *, float **, float **, int); | |||||
}; | |||||
typedef struct _AEffect AEffect; | |||||
struct _VstTimeInfo | |||||
{ | |||||
// 00 | |||||
double samplePos; | |||||
// 08 | |||||
double sampleRate; | |||||
// unconfirmed 10 18 | |||||
char empty1[8 + 8]; | |||||
// 20? | |||||
double tempo; | |||||
// unconfirmed 28 30 38 | |||||
char empty2[8 + 8 + 8]; | |||||
// 40? | |||||
int timeSigNumerator; | |||||
// 44? | |||||
int timeSigDenominator; | |||||
// unconfirmed 48 4c 50 | |||||
char empty3[4 + 4 + 4]; | |||||
// 54 | |||||
int flags; | |||||
}; | |||||
typedef struct _VstTimeInfo VstTimeInfo; | |||||
typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); | |||||
#endif |
@@ -695,7 +695,6 @@ def recheck_all_plugins(qobject=None): | |||||
# Parse all RDF files | # Parse all RDF files | ||||
for i in range(len(rdf_files)): | for i in range(len(rdf_files)): | ||||
rdf_file = rdf_files[i] | rdf_file = rdf_files[i] | ||||
print(rdf_file) | |||||
# Tell GUI we're parsing this bundle | # Tell GUI we're parsing this bundle | ||||
if (qobject): | if (qobject): | ||||