From 849d08c6efe0fd61d99935ecd7db745392216968 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 11 Sep 2014 16:54:31 +0100 Subject: [PATCH] Initial version of Carla plugin for LMMS --- CMakeLists.txt | 14 + plugins/CMakeLists.txt | 3 + plugins/carlabase/CMakeLists.txt | 7 + plugins/carlabase/carla.cpp | 483 ++++++++++++++++++++++++ plugins/carlabase/carla.h | 112 ++++++ plugins/carlapatchbay/CMakeLists.txt | 8 + plugins/carlapatchbay/carlapatchbay.cpp | 51 +++ plugins/carlapatchbay/logo.png | Bin 0 -> 3313 bytes plugins/carlarack/CMakeLists.txt | 8 + plugins/carlarack/carlarack.cpp | 51 +++ plugins/carlarack/logo.png | Bin 0 -> 3313 bytes 11 files changed, 737 insertions(+) create mode 100644 plugins/carlabase/CMakeLists.txt create mode 100644 plugins/carlabase/carla.cpp create mode 100644 plugins/carlabase/carla.h create mode 100644 plugins/carlapatchbay/CMakeLists.txt create mode 100644 plugins/carlapatchbay/carlapatchbay.cpp create mode 100644 plugins/carlapatchbay/logo.png create mode 100644 plugins/carlarack/CMakeLists.txt create mode 100644 plugins/carlarack/carlarack.cpp create mode 100644 plugins/carlarack/logo.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 9726c7cda..31670495a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ INCLUDE(DetectMachine) OPTION(WANT_ALSA "Include ALSA (Advanced Linux Sound Architecture) support" ON) OPTION(WANT_CALF "Include CALF LADSPA plugins" ON) OPTION(WANT_CAPS "Include C* Audio Plugin Suite (LADSPA plugins)" ON) +OPTION(WANT_CARLA "Include Carla plugin" ON) OPTION(WANT_CMT "Include Computer Music Toolkit LADSPA plugins" ON) OPTION(WANT_JACK "Include JACK (Jack Audio Connection Kit) support" ON) OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON) @@ -157,6 +158,18 @@ SET(STATUS_TAP "not built as requested") ENDIF(WANT_TAP) +# check for CARLA +IF(WANT_CARLA) + PKG_CHECK_MODULES(CARLA carla-standalone>=1.9.5) + IF(CARLA_FOUND) + SET(LMMS_HAVE_CARLA TRUE) + SET(STATUS_CARLA "OK") + ELSE(CARLA_FOUND) + SET(STATUS_CARLA "not found, please install the latest carla") + ENDIF(CARLA_FOUND) +ENDIF(WANT_CARLA) + + # check for SDL IF(WANT_SDL) SET(SDL_BUILDING_LIBRARY TRUE) @@ -606,6 +619,7 @@ MESSAGE( MESSAGE( "Optional plugins\n" "----------------\n" +"* Carla Patchbay & Rack : ${STATUS_CARLA}\n" "* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n" "* Stk Mallets : ${STATUS_STK}\n" "* VST-instrument hoster : ${STATUS_VST}\n" diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 76990491d..24eeef641 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,6 +2,9 @@ ADD_SUBDIRECTORY(Amplifier) ADD_SUBDIRECTORY(audio_file_processor) ADD_SUBDIRECTORY(BassBooster) ADD_SUBDIRECTORY(bit_invader) +ADD_SUBDIRECTORY(carlabase) +ADD_SUBDIRECTORY(carlapatchbay) +ADD_SUBDIRECTORY(carlarack) ADD_SUBDIRECTORY(DualFilter) ADD_SUBDIRECTORY(dynamics_processor) ADD_SUBDIRECTORY(flp_import) diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt new file mode 100644 index 000000000..c23082ba6 --- /dev/null +++ b/plugins/carlabase/CMakeLists.txt @@ -0,0 +1,7 @@ +if(LMMS_HAVE_CARLA) + INCLUDE(BuildPlugin) + INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) + LINK_DIRECTORIES(${CARLA_LIBRARY_DIRS}) + LINK_LIBRARIES(${CARLA_LIBRARIES}) + BUILD_PLUGIN(carlabase carla.cpp carla.h MOCFILES carla.h) +endif(LMMS_HAVE_CARLA) diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp new file mode 100644 index 000000000..b46a8d626 --- /dev/null +++ b/plugins/carlabase/carla.cpp @@ -0,0 +1,483 @@ +/* + * carla.cpp - Carla for LMMS + * + * Copyright (C) 2014 Filipe Coelho + * + * 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 "carla.h" + +#define REAL_BUILD // FIXME this shouldn't be needed +#include "CarlaDefines.h" + +#include "engine.h" +#include "InstrumentPlayHandle.h" +#include "InstrumentTrack.h" + +#include +#include +#include +#include + +// ----------------------------------------------------------------------- + +#define handlePtr ((CarlaInstrument*)handle) + +static uint32_t host_get_buffer_size(NativeHostHandle handle) +{ + return handlePtr->handleGetBufferSize(); +} + +static double host_get_sample_rate(NativeHostHandle handle) +{ + return handlePtr->handleGetSampleRate(); +} + +static bool host_is_offline(NativeHostHandle handle) +{ + return handlePtr->handleIsOffline(); +} + +static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle) +{ + return handlePtr->handleGetTimeInfo(); +} + +static bool host_write_midi_event(NativeHostHandle, const NativeMidiEvent*) +{ + return false; // unsupported +} + +static void host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value) +{ + handlePtr->handleUiParameterChanged(index, value); +} + +static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value) +{ + handlePtr->handleUiCustomDataChanged(key, value); +} + +static void host_ui_closed(NativeHostHandle handle) +{ + handlePtr->handleUiClosed(); +} + +static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter) +{ + return handlePtr->handleUiOpenFile(isDir, title, filter); +} + +static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter) +{ + return handlePtr->handleUiSaveFile(isDir, title, filter); +} + +static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt) +{ + return handlePtr->handleDispatcher(opcode, index, value, ptr, opt); +} + +#undef handlePtr + +// ----------------------------------------------------------------------- + +CARLA_EXPORT +const NativePluginDescriptor* carla_get_native_patchbay_plugin(); + +CARLA_EXPORT +const NativePluginDescriptor* carla_get_native_rack_plugin(); + +// ----------------------------------------------------------------------- + +CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay) + : Instrument(instrumentTrack, descriptor), + kIsPatchbay(isPatchbay), + fHandle(NULL), + fDescriptor(isPatchbay ? carla_get_native_patchbay_plugin() : carla_get_native_rack_plugin()), + fMidiEventCount(0) +{ + fHost.handle = this; + fHost.resourceDir = strdup("/usr/share/carla/resources/"); // TODO + fHost.uiName = NULL; + fHost.uiParentId = 0; + + fHost.get_buffer_size = host_get_buffer_size; + fHost.get_sample_rate = host_get_sample_rate; + fHost.is_offline = host_is_offline; + fHost.get_time_info = host_get_time_info; + fHost.write_midi_event = host_write_midi_event; + fHost.ui_parameter_changed = host_ui_parameter_changed; + fHost.ui_custom_data_changed = host_ui_custom_data_changed; + fHost.ui_closed = host_ui_closed; + fHost.ui_open_file = host_ui_open_file; + fHost.ui_save_file = host_ui_save_file; + fHost.dispatcher = host_dispatcher; + + std::memset(&fTimeInfo, 0, sizeof(NativeTimeInfo)); + + fHandle = fDescriptor->instantiate(&fHost); + Q_ASSERT(fHandle != NULL); + + if (fHandle != NULL && fDescriptor->activate != NULL) + fDescriptor->activate(fHandle); + + // we need a play-handle which cares for calling play() + InstrumentPlayHandle * iph = new InstrumentPlayHandle( this ); + engine::mixer()->addPlayHandle( iph ); + + connect(engine::mixer(), SIGNAL(sampleRateChanged()), this, SLOT(sampleRateChanged())); +} + +CarlaInstrument::~CarlaInstrument() +{ + engine::mixer()->removePlayHandles( instrumentTrack() ); + + std::free((char*)fHost.resourceDir); + fHost.resourceDir = NULL; + + std::free((char*)fHost.uiName); + fHost.uiName = NULL; + + if (fHandle == NULL) + return; + + if (fDescriptor->deactivate != NULL) + fDescriptor->deactivate(fHandle); + + if (fDescriptor->cleanup != NULL) + fDescriptor->cleanup(fHandle); + + fHandle = NULL; +} + +// ------------------------------------------------------------------- + +uint32_t CarlaInstrument::handleGetBufferSize() const +{ + return engine::mixer()->framesPerPeriod(); +} + +double CarlaInstrument::handleGetSampleRate() const +{ + return engine::mixer()->processingSampleRate(); +} + +bool CarlaInstrument::handleIsOffline() const +{ + return false; // TODO +} + +const NativeTimeInfo* CarlaInstrument::handleGetTimeInfo() const +{ + return &fTimeInfo; +} + +void CarlaInstrument::handleUiParameterChanged(const uint32_t /*index*/, const float /*value*/) const +{ +} + +void CarlaInstrument::handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const +{ +} + +void CarlaInstrument::handleUiClosed() +{ + emit uiClosed(); +} + +const char* CarlaInstrument::handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const +{ + // TODO + return NULL; +} + +const char* CarlaInstrument::handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const +{ + // TODO + return NULL; +} + +intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) +{ + intptr_t ret = 0; + + switch (opcode) + { + case HOST_OPCODE_NULL: + break; + case HOST_OPCODE_UPDATE_PARAMETER: + case HOST_OPCODE_UPDATE_MIDI_PROGRAM: + case HOST_OPCODE_RELOAD_PARAMETERS: + case HOST_OPCODE_RELOAD_MIDI_PROGRAMS: + case HOST_OPCODE_RELOAD_ALL: + // nothing + break; + case HOST_OPCODE_UI_UNAVAILABLE: + handleUiClosed(); + break; + } + + return ret; + + // unused for now + (void)index; (void)value; (void)ptr; (void)opt; +} + +// ------------------------------------------------------------------- + +Instrument::Flags CarlaInstrument::flags() const +{ + return IsSingleStreamed|IsMidiBased|IsNotBendable; +} + +QString CarlaInstrument::nodeName() const +{ + return descriptor()->name; +} + +void CarlaInstrument::saveSettings(QDomDocument& doc, QDomElement& parent) +{ + if (fHandle == NULL || fDescriptor->get_state == NULL) + return; + + char* const state = fDescriptor->get_state(fHandle); + + if (state == NULL) + return; + + QDomDocument carlaDoc("carla"); + + if (carlaDoc.setContent(QString(state))) + { + QDomNode n = doc.importNode(carlaDoc.documentElement(), true); + parent.appendChild(n); + } + + std::free(state); +} + +void CarlaInstrument::loadSettings(const QDomElement& elem) +{ + if (fHandle == NULL || fDescriptor->get_state == NULL) + return; + + QDomDocument carlaDoc("carla"); + carlaDoc.appendChild(carlaDoc.importNode(elem.firstChildElement(), true )); + + fDescriptor->set_state(fHandle, carlaDoc.toString(0).toUtf8().constData()); +} + +void CarlaInstrument::play(sampleFrame* workingBuffer) +{ + const uint bufsize = engine::mixer()->framesPerPeriod(); + + std::memset(workingBuffer, 0, sizeof(sample_t)*bufsize*DEFAULT_CHANNELS); + + if (fHandle == NULL) + { + instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, NULL); + return; + } + + float buf1[bufsize]; + float buf2[bufsize]; + float* rBuf[] = { buf1, buf2 }; + std::memset(buf1, 0, sizeof(float)*bufsize); + std::memset(buf2, 0, sizeof(float)*bufsize); + + { + const QMutexLocker ml(&fMutex); + fDescriptor->process(fHandle, rBuf, rBuf, bufsize, fMidiEvents, fMidiEventCount); + fMidiEventCount = 0; + } + + for (uint i=0; i < bufsize; ++i) + { + workingBuffer[i][0] = buf1[i]; + workingBuffer[i][1] = buf2[i]; + } + + instrumentTrack()->processAudioBuffer(workingBuffer, bufsize, NULL); +} + +bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f_cnt_t offset) +{ + const QMutexLocker ml(&fMutex); + + if (fMidiEventCount >= kMaxMidiEvents) + return false; + + NativeMidiEvent& nEvent(fMidiEvents[fMidiEventCount++]); + std::memset(&nEvent, 0, sizeof(NativeMidiEvent)); + + nEvent.port = 0; + nEvent.time = offset; + nEvent.data[0] = event.type() | (event.channel() & 0x0F); + + switch (event.type()) + { + case MidiNoteOn: + if (event.velocity() > 0) + { + if (event.key() < 0 || event.key() > MidiMaxKey) + break; + + nEvent.data[1] = event.key(); + nEvent.data[2] = event.velocity(); + nEvent.size = 3; + break; + } + else + { + nEvent.data[0] = MidiNoteOff | (event.channel() & 0x0F); + // nobreak + } + + case MidiNoteOff: + if (event.key() < 0 || event.key() > MidiMaxKey) + break; + + nEvent.data[1] = event.key(); + nEvent.data[2] = event.velocity(); + nEvent.size = 3; + break; + + case MidiKeyPressure: + nEvent.data[1] = event.key(); + nEvent.data[2] = event.velocity(); + nEvent.size = 3; + break; + + case MidiControlChange: + nEvent.data[1] = event.controllerNumber(); + nEvent.data[2] = event.controllerValue(); + nEvent.size = 3; + break; + + case MidiProgramChange: + nEvent.data[1] = event.program(); + nEvent.size = 2; + break; + + case MidiChannelPressure: + nEvent.data[1] = event.channelPressure(); + nEvent.size = 2; + break; + + case MidiPitchBend: + nEvent.data[1] = event.pitchBend() & 0x7f; + nEvent.data[2] = event.pitchBend() >> 7; + nEvent.size = 3; + break; + + default: + // unhandled + --fMidiEventCount; + break; + } + + return true; +} + +PluginView* CarlaInstrument::instantiateView(QWidget* parent) +{ + if (QWidget* const window = parent->window()) + fHost.uiParentId = window->winId(); + else + fHost.uiParentId = 0; + + std::free((char*)fHost.uiName); + fHost.uiName = strdup(parent->windowTitle().toUtf8().constData()); + + return new CarlaInstrumentView(this, parent); +} + +void CarlaInstrument::sampleRateChanged() +{ + fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, handleGetSampleRate()); +} + +// ------------------------------------------------------------------- + +CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWidget* const parent) + : InstrumentView(instrument, parent), + fHandle(instrument->fHandle), + fDescriptor(instrument->fDescriptor), + fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(50) : 0) +{ + setAutoFillBackground(true); + + //QPalette pal; + //pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork")); + //setPalette(pal); + + QVBoxLayout * l = new QVBoxLayout( this ); + l->setContentsMargins( 20, 80, 10, 10 ); + l->setSpacing( 10 ); + + m_toggleUIButton = new QPushButton( tr( "Show GUI" ), this ); + m_toggleUIButton->setCheckable( true ); + m_toggleUIButton->setChecked( false ); + //m_toggleUIButton->setIcon( embed::getIconPixmap( "zoom" ) ); + //m_toggleUIButton->setFont( pointSize<8>( m_toggleUIButton->font() ) ); + connect( m_toggleUIButton, SIGNAL( clicked(bool) ), this, SLOT( toggleUI( bool ) ) ); + + m_toggleUIButton->setWhatsThis( + tr( "Click here to show or hide the graphical user interface (GUI) of Carla." ) ); + + l->addWidget( m_toggleUIButton ); + l->addStretch(); + + connect(instrument, SIGNAL(uiClosed()), this, SLOT(uiClosed())); +} + +CarlaInstrumentView::~CarlaInstrumentView() +{ + if (m_toggleUIButton->isChecked()) + toggleUI(false); +} + +void CarlaInstrumentView::toggleUI(bool visible) +{ + if (fHandle != NULL && fDescriptor->ui_show != NULL) + fDescriptor->ui_show(fHandle, visible); +} + +void CarlaInstrumentView::uiClosed() +{ + m_toggleUIButton->setChecked(false); +} + +void CarlaInstrumentView::modelChanged() +{ +} + +void CarlaInstrumentView::timerEvent(QTimerEvent* event) +{ + if (event->timerId() == fTimerId) + fDescriptor->ui_idle(fHandle); + + InstrumentView::timerEvent(event); +} + +// ------------------------------------------------------------------- + +#include "moc_carla.cxx" diff --git a/plugins/carlabase/carla.h b/plugins/carlabase/carla.h new file mode 100644 index 000000000..bd9ce5193 --- /dev/null +++ b/plugins/carlabase/carla.h @@ -0,0 +1,112 @@ +/* + * carla.h - Carla for LMMS + * + * Copyright (C) 2014 Filipe Coelho + * + * 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. + * + */ + +#ifndef _CARLA_H +#define _CARLA_H + +#include "CarlaNative.h" + +#include "Instrument.h" +#include "InstrumentView.h" + +class QPushButton; + +class PLUGIN_EXPORT CarlaInstrument : public Instrument +{ + Q_OBJECT + +public: + static const uint32_t kMaxMidiEvents = 512; + + CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay); + virtual ~CarlaInstrument(); + + // CarlaNative functions + uint32_t handleGetBufferSize() const; + double handleGetSampleRate() const; + bool handleIsOffline() const; + const NativeTimeInfo* handleGetTimeInfo() const; + void handleUiParameterChanged(const uint32_t index, const float value) const; + void handleUiCustomDataChanged(const char* const key, const char* const value) const; + void handleUiClosed(); + const char* handleUiOpenFile(const bool isDir, const char* const title, const char* const filter) const; + const char* handleUiSaveFile(const bool isDir, const char* const title, const char* const filter) const; + intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt); + + // LMMS functions + virtual Flags flags() const; + virtual QString nodeName() const; + virtual void saveSettings(QDomDocument& doc, QDomElement& parent); + virtual void loadSettings(const QDomElement& elem); + virtual void play(sampleFrame* workingBuffer); + virtual bool handleMidiEvent(const MidiEvent& event, const MidiTime& time, f_cnt_t offset); + virtual PluginView* instantiateView(QWidget* parent); + +signals: + void uiClosed(); + +private slots: + void sampleRateChanged(); + +private: + const bool kIsPatchbay; + + NativePluginHandle fHandle; + NativeHostDescriptor fHost; + const NativePluginDescriptor* fDescriptor; + + uint32_t fMidiEventCount; + NativeMidiEvent fMidiEvents[kMaxMidiEvents]; + NativeTimeInfo fTimeInfo; + + // this is only needed because note-offs are being sent during play + QMutex fMutex; + + friend class CarlaInstrumentView; +}; + +class CarlaInstrumentView : public InstrumentView +{ + Q_OBJECT + +public: + CarlaInstrumentView(CarlaInstrument* const instrument, QWidget* const parent); + virtual ~CarlaInstrumentView(); + +private slots: + void toggleUI(bool); + void uiClosed(); + +private: + virtual void modelChanged(); + virtual void timerEvent(QTimerEvent*); + + NativePluginHandle fHandle; + const NativePluginDescriptor* fDescriptor; + int fTimerId; + + QPushButton * m_toggleUIButton; +}; + +#endif diff --git a/plugins/carlapatchbay/CMakeLists.txt b/plugins/carlapatchbay/CMakeLists.txt new file mode 100644 index 000000000..878415ea0 --- /dev/null +++ b/plugins/carlapatchbay/CMakeLists.txt @@ -0,0 +1,8 @@ +if(LMMS_HAVE_CARLA) + ADD_DEFINITIONS(-DCARLA_PLUGIN_PATCHBAY -DCARLA_PLUGIN_SYNTH) + INCLUDE(BuildPlugin) + INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase") + LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/../carlabase") + LINK_LIBRARIES(carlabase) + BUILD_PLUGIN(carlapatchbay carlapatchbay.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") +endif(LMMS_HAVE_CARLA) diff --git a/plugins/carlapatchbay/carlapatchbay.cpp b/plugins/carlapatchbay/carlapatchbay.cpp new file mode 100644 index 000000000..4c990994d --- /dev/null +++ b/plugins/carlapatchbay/carlapatchbay.cpp @@ -0,0 +1,51 @@ +/* + * carlapatchbay.cpp - Carla for LMMS (Patchbay) + * + * Copyright (C) 2014 Filipe Coelho + * + * 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 "carla.h" + +#include "embed.cpp" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT carlapatchbay_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Carla Patchbay", + QT_TRANSLATE_NOOP( "pluginBrowser", + "Carla Patchbay Instrument" ), + "falkTX ", + 0x0195, + Plugin::Instrument, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + +Plugin* PLUGIN_EXPORT lmms_plugin_main(Model*, void* data) +{ + return new CarlaInstrument(static_cast(data), &carlapatchbay_plugin_descriptor, true); +} + +} diff --git a/plugins/carlapatchbay/logo.png b/plugins/carlapatchbay/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..353d5d718d6fef054ff4fed2932f4f45df7f792c GIT binary patch literal 3313 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 literal 0 HcmV?d00001 diff --git a/plugins/carlarack/CMakeLists.txt b/plugins/carlarack/CMakeLists.txt new file mode 100644 index 000000000..2655fa89b --- /dev/null +++ b/plugins/carlarack/CMakeLists.txt @@ -0,0 +1,8 @@ +if(LMMS_HAVE_CARLA) + ADD_DEFINITIONS(-DCARLA_PLUGIN_RACK -DCARLA_PLUGIN_SYNTH) + INCLUDE(BuildPlugin) + INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase") + LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/../carlabase") + LINK_LIBRARIES(carlabase) + BUILD_PLUGIN(carlarack carlarack.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") +endif(LMMS_HAVE_CARLA) diff --git a/plugins/carlarack/carlarack.cpp b/plugins/carlarack/carlarack.cpp new file mode 100644 index 000000000..a2b2e0570 --- /dev/null +++ b/plugins/carlarack/carlarack.cpp @@ -0,0 +1,51 @@ +/* + * carlarack.cpp - Carla for LMMS (Rack) + * + * Copyright (C) 2014 Filipe Coelho + * + * 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 "carla.h" + +#include "embed.cpp" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT carlarack_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Carla Rack", + QT_TRANSLATE_NOOP( "pluginBrowser", + "Carla Rack Instrument" ), + "falkTX ", + 0x0195, + Plugin::Instrument, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + +Plugin* PLUGIN_EXPORT lmms_plugin_main(Model*, void* data) +{ + return new CarlaInstrument(static_cast(data), &carlarack_plugin_descriptor, false); +} + +} diff --git a/plugins/carlarack/logo.png b/plugins/carlarack/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..353d5d718d6fef054ff4fed2932f4f45df7f792c GIT binary patch literal 3313 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 literal 0 HcmV?d00001