summaryrefslogtreecommitdiff
path: root/muse2/synti/fluidsynth
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/synti/fluidsynth')
-rw-r--r--muse2/synti/fluidsynth/Makefile.am19
-rw-r--r--muse2/synti/fluidsynth/Makefile.in655
-rw-r--r--muse2/synti/fluidsynth/README.txt45
-rw-r--r--muse2/synti/fluidsynth/TODO13
-rw-r--r--muse2/synti/fluidsynth/fluidsynthgui.cpp819
-rw-r--r--muse2/synti/fluidsynth/fluidsynthgui.h225
-rw-r--r--muse2/synti/fluidsynth/fluidsynthguibase.ui632
-rw-r--r--muse2/synti/fluidsynth/fluidsynti.cpp1314
-rw-r--r--muse2/synti/fluidsynth/fluidsynti.h150
9 files changed, 3872 insertions, 0 deletions
diff --git a/muse2/synti/fluidsynth/Makefile.am b/muse2/synti/fluidsynth/Makefile.am
new file mode 100644
index 00000000..817c3cb5
--- /dev/null
+++ b/muse2/synti/fluidsynth/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/common.am
+include $(top_srcdir)/synti/synti-install.am
+
+AM_CXXFLAGS += -fPIC -O3 -ffast-math -fno-exceptions
+
+synthi_LTLIBRARIES = fluidsynth.la
+
+fluidsynth_la_SOURCES = fluidsynti.h fluidsynti.cpp \
+ fluidsynthgui.cpp fluidsynthgui.h \
+ fluidsynthguibase.ui
+
+nodist_fluidsynth_la_SOURCES = moc_fluidsynthgui.cpp
+
+fluidsynth_la_LIBADD = ../libsynti/libsynti.la -lfluidsynth
+fluidsynth_la_LDFLAGS = -module -avoid-version
+
+CLEANFILES = $(wildcard *.ui~)
+EXTRA_DIST = TODO README.txt
+
diff --git a/muse2/synti/fluidsynth/Makefile.in b/muse2/synti/fluidsynth/Makefile.in
new file mode 100644
index 00000000..e567a9b8
--- /dev/null
+++ b/muse2/synti/fluidsynth/Makefile.in
@@ -0,0 +1,655 @@
+# 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 = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/common.am $(top_srcdir)/synti/synti-install.am \
+ TODO
+subdir = synti/fluidsynth
+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)
+fluidsynth_la_DEPENDENCIES = ../libsynti/libsynti.la
+am_fluidsynth_la_OBJECTS = fluidsynti.lo fluidsynthgui.lo \
+ fluidsynthguibase.lo
+nodist_fluidsynth_la_OBJECTS = moc_fluidsynthgui.lo
+fluidsynth_la_OBJECTS = $(am_fluidsynth_la_OBJECTS) \
+ $(nodist_fluidsynth_la_OBJECTS)
+fluidsynth_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(fluidsynth_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 = $(fluidsynth_la_SOURCES) $(nodist_fluidsynth_la_SOURCES)
+DIST_SOURCES = $(fluidsynth_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 -ffast-math \
+ -fno-exceptions
+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 = fluidsynth.la
+fluidsynth_la_SOURCES = fluidsynti.h fluidsynti.cpp \
+ fluidsynthgui.cpp fluidsynthgui.h \
+ fluidsynthguibase.ui
+
+nodist_fluidsynth_la_SOURCES = moc_fluidsynthgui.cpp
+fluidsynth_la_LIBADD = ../libsynti/libsynti.la -lfluidsynth
+fluidsynth_la_LDFLAGS = -module -avoid-version
+CLEANFILES = $(wildcard *.ui~)
+EXTRA_DIST = TODO README.txt
+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/fluidsynth/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu synti/fluidsynth/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
+fluidsynth.la: $(fluidsynth_la_OBJECTS) $(fluidsynth_la_DEPENDENCIES)
+ $(fluidsynth_la_LINK) -rpath $(synthidir) $(fluidsynth_la_OBJECTS) $(fluidsynth_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fluidsynthgui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fluidsynti.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_fluidsynthgui.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/fluidsynth/README.txt b/muse2/synti/fluidsynth/README.txt
new file mode 100644
index 00000000..7764edb6
--- /dev/null
+++ b/muse2/synti/fluidsynth/README.txt
@@ -0,0 +1,45 @@
+README.txt
+----------
+
+Graphical frontend and built-in softsynth (MusE Experimental Soft Synth) for MusE, based on Fluidsynth
+(http://www.fluidsynth.org).
+
+Features:
+---------
+- Loading/unloading of soundfonts
+- Easy control of fluidsynth's send effects and their parameters
+- Mapping of soundfonts to fluidsynth channels
+- Stores all settings in the current project file and automatically loads all effect parameters,
+ soundfonts, channel settings and presets when re-opening the project.
+- Makes it possible to use several soundfonts in one single fluidsynth instance (thereby reducing CPU usage since they share
+ the same send effects)
+
+
+Changelog/History
+-----------------
+040524
+- Err... Fount out that this changelog is neglected. See ../../Changelog.txt instead.
+031019
+- Bugfixes and changes in storing/retrieving init parameters (Mathias Lundgren)
+031009
+- Unloading of soundfonts works (Mathias Lundgren)
+- Last dir stored in project-file (Mathias Lundgren)
+- Ordinary controller-events enabled (Mathias Lundgren)
+031008
+- Mapping of soundfonts to fluidchannels and selection of patches implemented. (Mathias Lundgren)
+- Permanent storage of channels & patches. Extended GUI. (Mathias Lundgren)
+031002
+- Various communication problems fixed between GUI and client (Mathias Lundgren)
+- Storage of synth parameters and soundfonts enabled (Mathias Lundgren/Robert Jonsson)
+
+0309xx
+- Problem with loading of soundfonts resulting in Jack timeout fixed by moving loading of soundfonts to separate thread. (Robert Jonsson)
+
+Original code written by Robert Ham (no information about the history of his work)
+
+
+Known problems/TODO:
+--------------------------------------------------------------
+* Turning on the chorus and/or modifying chorus parameters locks the client.
+* Illegal chorus parameters can be sent to fluidsynth.
+* Drum patches (lbank=128) not implemented yet
diff --git a/muse2/synti/fluidsynth/TODO b/muse2/synti/fluidsynth/TODO
new file mode 100644
index 00000000..e941e1e9
--- /dev/null
+++ b/muse2/synti/fluidsynth/TODO
@@ -0,0 +1,13 @@
+ TODO
+
+o preset loading/saving
+o configuration loading/saving
+o soundfont information display
+o remembering the last directory that was dealt with
+o change gui<->synth communication to nrpns
+
+ DONE
+
+o get all controllers working
+o soundfont stack operations
+o patch name retrieval
diff --git a/muse2/synti/fluidsynth/fluidsynthgui.cpp b/muse2/synti/fluidsynth/fluidsynthgui.cpp
new file mode 100644
index 00000000..bdb0719b
--- /dev/null
+++ b/muse2/synti/fluidsynth/fluidsynthgui.cpp
@@ -0,0 +1,819 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynthgui.cpp,v 1.13.2.2 2009/08/12 20:47:01 spamatica Exp $
+ *
+ */
+
+#include "fluidsynthgui.h"
+#include "fluidsynti.h"
+#include <qpushbutton.h>
+
+#include <iostream>
+#include <qlineedit.h>
+#include <q3filedialog.h>
+#include <qsocketnotifier.h>
+#include <qpixmap.h>
+#include <q3listview.h>
+#include <qslider.h>
+#include <qmessagebox.h>
+#include <q3popupmenu.h>
+#include <q3header.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qcombobox.h>
+
+#include "muse/midi.h"
+#include "xpm/buttondown.xpm"
+
+
+ /*
+#include "muse/debug.h"
+#include <iomanip>
+#include <qtooltip.h>
+#include <qapplication.h>
+#include <qlistbox.h>
+#define MUSE_FLUID_DEBUG false
+*/
+
+FluidSynthGui::FluidSynthGui()
+ : MessGui()
+ {
+ //Connect socketnotifier to fifo
+ QSocketNotifier* s = new QSocketNotifier(readFd, QSocketNotifier::Read);
+ connect(s, SIGNAL(activated(int)), SLOT(readMessage(int)));
+ connect (Push, SIGNAL (clicked()), SLOT(loadClicked()));
+
+ lastdir = "";
+
+ channelListView->setColumnWidthMode(FS_CHANNEL_COL,Q3ListView::Maximum);
+ channelListView->setColumnWidthMode(FS_SF_ID_COL,Q3ListView::Maximum);
+ ReverbFrame->setEnabled(true);
+ ChorusFrame->setEnabled(true);
+
+ if (!FS_DEBUG)
+ dumpInfoButton->hide();
+
+ //Init reverb sliders:
+ /*ReverbRoomSize->setValue((int)(16383*FS_PREDEF_REVERB_ROOMSIZE));
+ ReverbDamping->setValue((int)(16383*FS_PREDEF_REVERB_DAMPING));
+ ReverbWidth->setValue((int)(16383*FS_PREDEF_REVERB_WIDTH));*/
+
+ connect(Gain, SIGNAL(valueChanged(int)), SLOT(changeGain(int)));
+ connect(dumpInfoButton , SIGNAL(clicked()), SLOT(dumpInfo()));
+ connect(channelListView, SIGNAL(pressed(Q3ListViewItem*,const QPoint&,int)),
+ this, SLOT(channelItemClicked(Q3ListViewItem*,const QPoint&,int)));
+
+ connect(Reverb, SIGNAL (toggled(bool)), SLOT(toggleReverb(bool)));
+ connect(ReverbLevel, SIGNAL (valueChanged (int)), SLOT(changeReverbLevel(int)));
+ connect(ReverbRoomSize, SIGNAL (valueChanged (int)), SLOT(changeReverbRoomSize(int)));
+ connect(ReverbDamping, SIGNAL (valueChanged (int)), SLOT(changeReverbDamping(int)));
+ connect(ReverbWidth, SIGNAL (valueChanged (int)), SLOT(changeReverbWidth(int)));
+
+ connect (Pop, SIGNAL (clicked()), SLOT(popClicked()));
+ connect(sfListView, SIGNAL(pressed(Q3ListViewItem*,const QPoint&,int)),
+ this, SLOT(sfItemClicked(Q3ListViewItem*,const QPoint&,int)));
+ connect(Chorus, SIGNAL (toggled (bool)), SLOT(toggleChorus (bool)));
+ connect(ChorusNumber, SIGNAL (valueChanged (int)), SLOT(changeChorusNumber (int)));
+ connect(ChorusType, SIGNAL (activated (int)), SLOT(changeChorusType (int)));
+ connect(ChorusSpeed, SIGNAL (valueChanged (int)), SLOT(changeChorusSpeed (int)));
+ connect(ChorusDepth, SIGNAL (valueChanged (int)), SLOT(changeChorusDepth (int)));
+ connect(ChorusLevel, SIGNAL (valueChanged (int)), SLOT(changeChorusLevel (int)));
+/*
+ _notifier = new QSocketNotifier(0, QSocketNotifier::Read);
+ connect(_notifier, SIGNAL(activated(int)), SLOT(readData(int)));
+
+ //Setup the ListView
+ sfListView->setColumnWidthMode(MUSE_FLUID_ID_COL,QListView::Maximum);
+ sfListView->setColumnWidthMode(MUSE_FLUID_SFNAME_COL,QListView::Maximum);
+
+ sfListView->setColumnAlignment(MUSE_FLUID_ID_COL,AlignHCenter);
+ sfListView->setSorting(MUSE_FLUID_ID_COL,true);
+ channelListView->setColumnAlignment(MUSE_FLUID_CHANNEL_COL,AlignHCenter);
+
+ _currentlySelectedFont = -1; //No selected font to start with
+ // The GUI-process is killed every time the window is shut,
+ // need to get all parameters from the synth
+
+ requestAllParameters();
+
+ */
+
+ //Clear channels
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++)
+ channels[i] = FS_UNSPECIFIED_ID;
+
+ // 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();
+ }
+
+FluidSynthGui::~FluidSynthGui()
+ {
+ /*
+ delete _notifier;
+ */
+ }
+
+void FluidSynthGui::toggleReverb(bool on) { sendController(0, FS_REVERB_ON, on); }
+void FluidSynthGui::changeReverbLevel(int val) { sendController(0, FS_REVERB_LEVEL, val); }
+void FluidSynthGui::changeReverbRoomSize(int val) { sendController(0, FS_REVERB_ROOMSIZE, val); }
+void FluidSynthGui::changeReverbWidth(int val) { sendController(0, FS_REVERB_WIDTH, val); }
+void FluidSynthGui::changeReverbDamping(int val) { sendController(0, FS_REVERB_DAMPING, val); }
+
+void FluidSynthGui::toggleChorus(bool val) { sendController(0, FS_CHORUS_ON, val); }
+void FluidSynthGui::changeChorusNumber(int val) { sendController(0, FS_CHORUS_NUM, val); }
+void FluidSynthGui::changeChorusType(int val) { sendController(0, FS_CHORUS_TYPE, val); }
+void FluidSynthGui::changeChorusSpeed(int val) { sendController(0, FS_CHORUS_SPEED, val); }
+void FluidSynthGui::changeChorusDepth(int val) { sendController(0, FS_CHORUS_DEPTH, val); }
+void FluidSynthGui::changeChorusLevel(int val) { sendController(0, FS_CHORUS_LEVEL, val); }
+
+ /*
+
+void FluidSynthGui::pushClicked()
+ {
+ const QString& fns = Filename->text();
+ if (fns.isEmpty())
+ return;
+ const char * fn = fns.latin1();
+
+ int datalen = strlen(fn) + 3;
+ unsigned char data [datalen];
+ data[0] = MUSE_FLUID_SOUNDFONT_PUSH;
+ data[1] = MUSE_FLUID_UNSPECIFIED_ID; //This makes the client choose next available external id
+ memcpy(data + 2, fn, strlen(fn) + 1 ); //Store filename
+ sendSysex(data, datalen);
+ data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS; //For simplicity's sake, just get all the soundfont data again.
+ sendSysex(data, 1);
+ printf("Gui sent Sysex.\n");
+
+ return;
+ }
+ */
+
+void FluidSynthGui::loadClicked()
+ {
+ QString filename = Q3FileDialog::getOpenFileName(lastdir, QString("*.[Ss][Ff]2"),
+ this,
+ "Load Soundfont dialog",
+ "Choose soundfont");
+ if (filename != QString::null) {
+ int lastslash = filename.findRev('/');
+ lastdir = filename.left(lastslash);
+
+ sendLastdir(lastdir);
+ sendLoadFont(filename);
+ }
+ }
+
+//---------------------------------------------------------
+// sendLastdir
+// Send the last dir-value to the client
+//---------------------------------------------------------
+
+void FluidSynthGui::sendLastdir(QString dir)
+ {
+ int l = strlen(dir)+2;
+ byte data[l];
+ data[0] = FS_LASTDIR_CHANGE;
+ memcpy(data+1, dir.latin1(), strlen(dir)+1);
+ sendSysex(data,l);
+ }
+
+//---------------------------------------------------------
+// sendLoadFont
+// Tell the client to load a font with first available id
+//---------------------------------------------------------
+
+void FluidSynthGui::sendLoadFont(QString filename)
+ {
+ int l = filename.length()+3;
+ byte data[l];
+ data[0] = FS_PUSH_FONT;
+ data[1] = FS_UNSPECIFIED_ID;
+ memcpy(data+2, filename.latin1(), filename.length()+1);
+ sendSysex(data,l);
+ }
+
+//---------------------------------------------------------
+// processEvent
+//---------------------------------------------------------
+
+void FluidSynthGui::processEvent(const MidiPlayEvent& ev)
+ {
+ //Sysexes sent from the client
+ if (ev.type() == ME_SYSEX) {
+ byte* data = ev.data();
+ switch (*data) {
+ case FS_LASTDIR_CHANGE:
+ lastdir = QString((const char*)data+1);
+ break;
+ case FS_ERROR: {
+ char* msg = (char*) (data+1);
+
+ printf("Muse: fluidsynth error: %s\n", msg);
+
+ break;
+ }
+ case FS_SEND_SOUNDFONTDATA: {
+ int chunk_len;
+ int filename_len;
+
+ int count = (int)*(data+1); //Number of elements
+ byte* cp = data+2; //Point to beginning of first chunk
+ sfListView->clear(); //Clear the listview
+ stack.clear(); //Clear the stack since we're starting over again
+
+ while (count) {
+ FluidGuiSoundFont font;
+ filename_len = strlen((const char*)cp) + 1;
+ font.name = (const char*)cp;
+ font.id = *(cp + filename_len);
+ chunk_len = filename_len + FS_SFDATALEN;
+ stack.push_front(font);
+ cp += chunk_len; //Move to next chunk
+ count--;
+ }
+ updateSoundfontListView();
+ updateChannelListView();
+ break;
+ }
+ case FS_SEND_CHANNELINFO: {
+ byte* chptr = (data+1);
+ for (int i=0; i< FS_MAX_NR_OF_CHANNELS; i++) {
+ byte id = *chptr;
+ byte channel = *(chptr+1);
+ channels[channel] = id;
+ chptr+=2;
+ }
+ updateChannelListView();
+
+ break;
+ }
+ case FS_SEND_DRUMCHANNELINFO: {
+ byte* drumchptr = (data+1);
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ drumchannels[i] = *drumchptr;
+ drumchptr++;
+ }
+ updateChannelListView();
+ break;
+ }
+ default:
+ if (FS_DEBUG)
+ printf("FluidSynthGui::processEvent() : Unknown Sysex received: %d\n", ev.type());
+ break;
+ }
+ }
+ //Controllers sent from the client:
+ else
+ if(ev.type() == ME_CONTROLLER) {
+ int id = ev.dataA();
+ int val = ev.dataB();
+ switch (id) {
+ case FS_GAIN: {
+ bool sb = Gain->signalsBlocked();
+ Gain->blockSignals(true);
+ // Update Gain-slider without causing it to respond to it's own signal (and send another msg to the synth)
+ Gain->setValue(val);
+ Gain->blockSignals(sb);
+ break;
+ }
+ case FS_REVERB_ON: {
+ bool sb = Reverb->signalsBlocked();
+ Reverb->blockSignals(true);
+ Reverb->setChecked(val);
+ Reverb->blockSignals(sb);
+ break;
+ }
+ case FS_REVERB_LEVEL: {
+ bool sb = ReverbLevel->signalsBlocked();
+ ReverbLevel->blockSignals(true);
+ ReverbLevel->setValue(val);
+ ReverbLevel->blockSignals(sb);
+ break;
+ }
+ case FS_REVERB_DAMPING: {
+ bool sb = ReverbDamping->signalsBlocked();
+ ReverbDamping->blockSignals(true);
+ ReverbDamping->setValue(val);
+ ReverbDamping->blockSignals(sb);
+ break;
+ }
+ case FS_REVERB_ROOMSIZE: {
+ bool sb = ReverbRoomSize->signalsBlocked();
+ ReverbRoomSize->blockSignals(true);
+ ReverbRoomSize->setValue(val);
+ ReverbRoomSize->blockSignals(sb);
+ break;
+ }
+ case FS_REVERB_WIDTH: {
+ bool sb = ReverbWidth->signalsBlocked();
+ ReverbWidth->blockSignals(true);
+ ReverbWidth->setValue(val);
+ ReverbWidth->blockSignals(sb);
+ break;
+ }
+ case FS_CHORUS_ON: {
+ Chorus->blockSignals(true);
+ Chorus->setChecked(val);
+ Chorus->blockSignals(false);
+ break;
+ }
+ case FS_CHORUS_SPEED: {
+ ChorusSpeed->blockSignals(true);
+ ChorusSpeed->setValue(val);
+ ChorusSpeed->blockSignals(false);
+ break;
+ }
+ case FS_CHORUS_NUM: {
+ ChorusNumber->blockSignals(true);
+ ChorusNumber->setValue(val);
+ ChorusNumber->blockSignals(false);
+ break;
+ }
+ case FS_CHORUS_TYPE: {
+ ChorusType->blockSignals(true);
+ ChorusType->setCurrentItem(val);
+ ChorusType->blockSignals(false);
+ break;
+ }
+ case FS_CHORUS_DEPTH: {
+ ChorusDepth->blockSignals(true);
+ ChorusDepth->setValue(val);
+ ChorusDepth->blockSignals(false);
+ break;
+ }
+ case FS_CHORUS_LEVEL: {
+ ChorusLevel->blockSignals(true);
+ ChorusLevel->setValue(val);
+ ChorusLevel->blockSignals(false);
+ break;
+ }
+ default:
+ if (FS_DEBUG)
+ printf("FluidSynthGui::processEvent() : Unknown controller sent to gui: %x\n",id);
+ break;
+ }
+ }
+ else
+ if (FS_DEBUG)
+ printf("FluidSynthGui::processEvent - unknown event of type %dreceived from synth.\n", ev.type());
+ }
+
+//---------------------------------------------------------
+// readMessage
+//---------------------------------------------------------
+void FluidSynthGui::readMessage(int)
+ {
+ MessGui::readMessage();
+ }
+
+//---------------------------------------------------------
+// updateChannels
+//---------------------------------------------------------
+void FluidSynthGui::updateChannelListView()
+ {
+ if (FS_DEBUG)
+ printf("FluidSynthGui::updateChannelListView\n");
+ channelListView->clear();
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ QString chanstr, sfidstr, drumchanstr;
+
+ //Soundfont id string:
+ if (channels[i] == FS_UNSPECIFIED_ID)
+ sfidstr = "unspecified";
+ else
+ sfidstr = getSoundFontName(channels[i]);
+ //Channel string:
+ chanstr = QString::number(i+1);
+ if (chanstr.length()==1)
+ chanstr = "0" + chanstr;
+
+ //Drumchan string:
+ if (drumchannels[i])
+ drumchanstr = "Yes";
+ else
+ drumchanstr = "No";
+ Q3ListViewItem* qlvNewItem = new Q3ListViewItem(channelListView);
+ qlvNewItem->setText(FS_CHANNEL_COL, chanstr);
+ qlvNewItem->setPixmap(FS_SF_ID_COL, buttondown_xpm);
+ qlvNewItem->setText(FS_SF_ID_COL, sfidstr);
+ qlvNewItem->setPixmap(FS_DRUM_CHANNEL_COL, buttondown_xpm);
+ qlvNewItem->setText(FS_DRUM_CHANNEL_COL, drumchanstr);
+ channelListView->insertItem(qlvNewItem);
+ }
+ }
+
+//---------------------------------------------------------
+// updateSoundfontListView
+//---------------------------------------------------------
+void FluidSynthGui::updateSoundfontListView()
+ {
+ sfListView->clear(); //Clear the listview
+ for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
+ Q3ListViewItem* qlvNewItem = new Q3ListViewItem(sfListView);
+ QString qsid = QString("%1").arg(it->id);
+ qlvNewItem->setText(FS_ID_COL, qsid);
+ qlvNewItem->setText(FS_SFNAME_COL, QString(it->name));
+ sfListView->insertItem(qlvNewItem);
+ }
+ sfListView->sort();
+ }
+
+//---------------------------------------------------------
+// changeGain
+//---------------------------------------------------------
+void FluidSynthGui::changeGain(int value)
+ {
+ sendController(0, FS_GAIN, value);
+ }
+
+
+//---------------------------------------------------------
+// dumpInfoButton
+//---------------------------------------------------------
+void FluidSynthGui::dumpInfo()
+ {
+ byte data[1];
+ data[0] = FS_DUMP_INFO;
+ sendSysex(data, 1);
+ }
+
+//---------------------------------------------------------
+// getSoundFontName
+//---------------------------------------------------------
+
+QString FluidSynthGui::getSoundFontName(int id)
+ {
+ QString name = NULL;
+ for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
+ if (id == it->id) {
+ name = it->name;
+ continue;
+ }
+ }
+ return name;
+ }
+
+//---------------------------------------------------------
+// channelItemClicked
+// change channel parameters like soundfont / drumchannel on/off
+//---------------------------------------------------------
+
+void FluidSynthGui::channelItemClicked(Q3ListViewItem* item, const QPoint&, int col)
+ {
+ if (col == FS_SF_ID_COL) {
+ Q3PopupMenu* popup = new Q3PopupMenu(this);
+ QPoint ppt = channelListView->itemRect(item).bottomLeft();
+ Q3ListView* listView = item->listView();
+ ppt += QPoint(listView->header()->sectionPos(col), listView->header()->height());
+ ppt = listView->mapToGlobal(ppt);
+
+ int i = 0;
+ for (std::list<FluidGuiSoundFont>::reverse_iterator it = stack.rbegin(); it != stack.rend(); it++) {
+ i++;
+ /*byte* d = (byte*) it->name.latin1();
+ for (int i=0; i<96; i++) {
+ if (i%16 == 0)
+ printf("%x:",(i+d));
+
+ printf("%x ",*(d-48+i));
+
+ if (i%16 == 15)
+ printf("\n");
+ }
+ for (int i=0; i<96; i++) {
+ if (i%16 == 0)
+ printf("%x:",(i+d-48));
+
+ printf("%c ",*(d-48+i));
+
+ if (i%16 == 15)
+ printf("\n");
+ }
+ printf("\n\n");*/
+ popup->insertItem(it->name,i);
+ }
+ int lastindex = i+1;
+ popup->insertItem("unspecified",lastindex);
+ int index = popup->exec(ppt, 0);
+ if (index !=-1) {
+ byte sfid;
+ QString fontname;
+ if (index == lastindex) {
+ sfid = FS_UNSPECIFIED_ID;
+ fontname = "unspecified"; //Actually, it's not possible to reset fluid-channels as for now,
+ } //so this is just a dummy that makes the synth block any events for the channel
+ else {
+ sfid = getSoundFontId(popup->text(index));
+ fontname = getSoundFontName(sfid);
+ }
+ byte channel = atoi(item->text(FS_CHANNEL_COL).latin1()) - 1;
+ sendChannelChange(sfid, channel);
+ item->setText(FS_SF_ID_COL, fontname);
+ }
+ delete popup;
+ }
+ // Drumchannel column:
+ else if (col == FS_DRUM_CHANNEL_COL) {
+ Q3PopupMenu* popup = new Q3PopupMenu(this);
+ QPoint ppt = channelListView->itemRect(item).bottomLeft();
+ Q3ListView* listView = item->listView();
+ ppt += QPoint(listView->header()->sectionPos(col), listView->header()->height());
+ ppt = listView->mapToGlobal(ppt);
+ popup->insertItem("Yes", 1);
+ popup->insertItem("No", 0);
+ byte channel = atoi(item->text(FS_CHANNEL_COL).latin1()) - 1;
+
+ int index = popup->exec(ppt, 0);
+ if (index != drumchannels[channel] && index !=-1) {
+ sendDrumChannelChange(index, channel);
+ drumchannels[channel] = index;
+ item->setText(FS_DRUM_CHANNEL_COL, index == 0 ? "No" : "Yes" );
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// getSoundFontId
+//---------------------------------------------------------
+
+int FluidSynthGui::getSoundFontId(QString q)
+ {
+ int id = -1;
+ for (std::list<FluidGuiSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
+ if (q == it->name)
+ id = it->id;
+ }
+ return id;
+ }
+
+//---------------------------------------------------------
+// sendChannelChange
+// Tell the client to set a soundfont to a specific fluid channel
+//---------------------------------------------------------
+
+void FluidSynthGui::sendChannelChange(byte font_id, byte channel)
+ {
+ byte data[3];
+ data[0] = FS_SOUNDFONT_CHANNEL_SET;
+ data[1] = font_id;
+ data[2] = channel;
+ sendSysex(data, 3);
+ }
+
+//---------------------------------------------------------
+// sendDrumChannelChange
+// Tell the client to set a specific channel to drum channel (equiv to midichan 10)
+//---------------------------------------------------------
+void FluidSynthGui::sendDrumChannelChange(byte onoff, byte channel)
+ {
+ byte data[3];
+ data[0] = FS_DRUMCHANNEL_SET;
+ data[1] = onoff;
+ data[2] = channel;
+ sendSysex(data, 3);
+ if (FS_DEBUG)
+ printf("Sent FS_DRUMCHANNEL_SET for channel %d, status: %d\n", channel, onoff);
+ }
+
+void FluidSynthGui::popClicked()
+ {
+ byte data[2];
+ data[0] = FS_SOUNDFONT_POP;
+ data[1] = currentlySelectedFont;
+ sendSysex(data,2);
+ }
+
+void FluidSynthGui::sfItemClicked(Q3ListViewItem* item, const QPoint&, int /*col*/)
+ {
+ if (item != 0) {
+ currentlySelectedFont = atoi(item->text(FS_ID_COL));
+ Pop->setEnabled(true);
+ }
+ else {
+ currentlySelectedFont = -1;
+ Pop->setEnabled(false);
+ }
+ }
+
+#if 0
+
+
+
+void FluidSynthGui::readData (int fd)
+ {
+ unsigned char buffer[512];
+ int n = ::read(fd, buffer, 512);
+// dataInput(buffer, n);
+ }
+
+
+
+void FluidSynthGui::changeReverbRoomSize (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
+ "roomsize", value);
+}
+
+void FluidSynthGui::changeReverbDamping (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
+ "damping", value);
+}
+
+void FluidSynthGui::changeReverbWidth (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_REVERB,
+ "width", value);
+}
+
+
+void FluidSynthGui::changeChorusNumber (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
+ "number", value);
+}
+
+void FluidSynthGui::changeChorusType (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
+ "type", value);
+}
+
+void FluidSynthGui::changeChorusSpeed (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
+ "speed", value); //TODO: Right now illegal values may be sent.
+ //Make sure they stay within fluidsynths legal boundaries (0.29-5Hz) dunno what that is in doubles
+ //This might be the case for the other chorus parameters as well
+}
+
+void FluidSynthGui::changeChorusDepth (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
+ "depth", value);
+}
+
+void FluidSynthGui::changeChorusLevel (int value) {
+ sendParameterChange(MUSE_FLUID_PARAMETER_CHORUS,
+ "level", value);
+}
+
+
+void FluidSynthGui::sysexReceived(unsigned char const * data, int len)
+ {
+ char * cp;
+ double * dp;
+ //std::cerr << "FluidSynthGui, sysexReceived: " << (int) *data << std::endl;
+ switch (*data) {
+ case MUSE_FLUID_CLIENT_SEND_PARAMETER:
+ cp = (char *) (data + 2);
+ dp = (double *) (data + strlen (cp) + 3);
+ setParameter ((int) *(data+1), cp, *dp);
+ break;
+
+ case MUSE_FLUID_GAIN_GET:
+ dp = (double *) (data + 1);
+ Gain->setValue ((int) (*dp * 12.8));
+ break;
+
+ case MUSE_FLUID_CLIENT_LASTDIR_CHANGE: {
+ if (*(char*)(data+1) != MUSE_FLUID_UNSPECIFIED_LASTDIR)
+ _lastDir = QString((char*)(data+1));
+ else
+ _lastDir="";
+ }
+
+ default:
+ break;
+ }
+ }
+
+
+
+
+
+
+
+void FluidSynthGui::requestAllParameters () {
+ unsigned char data[1];
+
+ //data[0] = MUSE_FLUID_ADVGUI_GET;
+ //sendSysex (data, 1);
+ dbgMsg("Requesting all parameters!\n");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "on");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "roomsize");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "damping");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "width");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_REVERB, "level");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "on");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "number");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "type");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "speed");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "depth");
+ sendParameterRequest (MUSE_FLUID_PARAMETER_CHORUS, "level");
+ data[0] = MUSE_FLUID_GAIN_GET;
+ sendSysex (data, 1);
+ data[0] = MUSE_FLUID_GUI_REQ_SOUNDFONTS;
+ sendSysex (data, 1);
+}
+
+bool FluidSynthGui::sendParameterRequest (int parameterSet, const char * parameter) {
+ size_t parameterMem = strlen (parameter) + 1;
+ int datalen = 2 + parameterMem;
+ unsigned char * data = new unsigned char [datalen];
+ *data = MUSE_FLUID_GUI_REQ_FXPARAMETER_GET;
+ *(data + 1) = (char) parameterSet;
+ memcpy (data + 2, parameter, parameterMem);
+ sendSysex (data, datalen);
+ delete data;
+ return true;
+}
+
+void FluidSynthGui::setParameter (int parameterSet, const char * parameter, double value) {
+ int ival = (int) (value * 128);
+ std::string ps (parameter);
+ if (parameterSet == MUSE_FLUID_PARAMETER_REVERB) {
+ if (ps == "roomsize") {
+ ReverbRoomSize->setValue (ival);
+ } else if (ps == "damping") {
+ ReverbDamping->setValue (ival);
+ } else if (ps == "width") {
+ ReverbWidth->setValue (ival);
+ } else if (ps == "level") {
+ ReverbLevel->setValue (ival);
+ } else if (ps == "on") {
+ Reverb->setChecked (ival);
+ }
+ } else {
+ if (ps == "number") {
+ ChorusNumber->setValue (ival);
+ } else if (ps == "type") {
+ ChorusType->setCurrentItem (ival);
+ } else if (ps == "speed") {
+ ChorusSpeed->setValue (ival);
+ } else if (ps == "depth") {
+ ChorusDepth->setValue (ival);
+ } else if (ps == "level") {
+ ChorusLevel->setValue (ival);
+ } else if (ps == "on") {
+ Chorus->setChecked (ival);
+ }
+ }
+}
+
+//Sends parameter to reverb or chorus
+bool FluidSynthGui::sendParameterChange (int parameterSet, const char * parameter, int value) {
+ size_t parameterMem = strlen (parameter) + 1;
+ int datalen = 2 + parameterMem + sizeof (double);
+ unsigned char * data = new unsigned char [datalen];
+ *data = (unsigned char) MUSE_FLUID_GUI_REQ_FXPARAMETER_SET;
+ *(data + 1) = (unsigned char) parameterSet;
+ memcpy (data + 2, parameter, parameterMem);
+ double * dp = (double *) (data + 2 + parameterMem);
+ *dp = ((double) value) / ((double) 128.0);
+ sendSysex (data, datalen);
+ delete data;
+ return true;
+}
+
+void FluidSynthGui::dbgMsg(const char* msg)
+ {
+ if (MUSE_FLUID_DEBUG)
+ std::cerr << msg << std::endl;
+ }
+//---------------------------------------------------------
+// main
+//---------------------------------------------------------
+
+/*QString museProject;
+QString museGlobalShare;
+QString museUser;*/
+
+
+int main(int argc, char* argv[])
+{
+/*
+ museUser = getenv("MUSEHOME");
+ if (museUser == 0)
+ museUser = getenv("HOME");
+ museGlobalShare = getenv("MUSE");
+ if (museGlobalShare == 0) {
+ museGlobalShare = "/usr/muse";
+ if (access(museGlobalShare.latin1(), R_OK) != 0) {
+ museGlobalShare = "/usr/local/muse";
+ if (access(museGlobalShare.latin1(), R_OK) != 0)
+ museGlobalShare = museUser;
+ }
+ }*/
+ char * instanceName = argv[1];
+ QApplication app (argc, argv, true);
+ QWidget* w = new FluidSynthGui ();
+ if (argc > 1)
+ w->setCaption(QString(instanceName));
+ w->show();
+ app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+ qApp->exec();
+}
+
+#endif
diff --git a/muse2/synti/fluidsynth/fluidsynthgui.h b/muse2/synti/fluidsynth/fluidsynthgui.h
new file mode 100644
index 00000000..d464dee2
--- /dev/null
+++ b/muse2/synti/fluidsynth/fluidsynthgui.h
@@ -0,0 +1,225 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynthgui.h,v 1.10.2.3 2009/02/02 21:38:02 terminator356 Exp $
+ *
+ */
+
+#ifndef __MUSE_FLUIDSYNTHGUI_H__
+#define __MUSE_FLUIDSYNTHGUI_H__
+
+#include "fluidsynthguibase.h"
+#include "libsynti/gui.h"
+#include <list>
+
+struct FluidChannel;
+#define FS_DEBUG 0 //Turn on/off debug
+/*
+#include <list>
+#include <string>
+#include <qscrollview.h>
+
+#include <qevent.h>
+#include <qmenubar.h>
+#include <qsocketnotifier.h>
+#include <alsa/asoundlib.h>
+#include <qlistview.h>
+#include <qheader.h>
+#include "muse/debug.h"
+*/
+
+#define FS_MAX_NR_OF_CHANNELS 16
+#define FS_UNSPECIFIED_FONT 126
+#define FS_UNSPECIFIED_ID 127
+#define FS_UNSPECIFIED_PRESET 129
+#define FS_CHANNEL_COL 0
+#define FS_ID_COL 0
+#define FS_SFNAME_COL 1
+#define FS_SF_ID_COL 1
+#define FS_DRUM_CHANNEL_COL 2
+
+#define FS_SFDATALEN 1
+#define FS_VERSION_MAJOR 0
+#define FS_VERSION_MINOR 4
+#define FS_INIT_DATA_HEADER_SIZE 4
+#define FS_INIT_CHANNEL_SECTION 255
+
+// Predefined init-values for fluidsynth
+#define FS_PREDEF_VOLUME 0.063
+#define FS_PREDEF_REVERB_LEVEL 0.125
+#define FS_PREDEF_REVERB_ROOMSIZE 0.125
+#define FS_PREDEF_REVERB_DAMPING 0.3
+#define FS_PREDEF_REVERB_WIDTH 0.125
+#define FS_PREDEF_CHORUS_NUM 3
+#define FS_PREDEF_CHORUS_TYPE 1
+#define FS_PREDEF_CHORUS_SPEED 0.5
+#define FS_PREDEF_CHORUS_DEPTH 0.3
+#define FS_PREDEF_CHORUS_LEVEL 0.5
+typedef unsigned char byte;
+
+
+/*
+
+
+#define MUSE_FLUID_UNSPECIFIED_CHANNEL 127
+
+
+#define MUSE_FLUID_UNSPECIFIED_LASTDIR 127
+*/
+
+//Various messages the gui and the client uses to communicate
+enum {
+ FS_LASTDIR_CHANGE = 1,
+ FS_PUSH_FONT
+ };
+
+enum {
+ //FS_GAIN_SET,
+ FS_SEND_SOUNDFONTDATA = 4,
+ FS_SEND_CHANNELINFO, //Used by synth to send info about all channels, on init
+ FS_SOUNDFONT_CHANNEL_SET,
+ FS_SOUNDFONT_POP,
+ FS_SEND_DRUMCHANNELINFO, //Used by synth to send drumchannel status about all channels, on init
+ FS_DRUMCHANNEL_SET //Used by gui to set drumchannel status for specific channel
+ };
+
+enum
+ {
+ FS_DUMP_INFO = 240,
+ FS_ERROR,
+ FS_INIT_DATA
+ };
+/*
+enum {
+ MUSE_FLUID_REVERB = 100,
+ MUSE_FLUID_REVERB_ROOMSIZE,
+ MUSE_FLUID_REVERB_DAMPING,
+ MUSE_FLUID_REVERB_WIDTH,
+ MUSE_FLUID_REVERB_LEVEL,
+ MUSE_FLUID_CHORUS,
+ MUSE_FLUID_CHORUS_NUMBER,
+ MUSE_FLUID_CHORUS_TYPE,
+ MUSE_FLUID_CHORUS_SPEED,
+ MUSE_FLUID_CHORUS_DEPTH,
+ MUSE_FLUID_CHORUS_LEVEL,
+ MUSE_FLUID_GAIN,
+ MUSE_FLUID_SOUNDFONT,
+ MUSE_FLUID_STRING,
+ MUSE_FLUID_STRING_END
+ };
+
+enum {
+ MUSE_FLUID_CLIENT_SEND_PARAMETER = 33,
+ MUSE_FLUID_CLIENT_SEND_SOUNDFONTS,
+ MUSE_FLUID_PARAMETER_GET,
+ MUSE_FLUID_PARAMETER_REVERB,
+ MUSE_FLUID_PARAMETER_CHORUS,
+
+ MUSE_FLUID_GAIN_GET,
+ MUSE_FLUID_SOUNDFONT_PUSH,
+ MUSE_FLUID_SOUNDFONT_POP,
+
+ MUSE_FLUID_CLIENT_SEND_ERROR = 44,
+ MUSE_FLUID_SOUNDFONT_LOAD,
+ ,
+ MUSE_FLUID_CLIENT_RESTORE_CHANNELDATA,
+ MUSE_FLUID_CLIENT_INIT_PARAMS,
+ MUSE_FLUID_CLIENT_LASTDIR_CHANGE,
+
+ MUSE_FLUID_GUI_REQ_SOUNDFONTS = 60,
+ MUSE_FLUID_GUI_REQ_FXPARAMETER_SET,
+ MUSE_FLUID_GUI_REQ_FXPARAMETER_GET,
+ MUSE_FLUID_GUI_SEND_ERROR,
+ MUSE_FLUID_GUI_LASTDIR_CHANGE
+ };
+*/
+
+struct FluidGuiSoundFont
+ {
+ QString filename;
+ QString name;
+ byte id;
+ };
+
+//---------------------------------------------------------
+// FluidSynthGui
+//---------------------------------------------------------
+
+class FluidSynthGui : public FLUIDSynthGuiBase, public MessGui
+ {
+ Q_OBJECT
+ private:
+ virtual void processEvent(const MidiPlayEvent& ev);
+ void sendLastdir(QString);
+ void sendLoadFont(QString);
+ void sendChannelChange(byte font_id, byte channel);
+ void sendDrumChannelChange(byte onoff, byte channel);
+ void updateSoundfontListView();
+ void updateChannelListView();
+
+ QString getSoundFontName(int id);
+ int getSoundFontId(QString q);
+ QString lastdir;
+ std::list<FluidGuiSoundFont> stack;
+ byte channels[FS_MAX_NR_OF_CHANNELS]; //Array of bytes, for mapping soundfonts to individual channels
+ byte drumchannels[FS_MAX_NR_OF_CHANNELS]; // Array of bytes for setting channels to drumchannels or not (equiv to midichan 10)
+
+ int currentlySelectedFont; //Font currently selected in sfListView. -1 if none selected
+
+/*
+ unsigned _smallH;
+ unsigned _bigH;
+ QSocketNotifier * _notifier;
+ bool sendParameterChange (int, const char *, int);
+ void setParameter (int, const char *, double);
+ void requestAllParameters ();
+ void dbgMsg(const char*);
+ bool sendParameterRequest(int, const char *);
+ //void dealWithSysex (unsigned char const * data, int datalen);
+
+
+
+
+
+
+*/
+ private slots:
+ void loadClicked();
+ void readMessage(int);
+ void changeGain(int);
+ void dumpInfo();
+ void channelItemClicked(Q3ListViewItem* item, const QPoint&, int col);
+ void toggleReverb(bool);
+ void changeReverbLevel (int);
+ void changeReverbRoomSize(int val);
+ void changeReverbWidth(int val);
+ void changeReverbDamping(int val);
+ void toggleChorus(bool);
+ void changeChorusNumber(int);
+ void changeChorusType(int);
+ void changeChorusSpeed(int);
+ void changeChorusDepth(int);
+ void changeChorusLevel(int);
+
+ void popClicked();
+ void sfItemClicked(Q3ListViewItem* item, const QPoint&, int col);
+ /*
+ void readData(int);
+
+
+
+
+ */
+
+ public:
+// virtual void sysexReceived (const unsigned char *, int);
+// virtual void controllerReceived(int, int, int);
+
+ FluidSynthGui();
+ ~FluidSynthGui();
+};
+
+
+#endif /* __MUSE_FLUIDSYNTHGUI_H__ */
diff --git a/muse2/synti/fluidsynth/fluidsynthguibase.ui b/muse2/synti/fluidsynth/fluidsynthguibase.ui
new file mode 100644
index 00000000..336ee9fa
--- /dev/null
+++ b/muse2/synti/fluidsynth/fluidsynthguibase.ui
@@ -0,0 +1,632 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>FLUIDSynthGuiBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>FLUIDSynthGuiBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>617</width>
+ <height>514</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>FLUID Synth</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="resizeMode">
+ <enum>Minimum</enum>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame" row="2" column="0">
+ <property name="name">
+ <cstring>DiskButtons</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>Push</cstring>
+ </property>
+ <property name="text">
+ <string>Load</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>Pop</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>dumpInfoButton</cstring>
+ </property>
+ <property name="text">
+ <string>Dump Info</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView" row="1" column="0">
+ <column>
+ <property name="text">
+ <string>ID</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Fontname</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>sfListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QListView" row="1" column="1">
+ <column>
+ <property name="text">
+ <string>Chnl</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Soundfont</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Drum Chnl</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>channelListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QFrame" row="3" column="0">
+ <property name="name">
+ <cstring>ReverbFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSlider" row="4" column="1">
+ <property name="name">
+ <cstring>ReverbLevel</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QSlider" row="3" column="1">
+ <property name="name">
+ <cstring>ReverbWidth</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QSlider" row="2" column="1">
+ <property name="name">
+ <cstring>ReverbDamping</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QSlider" row="1" column="1">
+ <property name="name">
+ <cstring>ReverbRoomSize</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>ReverbLevelLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Level</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>ReverbWidthLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Width</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>ReverbDampingLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Damping</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>ReverbRoomSizeLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Room Size</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Reverb</cstring>
+ </property>
+ <property name="text">
+ <string>Reverb</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>fontSetupLabel</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>CHANNEL SETUP</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QFrame" row="3" column="1">
+ <property name="name">
+ <cstring>ChorusFrame</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="4">
+ <item>
+ <property name="text">
+ <string>Sine</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Triangle</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>ChorusType</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>ChorusTypeLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ChorusNumber</cstring>
+ </property>
+ <property name="maxValue">
+ <number>127</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>ChorusNumberLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Number</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSlider" row="2" column="2" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>ChorusSpeed</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ChorusSpeedLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Speed</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSlider" row="3" column="2" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>ChorusDepth</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ChorusDepthLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Depth</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSlider" row="4" column="2" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>ChorusLevel</cstring>
+ </property>
+ <property name="maxValue">
+ <number>16383</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="pageStep">
+ <number>1638</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1638</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ChorusLevelLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Level</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>Chorus</cstring>
+ </property>
+ <property name="text">
+ <string>Chorus</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>GainBox</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>GainLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Gain</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>Gain</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>127</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>13</number>
+ </property>
+ <property name="tracking">
+ <bool>true</bool>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>7</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>loadedFontsLabel</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>LOADED SOUNDFONTS</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>pixmapLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pixmap">
+ <pixmap>image3</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1195">89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af400000472494441545885c557cb6e1c45143db7a77b7a5ec699b1c71e3fb0239010f80ff807d6d9b065c12f20250a2862c10690901c93c40111136c1ca448880dec67c18e05444158b63103f22376e2b167babaaafb66d1efd780c2c225cda3abcebdf7dc5375abaaa9dbede2229bf67f8c7f3416f8a7f2225f0881efed0e379a33a8373bf8c1997b61127afce1eb3d83c7da1d58fd535c693fa35186f5e60c94f4f8d7c63bc0596f64a08dfd0657c79be81fede3ed793bf49d5060627109f5d61c5af3afe1dba37661561b87930c3621052005c05cc683934e217e7dbfc5ad975f47bd3587c9c5a5c4584860e3609635ad062508aea3a331b150984d656c0aca262801289f84596f17e2c7da97c1ae01250844556c1e2f8464430266bd0d290065fb59b9657cf3cf426e56a55223c42adb23415a2d37f8fdde5ca856e0bb5c9dc82a0054c28c824fb996cd6a6def323bb294c13ab686fbbd573384cdfa5406cbae992470e7b769766c2d03845bc6178fe7134ecbd5c90c2ef81895163eeb9642fceaa319663673c812ee3ef62a470700add480140c04a60410111880d9e8e0f6af1a2b5ba0d2b884ea4b065c051001cc9e01b38707e9189f59c2e7bf3c612a95506f4e43d914f9856f0780b43a4202400d52a4c563dfc040a5311bf64a2b1a4be38908546aa076c973ce0e41298053780201a84604d82d7b9287aed807e505f3dc913f42218672b1488c47fdae6b44041ca5c3f165050249bddf22074414e2029b64e0081f27cbe1782946c0a64cd024816c0bc7f3120fc213122403169e9dd7496fbdb7c56393af8099235fcce122cccf8863dfc162a418249a42cec107937cf66407baeb185e6dc663b8482a3eaa152850d81f4b8a5d03ba23c9dfcf933629d5121aa495cf1da7c8679e1f6640490dbab4140c334636cd209f7c3edb603898f73cd631901c4a50b7dbc5079b6f7242af3438a70a463db3bf8646e19919ef5ff999740050820b252e4a20dd97988ea0a246f8092a4c07006939007975995f7ee9d0c5cf9efdbfe3999d88803db4a1e95580a333205a95f1dd4c8bf5e568c3c1024c2d8e9c8a701d152760c128a7cff3a862953880eb9cc3a8cc82b46a6c9b8ee302c702caee41d3aad0cd6950c1b55379874a406000a0950fb44fb072759b00e09d6b43361b6f80fce94a3466b82c21fa8fb0fae19000e0dd1b25d6cda95cbf5e4cff3e70ebfa1e498b33e7b6b41cac5cfd3d4cf7ce8d3ed9e7cff2ef0336c11e9c86c10160e5da16c9a1cafa15c0adeb7f52a8000048cb0669d14d05001cf934c37cd8efc1ac37915713f6e03083178363948ca40acc32fc1f4e903d3849317560f577330ed73e3923391c66b31a0adcfbf86966fbfaf2a32d525652057b1025161258fb749ba425fd4ba60b717e88f56591bb1f8ac1912f7b74291583e33ca88f3f8012ae7f295510677b59020020ce77600f4f21067f637d79bb7033deb8d92329546c4e1d6cdcdc2dc4af2fef9238ffcbf37db68bcddb51628937a3efee1e1170549849bcd98343687a0700c1758ab30fda83d51e01d9b7a7177e377c786f87e4f014d23ac5c3affef8af8777a6d145bf9e3f076c35aaedab709f8e0000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="269">789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade652323452002220a1a4c3a5a4a790aca06c000620ae32886b649096666801964502e4f1959595c13c6565301fc481626c7c985a65b2ed43e2d75a73010022253132</data>
+ </image>
+ <image name="image2">
+ <data format="XPM.GZ" length="269">789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade652323452002220a1a4c3a5a4a790aca06c000620ae32886b649096666801964502e4f29551f9ca500165085f590f86c17ca81c88063b07aa57991cfb6badb90035703153</data>
+ </image>
+ <image name="image3">
+ <data format="PNG" length="7252">89504e470d0a1a0a0000000d494844520000007c0000002d08060000006ccc0fec00001c1b49444154789ced9c779ca55779dfbfe7bcedf6693bb333b35d5af506261059103b9490c40ec514f1010ca60a442008448bb1892146b11cba648a4237b215d1314522d8a0c4a08201f5bada5d6d9d3e73fb7dcb394ffe786f9d99d5162448849fcfe7eedeb9e7bee7fc9ee777cef33ca75df5939ffc847f96df1c717fdd007e9572cd4c227e2e87761c4061ad256935b9705ca95f37b65f95fc4610fe95e5408a1bc6993ab584e3fb28a54001229824e1fbb5aad4171728cfcdf08a9dc5c734f98f69c2af3ea864646a33635b87f1820cda7152b2fb443942decd11e446c80e4f70edec21b9703c7ccc927ec2847ff6be86f8d9028ee7910e17b0d660a290b05ee3b567977ead46bb76be201bb66e22532ca21d1750580322abbfa950ca41bb59b2251fc7cbf1b5f919795e69f1d74efa1776c5e20401da75514a03828913a2469d579d9639217cea7893b62fedf3253fba81205fc4f503b476daee11440463624c1811b51ab4aa2bd4571679cd192706ee44e5cb8ba3529a98c6cf76e2f57a440f4a67e08bb5c451486d719685bdbb78edd9f95f19f6ab6eaf497e740399e21041ae90dad7f5d05aa50005ac589230246ad668ac2cf392e9fa71e13b66c23f738f95e1e9ad644b235df7c87ab94edbb2622d2689899a0d1a2b8b94670f70d1398f3ef1d72e8c4b697c0a2f936d8f8a75c8eea090bef77d4522421285d496e759dcf720179d1d3caab83ffeb3b20c4f6da130328e972be07a3e5aebd4bedd9e2803efc55a9238a4592d539d3bc4cb7744c784f19808fffcae408627b7121487701cb71b07bb76ecbce96bb2f3d68ac5c43161bd4265fe307fb4e3f87ae4b1ca95b754647cdba914366cc40bb2eb635c4d74ffff7da0bba4c7318d950596f63fc845e7ba8f0aeecfddef4b69629a4c6918d70b505a0f405a83b10db0f3913586a859a33a7788976e59392ac6a312feb9fb72323cbd153f57eabac71311b196a8d5a0b134c7e2c10779d3bf2c3c6206bce2e69a8c6d3985c2d8465c3fb326313b5111041b2734ca8b2c1fdccdebce7b64a76f5fdc332cc5f169fc6c01e568d46a7773ac38c512b71a54e60ef1b26d0f9f7b3c2ce157dde1cbc8f44904853eb28f120b8fdc523bc6c711cdf222cb0776f386273abfb401afb8a925a39b77921f19c7f18394ec13c5b85afaa66eadca12cb87f7f2fac7d95f1ef38d0d19d97432f99109dc2083d269e83921dcdddc43885b75ca33fb78e5a9e523623c22e11fbb31920d5bcf203b34f6cb93dd074e009bc484d515ca33fb78fd6f1d5bec594f3efe532d4353dbc81447713cef9125bb236d743649086b652a73fbb9e8bce60963bef2662bc35327911d1ac5f1fc47067307a3b544f50acb071fe4f58f5fdfae4724fc33f74e4871c3e674d4c0609c5b2f06f657bf5e92b42a4e4a3bf6d4976628cf3ec4a54f3fbe058f4fdd5692e2d8347eae8876ddf5db5dafedf56279bfaca74b3fe6b0417d7186f2ec5e2e7ddaf185a54fdd5a94c28669825c09e5ba6b1df8c3e1399acddb1f4912d3589967e1a17b78eb53736b9a5897f02b6f0e64786a277eb688d27dcf1ccda0ab9a17e8a6c8695c550320452c268a08ebcb345616682ccff1b667ae05d92f57dc14487e6423d9c2084e90e966e25d7c5d3c82f4a5e7ddf6d7e05e950dada75fbf5622d838a455afd05899a3be7488b73ff3e13beb1537fa921f9920531cc5f5b33d17be2eee556df7656f47d5a78d2f099b54e6f7f1fac72d1f1be19fbe7b9be48626504ebb178a60ad41ac49696ccf10faa73b2a45d155c6c42149d4c49a04a5348e17e006391cd7efe9d8ae43acc1c41149ab4ed8ac10376b189320d62236c1442d945678d922417e984c6138ed8c8ed7af6b57ac8949c20649d442c4a2b5831be4dac67652e3598b3531d618446c5a8fd668eda0b48352ce1a627a8e42b056b07144dcaa12d62b44ad1ad624088242a19db4cd203744ba4015a0da6bf8eb6146a46b5b543fa1824d12e2a88169eba3b48337a0cf2a8cd6d2aa2db3b8ff6edef6f4c1d9c59a95b68ffe9fbc0c4d0e61add3f6112979adda12617591240e01dbabbd5b9dc2717dfcdc30ae9fa1b13243757e2f51b38ae3fae447a7199a3c954c712c5dace907a81c9493c5cb06b8c110b6942e89890851b342656e0fb5857d98782f6e90a5b0611b43933bc9e486413b03c6b3d610d6565899d9457de900260ef132054ae33b284e6cc70b72247148585f26ac2d11b76a98380495e277fd2c5eb644901fc6cf96d0ae3f10013abaa2143819bcac8f130c93ed5bc64bcda2504ea7f368ac0071f7e9dea016c1241149d448712068c7c70b72385e808810d65628cfeca2b6b81f9384784181d2c693294decc0cb14d64e41d168374fa6b011581ce0770de15e760c510126692713626955ab540fdfc3c9a30fe0fb4d10db06dc171c95423901771ddc82ce4d636a7b79fb85b36c9b8638862bafad31b73286eb0fa15d67c0883dcfa5db2f0f940086248c715afbb9eca2794687157152e77d5735689637e0baa5d4a87df84d92d058596254ddcfe56fa9e33ac262b9c27b3f1be3664688fd88dae27eea73f772c69645769e6a2966856628946b707016f63d54a09a3b8591e933090a831d74d0b0fd98dd81793c805845db791c317d30494ca33c4b65e6011a9539b096a030cad0e429e44736815234569628997bf8c0db5b08c2c25299f77d41087213289debe2ebe25220d6c70b4678ffdfed97773fab17260708bffc3a4f86274b8871b036adc15a216a3491e60caf7eae61f3547e751fe94a1c0baf7bef616a951c342b0c178489319f30b2903488a216712b41bbba0b4f298d529de54f9bbad7f6aa523abf8c499a7546861413631e512424610dd38a4822413b923e6753d76ce290b05e27676a8c8fbab8ae423044f50aad4a99249ea510dfca656f8dd93419acab47a365f8932bf7b2bc3285760a28edb6d30f95bad04ede20360d3b6d8f97cea3536a45a413e77a1ddaf64247c715c7ad16d5b9835cb0f37e5ef4ef52977ae3ad2b7ce9872e8e5bc2f102c27a8320aa313e9601c0241151bd42d868e078611753baccddc1a0d04e9e4c6e2350edea3640b8178c82ca6012d5cdccad85244e932b39da823420cac31a8518191809d6589230a25959c6442d4c12a2b4c6cb14f1b3c328a5895a65e266056b13b4e3e30679e230a6d110bef5bd59724184e053a94e901dd298d812870de26699b0b182895b884d685666c967ebc050bb238189135ab50a61793f7f7649c4a6c934fe4791e5a1032d40b171dca358704120095bb44c0591c35893eaee781982dc305ea684528a246c10369649a27a5aee0638ae8f3131364e47a3d62e4a3b589360e21628851714f073c3388e4fb3b640757e3fcef60a1363230064bd2a95d9dd68278f171468d596c8a910c8b4f5115ab532d5f903b4aa65001c3f4b901bc1cb0ee1b8417bc004b8c1c8fa84ff976b9a32baa984b50e12d3f53962041b0bd6d0f51922f0b1abf6f0bd1b62fcec50374eb941119bd986972d92583de0fbacb1848d3a716b17a3fe1eb4ada21d97e595cdc44367a1b44bb8722fc3de5eb021a2f32c2f6d4779251a0dcbf77fb880c465b49fa7ca387e6c69d56a34cb87682cdecfcea979a6a7131696626eb96799c6581da144c7899ac410d66b8ce69638657b4af6e252c4abdeb28ba5e6047e7608c4303ddee2b71fef530b4789a23a3a3cc0903f8b3531b114595a3a8da18da7a11d8fdae24338cd3b29788b80d04c4acc568b0c656b943265c41a2a7587b945d8b609ce3d196a0dcb7d0fe528eb1d640a638495036cf077335288bab62a64123666f71044153005660e4169acd9edc0885099db83af9b9c775e1e470bbb0ffacc1dde4c69e3196487a671bc0ca051bac0fbbe6ae53dcf4fa75b5dc2dd600454169bf422a202ac01938035423f83f586b052cb104811ed7828ede0eb118aa531d019c40e66b8d60871ab894a56b8f4ad754e3b39edadeffed001ee5b9844bb3e63de7e2ebf542815331c9c0979e787f6530bb752ca593ef6eeb3d838ee1146c26bdf1dd1acd7891a0ddce66dbcff0d4dce3ad5031c20e0e06197abafadf5b99d540fe2844ccef4ab4d2b04ad3378c1286e90672571b9fee71e7e7604ed0839672f1f7807e4b201cbe516af78d75dd4bd619c20c7cae1fb79f7abe679f2bf4843c3e59f9ce7bb372cf1dc671b5ef3e22200d7fffd1cd5bae5f9cf9aecee7d349a09977dfc0e6eb967845266850ffcd721c6467a79c2054f1ae18227a5a37d662ee1b9af3e4852ead95ec4f27bbfa3b8e4e22172b9f4396384af5cb787bffd8105952153dc988622021c6f04483d415773c71902f131f1e08441ba84f74d4b143ced29c36c9a8ed04e0ba52294d21c5e34fce3ddc33899098ce91bded271ab16a2b03b0d0230514812c568a3304e88d0898f4212862436c1edc4f54ee789635ae10a617d8ecbdedce0ac53d3a95e9208fb0eb6182eb9bced4da70faca98b2820c3c1b90c6164097cc5d8a8cf373e773a37fdbcce5d0f1ce4f6fb14bb0f16f00b9bf07301daf1393c5fe4c73f2df36f7e27cb5051f3dbe794f9c77bf6e1664ae4d421ce3ddd6b1313f3d3db144a0588edb9d067fceb71b4562cafc4948a694e91cb6afee3cb3c6ebe643f91d5345b2e71acf03cdd252f8a2c82a2150ae02136eed639b931cb1f5f7a06b57a42a361c8e51c1c47f1dc67f8fcf4f643ec59de82e38de2780e625d1ca7b09670a57318a3519226c89d2cd2da1ee1fd2efafc278e72fe1307fa06b7dc1a72c3cf2b881a41561d36100b36018c0c92d7f95cc076e6a1eda6ac4d43899581a6d378dc5862e7f42ce79d9103d284f15def9fe5a6dbb264fd0a7ffe8e3ce73fa1d07bc83a386e8928dacc67aeb99f37bc3c0b4036ab79ea938b3cf5c9e9d7169612aefefa2ebe7f4b037fe854943bce37fed7019efe14d01a9efd0c8feffe68176e50e499e737c9e75237fb939fc5ac3426707d0768749b8d13e1f22b66f9ce0f2ddba742fee693db715dc5d484c7f438ec9919e105172df2a2df8f78cbeb370370fd3f2cf29e0f54c90d6fc1cb0c931b2ea2ddfddd3a1d47f1f5ef2ef3c1ab1a783ae2caffb691b34ecb11048ad3b7b7b8f7276592a118c820a2416579e7a7eb72f96bf269baf98eff118948808d15261292184cdfcb26d0372801a8d513169622169762169662169712aaf5b472b14eda41fa446cda69ecaa7a8c114c92be06ca24cd1f4c2288194c166d62089b55ce3cc9e279e928bef3de2677ee1e6778fa7c54fe5cbe7e5d3cf88c4de359a674325fbf610797fc59931b6e6cd06c0d02da30eaf29f5e95e339bf3b4b636506ed16d97d688c5fdcd102e0f49d19b66d384879e66e9ef6db1aad53cf72dd8f345e760ae5e491be89e203bb237e70f328c3534f64b632cdfe4361b76c722243909f26377c32aed7eb9cdacd50183b9dd12dff8a914d17901d3a09ed64076cf6e9ff09d9d1276083d3b8e39e9eae13638a386c9144a6cd9d0209503a1d182ea42326890d6956dfb7d9aa52a24ccc008122f0914f1ce49b3fc8121426d318ae5cbccc30d9e16da01cac1ddc14b0168c016554dbbd760a246ddbc4e026dd291ab43b4802abd2018c154c1451c8f51a285784448a04fe184e028b2b1e564077366c8c601270fd8020bf95bb0fe4b8f5ca4554b2c4f6e9324f382be605cf2a32b9314843d6050edff8fb25c46ec1ea4d7ce3fa799e705e3aca9ff36f7d0eeddfcbb9676e07e0b6bb43f6cf8de196c649a218faf4db7fc8e0f81bf1b35324cd455aad956e99a315a8f66e99ea9f3069b453c4f136e0b839945a01e919617129a1190f932d4e610db4c2a5de935a30b12189413b2957496c3071027829e11f7c434efde9d54d711cbb7639b1edd2578f70c72f51d87026850d67b4416994e3a1b547d45a4456ef225ab046a3ad3330923d27a25599076078a24536d3ebc95daf30982f22a210f1a8f69da528e61524355ad525e2d632439331dd6d00019b58c27a99b07a98a8b988e0e37aa3e08fb17ba6cc9df73ec8fe0387b8ec4fb7e3388a5c06f281a1253e5e768a9befd8cb43fbeb6cdbe2f37bcf9c60e6708520486df5fd1b0cb19ac2774a889d1b0865710ce023e221d6c15819d0c31a8d883340a8584bd8acd2aa2de2fa3171d8c2eade737122201e223e222ea6df9bdade4031719ae045cd26fffd75a92becb612356a246142120dbaf38e5b905523532917ed0ee3fa13b8c1465c7f02ed8e02396ca2d3b9f8c00857202ec6665858ea153cfe4ca13a771ba67a3b17fe07bfeba23bcf58a3d6761e71d04e91bbefd7a9f2c0d96766d83935c3d2fe9b88566ee759cf1c5c44b489216a9429b90ff2f9bf98e3594fb99f02bfa0327b27f5e5bd28b3cc19a76670da5bf48da6a2dac800591c778c84cd7ce37ba9ebcc655d2e7eed6928958eb61fffac80174c2264db78fbb182350a93a4bab02aaf11a311f1a8d47a846f99d6d07c8085bd3f66e9c03fd15839848907439458854d54db65f725a7a403d4c469684e2243d4ece5145dab84f565dccc349e17f4ce4eb52b3609a8554617ab11a3b18933e08645da40cc2008442312801ee5f6bb67f9dd0bd2b2173d6f034f3ebf45a9e876173d7adb91e94953cb809d403c1c6f84db1f88b9ebde151e77b64fe06b3e7ad924f73ed060c368894dd39941c2adc2c60613b7d8b625e0d28b87b8f462a8d50cd59a6164781b994ccfe8fffb264b2b1ec757795019dccc26befbc30779d58b0dc5a2d3ed183ffc7144b5b999627114315e5bef7edd535bd884b5798d805817ed061c9c0968b5844c4671f619397ef4cd2d542a09dff9c1437cec330e66381c78b6d789069363042401132b944e77f6a27a2f8c7435fcc8254ac5cd1a496407477892ba6218ec084a7988789844adf508c601fc6ef50a052a40a902ae3fcdd7ae1fe3b6bb7a3d76f3748638163ef2577b58a9743e4f9f11eba35406d5838ad2591c6f0341fe34defbc12c0fec4e00c864348f3ba74026e3f0d18fef218e6db72ea5b22855a4158d72d7bd71d7488582c3d4a4df253b4e84af7e3be26fff6e123fbb0d911c625cb433422d9ce05bd7d50708fbd6f50ac79b060a58e322e2035e0f2b0e48801817a532a46b059dc2005416c71de7ce5dd37ce5db09619402f35cc5d8a8473e9b761445ff3270ca8758172400e5f595b9083e2681244a8f9585b5e55e93fddba3977c785832c51d2827689394c680245c26aadec5d6f107f0741d94cbecf2040d1e4f90df82d67eff8e01495426acdcc3960df7e3bb55048f03f39b31de39385e91a87188b072374f3a77816d9b2d8bcbf0e35b842882534e02d711129b63dfdc0ec49b42e2c36cdfb81b57b740f9ec3eb40d277736dacd10d60e20e1fd3cf19c45b64c19e6162d37fed412468ad34fd1a42be905761f3a0937b71513576955f790f36639fde490cd5342b1a0301666e714b7df9763b9be996c69277e6e12edf898a441d498a5be7c079b477ec157bfb815805bef68f1a6f78c110c3f85203f8dd88456ed214ade1d8c0fcd212294eba3ccd7cec4cb4e10d5f7b175fc5e02b78a522e07e6a7899d73703363c4ad459ae55d649c036c1c6b90cf5a509a956a89430b1b08bc063bb72e203622b17976cf9c4a503889245c6638b88bb1a10510a1dc1865be7636d9e2c928c725acede3c36f5e50eb127ef19fc7921d3a0bd71f193858606d8889ca24d10ad64628348e97c70dc670dc1c7d8ea2cd794c129749c265ac0d51cac1f14a78c1084afb581b92842b9868196b429476d14e065088c488085afb38fe108e93c5240d4c5cc6da18a55c5cbf9462d41ed684986825c5669aa09cb42ea5c126edf56c1fd71fc6f18a88586c52c7c4354c52c79a30f5814aa39d00c72be27843385e01ad5c4c52a7597d90e6cadde4bc3dbcf1d59a0b9fb701803f797f837ff8a7df223f7a2eae57020413d789a3656c5c0304ede670fd51b41360927a1b67ab7d46a0d82ecb209260e31a495cc59a162249ea1f9c0cdacd2136c62475444c5b9f111caf80b51149b48c8d1bedf6b2699d5e1e9bd46994efe5137f2ceb130ef0c6cb27c4cf6d46eba02f14497b17ab2f9a7677b9d63becd1f7fdceaed1c0f73be59dc3072a75d98a813604d5bd71d10b542add0357fa08753150d6794629dddbe5eac327fd3aa1fb0e3e681043d49a87d6cd7cfcb2839c795a2f11bcfdae888bde368c5fba003fbf09adbc74d74c2c22d29bd976f46eeffeb1ba3ddd674369efbc49ffb424c59e6e5cd94ea5e91982ce3e7867e5aa631fe5802444cdc35cf1f6430f7f0022accfa174e750a0ee5582c340fc795839daf757970b562c6223ac6922128124a9224aa170514e80d6d934dcd80ea1ebb775f43d3dc56aaf34f0ace9fd91ae0ea6c9519208e58ae1c65b123ef4c93c78a70379e26635f54c366ad7e0b637943cb49345e9a0ddd9d7b1c94022d7d95b3f5ef106fe4a0f55b408ebf36bbeb9ee11a78bde3b2e7e760b4afb9ce859e9a349efa896c1da26362993448b24e1029ffb8bec9a465ff1aeaab8de28ae3f81e38fa075b6bb58f1e8204c519aa44a58df4358db8549aa28ede378237899711c278fb54d4cbcb23ee677d6c40dc670bd311c6f18ede441ad7378f111450c6223e2d6213ef59ec3c776a6ede56f0f25533813c71b4b5d1cb41338569dcf59759243f515f59f77eb3bffd67b2f88c4987899383ccce72e3bf6a3bfaff8cf8e78c1261c6f14add3d8df7f45e0486dd387b3fbbd3e053a7b085ddd14883558dbc026f534ae8a416c8b245ee2f3971f3b77af7ca71637b309d71f43e980347cb471b07edbeb613c9acd05838d57086bf7f1f9bf5c7b71e288c794ffe81d39f13327a1dd7c1a7fe98563691ba7237dd1a3d731fa1be9fed347b66d9284b384adbd5cfde1e3bf73f69237af48903b19cf9f423939c01934525fdbab5d7c3f4eb5aa40d61854ba8614d3c4c4f3448d3d7ce9230f7fbaf648f2ca778d8aeb4fa576edc3dcc13dc06d3fc147b379bb026b9bc4cd87f8fce5eb5f3b7ad89b272f7fdbb878c1344a67dbb174b0a17e43f6ad62ae6da44f2130585327090ff2c50f1efd2ed4d1e4656fcd8a176c45bb25c01d1835ab71f6635c356806bebba64c6c8a393ac8173fb0f6e8eff163ce89176c413925941ac4bc1eae8e1cc9e690c66d9198249ae10b7f79f088188f7ab7ec656f9914c79b6a271e6beb7938d207ff9674ea91ac904407f89b8fb51eb150f69237f9e206db71dca18118b99ee1068cc49189efe2168bb53592e800577fe4c857788e575efc46c40bb6e3b8a3a0fcee805a0ff7ea46d7e06c936d9305a2c6fd5cf38923df763d2ae12f78cd8af899d3d0de647baeacd718add3f86a0376cbc52212629345a2700f5ffed4237f13f3c28b1df1fc1d6877241d35abf0f5635cfd7eb5f446b6c19a1a49bc9f6bfeaafa88637ee16b1be26576e0781328956d4f1bd5bad83bb8faa53b906c844de6895bbbb9f62aef61711ef3fdf00b5f372cae3785d29d4cb3afde553da003046c3a5d31554c32c7b59faa3c9a092a2f788d1237d8817646dba4abf5738a6eccebbdef026be3173188ad9244fbf8f2558fce15e78ebcf0a28c38de245a0f7513ba7ee28f6cdf348134c91c49b89baf7ef6e83f5e705cbf00f1bc57228e3b85764648d7c6dd145cb74bb6171e302011d6d611b38c4966f9fa17d64e5b1e0df983578ab8de0eb43386521eeb05f5fe9c42b587b3f47d98925d2689f7f1b5cf3e72a1e768f2fc57e745eb11945340a9205d8757edb979ef272a10312021d656b0c90c5ffd6c7ccc188ffb273f009ef38789286718ad5360698fb48844883411db426c9d6f7ee997bf0e7c22f2ec9786e2fa3bd0ce787bc342b32640ae7e0f6db223ac59c224fbf8e65ffff257834f449ef387a1285d48377c74b6cfc6a436b635ac2df3cdbf3efefbea2744f8ff2ff2ec978e887626513a9f7a23516b032190269426edac661e93ece1dbd79cd8b4ebff75794c130ef0fb2f44943385d223e9366b270c011da2a185d832d6ccf19d6b1fbb3fd905bf018477e4dfff8111a537802af4ae3661db216889ebbe661ed34477e43786f07f9654fe2fc2ee9042ad017b950000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="3" margin="8"/>
+</UI>
diff --git a/muse2/synti/fluidsynth/fluidsynti.cpp b/muse2/synti/fluidsynth/fluidsynti.cpp
new file mode 100644
index 00000000..d3cd5699
--- /dev/null
+++ b/muse2/synti/fluidsynth/fluidsynti.cpp
@@ -0,0 +1,1314 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynti.cpp,v 1.19.2.18 2009/12/06 10:05:00 terminator356 Exp $
+ *
+ */
+
+#include "fluidsynti.h"
+#include "muse/midi.h"
+
+#include <list>
+#include <iostream>
+#include <qfileinfo.h>
+
+
+FluidCtrl FluidSynth::fluidCtrl[] = {
+ //{ "Expression", CTRL_EXPRESSION, 0, 127 },
+ //{ "Sustain", CTRL_SUSTAIN, 0, 127 },
+ //{ "Portamento", CTRL_PORTAMENTO, 0, 127 },
+ //{ "Soft Pedal", CTRL_SOFT_PEDAL, 0, 127 },
+ //{ "Variation", CTRL_VARIATION_SEND, 0, 127 },
+ //{ "Channel reverb send", CTRL_REVERB_SEND, 0, 127 },
+ //{ "Channel chorus send", CTRL_CHORUS_SEND, 0, 127 },
+ //{ "Pitch", CTRL_PITCH, -8192, 8191 }
+
+ // These controllers' initial values are set by the FS_PREDEF_ values, so just set them to zero here.
+ { "Gain", FS_GAIN ,0, 127, 0},
+ { "Master reverb on/off", FS_REVERB_ON , 0, 1, 0},
+ { "Master reverb level", FS_REVERB_LEVEL, 0, 16384, 0},
+ { "Master reverb size", FS_REVERB_ROOMSIZE, 0, 16384, 0}, // Interval: [0,1]
+ { "Master reverb damping", FS_REVERB_DAMPING, 0, 16384, 0}, // Interval: [0,1]
+ { "Master reverb width", FS_REVERB_WIDTH, 0, 16384, 0}, // Interval: [0,100]
+ { "Master chorus on/off", FS_CHORUS_ON, 0, 1, 0},
+ { "Master chorus num delay lines", FS_CHORUS_NUM, 0, 10, 0}, //Default: 3
+ { "Master chorus type", FS_CHORUS_TYPE, 0, 1, 0},
+ { "Master chorus speed", FS_CHORUS_SPEED, 0, 16384, 0}, // (0.291,5) Hz
+ { "Master chorus depth", FS_CHORUS_DEPTH, 0, 16384, 0}, // [0,40]
+ { "Master chorus level", FS_CHORUS_LEVEL, 0, 16384, 0}, // [0,1]
+
+ { "Program", CTRL_PROGRAM, 0, 0xffffff, 0},
+ { "Modulation", CTRL_MODULATION, 0, 127, 0},
+ { "Portamento time", CTRL_PORTAMENTO_TIME, 0, 127, 0},
+ { "Volume", CTRL_VOLUME, 0, 127, 100},
+ { "Pan", CTRL_PANPOT, -64, 63, 0},
+ { "Expression", CTRL_EXPRESSION, 0, 127, 127},
+ { "Sustain", CTRL_SUSTAIN, 0, 127, 0},
+ { "Portamento", CTRL_PORTAMENTO, 0, 127, 0},
+ { "Soft Pedal", CTRL_SOFT_PEDAL, 0, 127, 0},
+ { "Variation", CTRL_VARIATION_SEND, 0, 127, 0},
+ { "Channel reverb send", CTRL_REVERB_SEND, 0, 127, 40},
+ { "Channel chorus send", CTRL_CHORUS_SEND, 0, 127, 0},
+ { "Pitch", CTRL_PITCH, -8192, 8191, 0},
+ // Added by T356
+ { "Pitch bend sensitivity", FS_PITCHWHEELSENS, 0, 24, 2}
+ };
+
+static int NUM_CONTROLLER = sizeof(FluidSynth::fluidCtrl)/sizeof(*(FluidSynth::fluidCtrl));
+
+QString *projPathPtr;
+//
+// Fluidsynth
+//
+FluidSynth::FluidSynth(int sr, pthread_mutex_t *_Globalsfloader_mutex) : Mess(2)
+ {
+ setSampleRate(sr);
+ fluid_settings_t* s = new_fluid_settings();
+ fluid_settings_setnum(s, (char*) "synth.sample-rate", float(sampleRate()));
+ fluidsynth = new_fluid_synth(s);
+ if (!fluidsynth) {
+ printf("Error while creating fluidsynth!\n");
+ return;
+ }
+
+ //Set up channels:
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ //channels[i].font = 0;
+ channels[i].font_extid = FS_UNSPECIFIED_ID;
+ channels[i].font_intid = FS_UNSPECIFIED_ID;
+ channels[i].preset = FS_UNSPECIFIED_PRESET;
+ channels[i].drumchannel= false;
+ }
+ //pthread_mutex_init(&_sfloader_mutex,NULL);
+ _sfloader_mutex = _Globalsfloader_mutex;
+
+/*
+ buffer = 0;
+ bufferlen = 0;
+ */
+ }
+
+FluidSynth::~FluidSynth()
+ {
+ int err = delete_fluid_synth (fluidsynth);
+ delete gui;
+
+/* if (buffer)
+ delete [] buffer;*/
+ if (err == -1) {
+ std::cerr << DEBUG_ARGS << "error while destroying synth: " << fluid_synth_error(fluidsynth) << std::endl;
+ return;
+ }
+ //Destroy the mutex
+/* if (pthread_mutex_destroy(&_sfloader_mutex) != 0)
+ std::cerr << DEBUG_ARGS << "Strange, mutex busy! Should not be!" << std::endl;*/
+
+ }
+
+bool FluidSynth::init(const char* name)
+ {
+ debug("FluidSynth::init\n");
+
+ gui = new FluidSynthGui();
+ gui->show();
+ gui->setCaption(name);
+
+ lastdir= "";
+ currentlyLoadedFonts = 0;
+ nrOfSoundfonts = 0;
+ sendChannelData();
+ cho_on = false;
+ cho_num = FS_PREDEF_CHORUS_NUM;
+ cho_type = FS_PREDEF_CHORUS_TYPE;
+ cho_level = FS_PREDEF_CHORUS_LEVEL;
+ cho_speed = FS_PREDEF_CHORUS_SPEED;
+ cho_depth = FS_PREDEF_CHORUS_DEPTH;
+ setController(0, FS_GAIN, (int)(fluidCtrl[0].max*FS_PREDEF_VOLUME));
+ setController(0, FS_REVERB_ON, 0);
+ setController(0, FS_REVERB_LEVEL, (int)(fluidCtrl[2].max*FS_PREDEF_REVERB_LEVEL));
+ setController(0, FS_REVERB_ROOMSIZE, (int)(fluidCtrl[3].max*FS_PREDEF_REVERB_ROOMSIZE));
+ setController(0, FS_REVERB_DAMPING, (int)(fluidCtrl[4].max*FS_PREDEF_REVERB_DAMPING));
+ setController(0, FS_REVERB_WIDTH, (int)(fluidCtrl[5].max*FS_PREDEF_REVERB_WIDTH));
+ setController(0, FS_CHORUS_ON, 0);
+ setController(0, FS_CHORUS_NUM, FS_PREDEF_CHORUS_NUM);
+ //setController(0, FS_CHORUS_TYPE, FS_PREDEF_CHORUS_TYPE); //?
+ setController(0, FS_CHORUS_SPEED, (int)(fluidCtrl[9].max*FS_PREDEF_CHORUS_SPEED));
+ setController(0, FS_CHORUS_DEPTH, (int)(fluidCtrl[10].max*FS_PREDEF_CHORUS_DEPTH));
+ setController(0, FS_CHORUS_LEVEL, (int)(fluidCtrl[11].max*FS_PREDEF_CHORUS_LEVEL));
+ return false;
+ }
+
+//---------------------------------------------------------
+// processMessages
+// Called from host always, even if output path is unconnected.
+//---------------------------------------------------------
+
+void FluidSynth::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 (FS_DEBUG)
+ printf("FluidSynth::process(): unknown event, type: %d\n", ev.type());
+ }
+ }
+
+}
+
+//---------------------------------------------------------
+// process
+// Called from host, ONLY if output path is connected.
+//---------------------------------------------------------
+
+void FluidSynth::process(float** ports, 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 (FS_DEBUG)
+ printf("FluidSynth::process(): unknown event, type: %d\n", ev.type());
+ }
+ }
+ */
+
+ if (fluid_synth_write_float(fluidsynth, len, ports[0], offset, 1, ports[1], offset, 1)) {
+ M_ERROR("Error writing from synth!");
+ return;
+ }
+ }
+
+//---------------------------------------------------------
+// getInitData
+// Prepare data that will restore the synth's state on load
+//---------------------------------------------------------
+void FluidSynth::getInitData(int* n, const unsigned char** data) const
+ {
+
+ //printf("projPathPtr ");
+ //std::cout << *projPathPtr << std::endl;
+
+ // Data setup:
+ // FS_INIT_DATA (1 byte)
+ // FluidSynth version (2 bytes, x.y)
+ // n = Number of soundfonts (1 byte)
+ // Lastdir (variable size)
+ //
+ // FS_FONTS_BEGIN
+ // n blocks with font path (variable size)
+ // n bytes with font external id
+ //
+ // for all channels (16), 1 byte each for external id + 1 byte for preset + 1 byte for bankno
+ // which is mapped to internal id after all fonts are loaded.
+ //
+ // reverb + chorus on/off (2 bytes)
+ if (FS_DEBUG)
+ printf("FluidSynth::getInitData()\n");
+
+ //Calculate length:
+ int len = FS_INIT_DATA_HEADER_SIZE + strlen(lastdir.c_str()) + 1; //header size
+ for (std::list<FluidSoundFont>::const_iterator it = stack.begin(); it!=stack.end(); it++) {
+
+ // if the soundfont is located under the projectPath we extract this from the filename
+ int fileLen = strlen(it->filename.c_str());
+ if (QString(it->filename.c_str()).startsWith(*projPathPtr)) {
+ printf("project path found in filename, len %d shortened with %d\n",fileLen, projPathPtr->length()+1);
+ fileLen = fileLen - projPathPtr->length()-1;
+ }
+ len+=fileLen + 2;
+ }
+ //Add length for lastdir and channels:
+ len+=strlen(lastdir.c_str())+1;
+ len+=(FS_MAX_NR_OF_CHANNELS*4); // 4 bytes: ext+int id + bankno + drumchannel status
+ // + reverb
+ len+=2;
+
+ if (FS_DEBUG)
+ printf("Total length of init sysex: %d\n", len);
+ byte* d = new byte[len];
+
+ // Header:
+ d[0] = FS_INIT_DATA;
+ d[1] = FS_VERSION_MAJOR;
+ d[2] = FS_VERSION_MINOR;
+ d[3] = stack.size();
+
+ //Lastdir:
+ byte* chptr = d + FS_INIT_DATA_HEADER_SIZE;
+ memcpy(chptr, lastdir.c_str(), strlen(lastdir.c_str())+1);
+
+ //For each font...
+ chptr+=strlen(lastdir.c_str())+1;
+ for (std::list<FluidSoundFont>::const_iterator it =stack.begin(); it!=stack.end(); it++) {
+
+ // if the soundfont is located under the projectPath we extract this from the filename
+ int offset=0;
+ if (QString(it->filename.c_str()).startsWith(*projPathPtr)) {
+ offset= projPathPtr->length()+1;
+ }
+
+ memcpy(chptr, it->filename.c_str()+offset, strlen(it->filename.c_str())-offset+1);
+ //printf("path name stored=%s\n", it->filename.c_str()+offset);
+ chptr = chptr + 1 + strlen(it->filename.c_str())-offset;
+ }
+
+ //For each font again...
+ *chptr = FS_INIT_CHANNEL_SECTION;
+ chptr++;
+ for (std::list<FluidSoundFont>::const_iterator it =stack.begin(); it!=stack.end(); it++) {
+ *chptr = it->extid;
+ chptr++;
+ }
+
+ //External id:s & preset for all channels:
+ for(int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ *chptr = channels[i].font_extid; chptr++;
+ *chptr = channels[i].preset; chptr++;
+ *chptr = channels[i].banknum; chptr++;
+ *chptr = channels[i].drumchannel; chptr++;
+ }
+
+ //Reverb:
+ *chptr = rev_on; chptr++;
+ *chptr = cho_on; chptr++;
+ if (FS_DEBUG) {
+ for (int i=0; i<len; i++)
+ printf("%c ", d[i]);
+ printf("\n");
+ for (int i=0; i<len; i++)
+ printf("%x ", d[i]);
+ printf("\n");
+ }
+ // Give values to host:
+ *data = d;
+ *n = len;
+ }
+
+//-----------------------------------
+// parseInitData
+//-----------------------------------
+void FluidSynth::parseInitData(int n, const byte* d)
+ {
+ printf("projPathPtr ");
+ std::cout << *projPathPtr->toAscii().data() << std::endl;
+
+ bool load_drumchannels = true; // Introduced in initdata ver 0.3
+ bool handle_bankvalue = true; // Introduced in initdata ver 0.4
+
+ if (FS_DEBUG) {
+ printf("--- PARSING INIT DATA ---\n");
+ for (int i=0; i<n; i++)
+ printf("%c ", d[i]);
+ printf("\n");
+ }
+
+ byte version_major, version_minor;
+ version_major = d[1]; version_minor = d[2];
+
+ // Check which version of the initdata we're using and if it's OK
+ if (!(version_major == FS_VERSION_MAJOR && version_minor == FS_VERSION_MINOR)) {
+ if (FS_DEBUG) {
+ printf("Project saved with other version of fluidsynth format. Ver: %d.%d\n", version_major, version_minor);
+ }
+
+ if (version_major == 0 && version_minor == 1) {
+ sendError("Initialization data created with different version of FluidSynth Mess, will be ignored.");
+ return;
+ }
+
+ if (version_major == 0 && version_minor <= 2) {
+ load_drumchannels = false;
+ }
+
+ if (version_major == 0 && version_minor <= 3) {
+ handle_bankvalue = false;
+ }
+ }
+
+ byte nr_of_fonts = d[3];
+ nrOfSoundfonts = nr_of_fonts; //"Global" counter
+ const byte* chptr = (d + 4);
+
+ //Get lastdir:
+ lastdir = std::string((char*)chptr);
+ sendLastdir(lastdir.c_str());
+
+ chptr+=strlen(lastdir.c_str())+1;
+
+ FluidSoundFont fonts[nrOfSoundfonts]; //Just a temp one
+ //Fonts:
+ for (int i=0; i<nr_of_fonts; i++) {
+ fonts[i].filename = (char*)(chptr);
+ chptr+=(strlen(fonts[i].filename.c_str())+1);
+
+ if (QFileInfo(fonts[i].filename.c_str()).isRelative()) {
+ printf("path is relative, we append full path!\n");
+ fonts[i].filename = projPathPtr->ascii() + std::string("/")+ fonts[i].filename;
+ }
+ std::cout << "SOUNDFONT FILENAME + PATH " << fonts[i].filename << std::endl;
+ }
+
+ if (*chptr != FS_INIT_CHANNEL_SECTION) {
+ sendError("Init-data corrupt... Projectfile error. Initdata ignored.\n");
+ return;
+ }
+
+ chptr++;
+ for (int i=0; i<nr_of_fonts; i++) {
+ fonts[i].extid = *chptr;
+ chptr++;
+ //printf("Extid, %d: %d\n",i,fonts[i].extid);
+ }
+
+ // All channels external id + preset
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ channels[i].font_extid = *chptr; chptr++;
+ channels[i].preset = *chptr; chptr++;
+ if (handle_bankvalue) { // Ver 0.4 and later
+ channels[i].banknum = *chptr; chptr++;
+ }
+ else {
+ channels[i].banknum = 0;
+ }
+
+ if (load_drumchannels) { // Ver 0.3 and later
+ channels[i].drumchannel = *chptr;
+ chptr++;
+ }
+ }
+
+ //Reverb:
+ setController(0, FS_REVERB_ON, *chptr); chptr++;
+ setController(0, FS_CHORUS_ON, *chptr); chptr++;
+
+ if (FS_DEBUG)
+ printf("--- END PARSE INIT DATA ---\n");
+ //Load the shit:
+ for (int i=0; i<nrOfSoundfonts; i++) {
+ pushSoundfont(fonts[i].filename.c_str(), fonts[i].extid);
+ }
+ }
+
+
+//---------------------------------------------------------
+// processEvent
+// All events from the sequencer goes here
+//---------------------------------------------------------
+
+bool FluidSynth::processEvent(const MidiPlayEvent& ev)
+ {
+ switch(ev.type()) {
+ case ME_CONTROLLER:
+ if (FS_DEBUG_DATA) {
+ printf("*** FluidSynth::process - 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 (FS_DEBUG_DATA) {
+ printf("*** FluidSynth::process - Sysex received\n");
+ for (int i=0; i< ev.len(); i++)
+ printf("%x ", ev.data()[i]);
+ printf("\n");
+ }
+ return sysex(ev.len(), ev.data());
+ case ME_PITCHBEND:
+ setController(ev.channel(), CTRL_PITCH, ev.dataA(), false);
+ break;
+
+ case ME_PROGRAM:
+ setController(ev.channel(), CTRL_PROGRAM, ev.dataA(), false);
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// sysex
+//---------------------------------------------------------
+
+bool FluidSynth::sysex(int n, const unsigned char* d)
+ {
+ switch(*d) {
+ case FS_LASTDIR_CHANGE: {
+ lastdir = std::string((char*)(d+1));
+ sendLastdir(lastdir.c_str());
+ break;
+ }
+ case FS_PUSH_FONT: {
+ int extid = d[1];
+
+ if (FS_DEBUG)
+ printf("Client: Got push font %s, id: %d\n",(d+1), extid);
+
+ const char* filename = (const char*)(d+2);
+ if (!pushSoundfont(filename, extid))
+ sendError("Could not load soundfont ");
+ break;
+ }
+ case FS_DUMP_INFO: {
+ dumpInfo();
+ break;
+ }
+ case FS_SOUNDFONT_CHANNEL_SET: {
+ sfChannelChange(*(d+1), *(d+2));
+ break;
+ }
+ case FS_INIT_DATA: {
+ parseInitData(n,d);
+ break;
+ }
+ case FS_SOUNDFONT_POP:
+ popSoundfont(*(d+1));
+ break;
+ case FS_DRUMCHANNEL_SET: {
+ byte onoff = (*(d+1));
+ byte channel = (*(d+2));
+ channels[channel].drumchannel = onoff;
+ if (FS_DEBUG)
+ printf("Client: Set drumchannel on chan %d to %d\n",channel, onoff);
+ break;
+ }
+ default:
+ if (FS_DEBUG)
+ printf("FluidSynth::sysex() : unknown sysex received: %d\n",*d);
+ break;
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// sendSysex
+//---------------------------------------------------------
+void FluidSynth::sendSysex(int l, const unsigned char* d)
+ {
+ MidiPlayEvent ev(0, 0, ME_SYSEX, d, l);
+ gui->writeEvent(ev);
+ }
+
+//-----------------------------------
+// pushSoundfont - load a soundfont
+//-----------------------------------
+bool FluidSynth::pushSoundfont (const char* filename, int extid)
+ {
+ pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
+ pthread_attr_init(attributes);
+ pthread_attr_setdetachstate(attributes, PTHREAD_CREATE_DETACHED);
+
+ FS_Helper* helper = new FS_Helper;
+ helper->fptr = this;
+ helper->filename = filename;
+ helper->id = extid;
+
+ if (pthread_create(&fontThread, attributes, ::fontLoadThread, (void*) helper))
+ perror("creating thread failed:");
+
+ pthread_attr_destroy(attributes);
+ return true;
+ }
+
+//---------------------------------------------------------
+// fontLoadThread
+// helper thread to load soundfont in the
+// background
+//---------------------------------------------------------
+
+static void* fontLoadThread(void* t)
+ {
+ //Init vars
+ FS_Helper* h = (FS_Helper*) t;
+ FluidSynth* fptr = h->fptr;
+ const char* filename = h->filename.c_str();
+ pthread_mutex_t* sfloader_mutex = (fptr->_sfloader_mutex);
+
+ //Let only one loadThread have access to the fluidsynth-object at the time
+ pthread_mutex_lock(sfloader_mutex);
+ int rv = fluid_synth_sfload(fptr->fluidsynth, filename, 1);
+
+ if (rv ==-1) {
+ fptr->sendError(fluid_synth_error(fptr->fluidsynth));
+ if (FS_DEBUG)
+ std::cerr << DEBUG_ARGS << "error loading soundfont: " << fluid_synth_error(fptr->fluidsynth) << std::endl;
+
+ //Unlock the mutex, or else we might be stuck here forever...
+ pthread_mutex_unlock(sfloader_mutex);
+ delete h;
+ pthread_exit(0);
+ }
+
+ //Deal with internal and external id etc.
+ if (FS_DEBUG)
+ printf("Soundfont %s loaded, index %d\n", filename, rv);
+
+ FluidSoundFont font;
+ font.filename = h->filename;//strdup(filename);
+
+ font.intid = rv;
+ if (h->id == FS_UNSPECIFIED_ID) {
+ font.extid = fptr->getNextAvailableExternalId();
+ if (FS_DEBUG)
+ printf("Font got extid %d\n",font.extid);
+ }
+ else
+ font.extid = h->id;
+ if (FS_DEBUG)
+ printf("Font has external id: %d int id:%d\n", font.extid, font.intid);
+
+ //Strip off the filename
+ QString temp = QString(filename);
+ QString name = temp.right(temp.length() - temp.findRev('/',-1) - 1);
+ name = name.left(name.length()-4); //Strip off ".sf2"
+ font.name = name.latin1();
+ fptr->stack.push_front(font);
+ fptr->currentlyLoadedFonts++;
+
+ //Cleanup & unlock:
+ pthread_mutex_unlock(sfloader_mutex);
+ delete h;
+
+ if (FS_DEBUG)
+ printf("Currently loaded fonts: %d Nr of soundfonts: %d\n",fptr->currentlyLoadedFonts, fptr->nrOfSoundfonts);
+ //Check whether this was the last font or not. If so, run initSynth();
+ if (fptr->nrOfSoundfonts <= fptr->currentlyLoadedFonts) {
+ if (FS_DEBUG)
+ printf("This was the last font, rewriting channel settings...\n");
+ fptr->rewriteChannelSettings();
+ //Update data in GUI-window.
+ fptr->sendSoundFontData();;
+ fptr->sendChannelData();
+ }
+
+ pthread_exit(0);
+ }
+
+//---------------------------------------------------------
+// playNote
+// called from host
+//---------------------------------------------------------
+
+bool FluidSynth::playNote(int channel, int pitch, int velo)
+ {
+ if (channels[channel].font_intid == FS_UNSPECIFIED_FONT ||
+ channels[channel].font_intid == FS_UNSPECIFIED_ID)
+ return false;
+
+ if (velo) {
+ if (fluid_synth_noteon(fluidsynth, channel, pitch, velo)) {
+ if (FS_DEBUG)
+ std::cerr << DEBUG_ARGS << "error processing noteon event: " << fluid_synth_error(fluidsynth);
+ }
+ }
+ else {
+ if (fluid_synth_noteoff(fluidsynth, channel, pitch))
+ if (FS_DEBUG)
+ std::cerr << DEBUG_ARGS << "error processing noteoff event: " << fluid_synth_error(fluidsynth) << std::endl;
+ }
+ return false;
+ }
+//---------------------------------------------------------
+// sendSoundFontData
+//---------------------------------------------------------
+void FluidSynth::sendSoundFontData()
+ {
+ int ndatalen = 2; //2 bytes for command and length
+
+ //Calculate length in chars of all strings in the soundfontstack in one string
+ for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++) {
+ ndatalen += 1 + strlen(it->name.c_str());
+ ndatalen += FS_SFDATALEN; //unsigned char for ID
+ }
+ byte ndata[ndatalen];
+ *ndata = FS_SEND_SOUNDFONTDATA; //The command
+ *(ndata + 1) = (unsigned char)stack.size (); //Nr of Soundfonts
+
+ // Copy the stuff to ndatalen:
+ char* chunk_start = (char*)(ndata + 2);
+ int chunk_len, name_len;
+ for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); ++it) {
+ name_len = strlen(it->name.c_str()) + 1;
+ chunk_len = name_len + FS_SFDATALEN;
+ memcpy(chunk_start, it->name.c_str(), name_len); //First, store the fontname
+ *(chunk_start + name_len) = it->extid; //The GUI only needs to know about the external id, store that here
+ chunk_start += chunk_len;
+ }
+ sendSysex(ndatalen, ndata);
+ }
+
+//---------------------------------------------------------
+// sendChannelData
+//---------------------------------------------------------
+void FluidSynth::sendChannelData()
+ {
+ int chunk_size = 2;
+ int chdata_length = (chunk_size * FS_MAX_NR_OF_CHANNELS) +1 ; //Command and the 2 channels * 16
+ byte chdata[chdata_length];
+ byte* chdptr;
+ chdata[0] = FS_SEND_CHANNELINFO;
+ chdptr = (chdata + 1);
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ *(chdptr) = channels[i].font_extid; //Font external id
+ *(chdptr+1) = i; //Channel nr
+ chdptr += chunk_size;
+ }
+ sendSysex(chdata_length, chdata);
+ // Send drum channel info afterwards (later addition, not very neat, but works...)
+
+ int drumchdata_length = FS_MAX_NR_OF_CHANNELS + 1; //1 byte for the command, one byte for each channel
+ byte drumchdata[drumchdata_length ];
+ byte* drumchdataptr = drumchdata;
+ *drumchdata = FS_SEND_DRUMCHANNELINFO;
+
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ drumchdataptr++;
+ *drumchdataptr = channels[i].drumchannel;
+ }
+ sendSysex(drumchdata_length, drumchdata);
+ }
+
+//---------------------------------------------------------
+// dumpInfo
+//---------------------------------------------------------
+
+void FluidSynth::dumpInfo()
+ {
+ printf("-----------------------------------------------------\n");
+ printf("Dumping info...\n");
+ printf("Last dir: %s\n", lastdir.c_str());
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++)
+ printf("Chan %d\tFont extid:%d\tintid:%d\tdrumchan:%d\tpreset: %d\n", i, channels[i].font_extid, channels[i].font_intid, channels[i].drumchannel, channels[i].preset);
+
+ printf("\n");
+ for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++)
+ printf("Font: %s\tintid: %d\textid %d\tfilename:%s\n", it->name.c_str(), it->intid, it->extid, it->filename.c_str());
+ printf("Reverb on: %d, width: %f, size: %f level: %f damp: %f\n",rev_on, rev_width, rev_size, rev_level, rev_damping);
+ printf("-----------------------------------------------------\n");
+ }
+
+//---------------------------------------------------------
+// guiVisible
+//---------------------------------------------------------
+
+bool FluidSynth::guiVisible() const
+ {
+ return gui->isVisible();
+ }
+
+
+//---------------------------------------------------------
+// showGui
+//---------------------------------------------------------
+
+void FluidSynth::showGui(bool val)
+ {
+ gui->setShown(val);
+ }
+
+//---------------------------------------------------------
+// setController
+//---------------------------------------------------------
+
+bool FluidSynth::setController(int channel, int id, int val)
+ {
+ setController(channel, id, val, false);
+ return false;
+ }
+
+//---------------------------------------------------------
+// setController
+//---------------------------------------------------------
+
+void FluidSynth::setController(int channel, int id, int val, bool fromGui)
+ {
+ //
+ // Channelless controllers
+ //
+ int err = 0;
+ switch (id) {
+ case FS_GAIN: {
+ fluid_synth_set_gain(fluidsynth, (float) val/25); //gives val an interval of approximately[0,5]
+ //Forward to gui if not from Gui
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_GAIN, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_REVERB_ON: {
+ rev_on = val;
+ fluid_synth_set_reverb_on(fluidsynth, val); // 0 or 1
+ //if (rev_on)
+ // fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_ON, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_REVERB_LEVEL:
+ //Interval: 0-2
+ rev_level = (double)2*val/16384; //[0,2]
+ //if (rev_on)
+ fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_LEVEL, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ case FS_REVERB_WIDTH: //
+ rev_width = (double)val/164; //[0,100]
+ //if (rev_on)
+ fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_WIDTH, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ case FS_REVERB_DAMPING: //[0,1]
+ rev_damping = (double)val/16384;
+ //if (rev_on)
+ fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_DAMPING, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ case FS_REVERB_ROOMSIZE: //[0,1]
+ rev_size = (double)val/16384;
+ //if (rev_on)
+ fluid_synth_set_reverb(fluidsynth, rev_size, rev_damping, rev_width, rev_level);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_REVERB_ROOMSIZE, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ case FS_CHORUS_ON: {// 0 or 1
+ cho_on = val;
+ fluid_synth_set_chorus_on(fluidsynth, val);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_ON, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_CHORUS_NUM: {//Number of delay lines
+ cho_num = val;
+ fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_NUM, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_CHORUS_TYPE: {//?
+ cho_type = val;
+ fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_TYPE, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_CHORUS_SPEED: {//(0.291,5) Hz
+ cho_speed = (double)(0.291 + (double)val/3479);
+ fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_SPEED, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_CHORUS_DEPTH: { //[0,40]
+ cho_depth = (double) val*40/16383;
+ fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_DEPTH, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ case FS_CHORUS_LEVEL: { //[0,1]
+ cho_level = (double) val/16383;
+ fluid_synth_set_chorus(fluidsynth, cho_num, cho_level, cho_speed, cho_depth, cho_type);
+ if (!fromGui) {
+ MidiPlayEvent ev(0, 0, 0, ME_CONTROLLER, FS_CHORUS_LEVEL, val);
+ gui->writeEvent(ev);
+ }
+ break;
+ }
+ //
+ // Controllers that depend on channels
+ //
+ case CTRL_PITCH:
+ // MusE's range is from -8192 to +8191, fluidsynth seems to be [0, 16384]
+ val +=8192;
+ err = fluid_synth_pitch_bend (fluidsynth, channel, val);
+ break;
+
+ // Added by T356
+ case FS_PITCHWHEELSENS:
+ err = fluid_synth_pitch_wheel_sens(fluidsynth, channel, val);
+ break;
+
+ case CTRL_PROGRAM: {
+ //Check if MusE is trying to set a preset on an unspecified font. If so, ignore.
+ if (FS_DEBUG)
+ printf("Program select : channel %d val %d\n",channel, val);
+ byte font_intid = channels[channel].font_intid;
+
+ if (font_intid == FS_UNSPECIFIED_ID || font_intid == FS_UNSPECIFIED_FONT)
+ return;
+
+ byte banknum = ((val >> 16) & 0xff);
+ byte patch = (val & 0xff);
+ //printf("val: %d banknum: %x patch: %d\n", val, banknum, patch);
+
+ err = fluid_synth_program_select(fluidsynth, channel, font_intid , banknum, patch);
+ if (err)
+ printf("FluidSynth::setController() - Error changing program on soundfont %s, channel: %d\n", fluid_synth_error(fluidsynth), channel);
+ else {
+ channels[channel].preset = val;//setChannelPreset(val, channel);
+ channels[channel].banknum = banknum;
+ }
+ break;
+ }
+ default:
+ if (FS_DEBUG)
+ printf("Setting controller on channel: %d with id: 0x%x to val: %d\n",channel, id, val);
+ err = fluid_synth_cc(fluidsynth, channel, id, val);
+ break;
+ }
+
+ if (err)
+ printf ("FluidSynth::setController() - error processing controller event: %s\n", fluid_synth_error(fluidsynth));
+ }
+
+//---------------------------------------------------------
+// getControllerInfo
+//---------------------------------------------------------
+int FluidSynth::getControllerInfo(int id, const char** name, int* controller, int* min, int* max, int* initval) const
+ {
+ if (id >= NUM_CONTROLLER)
+ return 0;
+ *controller = fluidCtrl[id].num;
+ *name = fluidCtrl[id].name;
+ *min = fluidCtrl[id].min;
+ *max = fluidCtrl[id].max;
+ switch(id)
+ {
+ case 0:
+ *initval = (int)(fluidCtrl[0].max*FS_PREDEF_VOLUME);
+ break;
+ case 1:
+ *initval = 0;
+ break;
+ case 2:
+ *initval = (int)(fluidCtrl[2].max*FS_PREDEF_REVERB_LEVEL);
+ break;
+ case 3:
+ *initval = (int)(fluidCtrl[3].max*FS_PREDEF_REVERB_ROOMSIZE);
+ break;
+ case 4:
+ *initval = (int)(fluidCtrl[4].max*FS_PREDEF_REVERB_DAMPING);
+ break;
+ case 5:
+ *initval = (int)(fluidCtrl[5].max*FS_PREDEF_REVERB_WIDTH);
+ break;
+ case 6:
+ *initval = 0;
+ break;
+ case 7:
+ *initval = (int)(fluidCtrl[7].max*FS_PREDEF_CHORUS_NUM);
+ break;
+ case 8:
+ *initval = (int)(fluidCtrl[8].max*FS_PREDEF_CHORUS_TYPE);
+ break;
+ case 9:
+ *initval = (int)(fluidCtrl[9].max*FS_PREDEF_CHORUS_SPEED);
+ break;
+ case 10:
+ *initval = (int)(fluidCtrl[10].max*FS_PREDEF_CHORUS_DEPTH);
+ break;
+ case 11:
+ *initval = (int)(fluidCtrl[11].max*FS_PREDEF_CHORUS_LEVEL);
+ break;
+ default:
+ *initval = fluidCtrl[id].initval;
+ break;
+ }
+
+ if (FS_DEBUG)
+ //printf("FluidSynth::getControllerInfo() id: %d name: %s controller: %d min: %d max: %d\n",id,*name,*controller,*min,*max);
+ printf("FluidSynth::getControllerInfo() id: %d name: %s controller: %d min: %d max: %d initval: %d\n",id,*name,*controller,*min,*max,*initval);
+ return ++id;
+ }
+
+//---------------------------------------------------------
+// sendError
+//---------------------------------------------------------
+void FluidSynth::sendError(const char *errorMessage)
+ {
+ int len = 2 + strlen(errorMessage);
+ unsigned char data[len];
+ *data = FS_ERROR;
+ memcpy(data + 1, errorMessage, len - 1);
+ sendSysex(len, data);
+ }
+
+//---------------------------------------------------------
+// getNextAvailableExternalId
+//---------------------------------------------------------
+
+int FluidSynth::getNextAvailableExternalId()
+ {
+ unsigned char place[FS_MAX_NR_OF_CHANNELS];
+ for(int i=0; i<FS_MAX_NR_OF_CHANNELS; i++)
+ place[i] = 0;
+ for (std::list<FluidSoundFont>::iterator it = stack.begin(); it != stack.end(); it++)
+ place[it->extid] = 1;
+
+ int i=0;
+ while (i < FS_MAX_NR_OF_CHANNELS && place[i] == 1)
+ i++;
+
+ return i;
+ }
+
+//---------------------------------------------------------
+// sfChannelChange
+//---------------------------------------------------------
+
+void FluidSynth::sfChannelChange(byte extid, byte channel)
+ {
+ if (FS_DEBUG)
+ printf("FluidSynth::sfChannelChange()-Setting channel %d to font with extid %d intid %d\n",channel, extid, getFontInternalIdByExtId(extid));
+ channels[channel].font_extid = extid;
+ channels[channel].font_intid = getFontInternalIdByExtId(extid);
+ }
+
+//---------------------------------------------------------
+// getFontInternalIdByExtId
+//---------------------------------------------------------
+byte FluidSynth::getFontInternalIdByExtId(byte ext_id)
+ {
+ for (std::list<FluidSoundFont>::iterator it = stack.begin(); it !=stack.end(); it++) {
+ if (it->extid == ext_id)
+ return it->intid;
+ }
+ return FS_UNSPECIFIED_FONT;
+ }
+
+//---------------------------------------------------------
+// sendLastDir
+//---------------------------------------------------------
+void FluidSynth::sendLastdir(const char* lastdir)
+ {
+ int n = strlen(lastdir) + 2;
+ byte d[n];
+ d[0] = FS_LASTDIR_CHANGE;
+ memcpy(d+1,lastdir, strlen(lastdir)+1);
+
+ MidiPlayEvent ev(0,0, ME_SYSEX, d, n);
+ gui->writeEvent(ev);
+ }
+
+
+//---------------------------------------------------------
+// rewriteChannelSettings
+//---------------------------------------------------------
+void FluidSynth::rewriteChannelSettings()
+ {
+ //Walk through the channels, remap internal ID:s to external ID:s (something that actually only needs to be done at
+ //startup, since the fonts aren't loaded yet at that time and it isn't possible to give them a correct internal id
+ //since they don't have any at that time, this can probably be fixed in a smarter way (but it works..))
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ int ext_id = channels[i].font_extid;//getFontExternalIdByChannel(i);
+ if (ext_id != FS_UNSPECIFIED_ID) //Check if ext_id is set to any sane font
+ {
+ channels[i].font_intid = getFontInternalIdByExtId(ext_id);//(getFontInternalIdByExtId(ext_id));//if so, get value from the stack
+ }
+ else
+ channels[i].font_intid = FS_UNSPECIFIED_FONT; //if not, set it to unspecified
+ }
+
+ //Assign correct presets to all channels
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ int preset = channels[i].preset;
+ int int_id = channels[i].font_intid;
+ byte banknum = channels[i].banknum;
+
+ if (channels[i].drumchannel)
+ banknum = 128;
+
+ //printf("Channel %d, font int-id %d ext_id %d, preset %d\n",i, int_id, getFontExternalIdByChannel(i), preset);
+ if (!(preset == FS_UNSPECIFIED_PRESET
+ || int_id == FS_UNSPECIFIED_FONT
+ || int_id == FS_UNSPECIFIED_ID)) {
+ int rv = fluid_synth_program_select(fluidsynth, i, int_id, banknum, preset);
+ if (rv)
+ std::cerr << DEBUG_ARGS << "Error changing preset! " << fluid_synth_error(fluidsynth) << std::endl;
+ }
+ }
+ }
+//---------------------------------------------------------
+// getPatchName
+//---------------------------------------------------------
+const char* FluidSynth::getPatchName(int i, int, int, bool /*drum*/) const
+ {
+ if (channels[i].font_intid == FS_UNSPECIFIED_FONT ||
+ channels[i].font_intid == FS_UNSPECIFIED_ID)
+ //return "no preset";
+ return "<unknown>";
+ else if (channels[i].preset == FS_UNSPECIFIED_PRESET)
+ //return "no preset";
+ return "<unknown>";
+ else {
+ fluid_preset_t *preset = fluid_synth_get_channel_preset(fluidsynth, i);
+ //if (!preset) return "no preset";
+ if (!preset) return "<unknown>";
+ return preset->get_name(preset);
+ }
+ }
+//---------------------------------------------------------
+// getPatchInfo
+//---------------------------------------------------------
+const MidiPatch* FluidSynth::getPatchInfo(int i, const MidiPatch* patch) const
+ {
+ //if (channels[i].font_intid == FS_UNSPECIFIED_FONT)
+ if (channels[i].font_intid == FS_UNSPECIFIED_FONT ||
+ channels[i].font_intid == FS_UNSPECIFIED_ID)
+ return 0;
+ //else if (channels[i].preset == FS_UNSPECIFIED_PRESET)
+ // return 0;
+ else {
+ //printf("Getpatchname, channel: %d\n",channel);
+ if (!patch)
+ //Deliver first patch
+ return getFirstPatch(i);
+ else
+ //Deliver next patch
+ return getNextPatch(i, patch);
+ }
+ }
+
+//---------------------------------------------------------
+// getFirstPatch
+//---------------------------------------------------------
+const MidiPatch* FluidSynth::getFirstPatch (int channel) const
+ {
+ static MidiPatch midiPatch;
+
+ midiPatch.typ = 0;
+ midiPatch.lbank = 0;
+
+ fluid_preset_t* preset;
+ int font_id = channels[channel].font_intid;
+ //if (font_id == FS_UNSPECIFIED_FONT)
+ if (font_id == FS_UNSPECIFIED_FONT || font_id == FS_UNSPECIFIED_ID)
+ return 0;
+
+ fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(fluidsynth, font_id);
+
+ if (!channels[channel].drumchannel) {
+ for (unsigned bank = 0; bank < 128; ++bank) {
+ for (unsigned patch = 0; patch < 128; ++patch) {
+ preset = sfont->get_preset (sfont, bank, patch);
+ if (preset) {
+ midiPatch.hbank = bank;
+ midiPatch.prog = patch;
+ midiPatch.name = preset->get_name (preset);
+ return &midiPatch;
+ }
+ }
+ }
+ return 0;
+ }
+ else { //This is a drumchannel
+ int bank = 128;
+ for (unsigned patch = 0; patch < 128; ++patch) {
+ preset = sfont->get_preset (sfont, bank, patch);
+ if (preset) {
+ midiPatch.hbank = bank;
+ midiPatch.prog = patch;
+ midiPatch.name = preset->get_name(preset);
+ return &midiPatch;
+ }
+ }
+ }
+ return 0;
+ }
+
+//---------------------------------------------------------
+// getNextPatch
+//---------------------------------------------------------
+const MidiPatch* FluidSynth::getNextPatch (int channel, const MidiPatch* patch) const
+ {
+ static MidiPatch midiPatch;
+ //First check if there actually is any soundfont associated to the channel. If not, don't bother
+ int font_id = channels[channel].font_intid;
+ if (font_id == FS_UNSPECIFIED_FONT || font_id == FS_UNSPECIFIED_ID)
+ return 0;
+ if (patch == 0)
+ return getFirstPatch(channel);
+ midiPatch.typ = 0;
+ midiPatch.lbank = 0;
+
+ //printf("Font has internal id: %d\n",font_id);
+ fluid_preset_t* preset;
+ fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(fluidsynth, font_id);
+
+ if (!channels[channel].drumchannel) {
+ unsigned prog = patch->prog + 1;
+
+ for (unsigned bank = patch->hbank; bank < 128; ++bank) {
+ for ( ; prog < 128; ++prog) {
+ preset = sfont->get_preset (sfont, bank, prog);
+ if (preset) {
+ //printf("Preset info: bank: %d prog: %d name: %s\n", bank, prog, preset->get_name(preset));
+ midiPatch.hbank = bank;
+ midiPatch.prog = prog;
+ midiPatch.name = preset->get_name (preset);
+ return &midiPatch;
+ }
+ }
+ prog = 0; // Reset if we "come around"
+ }
+ }
+ else { //This is a drum channel
+ unsigned bank = 128;
+ unsigned prog = patch->prog;
+ for (prog = patch->prog + 1; prog < 128; ++prog) {
+ preset = sfont->get_preset (sfont, bank, prog);
+ if (preset) {
+ //printf("Preset info: bank: %d prog: %d name: %s\n",bank, prog, preset->get_name(preset));
+ midiPatch.hbank = bank;
+ midiPatch.prog = prog;
+ midiPatch.name = preset->get_name (preset);
+ return &midiPatch;
+ }
+ }
+ }
+ return 0;
+ }
+
+//---------------------------------------------------------
+// popSoundfont
+//---------------------------------------------------------
+
+bool FluidSynth::popSoundfont (int ext_id)
+ {
+ bool success = false;
+ int int_id = getFontInternalIdByExtId(ext_id);
+
+ //if (int_id == FS_UNSPECIFIED_FONT) {
+ if (int_id == FS_UNSPECIFIED_FONT || int_id == FS_UNSPECIFIED_ID) {
+ std::cerr << DEBUG_ARGS << "Internal error! Request for deletion of Soundfont that is not registered!" << std::endl;
+ }
+ else
+ {
+ //Try to unload soundfont
+ int err = fluid_synth_sfunload(fluidsynth, int_id, 0);
+ if (err != -1) {//Success
+ //Check all channels that the font is used in
+ for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
+ //Set them to unspecified and reset preset settings
+ if (channels[i].font_intid == int_id) {
+ channels[i].font_intid = FS_UNSPECIFIED_ID;
+ channels[i].font_extid = FS_UNSPECIFIED_ID;
+ channels[i].preset = FS_UNSPECIFIED_PRESET;
+ }
+ }
+ //Remove it from soundfont stack
+ for (std::list<FluidSoundFont>::iterator it =stack.begin(); it !=stack.end(); it++) {
+ if (it->intid == int_id) {
+ stack.erase(it);
+ break;
+ }
+ }
+ //Resend fontdata & re-initialize
+ sendSoundFontData();
+ sendChannelData();
+ rewriteChannelSettings();
+ success = true;
+ currentlyLoadedFonts--;
+ }
+ else //OK, there was trouble
+ std::cerr << DEBUG_ARGS << "Error unloading soundfont!" << fluid_synth_error(fluidsynth) << std::endl;
+ }
+ if (FS_DEBUG)
+ printf("Removed soundfont with ext it: %d\n",ext_id);
+ return success;
+ }
+
+//---------------------------------------------------------
+// instantiate
+// construct a new synthesizer instance
+//---------------------------------------------------------
+
+class QWidget;
+static pthread_mutex_t globalMutex;
+static bool mutexEnabled = false;
+
+
+static Mess* instantiate(int sr, QWidget*, QString* projectPathPtr, const char* name)
+ {
+printf("fluidsynth sampleRate %d\n", sr);
+ projPathPtr=projectPathPtr;
+
+ if (!mutexEnabled) {
+ pthread_mutex_init(&globalMutex,NULL);
+ mutexEnabled = true;
+ }
+
+ FluidSynth* synth = new FluidSynth(sr, &globalMutex);
+ if (synth->init(name)) {
+ delete synth;
+ synth = 0;
+ }
+ return synth;
+ }
+
+extern "C"
+ {
+ static MESS descriptor = {
+ "FluidSynth",
+ "FluidSynth soundfont loader by Mathias Lundgren", //Mathias Lundgren (lunar_shuttle@users.sf.net)
+ "0.1", //Version string
+ MESS_MAJOR_VERSION, MESS_MINOR_VERSION,
+ instantiate,
+ };
+ const MESS* mess_descriptor() { return &descriptor; }
+ }
+
diff --git a/muse2/synti/fluidsynth/fluidsynti.h b/muse2/synti/fluidsynth/fluidsynti.h
new file mode 100644
index 00000000..10b96b9d
--- /dev/null
+++ b/muse2/synti/fluidsynth/fluidsynti.h
@@ -0,0 +1,150 @@
+/*
+ * MusE FLUID Synth softsynth plugin
+ *
+ * Copyright (C) 2004 Mathias Lundgren (lunar_shuttle@users.sourcforge.net)
+ *
+ * $Id: fluidsynti.h,v 1.15.2.5 2009/11/19 04:20:33 terminator356 Exp $
+ *
+ */
+
+#ifndef __MUSE_FLUIDSYNTI_H__
+#define __MUSE_FLUIDSYNTI_H__
+
+#include <fluidsynth.h>
+#include <qstring.h>
+#include <pthread.h>
+#include <string>
+#include "fluidsynthgui.h"
+#include "libsynti/mess.h"
+#include "muse/debug.h"
+#include "libsynti/mpevent.h"
+#include "muse/midictrl.h"
+
+#define FS_DEBUG_DATA 0 //Turn on/off debug print of midi data sent to fluidsynth
+
+typedef unsigned char byte;
+
+struct FluidSoundFont
+ {
+ std::string filename;
+ std::string name;
+ byte extid, intid;
+ };
+
+struct FluidCtrl {
+ const char* name;
+ int num;
+ int min, max;
+ //int val;
+ int initval;
+ };
+
+// NRPN-controllers:
+static const int FS_GAIN = 0 + CTRL_NRPN14_OFFSET;
+static const int FS_REVERB_ON = 1 + CTRL_NRPN14_OFFSET;
+static const int FS_REVERB_LEVEL = 2 + CTRL_NRPN14_OFFSET;
+static const int FS_REVERB_ROOMSIZE = 3 + CTRL_NRPN14_OFFSET;
+static const int FS_REVERB_DAMPING = 4 + CTRL_NRPN14_OFFSET;
+static const int FS_REVERB_WIDTH = 5 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_ON = 6 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_NUM = 7 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_TYPE = 8 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_SPEED = 9 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_DEPTH = 10 + CTRL_NRPN14_OFFSET;
+static const int FS_CHORUS_LEVEL = 11 + CTRL_NRPN14_OFFSET;
+// Added by T356
+static const int FS_PITCHWHEELSENS = 0 + CTRL_RPN_OFFSET;
+
+// FluidChannel is used to map different soundfonts to different fluid-channels
+// This is to be able to select different presets from specific soundfonts, since
+// Fluidsynth has a quite strange way of dealing with fontloading and channels
+// We also need this since getFirstPatch and getNextPatch only tells us which channel is
+// used, so this works as a connection between soundfonts and fluid-channels (one channel
+// can only have one soundfont, but one soundfont can have many channels)
+
+struct FluidChannel
+ {
+ byte font_extid, font_intid, preset, drumchannel;
+ byte banknum; // hbank
+ //FluidSoundFont* font;
+ };
+
+/*#include <string>
+#include <list>
+#include <map>
+*/
+
+class FluidSynth : public Mess {
+ private:
+ bool pushSoundfont (const char*, int);
+ void sendSysex(int l, const unsigned char* d);
+ void sendLastdir(const char*);
+ void sfChannelChange(unsigned char font_id, unsigned char channel);
+ void parseInitData(int n, const byte* d);
+
+ byte getFontInternalIdByExtId (byte channel);
+
+ void debug(const char* msg) { if (FS_DEBUG) printf("Debug: %s\n",msg); }
+ void dumpInfo(); //Prints out debug info
+
+ FluidChannel channels[FS_MAX_NR_OF_CHANNELS];
+ std::string lastdir;
+ pthread_t fontThread;
+ const MidiPatch * getFirstPatch (int channel) const;
+ const MidiPatch* getNextPatch (int, const MidiPatch *) const;
+
+ //For reverb and chorus:
+ double rev_size, rev_damping, rev_width, rev_level, cho_level, cho_speed, cho_depth;
+ bool rev_on, cho_on;
+ int cho_num, cho_type;
+
+public:
+ FluidSynth(int sr, pthread_mutex_t *_Globalsfloader_mutex);
+ ~FluidSynth();
+ bool init(const char*);
+ virtual void processMessages();
+ virtual void process(float**, int, int);
+ virtual bool playNote(int channel, int pitch, int velo);
+ virtual bool sysex(int, const unsigned char*);
+ virtual bool setController(int, int, int);
+ void setController(int, int , int, bool);
+ virtual void getInitData(int*, const unsigned char**) const;
+ virtual const char* getPatchName(int, int, int, bool) const;
+ virtual const MidiPatch* getPatchInfo(int i, const MidiPatch* patch) const;
+ virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) const;
+ virtual bool processEvent(const MidiPlayEvent&);
+
+ virtual bool hasGui() const { return true; }
+ virtual bool guiVisible() const;
+ virtual void showGui(bool val);
+
+ void sendError(const char*);
+ void sendSoundFontData();
+ void sendChannelData();
+ void rewriteChannelSettings(); //used because fluidsynth does some very nasty things when loading a font!
+ bool popSoundfont (int ext_id);
+
+ int getNextAvailableExternalId();
+
+ fluid_synth_t* fluidsynth;
+ FluidSynthGui* gui;
+ pthread_mutex_t *_sfloader_mutex;
+ int currentlyLoadedFonts; //To know whether or not to run the init-parameters
+ std::list<FluidSoundFont> stack;
+ int nrOfSoundfonts;
+
+ void initInternal();
+
+ static FluidCtrl fluidCtrl[];
+
+ };
+
+struct FS_Helper //Only used to pass parameters when calling the loading thread
+ {
+ FluidSynth* fptr;
+ std::string filename;
+ int id;
+ };
+
+static void* fontLoadThread(void* t);
+#endif /* __MUSE_FLUIDSYNTI_H__ */