diff options
Diffstat (limited to 'muse2/synti/simpledrums')
-rw-r--r-- | muse2/synti/simpledrums/COPYING | 3 | ||||
-rw-r--r-- | muse2/synti/simpledrums/Makefile.am | 20 | ||||
-rw-r--r-- | muse2/synti/simpledrums/Makefile.in | 661 | ||||
-rw-r--r-- | muse2/synti/simpledrums/README | 44 | ||||
-rw-r--r-- | muse2/synti/simpledrums/ReleaseNotes.txt | 21 | ||||
-rw-r--r-- | muse2/synti/simpledrums/common.h | 110 | ||||
-rw-r--r-- | muse2/synti/simpledrums/simpledrums.cpp | 1759 | ||||
-rw-r--r-- | muse2/synti/simpledrums/simpledrums.h | 177 | ||||
-rw-r--r-- | muse2/synti/simpledrums/simpledrumsgui.cpp | 892 | ||||
-rw-r--r-- | muse2/synti/simpledrums/simpledrumsgui.h | 212 | ||||
-rw-r--r-- | muse2/synti/simpledrums/simpledrumsguibase.ui | 27 | ||||
-rw-r--r-- | muse2/synti/simpledrums/ssplugin.cpp | 461 | ||||
-rw-r--r-- | muse2/synti/simpledrums/ssplugin.h | 153 | ||||
-rw-r--r-- | muse2/synti/simpledrums/sspluginchooserbase.ui | 134 | ||||
-rw-r--r-- | muse2/synti/simpledrums/ssplugingui.cpp | 534 | ||||
-rw-r--r-- | muse2/synti/simpledrums/ssplugingui.h | 206 |
16 files changed, 5414 insertions, 0 deletions
diff --git a/muse2/synti/simpledrums/COPYING b/muse2/synti/simpledrums/COPYING new file mode 100644 index 00000000..5c3cefc2 --- /dev/null +++ b/muse2/synti/simpledrums/COPYING @@ -0,0 +1,3 @@ +COPYING +--------------------------------------- +This software is licensed under GNU GPL. diff --git a/muse2/synti/simpledrums/Makefile.am b/muse2/synti/simpledrums/Makefile.am new file mode 100644 index 00000000..16b77dc5 --- /dev/null +++ b/muse2/synti/simpledrums/Makefile.am @@ -0,0 +1,20 @@ +include $(top_srcdir)/common.am +include $(top_srcdir)/synti/synti-install.am + +AM_CXXFLAGS +=-fPIC -O3 -fno-rtti -ffast-math -fno-exceptions -include $(top_srcdir)/all-pic.h + +synthi_LTLIBRARIES = simpledrums.la + +simpledrums_la_SOURCES = simpledrums.h simpledrums.cpp common.h \ + simpledrumsgui.cpp simpledrumsgui.h \ + ssplugin.h ssplugin.cpp ssplugingui.h ssplugingui.cpp \ + simpledrumsguibase.ui sspluginchooserbase.ui + +nodist_simpledrums_la_SOURCES = moc_simpledrumsgui.cpp moc_ssplugingui.cpp + +simpledrums_la_LIBADD = ../libsynti/libsynti.la -lsamplerate +simpledrums_la_LDFLAGS = -module -avoid-version + +CLEANFILES = $(wildcard *.ui~) +EXTRA_DIST = README ReleaseNotes.txt COPYING + diff --git a/muse2/synti/simpledrums/Makefile.in b/muse2/synti/simpledrums/Makefile.in new file mode 100644 index 00000000..9526cba6 --- /dev/null +++ b/muse2/synti/simpledrums/Makefile.in @@ -0,0 +1,661 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/common.am $(top_srcdir)/synti/synti-install.am \ + COPYING +subdir = synti/simpledrums +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/aclocal-include.m4 \ + $(top_srcdir)/m4/alsa.m4 $(top_srcdir)/m4/docbook.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(synthidir)" +LTLIBRARIES = $(synthi_LTLIBRARIES) +simpledrums_la_DEPENDENCIES = ../libsynti/libsynti.la +am_simpledrums_la_OBJECTS = simpledrums.lo simpledrumsgui.lo \ + ssplugin.lo ssplugingui.lo simpledrumsguibase.lo \ + sspluginchooserbase.lo +nodist_simpledrums_la_OBJECTS = moc_simpledrumsgui.lo \ + moc_ssplugingui.lo +simpledrums_la_OBJECTS = $(am_simpledrums_la_OBJECTS) \ + $(nodist_simpledrums_la_OBJECTS) +simpledrums_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(simpledrums_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(simpledrums_la_SOURCES) $(nodist_simpledrums_la_SOURCES) +DIST_SOURCES = $(simpledrums_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOCBOOKSTYLE = @DOCBOOKSTYLE@ +DOCBOOKTARGETS = @DOCBOOKTARGETS@ +DOT = @DOT@ +DOTPATH = @DOTPATH@ +DOXYGEN = @DOXYGEN@ +DOXYGEN_TREEVIEW = @DOXYGEN_TREEVIEW@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLUIDSYNTHDIRS = @FLUIDSYNTHDIRS@ +FST_CFLAGS = @FST_CFLAGS@ +FST_LIBS = @FST_LIBS@ +Fluidsynth_CFLAGS = @Fluidsynth_CFLAGS@ +Fluidsynth_LIBS = @Fluidsynth_LIBS@ +GIVERTCAP = @GIVERTCAP@ +GREP = @GREP@ +HAVEDOT = @HAVEDOT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JACK_CFLAGS = @JACK_CFLAGS@ +JACK_LIBS = @JACK_LIBS@ +JADE = @JADE@ +LASH_CFLAGS = @LASH_CFLAGS@ +LASH_LIBS = @LASH_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LO_CFLAGS = @LO_CFLAGS@ +LO_LIBS = @LO_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MUSECXXFLAGS = @MUSECXXFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NSGMLS = @NSGMLS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCH = @PCH@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIB = @PYTHON_LIB@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +QTDIR_BIN = @QTDIR_BIN@ +QTDIR_INC = @QTDIR_INC@ +QT_LIBS = @QT_LIBS@ +RANLIB = @RANLIB@ +SAMPLERATE_CFLAGS = @SAMPLERATE_CFLAGS@ +SAMPLERATE_LIBS = @SAMPLERATE_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ +SNDFILE_LIBS = @SNDFILE_LIBS@ +STRIP = @STRIP@ +SUIDBUILD = @SUIDBUILD@ +SUIDINSTALL = @SUIDINSTALL@ +USE_SSE = @USE_SSE@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +have_docbook = @have_docbook@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +synth_fluid = @synth_fluid@ +synth_fluidsynth = @synth_fluidsynth@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CXXFLAGS = $(MUSECXXFLAGS) -I.. -I$(top_srcdir)/synti \ + -I$(top_srcdir)/muse/widgets -DQT_SHARED -DQT_THREAD_SUPPORT \ + -DQT_PLUGIN $(QTDIR_INC) -DQT3_SUPPORT -fPIC -O3 -fno-rtti \ + -ffast-math -fno-exceptions -include $(top_srcdir)/all-pic.h +AM_CPPFLAGS = +MOC = $(QTDIR_BIN)/moc +#UIC = $(QTDIR_BIN)/uic3 +UIC = /usr/bin/uic3 +UIFILES = $(wildcard *.ui) +MOCFILES = $(shell for h in $(filter %.h,$(SOURCES)); do \ + if grep -q Q_OBJECT $$h; then \ + echo $$h | sed "s/\(.*\)\.h/moc_\1.cpp/"; \ + fi; \ + done) + +BUILT_SOURCES = $(MOCFILES) $(UIFILES:%.ui=%.h) +MOSTLYCLEANFILES = $(MOCFILES) $(UIFILES:%.ui=%.h) +SUFFIXES = .ui .h.gch +synthidir = $(pkglibdir)/synthi +synthi_LTLIBRARIES = simpledrums.la +simpledrums_la_SOURCES = simpledrums.h simpledrums.cpp common.h \ + simpledrumsgui.cpp simpledrumsgui.h \ + ssplugin.h ssplugin.cpp ssplugingui.h ssplugingui.cpp \ + simpledrumsguibase.ui sspluginchooserbase.ui + +nodist_simpledrums_la_SOURCES = moc_simpledrumsgui.cpp moc_ssplugingui.cpp +simpledrums_la_LIBADD = ../libsynti/libsynti.la -lsamplerate +simpledrums_la_LDFLAGS = -module -avoid-version +CLEANFILES = $(wildcard *.ui~) +EXTRA_DIST = README ReleaseNotes.txt COPYING +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .ui .h.gch .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/common.am $(top_srcdir)/synti/synti-install.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu synti/simpledrums/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu synti/simpledrums/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-synthiLTLIBRARIES: $(synthi_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(synthidir)" || $(MKDIR_P) "$(DESTDIR)$(synthidir)" + @list='$(synthi_LTLIBRARIES)'; test -n "$(synthidir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(synthidir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(synthidir)"; \ + } + +uninstall-synthiLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(synthi_LTLIBRARIES)'; test -n "$(synthidir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(synthidir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(synthidir)/$$f"; \ + done + +clean-synthiLTLIBRARIES: + -test -z "$(synthi_LTLIBRARIES)" || rm -f $(synthi_LTLIBRARIES) + @list='$(synthi_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +simpledrums.la: $(simpledrums_la_OBJECTS) $(simpledrums_la_DEPENDENCIES) + $(simpledrums_la_LINK) -rpath $(synthidir) $(simpledrums_la_OBJECTS) $(simpledrums_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_simpledrumsgui.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_ssplugingui.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpledrums.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpledrumsgui.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssplugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssplugingui.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(synthidir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-synthiLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-synthiLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-synthiLTLIBRARIES + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-synthiLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip install-synthiLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-synthiLTLIBRARIES + + +de: + @for base in $(MOCFILES); do echo -e "\t$${base}.cpp $${base}.h \\"; done + +nde: + @for base in $(MOCFILES); do echo -e "\tmoc_$${base}.cpp \\"; done + +.ui.o: %.h + $(UIC) -L $(top_srcdir)/muse/widgets -o $*.cpp -impl $*.h $*.ui + $(MOC) $*.h >> $*.cpp + $(CXXCOMPILE) -c $*.cpp -o $*.o + $(RM) $*.cpp moc_$*.cpp moc_$*.o + +.ui.lo: %.h + $(UIC) -L $(top_srcdir)/muse/widgets -o $*.cpp -impl $*.h $*.ui + $(MOC) $*.h >> $*.cpp + $(LTCXXCOMPILE) -c $*.cpp -o $*.lo + $(RM) $*.cpp moc_$*.cpp moc_$*.lo moc_$*.o + +moc_%.cpp: %.h + $(MOC) $< -o $@ + +%.h: %.ui + $(UIC) -o $@ $< +# $(UIC) -L $(top_srcdir)/muse/widgets -o $@ $< + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/muse2/synti/simpledrums/README b/muse2/synti/simpledrums/README new file mode 100644 index 00000000..9e2695dc --- /dev/null +++ b/muse2/synti/simpledrums/README @@ -0,0 +1,44 @@ +-------------------------------------- +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 +- Possible to save synth state to file +- 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/simpledrums/ReleaseNotes.txt b/muse2/synti/simpledrums/ReleaseNotes.txt new file mode 100644 index 00000000..1144321a --- /dev/null +++ b/muse2/synti/simpledrums/ReleaseNotes.txt @@ -0,0 +1,21 @@ +RELEASE NOTES: +-------------- +2005-05-07 ver 1.0 (go figure!) +- Now possible to load/save setup to file + +2004-12-13 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/simpledrums/common.h b/muse2/synti/simpledrums/common.h new file mode 100644 index 00000000..e4763540 --- /dev/null +++ b/muse2/synti/simpledrums/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/simpledrums/simpledrums.cpp b/muse2/synti/simpledrums/simpledrums.cpp new file mode 100644 index 00000000..5a0431a0 --- /dev/null +++ b/muse2/synti/simpledrums/simpledrums.cpp @@ -0,0 +1,1759 @@ +// +// 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.latin1(); + controllers[i].num = CTRL_NRPN14_OFFSET+i; + controllers[i].min = 0; + controllers[i].max = 127; + + controllers[i+1].name = c2.latin1(); + controllers[i+1].num = CTRL_NRPN14_OFFSET+i+1; + controllers[i+1].min = 0; + controllers[i+1].max = 127; + + controllers[i+2].name = c3.latin1(); + controllers[i+2].num = CTRL_NRPN14_OFFSET+i+2; + controllers[i+2].min = 0; + controllers[i+2].max = 1; + + controllers[i+3].name = c4.latin1(); + controllers[i+3].num = CTRL_NRPN14_OFFSET+i+3; + controllers[i+3].min = 0; + controllers[i+3].max = 1; + + controllers[i+4].name = c5.latin1(); + controllers[i+4].num = CTRL_NRPN14_OFFSET+i+4; + + controllers[i+5].name = c6.latin1(); + controllers[i+5].num = CTRL_NRPN14_OFFSET+i+5; + + controllers[i+6].name = c7.latin1(); + controllers[i+6].num = CTRL_NRPN14_OFFSET+i+6; + + controllers[i+7].name = c8.latin1(); + 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.latin1(); + controllers[i].num = CTRL_NRPN14_OFFSET+i; + controllers[i].min = 0; + controllers[i].max = 127; + + controllers[i+1].name = c2.latin1(); + 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.latin1(), label.latin1()); + } + 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 + \param drum - is it a drum track? + \return const char* with patchname + */ +//--------------------------------------------------------- +const char* SimpleSynth::getPatchName(int /*index*/, int, int, bool /*drum*/) const + { + SS_TRACE_IN + SS_TRACE_OUT + //return 0; + //return "<unknown>"; + return "SimpleSynth"; + } + +//--------------------------------------------------------- +// 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, int* /*initval*/ ) const + { + 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); + } + +//--------------------------------------------------------- +// processMessages +/*! + \fn SimpleSynth::processMessages + \brief Called from host always, even if output path is unconnected + */ +//--------------------------------------------------------- +void SimpleSynth::processMessages() +{ + //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()); + } + } +} + +//--------------------------------------------------------- +// process +/*! + \fn SimpleSynth::process + \brief Realtime function where the processing actually occurs. Called from host, ONLY if output path is connected. + \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->setCaption(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) const + { + 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 = strlen(plugin->lib()) + 2; + int labelnamelen = strlen(plugin->label()) + 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 = strlen(sendEffects[j].plugin->label()) + 1; + buffer[i] = labelnamelen; + memcpy((buffer+i+1), sendEffects[j].plugin->label(), 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 = strlen(sendEffects[j].plugin->lib()) + 1; + buffer[i] = namelen; + memcpy((buffer+i+1), sendEffects[j].plugin->lib(), 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[%zd] - channels[ch].volume_ctrlval = \t%d\n", ptr-data, *ptr); + printf("buffer[%zd] - channels[ch].pan = \t\t%d\n", ptr-data+1, *(ptr+1)); + printf("buffer[%zd] - channels[ch].noteoff_ignore = \t%d\n", ptr-data+2, *(ptr+2)); + printf("buffer[%zd] - 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[%zd] - 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[%zd] - 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", (long) 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); + } + +QString *projPathPtr; + +static Mess* instantiate(int sr, QWidget*, QString* projectPathPtr, const char* name) + { + projPathPtr = projectPathPtr; + 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", + "SimpleSynth drums by Mathias Lundgren", // (lunar_shuttle@users.sf.net) + "0.1", //Version string + MESS_MAJOR_VERSION, MESS_MINOR_VERSION, + instantiate, + }; + 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.latin1()); + 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); + } + 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().latin1()); + 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/simpledrums/simpledrums.h b/muse2/synti/simpledrums/simpledrums.h new file mode 100644 index 00000000..9d0d1331 --- /dev/null +++ b/muse2/synti/simpledrums/simpledrums.h @@ -0,0 +1,177 @@ +// +// 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 <iostream> +#include <string> +#include <Qt3Support> +#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, bool arg4) 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, int* arg6) const; + virtual void processMessages(); + virtual void process(float** data, int offset, int len); + virtual void showGui(bool arg1); + virtual void getInitData(int*, const unsigned char**) const; + 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/simpledrums/simpledrumsgui.cpp b/muse2/synti/simpledrums/simpledrumsgui.cpp new file mode 100644 index 00000000..03fa658c --- /dev/null +++ b/muse2/synti/simpledrums/simpledrumsgui.cpp @@ -0,0 +1,892 @@ +// +// C++ Implementation: testogui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include <q3buttongroup.h> +#include <qlabel.h> +#include <q3filedialog.h> +#include <qsocketnotifier.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qlineedit.h> +#include <QtGui> +//Added by qt3to4: +#include <Q3HBoxLayout> +#include <Q3GridLayout> +#include <Q3VBoxLayout> + +#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, const char* name) + : QSlider(orientation, parent, name) + { + 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->maxValue() - 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->maxValue() - val; + inverted = (inverted > 127 ? 127 : inverted); + inverted = (inverted < 0 ? 0 : inverted); + emit invertedValueChanged(inverted); + QSlider::setValue(val); + } + + +/*! + \fn QChannelCheckbox::QChannelCheckbox(QWidget* parent, int ch, const char* name) + */ +QChannelCheckbox::QChannelCheckbox(QWidget* parent, int ch, const char* name) + : QCheckBox(parent, name) + { + channel = ch; + connect(this, SIGNAL(clicked()), SLOT(isClicked())); + } + + +/*! + \fn QChannelCheckbox::isClicked() + */ +void QChannelCheckbox::isClicked() + { + emit channelState(channel, this->isOn()); + } + +/*! + \fn QChannelButton::QChannelButton(QWidget* parent, const char* text, int ch, const char* name) + */ +QChannelButton::QChannelButton(QWidget* parent, const char* text, int ch, const char* name) + : QPushButton(parent, name), channel (ch) + { + connect(this, SIGNAL(clicked()), SLOT(isClicked())); + setText(text); + } + +/*! + \fn QChannelButton::isClicked() + */ +void QChannelButton::isClicked() + { + emit channelState(channel, this->isOn()); + } + +/*! + \fn QChannelDial() + */ +QChannelDial::QChannelDial(QWidget* parent, int ch, int fxid, const char* name) + : QDial(parent, name) + { + 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 + simplesynthgui_ptr = this; + pluginGui = new SS_PluginGui(this); + pluginGui->hide(); + + Q3VBoxLayout* mainLayout = new Q3VBoxLayout(this, 3); + Q3HBoxLayout* channelLayout = new Q3HBoxLayout(mainLayout, 1, "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 Q3ButtonGroup(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->add(channelButtonGroups[i]); + + Q3VBoxLayout* inchnlLayout = new Q3VBoxLayout(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); + QToolTip::add(onOff[i], "Channel " + QString::number(i + 1) + " on/off"); + inchnlLayout->add(onOff[i]); + connect(onOff[i], SIGNAL(channelState(int, bool)), SLOT(channelOnOff(int, bool))); + + volumeSliders[i] = new QInvertedChannelSlider(Qt::Vertical, i, channelButtonGroups[i], name); + volumeSliders[i]->setMinValue(SS_VOLUME_MIN_VALUE); + volumeSliders[i]->setMaxValue(SS_VOLUME_MAX_VALUE); + volumeSliders[i]->setValue(SS_VOLUME_MAX_VALUE - SS_VOLUME_DEFAULT_VALUE); + volumeSliders[i]->setMinimumSize(SS_VOLSLDR_WIDTH, SS_VOLSLDR_LENGTH); + QToolTip::add(volumeSliders[i], "Volume, channel " + QString::number(i + 1)); + setMinimumSize(SS_VOLSLDR_WIDTH, SS_VOLSLDR_LENGTH); + inchnlLayout->add(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->add(nOffLabel[i]); + + nOffIgnore[i] = new QChannelCheckbox(channelButtonGroups[i], i); + nOffIgnore[i]->setMinimumSize(SS_NONOFF_WIDTH, SS_NONOFF_HEIGHT); + QToolTip::add(nOffIgnore[i], "Note off ignore, channel " + QString::number(i + 1)); + inchnlLayout->add(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); + QToolTip::add(panSliders[i], "Pan, channel " + QString::number(i + 1)); + inchnlLayout->add(panSliders[i]); + connect(panSliders[i], SIGNAL(valueChanged(int, int)), SLOT(panChanged(int, int))); + + Q3GridLayout* dialGrid = new Q3GridLayout(inchnlLayout, 2, 2, 0); + 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); + QToolTip::add(sendFxDial[i][0], "Fx 1 send amount"); + //inchnlLayout->add(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); + QToolTip::add(sendFxDial[i][1], "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); + QToolTip::add(sendFxDial[i][2], "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); + QToolTip::add(sendFxDial[i][3], "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 Q3ButtonGroup(this, "masterButtonGroup"); + channelLayout->add(masterButtonGroup); + Q3VBoxLayout* mbgLayout = new Q3VBoxLayout(masterButtonGroup, 0); + mbgLayout->setAlignment(Qt::AlignCenter); + masterButtonGroup->setMinimumSize(SS_BTNGRP_WIDTH, SS_BTNGRP_HEIGHT); + masterSlider = new QInvertedSlider(Qt::Vertical, masterButtonGroup); + QToolTip::add(masterSlider, "Master volume"); + mbgLayout->add(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 Q3GroupBox(this, "mainGroupBox"); + mainLayout->add(mainGroupBox); + + Q3GridLayout* mgbLayout = new Q3GridLayout(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++) { + Q3HBoxLayout* strip = new Q3HBoxLayout;//(mgbLayout, 5); + mgbLayout->addLayout(strip, r, c); + + QLabel* channelLabel = new QLabel(QString("Ch ") + QString::number(i + 1), mainGroupBox); + strip->add(channelLabel); + + sampleNameLineEdit[i] = new QLineEdit(mainGroupBox); + sampleNameLineEdit[i]->setReadOnly(true); + strip->add(sampleNameLineEdit[i]); + + loadSampleButton[i] = new QChannelButton(mainGroupBox, "L", i); + loadSampleButton[i]->setMinimumSize(SS_SAMPLE_LOAD_WIDTH, SS_SAMPLE_LOAD_HEIGHT); + QToolTip::add(loadSampleButton[i], "Load sample on channel " + QString::number(i + 1)); + strip->add(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); + QToolTip::add(clearSampleButton[i], "Clear sample on channel " + QString::number(i + 1)); + strip->add(clearSampleButton[i]); + connect(clearSampleButton[i], SIGNAL(channelState(int, bool)), SLOT(clearSample(int))); + + i++; + } + } + + // Right bottom panel: + Q3ButtonGroup* rbPanel= new Q3ButtonGroup(mainGroupBox, "right_bottom_panel"); + mgbLayout->addMultiCellWidget(rbPanel, 1, 8, 3, 3, Qt::AlignCenter); + Q3GridLayout* rbLayout = new Q3GridLayout(rbPanel, 6, 1, 8, 5); + openPluginsButton = new QPushButton("&Send Effects", rbPanel); + QToolTip::add(openPluginsButton, "Configure LADSPA send effects"); + connect(openPluginsButton, SIGNAL(clicked()), SLOT(openPluginButtonClicked())); + aboutButton = new QPushButton("About SimpleDrums", rbPanel); + connect(aboutButton, SIGNAL(clicked()), SLOT(aboutButtonClicked())); + QPushButton* loadButton = new QPushButton(tr("&Load setup"), rbPanel); + connect(loadButton, SIGNAL(clicked()), SLOT(loadSetup())); + QPushButton* 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 + + // work around for probable QT/WM interaction bug. + // for certain window managers, e.g xfce, this window is + // is displayed although not specifically set to show(); + // bug: 2811156 Softsynth GUI unclosable with XFCE4 (and a few others) + show(); + hide(); + } + +/*! + \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.latin1(), 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: { + const unsigned initdata_len = ev.len() - 1; + byte* init_data = (data + 1); + QFileInfo fileInfo = QFileInfo(lastSavedProject); + + lastProjectDir = fileInfo.dirPath(true); + if (fileInfo.extension(false) != "sds" && fileInfo.extension(false) != "SDS") { + lastSavedProject += ".sds"; + fileInfo = QFileInfo(lastSavedProject); + } + QFile theFile(fileInfo.filePath()); + + // Write data + if (theFile.open(QIODevice::WriteOnly)) { + theFile.writeBlock((const char*)&initdata_len, sizeof(initdata_len)); // First write length + if (theFile.writeBlock((const char*)init_data, initdata_len) == -1) { + // Fatal error writing + QMessageBox msgBox("IO error", "Fatal error when writing to file. Setup not saved.", + QMessageBox::Warning, + QMessageBox::Ok, + QMessageBox::NoButton, + QMessageBox::NoButton, + this); + msgBox.exec(); + } + theFile.close(); + } + else { + // An error occured when opening + QMessageBox msgBox("IO error", "Error opening file. Setup was not saved.", QMessageBox::Warning, + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this); + msgBox.exec(); + } + + 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 = + Q3FileDialog::getOpenFileName(lastDir, + QString("*.wav;*.WAV"), + this, + "Load sample dialog","Choose sample"); + + if (filename != QString::null) { + lastDir = filename.left(filename.findRev("/")); + + if (SS_DEBUG) + printf("lastDir = %s\n", lastDir.latin1()); + + 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.latin1(), 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); + } + } + +/*! + \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.latin1(), lib.length()+1); + memcpy (d+3+lib.length(), label.latin1(), 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->isShown()) + 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-2005 Mathias Lundgren (lunar_shuttle@users.sf.net), Werner Schweer\nPublished under the GNU Public License"; + QMessageBox msgBox(caption, text, QMessageBox::NoIcon, + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this); + msgBox.exec(); + } + + + +/*! + \fn SimpleSynthGui::loadSetup() + \brief Load setup from file + */ +void SimpleSynthGui::loadSetup() + { + bool success = true; + QString filename = + Q3FileDialog::getOpenFileName(lastProjectDir, + QString("*.sds;*.SDS"), + this, + "Load setup dialog", "Choose SimpleDrums setup"); + + if (filename != QString::null) { + QFile theFile(filename); + if (theFile.open(QIODevice::ReadOnly)) { + unsigned initdata_len = 0; + if (theFile.readBlock((char*)&initdata_len, sizeof(initdata_len)) == -1) + success = false; + + byte* init_data = new byte[initdata_len]; + if (theFile.readBlock((char*)(init_data), initdata_len) == -1) + success = false; + + if (!success) { + QMessageBox msgBox("IO error", "Error opening/reading from file. Setup not loaded.", QMessageBox::Warning, + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this); + msgBox.exec(); + } + else { + sendSysex(init_data, initdata_len); + } + + delete[] init_data; + } + } + } + + +/*! + \fn SimpleSynthGui::saveSetup() + \brief Save setup to file + */ +void SimpleSynthGui::saveSetup() + { + QString filename = + Q3FileDialog::getSaveFileName(lastProjectDir, + QString("*.sds;*.SDS"), + this, + "Save setup dialog", "Save SimpleDrums setup"); + + 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/simpledrums/simpledrumsgui.h b/muse2/synti/simpledrums/simpledrumsgui.h new file mode 100644 index 00000000..47a98ca1 --- /dev/null +++ b/muse2/synti/simpledrums/simpledrumsgui.h @@ -0,0 +1,212 @@ +// +// 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.h> +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <qdial.h> +#include <Qt3Support> +//Added by qt3to4: +#include <QLabel> + +#include "libsynti/gui.h" +#include "simpledrumsguibase.h" +#include "common.h" + + + +class Q3ButtonGroup; +class QLabel; +class SS_PluginGui; + +//-------------------------------------- +// QChannelSlider +//-------------------------------------- +class QChannelSlider: public QSlider + { + Q_OBJECT + + public: + QChannelSlider(Qt::Orientation, int ch, QWidget* paren, const char* name = 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, const char* name = 0) + : QSlider(o, parent, name) {} + + 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, const char* name = 0) + : QChannelSlider(o, channel, parent, name) {}; + + public slots: + virtual void setValue(int val); + }; + + +//-------------------------------------- +// QChannelOnOff +//-------------------------------------- + +class QChannelCheckbox : public QCheckBox + { + Q_OBJECT + public: + QChannelCheckbox(QWidget* parent, int channel, const char* name = 0); + + 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, const char* name = 0); + + 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, const char* name = 0); + + 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 SimpleDrumsGuiBase, public MessGui + { + Q_OBJECT + private: + // MESS interface: + virtual void processEvent(const MidiPlayEvent& ev); + void setChannelVolume(int channel, int volume); + void displayPluginGui(); + Q3GroupBox* channelButtonGroups[SS_NR_OF_CHANNELS]; + Q3ButtonGroup* masterButtonGroup; + Q3GroupBox* 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; + + 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/simpledrums/simpledrumsguibase.ui b/muse2/synti/simpledrums/simpledrumsguibase.ui new file mode 100644 index 00000000..244273a6 --- /dev/null +++ b/muse2/synti/simpledrums/simpledrumsguibase.ui @@ -0,0 +1,27 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>SimpleDrumsGuiBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SimpleDrumsGuiBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>602</width> + <height>509</height> + </rect> + </property> + <property name="paletteBackgroundColor"> + <color> + <red>194</red> + <green>194</green> + <blue>194</blue> + </color> + </property> + <property name="caption"> + <string>DrumSynth 0.1</string> + </property> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/muse2/synti/simpledrums/ssplugin.cpp b/muse2/synti/simpledrums/ssplugin.cpp new file mode 100644 index 00000000..0efbc55e --- /dev/null +++ b/muse2/synti/simpledrums/ssplugin.cpp @@ -0,0 +1,461 @@ +// +// 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().latin1()); + } + void* handle = dlopen(fi->filePath().ascii(), RTLD_NOW); + if (handle == 0) { + fprintf(stderr, "dlopen(%s) failed: %s\n", + fi->filePath().ascii(), 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().ascii(), + txt); + 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"), QDir::DirsLast, QDir::Files); + if (pluginDir.exists()) { + QList<QFileInfo> list = pluginDir.entryInfoList(); + QList<QFileInfo>::iterator it=list.begin(); + QFileInfo* fi; + while((fi = &(*it))) { + loadPluginLib(fi); + ++it; + } + } + SS_TRACE_OUT + } + +//--------------------------------------------------------- +// initPlugins +// search for LADSPA plugins +//--------------------------------------------------------- + +void SS_initPlugins() + { + SS_TRACE_IN + //loadPluginDir(museGlobalLib + QString("/plugins")); + + const char* ladspaPath = getenv("LADSPA_PATH"); + if (ladspaPath == 0) + ladspaPath = "/usr/local/lib64/ladspa:/usr/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa"; + + const char* p = ladspaPath; + while (*p != '\0') { + const 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().latin1(), this->lib().latin1(), 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().latin1()); + 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().latin1()); + 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().latin1()); + if (plugin->deactivate) { + SS_DBG_LADSPA2("Deactivating ", label().latin1()); + 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.latin1()); + 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/simpledrums/ssplugin.h b/muse2/synti/simpledrums/ssplugin.h new file mode 100644 index 00000000..8f2b5df3 --- /dev/null +++ b/muse2/synti/simpledrums/ssplugin.h @@ -0,0 +1,153 @@ +// +// 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 "muse/ladspa.h" +#include "muse/fastlog.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 ""; } //prevnt unused parameter + QString lib() const { return fi.baseName(); } + QString path() const { return fi.dirPath(); } + }; + +//--------------------------------------------------------- +// 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); + + }; + +//--------------------------------------------------------- +// 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/simpledrums/sspluginchooserbase.ui b/muse2/synti/simpledrums/sspluginchooserbase.ui new file mode 100644 index 00000000..3ce1d10e --- /dev/null +++ b/muse2/synti/simpledrums/sspluginchooserbase.ui @@ -0,0 +1,134 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>SS_PluginChooserBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SS_PluginChooserBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>777</width> + <height>681</height> + </rect> + </property> + <property name="caption"> + <string>SimpleDrums - Ladspa Plugin Chooser</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Label</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Inports</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Outports</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Creator</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>effectsListView</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>301</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancelButton</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string>Alt+C</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>okButton</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string>Alt+O</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/muse2/synti/simpledrums/ssplugingui.cpp b/muse2/synti/simpledrums/ssplugingui.cpp new file mode 100644 index 00000000..bd4e88d8 --- /dev/null +++ b/muse2/synti/simpledrums/ssplugingui.cpp @@ -0,0 +1,534 @@ +// +// C++ Implementation: ssplugingui +// +// Description: +// +// +// Author: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include <stdlib.h> +#include <qlayout.h> +//Added by qt3to4: +#include <Q3HBoxLayout> +#include <Q3Frame> +#include <QLabel> +#include <Q3VBoxLayout> +#include <QtGui> +#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, const char* name) + :SS_PluginChooserBase(parent, name) + { + SS_TRACE_IN + 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) ) { + Q3ListViewItem* tmpItem = new Q3ListViewItem(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->insertItem(tmpItem); + } + } + connect(okButton, SIGNAL(pressed()), SLOT(okPressed())); + connect(cancelButton, SIGNAL(pressed()), SLOT(cancelPressed())); + connect(effectsListView, SIGNAL(selectionChanged(Q3ListViewItem*)), SLOT(selectionChanged(Q3ListViewItem*))); + connect(effectsListView, SIGNAL(doubleClicked(Q3ListViewItem*)), SLOT(doubleClicked(Q3ListViewItem*))); + SS_TRACE_OUT + } + +/*! + \fn SS_PluginChooser::selectionChanged(QListViewItem* item) + */ +void SS_PluginChooser::selectionChanged(Q3ListViewItem* 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(Q3ListViewItem* /*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, const char* name) + : Q3GroupBox(parent, name), fxid (in_fxid) + { + SS_TRACE_IN + expanded = false; + pluginChooser = 0; + plugin = 0; + expGroup = 0; + + setLineWidth(3); + setFlat(false); + setFrameStyle( Q3Frame::Box | Q3Frame::Raised ); + setFrameShape(Q3GroupBox::Box);// QFrame::Box); + setFrameShadow(Sunken); + setFocusPolicy(Qt::NoFocus); + setMinimumSize(SS_PLUGINFRONT_MINWIDTH, SS_PLUGINFRONT_MINHEIGHT); + setMaximumSize(SS_PLUGINGUI_MAX_WIDTH, SS_PLUGINFRONT_MINHEIGHT); + + Q3VBoxLayout* bigLayout = new Q3VBoxLayout(this); + bigLayout->setMargin(SS_PLUGINFRONT_MARGIN); + bigLayout->setAlignment(Qt::AlignTop); + bigLayout->setResizeMode(QLayout::SetNoConstraint); + + layout = new Q3HBoxLayout(bigLayout); + layout->setAlignment(Qt::AlignVCenter); + layout->setResizeMode(QLayout::SetNoConstraint); + + + Q3VBoxLayout* onOffLayout = new Q3VBoxLayout(layout); + onOffLayout->setMargin(SS_PLUGINFRONT_MARGIN); + onOff = new QCheckBox(this); + onOffLayout->add(new QLabel("On/Off", this)); + onOffLayout->add(onOff); + connect(onOff, SIGNAL(toggled(bool)), SLOT(onOffToggled(bool))); + + pluginName = new QLineEdit(this); + pluginName->setReadOnly(true); + layout->add(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->add(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->add(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->add(expandButton); + + layout->addSpacing(5); + + Q3VBoxLayout* gainSliderLayout = new Q3VBoxLayout(layout); + gainSliderLayout->add(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->add(outGainSlider); + clearPluginDisplay(); + + expLayout = new Q3VBoxLayout(bigLayout, 2); + + QToolTip::add(clearFxButton, "Clear and unload effect"); + QToolTip::add(loadFxButton, "Load effect"); + QToolTip::add(expandButton, "Toggle display of effect parameters"); + QToolTip::add(onOff, "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, "temppluginchooser"); + + pluginChooser->exec(); + if ((pluginChooser->result() == QDialog::Accepted) && pluginChooser->getSelectedPlugin()) { + Plugin* p = pluginChooser->getSelectedPlugin(); + //printf("Selected plugin: %s\n", pluginChooser->getSelectedPlugin()->name().latin1()); + 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 { + 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 Q3ButtonGroup(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->add(expGroup); + expGroup->show(); + Q3VBoxLayout* expGroupLayout = new Q3VBoxLayout(expGroup, 1); + expGroupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + expGroupLayout->setResizeMode(QLayout::SetNoConstraint); + expGroupLayout->setMargin(SS_PLUGINFRONT_MARGIN); + + for (int i=0; i < plugin->parameter(); i++) { + Q3HBoxLayout* paramStrip = new Q3HBoxLayout(expGroupLayout, 3); + 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->add(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->add(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->add(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, const char* name) + : QDialog(parent, name, false) + { + this->setCaption("SimpleDrums LADSPA sendeffects"); + for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { + pluginFronts[i] = 0; + } + layout = new Q3VBoxLayout(this); + + for (int i=0; i<SS_NR_OF_SENDEFFECTS; i++) { + pluginFronts[i] = new SS_PluginFront(this, i); + pluginFronts[i]->update(); + layout->add(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/simpledrums/ssplugingui.h b/muse2/synti/simpledrums/ssplugingui.h new file mode 100644 index 00000000..166d8787 --- /dev/null +++ b/muse2/synti/simpledrums/ssplugingui.h @@ -0,0 +1,206 @@ +// +// 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.h> +#include <qslider.h> +#include <Q3ButtonGroup> +#include <QtGui> +//Added by qt3to4: +#include <Q3HBoxLayout> +#include <Q3VBoxLayout> +#include "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 /*val*/) { //prevent compiler warning unused parameter + 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, const char* name = 0) + : QCheckBox(parent, name) , 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->isOn()); 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, const char* name = 0) + : QSlider(Qt::Horizontal, parent, name), 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 SS_PluginChooserBase +{ + Q_OBJECT + private: + LadspaPlugin* selectedPlugin; + protected: + + public: + SS_PluginChooser(QWidget* parent, const char* name=0); + LadspaPlugin* getSelectedPlugin() { SS_TRACE_IN SS_TRACE_OUT return selectedPlugin; } + + private slots: + void okPressed(); + void cancelPressed(); + void selectionChanged(Q3ListViewItem* item); + void doubleClicked(Q3ListViewItem* item); + + private: + Q3ListViewItem* selectedItem; + LadspaPlugin* findSelectedPlugin(); + +}; + +//------------------------------- +// SS_PluginGuiFront +//------------------------------- +class SS_PluginFront : public Q3GroupBox + { + Q_OBJECT + private: + Q3HBoxLayout* layout; + Q3VBoxLayout* expLayout; + QLineEdit* pluginName; + QCheckBox* onOff; + QPushButton* loadFxButton; + QPushButton* clearFxButton; + QPushButton* expandButton; + QSlider* outGainSlider; + SS_PluginChooser* pluginChooser; + LadspaPlugin* plugin; + Q3ButtonGroup* expGroup; + + int fxid; + bool expanded; + + //For effect parameters: + SS_ParameterWidgetList paramWidgets; + + protected: + + public: + SS_PluginFront(QWidget* parent, int id, const char* name = 0); + 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: + Q3VBoxLayout* layout; + SS_PluginFront* pluginFronts[4]; + + public: + SS_PluginGui(QWidget* parent, const char* name = 0); + SS_PluginFront* getPluginFront(unsigned i); + ~SS_PluginGui() {} +private slots: + void pluginFrontSizeChanged(int fxid, int val); + }; + + +#endif + |