diff options
| author | Tim E. Real <termtech@rogers.com> | 2010-11-01 08:36:22 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2010-11-01 08:36:22 +0000 | 
| commit | bf32fe9882d7dd1dd6fbb88f39a42371063b6cd6 (patch) | |
| tree | 57ce439a666b14632a186d859fd357134e6c414b /muse2 | |
| parent | 4f767f96be2382c3f73a9619097a8cbabe3f7587 (diff) | |
All MESS plugins: compile with -fvisibility=hidden, fixes LADSPA plugins not appearing in list.
Added simpledrums2 (from muse_qt4_evolution).
Diffstat (limited to 'muse2')
36 files changed, 4805 insertions, 15 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 632b022e..378faa9f 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,9 @@ +01.11.2010 +        - Fixed all MESS plugins: compile with -fvisibility=hidden, to avoid namespace conflicts. +          In particular, simplesynth was causing conflict with variable 'plugins' causing it to  +           be overwritten.  +        - So, this fixes LADSPA plugins not appearing in plugin list. +        - Added simpledrums from muse_qt4_evolution, is called 'simpledrums2' and replaces the original.  31.10.2010          - Fixed Toolbar1 class. 'Snap', 'Quantize' combo boxes should work now. Thanks to Luis G. for help. (Tim)  30.10.2010 diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index e07b6c6e..f9087051 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -1395,7 +1395,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow()              }        initMidiSynth(); - +              populateAddTrack(addTrack);        transport = new Transport(this, "transport"); @@ -3460,6 +3460,7 @@ int main(int argc, char* argv[])        initMetronome();        //QApplication::clipboard()->setSelectionMode(false); ddskrjo +              QApplication::addLibraryPath(museGlobalLib + "/qtplugins");        if (debugMsg) {              QStringList list = app.libraryPaths(); @@ -3474,6 +3475,7 @@ int main(int argc, char* argv[])        muse = new MusE(argc, &argv[optind]);        app.setMuse(muse);        muse->setIcon(*museIcon); +              // Added by Tim. p3.3.22        if (!debugMode) {              if (mlockall(MCL_CURRENT | MCL_FUTURE)) diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 9bcf11bf..61e49401 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -972,6 +972,9 @@ static void loadPluginLib(QFileInfo* fi)          //LADSPA_Properties properties = descr->LADSPA_Plugin->Properties;          //bool inPlaceBroken = LADSPA_IS_INPLACE_BROKEN(properties);          //plugins.add(fi, descr, !inPlaceBroken); +        if(debugMsg) +          fprintf(stderr, "loadPluginLib: adding dssi effect plugin:%s name:%s label:%s\n", fi->filePath().latin1(), descr->LADSPA_Plugin->Name, descr->LADSPA_Plugin->Label); +                plugins.add(fi, descr->LADSPA_Plugin, true);        }      }       @@ -1014,6 +1017,8 @@ static void loadPluginLib(QFileInfo* fi)        //LADSPA_Properties properties = descr->Properties;        //bool inPlaceBroken = LADSPA_IS_INPLACE_BROKEN(properties);        //plugins.add(fi, ladspa, descr, !inPlaceBroken); +      if(debugMsg) +        fprintf(stderr, "loadPluginLib: adding ladspa plugin:%s name:%s label:%s\n", fi->filePath().latin1(), descr->Name, descr->Label);        plugins.add(fi, descr);      }    }   @@ -1082,7 +1087,7 @@ void initPlugins()        p = ladspaPath;        if(debugMsg) -        fprintf(stderr, "loadPluginLib: ladspa path:%s\n", ladspaPath); +        fprintf(stderr, "loadPluginDir: ladspa path:%s\n", ladspaPath);        while (*p != '\0') {              const char* pe = p; @@ -1095,7 +1100,7 @@ void initPlugins()                    strncpy(buffer, p, n);                    buffer[n] = '\0';                    if(debugMsg) -                    fprintf(stderr, "loadPluginLib: loading ladspa dir:%s\n", buffer); +                    fprintf(stderr, "loadPluginDir: loading ladspa dir:%s\n", buffer);                    loadPluginDir(QString(buffer));                    delete[] buffer; diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index 4d377fb4..74a27290 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -36,6 +36,9 @@  #include "midictrl.h"  //#include "stringparam.h" +// REMOVE Tim. +#include "plugin.h" +  std::vector<Synth*> synthis;  // array of available synthis  extern void connectNodes(AudioTrack*, AudioTrack*); @@ -509,6 +512,8 @@ void initMidiSynth()                    const char* path = fi->filePath().latin1();                    // load Synti dll +                  //printf("initMidiSynth: dlopen file:%s name:%s desc:%s\n", fi->filePath().latin1(), QString(descr->name), QString(descr->description), QString(""), QString(descr->version))); +                  printf("initMidiSynth: dlopen file:%s\n", fi->filePath().latin1());                    void* handle = dlopen(path, RTLD_NOW);                    if (handle == 0) {                          fprintf(stderr, "initMidiSynth: MESS dlopen(%s) failed: %s\n", path, dlerror()); diff --git a/muse2/synti/CMakeLists.txt b/muse2/synti/CMakeLists.txt index b2bc87ea..1a7fd322 100644 --- a/muse2/synti/CMakeLists.txt +++ b/muse2/synti/CMakeLists.txt @@ -28,7 +28,8 @@ include_directories(     )  # set (SubDirs libsynti s1 organ deicsonze deicsonze2 simpledrums vam) -set (SubDirs libsynti s1 organ deicsonze simpledrums vam) +# set (SubDirs libsynti s1 organ deicsonze simpledrums vam) +set (SubDirs libsynti s1 organ deicsonze simpledrums2 vam)  if (HAVE_FLUIDSYNTH)        set (SubDirs ${SubDirs} fluid fluidsynth ) diff --git a/muse2/synti/deicsonze/CMakeLists.txt b/muse2/synti/deicsonze/CMakeLists.txt index a39b0e14..c9da5854 100644 --- a/muse2/synti/deicsonze/CMakeLists.txt +++ b/muse2/synti/deicsonze/CMakeLists.txt @@ -47,7 +47,7 @@ add_library ( deicsonze SHARED  set_target_properties ( deicsonze     PROPERTIES PREFIX ""     #COMPILE_FLAGS "-O2 -include ${PROJECT_BINARY_DIR}/all-pic.h" -   COMPILE_FLAGS "-DINSTPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -DINSTPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -include ${PROJECT_BINARY_DIR}/all-pic.h"     )  target_link_libraries(deicsonze diff --git a/muse2/synti/deicsonze/deicsonze.cpp b/muse2/synti/deicsonze/deicsonze.cpp index 3dc5fafd..4eea4102 100644 --- a/muse2/synti/deicsonze/deicsonze.cpp +++ b/muse2/synti/deicsonze/deicsonze.cpp @@ -1660,7 +1660,12 @@ extern "C" {  	MESS_MAJOR_VERSION, MESS_MINOR_VERSION,  	instantiate      }; +    // We must compile with -fvisibility=hidden to avoid namespace +    // conflicts with global variables. +    // Only visible symbol is "mess_descriptor". +    // (TODO: all plugins should be compiled this way) +    __attribute__ ((visibility("default")))      const MESS* mess_descriptor() { return &descriptor; }  } diff --git a/muse2/synti/deicsonze2/CMakeLists.txt b/muse2/synti/deicsonze2/CMakeLists.txt index 430953ca..12f88212 100644 --- a/muse2/synti/deicsonze2/CMakeLists.txt +++ b/muse2/synti/deicsonze2/CMakeLists.txt @@ -46,7 +46,7 @@ target_link_libraries( deicsonze synti )  set_target_properties ( deicsonze     PROPERTIES PREFIX ""     #COMPILE_FLAGS "-O2 -include ${PROJECT_BINARY_DIR}/all-pic.h" -   COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h"     )  target_link_libraries(deicsonze diff --git a/muse2/synti/deicsonze2/deicsonze.cpp b/muse2/synti/deicsonze2/deicsonze.cpp index 28b9183e..74c1f56e 100644 --- a/muse2/synti/deicsonze2/deicsonze.cpp +++ b/muse2/synti/deicsonze2/deicsonze.cpp @@ -4350,7 +4350,12 @@ extern "C" {  	MESS_MAJOR_VERSION, MESS_MINOR_VERSION,  	instantiate      }; +    // We must compile with -fvisibility=hidden to avoid namespace +    // conflicts with global variables. +    // Only visible symbol is "mess_descriptor". +    // (TODO: all plugins should be compiled this way) +    __attribute__ ((visibility("default")))      const MESS* mess_descriptor() { return &descriptor; }  } diff --git a/muse2/synti/fluid/CMakeLists.txt b/muse2/synti/fluid/CMakeLists.txt index 38184550..0007537f 100644 --- a/muse2/synti/fluid/CMakeLists.txt +++ b/muse2/synti/fluid/CMakeLists.txt @@ -38,7 +38,7 @@ add_library ( fluid SHARED  #  set_target_properties ( fluid     PROPERTIES PREFIX "" -   COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h"     LINK_FLAGS "${FLUIDSYN_LDFLAGS}"   # "-lfluidsynth"     )  target_link_libraries(fluid diff --git a/muse2/synti/fluid/fluid.cpp b/muse2/synti/fluid/fluid.cpp index a03be4de..13cfbef3 100644 --- a/muse2/synti/fluid/fluid.cpp +++ b/muse2/synti/fluid/fluid.cpp @@ -61,6 +61,12 @@ extern "C" {              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate,              }; +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) +   +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        } diff --git a/muse2/synti/fluidsynth/CMakeLists.txt b/muse2/synti/fluidsynth/CMakeLists.txt index cdb298e2..0c3e1b97 100644 --- a/muse2/synti/fluidsynth/CMakeLists.txt +++ b/muse2/synti/fluidsynth/CMakeLists.txt @@ -38,7 +38,7 @@ add_library ( fluidsynth SHARED  #  set_target_properties ( fluidsynth      PROPERTIES PREFIX "" -   COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h"     LINK_FLAGS "${FLUIDSYN_LDFLAGS}"   # "-lfluidsynth"     ) diff --git a/muse2/synti/fluidsynth/fluidsynti.cpp b/muse2/synti/fluidsynth/fluidsynti.cpp index bf27a61c..bf12b7f8 100644 --- a/muse2/synti/fluidsynth/fluidsynti.cpp +++ b/muse2/synti/fluidsynth/fluidsynti.cpp @@ -1310,6 +1310,12 @@ extern "C"              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate,              }; +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) +   +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        } diff --git a/muse2/synti/organ/CMakeLists.txt b/muse2/synti/organ/CMakeLists.txt index 8dd67aa8..40db20c1 100644 --- a/muse2/synti/organ/CMakeLists.txt +++ b/muse2/synti/organ/CMakeLists.txt @@ -40,7 +40,7 @@ add_library ( organ SHARED  #  set_target_properties ( organ     PROPERTIES PREFIX "" -   COMPILE_FLAGS "-O2 -include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -O2 -include ${PROJECT_BINARY_DIR}/all-pic.h"     )  target_link_libraries(organ diff --git a/muse2/synti/organ/organ.cpp b/muse2/synti/organ/organ.cpp index a1788a6c..2dede8de 100644 --- a/muse2/synti/organ/organ.cpp +++ b/muse2/synti/organ/organ.cpp @@ -704,7 +704,12 @@ extern "C" {              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate,              }; - +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) +   +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        } diff --git a/muse2/synti/s1/CMakeLists.txt b/muse2/synti/s1/CMakeLists.txt index 890c6b12..7dffe905 100644 --- a/muse2/synti/s1/CMakeLists.txt +++ b/muse2/synti/s1/CMakeLists.txt @@ -25,7 +25,10 @@ add_library ( s1 SHARED s1.cpp )  # tell cmake to name target s1.so instead of   # libs1.so  # -set_target_properties ( s1 PROPERTIES PREFIX "" ) +set_target_properties ( s1  +  PROPERTIES PREFIX ""  +  COMPILE_FLAGS "-fvisibility=hidden" +  )  target_link_libraries(s1        synti diff --git a/muse2/synti/s1/s1.cpp b/muse2/synti/s1/s1.cpp index c73615bd..8520a742 100644 --- a/muse2/synti/s1/s1.cpp +++ b/muse2/synti/s1/s1.cpp @@ -221,7 +221,12 @@ extern "C" {              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate              }; - +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) +   +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        } diff --git a/muse2/synti/simpledrums/CMakeLists.txt b/muse2/synti/simpledrums/CMakeLists.txt index 696389c6..6b015f2b 100644 --- a/muse2/synti/simpledrums/CMakeLists.txt +++ b/muse2/synti/simpledrums/CMakeLists.txt @@ -40,7 +40,7 @@ add_library ( simpledrums SHARED  #  set_target_properties ( simpledrums     PROPERTIES PREFIX "" -   COMPILE_FLAGS "-O6 -include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-O6 -fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h"     )  target_link_libraries(simpledrums diff --git a/muse2/synti/simpledrums/simpledrums.cpp b/muse2/synti/simpledrums/simpledrums.cpp index 5a0431a0..8bca91a4 100644 --- a/muse2/synti/simpledrums/simpledrums.cpp +++ b/muse2/synti/simpledrums/simpledrums.cpp @@ -1531,6 +1531,12 @@ extern "C"              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate,              }; +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) + +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        } diff --git a/muse2/synti/simpledrums2/CMakeLists.txt b/muse2/synti/simpledrums2/CMakeLists.txt new file mode 100644 index 00000000..3c7ba3c7 --- /dev/null +++ b/muse2/synti/simpledrums2/CMakeLists.txt @@ -0,0 +1,52 @@ +#============================================================================= +#  MusE +#  Linux Music Editor +#  $Id:$ +# +#  Copyright (C) 2002-2006 by Werner Schweer and others +# +#  This program is free software; you can redistribute it and/or modify +#  it under the terms of the GNU General Public License version 2. +# +#  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; if not, write to the Free Software +#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#============================================================================= + +QT4_WRAP_CPP ( simpledrums_mocs simpledrumsgui.h ssplugingui.h ) +QT4_WRAP_UI (  simpledrums_uis simpledrumsguibase.ui sspluginchooserbase.ui ) + +add_library ( simpledrums SHARED +      simpledrums.cpp +      simpledrumsgui.cpp +      simpledrums.h +      ssplugin.cpp +      ssplugingui.cpp +      ssplugin.h +      common.h +      ${simpledrums_mocs} +      ${simpledrums_uis} +      ) + +# - tell cmake to name target simpledrums.so instead of +#   libsimpledrums.so +# - use precompiled header files +# +set_target_properties ( simpledrums +   PROPERTIES PREFIX "" +   COMPILE_FLAGS "-O6 -fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h" +   ) + +target_link_libraries(simpledrums +      synti +#      awl +      ${QT_LIBRARIES} +      ) + +install_targets ( /${CMAKE_INSTALL_LIBDIR}/${MusE_INSTALL_NAME}/synthi/ simpledrums ) + diff --git a/muse2/synti/simpledrums2/COPYING b/muse2/synti/simpledrums2/COPYING new file mode 100644 index 00000000..5c3cefc2 --- /dev/null +++ b/muse2/synti/simpledrums2/COPYING @@ -0,0 +1,3 @@ +COPYING +--------------------------------------- +This software is licensed under GNU GPL. diff --git a/muse2/synti/simpledrums2/README b/muse2/synti/simpledrums2/README new file mode 100644 index 00000000..468640b1 --- /dev/null +++ b/muse2/synti/simpledrums2/README @@ -0,0 +1,43 @@ +-------------------------------------- +Simpledrums v 0.2, by Mathias Lundgren +-------------------------------------- + +Simpledrums is a simple MESS-synth sampler (MusE Experimental Soft +Synth) aiming at becoming a simple, tightly integrated sampler for +MusE, specifically aimed at drumsamples. + +Features: +- 16 channels/samples (1 sample/channel) +- Simple controls for each individual channel: volume, balance, noteoff-ignore, channel on/off +- Main volume +- 4 LADSPA send-effects can be used, 4 effect taps for each individual channel +- All channel parameters are controllable via the GUI, or by MusE:s controller handling (controller pane in pianoroll/drumeditor) +- All effect parameters can be controlled via the GUI, or by Sysex messages (f.ex. turn effect on/off, modify effect parameters) +- Complete synth state (fx-parameters, samples etc) is saved together with MusE project, and restored later when loaded +- Samples automatically resampled when loaded (if needed) + +That's all folks! + +------------- +Known issues: +------------- +- Not the prettiest gui in the world +- All samples are read directly into memory (no caching) +- Some obscure LADSPA-effects make SimpleSynth segfault +- More... + +------------- +Future plans: +------------- +- Fix all the known issues! ;-) +- Sample loops +- Sample offset variation w respect to note velocity +- Treble/eq-controller for each individual channel +- Treble level variation w respect to note velocity +- More... + +Mathias Lundgren, (lunar_shuttle@users.sourceforge.net), 2004 +Plugin management code based on Werner Schweers plugin management handling for MusE + +(C) Copyright Mathias Lundgren, Werner Schweer 2000-2004 +Licensed under the GNU General Public License diff --git a/muse2/synti/simpledrums2/ReleaseNotes.txt b/muse2/synti/simpledrums2/ReleaseNotes.txt new file mode 100644 index 00000000..e0d633d8 --- /dev/null +++ b/muse2/synti/simpledrums2/ReleaseNotes.txt @@ -0,0 +1,18 @@ +RELEASE NOTES: +-------------- +????-??-?? ver 0.2 +- Support for 4 LADSPA sendeffects added +- Resampling of samples when loading (libsamplerate) +- Synth state is saved to/restored from project file +- Channel settings: balance, volume, effect tap for each sendeffect +- Effect settings: all LADSPA parameters controllable and saved to MusE project, effect master volume, effect on/off +- Support for mono + stereo samples +- Support for stereo + mono LADSPA effects +- Bugfixes, GUI-improvements etc... + +2004-11-09 ver 0.1 +- Simpledrums initial release +- 16 channels (1 sample for each channel) with parameters: volume, balance, noteoff-ignore + +(C) Copyright Mathias Lundgren, Werner Schweer 2000-2004 +Licensed under the GNU General Public License diff --git a/muse2/synti/simpledrums2/common.h b/muse2/synti/simpledrums2/common.h new file mode 100644 index 00000000..e4763540 --- /dev/null +++ b/muse2/synti/simpledrums2/common.h @@ -0,0 +1,110 @@ +// +// C++ Interface: common +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef __MUSE_TESTO_COMMON_H__ +#define __MUSE_TESTO_COMMON_H__ + +#include "muse/midictrl.h" + +#define SS_VERSIONSTRING "1.0" + +#define SS_DEBUG        0 +#define SS_DEBUG_INIT   0 +#define SS_TRACE_FUNC   0 +#define SS_DEBUG_MIDI   0 +#define SS_DEBUG_LADSPA 0 +#define SS_DEBUG_STATE  0 + +#define SS_DBG(string) if (SS_DEBUG) fprintf(stderr, "%s:%d:%s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string); +#define SS_DBG2(string1, string2) if (SS_DEBUG) fprintf(stderr, "%s:%d:%s: %s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1, string2); +#define SS_DBG_I(string1, int) if (SS_DEBUG) fprintf(stderr, "%s:%d:%s: %s: %d\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1, int); + +#define SS_TRACE_IN if (SS_TRACE_FUNC) fprintf (stderr, "->%s:%d\n", __PRETTY_FUNCTION__, __LINE__); +#define SS_TRACE_OUT if (SS_TRACE_FUNC) fprintf (stderr, "<-%s:%d\n", __PRETTY_FUNCTION__, __LINE__); +#define SS_ERROR(string) fprintf(stderr, "SimpleDrums error: %s\n", string) +#define SS_DBG_LADSPA(string1) if (SS_DEBUG_LADSPA) fprintf(stderr, "%s:%d:%s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1); +#define SS_DBG_LADSPA2(string1, string2) if (SS_DEBUG_LADSPA) fprintf(stderr, "%s:%d:%s: %s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1, string2); + +#define SS_SYSEX_INIT_DATA_VERSION           1 + +#define SS_NR_OF_CHANNELS                   16 +#define SS_AUDIO_CHANNELS                    2 +#define SS_NR_OF_SENDEFFECTS                 4 + +// Controller-related: +#define SS_CHANNEL_CTRL_VOLUME 0 +#define SS_CHANNEL_CTRL_PAN    1 +#define SS_CHANNEL_CTRL_NOFF   2 +#define SS_CHANNEL_CTRL_ONOFF  3 +#define SS_CHANNEL_SENDFX1     4 +#define SS_CHANNEL_SENDFX2     5 +#define SS_CHANNEL_SENDFX3     6 +#define SS_CHANNEL_SENDFX4     7 + +#define SS_PLUGIN_RETURN       0 +#define SS_PLUGIN_ONOFF        1 + +#define SS_NR_OF_MASTER_CONTROLLERS          1 +#define SS_NR_OF_CHANNEL_CONTROLLERS         8 +#define SS_NR_OF_PLUGIN_CONTROLLERS          2 + +#define SS_NR_OF_CONTROLLERS                 (SS_NR_OF_MASTER_CONTROLLERS + (SS_NR_OF_CHANNELS * SS_NR_OF_CHANNEL_CONTROLLERS) + (SS_NR_OF_PLUGIN_CONTROLLERS*SS_NR_OF_SENDEFFECTS)) +#define SS_FIRST_MASTER_CONTROLLER           CTRL_NRPN14_OFFSET +#define SS_FIRST_CHANNEL_CONTROLLER          (SS_FIRST_MASTER_CONTROLLER + SS_NR_OF_MASTER_CONTROLLERS) +#define SS_LAST_MASTER_CONTROLLER            (SS_FIRST_CHANNEL_CONTROLLER - 1) +#define SS_LAST_CHANNEL_CONTROLLER           (SS_FIRST_CHANNEL_CONTROLLER -1 + (SS_NR_OF_CHANNEL_CONTROLLERS * SS_NR_OF_CHANNELS)) + +#define SS_FIRST_PLUGIN_CONTROLLER           (SS_LAST_CHANNEL_CONTROLLER + 1) +#define SS_LAST_PLUGIN_CONTROLLER            (SS_FIRST_PLUGIN_CONTROLLER -1 + SS_NR_OF_SENDEFFECTS*SS_NR_OF_PLUGIN_CONTROLLERS) + +#define SS_MASTER_CTRL_VOLUME                SS_FIRST_MASTER_CONTROLLER + +#define SS_CHANNEL_VOLUME_CONTROLLER(int)    (SS_FIRST_CHANNEL_CONTROLLER + (SS_NR_OF_CHANNEL_CONTROLLERS * int) + SS_CHANNEL_CTRL_VOLUME) +#define SS_CHANNEL_PAN_CONTROLLER(int)       (SS_FIRST_CHANNEL_CONTROLLER + (SS_NR_OF_CHANNEL_CONTROLLERS * int) + SS_CHANNEL_CTRL_PAN) +#define SS_CHANNEL_NOFF_CONTROLLER(int)      (SS_FIRST_CHANNEL_CONTROLLER + (SS_NR_OF_CHANNEL_CONTROLLERS * int) + SS_CHANNEL_CTRL_NOFF) +#define SS_CHANNEL_ONOFF_CONTROLLER(int)     (SS_FIRST_CHANNEL_CONTROLLER + (SS_NR_OF_CHANNEL_CONTROLLERS * int) + SS_CHANNEL_CTRL_ONOFF) +#define SS_CHANNEL_SENDFX_CONTROLLER(int1,int2) (SS_FIRST_CHANNEL_CONTROLLER + (SS_NR_OF_CHANNEL_CONTROLLERS * int1) + SS_CHANNEL_SENDFX1 + int2) + +#define SS_PLUGIN_RETURNLEVEL_CONTROLLER(int) (SS_FIRST_PLUGIN_CONTROLLER + (int * SS_NR_OF_PLUGIN_CONTROLLERS)) +#define SS_PLUGIN_ONOFF_CONTROLLER(int) (SS_FIRST_PLUGIN_CONTROLLER + (int * SS_NR_OF_PLUGIN_CONTROLLERS) + 1) + +#define SS_LOWEST_NOTE                       36 +#define SS_HIGHEST_NOTE                      (SS_LOWEST_NOTE + SS_NR_OF_CHANNELS) + +#define SS_PLUGIN_PARAM_MIN                  0 +#define SS_PLUGIN_PARAM_MAX                127 + +typedef unsigned char byte; + +enum { +      SS_SYSEX_LOAD_SAMPLE = 0,   // gui -> synth: tell synth to load sample +      SS_SYSEX_INIT_DATA,         // synth reinitialization, the position of this (1) in the enum must not be changed since this value is written into proj file +      SS_SYSEX_LOAD_SAMPLE_OK,    // synth -> gui: tell gui sample loaded OK +      SS_SYSEX_LOAD_SAMPLE_ERROR, // synth -> gui: tell gui sample ! loaded OK +      SS_SYSEX_CLEAR_SAMPLE,       // gui -> synth: tell synth to clear sample +      SS_SYSEX_CLEAR_SAMPLE_OK,    // synth->gui: confirm sample cleared OK +      SS_SYSEX_LOAD_SENDEFFECT,   // gui -> synth: tell synth to load laspa-effect +      SS_SYSEX_LOAD_SENDEFFECT_OK,// synth->gui: plugin loaded ok +      SS_SYSEX_LOAD_SENDEFFECT_ERROR, // synth->gui: plugin _not_ loaded ok +      SS_SYSEX_CLEAR_SENDEFFECT,  // gui->synth: clear plugin +      SS_SYSEX_CLEAR_SENDEFFECT_OK,// synth->gui: plugin cleared +      SS_SYSEX_SET_PLUGIN_PARAMETER, //gui->synth: set plugin parameter +      SS_SYSEX_SET_PLUGIN_PARAMETER_OK, // synth->gui: set plugin parameter (update gui) +      SS_SYSEX_ERRORMSG,           // synth -> gui: general error message from synth +      SS_SYSEX_GET_INIT_DATA,      // gui->synth: request init data +      SS_SYSEX_SEND_INIT_DATA      // synth->gui: give gui init data +      }; + +extern int SS_samplerate; +extern float SS_map_pluginparam2logdomain(int pluginparam_val); +extern int SS_map_logdomain2pluginparam(float pluginparam_log); +#endif + diff --git a/muse2/synti/simpledrums2/simpledrums.cpp b/muse2/synti/simpledrums2/simpledrums.cpp new file mode 100644 index 00000000..242fd8dd --- /dev/null +++ b/muse2/synti/simpledrums2/simpledrums.cpp @@ -0,0 +1,1726 @@ +// +// C++ Implementation: simplesynth +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "muse/midictrl.h" +#include "muse/midi.h" +#include "libsynti/mpevent.h" +#include "simpledrums.h" +// #include <qstring.h> +#include <samplerate.h> + +const char* SimpleSynth::synth_state_descr[] = +      { +      "SS_INITIALIZING", +      "SS_LOADING_SAMPLE", +      "SS_CLEARING_SAMPLE", +      "SS_RUNNING" +      }; + +const char* SimpleSynth::channel_state_descr[] = +      { +      "SS_CHANNEL_INACTIVE", +      "SS_SAMPLE_PLAYING" +      }; + +#define SWITCH_SYNTH_STATE(state)\ +synth_state = state; \ +if (SS_DEBUG_STATE) \ +      fprintf (stderr, "SS STATE: %s\n", SimpleSynth::synth_state_descr[state]); + +#define SWITCH_CHAN_STATE(ch, s)\ +channels[ch].state = s; \ +if (SS_DEBUG_STATE) \ +      fprintf (stderr, "SS CHAN %d STATE: %s\n", ch, SimpleSynth::channel_state_descr[s]); + +#define SS_CHANNEL_VOLUME_QUOT 100.0 +#define SS_MASTER_VOLUME_QUOT  100.0 +int SS_samplerate; + +#define SS_LOG_MAX   0 +#define SS_LOG_MIN -10 +#define SS_LOG_OFFSET SS_LOG_MIN + + +// +// Map plugin parameter on domain [SS_PLUGIN_PARAM_MIN, SS_PLUGIN_PARAM_MAX] to domain [SS_LOG_MIN, SS_LOG_MAX] (log domain) +// +float SS_map_pluginparam2logdomain(int pluginparam_val) +      { +      float scale = (float) (SS_LOG_MAX - SS_LOG_MIN)/ (float) SS_PLUGIN_PARAM_MAX; +      float scaled = (float) pluginparam_val * scale; +      float mapped = scaled + SS_LOG_OFFSET; +      return mapped; +      } +// +// Map plugin parameter on domain to domain [SS_LOG_MIN, SS_LOG_MAX] to [SS_PLUGIN_PARAM_MIN, SS_PLUGIN_PARAM_MAX]  (from log-> [0,127]) +// (inverse func to the above) +int SS_map_logdomain2pluginparam(float pluginparam_log) +      { +      float mapped = pluginparam_log - SS_LOG_OFFSET; +      float scale = (float) SS_PLUGIN_PARAM_MAX / (float) (SS_LOG_MAX - SS_LOG_MIN); +      int scaled  = (int) round(mapped * scale); +      return scaled; +      } + +//--------------------------------------------------------- +//   SimpleSynth +//--------------------------------------------------------- +SimpleSynth::SimpleSynth(int sr) +      : Mess(SS_AUDIO_CHANNELS) +      { +      SS_TRACE_IN +      SS_samplerate = sr; +      SS_initPlugins(); + +      simplesynth_ptr = this; +      master_vol = 100.0 / SS_MASTER_VOLUME_QUOT; +      master_vol_ctrlval = 100; + +      //initialize +      for (int i=0; i<SS_NR_OF_CHANNELS; i++) { +            channels[i].sample = 0; +            channels[i].playoffset = 0; +            channels[i].noteoff_ignore = false; +            channels[i].volume = (double) (100.0/SS_CHANNEL_VOLUME_QUOT ); +            channels[i].volume_ctrlval = 100; +            channels[i].pan = 64; +            channels[i].balanceFactorL = 1.0; +            channels[i].balanceFactorR = 1.0; +            SWITCH_CHAN_STATE(i, SS_CHANNEL_INACTIVE); +            channels[i].channel_on = false; +            for (int j=0; j<SS_NR_OF_SENDEFFECTS; j++) { +                  channels[i].sendfxlevel[j] = 0.0; +                  } +            } + +      //Process buffer: +      processBuffer[0] = new double[SS_PROCESS_BUFFER_SIZE]; //left +      processBuffer[1] = new double[SS_PROCESS_BUFFER_SIZE]; //right + +      //Send effects +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            sendFxLineOut[i][0] = new float[SS_SENDFX_BUFFER_SIZE]; //left out +            sendFxLineOut[i][1] = new float[SS_SENDFX_BUFFER_SIZE]; //right out +            sendFxReturn[i][0]  = new float[SS_SENDFX_BUFFER_SIZE]; //left in +            sendFxReturn[i][1]  = new float[SS_SENDFX_BUFFER_SIZE]; //right in +            } + +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            sendEffects[i].state       = SS_SENDFX_OFF; +            sendEffects[i].plugin      = 0; +            sendEffects[i].retgain     = 1.0; +            sendEffects[i].retgain_ctrlval = 100; +            sendEffects[i].nrofparameters = 0; +            } + +      //Build controller list: +      controllers[0].name = "Master volume"; +      controllers[0].num  = CTRL_NRPN14_OFFSET; +      controllers[0].min  = 0; +      controllers[0].max  = 127; + +      int i=1; +      for (int ch=0; ch<SS_NR_OF_CHANNELS; ch++) { +            QString c1 = "Channel " + QString::number(ch + 1) + " volume"; +            QString c2 = "Channel " + QString::number(ch + 1) + " pan"; +            QString c3 = "Channel " + QString::number(ch + 1) + " noteoff ignore"; +            QString c4 = "Channel " + QString::number(ch + 1) + " on/off"; +            QString c5 = "Channel " + QString::number(ch + 1) + " fx send 1"; +            QString c6 = "Channel " + QString::number(ch + 1) + " fx send 2"; +            QString c7 = "Channel " + QString::number(ch + 1) + " fx send 3"; +            QString c8 = "Channel " + QString::number(ch + 1) + " fx send 4"; +            controllers[i].name = c1.toLatin1().data(); +            controllers[i].num  = CTRL_NRPN14_OFFSET+i; +            controllers[i].min  = 0; +            controllers[i].max  = 127; + +            controllers[i+1].name = c2.toLatin1().data(); +            controllers[i+1].num  = CTRL_NRPN14_OFFSET+i+1; +            controllers[i+1].min  = 0; +            controllers[i+1].max  = 127; + +            controllers[i+2].name = c3.toLatin1().data(); +            controllers[i+2].num  = CTRL_NRPN14_OFFSET+i+2; +            controllers[i+2].min  = 0; +            controllers[i+2].max  = 1; + +            controllers[i+3].name = c4.toLatin1().data(); +            controllers[i+3].num  = CTRL_NRPN14_OFFSET+i+3; +            controllers[i+3].min  = 0; +            controllers[i+3].max  = 1; + +            controllers[i+4].name = c5.toLatin1().data(); +            controllers[i+4].num  = CTRL_NRPN14_OFFSET+i+4; + +            controllers[i+5].name = c6.toLatin1().data(); +            controllers[i+5].num  = CTRL_NRPN14_OFFSET+i+5; + +            controllers[i+6].name = c7.toLatin1().data(); +            controllers[i+6].num  = CTRL_NRPN14_OFFSET+i+6; + +            controllers[i+7].name = c8.toLatin1().data(); +            controllers[i+7].num  = CTRL_NRPN14_OFFSET+i+7; + +            controllers[i+4].min = controllers[i+5].min = controllers[i+6].min = controllers[i+7].min = 0; +            controllers[i+4].max = controllers[i+5].max = controllers[i+6].max = controllers[i+7].max = 127; + +            i+=8; +            } + +      for (int sfx=0; sfx<SS_NR_OF_SENDEFFECTS; sfx++) { +            QString c1 = "Sendfx " + QString::number(sfx) + " ret gain"; +            QString c2 = "Sendfx " + QString::number(sfx) + " on/off"; +            controllers[i].name = c1.toLatin1().data(); +            controllers[i].num  = CTRL_NRPN14_OFFSET+i; +            controllers[i].min  = 0; +            controllers[i].max  = 127; + +            controllers[i+1].name = c2.toLatin1().data(); +            controllers[i+1].num  = CTRL_NRPN14_OFFSET+i+1; +            controllers[i+1].min  = 0; +            controllers[i+1].max  = 1; +            i+=2; +            } + +      pthread_mutex_init(&SS_LoaderMutex, NULL); +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   ~SimpleSynth +//--------------------------------------------------------- +SimpleSynth::~SimpleSynth() +      { +      SS_TRACE_IN + +      // Cleanup channels and samples: +      SS_DBG("Cleaning up sample data"); +      for (int i=0; i<SS_NR_OF_CHANNELS; i++) { +            if (channels[i].sample) { +                  delete[] channels[i].sample->data; +                  delete channels[i].sample; +                  } +            } +      simplesynth_ptr = NULL; + +      SS_DBG("Deleting pluginlist"); +      //Cleanup plugins: +      for (iPlugin i = plugins.begin(); i != plugins.end(); ++i) { +            delete (*i); +            } +      plugins.clear(); + +      SS_DBG("Deleting sendfx buffers"); +      //Delete sendfx buffers: +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            delete[] sendFxLineOut[i][0]; +            delete[] sendFxLineOut[i][1]; +            delete[] sendFxReturn[i][0]; +            delete[] sendFxReturn[i][1]; +            } + +      //processBuffer: +      SS_DBG("Deleting process buffer"); +      delete[] processBuffer[0]; +      delete[] processBuffer[1]; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   guiVisible +/*! +    \fn SimpleSynth::guiVisible +    \brief Tells if the gui is hidden or shown +    \return true/false if gui is shown/hidden + */ +//--------------------------------------------------------- +bool SimpleSynth::guiVisible() const +      { +      SS_TRACE_IN +      bool v = gui->isVisible(); +      SS_TRACE_OUT +      return v; +      } + +//--------------------------------------------------------- +//   hasGui +/*! +    \fn SimpleSynth::hasGui +    \brief Tells if the synth has a gui or not +    \return true if synth has gui, false it synth has no gui + */ +//--------------------------------------------------------- +bool SimpleSynth::hasGui() const +      { +      SS_TRACE_IN +      SS_TRACE_OUT +      return true; +      } + +//--------------------------------------------------------- +//   playNote +/*! +    \fn SimpleSynth::playNote +    \brief Triggers a note on (noteoffs are noteons with velo=0) +    \param channel midi channel +    \param pitch note pitch +    \param velo note velocity +    \return false for ok, true for not ok (not sure these are handled differently, but...) + */ +//--------------------------------------------------------- +bool SimpleSynth::playNote(int /*channel*/, int pitch, int velo) +      { +      SS_TRACE_IN +      //Don't bother about channel, we're processing every playnote! +      if ((pitch >= SS_LOWEST_NOTE) && (pitch <= SS_HIGHEST_NOTE)) { +            bool noteOff = (velo == 0 ? 1 : 0); +            int ch = pitch - SS_LOWEST_NOTE; +            if(!noteOff) { +                  if (channels[ch].sample) { +                        //Turn on the white stuff: +                        channels[ch].playoffset = 0; +                        SWITCH_CHAN_STATE(ch , SS_SAMPLE_PLAYING); +                        channels[ch].cur_velo = (double) velo / 127.0; +                        channels[ch].gain_factor = channels[ch].cur_velo * channels[ch].volume; +                        if (SS_DEBUG_MIDI) { +                              printf("Playing note %d on channel %d\n", pitch, ch); +                              } +                        } +                  } +            else { +                  //Note off: +                  if (channels[ch].noteoff_ignore) { +                        if (SS_DEBUG_MIDI) { +                              printf("Note off on channel %d\n", ch); +                              } +                        SWITCH_CHAN_STATE(ch , SS_CHANNEL_INACTIVE); +                        channels[ch].playoffset = 0; +                        channels[ch].cur_velo = 0; +                        } +                  } +            } +      SS_TRACE_OUT +      return false; +      } + +//--------------------------------------------------------- +//   processEvent +/*! +    \fn SimpleSynth::processEvent +    \brief All events from sequencer first shows up here and are forwarded to their correct functions +    \param event The event sent from sequencer +    \return false for ok, true for not ok + */ +//--------------------------------------------------------- +bool SimpleSynth::processEvent(const MidiPlayEvent& ev) +      { +      SS_TRACE_IN +      switch(ev.type()) { +            case ME_CONTROLLER: +                  if (SS_DEBUG_MIDI) { +                        printf("SimpleSynth::processEvent - Controller. Chan: %x dataA: %x dataB: %x\n", ev.channel(), ev.dataA(), ev.dataB()); +                        for (int i=0; i< ev.len(); i++) +                              printf("%x ", ev.data()[i]); +                        } +                  setController(ev.channel(), ev.dataA(), ev.dataB(), false); +                  return true; +            case ME_NOTEON: +                  return playNote(ev.channel(), ev.dataA(), ev.dataB()); +            case ME_NOTEOFF: +                  return playNote(ev.channel(), ev.dataA(), 0); +            case ME_SYSEX: +                  //Debug print +                  if (SS_DEBUG_MIDI) { +                        printf("SimpleSynth::processEvent - Sysex received\n"); +                        for (int i=0; i< ev.len(); i++) +                              printf("%x ", ev.data()[i]); +                        printf("\n"); +                        } +                  return sysex(ev.len(), ev.data()); +            } +      return false; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   setController +/*! +    \fn SimpleSynth::setController +    \brief Called from sequencer indirectly via SimpleSynth::processEvent +    \brief when the synth is supposed to set a controller value +    \param channel channel nr +    \param id controller id +    \param val value of controller +    \return false for ok, true for not ok + */ +//--------------------------------------------------------- +bool SimpleSynth::setController(int channel, int id, int val) +      { +      SS_TRACE_IN +      if (SS_DEBUG_MIDI) { +            printf("SimpleSynth::setController - received controller on channel %d, id %d value %d\n", channel, id, val); +            } + +      // Channel controllers: +      if (id >= SS_FIRST_CHANNEL_CONTROLLER && id <= SS_LAST_CHANNEL_CONTROLLER ) { +            // Find out which channel we're dealing with: +            id-= SS_FIRST_CHANNEL_CONTROLLER; +            int ch = (id / SS_NR_OF_CHANNEL_CONTROLLERS); +            id = (id % SS_NR_OF_CHANNEL_CONTROLLERS); + +            switch (id) { +                  case SS_CHANNEL_CTRL_VOLUME: +                        if (SS_DEBUG_MIDI) +                              printf("Received channel ctrl volume %d for channel %d\n", val, ch); +                        channels[ch].volume_ctrlval = val; +                        updateVolume(ch, val); +                        break; +                  case SS_CHANNEL_CTRL_NOFF: +                        if (SS_DEBUG_MIDI) +                              printf("Received ctrl noff %d for channel %d\n", val, ch); +                        channels[ch].noteoff_ignore = val; +                        break; +                  case SS_CHANNEL_CTRL_PAN: +                        { +                        if (SS_DEBUG_MIDI) +                              printf("Received ctrl pan %d for channel %d\n", val, ch); +                        channels[ch].pan = val; +                        updateBalance(ch, val); +                        break; +                        } +                  case SS_CHANNEL_CTRL_ONOFF: +                        { +                        if (SS_DEBUG_MIDI) +                              printf("Received ctrl onoff %d for channel %d\n", val, ch); + +                        if (val == false && channels[ch].channel_on == true) { +                              SWITCH_CHAN_STATE(ch, SS_CHANNEL_INACTIVE); +                              channels[ch].channel_on = val; +                              } +                        else if (val == true && channels[ch].channel_on == false) { // if it actually _was_ off: +                              SWITCH_CHAN_STATE(ch, SS_CHANNEL_INACTIVE); +                              channels[ch].playoffset = 0; +                              channels[ch].channel_on = val; +                              } +                        break; +                        } +                  case SS_CHANNEL_SENDFX1: +                  case SS_CHANNEL_SENDFX2: +                  case SS_CHANNEL_SENDFX3: +                  case SS_CHANNEL_SENDFX4: +                        { +                        int fxid = id - SS_CHANNEL_SENDFX1; +                        channels[ch].sendfxlevel[fxid] = (double)val/127.0; +                        break; +                        } + +                  default: +                        if (SS_DEBUG_MIDI) +                              printf("Unknown controller received for channel %d. id=%d\n", ch, id); +                        break; +                  } +            } +      // Master controllers: +      else if (id >= SS_FIRST_MASTER_CONTROLLER && id <= SS_LAST_MASTER_CONTROLLER) { +            if (SS_DEBUG_MIDI) +                  printf("Mastervol controller received: %d\n", id); +            master_vol_ctrlval = val; +            master_vol = (double) master_vol_ctrlval / SS_MASTER_VOLUME_QUOT; +            } +      // Emmm, this one should've been there in the beginning +      else if (id == CTRL_VOLUME) { +            if (SS_DEBUG_MIDI) { +                  printf("Ctrl volume received: vol: %d\n", val); +                  } +            master_vol_ctrlval = val; +            master_vol = (double) master_vol_ctrlval / SS_MASTER_VOLUME_QUOT; +            //This one can't be from the gui, update gui: +            guiUpdateMasterVol(val); +            } +      // Plugin controllers: +      else if (id >= SS_FIRST_PLUGIN_CONTROLLER && id <= SS_LAST_PLUGIN_CONTROLLER) { + +            int fxid = (id - SS_FIRST_PLUGIN_CONTROLLER) / SS_NR_OF_PLUGIN_CONTROLLERS; +            int cmd = (id - SS_FIRST_PLUGIN_CONTROLLER) % SS_NR_OF_PLUGIN_CONTROLLERS; + +            // Plugin return-gain: +            if (cmd == SS_PLUGIN_RETURN) { +                  if (SS_DEBUG_MIDI) +                        printf("Ctrl fx retgain received: fxid: %d val: %d\n", fxid, val); +                  sendEffects[fxid].retgain_ctrlval = val; +                  sendEffects[fxid].retgain = (double) val / 75.0; +                  } +            // Plugin on/off: +            else if (cmd == SS_PLUGIN_ONOFF) { +                  if (SS_DEBUG_MIDI) +                        printf("Ctrl fx onoff received: fxid: %d val: %d\n", fxid, val); +                  sendEffects[fxid].state = (SS_SendFXState) val; +                  } +            } +      else { +            if (SS_DEBUG_MIDI) +                  printf("Unknown controller received: %d\n", id); +            } +      SS_TRACE_OUT +      return false; +      } + +//--------------------------------------------------------- +/*! +    \fn SimpleSynth::setController + */ +//--------------------------------------------------------- +bool SimpleSynth::setController(int channel, int id, int val, bool /*fromGui*/) +      { +      SS_TRACE_IN +      bool ret = setController(channel, id, val); //Perhaps TODO... Separate events from the gui +      SS_TRACE_OUT +      return ret; +      } +//--------------------------------------------------------- +//   sysex +/*! +    \fn SimpleSynth::sysex +    \brief Called from sequencer indirectly via SimpleSynth::processEvent +    \param len length of the sysex data +    \param data the sysex data +    \return false for ok, true for not ok +*/ +//--------------------------------------------------------- +bool SimpleSynth::sysex(int /*len*/, const unsigned char* data) +      { +      SS_TRACE_IN +      int cmd = data[0]; +      switch (cmd) { +            case SS_SYSEX_LOAD_SAMPLE: +                  { +                  int channel = data[1]; +                  //int l = data[2]; +                  const char* filename = (const char*)(data+3); +                  if (SS_DEBUG_MIDI) { +                        printf("Sysex cmd: load sample, filename %s, on channel: %d\n", filename, channel); +                        } +                  loadSample(channel, filename); +                  break; +                  } +            case SS_SYSEX_CLEAR_SAMPLE: +                  { +                  int ch = data[1]; +                  clearSample(ch); +                  break; +                  } + +            case SS_SYSEX_INIT_DATA: +                  { +                  parseInitData(data); +                  break; +                  } + +            case SS_SYSEX_LOAD_SENDEFFECT: +                  { +                  int fxid = data[1]; +                  QString lib = (const char*) (data + 2); +                  QString label = (const char*) (data + lib.length() + 3); +                  if (SS_DEBUG_MIDI) { +                        printf("Sysex cmd load effect: %d %s %s\n", fxid, lib.toLatin1().data(), label.toLatin1().data()); +                        } +                  initSendEffect(fxid, lib, label); +                  break; +                  } + +            case SS_SYSEX_CLEAR_SENDEFFECT: +                  { +                  int fxid = data[1]; +                  if (SS_DEBUG_MIDI) { +                        printf("Sysex cmd clear effect: %d\n", fxid); +                        } +                  sendEffects[fxid].state = SS_SENDFX_OFF; +                  cleanupPlugin(fxid); +                  sendEffects[fxid].plugin = 0; +                  break; +                  } + +            case SS_SYSEX_SET_PLUGIN_PARAMETER: +                  { +                  int fxid = data[1]; +                  int parameter = data[2]; +                  int val = data[3]; +                  // Write it to the plugin: +                  float floatval = sendEffects[fxid].plugin->convertGuiControlValue(parameter, val); +                  setFxParameter(fxid, parameter, floatval); +                  break; +                  } + +            case SS_SYSEX_GET_INIT_DATA: +                  { +                  int initdata_len = 0; +                  const byte* tmp_initdata = NULL; +                  byte* event_data = NULL; + +                  getInitData(&initdata_len, &tmp_initdata); +                  int totlen = initdata_len + 1; + +                  event_data = new byte[initdata_len + 1]; +                  event_data[0] = SS_SYSEX_SEND_INIT_DATA; +                  memcpy(event_data + 1, tmp_initdata, initdata_len); +                  delete[] tmp_initdata; +                  tmp_initdata = NULL; + +                  MidiPlayEvent ev(0, 0, ME_SYSEX, event_data, totlen); +                  gui->writeEvent(ev); +                  delete[] event_data; + +                  break; +                  } + +            default: +                  if (SS_DEBUG_MIDI) +                        printf("Unknown sysex cmd received: %d\n", cmd); +                  break; +            } +      SS_TRACE_OUT +      return false; +      } + +//--------------------------------------------------------- +//   getPatchName +/*! +    \fn SimpleSynth::getPatchName +    \brief Called from host to get names of patches +    \param index - which patchnr we're about to deliver +    \return const char* with patchname + */ +//--------------------------------------------------------- +const char* SimpleSynth::getPatchName(int /*index*/, int, int) const +      { +      SS_TRACE_IN +      SS_TRACE_OUT +      return 0; +      } + +//--------------------------------------------------------- +//   getPatchInfo +/*! +    \fn SimpleSynth::getPatchInfo +    \brief Called from host to get info about patches +    \param index - which patchnr we're about to deliver +    \param patch - if this one is 0, this is the first call, otherwise keep deliver the host patches... or something +    \return MidiPatch with patch info for host + */ +//--------------------------------------------------------- +const MidiPatch* SimpleSynth::getPatchInfo(int index, const MidiPatch* patch) const +      { +      SS_TRACE_IN +      index = 0; patch = 0; +      SS_TRACE_OUT +      return 0; +      } + +//--------------------------------------------------------- +//   getControllerInfo +/*! +    \fn SimpleSynth::getControllerInfo +    \brief Called from host to collect info about which controllers the synth supports +    \param index current controller number +    \param name pointer where name is stored +    \param controller int pointer where muse controller number is stored +    \param min int pointer where controller min value is stored +    \param max int pointer where controller max value is stored +    \return 0 when done, otherwise return next desired controller index + */ +//--------------------------------------------------------- +int SimpleSynth::getControllerInfo(int index, const char** name, int* controller, int* min, int* max) +      { +      SS_TRACE_IN +      if (index >= SS_NR_OF_CONTROLLERS) { +            SS_TRACE_OUT +            return 0; +            } + +      *name = controllers[index].name.c_str(); +      *controller = controllers[index].num; +      *min = controllers[index].min; +      *max = controllers[index].max; + +      if (SS_DEBUG_MIDI) { +            printf("setting controller info: index %d name %s controller %d min %d max %d\n", index, *name, *controller, *min, *max); +            } +      SS_TRACE_OUT +      return (index +1); +      } + +//--------------------------------------------------------- +//   process +/*! +    \fn SimpleSynth::process +    \brief Realtime function where the processing actually occurs +    \param channels - audio data +    \param offset - sample offset +    \param len - nr of samples to process + */ +//--------------------------------------------------------- +void SimpleSynth::process(float** out, int offset, int len) +      { +      //Process messages from the gui +      while (gui->fifoSize()) { +            MidiPlayEvent ev = gui->readEvent(); +            if (ev.type() == ME_SYSEX) { +                  sysex(ev.len(), ev.data()); +                  sendEvent(ev); +                  } +            else if (ev.type() == ME_CONTROLLER) { +                  setController(ev.channel(), ev.dataA(), ev.dataB(), true); +                  sendEvent(ev); +                  } +            else { +                  if (SS_DEBUG) +                        printf("SimpleSynth::process(): unknown event, type: %d\n", ev.type()); +                  } +            } + +      if (synth_state == SS_RUNNING) { + +      //Temporary mix-doubles +      double out1, out2; +      //double ltemp, rtemp; +      float* data; +      // Velocity factor: +      double gain_factor; + + +      // Clear send-channels. Skips if fx not turned on +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            if (sendEffects[i].state == SS_SENDFX_ON) { +                  memset(sendFxLineOut[i][0], 0, SS_SENDFX_BUFFER_SIZE * sizeof(float)); +                  memset(sendFxLineOut[i][1], 0, SS_SENDFX_BUFFER_SIZE * sizeof(float)); +                  } +            } + + +      memset(out[0] + offset, 0, len * sizeof(float)); +      memset(out[1] + offset, 0, len * sizeof(float)); + +      //Process 1 channel at a time +      for (int ch=0; ch < SS_NR_OF_CHANNELS; ch++) { +            // If channels is turned off, skip: +            if (channels[ch].channel_on == false) +                  continue; + +            //If sample isn't playing, skip: +            if (channels[ch].state == SS_SAMPLE_PLAYING) { +                  memset(processBuffer[0], 0, SS_PROCESS_BUFFER_SIZE * sizeof(double)); +                  memset(processBuffer[1], 0, SS_PROCESS_BUFFER_SIZE * sizeof(double)); + +                  for (int i=0; i<len; i++) { +                        // Current channel sample data: +                        data = channels[ch].sample->data; +                        gain_factor = channels[ch].gain_factor; +                        // Current velocity factor: + +                        if (channels[ch].sample->channels == 2) { +                              // +                              // Stereo sample: +                              // +                              // Add from sample: +                              out1 = (double) (data[channels[ch].playoffset] * gain_factor * channels[ch].balanceFactorL); +                              out2 = (double) (data[channels[ch].playoffset + 1] * gain_factor * channels[ch].balanceFactorR); +                              channels[ch].playoffset += 2; +                              } +                        else { +                              // +                              // Mono sample: +                              // +                              out1 = (double) (data[channels[ch].playoffset] * gain_factor * channels[ch].balanceFactorL); +                              out2 = (double) (data[channels[ch].playoffset] * gain_factor * channels[ch].balanceFactorR); +                              channels[ch].playoffset++; +                              } + +                        processBuffer[0][i] = out1; +                        processBuffer[1][i] = out2; + +                        // If send-effects tap is on, tap signal to respective lineout channel +                        for (int j=0; j<SS_NR_OF_SENDEFFECTS; j++) { +                              if (channels[ch].sendfxlevel[j] != 0.0) { +                                    //If the effect has 2 inputs (stereo in): +                                    if (sendEffects[j].inputs == 2) { +                                          sendFxLineOut[j][0][i]+= (out1 * channels[ch].sendfxlevel[j]); +                                          sendFxLineOut[j][1][i]+= (out2 * channels[ch].sendfxlevel[j]); +                                          } +                                    //If the effect is mono (1 input), only use first fxLineOut +                                    else if (sendEffects[j].inputs == 1) { +                                          sendFxLineOut[j][0][i]+= ((out1 + out2) * channels[ch].sendfxlevel[j] / 2.0); +                                          } +                                    //Effects with 0 or >2 inputs are ignored +                                    } +                              } + +                        // +                        // If we've reached the last sample, set state to inactive +                        // +                        if (channels[ch].playoffset >= channels[ch].sample->samples) { +                              SWITCH_CHAN_STATE(ch, SS_CHANNEL_INACTIVE); +                              channels[ch].playoffset = 0; +                              break; +                              } +                        } +                        // Add contribution for this channel, for this frame, to final result: +                        for (int i=0; i<len; i++) { +                              out[0][i+offset]+=processBuffer[0][i]; +                              out[1][i+offset]+=processBuffer[1][i]; +                              } +                  } +            } +            // Do something funny with the sendies: +            for (int j=0; j<SS_NR_OF_SENDEFFECTS; j++) { +                  if (sendEffects[j].state == SS_SENDFX_ON) { +                        sendEffects[j].plugin->process(len); +                        for (int i=0; i<len; i++) { +                              //Effect has mono output: +                              if (sendEffects[j].outputs == 1) { +                                    //Add the result to both channels: +                                    out[0][i+offset]+=((sendEffects[j].retgain * sendFxReturn[j][0][i]) / 2.0); +                                    out[1][i+offset]+=((sendEffects[j].retgain * sendFxReturn[j][0][i]) / 2.0); +                                    } +                              else if (sendEffects[j].outputs == 2) { +                                    // Effect has stereo output +                                    out[0][i+offset]+=(sendEffects[j].retgain * sendFxReturn[j][0][i]); +                                    out[1][i+offset]+=(sendEffects[j].retgain * sendFxReturn[j][1][i]); +                                    } +                              } +                        } +                  } +            // Finally master gain: +            for (int i=0; i<len; i++) { +                  out[0][i+offset] = (out[0][i+offset] * master_vol); +                  out[1][i+offset] = (out[1][i+offset] * master_vol); +                  } +            } +      } + +//--------------------------------------------------------- +//   showGui +/*! +    \fn SimpleSynth::showGui +    \brief Displays or hides the gui window +    \param val true or false = gui shown or hidden + */ +//--------------------------------------------------------- +void SimpleSynth::showGui(bool val) +      { +      SS_TRACE_IN +      gui->setShown(val); +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +/*! +    \fn SimpleSynth::init +    \brief Initializes the SimpleSynth +    \param name string set to caption in the gui dialog +    \return true if successful, false if unsuccessful + */ +//--------------------------------------------------------- +bool SimpleSynth::init(const char* name) +      { +      SS_TRACE_IN +      SWITCH_SYNTH_STATE(SS_INITIALIZING); +      gui = new SimpleSynthGui(); +      gui->show(); +      gui->setWindowTitle(name); +      SWITCH_SYNTH_STATE(SS_RUNNING); +      SS_TRACE_OUT +      return true; +      } + +//--------------------------------------------------------- +/*! +    \fn SimpleSynth::getInitData +    \brief Data for reinitialization of SimpleSynth when loading project +    \param n - number of chars used in the data +    \param data - data that is sent as a sysex to the synth on reload of project + */ +//--------------------------------------------------------- +void SimpleSynth::getInitData(int* n, const unsigned char** data) +      { +      SS_TRACE_IN +      // Calculate length of data +      // For each channel, we need to store volume, pan, noff, onoff +      int len = SS_NR_OF_CHANNEL_CONTROLLERS * SS_NR_OF_CHANNELS; +      // Sampledata: filenames len +      for (int i=0; i<SS_NR_OF_CHANNELS; i++) { +            if (channels[i].sample) { +                  int filenamelen = strlen(channels[i].sample->filename.c_str()) + 2; +                  len+=filenamelen; +                  } +            else +                  len++; //Add place for SS_NO_SAMPLE +            } +      len+=3; // 1 place for SS_SYSEX_INIT_DATA, 1 byte for master vol, 1 byte for version data + +      // Effect data length +      len++; //Add place for SS_SYSEX_INIT_DATA_VERSION, as control + +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            Plugin* plugin = sendEffects[i].plugin; +            if (plugin) { +                  int namelen = plugin->lib().size() + 2; +                  int labelnamelen = plugin->label().size() + 2; +                  len+=(namelen + labelnamelen); + +                  len+=3; //1 byte for nr of parameters, 1 byte for return gain, 1 byte for effect on/off +                  len+=sendEffects[i].nrofparameters; // 1 byte for each parameter value +                  } +            else { +                  len++; //place for SS_NO_PLUGIN +                  } +            } + +      // First, SS_SYSEX_INIT_DATA +      byte* buffer = new byte[len]; +      memset(buffer, 0, len); +      buffer[0] = SS_SYSEX_INIT_DATA; +      buffer[1] = SS_SYSEX_INIT_DATA_VERSION; +      if (SS_DEBUG_INIT) { +            printf("Length of init data: %d\n", len); +            printf("buffer[0] - SS_SYSEX_INIT_DATA: %d\n", SS_SYSEX_INIT_DATA); +            printf("buffer[1] - SS_SYSEX_INIT_DATA_VERSION: %d\n", SS_SYSEX_INIT_DATA_VERSION); +            } +      int i = 2; +      // All channels: +      // 0       - volume ctrlval (0-127) +      // 1       - pan (0-127) +      // 2       - noff ignore (0-1) +      // 3       - channel on/off (0-1) +      // 4 - 7   - sendfx 1-4 (0-127) +      // 8       - len of filename, n +      // 9 - 9+n - filename +      for (int ch=0; ch<SS_NR_OF_CHANNELS; ch++) { +            buffer[i]   = (byte) channels[ch].volume_ctrlval; +            buffer[i+1] = (byte) channels[ch].pan; +            buffer[i+2] = (byte) channels[ch].noteoff_ignore; +            buffer[i+3] = (byte) channels[ch].channel_on; +            buffer[i+4] = (byte) round(channels[ch].sendfxlevel[0] * 127.0); +            buffer[i+5] = (byte) round(channels[ch].sendfxlevel[1] * 127.0); +            buffer[i+6] = (byte) round(channels[ch].sendfxlevel[2] * 127.0); +            buffer[i+7] = (byte) round(channels[ch].sendfxlevel[3] * 127.0); + +            if (SS_DEBUG_INIT) { +                  printf("Channel %d:\n", ch); +                  printf("buffer[%d] - channels[ch].volume_ctrlval = \t%d\n", i, channels[ch].volume_ctrlval); +                  printf("buffer[%d] - channels[ch].pan = \t\t%d\n", i+1, channels[ch].pan); +                  printf("buffer[%d] - channels[ch].noteoff_ignore = \t%d\n", i+2, channels[ch].noteoff_ignore ); +                  printf("buffer[%d] - channels[ch].channel_on = \t%d\n", i+3, channels[ch].channel_on); +                  for (int j= i+4; j < i+8; j++) { +                        printf("buffer[%d] - channels[ch].sendfxlevel[%d]= \t%d\n", j, j-i-4, (int)round(channels[ch].sendfxlevel[j-i-4] * 127.0)); +                        } +                  } +            if (channels[ch].sample) { +                  int filenamelen = strlen(channels[ch].sample->filename.c_str()) + 1; +                  buffer[i+8] = (byte) filenamelen; +                  memcpy((buffer+(i+9)), channels[ch].sample->filename.c_str(), filenamelen); +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d] - filenamelen: %d\n", i+8, filenamelen); +                        printf("buffer[%d] - buffer[%d] - filename: ", (i+9), (i+9) + filenamelen - 1); +                        for (int j = i+9; j< i+9+filenamelen; j++) { +                              printf("%c",buffer[j]); +                              } +                        printf("\n"); +                        } +                  i+= (SS_NR_OF_CHANNEL_CONTROLLERS + 1 + filenamelen); +                  } +            else { +                  buffer[i+8] = SS_NO_SAMPLE; +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d]: SS_NO_SAMPLE: - %d\n", i+8, SS_NO_SAMPLE); +                        } +                  i+= (SS_NR_OF_CHANNEL_CONTROLLERS + 1); +                  } +            } +      if (SS_DEBUG_INIT) { +            printf("buffer[%d]: Master vol: - %d\n", i, master_vol_ctrlval); +            } +      buffer[i] = master_vol_ctrlval; +      *(data) = buffer; *n = len; +      i++; + +      //Send effects: +      buffer[i] = SS_SYSEX_INIT_DATA_VERSION; //Just for check +      if (SS_DEBUG_INIT) { +            printf("buffer[%d]: Control value, SS_SYSEX_INIT_DATA_VERSION\n", i); +            } + +      i++; +      for (int j=0; j<SS_NR_OF_SENDEFFECTS; j++) { +            if (sendEffects[j].plugin) { +                  int labelnamelen = sendEffects[j].plugin->label().size() + 1; +                  buffer[i] = labelnamelen; +                  memcpy((buffer+i+1), sendEffects[j].plugin->label().toLatin1().data(), labelnamelen); +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d] - labelnamelen: %d\n", i, labelnamelen); +                        printf("buffer[%d] - buffer[%d] - filename: ", (i+1), (i+1) + labelnamelen - 1); +                        for (int k = i+1; k < i+1+labelnamelen; k++) { +                              printf("%c",buffer[k]); +                              } +                        printf("\n"); +                        } + +                  i+=(labelnamelen + 1); + +                  int namelen = sendEffects[j].plugin->lib().size() + 1; +                  buffer[i] = namelen; +                  memcpy((buffer+i+1), sendEffects[j].plugin->lib().toLatin1().data(), namelen); +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d] - libnamelen : %d\n", i, namelen); +                        printf("buffer[%d] - buffer[%d] - filename: ", (i+1), (i+1) + namelen - 1); +                        for (int k = i+1; k < i+1+namelen; k++) { +                              printf("%c",buffer[k]); +                              } +                        printf("\n"); +                        } + +                  i+=(namelen + 1); + +                  buffer[i]=sendEffects[j].nrofparameters; +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d]: sendEffects[%d].nrofparameters=%d\n", i, j, buffer[i]); +                        } +                  i++; + +                  buffer[i]=sendEffects[j].retgain_ctrlval; +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d]: sendEffects[%d].retgain_ctrlval=%d\n", i, j, buffer[i]); +                        } +                  i++; + +                  for (int k=0; k<sendEffects[j].nrofparameters; k++) { +                        //TODO: Convert to 127-scale +                        buffer[i] = sendEffects[j].plugin->getGuiControlValue(k); +                        if (SS_DEBUG_INIT) { +                              printf("buffer[%d]: sendEffects[%d].parameterval[%d]=%d\n", i, j, k, buffer[i]); +                              } +                        i++; +                        } +                  } +            // No plugin loaded: +            else { +                  buffer[i] = SS_NO_PLUGIN; +                  if (SS_DEBUG_INIT) { +                        printf("buffer[%d]: SS_NO_PLUGIN\n", i); +                        } +                  i++; +                  } +            } + +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::parseInitData() + */ +void SimpleSynth::parseInitData(const unsigned char* data) +      { +      SS_TRACE_IN +      //int len = strlen((const char*)data); +      if (SS_DEBUG_INIT) { +            printf("buffer[1], SS_SYSEX_INIT_DATA_VERSION=%d\n", *(data+1)); +            } +      const byte* ptr = data+2; +      for (int ch=0; ch<SS_NR_OF_CHANNELS; ch++) { +               channels[ch].volume_ctrlval = (byte) *(ptr); + +               if (SS_DEBUG_INIT) { +                     printf("Channel %d:\n", ch); +                     printf("buffer[%ld] - channels[ch].volume_ctrlval = \t%d\n", ptr-data, *ptr); +                     printf("buffer[%ld] - channels[ch].pan = \t\t%d\n", ptr-data+1, *(ptr+1)); +                     printf("buffer[%ld] - channels[ch].noteoff_ignore = \t%d\n", ptr-data+2, *(ptr+2)); +                     printf("buffer[%ld] - channels[ch].channel_on = \t%d\n", ptr-data+3, *(ptr+3)); +                     } +               updateVolume(ch, *(ptr)); +               guiUpdateVolume(ch, *(ptr)); + +               channels[ch].pan = *(ptr+1); +               updateBalance(ch, *(ptr+1)); +               guiUpdateBalance(ch, *(ptr+1)); + +               channels[ch].noteoff_ignore = *(ptr+2); +               guiUpdateNoff(ch, *(ptr+2)); + +               channels[ch].channel_on = *(ptr+3); +               guiUpdateChoff(ch, *(ptr+3)); + +               ptr+=4; + +               for (int i=0; i<4; i++) { +                     channels[ch].sendfxlevel[i] = (float) (*(ptr)/127.0); +                     guiUpdateSendFxLevel(ch, i, *(ptr)); +                     ptr++; +                     } + +               bool hasSample = *(ptr); +               ptr++; + +               channels[ch].sample = 0; +               channels[ch].playoffset = 0; +               SWITCH_CHAN_STATE(ch, SS_CHANNEL_INACTIVE); +               if (SS_DEBUG_INIT) { +                     printf("parseInitData: channel %d, volume: %f pan: %d bfL %f bfR %f chON %d s1: %f s2: %f s3: %f s4: %f\n", +                              ch, +                              channels[ch].volume, +                              channels[ch].pan, +                              channels[ch].balanceFactorL, +                              channels[ch].balanceFactorR, +                              channels[ch].channel_on, +                              channels[ch].sendfxlevel[0], +                              channels[ch].sendfxlevel[1], +                              channels[ch].sendfxlevel[2], +                              channels[ch].sendfxlevel[3] +                              ); +                     } +               if (hasSample) { +                     std::string filenametmp = (const char*) ptr; +                     ptr+= strlen(filenametmp.c_str()) + 1; +                     //printf("We should load %s\n", filenametmp.c_str()); +                     loadSample(ch, filenametmp.c_str()); +                     } +               else { +                     //Clear sample +                     clearSample(ch); +                     guiNotifySampleCleared(ch); +                     } +               } +      //Master vol: +      master_vol_ctrlval = *(ptr); +      master_vol = (double) master_vol_ctrlval / SS_MASTER_VOLUME_QUOT; +      guiUpdateMasterVol(master_vol_ctrlval); +      if (SS_DEBUG_INIT) { +                  printf("Master vol: %d\n", master_vol_ctrlval); +                  } +      ptr++; + +      // Effects: +      if (*(ptr) != SS_SYSEX_INIT_DATA_VERSION) { +            fprintf(stderr, "Error loading init data - control byte not found. Skipping...\n"); +            SS_TRACE_OUT +            return; +            } +      ptr++; + +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            if (SS_DEBUG_INIT) +                  printf("buffer[%ld] - sendeffect[%d], labelnamelen=%d\n", ptr-data, i, *ptr); +            int labelnamelen = *(ptr); + +            if (labelnamelen != SS_NO_PLUGIN) { +                  ptr++; +                  std::string labelnametmp = (const char*) ptr; +                  ptr+= labelnamelen; + +                  //int libnamelen = *(ptr); +                  ptr++; +                  std::string libnametmp = (const char*) ptr; +                  ptr+= strlen(libnametmp.c_str()) + 1; + + +                  initSendEffect(i, libnametmp.c_str(), labelnametmp.c_str()); +                  //initSendEffect(0, "cmt", "freeverb3"); + +                  byte params = *(ptr); +                  byte retgain = *(ptr+1); +                  ptr+=2; + +                  sendEffects[i].nrofparameters = params; + +                  sendEffects[i].retgain_ctrlval = retgain; +                  sendEffects[i].retgain = retgain; +                  sendEffects[i].retgain = (double) retgain/ 75.0; +                  MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_PLUGIN_RETURNLEVEL_CONTROLLER(i), retgain); +                  gui->writeEvent(ev); + +                  for (int j=0; j<params; j++) { +                        if (SS_DEBUG_INIT) +                              printf("buffer[%ld] - sendeffect[%d], parameter[%d]=%d\n", ptr-data, i, j, *ptr); +                        setFxParameter(i, j, sendEffects[i].plugin->convertGuiControlValue(j, *(ptr))); +                        ptr++; +                        } +                  } +            else { +                  if (sendEffects[i].plugin) +                        cleanupPlugin(i); +                  ptr++; +                  } +            } + +      SS_TRACE_OUT +      } + +/*! +    \fn SimpleSynth::loadSample(int chno, const char* filename) + */ +bool SimpleSynth::loadSample(int chno, const char* filename) +      { +      SS_TRACE_IN +      SS_Channel* ch = &channels[chno]; + +      // Thread stuff: +      SS_SampleLoader* loader = new SS_SampleLoader; +      loader->channel = ch; +      loader->filename = std::string(filename); +      loader->ch_no   = chno; +      if (SS_DEBUG) { +            printf("Loader filename is: %s\n", filename); +            } +      pthread_t sampleThread; +      pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t)); +      pthread_attr_init(attributes); +      pthread_attr_setdetachstate(attributes, PTHREAD_CREATE_DETACHED); +      if (pthread_create(&sampleThread, attributes, ::loadSampleThread, (void*) loader)) { +            perror("creating thread failed:"); +            pthread_attr_destroy(attributes); +            delete loader; +            return false; +            } + +      pthread_attr_destroy(attributes); +      SS_TRACE_OUT +      return true; +      } + +/*! +    \fn loadSampleThread(void* p) +    \brief Since process needs to respond withing a certain time, loading of samples need to be done in a separate thread + */ +static void* loadSampleThread(void* p) +      { +      SS_TRACE_IN +      pthread_mutex_lock(&SS_LoaderMutex); + +      // Crit section: +      SS_State prevState = synth_state; +      SWITCH_SYNTH_STATE(SS_LOADING_SAMPLE); +      SS_SampleLoader* loader = (SS_SampleLoader*) p; +      SS_Channel* ch = loader->channel; +      int ch_no      = loader->ch_no; + +      if (ch->sample) { +            delete[] ch->sample->data; +            delete ch->sample; +            } +      ch->sample = new SS_Sample; +      SS_Sample* smp = ch->sample; + +      SNDFILE* sf; +      const char* filename = loader->filename.c_str(); +      SF_INFO sfi; + +      if (SS_DEBUG) +            printf("loadSampleThread: filename = %s\n", filename); + +      sf = sf_open(filename, SFM_READ, &sfi); +      if (sf == 0) { +            fprintf(stderr,"Error opening file: %s\n", filename); +            SWITCH_SYNTH_STATE(prevState); +            simplesynth_ptr->guiSendSampleLoaded(false, loader->ch_no, filename); +            delete ch->sample; ch->sample = 0; +            delete loader; +            pthread_mutex_unlock(&SS_LoaderMutex); +            SS_TRACE_OUT +            pthread_exit(0); +            } + +      //Print some info: +      if (SS_DEBUG) { +            printf("Sample info:\n"); +            printf("Frames: \t%ld\n", (long) sfi.frames); +            printf("Channels: \t%d\n", sfi.channels); +            printf("Samplerate: \t%d\n", sfi.samplerate); +            } + +      // +      // Allocate and read the thingie +      // + +      // If current samplerate is the same as MusE's: +      if (SS_samplerate == sfi.samplerate) { +            smp->data = new float[sfi.channels * sfi.frames]; +            sf_count_t n = sf_readf_float(sf, smp->data, sfi.frames); +            smp->frames = sfi.frames; +            smp->samples = (n * sfi.channels); +            smp->channels = sfi.channels; +            if (SS_DEBUG) { +                  printf("%ld frames read\n", (long) n); +                  } +            } +      else  // otherwise, resample: +      { +            smp->channels = sfi.channels; +            // Get new nr of frames: +            double srcratio = (double) SS_samplerate/ (double) sfi.samplerate; +            smp->frames = (long) floor(((double) sfi.frames * srcratio)); +            smp->frames = (sfi.channels == 1 ? smp->frames * 2 : smp->frames ); // Double nr of new frames if mono->stereo +            smp->samples = smp->frames * smp->channels; + +            if (SS_DEBUG) { +                  printf("Resampling from %ld frames to %ld frames - srcration: %lf\n", sfi.frames, smp->frames, srcratio); +                  printf("Nr of new samples: %ld\n", smp->samples); +                  } + +            // Read to temporary: +            float temp[sfi.frames * sfi.channels]; +            int frames_read = sf_readf_float(sf, temp, sfi.frames); +            if (frames_read != sfi.frames) { +                  fprintf(stderr,"Error reading sample %s\n", filename); +                  simplesynth_ptr->guiSendSampleLoaded(false, loader->ch_no, filename); +                  sf_close(sf); +                  SWITCH_SYNTH_STATE(prevState); +                  delete ch->sample; ch->sample = 0; +                  delete loader; +                  pthread_mutex_unlock(&SS_LoaderMutex); +                  pthread_exit(0); +                  SS_TRACE_OUT +                  } + +            // Allocate mem for the new one +            smp->data = new float[smp->frames * smp->channels]; +            memset(smp->data, 0, sizeof(float)* smp->frames * smp->channels); + +            // libsamplerate & co (secret rabbits in the code!) +            SRC_DATA srcdata; +            srcdata.data_in  = temp; +            srcdata.data_out = smp->data; +            srcdata.input_frames  = sfi.frames; +            srcdata.output_frames = smp->frames; +            srcdata.src_ratio = (double) SS_samplerate / (double) sfi.samplerate; + +            if (SS_DEBUG) { +                  printf("Converting sample....\n"); +                  } + +            if (src_simple(&srcdata, SRC_SINC_BEST_QUALITY, sfi.channels)) { +                  SS_ERROR("Error when resampling, ignoring current sample"); +                  //TODO: deallocate and stuff +                  } +            else if (SS_DEBUG) { +                  printf("Sample converted. %ld input frames used, %ld output frames generated\n", +                           srcdata.input_frames_used, +                           srcdata.output_frames_gen); +                  } +         } +      //Just close the dam thing +      sf_close(sf); +      SWITCH_SYNTH_STATE(prevState); +      ch->sample->filename = loader->filename; +      simplesynth_ptr->guiSendSampleLoaded(true, ch_no, filename); +      delete loader; +      pthread_mutex_unlock(&SS_LoaderMutex); +      SS_TRACE_OUT +      pthread_exit(0); +      } + + +//static Mess* instantiate(int sr, const char* name) +static Mess* instantiate(int sr, QWidget*, QString* projectPathPtr, const char* name) +      { +      printf("SimpleSynth sampleRate %d\n", sr); +      SimpleSynth* synth = new SimpleSynth(sr); +      if (!synth->init(name)) { +            delete synth; +            synth = 0; +            } +      return synth; +      } + + +/*! +    \fn SimpleSynth::updateBalance(int pan) + */ +void SimpleSynth::updateBalance(int ch, int val) +      { +      SS_TRACE_IN +      channels[ch].pan = val; + +      // Balance: +      channels[ch].balanceFactorL = 1.0; +      channels[ch].balanceFactorR = 1.0; +      double offset = 0; +      int dev = val - 64; +      offset = (double) dev / 64.0; +      if (offset < 0) { +            channels[ch].balanceFactorR = 1.0 + offset; +            } +      else { +            channels[ch].balanceFactorL = 1.0 - offset; +            } + +      if (SS_DEBUG_MIDI) +            printf("balanceFactorL %f balanceFactorR %f\n", channels[ch].balanceFactorL, channels[ch].balanceFactorR); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::updateVolume(int invol_ctrlval) + */ +void SimpleSynth::updateVolume(int ch, int invol_ctrlval) +      { +      SS_TRACE_IN +      channels[ch].volume = (double)invol_ctrlval/ (double) SS_CHANNEL_VOLUME_QUOT; +      channels[ch].volume_ctrlval = invol_ctrlval; +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiUpdateBalance(int ch, int bal) + */ +void SimpleSynth::guiUpdateBalance(int ch, int bal) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, ch, ME_CONTROLLER, SS_CHANNEL_PAN_CONTROLLER(ch), bal); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiUpdateVolume(int ch, int val) + */ +void SimpleSynth::guiUpdateVolume(int ch, int val) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_CHANNEL_VOLUME_CONTROLLER(ch), val); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiUpdateNoff(bool b) + */ +void SimpleSynth::guiUpdateNoff(int ch, bool b) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_CHANNEL_NOFF_CONTROLLER(ch), b); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiUpdateChoff(int ch, bool b) + */ +void SimpleSynth::guiUpdateChoff(int ch, bool b) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_CHANNEL_ONOFF_CONTROLLER(ch), b); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiUpdateMasterVol(int val) + */ +void SimpleSynth::guiUpdateMasterVol(int val) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_MASTER_CTRL_VOLUME, val); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + +/*! +    \fn SimpleSynth::guiUpdateSendFxLevel(int fxid, int level) + */ +void SimpleSynth::guiUpdateSendFxLevel(int channel, int fxid, int level) +      { +      SS_TRACE_IN +      MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, SS_CHANNEL_SENDFX_CONTROLLER(channel, fxid), level); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiSendSampleLoaded(int ch, const char* filename) + */ +void SimpleSynth::guiSendSampleLoaded(bool success, int ch, const char* filename) +      { +      SS_TRACE_IN +      int len = strlen(filename) + 3; //2 + filenamelen + 1; +      byte out[len]; + +      if (success) { +            out[0] = SS_SYSEX_LOAD_SAMPLE_OK; +            } +      else { +            out[0] = SS_SYSEX_LOAD_SAMPLE_ERROR; +            } +      out[1] = ch; +      memcpy(out+2, filename, strlen(filename)+1); +      MidiPlayEvent ev(0, 0, ME_SYSEX, out, len); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiSendError(const char* errorstring) + */ +void SimpleSynth::guiSendError(const char* errorstring) +      { +      SS_TRACE_IN +      byte out[strlen(errorstring)+2]; +      out[0] = SS_SYSEX_ERRORMSG; +      memcpy(out+1, errorstring, strlen(errorstring) +1); +      SS_TRACE_OUT +      } + +extern "C" +      { +      static MESS descriptor = { +            "SimpleSynth", +            "Mathias Lundgren (lunar_shuttle@users.sf.net)", +            "0.1",      //Version string +            MESS_MAJOR_VERSION, MESS_MINOR_VERSION, +            instantiate, +            }; +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) + +      __attribute__ ((visibility("default"))) +      const MESS* mess_descriptor() { return &descriptor; } +      } + + +/*! +    \fn SimpleSynth::initSendEffect(int sendeffectid, QString lib, QString name) + */ +bool SimpleSynth::initSendEffect(int id, QString lib, QString name) +      { +      SS_TRACE_IN +      bool success = false; +      if (sendEffects[id].plugin) { +            //Cleanup if one was already there: +            cleanupPlugin(id); +            } +      sendEffects[id].plugin  = (LadspaPlugin*) plugins.find(lib, name); +      LadspaPlugin* plugin = sendEffects[id].plugin; +      if (plugin) { //We found one + +            sendEffects[id].inputs  = plugin->inports(); +            sendEffects[id].outputs = plugin->outports(); + +            if (plugin->instantiate()) { +                  SS_DBG2("Plugin instantiated", name.toLatin1().data()); +                  SS_DBG_I("Parameters", plugin->parameter()); +                  SS_DBG_I("No of inputs", plugin->inports()); +                  SS_DBG_I("No of outputs",plugin->outports()); +                  SS_DBG_I("Inplace-capable", plugin->inPlaceCapable()); + +                  // Connect inputs/outputs: +                  // If single output/input, only use first channel in sendFxLineOut/sendFxReturn +                  SS_DBG("Connecting ports..."); +                  plugin->connectInport(0, sendFxLineOut[id][0]); +                  if (plugin->inports() == 2) +                        plugin->connectInport(1, sendFxLineOut[id][1]); +                  else if (plugin->inports() > 2) { +                        fprintf(stderr, "Plugin has more than 2 inputs, not supported\n"); +                        } + +                  plugin->connectOutport(0, sendFxReturn[id][0]); +                  if (plugin->outports() == 2) +                        plugin->connectOutport(1, sendFxReturn[id][1]); +                  else if (plugin->outports() > 2) { +                        fprintf(stderr, "Plugin has more than 2 outputs, not supported\n"); +                        } +                  SS_DBG("Ports connected"); +                  if (plugin->start()) { +                        sendEffects[id].state = SS_SENDFX_ON; +                        success = true; + +                        int n = plugin->parameter(); +                        sendEffects[id].nrofparameters = n; + +                        // This is not nice, but freeverb doesn't want to play until some values are set: +                        if (name == "freeverb3") { +                              setFxParameter(id, 2, 0.5); +                              setFxParameter(id, 3, 0.5); +                              setFxParameter(id, 4, 0.5); +                              guiUpdateFxParameter(id, 2, 0.5); +                              guiUpdateFxParameter(id, 3, 0.5); +                              guiUpdateFxParameter(id, 4, 0.5); +                              } +                        } +                  //TODO: cleanup if failed +                  } +            } +      //Notify gui +      int len = 3; +      byte out[len]; +      out[0] = SS_SYSEX_LOAD_SENDEFFECT_OK; +      out[1] = id; +      int j=0; +      for (iPlugin i = plugins.begin(); i!=plugins.end(); i++, j++) { +            if ((*i)->lib() == plugin->lib() && (*i)->label() == plugin->label()) { +                  out[2] = j; +                  MidiPlayEvent ev(0, 0, ME_SYSEX, out, len); +                  gui->writeEvent(ev); +                  } +            } + +      if (!success) { +            QString errorString = "Error loading plugin \"" + plugin->label() + "\""; +            guiSendError(errorString.toLatin1().data()); +            } +      return success; +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::setSendFxLevel(int channel, int effectid, double val) + */ +void SimpleSynth::setSendFxLevel(int channel, int effectid, double val) +      { +      SS_TRACE_IN +      channels[channel].sendfxlevel[effectid] = val; +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::cleanupPlugin(int id) + */ +void SimpleSynth::cleanupPlugin(int id) +      { +      SS_TRACE_IN +      LadspaPlugin* plugin = sendEffects[id].plugin; +      plugin->stop(); +      SS_DBG2("Stopped fx", plugin->label().toLatin1().data()); +      sendEffects[id].nrofparameters = 0; +      sendEffects[id].state = SS_SENDFX_OFF; +      sendEffects[id].plugin = 0; + +      byte d[2]; +      d[0] = SS_SYSEX_CLEAR_SENDEFFECT_OK; +      d[1] = id; +      MidiPlayEvent ev(0, 0, ME_SYSEX, d, 2); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::setFxParameter(int fxid, int param, float val) +    \brief Set fx-parameter on plugin and notify gui + */ +void SimpleSynth::setFxParameter(int fxid, int param, float val) +      { +      SS_TRACE_IN +      LadspaPlugin* plugin = sendEffects[fxid].plugin; +      if (SS_DEBUG_LADSPA) { +            printf("Setting fx parameter: %f\n", val); +            } +      plugin->setParam(param, val); +      //sendEffects[fxid].parameter[param] = val; +      //guiUpdateFxParameter(fxid, param, val); +      SS_TRACE_OUT +      } + + + +/*! +    \fn SimpleSynth::guiUpdateFxParameter(int fxid, int param, float val) +    \brief Notify gui of changed fx-parameter + */ +void SimpleSynth::guiUpdateFxParameter(int fxid, int param, float val) +      { +      SS_TRACE_IN +      LadspaPlugin* plugin = sendEffects[fxid].plugin; +      float min, max; +      plugin->range(param, &min, &max); +      //offset: +      val-= min; + +      int intval = plugin->getGuiControlValue(param); +      /*if (plugin->isLog(param)) { +            intval = SS_map_logdomain2pluginparam(logf(val/(max - min) + min)); +            } +      else if (plugin->isBool(param)) { +            intval = (int) val; +            } +      else { +            float scale = SS_PLUGIN_PARAM_MAX / (max - min); +            intval = (int) ((val - min) * scale); +            }*/ +      if (SS_DEBUG_MIDI) { +            printf("Updating gui, fx parameter. fxid=%d, param=%d val=%d\n", fxid, param, intval); +            } + +      byte d[4]; +      d[0] = SS_SYSEX_SET_PLUGIN_PARAMETER_OK; +      d[1] = fxid; +      d[2] = param; +      d[3] = intval; +      MidiPlayEvent ev(0, 0, ME_SYSEX, d, 4); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::clearSample(int ch) +    \brief Clears a sample (actually clears a channel) + */ +void SimpleSynth::clearSample(int ch) +      { +      SS_TRACE_IN +      if (channels[ch].sample) { +            if (SS_DEBUG) +                  printf("Clearing sample on channel %d\n", ch); +            SS_State prevstate = synth_state; +            SWITCH_CHAN_STATE(ch, SS_CHANNEL_INACTIVE); +            SWITCH_SYNTH_STATE(SS_CLEARING_SAMPLE); +            if (channels[ch].sample->data) { +                  delete[] channels[ch].sample->data; +                  channels[ch].sample->data = 0; +                  } +            if (channels[ch].sample) { +                  delete channels[ch].sample; +                  channels[ch].sample = 0; +                  } +            SWITCH_SYNTH_STATE(prevstate); +            guiNotifySampleCleared(ch); +            if (SS_DEBUG) { +                  printf("Clear sample - sample cleared on channel %d\n", ch); +                  } +            } +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynth::guiNotifySampleCleared(int ch) + */ +void SimpleSynth::guiNotifySampleCleared(int ch) +      { +      SS_TRACE_IN +      byte d[2]; +      d[0] = SS_SYSEX_CLEAR_SAMPLE_OK; +      d[1] = (byte) ch; +      MidiPlayEvent ev(0, 0, ME_SYSEX, d, 2); +      gui->writeEvent(ev); +      SS_TRACE_OUT +      } diff --git a/muse2/synti/simpledrums2/simpledrums.h b/muse2/synti/simpledrums2/simpledrums.h new file mode 100644 index 00000000..f9463800 --- /dev/null +++ b/muse2/synti/simpledrums2/simpledrums.h @@ -0,0 +1,173 @@ +// +// C++ Interface: simplesynth +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef SIMPLESYNTH_H +#define SIMPLESYNTH_H + +#include <sndfile.h> +#include "libsynti/mess.h" +#include "common.h" +#include "libsynti/mpevent.h" +#include "simpledrumsgui.h" +#include "ssplugin.h" + +#define SS_NO_SAMPLE       0 +#define SS_NO_PLUGIN       0 + +#define SS_PROCESS_BUFFER_SIZE 4096 //TODO: Add initialization method for nr of frames in each process from MusE - if nr of frames > than this, this will fail +#define SS_SENDFX_BUFFER_SIZE  SS_PROCESS_BUFFER_SIZE + +enum SS_ChannelState +   { +      SS_CHANNEL_INACTIVE=0, +      SS_SAMPLE_PLAYING, +   }; + +enum SS_State +   { +      SS_INITIALIZING=0, +      SS_LOADING_SAMPLE, +      SS_CLEARING_SAMPLE, +      SS_RUNNING, +   }; + +enum SS_SendFXState +   { +      SS_SENDFX_OFF=0, +      SS_SENDFX_ON +   }; + +struct SS_SendFx +   { +      SS_SendFXState state; +      LadspaPlugin*  plugin; +      int            inputs; +      int            outputs; +      int            retgain_ctrlval; +      double         retgain; +      int            nrofparameters; +   }; + +struct SS_Sample +   { +      float*      data; +      int         samplerate; +      int         bits; +      std::string filename; +      long        samples; +      long        frames; +      int         channels; +      SF_INFO     sfinfo; +   }; + +struct SS_Channel +   { +      SS_ChannelState state; +      const char*     name; +      SS_Sample*      sample; +      int             playoffset; +      bool            noteoff_ignore; + +      double          volume; +      int             volume_ctrlval; + +      double          cur_velo; +      double          gain_factor; + +      int             pan; +      double          balanceFactorL; +      double          balanceFactorR; + +      bool            channel_on; + +      //Send fx: +      double          sendfxlevel[SS_NR_OF_SENDEFFECTS]; +   }; + +struct SS_Controller +   { +      std::string name; +      int num; +      int min, max; +   }; + +struct SS_SampleLoader +   { +      SS_Channel*  channel; +      std::string  filename; +      int          ch_no; +   }; + +class SimpleSynth : public Mess +   { +   public: +      SimpleSynth(int); + +      virtual ~SimpleSynth(); + +      virtual bool guiVisible() const; +      virtual bool hasGui() const; +      virtual bool playNote(int arg1, int arg2, int arg3); +      virtual bool processEvent(const MidiPlayEvent& arg1); +      virtual bool setController(int arg1, int arg2, int arg3); +      virtual bool sysex(int arg1, const unsigned char* arg2); +      virtual const char* getPatchName(int arg1, int arg2, int arg3) const; +      virtual const MidiPatch* getPatchInfo(int arg1, const MidiPatch* arg2) const; +      virtual int getControllerInfo(int arg1, const char** arg2, int* arg3, int* arg4, int* arg5); +      virtual void process(float** data, int offset, int len); +      virtual void showGui(bool arg1); +      virtual void getInitData(int*, const unsigned char**); +      bool init(const char* name); +      void guiSendSampleLoaded(bool success, int ch, const char* filename); +      void guiSendError(const char* errorstring); + +      static const char* synth_state_descr[]; +      static const char* channel_state_descr[]; + +private: +      SimpleSynthGui* gui; + +      SS_Channel channels[SS_NR_OF_CHANNELS]; +      SS_Controller controllers[SS_NR_OF_CONTROLLERS]; +      bool setController(int channel, int id, int val, bool fromGui); +      bool loadSample(int ch_no, const char* filename); +      void parseInitData(const unsigned char* data); +      void updateVolume(int ch, int in_volume_ctrlval); +      void updateBalance(int ch, int pan); +      void guiNotifySampleCleared(int ch); +      void guiUpdateBalance(int ch, int bal); +      void guiUpdateVolume(int ch, int val); +      void guiUpdateNoff(int ch, bool b); +      void guiUpdateChoff(int ch, bool b); +      void guiUpdateMasterVol(int val); +      void guiUpdateFxParameter(int fxid, int param, float val); +      void guiUpdateSendFxLevel(int channel, int fxid, int level); +      bool initSendEffect(int sendeffectid, QString lib, QString name); +      void setSendFxLevel(int channel, int effectid, double val); +      void cleanupPlugin(int id); +      void setFxParameter(int fxid, int param, float val); +      void clearSample(int ch); +      double master_vol; +      int master_vol_ctrlval; + +      //Send effects: +      SS_SendFx sendEffects[SS_NR_OF_SENDEFFECTS]; +      float* sendFxLineOut[SS_NR_OF_SENDEFFECTS][2]; //stereo output (fed into LADSPA inputs),sent from the individual channels -> LADSPA fx +      float* sendFxReturn[SS_NR_OF_SENDEFFECTS][2];  //stereo inputs, from LADSPA plugins, sent from LADSPA -> SS and added to the mix +      double* processBuffer[2]; +   }; + +static void* loadSampleThread(void*); +static pthread_mutex_t SS_LoaderMutex; +static SS_State synth_state; +static SimpleSynth* simplesynth_ptr; + +#endif diff --git a/muse2/synti/simpledrums2/simpledrumsgui.cpp b/muse2/synti/simpledrums2/simpledrumsgui.cpp new file mode 100644 index 00000000..ab511cec --- /dev/null +++ b/muse2/synti/simpledrums2/simpledrumsgui.cpp @@ -0,0 +1,890 @@ +// +// C++ Implementation: testogui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include <QButtonGroup> +#include <QLabel> +#include <QFileDialog> +#include <QSocketNotifier> +#include <QLayout> +#include <QToolTip> +#include <QLineEdit> +#include <QMessageBox> + +#include "simpledrumsgui.h" +#include "libsynti/mpevent.h" +#include "muse/midi.h" +#include "ssplugingui.h" + +#define SS_VOLUME_MIN_VALUE                     0 +#define SS_VOLUME_MAX_VALUE                   127 +#define SS_VOLUME_DEFAULT_VALUE               100 +#define SS_MASTERVOL_MAX_VALUE                127 +#define SS_MASTERVOL_DEFAULT_VALUE    100.0/127.0 +#define SS_SENDFX_MIN_VALUE                     0 +#define SS_SENDFX_MAX_VALUE                   127 + +//Gui constants: +#define SS_BTNGRP_WIDTH                        50 +#define SS_BTNGRP_HEIGHT                       80 +#define SS_ONOFF_WIDTH                         16 +#define SS_ONOFF_HEIGHT                        21 +#define SS_VOLSLDR_WIDTH                       (SS_BTNGRP_WIDTH - 8) +#define SS_VOLSLDR_LENGTH                     120 +#define SS_PANSLDR_WIDTH                       (SS_BTNGRP_WIDTH - 8) +#define SS_PANSLDR_LENGTH                      20 +#define SS_PANSLDR_DEFAULT_VALUE               63 +#define SS_NONOFF_LABEL_WIDTH                  30 +#define SS_NONOFF_LABEL_HEIGHT                 16 +#define SS_NONOFF_WIDTH                        SS_ONOFF_WIDTH +#define SS_NONOFF_HEIGHT                       SS_ONOFF_HEIGHT +#define SS_SENDFX_WIDTH                        ((SS_BTNGRP_WIDTH/2) - 4) +//#define SS_SENDFX_WIDTH                        28 +#define SS_SENDFX_HEIGHT                       SS_SENDFX_WIDTH +#define SS_MASTERSLDR_WIDTH                    (SS_BTNGRP_WIDTH - 8) +#define SS_MASTERSLDR_HEIGHT                   (SS_BTNGRP_HEIGHT - 4) + + +// Sample groupbox + +#define SS_SAMPLENAME_LABEL_WIDTH              30 +#define SS_SAMPLENAME_LABEL_HEIGHT             21 +#define SS_SAMPLENAME_LABEL_XOFF                4 + +#define SS_SAMPLE_LOAD_WIDTH                   15 +#define SS_SAMPLE_LOAD_HEIGHT                  19 + +#define SS_SAMPLE_CLEAR_WIDTH                   SS_SAMPLE_LOAD_WIDTH +#define SS_SAMPLE_CLEAR_HEIGHT                  SS_SAMPLE_LOAD_HEIGHT + +#define SS_SAMPLENAME_LINEEDIT_WIDTH           90 +#define SS_SAMPLENAME_LINEEDIT_HEIGHT          21 + +#define SS_SAMPLE_INFO_LINE_HEIGHT             22 +#define SS_SAMPLE_INFO_LINE_WIDTH               (SS_SAMPLENAME_LINEEDIT_XOFF + SS_SAMPLENAME_LINEEDIT_WIDTH) + +#define SS_GUI_WINDOW_WIDTH                     ((SS_NR_OF_CHANNELS +1) * SS_BTNGRP_XOFF) +#define SS_MAIN_GROUPBOX_HEIGHT                 200 +#define SS_GUI_WINDOW_HEIGHT                    (SS_BTNGRP_HEIGHT + SS_MAIN_GROUPBOX_HEIGHT) +#define SS_MAIN_GROUPBOX_WIDTH                  SS_GUI_WINDOW_WIDTH + +SimpleSynthGui* simplesynthgui_ptr; + + +/*! +    \fn QChannelSlider::QChannelSlider(Qt::Orientation orientation, int ch, QWidget* parent, const char* name) + */ +QChannelSlider::QChannelSlider(Qt::Orientation orientation, int ch, QWidget* parent) +      : QSlider(orientation, parent) +      { +      channel = ch; +      } + + +/*! +    \fn QChannelSlider::getChannel() + */ +int QChannelSlider::getChannel() +      { +      return channel; +      } + + +/*! +    \fn QChannelSlider::setChannel(int ch) + */ +void QChannelSlider::setChannel(int ch) +      { +      channel = ch; +      } + +/*! +    \fn QChannelSlider::setValue(int val) + */ +void QChannelSlider::setValue(int val) +      { +      val = (val > 127 ? 127 : val); +      val = (val < 0 ? 0 : val); +      QSlider::setValue(val); +      emit valueChanged(channel, val); +      } + +/*! +    \fn QInvertedChannelSlider::setValue(int val) + */ +void QInvertedChannelSlider::setValue(int val) +      { +      int inverted = this->maximum() - val; +      inverted = (inverted > 127 ? 127 : inverted); +      inverted = (inverted < 0 ? 0 : inverted); +      QSlider::setValue(val); +      emit valueChanged(channel, inverted); +      } + +/*! +    \fn QInvertedSlider::setValue(int val) + */ +void QInvertedSlider::setValue(int val) +      { +      int inverted = this->maximum() - val; +      inverted = (inverted > 127 ? 127 : inverted); +      inverted = (inverted < 0 ? 0 : inverted); +      emit invertedValueChanged(inverted); +      QSlider::setValue(val); +      } + + +/*! +    \fn QChannelCheckbox::QChannelCheckbox(QWidget* parent, int ch) + */ +QChannelCheckbox::QChannelCheckbox(QWidget* parent, int ch) +   : QCheckBox(parent) +      { +      channel = ch; +      connect(this, SIGNAL(clicked()), SLOT(isClicked())); +      } + + +/*! +    \fn QChannelCheckbox::isClicked() + */ +void QChannelCheckbox::isClicked() +      { +      emit channelState(channel, this->isChecked()); +      } + +/*! +    \fn QChannelButton::QChannelButton(QWidget* parent, const char* text, int ch, const char* name) + */ +QChannelButton::QChannelButton(QWidget* parent, const char* text, int ch) +      : QPushButton(parent), channel (ch) +      { +      connect(this, SIGNAL(clicked()), SLOT(isClicked())); +      setText(text); +      } + +/*! +    \fn QChannelButton::isClicked() + */ +void QChannelButton::isClicked() +      { +      emit channelState(channel, this->isChecked()); +      } + +/*! +    \fn QChannelDial() + */ +QChannelDial::QChannelDial(QWidget* parent, int ch, int fxid) +   : QDial(parent) +      { +      setTracking(true); +      channel = ch; +      sendfxid = fxid; +      } + +/*! +    \fn QChannelSlider::setValue(int val) + */ +void QChannelDial::setValue(int val) +      { +      QDial::setValue(val); +      emit valueChanged(channel, sendfxid, val); +      } + +/*! +    \fn SimpleSynthGui::SimpleSynthGui() + */ +SimpleSynthGui::SimpleSynthGui() +      { +      SS_TRACE_IN +      setupUi(this); +      simplesynthgui_ptr = this; +      pluginGui = new SS_PluginGui(this); +      pluginGui->hide(); + +      QVBoxLayout* mainLayout = new QVBoxLayout(this); //, 3); +      QHBoxLayout* channelLayout = new QHBoxLayout; +      mainLayout->addLayout(channelLayout); + +      //this->setFixedWidth(SS_GUI_WINDOW_WIDTH); +      //this->setFixedHeight(SS_GUI_WINDOW_HEIGHT); +      for (int i=0; i<SS_NR_OF_CHANNELS; i++) { +            channelButtonGroups[i] = new QGroupBox(this); +//            channelButtonGroups[i]->setMinimumSize(SS_BTNGRP_WIDTH, SS_BTNGRP_HEIGHT); +            channelButtonGroups[i]->setTitle(QString::number(i + 1)); + +            QString name = QString("volumeSlider"); +            name.append(i + 1); + +            channelLayout->addWidget(channelButtonGroups[i]); + +            QVBoxLayout* inchnlLayout = new QVBoxLayout(channelButtonGroups[i]); //, 2, 0, "channelinternallayout"); +            inchnlLayout->setAlignment(Qt::AlignHCenter); + +            onOff[i] = new QChannelCheckbox(channelButtonGroups[i], i); +//            onOff[i]->setMinimumSize(SS_ONOFF_WIDTH, SS_ONOFF_HEIGHT); +            onOff[i]->setToolTip("Channel " + QString::number(i + 1) + " on/off"); +            inchnlLayout->addWidget(onOff[i]); +            connect(onOff[i], SIGNAL(channelState(int, bool)), SLOT(channelOnOff(int, bool))); + +            volumeSliders[i] = new QInvertedChannelSlider(Qt::Vertical, i, channelButtonGroups[i]); +            volumeSliders[i]->setMinimum(SS_VOLUME_MIN_VALUE); +            volumeSliders[i]->setMaximum(SS_VOLUME_MAX_VALUE); +            volumeSliders[i]->setValue(SS_VOLUME_MAX_VALUE - SS_VOLUME_DEFAULT_VALUE); +//            volumeSliders[i]->setMinimumSize(SS_VOLSLDR_WIDTH, SS_VOLSLDR_LENGTH); +            volumeSliders[i]->setToolTip("Volume, channel " + QString::number(i + 1)); +//            setMinimumSize(SS_VOLSLDR_WIDTH, SS_VOLSLDR_LENGTH); +            inchnlLayout->addWidget(volumeSliders[i]); +            connect(volumeSliders[i], SIGNAL(valueChanged(int, int)), SLOT(volumeChanged(int, int))); + +            nOffLabel[i] = new QLabel(channelButtonGroups[i]); +//            nOffLabel[i]->setMinimumSize(SS_NONOFF_LABEL_WIDTH, SS_NONOFF_LABEL_HEIGHT); +            nOffLabel[i]->setText("nOff"); +            inchnlLayout->addWidget(nOffLabel[i]); + +            nOffIgnore[i] = new QChannelCheckbox(channelButtonGroups[i], i); +//            nOffIgnore[i]->setMinimumSize(SS_NONOFF_WIDTH, SS_NONOFF_HEIGHT); +            nOffIgnore[i]->setToolTip("Note off ignore, channel " + QString::number(i + 1)); +            inchnlLayout->addWidget(nOffIgnore[i]); +            connect(nOffIgnore[i], SIGNAL(channelState(int, bool)),SLOT(channelNoteOffIgnore(int, bool))); + +            panSliders[i] = new QChannelSlider(Qt::Horizontal, i, channelButtonGroups[i]); +            panSliders[i]->setRange(0, 127); +            panSliders[i]->setValue(SS_PANSLDR_DEFAULT_VALUE); +//            panSliders[i]->setMinimumSize(SS_PANSLDR_WIDTH, SS_PANSLDR_LENGTH); +            panSliders[i]->setToolTip("Pan, channel " + QString::number(i + 1)); +            inchnlLayout->addWidget(panSliders[i]); +            connect(panSliders[i], SIGNAL(valueChanged(int, int)), SLOT(panChanged(int, int))); + +            QGridLayout* dialGrid = new QGridLayout; +            inchnlLayout->addLayout(dialGrid); +            sendFxDial[i][0] = new QChannelDial(channelButtonGroups[i], i, 0); +            sendFxDial[i][0]->setRange(0, 127); +            sendFxDial[i][0]->setMaximumSize(SS_SENDFX_WIDTH, SS_SENDFX_HEIGHT); +            sendFxDial[i][0]->setToolTip("Fx 1 send amount"); +            //inchnlLayout->addWidget(sendFxDial[i][0]); +            dialGrid->addWidget(sendFxDial[i][0], 0, 0, Qt::AlignCenter | Qt::AlignTop); + +            connect(sendFxDial[i][0], SIGNAL(valueChanged(int, int, int)), SLOT(sendFxChanged(int, int, int))); + +            sendFxDial[i][1] = new QChannelDial(channelButtonGroups[i], i, 1); +            sendFxDial[i][1]->setRange(0, 127); +            //inchnlLayout->add(sendFxDial[i][1]); +            dialGrid->addWidget(sendFxDial[i][1], 0, 1, Qt::AlignCenter | Qt::AlignTop); +            sendFxDial[i][1]->setMaximumSize(SS_SENDFX_WIDTH, SS_SENDFX_HEIGHT); +            sendFxDial[i][1]->setToolTip("Fx 2 send amount"); + +            connect(sendFxDial[i][1], SIGNAL(valueChanged(int, int, int)), SLOT(sendFxChanged(int, int, int))); + +            sendFxDial[i][2] = new QChannelDial(channelButtonGroups[i], i, 2); +            sendFxDial[i][2]->setRange(0, 127); +            sendFxDial[i][2]->setMaximumSize(SS_SENDFX_WIDTH, SS_SENDFX_HEIGHT); +            //inchnlLayout->add(sendFxDial[i][2]); +            dialGrid->addWidget(sendFxDial[i][2], 1, 0, Qt::AlignCenter | Qt::AlignTop); +            sendFxDial[i][2]->setToolTip("Fx 3 send amount"); +            connect(sendFxDial[i][2], SIGNAL(valueChanged(int, int, int)), SLOT(sendFxChanged(int, int, int))); + +            sendFxDial[i][3] = new QChannelDial(channelButtonGroups[i], i, 3); +            sendFxDial[i][3]->setRange(0, 127); +            sendFxDial[i][3]->setMaximumSize(SS_SENDFX_WIDTH, SS_SENDFX_HEIGHT); +            sendFxDial[i][3]->setToolTip("Fx 4 send amount"); + +            dialGrid->addWidget(sendFxDial[i][3], 1, 1, Qt::AlignCenter | Qt::AlignTop); +            connect(sendFxDial[i][3], SIGNAL(valueChanged(int, int, int)), SLOT(sendFxChanged(int, int, int))); +            inchnlLayout->activate(); +            //channelLayout->activate(); +            } + +      //Master buttongroup: +      masterButtonGroup = new QGroupBox(this); +      channelLayout->addWidget(masterButtonGroup); +      QVBoxLayout* mbgLayout = new QVBoxLayout(masterButtonGroup); +      mbgLayout->setAlignment(Qt::AlignCenter); +//      masterButtonGroup->setMinimumSize(SS_BTNGRP_WIDTH, SS_BTNGRP_HEIGHT); +      masterSlider = new QInvertedSlider(Qt::Vertical, masterButtonGroup); +      masterSlider->setToolTip("Master volume"); +      mbgLayout->addWidget(masterSlider); +      masterSlider->setRange(0, 127); +      masterSlider->setValue(SS_VOLUME_MAX_VALUE - (int)(SS_MASTERVOL_DEFAULT_VALUE*SS_VOLUME_MAX_VALUE)); +//      masterSlider->setMinimumSize(SS_MASTERSLDR_WIDTH, SS_MASTERSLDR_HEIGHT); +      connect(masterSlider, SIGNAL(invertedValueChanged(int)), SLOT(masterVolChanged(int))); + +      //Main groupbox +      mainGroupBox = new QGroupBox(this); +      mainLayout->addWidget(mainGroupBox); + +      QGridLayout* mgbLayout = new QGridLayout(mainGroupBox); // , 8, 3, 1); + +      int i=0; + +      for (int c=0; c<2; c++) { +            for (int r=0; r<SS_NR_OF_CHANNELS/2; r++) { +                  QHBoxLayout* strip = new QHBoxLayout;//(mgbLayout, 5); +                  mgbLayout->addLayout(strip, r, c); + +                  QLabel* channelLabel = new QLabel(QString("Ch ") + QString::number(i + 1), mainGroupBox); +                  strip->addWidget(channelLabel); + +                  sampleNameLineEdit[i] = new QLineEdit(mainGroupBox); +                  sampleNameLineEdit[i]->setReadOnly(true); +                  strip->addWidget(sampleNameLineEdit[i]); + +                  loadSampleButton[i] = new QChannelButton(mainGroupBox, "L", i); +//                  loadSampleButton[i]->setMinimumSize(SS_SAMPLE_LOAD_WIDTH, SS_SAMPLE_LOAD_HEIGHT); +                  loadSampleButton[i]->setToolTip("Load sample on channel " + QString::number(i + 1)); +                  strip->addWidget(loadSampleButton[i]); +                  connect(loadSampleButton[i], SIGNAL(channelState(int, bool)), SLOT(loadSampleDialogue(int))); + +                  clearSampleButton[i] = new QChannelButton(mainGroupBox, "C", i); +//                  clearSampleButton[i]->setMinimumSize(SS_SAMPLE_CLEAR_WIDTH, SS_SAMPLE_CLEAR_HEIGHT); +                  clearSampleButton[i]->setToolTip("Clear sample on channel " + QString::number(i + 1)); +                  strip->addWidget(clearSampleButton[i]); +                  connect(clearSampleButton[i], SIGNAL(channelState(int, bool)), SLOT(clearSample(int))); + +                  i++; +                  } +            } + +      // Right bottom panel: +      QGroupBox* rbPanel= new QGroupBox(mainGroupBox); +      mgbLayout->addWidget(rbPanel, 1, 3, 7, 1, Qt::AlignCenter); +      QGridLayout* rbLayout = new QGridLayout(rbPanel); // 6, 1, 8, 5); + +      openPluginsButton = new QPushButton("&Send Effects"); +      openPluginsButton->setToolTip("Configure LADSPA send effects"); +      connect(openPluginsButton, SIGNAL(clicked()), SLOT(openPluginButtonClicked())); +      rbLayout->addWidget(openPluginsButton, 2, 1, Qt::AlignCenter | Qt::AlignVCenter); +      aboutButton = new QPushButton("About SimpleDrums"); +      connect(aboutButton, SIGNAL(clicked()), SLOT(aboutButtonClicked())); +//TD      rbLayout->addRowSpacing(3, 20); +      rbLayout->addWidget(aboutButton, 4, 1, Qt::AlignLeft | Qt::AlignVCenter); + + +      loadButton = new QPushButton(tr("&Load setup"), rbPanel); +      connect(loadButton, SIGNAL(clicked()), SLOT(loadSetup())); +      saveButton = new QPushButton(tr("&Save setup"), rbPanel); +      connect(saveButton, SIGNAL(clicked()), SLOT(saveSetup())); +      //rbLayout->addWidget(openPluginsButton, 1, 1, Qt::AlignCenter | Qt::AlignVCenter); +//      rbLayout->addRowSpacing(2, 20); +      rbLayout->addWidget(loadButton,  3, 1, Qt::AlignCenter | Qt::AlignVCenter); +      rbLayout->addWidget(saveButton,  4, 1, Qt::AlignCenter | Qt::AlignVCenter); +//      rbLayout->addRowSpacing(5, 20); +      rbLayout->addWidget(aboutButton, 6, 1, Qt::AlignCenter | Qt::AlignVCenter); + +      lastDir = ""; +      //Connect socketnotifier to fifo +      QSocketNotifier* s = new QSocketNotifier(readFd, QSocketNotifier::Read); +      connect(s, SIGNAL(activated(int)), SLOT(readMessage(int))); +      SS_TRACE_OUT +      } + +/*! +    \fn SimpleSynthGui::~SimpleSynthGui() + */ +SimpleSynthGui::~SimpleSynthGui() +      { +      SS_TRACE_IN +      simplesynthgui_ptr = 0; +      delete pluginGui; +      SS_TRACE_OUT +      } + +/*! +    \fn SimpleSynthGui::readMessage(int) + */ +void SimpleSynthGui::readMessage(int) +      { +      MessGui::readMessage(); +      } + +/*! +    \fn SimpleSynthGui::processEvent(const MidiPlayEvent& ev) + */ +void SimpleSynthGui::processEvent(const MidiPlayEvent& ev) +      { +      SS_TRACE_IN +      if (SS_DEBUG_MIDI) { +            printf("GUI received midi event\n"); +            } +      if (ev.type() == ME_CONTROLLER) { +            int id  = ev.dataA(); +            int val = ev.dataB(); + +            // Channel controllers: +            if (id >= SS_FIRST_CHANNEL_CONTROLLER && id <= SS_LAST_CHANNEL_CONTROLLER ) { +                  // Find out which channel we're dealing with: +                  id-= SS_FIRST_CHANNEL_CONTROLLER; +                  int ch = (id / SS_NR_OF_CHANNEL_CONTROLLERS); +                  id = (id % SS_NR_OF_CHANNEL_CONTROLLERS); + +                  int fxid = -1; + +                  if (SS_DEBUG_MIDI) { +                        printf("GUI received midi controller - id: %d val %d channel %d\n", id, val, ch); +                        } + +                  switch(id) { +                        case SS_CHANNEL_CTRL_VOLUME: +                              volumeSliders[ch]->blockSignals(true); +                              volumeSliders[ch]->setValue(SS_VOLUME_MAX_VALUE - val); +                              volumeSliders[ch]->blockSignals(false); +                              break; + +                        case SS_CHANNEL_CTRL_PAN: +                              panSliders[ch]->blockSignals(true); +                              panSliders[ch]->setValue(val); +                              panSliders[ch]->blockSignals(false); +                              break; + +                        case SS_CHANNEL_CTRL_NOFF: +                              nOffIgnore[ch]->blockSignals(true); +                              nOffIgnore[ch]->setChecked(val); +                              nOffIgnore[ch]->blockSignals(false); +                              break; + +                        case SS_CHANNEL_CTRL_ONOFF: +                              onOff[ch]->blockSignals(true); +                              onOff[ch]->setChecked(val); +                              onOff[ch]->blockSignals(false); +                              break; + +                        case SS_CHANNEL_SENDFX1: +                        case SS_CHANNEL_SENDFX2: +                        case SS_CHANNEL_SENDFX3: +                        case SS_CHANNEL_SENDFX4: +                              fxid = id - SS_CHANNEL_SENDFX1; +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui::processEvent - Channel sendfx, fxid: %d, val: %d\n", fxid, val); +                                    } +                              sendFxDial[ch][fxid]->blockSignals(true); +                              sendFxDial[ch][fxid]->setValue(val); +                              sendFxDial[ch][fxid]->blockSignals(false); +                              break; + +                        default: +                              if (SS_DEBUG_MIDI) +                                    printf("SimpleSynthGui::processEvent - unknown controller received: %d\n", id); +                        } +                  } +            // Master controllers: +            else if (id >= SS_FIRST_MASTER_CONTROLLER && id <= SS_LAST_MASTER_CONTROLLER) { +                  if (id == SS_MASTER_CTRL_VOLUME) { +                        masterSlider->blockSignals(true); +                        masterSlider->setValue(SS_MASTERVOL_MAX_VALUE - val); +                        masterSlider->blockSignals(false); +                        } +                  } +            else if (id>= SS_FIRST_PLUGIN_CONTROLLER && id <= SS_LAST_PLUGIN_CONTROLLER) { +                  int fxid = (id - SS_FIRST_PLUGIN_CONTROLLER) / SS_NR_OF_PLUGIN_CONTROLLERS; +                  int cmd = (id - SS_FIRST_PLUGIN_CONTROLLER) % SS_NR_OF_PLUGIN_CONTROLLERS; + +                  // Plugin return-gain: +                  if (cmd == SS_PLUGIN_RETURN) { +                        if (SS_DEBUG_MIDI) +                              printf("SimpleSynthGui::processEvent - fx retgain received: fxid: %d val: %d\n", fxid, val); + +                        SS_PluginFront* pf = pluginGui->getPluginFront((unsigned)fxid); +                        pf->setRetGain(val); +                        } +                  } +            } +            // +            // Sysexes: +            // +            else if (ev.type() == ME_SYSEX) { +                  byte* data = ev.data(); +                  int cmd = *data; +                  switch (cmd) { +                        case SS_SYSEX_LOAD_SAMPLE_OK: { +                              int ch = *(data+1); +                              QString filename = (const char*) (data+2); +                              sampleNameLineEdit[ch]->setText(filename.section('/',-1,-1)); +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui - sample %s loaded OK on channel: %d\n", filename.toLatin1().data(), ch); +                                    } +                              if (!onOff[ch]->isChecked()) { +                                    onOff[ch]->blockSignals(true); +                                    onOff[ch]->setChecked(true); +                                    onOff[ch]->blockSignals(false); +                                    channelOnOff(ch, true); +                                    } +                              break; +                              } + +                        case SS_SYSEX_LOAD_SAMPLE_ERROR: { +                              //int ch = *(data+1); +                              const char* filename = (const char*) (data+2); +                              /*QMessageBox* yn = new QMessageBox("Sample not found", "Failed to load sample: " + QString(filename) + "\n" + +                                                      "Do you want to open file browser and try to locate it elsewhere?", +                                                      QMessageBox::Warning, +                                                      QMessageBox::Yes, +                                                      QMessageBox::No, +                                                      QMessageBox::NoButton, +                                                      this);*/ +                              /*int res = QMessageBox::warning(this, +                                                      "SimpleDrums","Failed to load sample: " + QString(filename) + "\n" + +                                                      "Do you want to open file browser and try to locate it elsewhere?", +                                                      "&Yes", "&No"); +                                                      */ +                              //int res = yn->exec(); +                              printf("Error: Sample %s not found! TODO: Fix this\n", filename); +                              //if (res == 0) { +                              //      loadSampleDialogue(ch); +                              //      } +                              break; +                              } + +                        case SS_SYSEX_LOAD_SENDEFFECT_OK: { +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui - sysex load sendeffect OK on fxid: %d\n", *(data+1)); +                                    } +                              int fxid = *(data+1); +                              SS_PluginFront* pf = pluginGui->getPluginFront((unsigned)fxid); +                              pf->updatePluginValue(*(data+2)); +                              break; +                              } + +                        case SS_SYSEX_CLEAR_SENDEFFECT_OK: { +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui - sysex clear sendeffect OK on fxid: %d\n", *(data+1)); +                                    } +                              SS_PluginFront* pf = pluginGui->getPluginFront((unsigned)*(data+1)); +                              pf->clearPluginDisplay(); +                              break; +                              } + +                        case SS_SYSEX_CLEAR_SAMPLE_OK: { +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui - sysex clear samle OK on channel: %d\n", *(data+1)); +                                    } +                              byte ch = *(data+1); +                              sampleNameLineEdit[ch]->setText(""); +                              break; +                              } + +                        case SS_SYSEX_SET_PLUGIN_PARAMETER_OK: { +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui - plugin parameter OK on fxid: %d\n", *(data+1)); +                                    } +                              SS_PluginFront* pf = pluginGui->getPluginFront((unsigned)*(data+1)); +                              int param = *(data+2); +                              int val   = *(data+3); +                              pf->blockSignals(true); +                              pf->setParameterValue(param, val); +                              pf->blockSignals(false); +                              break; +                              } + +                        case SS_SYSEX_SEND_INIT_DATA: { +// FN: TODO +#if 1 +                              const unsigned initdata_len = ev.len() - 1; +                              byte* init_data = (data + 1); +                              QFileInfo fileInfo = QFileInfo(lastSavedProject); + +                              lastProjectDir = fileInfo.path(); +                              if (fileInfo.suffix() != "sds" && fileInfo.suffix() != "SDS") { +                                    lastSavedProject += ".sds"; +                                    fileInfo = QFileInfo(lastSavedProject); +                                    } +                              QFile theFile(fileInfo.filePath()); + +                              // Write data +                              if (theFile.open(QIODevice::WriteOnly)) { +                                    theFile.write((const char*)&initdata_len, sizeof(initdata_len)); // First write length +                                    if (theFile.write((const char*)init_data, initdata_len) == -1) { +                                          // Fatal error writing +                                          QMessageBox* msgBox = new QMessageBox(QMessageBox::Warning, "SimpleDrums error Dialog", "Fatal error when writing to file. Setup not saved.", +                                                QMessageBox::Ok, this); +                                          msgBox->exec(); +                                          delete msgBox; +                                          } +                                    theFile.close(); +                                    } +                              else { +                                    // An error occured when opening +                                    QMessageBox* msgBox = new QMessageBox(QMessageBox::Warning, "SimpleDrums error Dialog", "Error opening file. Setup was not saved.", +                                          QMessageBox::Ok, this); +                                    msgBox->exec(); +                                    delete msgBox; +                                    } +#endif + +                              break; +                              } + + +                        default: +                              if (SS_DEBUG_MIDI) { +                                    printf("SimpleSynthGui::processEvent - unknown sysex cmd received: %d\n", cmd); +                                    } +                              break; +                        } +                  } +      SS_TRACE_OUT +      } + + +/*! +    \fn SimpleSynthGui::volumeChanged(int val) + */ +void SimpleSynthGui::volumeChanged(int channel, int val) +      { +      setChannelVolume(channel, val); +      } + +/*! +    \fn SimpleSynthGui::panChanged(int channel, int value) + */ +void SimpleSynthGui::panChanged(int channel, int value) +      { +      sendController(0, SS_CHANNEL_PAN_CONTROLLER(channel), value); +      } + +/*! +    \fn SimpleSynthGui::channelOnOff(int channel, bool state) + */ +void SimpleSynthGui::channelOnOff(int channel, bool state) +      { +      sendController(0, SS_CHANNEL_ONOFF_CONTROLLER(channel), state); +      } + +/*! +    \fn SimpleSynthGui::channelNoteOffIgnore(bool state) + */ +void SimpleSynthGui::channelNoteOffIgnore(int channel, bool state) +      { +      sendController(0, SS_CHANNEL_NOFF_CONTROLLER(channel), (int) state); +      } + +/*! +    \fn SimpleSynthGui::sendFxChanged(int ch, int fxid, int val) + */ +void SimpleSynthGui::sendFxChanged(int ch, int fxid, int val) +      { +      sendController(0, SS_CHANNEL_SENDFX_CONTROLLER(ch, fxid), (int) val); +      } + +/*! +    \fn SimpleSynthGui::masterVolChanged(int val) + */ +void SimpleSynthGui::masterVolChanged(int val) +      { +      sendController(0, SS_MASTER_CTRL_VOLUME, val); +      } + +/*! +    \fn SimpleSynthGui::setChannelVolume(int channel, byte volume) + */ +void SimpleSynthGui::setChannelVolume(int channel, int volume) +      { +      //volumeSliders[channel]->setValue(SS_VOLUME_MAX_VALUE - volume); +      sendController(0, SS_CHANNEL_VOLUME_CONTROLLER(channel), (int)volume); +      } + + +/*! +    \fn SimpleSynthGui::loadSampleDialogue(int channel) + */ +void SimpleSynthGui::loadSampleDialogue(int channel) +      { +      QString filename = +            QFileDialog::getOpenFileName( +      					   this, +                                       tr("Load sample dialog"), +      					   lastDir, +                                       QString("*.wav *.WAV")); + +      if (filename != QString::null) { +            QFileInfo fi(filename); +            lastDir = fi.path(); + +            if (SS_DEBUG) +                  printf("lastDir = %s\n", lastDir.toLatin1().data()); + +            int l = filename.length() + 4; +            byte d[l]; + +            d[0] = SS_SYSEX_LOAD_SAMPLE; +            d[1] = (byte) channel; +            d[2] = (byte) filename.length(); +            memcpy(d+3, filename.toLatin1().data(), filename.length()+1); +            sendSysex(d, l); +            } +      } + + + +/*! +    \fn SimpleSynthGui::clearSample(int ch) + */ +void SimpleSynthGui::clearSample(int ch) +      { +      if (sampleNameLineEdit[ch]->text().length() > 0) { //OK, we've got a live one here +            byte d[2]; +            d[0] = SS_SYSEX_CLEAR_SAMPLE; +            d[1] = (byte) ch; +            sendSysex(d, 2); +            sampleNameLineEdit[ch]->setText(""); +            } +      } + +/*! +    \fn SimpleSynthGui::displayPluginGui() + */ +void SimpleSynthGui::displayPluginGui() +      { +      pluginGui->show(); +      } + +/*! +    \fn SimpleSynthGui::loadEffectInvoked(int fxid, QString lib, QString label) + */ +void SimpleSynthGui::loadEffectInvoked(int fxid, QString lib, QString label) +      { +      int l = 4 + lib.length() + label.length(); +      byte d[l]; +      d[0] = SS_SYSEX_LOAD_SENDEFFECT; +      d[1] = (byte) fxid; +      memcpy (d+2, lib.toLatin1().data(), lib.length()+1); +      memcpy (d+3+lib.length(), label.toLatin1().data(), label.length()+1); +      sendSysex(d, l); +      } + + +/*! +    \fn SimpleSynthGui::returnLevelChanged(int fxid, int val) + */ +void SimpleSynthGui::returnLevelChanged(int fxid, int val) +      { +      sendController(0, SS_PLUGIN_RETURNLEVEL_CONTROLLER(fxid), val); +      } + + +/*! +    \fn SimpleSynthGui::toggleEffectOnOff(int fxid, int state) + */ +void SimpleSynthGui::toggleEffectOnOff(int fxid, int state) +      { +      sendController(0, SS_PLUGIN_ONOFF_CONTROLLER(fxid), state); +      } + + +/*! +    \fn SimpleSynthGui::clearPlugin(int fxid) + */ +void SimpleSynthGui::clearPlugin(int fxid) +      { +      byte d[2]; +      d[0] = SS_SYSEX_CLEAR_SENDEFFECT; +      d[1] = fxid; +      sendSysex(d, 2); +      } + + +/*! +    \fn SimpleSynthGui::effectParameterChanged(int fxid, int parameter, int val) + */ +void SimpleSynthGui::effectParameterChanged(int fxid, int parameter, int val) +      { +      //printf("Gui: effectParameterChanged: %d %d %d\n", fxid, parameter, val); +      int len = 4; +      byte d[len]; +      d[0] = SS_SYSEX_SET_PLUGIN_PARAMETER; +      d[1] = (byte) fxid; +      d[2] = (byte) parameter; +      d[3] = (byte) val; +      sendSysex(d, len); +      } + + +/*! +    \fn SimpleSynthGui::openPluginButtonClicked() + */ +void SimpleSynthGui::openPluginButtonClicked() +      { +      if (pluginGui->isVisible()) +            pluginGui->raise(); +      else +            displayPluginGui(); +      } + + +/*! +    \fn SimpleSynthGui::aboutButtonClicked() + */ +void SimpleSynthGui::aboutButtonClicked() +      { +      QString caption = "SimpleDrums ver"; +      caption+= SS_VERSIONSTRING; +      QString text = caption + "\n\n(C) Copyright 2000-2004 Mathias Lundgren (lunar_shuttle@users.sf.net), Werner Schweer\nPublished under the GNU Public License"; +      QMessageBox* msgBox = new QMessageBox(caption, text, QMessageBox::NoIcon, +            QMessageBox::Ok, Qt::NoButton, Qt::NoButton, this); +      msgBox->exec(); +      } + + +/*! +    \fn SimpleSynthGui::loadSetup() +    \brief Load setup from file + */ +void SimpleSynthGui::loadSetup() +      { +      bool success = true; +      QString filename = +            QFileDialog::getOpenFileName(this, "Load setup dialog", lastProjectDir, +                                       QString("*.sds *.SDS")); + +      if (filename != QString::null) { +            QFile theFile(filename); +            if (theFile.open(QIODevice::ReadOnly)) { +                  unsigned initdata_len = 0; +                  if (theFile.read((char*)&initdata_len, sizeof(initdata_len)) == -1) +                     success = false; + +                  byte* init_data = new byte[initdata_len]; +                  if (theFile.read((char*)(init_data), initdata_len) == -1) +                     success = false; + +                  if (!success) { +                        QMessageBox* msgBox = new QMessageBox(QMessageBox::Warning, "SimpleDrums Error Dialog", "Error opening/reading from file. Setup not loaded.", +                              QMessageBox::Ok, this); +                        msgBox->exec(); +                        delete msgBox; +                        } +                  else { +                        sendSysex(init_data, initdata_len); +                        } + +                  delete[] init_data; +                  } +            } +      } + + +/*! +    \fn SimpleSynthGui::saveSetup() +    \brief Save setup to file + */ +void SimpleSynthGui::saveSetup() +      { +      QString filename = +            QFileDialog::getSaveFileName(this, "Save setup dialog", lastProjectDir, +                                       QString("*.sds *.SDS")); + +      if (filename != QString::null) { +            lastSavedProject = filename; +            byte d[1]; +            d[0] = SS_SYSEX_GET_INIT_DATA; +            sendSysex(d, 1); // Makes synth send gui initdata, where rest of the saving takes place +            } +      } + diff --git a/muse2/synti/simpledrums2/simpledrumsgui.h b/muse2/synti/simpledrums2/simpledrumsgui.h new file mode 100644 index 00000000..16a5caf5 --- /dev/null +++ b/muse2/synti/simpledrums2/simpledrumsgui.h @@ -0,0 +1,214 @@ +// +// C++ Interface: testogui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef __MUSE_TESTOGUI_H__ +#define __MUSE_TESTOGUI_H__ + +#include <QSlider> +#include <QCheckBox> +#include <QPushButton> +#include <QDial> +#include <QLabel> +//#include <QFileInfo> +#include <QGroupBox> + +#include "libsynti/gui.h" +#include "ui_simpledrumsguibase.h" +#include "common.h" + +class QButtonGroup; +class QLabel; +class SS_PluginGui; + +//-------------------------------------- +// QChannelSlider +//-------------------------------------- +class QChannelSlider: public QSlider +   { +   Q_OBJECT + +   public: +      QChannelSlider(Qt::Orientation, int ch, QWidget* paren = 0); +      int getChannel(); +      void setChannel(int ch); + +   public slots: +      virtual void setValue(int val); + +   signals: +      void valueChanged(int channel, int value); + +   protected: +      int channel; +   }; + +//-------------------------------------- +// QInvertedSlider +//-------------------------------------- +class QInvertedSlider : public QSlider +   { +   Q_OBJECT +   public: +      QInvertedSlider(Qt::Orientation o, QWidget* parent = 0) +         : QSlider(o, parent) {} + +   public slots: +      virtual void setValue(int val); + +   signals: +      void invertedValueChanged(int value); +   }; + +//-------------------------------------- +// QInvertedChannelSlider +//-------------------------------------- +class QInvertedChannelSlider : public QChannelSlider +   { +   Q_OBJECT +   public: +      QInvertedChannelSlider(Qt::Orientation o, int channel, QWidget* parent = 0) +         : QChannelSlider(o, channel, parent) {}; + +   public slots: +      virtual void setValue(int val); +   }; + + +//-------------------------------------- +// QChannelOnOff +//-------------------------------------- + +class QChannelCheckbox : public QCheckBox +   { +   Q_OBJECT +   public: +      QChannelCheckbox(QWidget* parent, int channel); + +   private: +      int channel; + +    private slots: +      void isClicked(); + +   signals: +      void channelState(int channel, bool state); +   }; + +//-------------------------------------- +// QChannelButton +//-------------------------------------- +class QChannelButton : public QPushButton +   { +   Q_OBJECT + +   private: +      int channel; + +   public: +      QChannelButton(QWidget* parent, const char* text, int ch); + +   private slots: +      void isClicked(); + +   signals: +      void channelState(int channel, bool state); + +   }; + +//-------------------------------------- +// QChannelDial +//-------------------------------------- + +class QChannelDial : public QDial +   { +   Q_OBJECT + +   public: +      QChannelDial(QWidget* parent, int ch, int fxid); + +   signals: +      void valueChanged(int channel, int fxid, int val); + +   public slots: +      virtual void setValue(int val); + +   protected: +      int channel; +      int sendfxid; +   }; + +//-------------------------------------- +// SimpleSynthGui - the Gui +//-------------------------------------- +class SimpleSynthGui : public QDialog, public Ui::SimpleDrumsGuiBase, public MessGui +   { +   Q_OBJECT +   private: +      // MESS interface: +      virtual void processEvent(const MidiPlayEvent& ev); +      void setChannelVolume(int channel, int volume); +      void displayPluginGui(); +      QGroupBox* channelButtonGroups[SS_NR_OF_CHANNELS]; +      QGroupBox*           masterButtonGroup; +      QGroupBox*              mainGroupBox; +      QInvertedChannelSlider* volumeSliders[SS_NR_OF_CHANNELS]; +      QChannelSlider*         panSliders[SS_NR_OF_CHANNELS]; +      QChannelCheckbox*       onOff[SS_NR_OF_CHANNELS]; +      QChannelCheckbox*       nOffIgnore[SS_NR_OF_CHANNELS]; +      QChannelButton*         loadSampleButton[SS_NR_OF_CHANNELS]; +      QChannelButton*         clearSampleButton[SS_NR_OF_CHANNELS]; +      QLabel*                 nOffLabel[SS_NR_OF_CHANNELS]; +      QLineEdit*              sampleNameLineEdit[SS_NR_OF_CHANNELS]; +      QInvertedSlider*        masterSlider; +      QChannelDial*           sendFxDial[SS_NR_OF_CHANNELS][SS_NR_OF_SENDEFFECTS]; + +      QPushButton*            openPluginsButton; +      QPushButton*            aboutButton; +      QPushButton*            loadButton; +      QPushButton*            saveButton; + + +      QString lastDir; +      QString lastSavedProject; +      QString lastProjectDir; +      SS_PluginGui* pluginGui; + +   public: +      SimpleSynthGui(); +      virtual ~SimpleSynthGui(); + +   public slots: +      void loadEffectInvoked(int fxid, QString lib, QString label); +      void returnLevelChanged(int fxid, int val); +      void toggleEffectOnOff(int fxid, int state); +      void clearPlugin(int fxid); +      void effectParameterChanged(int fxid, int parameter, int val); + +   private slots: +      void volumeChanged(int channel, int val); +      void panChanged(int channel, int value); +      void channelOnOff(int channel, bool state); +      void channelNoteOffIgnore(int channel, bool state); +      void masterVolChanged(int val); +      void loadSampleDialogue(int channel); +      void readMessage(int); +      void clearSample(int ch); +      void sendFxChanged(int ch, int fxid, int val); +      void openPluginButtonClicked(); +      void aboutButtonClicked(); +      void loadSetup(); +      void saveSetup(); + +   }; + +extern SimpleSynthGui* simplesynthgui_ptr; + +#endif diff --git a/muse2/synti/simpledrums2/simpledrumsguibase.ui b/muse2/synti/simpledrums2/simpledrumsguibase.ui new file mode 100644 index 00000000..412bfdf6 --- /dev/null +++ b/muse2/synti/simpledrums2/simpledrumsguibase.ui @@ -0,0 +1,23 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>SimpleDrumsGuiBase</class> + <widget class="QDialog" name="SimpleDrumsGuiBase" > +  <property name="geometry" > +   <rect> +    <x>0</x> +    <y>0</y> +    <width>602</width> +    <height>509</height> +   </rect> +  </property> +  <property name="windowTitle" > +   <string>DrumSynth 0.1</string> +  </property> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/muse2/synti/simpledrums2/ssplugin.cpp b/muse2/synti/simpledrums2/ssplugin.cpp new file mode 100644 index 00000000..7e8986e7 --- /dev/null +++ b/muse2/synti/simpledrums2/ssplugin.cpp @@ -0,0 +1,460 @@ +// +// C++ Implementation: plugin +// +// Description: +// +// +//  (C) Copyright 2000 Werner Schweer (ws@seh.de) +// Additions/modifications: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// Copyright: See COPYING file that comes with this distribution +// +// + +#include <QtCore> +#include <QtGui> +#include <stdlib.h> +#include <unistd.h> +#include <dlfcn.h> +#include "ssplugin.h" +#include "common.h" + +PluginList plugins; + + +Plugin::Plugin(const QFileInfo* f) +   : fi(*f) +      { +      } + +//--------------------------------------------------------- +//   loadPluginLib +//--------------------------------------------------------- + +static void loadPluginLib(QFileInfo* fi) +      { +      SS_TRACE_IN +      if (SS_DEBUG_LADSPA) { +            printf("loadPluginLib: %s\n", fi->fileName().toLatin1().data()); +            } +      void* handle = dlopen(fi->filePath().toAscii().data(), RTLD_NOW); +      if (handle == 0) { +            fprintf(stderr, "dlopen(%s) failed: %s\n", +              fi->filePath().toAscii().data(), dlerror()); +            return; +            } +      LADSPA_Descriptor_Function ladspa = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor"); + +      if (!ladspa) { +            const char *txt = dlerror(); +            if (txt) { +                  fprintf(stderr, +                        "Unable to find ladspa_descriptor() function in plugin " +                        "library file \"%s\": %s.\n" +                        "Are you sure this is a LADSPA plugin file?\n", +                        fi->filePath().toAscii().data(), +                        txt); +                  return;//exit(1); +                  } +            } +      const LADSPA_Descriptor* descr; +      for (int i = 0;; ++i) { +            descr = ladspa(i); +            if (descr == NULL) +                  break; +            plugins.push_back(new LadspaPlugin(fi, ladspa, descr)); +            } +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   loadPluginDir +//--------------------------------------------------------- + +static void loadPluginDir(const QString& s) +      { +      SS_TRACE_IN +      QDir pluginDir(s, QString("*.so"), 0, QDir::Files); +      if (pluginDir.exists()) { +            QFileInfoList list = pluginDir.entryInfoList(); +            int n = list.size(); +            for (int i = 0; i < n; ++i) { +                  QFileInfo fi = list.at(i); +                  loadPluginLib(&fi); +                  } +            } +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   initPlugins +//    search for LADSPA plugins +//--------------------------------------------------------- + +void SS_initPlugins() +      { +      SS_TRACE_IN +      //loadPluginDir(museGlobalLib + QString("/plugins")); + +      char* ladspaPath = getenv("LADSPA_PATH"); +      if (ladspaPath == 0) +            ladspaPath = "/usr/lib/ladspa:/usr/local/lib/ladspa"; + +      char* p = ladspaPath; +      while (*p != '\0') { +            char* pe = p; +            while (*pe != ':' && *pe != '\0') +                  pe++; + +            int n = pe - p; +            if (n) { +                  char* buffer = new char[n + 1]; +                  strncpy(buffer, p, n); +                  buffer[n] = '\0'; +                  loadPluginDir(QString(buffer)); +                  delete[] buffer; +                  } +            p = pe; +            if (*p == ':') +                  p++; +            } +      SS_TRACE_OUT +      } + + +//--------------------------------------------------------- +//   LadspaPlugin +//--------------------------------------------------------- + +LadspaPlugin::LadspaPlugin(const QFileInfo* f, +   const LADSPA_Descriptor_Function ldf, +   const LADSPA_Descriptor* d) +   : Plugin(f), ladspa(ldf), plugin(d) +      { +      SS_TRACE_IN +      _inports        = 0; +      _outports       = 0; +      _parameter      = 0; +      handle          = 0; +      active          = false; +      controls        = 0; +      inputs          = 0; +      outputs         = 0; + +      for (unsigned k = 0; k < plugin->PortCount; ++k) { +            LADSPA_PortDescriptor pd = d->PortDescriptors[k]; +            static const int CI = LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT; +            if ((pd &  CI) == CI) { +                  ++_parameter; +                  pIdx.push_back(k); +                  } +            else if (pd &  LADSPA_PORT_INPUT) { +                  ++_inports; +                  iIdx.push_back(k); +                  } +            else if (pd &  LADSPA_PORT_OUTPUT) { +                  ++_outports; +                  oIdx.push_back(k); +                  } +            } + +      /*if (SS_DEBUG_LADSPA) { +            printf("Label: %s\tLib: %s\tPortCount: %d\n", this->label().toLatin1().data(), this->lib().toLatin1().data(), plugin->PortCount); +            printf("LADSPA_PORT_CONTROL|LADSPA_PORT_INPUT: %d\t", pIdx.size()); +            printf("Input ports: %d\t", iIdx.size()); +            printf("Output ports: %d\n\n", oIdx.size()); +            }*/ + +      LADSPA_Properties properties = plugin->Properties; +      _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(properties); +      if (_inports != _outports) +            _inPlaceCapable = false; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   ~LadspaPlugin +//--------------------------------------------------------- +LadspaPlugin::~LadspaPlugin() +      { +      SS_TRACE_IN +      if (active) { +            stop(); +            } +      if (handle) { +         SS_DBG_LADSPA2("Cleaning up ", this->label().toLatin1().data()); +         plugin->cleanup(handle); +         } + +      //Free ports: +      if (controls) +            delete controls; +      if (inputs) +            delete inputs; +      if (outputs) +            delete outputs; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   instantiate +//--------------------------------------------------------- + +bool LadspaPlugin::instantiate() +      { +      bool success = false; +      handle = plugin->instantiate(plugin, SS_samplerate); +      success = (handle != NULL); +      if (success) +            SS_DBG_LADSPA2("Plugin instantiated", label().toLatin1().data()); +      return success; +      } + +//--------------------------------------------------------- +//   start +// activate and connect control ports +//--------------------------------------------------------- + +bool LadspaPlugin::start() +      { +      SS_TRACE_IN +      if (handle) { +            if (plugin->activate) { +                  plugin->activate(handle); +                  SS_DBG_LADSPA("Plugin activated"); +                  } +            active = true; +            } +      else { +            SS_DBG_LADSPA("Error trying to activate plugin - plugin not instantiated!"); +            SS_TRACE_OUT +            return false; +            } + +      //Connect ports: +      controls = new Port[_parameter]; + +      for (int k = 0; k < _parameter; ++k) { +            double val = defaultValue(k); +            controls[k].val    = val; +            plugin->connect_port(handle, pIdx[k], &controls[k].val); +            } + +      outputs  = new Port[_outports]; +      inputs   = new Port[_inports]; + +      SS_TRACE_OUT +      return true; +      } + +//--------------------------------------------------------- +//   stop +// deactivate +//--------------------------------------------------------- +void LadspaPlugin::stop() +      { +      SS_TRACE_IN +      if (handle) { +            SS_DBG_LADSPA2("Trying to stop plugin", label().toLatin1().data()); +            if (plugin->deactivate) { +                  SS_DBG_LADSPA2("Deactivating ", label().toLatin1().data()); +                  plugin->deactivate(handle); +                  active = false; +                  } +            } +      else +            SS_DBG_LADSPA("Warning - tried to stop plugin, but plugin was never started...\n"); +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   range +//--------------------------------------------------------- + +void LadspaPlugin::range(int i, float* min, float* max) const +      { +      SS_TRACE_IN +      i = pIdx[i]; +      LADSPA_PortRangeHint range = plugin->PortRangeHints[i]; +      LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor; +      if (desc & LADSPA_HINT_TOGGLED) { +            *min = 0.0; +            *max = 1.0; +            return; +            } +      float m = 1.0; +      if (desc & LADSPA_HINT_SAMPLE_RATE) +            m = (float) SS_samplerate; + +      if (desc & LADSPA_HINT_BOUNDED_BELOW) +            *min =  range.LowerBound * m; +      else +            *min = 0.0; +      if (desc & LADSPA_HINT_BOUNDED_ABOVE) +            *max =  range.UpperBound * m; +      else +            *max = 1.0; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   defaultValue +//--------------------------------------------------------- + +float LadspaPlugin::defaultValue(int k) const +      { +      SS_TRACE_IN +      k = pIdx[k]; +      LADSPA_PortRangeHint range = plugin->PortRangeHints[k]; +      LADSPA_PortRangeHintDescriptor rh = range.HintDescriptor; +      double val = 1.0; +      if (LADSPA_IS_HINT_DEFAULT_MINIMUM(rh)) +            val = range.LowerBound; +      else if (LADSPA_IS_HINT_DEFAULT_LOW(rh)) +            if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) +                  val = exp(fast_log10(range.LowerBound) * .75 + +                     log(range.UpperBound) * .25); +            else +                  val = range.LowerBound*.75 + range.UpperBound*.25; +      else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(rh)) +            if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) +                  val = exp(log(range.LowerBound) * .5 + +                     log(range.UpperBound) * .5); +            else +                  val = range.LowerBound*.5 + range.UpperBound*.5; +      else if (LADSPA_IS_HINT_DEFAULT_HIGH(rh)) +            if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) +                  val = exp(log(range.LowerBound) * .25 + +                     log(range.UpperBound) * .75); +            else +                  val = range.LowerBound*.25 + range.UpperBound*.75; +      else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(rh)) +            val = range.UpperBound; +      else if (LADSPA_IS_HINT_DEFAULT_0(rh)) +            val = 0.0; +      else if (LADSPA_IS_HINT_DEFAULT_1(rh)) +            val = 1.0; +      else if (LADSPA_IS_HINT_DEFAULT_100(rh)) +            val = 100.0; +      else if (LADSPA_IS_HINT_DEFAULT_440(rh)) +            val = 440.0; +      SS_TRACE_OUT +      return val; +      } + +//--------------------------------------------------------- +//   find +//--------------------------------------------------------- + +Plugin* PluginList::find(const QString& file, const QString& name) +      { +      SS_TRACE_IN +      for (iPlugin i = begin(); i != end(); ++i) { +            if ((file == (*i)->lib()) && (name == (*i)->label())) { +                  SS_TRACE_OUT +                  return *i; +                  } +            } +      printf("Plugin <%s> not found\n", name.toLatin1().data()); +      SS_TRACE_OUT +      return 0; +      } + +//--------------------------------------------------------- +//   connectInport +//--------------------------------------------------------- +void LadspaPlugin::connectInport(int k, LADSPA_Data* datalocation) +      { +      SS_TRACE_IN +      plugin->connect_port(handle, iIdx[k], datalocation); +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   connectOutport +//--------------------------------------------------------- +void LadspaPlugin::connectOutport(int k, LADSPA_Data* datalocation) +      { +      SS_TRACE_IN +      plugin->connect_port(handle, oIdx[k], datalocation); +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   process +//--------------------------------------------------------- +void LadspaPlugin::process(unsigned long frames) +      { +      plugin->run(handle, frames); +      } + +//--------------------------------------------------------- +//   setParam +//--------------------------------------------------------- + +void LadspaPlugin::setParam(int k, float val) +      { +      SS_TRACE_IN +      controls[k].val = val; +      SS_TRACE_OUT +      } + +//--------------------------------------------------------- +//   getGuiControlValue +//  scale control value to gui-slider/checkbox representation +//--------------------------------------------------------- + +int LadspaPlugin::getGuiControlValue(int param) const +      { +      SS_TRACE_IN +      float val = getControlValue(param); +      float min, max; +      range(param, &min, &max); +      int intval; +      if (isLog(param)) { +            intval = SS_map_logdomain2pluginparam(logf(val/(max - min) + min)); +            } +      else if (isBool(param)) { +            intval = (int) val; +            } +      else { +            float scale = SS_PLUGIN_PARAM_MAX / (max - min); +            intval = (int) ((val - min) * scale); +            } +      SS_TRACE_OUT +      return intval; +      } + +//--------------------------------------------------------- +//   convertGuiControlValue +//  scale control value to gui-slider/checkbox representation +//--------------------------------------------------------- + +float LadspaPlugin::convertGuiControlValue(int parameter, int val) const +      { +      SS_TRACE_IN +      float floatval = 0; +      float min, max; +      range(parameter, &min, &max); + +      if (isLog(parameter)) { +            if (val > 0) { +                  float logged = SS_map_pluginparam2logdomain(val); +                  float e = expf(logged) * (max - min); +                  e+=min; +                  floatval = e; +                  } +            } +      else if (isBool(parameter)) { +            floatval = (float) val; +            } +      else if (isInt(parameter)) { +            float scale = (max - min) / SS_PLUGIN_PARAM_MAX; +            floatval = (float) round((((float) val) * scale) + min); +            } +      else { +            float scale = (max - min) / SS_PLUGIN_PARAM_MAX; +            floatval = (((float) val) * scale) + min; +            } +      SS_TRACE_OUT +      return floatval; +      } diff --git a/muse2/synti/simpledrums2/ssplugin.h b/muse2/synti/simpledrums2/ssplugin.h new file mode 100644 index 00000000..64e80921 --- /dev/null +++ b/muse2/synti/simpledrums2/ssplugin.h @@ -0,0 +1,173 @@ +// +// C++ Interface: plugin +// +// Description: +// +// +//  (C) Copyright 2000 Werner Schweer (ws@seh.de) +// Additions/modifications: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef __PLUGIN_H__ +#define __PLUGIN_H__ + +#include <QFileInfo> + +#include <ladspa.h> +#include <math.h> + +//--------------------------------------------------------- +//   Port +//--------------------------------------------------------- + +struct Port { +      float val; +      }; + +//--------------------------------------------------------- +//   Plugin +//--------------------------------------------------------- + +class Plugin +   { +   protected: +      QFileInfo fi; + +   public: +      Plugin(const QFileInfo* f); +      virtual ~Plugin() {} +      virtual QString label() const     { return QString(); } +      virtual QString name() const      { return QString(); } +      virtual unsigned long id() const  { return 0;         } +      virtual QString maker() const     { return QString(); } +      virtual QString copyright() const { return QString(); } +      virtual int parameter() const       { return 0;     } +      virtual int inports() const         { return 0;     } +      virtual int outports() const        { return 0;     } +      virtual bool inPlaceCapable() const { return false; } + +      virtual bool isLog(int) const       { return false; } +      virtual bool isBool(int) const      { return false; } +      virtual bool isInt(int) const       { return false; } +      virtual float defaultValue(int) const { return 0.0f;  } +      virtual void range(int, float* min, float* max) const { +            *min = 0.0f; +            *max = 1.0f; +            } +      virtual const char* getParameterName(int /*param*/) const           { return ""; } +      QString lib() const               { return fi.baseName();    } +      QString path() const              { return fi.absolutePath();     } +   }; + +//--------------------------------------------------------- +//   LadspaPlugin +//--------------------------------------------------------- + +class LadspaPlugin : public Plugin +   { +      LADSPA_Descriptor_Function ladspa; +      const LADSPA_Descriptor* plugin; +      LADSPA_Handle handle; +      bool active; + +      Port* controls; +      Port* inputs; +      Port* outputs; + +   protected: +      int _parameter; +      std::vector<int> pIdx; //control port numbers + +      int _inports; +      std::vector<int> iIdx; //input port numbers + +      int _outports; +      std::vector<int> oIdx; //output port numbers + +      bool _inPlaceCapable; + +   public: +      LadspaPlugin(const QFileInfo* f, const LADSPA_Descriptor_Function, const LADSPA_Descriptor* d); +      virtual ~LadspaPlugin(); +      virtual QString label() const     { return QString(plugin->Label); } +      virtual QString name() const      { return QString(plugin->Name); } +      virtual unsigned long id() const  { return plugin->UniqueID; } +      virtual QString maker() const     { return QString(plugin->Maker); } +      virtual QString copyright() const { return QString(plugin->Copyright); } +      virtual int parameter() const { return _parameter;     } +      virtual int inports() const   { return _inports; } +      virtual int outports() const  { return _outports; } +      virtual bool inPlaceCapable() const { return _inPlaceCapable; } +      const LADSPA_Descriptor* ladspaDescriptor() const { return plugin; } +      virtual bool isLog(int k) const { +            LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; +            return LADSPA_IS_HINT_LOGARITHMIC(r.HintDescriptor); +            } +      virtual bool isBool(int k) const { +            return LADSPA_IS_HINT_TOGGLED(plugin->PortRangeHints[pIdx[k]].HintDescriptor); +            } +      virtual bool isInt(int k) const { +            LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; +            return LADSPA_IS_HINT_INTEGER(r.HintDescriptor); +            } +      virtual void range(int i, float*, float*) const; +      virtual const char* getParameterName(int i) const { +            return plugin->PortNames[pIdx[i]]; +            } +      virtual float defaultValue(int) const; +      virtual float getControlValue(int k) const { +            return controls[k].val; +            } + +      int   getGuiControlValue(int parameter) const; +      float convertGuiControlValue(int parameter, int val) const; + +      bool instantiate(); +      bool start(); +      void stop(); +      void connectInport(int k, LADSPA_Data* datalocation); +      void connectOutport(int k, LADSPA_Data* datalocation); +      void process(unsigned long); +      void setParam(int i, float val); + +   }; + + +static inline float fast_log2 (float val) +      { +      /* don't use reinterpret_cast<> because that prevents this +         from being used by pure C code (for example, GnomeCanvasItems) +      */ +      int* const exp_ptr = (int *)(&val); +      int x              = *exp_ptr; +      const int log_2    = ((x >> 23) & 255) - 128; +      x &= ~(255 << 23); +      x += 127 << 23; +      *exp_ptr = x; +      val = ((-1.0f/3) * val + 2) * val - 2.0f/3;   // (1) +      return (val + log_2); +      } + +static inline float fast_log10 (const float val) +      { +      return fast_log2(val) / 3.312500f; +      } + +//--------------------------------------------------------- +//   PluginList +//--------------------------------------------------------- + +typedef std::list<Plugin*>::iterator iPlugin; + +class PluginList : public std::list<Plugin*> { +   public: +      Plugin* find(const QString& file, const QString& name); +      PluginList() {} +      }; + +extern void SS_initPlugins(); +extern PluginList plugins; + +#endif diff --git a/muse2/synti/simpledrums2/sspluginchooserbase.ui b/muse2/synti/simpledrums2/sspluginchooserbase.ui new file mode 100644 index 00000000..63d254df --- /dev/null +++ b/muse2/synti/simpledrums2/sspluginchooserbase.ui @@ -0,0 +1,106 @@ +<ui version="4.0" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>SS_PluginChooserBase</class> + <widget class="QDialog" name="SS_PluginChooserBase" > +  <property name="geometry" > +   <rect> +    <x>0</x> +    <y>0</y> +    <width>777</width> +    <height>681</height> +   </rect> +  </property> +  <property name="windowTitle" > +   <string>SimpleDrums - Ladspa Plugin Chooser</string> +  </property> +  <layout class="QVBoxLayout" > +   <property name="margin" > +    <number>10</number> +   </property> +   <property name="spacing" > +    <number>6</number> +   </property> +   <item> +    <widget class="QTreeWidget" name="effectsListView" > +     <column> +      <property name="text" > +       <string>Name</string> +      </property> +     </column> +     <column> +      <property name="text" > +       <string>Label</string> +      </property> +     </column> +     <column> +      <property name="text" > +       <string>Inports</string> +      </property> +     </column> +     <column> +      <property name="text" > +       <string>Outports</string> +      </property> +     </column> +     <column> +      <property name="text" > +       <string>Creator</string> +      </property> +     </column> +    </widget> +   </item> +   <item> +    <layout class="QHBoxLayout" > +     <property name="margin" > +      <number>0</number> +     </property> +     <property name="spacing" > +      <number>6</number> +     </property> +     <item> +      <spacer> +       <property name="orientation" > +        <enum>Qt::Horizontal</enum> +       </property> +       <property name="sizeType" > +        <enum>QSizePolicy::Expanding</enum> +       </property> +       <property name="sizeHint" > +        <size> +         <width>301</width> +         <height>31</height> +        </size> +       </property> +      </spacer> +     </item> +     <item> +      <widget class="QPushButton" name="cancelButton" > +       <property name="text" > +        <string>&Cancel</string> +       </property> +       <property name="shortcut" > +        <string>Alt+C</string> +       </property> +      </widget> +     </item> +     <item> +      <widget class="QPushButton" name="okButton" > +       <property name="text" > +        <string>&OK</string> +       </property> +       <property name="shortcut" > +        <string>Alt+O</string> +       </property> +      </widget> +     </item> +    </layout> +   </item> +  </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/muse2/synti/simpledrums2/ssplugingui.cpp b/muse2/synti/simpledrums2/ssplugingui.cpp new file mode 100644 index 00000000..0428988b --- /dev/null +++ b/muse2/synti/simpledrums2/ssplugingui.cpp @@ -0,0 +1,530 @@ +// +// C++ Implementation: ssplugingui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "ssplugingui.h" +#include "ssplugin.h" +#include "simpledrumsgui.h" + +#define SS_PLUGINGUI_XOFF       300 +#define SS_PLUGINGUI_YOFF       300 +#define SS_PLUGINGUI_WIDTH      450 +#define SS_PLUGINGUI_MAX_WIDTH  700 + +#define SS_PLUGINFRONT_MINWIDTH SS_PLUGINGUI_WIDTH +#define SS_PLUGINFRONT_MINHEIGHT 70 +#define SS_PLUGINFRONT_MARGIN    9 +#define SS_PLUGINFRONT_INC_PARAM    30 +#define SS_PLUGINFRONT_INC_PARAM_MIN 60 +#define SS_PLUGINGUI_HEIGHT (SS_NR_OF_SENDEFFECTS * SS_PLUGINFRONT_MINHEIGHT) + +#define SS_PLUGINCHOOSER_NAMECOL     0 +#define SS_PLUGINCHOOSER_LABELCOL    1 +#define SS_PLUGINCHOOSER_INPORTSCOL  2 +#define SS_PLUGINCHOOSER_OUTPORTSCOL 3 +#define SS_PLUGINCHOOSER_CREATORCOL  4 + + +/*! +    \fn SS_PluginChooser::SS_PluginChooser(QWidget* parent, const char* name = 0) + */ +SS_PluginChooser::SS_PluginChooser(QWidget* parent) +      :QDialog(parent) +      { +      SS_TRACE_IN +      setupUi(this); +      selectedPlugin = 0; + +      for (iPlugin i=plugins.begin(); i !=plugins.end(); i++) { +            //Support for only 2 or 1 inport/outports +            if ( ((*i)->outports() == 2 || (*i)->outports() == 1) && ((*i)->inports() == 2 || (*i)->inports() == 1) ) { +                  QTreeWidgetItem* tmpItem = new QTreeWidgetItem(effectsListView); +                  tmpItem->setText(SS_PLUGINCHOOSER_NAMECOL, (*i)->name()); +                  tmpItem->setText(SS_PLUGINCHOOSER_LABELCOL, (*i)->label()); +                  tmpItem->setText(SS_PLUGINCHOOSER_INPORTSCOL, QString::number((*i)->inports())); +                  tmpItem->setText(SS_PLUGINCHOOSER_OUTPORTSCOL, QString::number((*i)->outports())); +                  tmpItem->setText(SS_PLUGINCHOOSER_CREATORCOL, (*i)->maker()); +                  effectsListView->addTopLevelItem(tmpItem); +                  } +            } +      connect(okButton, SIGNAL(pressed()), SLOT(okPressed())); +      connect(cancelButton, SIGNAL(pressed()), SLOT(cancelPressed())); +      connect(effectsListView, SIGNAL(selectionChanged(QTreeWidgetItem*)), SLOT(selectionChanged(QTreeWidgetItem*))); +      connect(effectsListView, SIGNAL(doubleClicked(QTreeWidgetItem*)), SLOT(doubleClicked(QTreeWidgetItem*))); +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginChooser::selectionChanged(QListViewItem* item) + */ +void SS_PluginChooser::selectionChanged(QTreeWidgetItem* item) +      { +      SS_TRACE_IN +      selectedItem  = item; +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginChooser::okPressed() + */ +void SS_PluginChooser::okPressed() +      { +      SS_TRACE_IN +      selectedPlugin = findSelectedPlugin(); +      done(QDialog::Accepted); +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginChooser::cancelPressed() + */ +void SS_PluginChooser::cancelPressed() +      { +      SS_TRACE_IN +      SS_TRACE_OUT +      done(QDialog::Rejected); +      } + +/*! +    \fn SS_PluginChooser::doubleClicked(QListViewItem* item) + */ +void SS_PluginChooser::doubleClicked(QTreeWidgetItem* /*item*/) +      { +      SS_TRACE_IN +      selectedPlugin = findSelectedPlugin(); +      SS_TRACE_OUT +      done(QDialog::Accepted); +      } + +/*! +    \fn SS_PluginChooser::getSelectedPlugin() + */ +LadspaPlugin* SS_PluginChooser::findSelectedPlugin() +      { +      SS_TRACE_IN +      LadspaPlugin* selected = 0; +      for (iPlugin i=plugins.begin(); i != plugins.end(); i++) { +            if ((*i)->name() == selectedItem->text(SS_PLUGINCHOOSER_NAMECOL)) +                  selected = (LadspaPlugin*) (*i); +            } +      SS_TRACE_OUT +      return selected; +      } + +/*! +    \fn SS_PluginFront::SS_PluginFront(QWidget* parent, const char* name = 0) + */ +SS_PluginFront::SS_PluginFront(QWidget* parent, int in_fxid) +      : QGroupBox(parent), fxid (in_fxid) +      { +      SS_TRACE_IN +      expanded = false; +      pluginChooser = 0; +      plugin = 0; +      expGroup = 0; + +//TD      setLineWidth(3); +      setFlat(false); +//TD      setFrameStyle( Q3Frame::Box | Q3Frame::Raised ); +//TD      setFrameShape(QFrame::StyledPanel); +//      setFrameShadow(Qt::Sunken); +      setFocusPolicy(Qt::NoFocus); +      setMinimumSize(SS_PLUGINFRONT_MINWIDTH, SS_PLUGINFRONT_MINHEIGHT); +      setMaximumSize(SS_PLUGINGUI_MAX_WIDTH, SS_PLUGINFRONT_MINHEIGHT); + +      QVBoxLayout* bigLayout = new QVBoxLayout(this); +      bigLayout->setMargin(SS_PLUGINFRONT_MARGIN); +      bigLayout->setAlignment(Qt::AlignTop); +//TODO      bigLayout->setResizeMode(QLayout::SetNoConstraint); + +      layout = new QHBoxLayout; +      bigLayout->addLayout(layout); +      layout->setAlignment(Qt::AlignVCenter); +//TODO      layout->setResizeMode(QLayout::SetNoConstraint); + + +      QVBoxLayout* onOffLayout = new QVBoxLayout; +      layout->addLayout(onOffLayout); +      onOffLayout->setMargin(SS_PLUGINFRONT_MARGIN); +      onOff = new QCheckBox(this); +      onOffLayout->addWidget(new QLabel("On/Off", this)); +      onOffLayout->addWidget(onOff); +      connect(onOff, SIGNAL(toggled(bool)), SLOT(onOffToggled(bool))); + +      pluginName = new QLineEdit(this); +      pluginName->setReadOnly(true); +      layout->addWidget(pluginName); + +      loadFxButton = new QPushButton("L", this); +      QRect r = loadFxButton->geometry(); +      loadFxButton->setGeometry(r.x(), r.y(), 20, pluginName->geometry().height()); +      loadFxButton->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); +      loadFxButton->setMinimumSize(20,pluginName->geometry().height()); +      loadFxButton->setMaximumSize(30,pluginName->geometry().height()); +      connect(loadFxButton, SIGNAL(clicked()), SLOT(loadButton())); +      layout->addWidget(loadFxButton); + +      clearFxButton = new QPushButton("C", this); +      r = clearFxButton->geometry(); +      clearFxButton->setGeometry(r.x(), r.y(), 20, pluginName->geometry().height()); +      clearFxButton->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); +      clearFxButton->setMinimumSize(20,pluginName->geometry().height()); +      clearFxButton->setMaximumSize(30,pluginName->geometry().height()); +      connect(clearFxButton, SIGNAL(clicked()), SLOT(clearButtonPressed())); +      layout->addWidget(clearFxButton); + +      layout->addSpacing(5); + +      expandButton = new QPushButton("->", this); +      r = loadFxButton->geometry(); +      expandButton->setGeometry(r.x(), r.y(), 20, pluginName->geometry().height()); +      expandButton->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); +      expandButton->setMinimumSize(20,pluginName->geometry().height()); +      expandButton->setMaximumSize(30,pluginName->geometry().height()); +      connect(expandButton, SIGNAL(clicked()), SLOT(expandButtonPressed())); +      layout->addWidget(expandButton); + +      layout->addSpacing(5); + +      QVBoxLayout* gainSliderLayout = new QVBoxLayout; +      layout->addLayout(gainSliderLayout); +      gainSliderLayout->addWidget(new QLabel("Return level", this)); +      gainSliderLayout->setMargin(SS_PLUGINFRONT_MARGIN); +      outGainSlider = new QSlider(Qt::Horizontal, this); +      outGainSlider->setMinimumSize(100, pluginName->geometry().height()); +      outGainSlider->setMaximumSize(500, pluginName->geometry().height()); +      loadFxButton->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); +      outGainSlider->setRange(0, 127); +      outGainSlider->setValue(75); +      connect(outGainSlider, SIGNAL(valueChanged(int)), SLOT(returnSliderMoved(int))); +      gainSliderLayout->addWidget(outGainSlider); +      clearPluginDisplay(); + +      expLayout = new QVBoxLayout; // (bigLayout, 2); +      bigLayout->addLayout(expLayout); + +      clearFxButton->setToolTip(tr("Clear and unload effect")); +      loadFxButton->setToolTip(tr("Load effect")); +      expandButton->setToolTip(tr("Toggle display of effect parameters")); +      onOff->setToolTip(tr("Turn effect on/off")); +      SS_TRACE_OUT +      } + +SS_PluginFront::~SS_PluginFront() +      { +      if (pluginChooser) +            delete pluginChooser; +      } + +/*! +    \fn SS_PluginFront::clearPluginDisplay() + */ +void SS_PluginFront::clearPluginDisplay() +      { +      SS_TRACE_IN +      if (expanded) +            expandButtonPressed(); + +      pluginName->setText("No plugin loaded"); +      pluginName->setEnabled(false); +      onOff->setEnabled(false); +      onOff->blockSignals(true); +      onOff->setChecked(false); +      onOff->blockSignals(false); + +      clearFxButton->setEnabled(false); +      expandButton->setEnabled(false); +      outGainSlider->setEnabled(false); +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginFront::setPluginName(QString name) + */ +void SS_PluginFront::setPluginName(QString name) +      { +      pluginName->setText(name); +      } + + +/*! +    \fn SS_PluginFront::loadButton() + */ +void SS_PluginFront::loadButton() +      { +      SS_TRACE_IN +      if (!pluginChooser) +            pluginChooser = new SS_PluginChooser(this); + +      pluginChooser->exec(); +      if ((pluginChooser->result() == QDialog::Accepted) && pluginChooser->getSelectedPlugin()) { +            Plugin* p = pluginChooser->getSelectedPlugin(); +            //printf("Selected plugin: %s\n", pluginChooser->getSelectedPlugin()->name().toLatin1().data()); +            emit loadPlugin(fxid, p->lib(), p->label()); +            } +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginFront::returnSliderMoved(int val) + */ +void SS_PluginFront::returnSliderMoved(int val) +      { +      emit returnLevelChanged(fxid, val); +      } + + +/*! +    \fn SS_PluginFront::updatePluginValue(unsigned i) + */ +void SS_PluginFront::updatePluginValue(unsigned k) +      { +      SS_TRACE_IN +      // If parameters are shown - close them +      if (expanded) { +            expandButtonPressed(); +            } + +      unsigned j=0; +      if (k > plugins.size()) { +            fprintf(stderr, "Internal error, tried to update plugin w range outside of list\n"); +            return; +            } + +      iPlugin i; +      for (i = plugins.begin(); j != k; i++, j++); +      plugin = (LadspaPlugin*) *(i); +      setPluginName(plugin->label()); +      outGainSlider->setEnabled(true); +      clearFxButton->setEnabled(true); +      expandButton->setEnabled(true); +      pluginName->setEnabled(true); +      onOff->setEnabled(true); +      onOff->setChecked(true); +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginFront::onOffToggled(bool state) + */ +void SS_PluginFront::onOffToggled(bool state) +      { +      emit fxToggled(fxid, state); +      } + +/*! +    \fn SS_PluginFront::sizeHint() const + */ +QSize SS_PluginFront::sizeHint() const +      { +      return QSize(SS_PLUGINFRONT_MINWIDTH, 50); +      } + +/*! +    \fn SS_PluginFront::sizePolicy() const + */ +QSizePolicy SS_PluginFront::sizePolicy() const +      { +      return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); +      } + + +/*! +    \fn SS_PluginFront::clearButtonPressed() + */ +void SS_PluginFront::clearButtonPressed() +      { +      // If parameters are shown - close them +      if (expanded) { +            expandButtonPressed(); +            } +      emit clearPlugin(fxid); +      } + +/*! +    \fn SS_PluginFront::setRetGain(int val) + */ +void SS_PluginFront::setRetGain(int val) +      { +      outGainSlider->blockSignals(true); +      outGainSlider->setValue(val); +      outGainSlider->blockSignals(false); +      } + +/*! +    \fn SS_PluginFront::expandButtonPressed() + */ +void SS_PluginFront::expandButtonPressed() +      { +      SS_TRACE_IN +      int sizeIncrease = 0; +      QRect pf = geometry(); + +      if (!expanded) { +            plugin->parameter() == 1 ? sizeIncrease = SS_PLUGINFRONT_INC_PARAM_MIN : sizeIncrease = plugin->parameter() * SS_PLUGINFRONT_INC_PARAM; +            pf.setHeight(pf.height() + sizeIncrease); +            setMinimumSize(QSize(pf.width(), pf.height())); +            setMaximumSize(QSize(SS_PLUGINGUI_MAX_WIDTH, pf.height())); +            setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); +            setGeometry(pf); +            emit sizeChanged(fxid, sizeIncrease); + +            expanded = true; +            expandButton->setText("<-"); +            createPluginParameters(); +            } +      else { +//TODO            expLayout->remove(expGroup); +            expGroup->hide(); +            expGroup->deleteLater(); +            paramWidgets.clear(); +            expGroup = 0; +            plugin->parameter() == 1 ? sizeIncrease = (0-SS_PLUGINFRONT_INC_PARAM_MIN) : sizeIncrease = 0 - (plugin->parameter() * SS_PLUGINFRONT_INC_PARAM); +            expandButton->setText("->"); +            expanded = false; +            pf.setHeight(pf.height() + sizeIncrease); +            pf.setTop(pf.top() + sizeIncrease); +            pf.setBottom(pf.bottom() + sizeIncrease); +            setGeometry(pf); +            adjustSize(); +            layout->activate(); +            setMinimumSize(QSize(pf.width(), pf.height())); +            setMaximumSize(QSize(SS_PLUGINGUI_MAX_WIDTH, pf.height())); +            setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); +            emit sizeChanged(fxid, sizeIncrease); +            } +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginFront::createPluginParameters() + */ +void SS_PluginFront::createPluginParameters() +      { +      SS_TRACE_IN +      expGroup = new QGroupBox(this); + +      expGroup->setMinimumSize(QSize(50, 50)); +      expGroup->setMaximumSize(QSize(SS_PLUGINGUI_MAX_WIDTH, (plugin->parameter() * SS_PLUGINFRONT_INC_PARAM  - SS_PLUGINFRONT_MARGIN))); +      expGroup->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); +      expLayout->addWidget(expGroup); +      expGroup->show(); +      QVBoxLayout* expGroupLayout = new QVBoxLayout(expGroup); // , 1); +      expGroupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); +//TD      expGroupLayout->setResizeMode(QLayout::FreeResize); +      expGroupLayout->setMargin(SS_PLUGINFRONT_MARGIN); + +      for (int i=0; i < plugin->parameter(); i++) { +            QHBoxLayout* paramStrip = new QHBoxLayout; // (expGroupLayout, 3); +            expGroupLayout->addLayout(paramStrip); +            paramStrip->setAlignment(Qt::AlignLeft); +            QLabel* paramName = new QLabel(plugin->getParameterName(i), expGroup); +            paramName->show(); +            paramName->setMinimumSize(QSize(150, 10)); +            paramName->setMaximumSize(QSize(300, SS_PLUGINFRONT_INC_PARAM)); +            paramName->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + +            paramStrip->addWidget(paramName); + +            if (plugin->isBool(i)) { +                  SS_ParameterCheckBox* paramCheckBox = new SS_ParameterCheckBox(expGroup, plugin, fxid, i); +                  paramCheckBox->setEnabled(true); +                  paramCheckBox->setParamValue((int) plugin->getControlValue(i)); +                  paramCheckBox->show(); +                  paramStrip->addWidget(paramCheckBox); +                  connect(paramCheckBox, SIGNAL(valueChanged(int, int, int)), SLOT(parameterValueChanged(int, int, int))); +                  } +            else  { +                  SS_ParameterSlider* paramSlider = new SS_ParameterSlider(expGroup, plugin, fxid, i); +                  paramSlider->setEnabled(true); +                  paramSlider->show(); +                  paramSlider->setRange(SS_PLUGIN_PARAM_MIN, SS_PLUGIN_PARAM_MAX); + +                  float max, min; +                  plugin->range(i, &min, &max); +                  //int intval = 0; +                  paramSlider->setParamValue(plugin->getGuiControlValue(i)); +                  connect(paramSlider, SIGNAL(valueChanged(int, int, int)), SLOT(parameterValueChanged(int, int, int))); +                  paramStrip->addWidget(paramSlider); +                  } +            } +      expLayout->activate(); +      SS_TRACE_OUT +      } + +/*! +    \fn SS_PluginFront::parameterValueChanged(int fxid, int parameter, int val) + */ +void SS_PluginFront::parameterValueChanged(int fxid, int parameter, int val) +      { +      emit effectParameterChanged(fxid, parameter, val); +      } + +/*! +    \fn SS_PluginFront::setParameterValue(int param, float val) + */ +void SS_PluginFront::setParameterValue(int param, int val) +      { +      SS_TRACE_IN +      int j=0; +      for (SS_iParameterWidgetList i=paramWidgets.begin(); i != paramWidgets.end(); i++, j++) { +            if (j == param) { +                  (*i)->setParamValue(val); +                  } +            } +      SS_TRACE_OUT +      } + +SS_PluginGui::SS_PluginGui(QWidget* parent) +      : QDialog(parent, false) +      { +      setWindowTitle("SimpleDrums LADSPA sendeffects"); +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            pluginFronts[i] = 0; +            } +      layout = new QVBoxLayout(this); + +      for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { +            pluginFronts[i] = new SS_PluginFront(this, i); +            pluginFronts[i]->update(); +            layout->addWidget(pluginFronts[i]); +            connect(pluginFronts[i], SIGNAL(loadPlugin(int, QString, QString)), simplesynthgui_ptr, SLOT(loadEffectInvoked(int, QString, QString))); +            connect(pluginFronts[i], SIGNAL(returnLevelChanged(int, int)), simplesynthgui_ptr, SLOT(returnLevelChanged(int, int))); +            connect(pluginFronts[i], SIGNAL(fxToggled(int, int)), simplesynthgui_ptr, SLOT(toggleEffectOnOff(int, int))); +            connect(pluginFronts[i], SIGNAL(clearPlugin(int)), simplesynthgui_ptr, SLOT(clearPlugin(int))); +            connect(pluginFronts[i], SIGNAL(sizeChanged(int, int)), SLOT(pluginFrontSizeChanged(int, int))); +            connect(pluginFronts[i], SIGNAL(effectParameterChanged(int, int, int)), simplesynthgui_ptr, SLOT(effectParameterChanged(int, int, int))); +            } +      setMinimumSize(QSize(SS_PLUGINGUI_WIDTH, geometry().height())); +      setMaximumSize(QSize(SS_PLUGINGUI_MAX_WIDTH, geometry().height())); +      } + + +/*! +    \fn SS_PluginGui::pluginFrontSizeChanged(int fxid, int val) + */ +void SS_PluginGui::pluginFrontSizeChanged(int /*fxid*/, int val) +      { +      QRect r = geometry(); +      r.setHeight(r.height() + val); +      setMinimumSize(QSize(SS_PLUGINGUI_WIDTH, r.height())); +      setMaximumSize(QSize(SS_PLUGINGUI_MAX_WIDTH, r.height())); +      setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); +      setGeometry(r); +      adjustSize(); +      } + +SS_PluginFront* SS_PluginGui::getPluginFront(unsigned i) +      { +      SS_TRACE_IN +      if (i<SS_NR_OF_SENDEFFECTS) +      SS_TRACE_OUT +      return pluginFronts[i]; +      } diff --git a/muse2/synti/simpledrums2/ssplugingui.h b/muse2/synti/simpledrums2/ssplugingui.h new file mode 100644 index 00000000..3d77ecf0 --- /dev/null +++ b/muse2/synti/simpledrums2/ssplugingui.h @@ -0,0 +1,204 @@ +// +// C++ Interface: ssplugingui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef __SS_PLUGINGUI_H__ +#define __SS_PLUGINGUI_H__ +#include <QDialog> +#include <QSlider> +#include <QButtonGroup> +#include <QtGui> +//#include <QHBoxLayout> +//#include <QVBoxLayout> + +#include "ui_sspluginchooserbase.h" +#include "common.h" +#include "ssplugin.h" + +class SS_ParameterWidget +      { +   protected: +      int fxid; +      int parameter; + +      LadspaPlugin* plugin; + +   public: +      SS_ParameterWidget() { } +      virtual ~SS_ParameterWidget() { } +      int getFxId() { SS_TRACE_IN SS_TRACE_OUT return fxid; } +      bool isBool() { SS_TRACE_IN SS_TRACE_OUT return plugin->isBool(parameter); } +      bool isLog()  { SS_TRACE_IN SS_TRACE_OUT return plugin->isLog(parameter); } +      bool isInt()  { SS_TRACE_IN SS_TRACE_OUT return plugin->isInt(parameter); } +      virtual void setParamValue(int) { printf("Virtual function - should not be called!"); }; +      }; + +class SS_ParameterCheckBox : public QCheckBox, public SS_ParameterWidget +   { +   Q_OBJECT + +   public: +      SS_ParameterCheckBox(QWidget* parent, LadspaPlugin* in_plugin, int in_id, int in_parameter) +         : QCheckBox(parent) , SS_ParameterWidget() +         { +         SS_TRACE_IN +         plugin = in_plugin; +         fxid = in_id; +         parameter = in_parameter; +         connect(this, SIGNAL(clicked()), SLOT(isClicked())); +         SS_TRACE_OUT +         } + +      virtual void setParamValue(int val) { SS_TRACE_IN setChecked(val); SS_TRACE_OUT} + +   private slots: +      void isClicked() { SS_TRACE_IN emit valueChanged(fxid, parameter, (int)this->isChecked()); SS_TRACE_OUT} + +   signals: +      void valueChanged(int id, int param, int val); +   }; + +class SS_ParameterSlider : public QSlider, public SS_ParameterWidget +   { +   Q_OBJECT + +   public: +      SS_ParameterSlider(QWidget* parent, LadspaPlugin* in_plugin, int in_id, int in_parameter) +         : QSlider(Qt::Horizontal, parent), SS_ParameterWidget() +         { +         SS_TRACE_IN +         plugin = in_plugin; +         fxid = in_id; +         parameter = in_parameter; +         SS_TRACE_OUT +         } + +      virtual void setParamValue(int val) { SS_TRACE_IN setValue(val); SS_TRACE_OUT} + +   public slots: +      virtual void setValue(int val) { SS_TRACE_IN QSlider::setValue(val); emit valueChanged(fxid, parameter, val); SS_TRACE_OUT } + +   signals: +      void valueChanged(int id, int param, int val); +   }; + +typedef std::list<SS_ParameterWidget*>           SS_ParameterWidgetList; +typedef std::list<SS_ParameterWidget*>::iterator SS_iParameterWidgetList ; + +//------------------------------- +// SS_PluginChooser +//------------------------------- +class SS_PluginChooser : public QDialog, Ui::SS_PluginChooserBase +{ +   Q_OBJECT +   private: +         LadspaPlugin* selectedPlugin; +   protected: + +   public: +         SS_PluginChooser(QWidget* parent); +         LadspaPlugin* getSelectedPlugin() { SS_TRACE_IN SS_TRACE_OUT return selectedPlugin; } + +   private slots: +      void okPressed(); +      void cancelPressed(); +      void selectionChanged(QTreeWidgetItem* item); +      void doubleClicked(QTreeWidgetItem* item); + +   private: +      QTreeWidgetItem* selectedItem; +      LadspaPlugin* findSelectedPlugin(); + +}; + +//------------------------------- +// SS_PluginGuiFront +//------------------------------- +class SS_PluginFront : public QGroupBox +   { +   Q_OBJECT +   private: +      QHBoxLayout*      layout; +      QVBoxLayout*      expLayout; +      QLineEdit*        pluginName; +      QCheckBox*        onOff; +      QPushButton*      loadFxButton; +      QPushButton*      clearFxButton; +      QPushButton*      expandButton; +      QSlider*          outGainSlider; +      SS_PluginChooser* pluginChooser; +      LadspaPlugin*     plugin; +      QGroupBox*     expGroup; + +      int               fxid; +      bool              expanded; + +      //For effect parameters: +      SS_ParameterWidgetList  paramWidgets; + +   protected: + +   public: +      SS_PluginFront(QWidget* parent, int id); +      void setPluginName(QString name); +      ~SS_PluginFront(); +      void updatePluginValue(unsigned i); +      void clearPluginDisplay(); +      void setParameterValue(int param, int val); +      void setRetGain(int val); + +   protected: +      virtual QSize sizeHint() const; +      virtual QSizePolicy sizePolicy() const; + +   private slots: +      void loadButton(); +      void returnSliderMoved(int val); +      void onOffToggled(bool state); +      void clearButtonPressed(); +      void expandButtonPressed(); +      void parameterValueChanged(int fxid, int parameter, int val); + +   signals: +      void loadPlugin(int fxid, QString lib, QString name); +      void returnLevelChanged(int fxid, int val); +      void fxToggled(int fxid, int state); +      void clearPlugin(int fxid); +      void sizeChanged(int fxid, int val); +      void effectParameterChanged(int fxid, int param, int val); + +   private: +      void createPluginParameters(); +   }; + + +//------------------------------- +// SS_PluginGui +// Main plugin class, dialog +//------------------------------- +class SS_PluginGui : public QDialog +   { +   Q_OBJECT +   private: +      QVBoxLayout* layout; +      SS_PluginFront* pluginFronts[4]; + +   public: +      SS_PluginGui(QWidget* parent); +      SS_PluginFront* getPluginFront(unsigned i); +      ~SS_PluginGui() {} +private slots: +    void pluginFrontSizeChanged(int fxid, int val); +   }; + + +#endif + diff --git a/muse2/synti/vam/CMakeLists.txt b/muse2/synti/vam/CMakeLists.txt index b93a5c9d..d146b2f9 100644 --- a/muse2/synti/vam/CMakeLists.txt +++ b/muse2/synti/vam/CMakeLists.txt @@ -38,7 +38,7 @@ add_library ( vam SHARED  #  set_target_properties ( vam      PROPERTIES PREFIX "" -   COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all-pic.h" +   COMPILE_FLAGS "-fvisibility=hidden -include ${PROJECT_BINARY_DIR}/all-pic.h"     )  target_link_libraries(vam diff --git a/muse2/synti/vam/vam.cpp b/muse2/synti/vam/vam.cpp index 95b80c13..9d0d6e30 100644 --- a/muse2/synti/vam/vam.cpp +++ b/muse2/synti/vam/vam.cpp @@ -1044,7 +1044,12 @@ extern "C" {              MESS_MAJOR_VERSION, MESS_MINOR_VERSION,              instantiate,              }; - +      // We must compile with -fvisibility=hidden to avoid namespace +      // conflicts with global variables. +      // Only visible symbol is "mess_descriptor". +      // (TODO: all plugins should be compiled this way) +   +      __attribute__ ((visibility("default")))        const MESS* mess_descriptor() { return &descriptor; }        }  | 
