summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2010-11-01 08:36:22 +0000
committerTim E. Real <termtech@rogers.com>2010-11-01 08:36:22 +0000
commitbf32fe9882d7dd1dd6fbb88f39a42371063b6cd6 (patch)
tree57ce439a666b14632a186d859fd357134e6c414b /muse2
parent4f767f96be2382c3f73a9619097a8cbabe3f7587 (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')
-rw-r--r--muse2/ChangeLog6
-rw-r--r--muse2/muse/app.cpp4
-rw-r--r--muse2/muse/plugin.cpp9
-rw-r--r--muse2/muse/synth.cpp5
-rw-r--r--muse2/synti/CMakeLists.txt3
-rw-r--r--muse2/synti/deicsonze/CMakeLists.txt2
-rw-r--r--muse2/synti/deicsonze/deicsonze.cpp5
-rw-r--r--muse2/synti/deicsonze2/CMakeLists.txt2
-rw-r--r--muse2/synti/deicsonze2/deicsonze.cpp5
-rw-r--r--muse2/synti/fluid/CMakeLists.txt2
-rw-r--r--muse2/synti/fluid/fluid.cpp6
-rw-r--r--muse2/synti/fluidsynth/CMakeLists.txt2
-rw-r--r--muse2/synti/fluidsynth/fluidsynti.cpp6
-rw-r--r--muse2/synti/organ/CMakeLists.txt2
-rw-r--r--muse2/synti/organ/organ.cpp7
-rw-r--r--muse2/synti/s1/CMakeLists.txt5
-rw-r--r--muse2/synti/s1/s1.cpp7
-rw-r--r--muse2/synti/simpledrums/CMakeLists.txt2
-rw-r--r--muse2/synti/simpledrums/simpledrums.cpp6
-rw-r--r--muse2/synti/simpledrums2/CMakeLists.txt52
-rw-r--r--muse2/synti/simpledrums2/COPYING3
-rw-r--r--muse2/synti/simpledrums2/README43
-rw-r--r--muse2/synti/simpledrums2/ReleaseNotes.txt18
-rw-r--r--muse2/synti/simpledrums2/common.h110
-rw-r--r--muse2/synti/simpledrums2/simpledrums.cpp1726
-rw-r--r--muse2/synti/simpledrums2/simpledrums.h173
-rw-r--r--muse2/synti/simpledrums2/simpledrumsgui.cpp890
-rw-r--r--muse2/synti/simpledrums2/simpledrumsgui.h214
-rw-r--r--muse2/synti/simpledrums2/simpledrumsguibase.ui23
-rw-r--r--muse2/synti/simpledrums2/ssplugin.cpp460
-rw-r--r--muse2/synti/simpledrums2/ssplugin.h173
-rw-r--r--muse2/synti/simpledrums2/sspluginchooserbase.ui106
-rw-r--r--muse2/synti/simpledrums2/ssplugingui.cpp530
-rw-r--r--muse2/synti/simpledrums2/ssplugingui.h204
-rw-r--r--muse2/synti/vam/CMakeLists.txt2
-rw-r--r--muse2/synti/vam/vam.cpp7
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>&amp;Cancel</string>
+ </property>
+ <property name="shortcut" >
+ <string>Alt+C</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>&amp;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; }
}