From f1d383d04deb91686f5407b259e529766739b034 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 28 Aug 2009 23:43:22 +0200 Subject: [PATCH] ZynAddSubFX: added GUI-less mode Added a new GUI-less mode to ZynAddSubFX instrument plugin which allows to let ZynAddSubFX audio processing happen within LMMS, giving a much better realtime behaviour. As soon as showing up the GUI settings of GUI-less ZynAddSubFX instance are saved and a traditional RemoteZynAddSubFx process is being launched and the settings are applied there. --- plugins/zynaddsubfx/CMakeLists.txt | 72 ++++-- plugins/zynaddsubfx/LocalZynAddSubFx.cpp | 238 ++++++++++++++++++ plugins/zynaddsubfx/LocalZynAddSubFx.h | 68 +++++ ..._zynaddsubfx.cpp => RemoteZynAddSubFx.cpp} | 162 ++---------- ...mote_zynaddsubfx.h => RemoteZynAddSubFx.h} | 7 +- .../{zynaddsubfx.cpp => ZynAddSubFx.cpp} | 212 ++++++++++------ .../{zynaddsubfx.h => ZynAddSubFx.h} | 20 +- 7 files changed, 522 insertions(+), 257 deletions(-) create mode 100644 plugins/zynaddsubfx/LocalZynAddSubFx.cpp create mode 100644 plugins/zynaddsubfx/LocalZynAddSubFx.h rename plugins/zynaddsubfx/{remote_zynaddsubfx.cpp => RemoteZynAddSubFx.cpp} (57%) rename plugins/zynaddsubfx/{remote_zynaddsubfx.h => RemoteZynAddSubFx.h} (88%) rename plugins/zynaddsubfx/{zynaddsubfx.cpp => ZynAddSubFx.cpp} (55%) rename plugins/zynaddsubfx/{zynaddsubfx.h => ZynAddSubFx.h} (86%) diff --git a/plugins/zynaddsubfx/CMakeLists.txt b/plugins/zynaddsubfx/CMakeLists.txt index 8899181db..1ffb1ec05 100644 --- a/plugins/zynaddsubfx/CMakeLists.txt +++ b/plugins/zynaddsubfx/CMakeLists.txt @@ -2,9 +2,7 @@ IF(LMMS_HAVE_FFTW3F) INCLUDE(BuildPlugin) -BUILD_PLUGIN(zynaddsubfx zynaddsubfx.cpp zynaddsubfx.h MOCFILES zynaddsubfx.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) - -SET(ZYN_SRC +SET(ZYN_SRC_CORE ${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/AnalogFilter.C ${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/Filter.C ${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/SVFilter.C @@ -51,7 +49,9 @@ SET(ZYN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Util.C ${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Master.C ${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Microtonal.C - ${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Part.C + ${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Part.C) + +SET(ZYN_SRC_GUI ${CMAKE_CURRENT_SOURCE_DIR}/src/UI/MasterUI.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/UI/VirKeyboard.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/UI/ConfigUI.cc @@ -87,53 +87,73 @@ SET(MXML_SRC # definitions for ZynAddSubFX IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE) -ADD_DEFINITIONS(-DOS_LINUX) + ADD_DEFINITIONS(-DOS_LINUX) ELSE(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE) -ADD_DEFINITIONS(-DOS_WINDOWS) + ADD_DEFINITIONS(-DOS_WINDOWS) ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE) +# do not conflict with LMMS' Controller class +ADD_DEFINITIONS(-DController=ZynController) + # use asm optimizations when on x86 or x86_64 IF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) -ADD_DEFINITIONS(-DASM_F2I_YES) + ADD_DEFINITIONS(-DASM_F2I_YES) ENDIF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) # build ZynAddSubFX with full optimizations SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wno-write-strings -Wno-deprecated-declarations") -# link default libraries -LINK_DIRECTORIES(${FFTW3F_LIBRARY_DIRS}) -LINK_LIBRARIES(${FFTW3F_LIBRARIES} -lz -lpthread ${CMAKE_CURRENT_BINARY_DIR}/fltk/bin/libfltk.a) - -# FLTK needs X -IF(LMMS_BUILD_LINUX) -FIND_PACKAGE(X11) -FIND_PACKAGE(Freetype) -LINK_LIBRARIES(${X11_LIBRARIES} ${X11_Xft_LIB} ${FREETYPE_LIBRARY}) -ENDIF(LMMS_BUILD_LINUX) - # link system-libraries when on win32 IF(LMMS_BUILD_WIN32) -ADD_DEFINITIONS(-DPTW32_STATIC_LIB) -LINK_LIBRARIES(${QT_LIBRARIES} -lole32 -luuid -lcomctl32 -lgdi32) + ADD_DEFINITIONS(-DPTW32_STATIC_LIB) ENDIF(LMMS_BUILD_WIN32) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/fltk/ ${CMAKE_CURRENT_SOURCE_DIR} ${FFTW3F_INCLUDE_DIRS}) -ADD_EXECUTABLE(remote_zynaddsubfx remote_zynaddsubfx.cpp ${ZYN_SRC} ${MXML_SRC}) -INSTALL(TARGETS remote_zynaddsubfx RUNTIME DESTINATION ${PLUGIN_DIR}) +ADD_LIBRARY(ZynAddSubFxCore SHARED LocalZynAddSubFx.cpp ${ZYN_SRC_CORE} ${MXML_SRC}) +TARGET_LINK_LIBRARIES(ZynAddSubFxCore ${FFTW3F_LIBRARIES} -lz -lpthread) +IF(LMMS_BUILD_WIN32) + TARGET_LINK_LIBRARIES(ZynAddSubFxCore -lwsock32) + INSTALL(TARGETS ZynAddSubFxCore DESTINATION ${PLUGIN_DIR}) +ELSE(LMMS_BUILD_WIN32) + INSTALL(TARGETS ZynAddSubFxCore LIBRARY DESTINATION ${PLUGIN_DIR}) +ENDIF(LMMS_BUILD_WIN32) + +BUILD_PLUGIN(ZynAddSubFx ZynAddSubFx.cpp ZynAddSubFx.h MOCFILES ZynAddSubFx.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) +TARGET_LINK_LIBRARIES(ZynAddSubFx ZynAddSubFxCore) + + +SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${PLUGIN_DIR}") +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp ${ZYN_SRC_GUI}) +INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION ${PLUGIN_DIR}) +TARGET_LINK_LIBRARIES(RemoteZynAddSubFx ZynAddSubFxCore ${CMAKE_CURRENT_BINARY_DIR}/fltk/bin/libfltk.a) + +# link system libraries when on win32 +IF(LMMS_BUILD_WIN32) + TARGET_LINK_LIBRARIES(RemoteZynAddSubFx ${QT_LIBRARIES} -lole32 -luuid -lcomctl32 -lgdi32) +ENDIF(LMMS_BUILD_WIN32) + +# FLTK needs X +IF(LMMS_BUILD_LINUX) + FIND_PACKAGE(X11) + FIND_PACKAGE(Freetype) + TARGET_LINK_LIBRARIES(RemoteZynAddSubFx ${X11_LIBRARIES} ${X11_Xft_LIB} ${FREETYPE_LIBRARY}) +ENDIF(LMMS_BUILD_LINUX) + IF(LMMS_BUILD_WIN32) - ADD_CUSTOM_COMMAND(TARGET remote_zynaddsubfx POST_BUILD COMMAND ${STRIP} ${CMAKE_CURRENT_BINARY_DIR}/remote_zynaddsubfx.exe) + ADD_CUSTOM_COMMAND(TARGET RemoteZynAddSubFx POST_BUILD COMMAND ${STRIP} ${CMAKE_CURRENT_BINARY_DIR}/RemoteZynAddSubFx.exe) ENDIF(LMMS_BUILD_WIN32) # build FLTK IF(LMMS_BUILD_WIN64) -SET(FLTK_EXTRA_FLAGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_SOURCE_DIR}/cmake/modules/Win64Toolchain.cmake") + SET(FLTK_EXTRA_FLAGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_SOURCE_DIR}/cmake/modules/Win64Toolchain.cmake") ELSEIF(LMMS_BUILD_WIN32) -SET(FLTK_EXTRA_FLAGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_SOURCE_DIR}/cmake/modules/Win32Toolchain.cmake") + SET(FLTK_EXTRA_FLAGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_SOURCE_DIR}/cmake/modules/Win32Toolchain.cmake") ENDIF(LMMS_BUILD_WIN64) ADD_CUSTOM_TARGET(libfltk COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/fltk && cd ${CMAKE_CURRENT_BINARY_DIR}/fltk && ${CMAKE_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR}/fltk ${FLTK_EXTRA_FLAGS} -DFLTK_USE_SYSTEM_ZLIB:BOOL=ON -DFLTK_USE_SYSTEM_JPEG:BOOL=ON -DFLTK_USE_SYSTEM_PNG:BOOL=ON -DUSE_OPENGL:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DCMAKE_BUILD_TYPE=release && ${CMAKE_BUILD_TOOL}) -ADD_DEPENDENCIES(remote_zynaddsubfx libfltk) +ADD_DEPENDENCIES(RemoteZynAddSubFx libfltk) ENDIF(LMMS_HAVE_FFTW3F) diff --git a/plugins/zynaddsubfx/LocalZynAddSubFx.cpp b/plugins/zynaddsubfx/LocalZynAddSubFx.cpp new file mode 100644 index 000000000..013f1bea9 --- /dev/null +++ b/plugins/zynaddsubfx/LocalZynAddSubFx.cpp @@ -0,0 +1,238 @@ +/* + * LocalZynAddSubFx.cpp - local implementation of ZynAddSubFx plugin + * + * Copyright (c) 2009 Tobias Doerffel + * + * 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 + +#include "LocalZynAddSubFx.h" + +#include "src/Input/MidiIn.h" +#include "src/Misc/Master.h" +#include "src/Misc/Dump.h" + + +int LocalZynAddSubFx::s_instanceCount = 0; + + +LocalZynAddSubFx::LocalZynAddSubFx() +{ + for( int i = 0; i < NumKeys; ++i ) + { + m_runningNotes[i] = 0; + } + + if( s_instanceCount == 0 ) + { +#ifdef LMMS_BUILD_WIN32 + // (non-portable) initialization of statically linked pthread library + pthread_win32_process_attach_np(); + pthread_win32_thread_attach_np(); +#endif + + config.init(); + OSCIL_SIZE = config.cfg.OscilSize; + + config.cfg.GzipCompression = 0; + + srand( time( NULL ) ); + denormalkillbuf = new REALTYPE[SOUND_BUFFER_SIZE]; + for( int i = 0; i < SOUND_BUFFER_SIZE; ++i ) + { + denormalkillbuf[i] = (RND-0.5)*1e-16; + } + + OscilGen::tmpsmps = new REALTYPE[OSCIL_SIZE]; + newFFTFREQS( &OscilGen::outoscilFFTfreqs, OSCIL_SIZE/2 ); + } + ++s_instanceCount; + + m_master = new Master(); + m_master->swaplr = 0; +} + + + + +LocalZynAddSubFx::~LocalZynAddSubFx() +{ + delete m_master; + + if( --s_instanceCount == 0 ) + { + delete[] denormalkillbuf; + delete[] OscilGen::tmpsmps; + deleteFFTFREQS( &OscilGen::outoscilFFTfreqs ); + } +} + + + + +void LocalZynAddSubFx::setSampleRate( int _sampleRate ) +{ + SAMPLE_RATE = _sampleRate; +} + + + + +void LocalZynAddSubFx::setBufferSize( int _bufferSize ) +{ + SOUND_BUFFER_SIZE = _bufferSize; +} + + + + +void LocalZynAddSubFx::saveXML( const std::string & _filename ) +{ + char * name = strdup( _filename.c_str() ); + m_master->saveXML( name ); + free( name ); +} + + + + +void LocalZynAddSubFx::loadXML( const std::string & _filename ) +{ + char * f = strdup( _filename.c_str() ); + + pthread_mutex_lock( &m_master->mutex ); + m_master->defaults(); + m_master->loadXML( f ); + pthread_mutex_unlock( &m_master->mutex ); + + m_master->applyparameters(); + + unlink( f ); + free( f ); +} + + + + +void LocalZynAddSubFx::loadPreset( const std::string & _filename, int _part ) +{ + char * f = strdup( _filename.c_str() ); + + pthread_mutex_lock( &m_master->mutex ); + m_master->part[_part]->defaultsinstrument(); + m_master->part[_part]->loadXMLinstrument( f ); + pthread_mutex_unlock( &m_master->mutex ); + + m_master->applyparameters(); + + free( f ); +} + + + + +void LocalZynAddSubFx::setPresetDir( const std::string & _dir ) +{ + m_presetsDir = _dir; + for( int i = 0; i < MAX_BANK_ROOT_DIRS; ++i ) + { + if( config.cfg.bankRootDirList[i] == NULL ) + { + config.cfg.bankRootDirList[i] = new char[MAX_STRING_SIZE]; + strcpy( config.cfg.bankRootDirList[i], m_presetsDir.c_str() ); + break; + } + else if( strcmp( config.cfg.bankRootDirList[i], + m_presetsDir.c_str() ) == 0 ) + { + break; + } + } +} + + + + +void LocalZynAddSubFx::processMidiEvent( const midiEvent & _e ) +{ + // all functions are called while m_master->mutex is held + static MidiIn midiIn; + + switch( _e.m_type ) + { + case MidiNoteOn: + if( _e.velocity() > 0 ) + { + if( _e.key() <= 0 || _e.key() >= 128 ) + { + break; + } + if( m_runningNotes[_e.key()] > 0 ) + { + m_master->NoteOff( 0, _e.key() ); + } + ++m_runningNotes[_e.key()]; + m_master->NoteOn( 0, _e.key(), _e.velocity() ); + break; + } + case MidiNoteOff: + if( _e.key() <= 0 || _e.key() >= 128 ) + { + break; + } + if( --m_runningNotes[_e.key()] <= 0 ) + { + m_master->NoteOff( 0, _e.key() ); + } + break; + case MidiPitchBend: + m_master->SetController( 0, C_pitchwheel, + _e.m_data.m_param[0] + + _e.m_data.m_param[1]*128-8192 ); + break; + case MidiControlChange: + m_master->SetController( 0, + midiIn.getcontroller( _e.m_data.m_param[0] ), + _e.m_data.m_param[1] ); + break; + default: + break; + } +} + + + + +void LocalZynAddSubFx::processAudio( sampleFrame * _out ) +{ + REALTYPE outputl[SOUND_BUFFER_SIZE]; + REALTYPE outputr[SOUND_BUFFER_SIZE]; + + m_master->AudioOut( outputl, outputr ); + + for( int f = 0; f < SOUND_BUFFER_SIZE; ++f ) + { + _out[f][0] = outputl[f]; + _out[f][1] = outputr[f]; + } +} + + diff --git a/plugins/zynaddsubfx/LocalZynAddSubFx.h b/plugins/zynaddsubfx/LocalZynAddSubFx.h new file mode 100644 index 000000000..978727257 --- /dev/null +++ b/plugins/zynaddsubfx/LocalZynAddSubFx.h @@ -0,0 +1,68 @@ +/* + * LocalZynAddSubFx.h - local implementation of ZynAddSubFx plugin + * + * Copyright (c) 2009 Tobias Doerffel + * + * 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 _LOCAL_ZYNADDSUBFX_H +#define _LOCAL_ZYNADDSUBFX_H + +#include "note.h" + +class Master; + +class LocalZynAddSubFx +{ +public: + LocalZynAddSubFx(); + ~LocalZynAddSubFx(); + + void setSampleRate( int _sampleRate ); + void setBufferSize( int _bufferSize ); + + void saveXML( const std::string & _filename ); + void loadXML( const std::string & _filename ); + + void loadPreset( const std::string & _filename, int _part = 0 ); + + void setPresetDir( const std::string & _dir ); + + void processMidiEvent( const midiEvent & _e ); + + void processAudio( sampleFrame * _out ); + + inline Master * master() + { + return m_master; + } + + +protected: + static int s_instanceCount; + + std::string m_presetsDir; + + int m_runningNotes[NumKeys]; + Master * m_master; + +} ; + +#endif diff --git a/plugins/zynaddsubfx/remote_zynaddsubfx.cpp b/plugins/zynaddsubfx/RemoteZynAddSubFx.cpp similarity index 57% rename from plugins/zynaddsubfx/remote_zynaddsubfx.cpp rename to plugins/zynaddsubfx/RemoteZynAddSubFx.cpp index 8f24c1e20..a70c637bf 100644 --- a/plugins/zynaddsubfx/remote_zynaddsubfx.cpp +++ b/plugins/zynaddsubfx/RemoteZynAddSubFx.cpp @@ -1,5 +1,5 @@ /* - * remote_zynaddsubfx.cpp - ZynAddSubFX-embedding plugin + * RemoteZynAddSubFx.cpp - ZynAddSubFx-embedding plugin * * Copyright (c) 2008-2009 Tobias Doerffel * @@ -28,56 +28,32 @@ #define BUILD_REMOTE_PLUGIN_CLIENT #include "note.h" #include "RemotePlugin.h" -#include "remote_zynaddsubfx.h" +#include "RemoteZynAddSubFx.h" +#include "LocalZynAddSubFx.h" -#include "src/Misc/Master.h" -#include "src/Misc/Util.h" -#include "src/Misc/Dump.h" #include "src/UI/MasterUI.h" #include -class RemoteZynAddSubFX : public RemotePluginClient +class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx { public: - RemoteZynAddSubFX( int _shm_in, int _shm_out ) : + RemoteZynAddSubFx( int _shm_in, int _shm_out ) : RemotePluginClient( _shm_in, _shm_out ), + LocalZynAddSubFx(), m_guiSleepTime( 100 ), m_guiExit( false ) { - for( int i = 0; i < NumKeys; ++i ) - { - m_runningNotes[i] = 0; - } setInputCount( 0 ); sendMessage( IdInitDone ); waitForMessage( IdInitDone ); - config.init(); - OSCIL_SIZE = config.cfg.OscilSize; - - config.cfg.GzipCompression = 0; - - srand( time( NULL ) ); - denormalkillbuf = new REALTYPE[SOUND_BUFFER_SIZE]; - for( int i = 0; i < SOUND_BUFFER_SIZE; ++i ) - { - denormalkillbuf[i] = (RND-0.5)*1e-16; - } - - OscilGen::tmpsmps = new REALTYPE[OSCIL_SIZE]; - newFFTFREQS( &OscilGen::outoscilFFTfreqs, OSCIL_SIZE/2 ); - - m_master = new Master(); - m_master->swaplr = 0; - pthread_mutex_init( &m_guiMutex, NULL ); pthread_create( &m_guiThreadHandle, NULL, guiThread, this ); - } - virtual ~RemoteZynAddSubFX() + virtual ~RemoteZynAddSubFx() { m_guiExit = true; #ifdef LMMS_BUILD_WIN32 @@ -85,23 +61,16 @@ public: #else usleep( m_guiSleepTime * 2 * 1000 ); #endif - - delete m_master; - - delete[] denormalkillbuf; - delete[] OscilGen::tmpsmps; - deleteFFTFREQS( &OscilGen::outoscilFFTfreqs ); - pthread_mutex_destroy( &m_guiMutex ); } virtual void updateSampleRate() { - SAMPLE_RATE = sampleRate(); + LocalZynAddSubFx::setSampleRate( sampleRate() ); } virtual void updateBufferSize() { - SOUND_BUFFER_SIZE = bufferSize(); + LocalZynAddSubFx::setBufferSize( bufferSize() ); } void run() @@ -133,31 +102,13 @@ public: case IdSaveSettingsToFile: { - char * name = strdup( _m.getString().c_str() ); - m_master->saveXML( name ); - free( name ); + LocalZynAddSubFx::saveXML( _m.getString() ); sendMessage( IdSaveSettingsToFile ); break; } case IdZasfPresetDirectory: - m_presetsDir = _m.getString(); - for( int i = 0; i < MAX_BANK_ROOT_DIRS; ++i ) - { - if( config.cfg.bankRootDirList[i] == NULL ) - { - config.cfg.bankRootDirList[i] = - new char[MAX_STRING_SIZE]; - strcpy( config.cfg.bankRootDirList[i], - m_presetsDir.c_str() ); - break; - } - else if( strcmp( config.cfg.bankRootDirList[i], - m_presetsDir.c_str() ) == 0 ) - { - break; - } - } + LocalZynAddSubFx::setPresetDir( _m.getString() ); break; default: @@ -170,74 +121,20 @@ public: virtual void processMidiEvent( const midiEvent & _e, const f_cnt_t /* _offset */ ) { - static MidiIn midiIn; - - switch( _e.m_type ) - { - case MidiNoteOn: - if( _e.velocity() > 0 ) - { - if( _e.key() <= 0 || _e.key() >= 128 ) - { - break; - } - if( m_runningNotes[_e.key()] > 0 ) - { - m_master->NoteOff( 0, _e.key() ); - } - ++m_runningNotes[_e.key()]; - m_master->NoteOn( 0, _e.key(), _e.velocity() ); - break; - } - case MidiNoteOff: - if( _e.key() <= 0 || _e.key() >= 128 ) - { - break; - } - if( --m_runningNotes[_e.key()] <= 0 ) - { - m_master->NoteOff( 0, _e.key() ); - } - break; - case MidiPitchBend: - m_master->SetController( 0, C_pitchwheel, - _e.m_data.m_param[0] + - _e.m_data.m_param[1]*128-8192 ); - break; - case MidiControlChange: - m_master->SetController( 0, - midiIn.getcontroller( _e.m_data.m_param[0] ), - _e.m_data.m_param[1] ); - break; - default: - break; - } + LocalZynAddSubFx::processMidiEvent( _e ); } virtual void process( const sampleFrame * _in, sampleFrame * _out ) { - REALTYPE outputl[SOUND_BUFFER_SIZE]; - REALTYPE outputr[SOUND_BUFFER_SIZE]; - - m_master->AudioOut( outputl, outputr ); - - for( int f = 0; f < SOUND_BUFFER_SIZE; ++f ) - { - _out[f][0] = outputl[f]; - _out[f][1] = outputr[f]; - } + LocalZynAddSubFx::processAudio( _out ); } static void * guiThread( void * _arg ); private: - std::string m_presetsDir; - const int m_guiSleepTime; - int m_runningNotes[NumKeys]; - Master * m_master; pthread_t m_guiThreadHandle; pthread_mutex_t m_guiMutex; @@ -248,12 +145,12 @@ private: -void * RemoteZynAddSubFX::guiThread( void * _arg ) +void * RemoteZynAddSubFx::guiThread( void * _arg ) { int e; MasterUI * ui = NULL; - RemoteZynAddSubFX * _this = static_cast( _arg ); + RemoteZynAddSubFx * _this = static_cast( _arg ); Master * master = _this->m_master; while( !_this->m_guiExit ) @@ -306,15 +203,11 @@ void * RemoteZynAddSubFX::guiThread( void * _arg ) case IdLoadSettingsFromFile: { - char * f = strdup( m.getString().c_str() ); - pthread_mutex_lock( &master->mutex ); - master->defaults(); - master->loadXML( f ); - pthread_mutex_unlock( &master->mutex ); - master->applyparameters(); - if( ui ) ui->refresh_master_ui(); - unlink( f ); - free( f ); + _this->LocalZynAddSubFx::loadXML( m.getString() ); + if( ui ) + { + ui->refresh_master_ui(); + } pthread_mutex_lock( &master->mutex ); _this->sendMessage( IdLoadSettingsFromFile ); pthread_mutex_unlock( &master->mutex ); @@ -323,21 +216,14 @@ void * RemoteZynAddSubFX::guiThread( void * _arg ) case IdLoadPresetFromFile: { - char * f = strdup( m.getString().c_str() ); - pthread_mutex_lock( &master->mutex ); - const int npart = ui ? - ui->npartcounter->value()-1 : 0; - master->part[npart]->defaultsinstrument(); - master->part[npart]->loadXMLinstrument( f ); - pthread_mutex_unlock( &master->mutex ); - master->applyparameters(); + _this->LocalZynAddSubFx::loadPreset( m.getString(), ui ? + ui->npartcounter->value()-1 : 0 ); if( ui ) { ui->npartcounter->do_callback(); ui->updatepanel(); ui->refresh_master_ui(); } - free( f ); pthread_mutex_lock( &master->mutex ); _this->sendMessage( IdLoadPresetFromFile ); pthread_mutex_unlock( &master->mutex ); @@ -375,8 +261,8 @@ int main( int _argc, char * * _argv ) #endif - RemoteZynAddSubFX * remoteZASF = - new RemoteZynAddSubFX( atoi( _argv[1] ), atoi( _argv[2] ) ); + RemoteZynAddSubFx * remoteZASF = + new RemoteZynAddSubFx( atoi( _argv[1] ), atoi( _argv[2] ) ); remoteZASF->run(); diff --git a/plugins/zynaddsubfx/remote_zynaddsubfx.h b/plugins/zynaddsubfx/RemoteZynAddSubFx.h similarity index 88% rename from plugins/zynaddsubfx/remote_zynaddsubfx.h rename to plugins/zynaddsubfx/RemoteZynAddSubFx.h index d4aa7fc19..cdf5037cb 100644 --- a/plugins/zynaddsubfx/remote_zynaddsubfx.h +++ b/plugins/zynaddsubfx/RemoteZynAddSubFx.h @@ -1,8 +1,8 @@ /* - * remote_zynaddsubfx.h - ZynAddSubFX-embedding plugin + * RemoteZynAddSubFx.h - ZynAddSubFX-embedding plugin + * + * Copyright (c) 2008-2009 Tobias Doerffel * - * Copyright (c) 2008 Tobias Doerffel - * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -22,7 +22,6 @@ * */ - #ifndef _REMOTE_ZYNADDSUBFX_H #define _REMOTE_ZYNADDSUBFX_H diff --git a/plugins/zynaddsubfx/zynaddsubfx.cpp b/plugins/zynaddsubfx/ZynAddSubFx.cpp similarity index 55% rename from plugins/zynaddsubfx/zynaddsubfx.cpp rename to plugins/zynaddsubfx/ZynAddSubFx.cpp index 0f725a0e6..ccf4d8628 100644 --- a/plugins/zynaddsubfx/zynaddsubfx.cpp +++ b/plugins/zynaddsubfx/ZynAddSubFx.cpp @@ -1,8 +1,8 @@ /* - * zynaddsubfx.cpp - ZynAddSubFX-embedding plugin + * ZynAddSubFx.cpp - ZynAddSubxFX-embedding plugin * * Copyright (c) 2008-2009 Tobias Doerffel - * + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -22,7 +22,6 @@ * */ - #include "lmmsconfig.h" #include @@ -32,17 +31,18 @@ #include "ResourceFileMapper.h" -#include "zynaddsubfx.h" +#include "ZynAddSubFx.h" #include "engine.h" #include "mmp.h" #include "instrument_play_handle.h" #include "InstrumentTrack.h" #include "gui_templates.h" #include "string_pair_drag.h" -#include "remote_zynaddsubfx.h" +#include "RemoteZynAddSubFx.h" +#include "LocalZynAddSubFx.h" #include "embed.cpp" -#include "moc_zynaddsubfx.cxx" +#include "moc_ZynAddSubFx.cxx" static const char * __supportedExts[] = @@ -51,7 +51,7 @@ static const char * __supportedExts[] = extern "C" { -Plugin::Descriptor PLUGIN_EXPORT zynaddsubfx_plugin_descriptor = +Plugin::Descriptor PLUGIN_EXPORT ZynAddSubFx_plugin_descriptor = { STRINGIFY( PLUGIN_NAME ), "ZynAddSubFX", @@ -69,49 +69,60 @@ Plugin::Descriptor PLUGIN_EXPORT zynaddsubfx_plugin_descriptor = -zynAddSubFx::zynAddSubFx( InstrumentTrack * _instrumentTrack ) : - Instrument( _instrumentTrack, &zynaddsubfx_plugin_descriptor ), - m_plugin( NULL ) +ZynAddSubFxInstrument::ZynAddSubFxInstrument( + InstrumentTrack * _instrumentTrack ) : + Instrument( _instrumentTrack, &ZynAddSubFx_plugin_descriptor ), + m_hasGUI( false ), + m_plugin( NULL ), + m_remotePlugin( NULL ) { - initRemotePlugin(); + initPlugin(); // now we need a play-handle which cares for calling play() InstrumentPlayHandle * iph = new InstrumentPlayHandle( this ); engine::getMixer()->addPlayHandle( iph ); connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), - this, SLOT( updateSampleRate() ) ); + this, SLOT( reloadPlugin() ) ); } -zynAddSubFx::~zynAddSubFx() +ZynAddSubFxInstrument::~ZynAddSubFxInstrument() { engine::getMixer()->removePlayHandles( instrumentTrack() ); m_pluginMutex.lock(); - delete m_plugin; + delete m_remotePlugin; m_pluginMutex.unlock(); } -void zynAddSubFx::saveSettings( QDomDocument & _doc, +void ZynAddSubFxInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) { QTemporaryFile tf; if( tf.open() ) { - m_plugin->lock(); - m_plugin->sendMessage( - RemotePlugin::message( IdSaveSettingsToFile ). - addString( - QSTR_TO_STDSTR( - QDir::toNativeSeparators( tf.fileName() ) ) ) ); - m_plugin->waitForMessage( IdSaveSettingsToFile ); - m_plugin->unlock(); + const std::string fn = QSTR_TO_STDSTR( + QDir::toNativeSeparators( tf.fileName() ) ); + m_pluginMutex.lock(); + if( m_remotePlugin ) + { + m_remotePlugin->lock(); + m_remotePlugin->sendMessage( + RemotePlugin::message( IdSaveSettingsToFile ).addString( fn ) ); + m_remotePlugin->waitForMessage( IdSaveSettingsToFile ); + m_remotePlugin->unlock(); + } + else + { + m_plugin->saveXML( fn ); + } + m_pluginMutex.unlock(); QByteArray a = tf.readAll(); // remove first blank line a.remove( 0, @@ -130,7 +141,7 @@ void zynAddSubFx::saveSettings( QDomDocument & _doc, -void zynAddSubFx::loadSettings( const QDomElement & _this ) +void ZynAddSubFxInstrument::loadSettings( const QDomElement & _this ) { if( !_this.hasChildNodes() ) { @@ -146,14 +157,24 @@ void zynAddSubFx::loadSettings( const QDomElement & _this ) QByteArray a = doc.toString( 0 ).toUtf8(); a.prepend( "\n" ); tf.write( a ); - m_plugin->lock(); - m_plugin->sendMessage( - RemotePlugin::message( IdLoadSettingsFromFile ). - addString( - QSTR_TO_STDSTR( - QDir::toNativeSeparators( tf.fileName() ) ) ) ); - m_plugin->waitForMessage( IdLoadSettingsFromFile ); - m_plugin->unlock(); + + const std::string fn = QSTR_TO_STDSTR( + QDir::toNativeSeparators( tf.fileName() ) ); + m_pluginMutex.lock(); + if( m_remotePlugin ) + { + m_remotePlugin->lock(); + m_remotePlugin->sendMessage( + RemotePlugin::message( IdLoadSettingsFromFile ). + addString( fn ) ); + m_remotePlugin->waitForMessage( IdLoadSettingsFromFile ); + m_remotePlugin->unlock(); + } + else + { + m_plugin->loadXML( fn ); + } + m_pluginMutex.unlock(); emit settingsChanged(); } @@ -162,15 +183,25 @@ void zynAddSubFx::loadSettings( const QDomElement & _this ) -void zynAddSubFx::loadResource( const ResourceItem * _item ) +void ZynAddSubFxInstrument::loadResource( const ResourceItem * _item ) { ResourceFileMapper mapper( _item ); - m_plugin->lock(); - m_plugin->sendMessage( - RemotePlugin::message( IdLoadPresetFromFile ). - addString( QSTR_TO_STDSTR( mapper.fileName() ) ) ); - m_plugin->waitForMessage( IdLoadPresetFromFile ); - m_plugin->unlock(); + const std::string fn = QSTR_TO_STDSTR( mapper.fileName() ); + if( m_remotePlugin ) + { + m_remotePlugin->lock(); + m_remotePlugin->sendMessage( + RemotePlugin::message( IdLoadPresetFromFile ). + addString( QSTR_TO_STDSTR( mapper.fileName() ) ) ); + m_remotePlugin->waitForMessage( IdLoadPresetFromFile ); + m_remotePlugin->unlock(); + } + else + { + m_pluginMutex.lock(); + m_plugin->loadPreset( fn ); + m_pluginMutex.unlock(); + } emit settingsChanged(); } @@ -178,18 +209,25 @@ void zynAddSubFx::loadResource( const ResourceItem * _item ) -QString zynAddSubFx::nodeName() const +QString ZynAddSubFxInstrument::nodeName() const { - return zynaddsubfx_plugin_descriptor.name; + return ZynAddSubFx_plugin_descriptor.name; } -void zynAddSubFx::play( sampleFrame * _buf ) +void ZynAddSubFxInstrument::play( sampleFrame * _buf ) { m_pluginMutex.lock(); - m_plugin->process( NULL, _buf ); + if( m_remotePlugin ) + { + m_remotePlugin->process( NULL, _buf ); + } + else + { + m_plugin->processAudio( _buf ); + } m_pluginMutex.unlock(); instrumentTrack()->processAudioBuffer( _buf, engine::getMixer()->framesPerPeriod(), NULL ); @@ -198,11 +236,18 @@ void zynAddSubFx::play( sampleFrame * _buf ) -bool zynAddSubFx::handleMidiEvent( const midiEvent & _me, +bool ZynAddSubFxInstrument::handleMidiEvent( const midiEvent & _me, const midiTime & _time ) { m_pluginMutex.lock(); - m_plugin->processMidiEvent( _me, 0 ); + if( m_remotePlugin ) + { + m_remotePlugin->processMidiEvent( _me, 0 ); + } + else + { + m_plugin->processMidiEvent( _me ); + } m_pluginMutex.unlock(); return true; @@ -211,43 +256,58 @@ bool zynAddSubFx::handleMidiEvent( const midiEvent & _me, -void zynAddSubFx::updateSampleRate() +void ZynAddSubFxInstrument::reloadPlugin() { - m_pluginMutex.lock(); - + // save state of current plugin instance multimediaProject m( multimediaProject::InstrumentTrackSettings ); saveSettings( m, m.content() ); - initRemotePlugin(); + // init plugin (will delete current one and create a new instance) + initPlugin(); + // and load the settings again loadSettings( m.content() ); +} + + + +void ZynAddSubFxInstrument::initPlugin() +{ + m_pluginMutex.lock(); + delete m_plugin; + delete m_remotePlugin; + m_plugin = NULL; + m_remotePlugin = NULL; + + if( m_hasGUI ) + { + m_remotePlugin = new RemotePlugin( "RemoteZynAddSubFx", false ); + m_remotePlugin->lock(); + m_remotePlugin->waitForInitDone( false ); + + m_remotePlugin->sendMessage( + RemotePlugin::message( IdZasfPresetDirectory ). + addString( + QSTR_TO_STDSTR( + QString( configManager::inst()->factoryPresetsDir() + + QDir::separator() + "ZynAddSubFX" ) ) ) ); + m_remotePlugin->showUI(); + m_remotePlugin->unlock(); + } + else + { + m_plugin = new LocalZynAddSubFx; + m_plugin->setSampleRate( engine::getMixer()->processingSampleRate() ); + m_plugin->setBufferSize( engine::getMixer()->framesPerPeriod() ); + } m_pluginMutex.unlock(); } -void zynAddSubFx::initRemotePlugin() -{ - delete m_plugin; - m_plugin = new RemotePlugin( "remote_zynaddsubfx", false ); - m_plugin->lock(); - m_plugin->waitForInitDone( false ); - - m_plugin->sendMessage( - RemotePlugin::message( IdZasfPresetDirectory ). - addString( - QSTR_TO_STDSTR( - QString( configManager::inst()->factoryPresetsDir() + - QDir::separator() + "ZynAddSubFX" ) ) ) ); - m_plugin->unlock(); -} - - - - -PluginView * zynAddSubFx::instantiateView( QWidget * _parent ) +PluginView * ZynAddSubFxInstrument::instantiateView( QWidget * _parent ) { return new ZynAddSubFxView( this, _parent ); } @@ -300,15 +360,9 @@ void ZynAddSubFxView::modelChanged() void ZynAddSubFxView::toggleUI() { - if( m_toggleUIButton->isChecked() ) - { - castModel()->m_plugin->showUI(); - } - else - { - castModel()->m_plugin->hideUI(); - } - + ZynAddSubFxInstrument * model = castModel(); + model->m_hasGUI = m_toggleUIButton->isChecked(); + model->reloadPlugin(); } @@ -322,7 +376,7 @@ extern "C" Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data ) { - return new zynAddSubFx( static_cast( _data ) ); + return new ZynAddSubFxInstrument( static_cast( _data ) ); } diff --git a/plugins/zynaddsubfx/zynaddsubfx.h b/plugins/zynaddsubfx/ZynAddSubFx.h similarity index 86% rename from plugins/zynaddsubfx/zynaddsubfx.h rename to plugins/zynaddsubfx/ZynAddSubFx.h index e84c3bed5..3f2d91549 100644 --- a/plugins/zynaddsubfx/zynaddsubfx.h +++ b/plugins/zynaddsubfx/ZynAddSubFx.h @@ -1,5 +1,5 @@ /* - * zynaddsubfx.h - ZynAddSubFX-embedding plugin + * ZynAddSubFx.h - ZynAddSubFX-embedding plugin * * Copyright (c) 2008-2009 Tobias Doerffel * @@ -22,12 +22,10 @@ * */ - #ifndef _ZYNADDSUBFX_H #define _ZYNADDSUBFX_H #include -#include #include "Instrument.h" #include "InstrumentView.h" @@ -36,16 +34,17 @@ class QPushButton; +class LocalZynAddSubFx; class ZynAddSubFxView; class notePlayHandle; -class zynAddSubFx : public Instrument +class ZynAddSubFxInstrument : public Instrument { Q_OBJECT public: - zynAddSubFx( InstrumentTrack * _instrument_track ); - virtual ~zynAddSubFx(); + ZynAddSubFxInstrument( InstrumentTrack * _instrument_track ); + virtual ~ZynAddSubFxInstrument(); virtual void play( sampleFrame * _working_buffer ); @@ -69,15 +68,16 @@ public: private slots: - void updateSampleRate(); + void reloadPlugin(); private: - void initRemotePlugin(); + void initPlugin(); + bool m_hasGUI; QMutex m_pluginMutex; - RemotePlugin * m_plugin; - + LocalZynAddSubFx * m_plugin; + RemotePlugin * m_remotePlugin; friend class ZynAddSubFxView;