summaryrefslogtreecommitdiff
path: root/muse2/muse/driver
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/driver')
-rw-r--r--muse2/muse/driver/Makefile.am10
-rw-r--r--muse2/muse/driver/Makefile.in595
-rw-r--r--muse2/muse/driver/alsamidi.cpp917
-rw-r--r--muse2/muse/driver/alsamidi.h53
-rw-r--r--muse2/muse/driver/alsatimer.cpp225
-rw-r--r--muse2/muse/driver/alsatimer.h52
-rw-r--r--muse2/muse/driver/audiodev.h74
-rw-r--r--muse2/muse/driver/dummyaudio.cpp454
-rw-r--r--muse2/muse/driver/jack.cpp2173
-rw-r--r--muse2/muse/driver/jackaudio.h97
-rw-r--r--muse2/muse/driver/jackmidi.cpp1563
-rw-r--r--muse2/muse/driver/jackmidi.h156
-rw-r--r--muse2/muse/driver/rtctimer.cpp155
-rw-r--r--muse2/muse/driver/rtctimer.h44
-rw-r--r--muse2/muse/driver/timerdev.h41
15 files changed, 6609 insertions, 0 deletions
diff --git a/muse2/muse/driver/Makefile.am b/muse2/muse/driver/Makefile.am
new file mode 100644
index 00000000..da3eba07
--- /dev/null
+++ b/muse2/muse/driver/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/common.am
+
+noinst_LIBRARIES = libdriver.a
+
+AM_CXXFLAGS += $(JACK_CFLAGS)
+
+libdriver_a_SOURCES = audiodev.h alsamidi.cpp alsamidi.h jack.cpp jackaudio.h \
+ dummyaudio.cpp alsatimer.cpp alsatimer.h timerdev.h rtctimer.cpp rtctimer.h \
+ jackmidi.cpp jackmidi.h
+
diff --git a/muse2/muse/driver/Makefile.in b/muse2/muse/driver/Makefile.in
new file mode 100644
index 00000000..8c773db5
--- /dev/null
+++ b/muse2/muse/driver/Makefile.in
@@ -0,0 +1,595 @@
+# 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
+subdir = muse/driver
+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 =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libdriver_a_AR = $(AR) $(ARFLAGS)
+libdriver_a_LIBADD =
+am_libdriver_a_OBJECTS = alsamidi.$(OBJEXT) jack.$(OBJEXT) \
+ dummyaudio.$(OBJEXT) alsatimer.$(OBJEXT) rtctimer.$(OBJEXT) \
+ jackmidi.$(OBJEXT)
+libdriver_a_OBJECTS = $(am_libdriver_a_OBJECTS)
+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 = $(libdriver_a_SOURCES)
+DIST_SOURCES = $(libdriver_a_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 $(JACK_CFLAGS)
+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
+noinst_LIBRARIES = libdriver.a
+libdriver_a_SOURCES = audiodev.h alsamidi.cpp alsamidi.h jack.cpp jackaudio.h \
+ dummyaudio.cpp alsatimer.cpp alsatimer.h timerdev.h rtctimer.cpp rtctimer.h \
+ jackmidi.cpp jackmidi.h
+
+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 $(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 muse/driver/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu muse/driver/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):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libdriver.a: $(libdriver_a_OBJECTS) $(libdriver_a_DEPENDENCIES)
+ -rm -f libdriver.a
+ $(libdriver_a_AR) libdriver.a $(libdriver_a_OBJECTS) $(libdriver_a_LIBADD)
+ $(RANLIB) libdriver.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alsamidi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alsatimer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummyaudio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jackmidi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtctimer.Po@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 $(LIBRARIES)
+installdirs:
+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:
+
+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-noinstLIBRARIES \
+ 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-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:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES 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 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
+
+
+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/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp
new file mode 100644
index 00000000..3b15fc6f
--- /dev/null
+++ b/muse2/muse/driver/alsamidi.cpp
@@ -0,0 +1,917 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: alsamidi.cpp,v 1.8.2.7 2009/11/19 04:20:33 terminator356 Exp $
+// (C) Copyright 2000-2001 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include <stdio.h>
+
+#include "alsamidi.h"
+#include "globals.h"
+#include "midi.h"
+#include "mididev.h"
+#include "../midiport.h"
+#include "../midiseq.h"
+#include "../midictrl.h"
+#include "../audio.h"
+#include "mpevent.h"
+//#include "sync.h"
+#include "utils.h"
+#include "audiodev.h"
+#include "xml.h"
+
+static int alsaSeqFdi = -1;
+static int alsaSeqFdo = -1;
+
+snd_seq_t* alsaSeq;
+static snd_seq_addr_t musePort;
+
+//---------------------------------------------------------
+// MidiAlsaDevice
+//---------------------------------------------------------
+
+MidiAlsaDevice::MidiAlsaDevice(const snd_seq_addr_t& a, const QString& n)
+ : MidiDevice(n)
+ {
+ adr = a;
+ init();
+ }
+
+//---------------------------------------------------------
+// selectWfd
+//---------------------------------------------------------
+
+int MidiAlsaDevice::selectWfd()
+ {
+ return alsaSeqFdo;
+ }
+
+//---------------------------------------------------------
+// open
+//---------------------------------------------------------
+
+QString MidiAlsaDevice::open()
+{
+ _openFlags &= _rwFlags; // restrict to available bits
+ snd_seq_port_subscribe_t* subs;
+ // Allocated on stack, no need to call snd_seq_port_subscribe_free() later.
+ snd_seq_port_subscribe_alloca(&subs);
+
+ QString estr;
+ int wer = 0;
+ int rer = 0;
+
+ // subscribe for writing
+ if (_openFlags & 1)
+ {
+ snd_seq_port_subscribe_set_sender(subs, &musePort);
+ snd_seq_port_subscribe_set_dest(subs, &adr);
+ // Not already subscribed (or error)? Then try subscribing.
+ if(snd_seq_get_port_subscription(alsaSeq, subs) < 0)
+ {
+ //int error = snd_seq_subscribe_port(alsaSeq, subs);
+ wer = snd_seq_subscribe_port(alsaSeq, subs);
+ //if (error < 0)
+ if(wer < 0)
+ //return QString("Play: ")+QString(snd_strerror(error));
+ estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" "));
+ }
+ if(!wer)
+ _writeEnable = true;
+ }
+
+ // subscribe for reading
+ if (_openFlags & 2)
+ {
+ snd_seq_port_subscribe_set_dest(subs, &musePort);
+ snd_seq_port_subscribe_set_sender(subs, &adr);
+ // Not already subscribed (or error)? Then try subscribing.
+ if(snd_seq_get_port_subscription(alsaSeq, subs) < 0)
+ {
+ //int error = snd_seq_subscribe_port(alsaSeq, subs);
+ rer = snd_seq_subscribe_port(alsaSeq, subs);
+ //if (error < 0)
+ if(rer < 0)
+ //return QString("Rec: ") + QString(snd_strerror(error));
+ estr += (QString("Rec: ") + QString(snd_strerror(rer)));
+ }
+ if(!rer)
+ _readEnable = true;
+ }
+
+
+ if(wer < 0 || rer < 0)
+ return estr;
+
+ return QString("OK");
+}
+
+//---------------------------------------------------------
+// close
+//---------------------------------------------------------
+
+void MidiAlsaDevice::close()
+{
+ snd_seq_port_subscribe_t* subs;
+ // Allocated on stack, no need to call snd_seq_port_subscribe_free() later.
+ snd_seq_port_subscribe_alloca(&subs);
+
+ // Changed by T356. This function appears to be called only by MidiPort::setMidiDevice(),
+ // which closes then opens the device.
+ // Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags.
+ //
+ // NOTE: Tested: The read unsubscribe works ok but not the write.
+ // As viewed in say, qjackctl, the connection is clearly lost,
+ // but strangely the events are still accepted, ie, playback notes
+ // are still heard etc. Tried an alsa midi device AND external fluidsynth inst.
+ //
+ // Also, jack running and with jack midi disabled, we get messages like
+ // MidiAlsaDevice::0x84512c0 putEvent(): midi write error: No such device
+ // dst 16:0
+ // only sometimes (not when playing notes), but with jack midi turned on,
+ // we don't get the messages. With jack stopped we get the messages
+ // no matter if jack midi is turned on or not.
+
+ //if (_openFlags & 1) {
+ //if (!(_openFlags & 1))
+ {
+ snd_seq_port_subscribe_set_sender(subs, &musePort);
+ snd_seq_port_subscribe_set_dest(subs, &adr);
+
+ // Already subscribed? Then unsubscribe.
+ if(!snd_seq_get_port_subscription(alsaSeq, subs))
+ {
+ if(!snd_seq_unsubscribe_port(alsaSeq, subs))
+ _writeEnable = false;
+ else
+ printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for writing\n");
+ }
+ else
+ _writeEnable = false;
+ }
+
+ //if (_openFlags & 2) {
+ //if (!(_openFlags & 2))
+ {
+ snd_seq_port_subscribe_set_dest(subs, &musePort);
+ snd_seq_port_subscribe_set_sender(subs, &adr);
+
+ // Already subscribed? Then unsubscribe.
+ if(!snd_seq_get_port_subscription(alsaSeq, subs))
+ {
+ if(!snd_seq_unsubscribe_port(alsaSeq, subs))
+ _readEnable = false;
+ else
+ printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for reading\n");
+ }
+ else
+ _readEnable = false;
+ }
+}
+
+//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void MidiAlsaDevice::writeRouting(int level, Xml& xml) const
+{
+ // p3.3.45
+ // If this device is not actually in use by the song, do not write any routes.
+ // This prevents bogus routes from being saved and propagated in the med file.
+ if(midiPort() == -1)
+ return;
+
+ QString s;
+ /*
+ //if(rwFlags() & 2) // Readable
+ {
+ //RouteList* rl = _inRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
+ {
+ // Since an ALSA midi device supports read + write, this is the only way we can tell if this route is using the device as input.
+ if(r->type == Route::TRACK_ROUTE)
+ continue;
+
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", r->name());
+ xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ //xml.strTag(level, "dstNode", name());
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ */
+
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ //if(r->type != Route::TRACK_ROUTE)
+ //{
+ // printf("MidiAlsaDevice::writeRouting Warning out route is not TRACK_ROUTE type\n");
+ // continue;
+ //}
+
+ if(!r->name().isEmpty())
+ {
+ //xml.tag(level++, "Route");
+
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+ xml.tag(level++, s);
+
+ /*
+ //xml.strTag(level, "srcNode", name());
+ if(r->channel != -1)
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, r->channel, name().latin1());
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, r->channel, name().latin1());
+ else
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ */
+ //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).latin1());
+
+ /*
+ //xml.strTag(level, "dstNode", r->name());
+ if(r->channel != -1)
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1());
+ }
+ else
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ }
+ */
+
+ s = QT_TR_NOOP("dest");
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType());
+ else
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ //s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name()));
+ xml.tag(level, s);
+
+ xml.etag(level--, "Route");
+ }
+ }
+}
+
+//---------------------------------------------------------
+// putEvent
+//---------------------------------------------------------
+
+bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
+ {
+ if (midiOutputTrace) {
+ printf("MidiOut: midiAlsa: ");
+ e.dump();
+ }
+ int chn = e.channel();
+ int a = e.dataA();
+ int b = e.dataB();
+
+ snd_seq_event_t event;
+ memset(&event, 0, sizeof(event));
+ event.queue = SND_SEQ_QUEUE_DIRECT;
+ event.source = musePort;
+ event.dest = adr;
+
+ switch(e.type()) {
+ case ME_NOTEON:
+ snd_seq_ev_set_noteon(&event, chn, a, b);
+ break;
+ case ME_NOTEOFF:
+ snd_seq_ev_set_noteoff(&event, chn, a, 0);
+ break;
+ case ME_PROGRAM:
+ snd_seq_ev_set_pgmchange(&event, chn, a);
+ break;
+ case ME_CONTROLLER:
+#if 1
+ snd_seq_ev_set_controller(&event, chn, a, b);
+#else
+ {
+ int a = e.dataA();
+ int b = e.dataB();
+ int chn = e.channel();
+ // p3.3.37
+ //if (a < 0x1000) { // 7 Bit Controller
+ if (a < CTRL_14_OFFSET) { // 7 Bit Controller
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ }
+ //else if (a < 0x20000) { // 14 bit high resolution controller
+ else if (a < CTRL_RPN_OFFSET) { // 14 bit high resolution controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ a = (ctrlH << 7) + ctrlL;
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ event.type = SND_SEQ_EVENT_CONTROL14;
+ }
+ //else if (a < 0x30000) { // RPN 7-Bit Controller
+ else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ a = (ctrlH << 7) + ctrlL;
+ b <<= 7;
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ event.type = SND_SEQ_EVENT_REGPARAM;
+ }
+ //else if (a < 0x40000) { // NRPN 7-Bit Controller
+ else if (a < CTRL_INTERNAL_OFFSET) { // NRPN 7-Bit Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ a = (ctrlH << 7) + ctrlL;
+ b <<= 7;
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ event.type = SND_SEQ_EVENT_NONREGPARAM;
+ }
+ //else if (a < 0x60000) { // RPN14 Controller
+ else if (a < CTRL_NRPN14_OFFSET) { // RPN14 Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ a = (ctrlH << 7) + ctrlL;
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ event.type = SND_SEQ_EVENT_REGPARAM;
+ }
+ //else if (a < 0x70000) { // NRPN14 Controller
+ else if (a < CTRL_NONE_OFFSET) { // NRPN14 Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ a = (ctrlH << 7) + ctrlL;
+ snd_seq_ev_set_controller(&event, chn, a, b);
+ event.type = SND_SEQ_EVENT_NONREGPARAM;
+ }
+ else {
+ printf("putEvent: unknown controller type 0x%x\n", a);
+ }
+ }
+#endif
+ break;
+ case ME_PITCHBEND:
+ snd_seq_ev_set_pitchbend(&event, chn, a);
+ break;
+ case ME_POLYAFTER:
+ // chnEvent2(chn, 0xa0, a, b);
+ break;
+ case ME_AFTERTOUCH:
+ snd_seq_ev_set_chanpress(&event, chn, a);
+ break;
+ case ME_SYSEX:
+ {
+ const unsigned char* p = e.data();
+ int n = e.len();
+ int len = n + sizeof(event) + 2;
+ char buf[len];
+ event.type = SND_SEQ_EVENT_SYSEX;
+ event.flags = SND_SEQ_EVENT_LENGTH_VARIABLE;
+ event.data.ext.len = n + 2;
+ event.data.ext.ptr = (void*)(buf + sizeof(event));
+ memcpy(buf, &event, sizeof(event));
+ char* pp = buf + sizeof(event);
+ *pp++ = 0xf0;
+ memcpy(pp, p, n);
+ pp += n;
+ *pp = 0xf7;
+ return putEvent(&event);
+ }
+ case ME_SONGPOS:
+ event.data.control.value = a;
+ event.type = SND_SEQ_EVENT_SONGPOS;
+ break;
+ case ME_CLOCK:
+ event.type = SND_SEQ_EVENT_CLOCK;
+ break;
+ case ME_START:
+ event.type = SND_SEQ_EVENT_START;
+ break;
+ case ME_CONTINUE:
+ event.type = SND_SEQ_EVENT_CONTINUE;
+ break;
+ case ME_STOP:
+ event.type = SND_SEQ_EVENT_STOP;
+ break;
+ default:
+ printf("MidiAlsaDevice::putEvent(): event type %d not implemented\n",
+ e.type());
+ return true;
+ }
+ return putEvent(&event);
+ }
+
+//---------------------------------------------------------
+// putEvent
+// return false if event is delivered
+//---------------------------------------------------------
+
+bool MidiAlsaDevice::putEvent(snd_seq_event_t* event)
+ {
+ int error;
+
+ do {
+ error = snd_seq_event_output_direct(alsaSeq, event);
+ int len = snd_seq_event_length(event);
+ if (error == len) {
+// printf(".");fflush(stdout);
+ return false;
+ }
+ if (error < 0) {
+ if (error == -12) {
+// printf("?");fflush(stdout);
+ return true;
+ }
+ else {
+ fprintf(stderr, "MidiAlsaDevice::%p putEvent(): midi write error: %s\n",
+ this, snd_strerror(error));
+ fprintf(stderr, " dst %d:%d\n", adr.client, adr.port);
+ //exit(-1);
+ }
+ }
+ else
+ fprintf(stderr, "MidiAlsaDevice::putEvent(): midi write returns %d, expected %d: %s\n",
+ error, len, snd_strerror(error));
+ } while (error == -12);
+ return true;
+ }
+
+//---------------------------------------------------------
+// initMidiAlsa
+// return true on error
+//---------------------------------------------------------
+
+bool initMidiAlsa()
+ {
+ if (debugMsg)
+ printf("initMidiAlsa\n");
+ int error = snd_seq_open(&alsaSeq, "hw", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
+ if (error < 0) {
+ fprintf(stderr, "Could not open ALSA sequencer: %s\n",
+ snd_strerror(error));
+ return true;
+ }
+ const int inCap = SND_SEQ_PORT_CAP_SUBS_READ;
+ const int outCap = SND_SEQ_PORT_CAP_SUBS_WRITE;
+
+ snd_seq_client_info_t *cinfo;
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+
+ while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) {
+ snd_seq_port_info_t *pinfo;
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
+ snd_seq_port_info_set_port(pinfo, -1);
+
+ while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) {
+ unsigned int capability = snd_seq_port_info_get_capability(pinfo);
+ if ((capability & outCap) == 0) {
+ const char *name = snd_seq_port_info_get_name(pinfo);
+ if (strcmp("Timer", name) == 0 ||
+ strcmp("Announce", name) == 0 ||
+ strcmp("Receiver", name) == 0)
+ continue;
+ }
+ snd_seq_addr_t adr = *snd_seq_port_info_get_addr(pinfo);
+ MidiAlsaDevice* dev = new MidiAlsaDevice(adr, QString(snd_seq_port_info_get_name(pinfo)));
+ int flags = 0;
+ if (capability & outCap)
+ flags |= 1;
+ if (capability & inCap)
+ flags |= 2;
+ dev->setrwFlags(flags);
+ if (debugMsg)
+ printf("ALSA port add: <%s>, %d:%d flags %d 0x%0x\n",
+ snd_seq_port_info_get_name(pinfo),
+ adr.client, adr.port,
+ flags, capability);
+ midiDevices.add(dev);
+
+ /*
+ // Experimental... Need to list 'sensible' devices first and ignore unwanted ones...
+ // Add instance last in midi device list.
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ MidiPort* mp = &midiPorts[i];
+ if(mp->device() == 0)
+ {
+ // midiSeq might not be initialzed yet!
+ //midiSeq->msgSetMidiDevice(mp, dev);
+ mp->setMidiDevice(dev);
+
+ //muse->changeConfig(true); // save configuration file
+ //update();
+ break;
+ }
+ }
+ */
+
+ }
+ }
+
+ // p3.3.38
+ //snd_seq_set_client_name(alsaSeq, "MusE Sequencer");
+ snd_seq_set_client_name(alsaSeq, audioDevice->clientName());
+
+ int ci = snd_seq_poll_descriptors_count(alsaSeq, POLLIN);
+ int co = snd_seq_poll_descriptors_count(alsaSeq, POLLOUT);
+
+ if (ci > 1 || co > 1) {
+ printf("ALSA midi: cannot handle more than one poll fd\n");
+ abort();
+ }
+
+ struct pollfd pfdi[ci];
+ struct pollfd pfdo[co];
+ snd_seq_poll_descriptors(alsaSeq, pfdi, ci, POLLIN);
+ snd_seq_poll_descriptors(alsaSeq, pfdo, co, POLLOUT);
+ alsaSeqFdo = pfdo[0].fd;
+ alsaSeqFdi = pfdi[0].fd;
+
+ int port = snd_seq_create_simple_port(alsaSeq, "MusE Port 0",
+ inCap | outCap | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE,
+ SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port < 0) {
+ perror("create port");
+ exit(1);
+ }
+ musePort.port = port;
+ musePort.client = snd_seq_client_id(alsaSeq);
+
+ //-----------------------------------------
+ // subscribe to "Announce"
+ // this enables callbacks for any
+ // alsa port changes
+ //-----------------------------------------
+
+ snd_seq_addr_t aadr;
+ aadr.client = SND_SEQ_CLIENT_SYSTEM;
+ aadr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
+
+ snd_seq_port_subscribe_t* subs;
+ snd_seq_port_subscribe_alloca(&subs);
+ snd_seq_port_subscribe_set_dest(subs, &musePort);
+ snd_seq_port_subscribe_set_sender(subs, &aadr);
+ error = snd_seq_subscribe_port(alsaSeq, subs);
+ if (error < 0) {
+ printf("Alsa: Subscribe System failed: %s", snd_strerror(error));
+ return true;
+ }
+ return false;
+ }
+
+struct AlsaPort {
+ snd_seq_addr_t adr;
+ char* name;
+ int flags;
+ AlsaPort(snd_seq_addr_t a, const char* s, int f) {
+ adr = a;
+ name = strdup(s);
+ flags = f;
+ }
+ };
+
+static std::list<AlsaPort> portList;
+
+//---------------------------------------------------------
+// alsaScanMidiPorts
+//---------------------------------------------------------
+
+void alsaScanMidiPorts()
+ {
+// printf("alsa scan midi ports\n");
+ const int inCap = SND_SEQ_PORT_CAP_SUBS_READ;
+ const int outCap = SND_SEQ_PORT_CAP_SUBS_WRITE;
+
+ portList.clear();
+
+ snd_seq_client_info_t* cinfo;
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_client_info_set_client(cinfo, 0);
+
+ while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) {
+ snd_seq_port_info_t *pinfo;
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) {
+ unsigned int capability = snd_seq_port_info_get_capability(pinfo);
+ if (((capability & outCap) == 0)
+ && ((capability & inCap) == 0))
+ continue;
+ snd_seq_addr_t adr;
+ const char* name;
+ adr = *snd_seq_port_info_get_addr(pinfo);
+ name = snd_seq_port_info_get_name(pinfo);
+ if (adr.client == musePort.client && adr.port == musePort.port)
+ continue;
+ int flags = 0;
+ if (capability & outCap)
+ flags |= 1;
+ if (capability & inCap)
+ flags |= 2;
+// printf("ALSA port add: <%s>, flags %d\n", name, flags);
+ portList.push_back(AlsaPort(adr, name, flags));
+ }
+ }
+ //
+ // check for devices to delete
+ //
+ for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end();) {
+ MidiAlsaDevice* d = dynamic_cast<MidiAlsaDevice*>(*i);
+ if (d == 0) {
+ ++i;
+ continue;
+ }
+ std::list<AlsaPort>::iterator k = portList.begin();
+ for (; k != portList.end(); ++k) {
+ if (k->adr.client == d->adr.client
+ && k->adr.port == d->adr.port) {
+ break;
+ }
+ }
+ if (k == portList.end()) {
+ if (d->midiPort() != -1)
+ midiPorts[d->midiPort()].setMidiDevice(0);
+ iMidiDevice k = i;
+// printf("erase device\n");
+ ++i;
+ midiDevices.erase(k);
+ }
+ else {
+ ++i;
+ }
+ }
+ //
+ // check for devices to add
+ //
+ for (std::list<AlsaPort>::iterator k = portList.begin(); k != portList.end(); ++k) {
+ iMidiDevice i = midiDevices.begin();
+// printf("ALSA port: <%s>\n", k->name);
+ for (;i != midiDevices.end(); ++i) {
+ MidiAlsaDevice* d = dynamic_cast<MidiAlsaDevice*>(*i);
+ if (d == 0)
+ continue;
+ if ((k->adr.client == d->adr.client) && (k->adr.port == d->adr.port)) {
+ break;
+ }
+ }
+ if (i == midiDevices.end()) {
+ // add device
+ MidiAlsaDevice* dev = new MidiAlsaDevice(k->adr,
+ QString(k->name));
+ dev->setrwFlags(k->flags);
+ midiDevices.add(dev);
+// printf("add device\n");
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// alsaSelectRfd
+//---------------------------------------------------------
+
+int alsaSelectRfd()
+ {
+ return alsaSeqFdi;
+ }
+
+//---------------------------------------------------------
+// alsaSelectWfd
+//---------------------------------------------------------
+
+int alsaSelectWfd()
+ {
+ return alsaSeqFdo;
+ }
+
+//---------------------------------------------------------
+// processInput
+//---------------------------------------------------------
+
+void alsaProcessMidiInput()
+{
+ MidiRecordEvent event;
+ snd_seq_event_t* ev;
+
+ for (;;)
+ {
+ int rv = snd_seq_event_input(alsaSeq, &ev);
+// printf("AlsaInput %d\n", rv);
+ if (rv < 0) {
+// printf("AlsaMidi: read error %s\n", snd_strerror(rv));
+ return;
+ }
+ switch(ev->type) {
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+ return;
+ case SND_SEQ_EVENT_CLIENT_START:
+ case SND_SEQ_EVENT_CLIENT_EXIT:
+ // return;
+ // on first start of a software synthesizer we only
+ // get CLIENT_START event and no PORT_START, why?
+
+ case SND_SEQ_EVENT_PORT_START:
+ case SND_SEQ_EVENT_PORT_EXIT:
+ alsaScanMidiPorts();
+ audio->midiPortsChanged(); // signal gui
+ snd_seq_free_event(ev);
+ return;
+ }
+
+ int curPort = -1;
+ MidiAlsaDevice* mdev = 0;
+ //
+ // find real source device
+ //
+ for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) {
+ MidiAlsaDevice* d = dynamic_cast<MidiAlsaDevice*>(*i);
+ if (d && d->adr.client == ev->source.client
+ && d->adr.port == ev->source.port) {
+ curPort = d->midiPort();
+ mdev = d;
+ }
+ }
+
+ if (mdev == 0 || curPort == -1) {
+ if (debugMsg) {
+ fprintf(stderr, "no port %d:%d found for received alsa event\n",
+ ev->source.client, ev->source.port);
+ }
+ snd_seq_free_event(ev);
+ return;
+ }
+
+ /*
+ if(curPort == -1)
+ {
+ if(mdev == 0)
+ {
+ if (debugMsg)
+ {
+ fprintf(stderr, "no port %d:%d found for received alsa event\n",
+ ev->source.client, ev->source.port);
+ }
+ }
+ else
+ {
+ // Allow the sync detect mechanisms to work, even if device is not assigned to a port.
+ if(ev->type == SND_SEQ_EVENT_CLOCK)
+ mdev->syncInfo().trigMCSyncDetect();
+ else
+ if(ev->type == SND_SEQ_EVENT_TICK)
+ mdev->syncInfo().trigTickDetect();
+ }
+ snd_seq_free_event(ev);
+ return;
+ }
+ */
+
+ event.setType(0); // mark as unused
+ event.setPort(curPort);
+ event.setB(0);
+
+ switch(ev->type)
+ {
+ case SND_SEQ_EVENT_NOTEON:
+ case SND_SEQ_EVENT_KEYPRESS:
+ event.setChannel(ev->data.note.channel);
+ event.setType(ME_NOTEON);
+ event.setA(ev->data.note.note);
+ event.setB(ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_NOTEOFF:
+ event.setChannel(ev->data.note.channel);
+ event.setType(ME_NOTEOFF);
+ event.setA(ev->data.note.note);
+ event.setB(ev->data.note.velocity);
+ break;
+
+ case SND_SEQ_EVENT_CHANPRESS:
+ event.setChannel(ev->data.control.channel);
+ event.setType(ME_AFTERTOUCH);
+ event.setA(ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_PGMCHANGE:
+ event.setChannel(ev->data.control.channel);
+ event.setType(ME_PROGRAM);
+ event.setA(ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_PITCHBEND:
+ event.setChannel(ev->data.control.channel);
+ event.setType(ME_PITCHBEND);
+ event.setA(ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_CONTROLLER:
+ event.setChannel(ev->data.control.channel);
+ event.setType(ME_CONTROLLER);
+ event.setA(ev->data.control.param);
+ event.setB(ev->data.control.value);
+ break;
+
+ case SND_SEQ_EVENT_CLOCK:
+ midiSeq->realtimeSystemInput(curPort, ME_CLOCK);
+ //mdev->syncInfo().trigMCSyncDetect();
+ break;
+
+ case SND_SEQ_EVENT_START:
+ midiSeq->realtimeSystemInput(curPort, ME_START);
+ break;
+
+ case SND_SEQ_EVENT_CONTINUE:
+ midiSeq->realtimeSystemInput(curPort, ME_CONTINUE);
+ break;
+
+ case SND_SEQ_EVENT_STOP:
+ midiSeq->realtimeSystemInput(curPort, ME_STOP);
+ break;
+
+ case SND_SEQ_EVENT_TICK:
+ midiSeq->realtimeSystemInput(curPort, ME_TICK);
+ //mdev->syncInfo().trigTickDetect();
+ break;
+
+ case SND_SEQ_EVENT_SYSEX:
+
+ // TODO: Deal with large sysex, which are broken up into chunks!
+ // For now, do not accept if the first byte is not SYSEX or the last byte is not EOX,
+ // meaning it's a chunk, possibly with more chunks to follow.
+ if((*((unsigned char*)ev->data.ext.ptr) != ME_SYSEX) ||
+ (*(((unsigned char*)ev->data.ext.ptr) + ev->data.ext.len - 1) != ME_SYSEX_END))
+ {
+ printf("MusE: alsaProcessMidiInput sysex chunks not supported!\n");
+ break;
+ }
+
+ event.setTime(0); // mark as used
+ event.setType(ME_SYSEX);
+ event.setData((unsigned char*)(ev->data.ext.ptr)+1,
+ ev->data.ext.len-2);
+ break;
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: // write port is released
+ break;
+ case SND_SEQ_EVENT_SONGPOS:
+ midiSeq->setSongPosition(curPort, ev->data.control.value);
+ break;
+ case SND_SEQ_EVENT_SENSING:
+ break;
+ case SND_SEQ_EVENT_QFRAME:
+ midiSeq->mtcInputQuarter(curPort, ev->data.control.value);
+ break;
+ // case SND_SEQ_EVENT_CLIENT_START:
+ // case SND_SEQ_EVENT_CLIENT_EXIT:
+ // case SND_SEQ_EVENT_CLIENT_CHANGE:
+ // case SND_SEQ_EVENT_PORT_CHANGE:
+ // case SND_SEQ_EVENT_SONGSEL:
+ // case SND_SEQ_EVENT_TIMESIGN:
+ // case SND_SEQ_EVENT_KEYSIGN:
+ // case SND_SEQ_EVENT_SETPOS_TICK:
+ // case SND_SEQ_EVENT_SETPOS_TIME:
+ // case SND_SEQ_EVENT_TEMPO:
+ // case SND_SEQ_EVENT_TUNE_REQUEST:
+ // case SND_SEQ_EVENT_RESET:
+
+ // case SND_SEQ_EVENT_NOTE:
+ // case SND_SEQ_EVENT_CONTROL14:
+ // case SND_SEQ_EVENT_NONREGPARAM:
+ // case SND_SEQ_EVENT_REGPARAM:
+ default:
+ printf("ALSA Midi input: type %d not handled\n", ev->type);
+ break;
+ }
+ if(event.type())
+ {
+ mdev->recordEvent(event);
+ // p3.3.26 1/23/10 Moved to MidiDevice now. Anticipating Jack midi support, so don't make it ALSA specific. Tim.
+ //if(ev->type != SND_SEQ_EVENT_SYSEX)
+ // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
+ // midiPorts[curPort].syncInfo().trigActDetect(event.channel());
+ }
+
+ snd_seq_free_event(ev);
+ if (rv == 0)
+ break;
+ }
+}
+
diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h
new file mode 100644
index 00000000..6c19ff0d
--- /dev/null
+++ b/muse2/muse/driver/alsamidi.h
@@ -0,0 +1,53 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: alsamidi.h,v 1.2 2004/01/14 09:06:43 wschweer Exp $
+// (C) Copyright 2001 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __ALSAMIDI_H__
+#define __ALSAMIDI_H__
+
+#include <config.h>
+#include <alsa/asoundlib.h>
+
+#include "mididev.h"
+
+class Xml;
+
+//---------------------------------------------------------
+// MidiAlsaDevice
+//---------------------------------------------------------
+
+class MidiAlsaDevice : public MidiDevice {
+ public:
+ snd_seq_addr_t adr;
+
+ private:
+ virtual QString open();
+ virtual void close();
+ virtual void processInput() {}
+ virtual int selectRfd() { return -1; }
+ virtual int selectWfd();
+
+ bool putEvent(snd_seq_event_t*);
+ virtual bool putMidiEvent(const MidiPlayEvent&);
+
+ public:
+ MidiAlsaDevice() {}
+ MidiAlsaDevice(const snd_seq_addr_t&, const QString& name);
+ virtual ~MidiAlsaDevice() {}
+ virtual void* clientPort() { return (void*)&adr; }
+ virtual void writeRouting(int, Xml&) const;
+ virtual inline int deviceType() { return ALSA_MIDI; }
+ };
+
+extern bool initMidiAlsa();
+extern int alsaSelectRfd();
+extern int alsaSelectWfd();
+extern void alsaProcessMidiInput();
+extern void alsaScanMidiPorts();
+
+#endif
+
+
diff --git a/muse2/muse/driver/alsatimer.cpp b/muse2/muse/driver/alsatimer.cpp
new file mode 100644
index 00000000..d851410d
--- /dev/null
+++ b/muse2/muse/driver/alsatimer.cpp
@@ -0,0 +1,225 @@
+ //=========================================================
+ // MusE
+ // Linux Music Editor
+ // $Id: alsatimer.cpp,v 1.1.2.9 2009/03/28 01:46:10 terminator356 Exp $
+ //
+ // Plenty of code borrowed from timer.c example in
+ // alsalib 1.0.7
+ //
+ // (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+ //=========================================================
+
+ #include "alsatimer.h"
+ #include <climits>
+
+#define TIMER_DEBUG 0
+
+ AlsaTimer::AlsaTimer()
+ {
+ if(TIMER_DEBUG)
+ fprintf(stderr,"AlsaTimer::AlsaTimer(this=%p) called\n",this);
+ handle = NULL;
+ id = NULL;
+ info = NULL;
+ params = NULL;
+ findBest = true;
+ }
+
+ AlsaTimer::~AlsaTimer()
+ {
+ if(TIMER_DEBUG)
+ fprintf(stderr,"AlsaTimer::~AlsaTimer(this=%p) called\n",this);
+ if (handle)
+ snd_timer_close(handle);
+ if (id) snd_timer_id_free(id);
+ if (info) snd_timer_info_free(info);
+ if (params) snd_timer_params_free(params);
+ }
+
+ signed int AlsaTimer::initTimer()
+ {
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::initTimer(this=%p)\n",this);
+
+ int err;
+ int devclass = SND_TIMER_CLASS_GLOBAL;
+ int sclass = SND_TIMER_CLASS_NONE;
+ int card = 0;
+ int device = SND_TIMER_GLOBAL_SYSTEM;
+ int subdevice = 0;
+ int test_ids[] = { SND_TIMER_GLOBAL_SYSTEM
+ , SND_TIMER_GLOBAL_RTC
+#ifdef SND_TIMER_GLOBAL_HPET
+ , SND_TIMER_GLOBAL_HPET
+#endif
+ };
+ int max_ids = sizeof(test_ids) / sizeof(int);
+ long best_res = LONG_MAX;
+ //int best_dev = -1; // SND_TIMER_GLOBAL_SYSTEM;
+ int best_dev = SND_TIMER_GLOBAL_SYSTEM; // p3.3.51
+ int i;
+
+ if (id || info || params) {
+ fprintf(stderr,"AlsaTimer::initTimer(): called on initialised timer!\n");
+ return fds->fd;
+ }
+ snd_timer_id_malloc(&id);
+ snd_timer_info_malloc(&info);
+ snd_timer_params_malloc(&params);
+
+ if (findBest) {
+ for (i = 0; i < max_ids; ++i) {
+ device = test_ids[i];
+ sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i", devclass, sclass, card, device, subdevice);
+ if ((err = snd_timer_open(&handle, timername, SND_TIMER_OPEN_NONBLOCK)) < 0) {
+ continue;
+ }
+ if ((err = snd_timer_info(handle, info)) < 0) {
+ snd_timer_close(handle);
+ continue;
+ }
+ // select a non slave timer with the lowest resolution value
+ int is_slave = snd_timer_info_is_slave(info);
+ long res = snd_timer_info_get_resolution(info);
+ if ((is_slave == 0) && (best_res > res)) {
+ best_res = res;
+ best_dev = device;
+ }
+ snd_timer_close(handle);
+ }
+ device = best_dev;
+ }
+
+ // p3.3.51 Removed.
+ //if(best_dev==-1)
+ // return -1; // no working timer found
+
+ sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i", devclass, sclass, card, device, subdevice);
+ if ((err = snd_timer_open(&handle, timername, SND_TIMER_OPEN_NONBLOCK))<0) {
+ fprintf(stderr, "AlsaTimer::initTimer(): timer open %i (%s)\n", err, snd_strerror(err));
+ return -1; // p3.3.51
+ }
+
+ if ((err = snd_timer_info(handle, info)) < 0) {
+ fprintf(stderr, "AlsaTimer::initTimer(): timer info %i (%s)\n", err, snd_strerror(err));
+ return -1;
+ }
+
+ //if(debugMsg)
+ fprintf(stderr, "AlsaTimer::initTimer(): best available ALSA timer: %s\n", snd_timer_info_get_name(info));
+
+ snd_timer_params_set_auto_start(params, 1);
+ snd_timer_params_set_ticks(params, 1);
+
+ if ((err = snd_timer_params(handle, params)) < 0) {
+ fprintf(stderr, "AlsaTimer::initTimer(): timer params %i (%s)\n", err, snd_strerror(err));
+ return -1;
+ }
+
+ count = snd_timer_poll_descriptors_count(handle);
+ fds = (pollfd *)calloc(count, sizeof(pollfd));
+ if (fds == NULL) {
+ fprintf(stderr, "AlsaTimer::initTimer(): malloc error\n");
+ return -1;
+ }
+ if ((err = snd_timer_poll_descriptors(handle, fds, count)) < 0) {
+ fprintf(stderr, "AlsaTimer::initTimer(): snd_timer_poll_descriptors error: %s\n", snd_strerror(err));
+ return -1;
+ }
+ return fds->fd;
+ }
+
+ unsigned int AlsaTimer::setTimerResolution(unsigned int resolution)
+ {
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::setTimerResolution(%d)\n",resolution);
+ /* Resolution of an AlsaTimer is fixed - it cannot be set */
+ return 0;
+ }
+
+ unsigned int AlsaTimer::setTimerFreq(unsigned int freq)
+ {
+ signed int err;
+ unsigned int setTick, actFreq;
+
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::setTimerFreq(this=%p)\n",this);
+
+ setTick = (1000000000 / snd_timer_info_get_resolution(info)) / freq;
+
+ if (setTick == 0) {
+ // return, print error if freq is below 500 (timing will suffer)
+ if (((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params)) < 500) {
+ fprintf(stderr,"AlsaTimer::setTimerTicks(): requested freq %u Hz too high for timer (max is %g)\n",
+ freq, 1000000000.0 / snd_timer_info_get_resolution(info));
+ fprintf(stderr," freq stays at %ld Hz\n",
+ (long int)((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params)));
+ }
+
+ return 0;
+ }
+ actFreq = (1000000000 / snd_timer_info_get_resolution(info)) / setTick;
+ if (actFreq != freq) {
+ fprintf(stderr,"AlsaTimer::setTimerTicks(): warning: requested %u Hz, actual freq is %u Hz\n",
+ freq, actFreq);
+ }
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::setTimerFreq(): Setting ticks (period) to %d ticks\n", setTick);
+ snd_timer_params_set_auto_start(params, 1);
+ snd_timer_params_set_ticks(params, setTick);
+ if ((err = snd_timer_params(handle, params)) < 0) {
+ fprintf(stderr, "AlsaTimer::setTimerFreq(): timer params %i (%s)\n", err, snd_strerror(err));
+ return 0;
+ }
+
+ return actFreq;
+ }
+
+ unsigned int AlsaTimer::getTimerResolution()
+ {
+ return snd_timer_info_get_resolution(info);
+ }
+
+ unsigned int AlsaTimer::getTimerFreq()
+ {
+ return (1000000000 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params);
+ }
+
+ bool AlsaTimer::startTimer()
+ {
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::startTimer(this=%p): handle=%p\n",this,handle);
+ int err;
+ if ((err = snd_timer_start(handle)) < 0) {
+ fprintf(stderr, "AlsaTimer::startTimer(): timer start %i (%s)\n", err, snd_strerror(err));
+ return false;
+ }
+ return true;
+ }
+
+ bool AlsaTimer::stopTimer()
+ {
+ int err;
+ if(TIMER_DEBUG)
+ printf("AlsaTimer::stopTimer(this=%p): handle=%p\n",this,handle);
+ if ((err = snd_timer_stop(handle)) < 0) {
+ fprintf(stderr, "AlsaTimer::stopTimer(): timer stop %i (%s)\n", err, snd_strerror(err));
+ return false;
+ }
+ return true;
+ }
+
+ unsigned int AlsaTimer::getTimerTicks(bool printTicks)
+ {
+ //if(TIMER_DEBUG)
+ // printf("AlsaTimer::getTimerTicks\n");
+ snd_timer_read_t tr;
+ tr.ticks = 0;
+ while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr)) {
+ if (printTicks) {
+ printf("TIMER: resolution = %uns, ticks = %u\n",
+ tr.resolution, tr.ticks);
+ }
+ }
+ return tr.ticks;
+ }
diff --git a/muse2/muse/driver/alsatimer.h b/muse2/muse/driver/alsatimer.h
new file mode 100644
index 00000000..211ba5ec
--- /dev/null
+++ b/muse2/muse/driver/alsatimer.h
@@ -0,0 +1,52 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: alsatimer.h,v 1.1.2.4 2009/03/09 02:05:18 terminator356 Exp $
+//
+// Plenty of code borrowed from timer.c example in
+// alsalib 1.0.7
+//
+// (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+//=========================================================
+
+#ifndef __ALSATIMER_H__
+#define __ALSATIMER_H__
+
+#include "alsa/asoundlib.h"
+#include "timerdev.h"
+
+
+//---------------------------------------------------------
+// AlsaTimer
+//---------------------------------------------------------
+
+class AlsaTimer : public Timer{
+
+ snd_timer_t *handle;
+ snd_timer_id_t *id;
+ snd_timer_info_t *info;
+ snd_timer_params_t *params;
+ struct pollfd *fds;
+ char timername[64];
+ signed int count;
+ unsigned int ticks;
+ bool findBest;
+
+ public:
+ AlsaTimer();
+ virtual ~AlsaTimer();
+
+ virtual signed int initTimer();
+ virtual unsigned int setTimerResolution(unsigned int resolution);
+ virtual unsigned int getTimerResolution();
+ virtual unsigned int setTimerFreq(unsigned int freq);
+ virtual unsigned int getTimerFreq();
+
+ virtual bool startTimer();
+ virtual bool stopTimer();
+ virtual unsigned int getTimerTicks(bool printTicks=false);
+
+ void setFindBestTimer(bool b) { findBest = b; }
+};
+
+#endif //__ALSATIMER_H__
diff --git a/muse2/muse/driver/audiodev.h b/muse2/muse/driver/audiodev.h
new file mode 100644
index 00000000..39ff822e
--- /dev/null
+++ b/muse2/muse/driver/audiodev.h
@@ -0,0 +1,74 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: audiodev.h,v 1.5.2.2 2009/12/20 05:00:35 terminator356 Exp $
+//
+// (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __AUDIODEV_H__
+#define __AUDIODEV_H__
+
+#include <qstring.h>
+#include <list>
+
+class MidiPlayEvent;
+
+//---------------------------------------------------------
+// AudioDevice
+//---------------------------------------------------------
+
+class AudioDevice {
+
+ public:
+ enum { DUMMY_AUDIO=0, JACK_AUDIO=1 }; // p3.3.52
+
+ AudioDevice() {}
+ virtual ~AudioDevice() {}
+
+ virtual int deviceType() = 0; // p3.3.52
+
+ //virtual void start() = 0;
+ virtual void start(int priority) = 0;
+
+ virtual void stop () = 0;
+ virtual int framePos() const = 0;
+ virtual unsigned frameTime() const = 0;
+
+ virtual float* getBuffer(void* port, unsigned long nframes) = 0;
+
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1) = 0;
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1) = 0;
+
+ virtual void registerClient() = 0;
+
+ virtual const char* clientName() = 0;
+
+ //virtual void* registerOutPort(const char* name) = 0;
+ //virtual void* registerInPort(const char* name) = 0;
+ virtual void* registerOutPort(const char* /*name*/, bool /*midi*/) = 0;
+ virtual void* registerInPort(const char* /*name*/, bool /*midi*/) = 0;
+
+ virtual void unregisterPort(void*) = 0;
+ virtual void connect(void*, void*) = 0;
+ virtual void disconnect(void*, void*) = 0;
+ virtual int connections(void* /*clientPort*/) = 0;
+ virtual void setPortName(void* p, const char* n) = 0;
+ virtual void* findPort(const char* name) = 0;
+ virtual QString portName(void* port) = 0;
+ virtual int getState() = 0;
+ virtual unsigned getCurFrame() = 0;
+ virtual bool isRealtime() = 0;
+ virtual int realtimePriority() const = 0; // return zero if not realtime
+ virtual void startTransport() = 0;
+ virtual void stopTransport() = 0;
+ virtual void seekTransport(unsigned frame) = 0;
+ virtual void seekTransport(const Pos &p) = 0;
+ virtual void setFreewheel(bool f) = 0;
+ virtual void graphChanged() {}
+ virtual void registrationChanged() {}
+ virtual int setMaster(bool f) = 0;
+ };
+
+#endif
+
diff --git a/muse2/muse/driver/dummyaudio.cpp b/muse2/muse/driver/dummyaudio.cpp
new file mode 100644
index 00000000..a17a99e7
--- /dev/null
+++ b/muse2/muse/driver/dummyaudio.cpp
@@ -0,0 +1,454 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: dummyaudio.cpp,v 1.3.2.16 2009/12/20 05:00:35 terminator356 Exp $
+// (C) Copyright 2002-2003 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <qmessagebox.h>
+
+#include "config.h"
+#include "audio.h"
+#include "audiodev.h"
+#include "globals.h"
+#include "song.h"
+#include "driver/alsatimer.h"
+#include "pos.h"
+#include "gconfig.h"
+#include "utils.h"
+
+class MidiPlayEvent;
+
+#define DEBUG_DUMMY 0
+//---------------------------------------------------------
+// DummyAudioDevice
+//---------------------------------------------------------
+
+//static const unsigned dummyFrames = 1024;
+
+enum Cmd {
+trSeek,
+trStart,
+trStop
+};
+
+struct Msg {
+ enum Cmd cmd;
+ int arg;
+};
+
+
+class DummyAudioDevice : public AudioDevice {
+ pthread_t dummyThread;
+ // Changed by Tim. p3.3.15
+ //float buffer[1024];
+ float* buffer;
+ int _realTimePriority;
+
+ public:
+ std::list<Msg> cmdQueue;
+ Audio::State state;
+ int _framePos;
+ int playPos;
+ bool realtimeFlag;
+
+ DummyAudioDevice();
+ virtual ~DummyAudioDevice()
+ {
+ // Added by Tim. p3.3.15
+ free(buffer);
+ }
+
+ virtual inline int deviceType() { return DUMMY_AUDIO; } // p3.3.52
+
+ //virtual void start();
+ virtual void start(int);
+
+ virtual void stop ();
+ virtual int framePos() const {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::framePos %d\n", _framePos);
+ return _framePos;
+ }
+
+ virtual float* getBuffer(void* /*port*/, unsigned long nframes)
+ {
+ // p3.3.30
+ //if (nframes > dummyFrames) {
+ //printf("error: segment size > 1024\n");
+ if (nframes > segmentSize) {
+ printf("DummyAudioDevice::getBuffer nframes > segment size\n");
+
+ exit(-1);
+ }
+ return buffer;
+ }
+
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1);
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);
+
+ virtual void registerClient() {}
+
+ virtual const char* clientName() { return "MusE"; }
+
+ //virtual void* registerOutPort(const char*) {
+ virtual void* registerOutPort(const char*, bool) {
+ return (void*)1;
+ }
+ //virtual void* registerInPort(const char*) {
+ virtual void* registerInPort(const char*, bool) {
+ return (void*)2;
+ }
+ virtual void unregisterPort(void*) {}
+ virtual void connect(void*, void*) {}
+ virtual void disconnect(void*, void*) {}
+ virtual int connections(void* /*clientPort*/) { return 0; }
+ virtual void setPortName(void*, const char*) {}
+ virtual void* findPort(const char*) { return 0;}
+ virtual QString portName(void*) {
+ return QString("mops");
+ }
+ virtual int getState() {
+// if(DEBUG_DUMMY)
+// printf("DummyAudioDevice::getState %d\n", state);
+
+ return state; }
+ virtual unsigned getCurFrame() {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::getCurFrame %d\n", _framePos);
+
+ return _framePos; }
+ virtual unsigned frameTime() const {
+ return lrint(curTime() * sampleRate);
+ }
+ virtual bool isRealtime() { return realtimeFlag; }
+ //virtual int realtimePriority() const { return 40; }
+ virtual int realtimePriority() const { return _realTimePriority; }
+ virtual void startTransport() {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::startTransport playPos=%d\n", playPos);
+ Msg trcmd;
+ trcmd.cmd = trStart;
+ trcmd.arg = playPos;
+ cmdQueue.push_front(trcmd);
+/* state = Audio::START_PLAY;
+ audio->sync(state, playPos);
+ state = Audio::PLAY;*/
+ }
+ virtual void stopTransport() {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::stopTransport, playPos=%d\n", playPos);
+ state = Audio::STOP;
+ }
+ virtual int setMaster(bool) { return 1; }
+
+ virtual void seekTransport(const Pos &p)
+ {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::seekTransport frame=%d topos=%d\n",playPos, p.frame());
+ Msg trcmd;
+ trcmd.cmd = trSeek;
+ trcmd.arg = p.frame();
+ cmdQueue.push_front(trcmd);
+ playPos = p.frame();
+ }
+ virtual void seekTransport(unsigned pos) {
+ if(DEBUG_DUMMY)
+ printf("DummyAudioDevice::seekTransport frame=%d topos=%d\n",playPos,pos);
+ Msg trcmd;
+ trcmd.cmd = trSeek;
+ trcmd.arg = pos;
+ cmdQueue.push_front(trcmd);
+ playPos = pos;
+/*
+ Audio::State tempState = state;
+ state = Audio::START_PLAY;
+ audio->sync(state, playPos);
+ state = tempState;*/
+ }
+ virtual void setFreewheel(bool) {}
+ void setRealTime() { realtimeFlag = true; }
+ };
+
+DummyAudioDevice* dummyAudio = 0;
+
+DummyAudioDevice::DummyAudioDevice()
+ {
+ // Added by Tim. p3.3.15
+ // p3.3.30
+ //posix_memalign((void**)&buffer, 16, sizeof(float) * dummyFrames);
+ posix_memalign((void**)&buffer, 16, sizeof(float) * config.dummyAudioBufSize);
+
+ realtimeFlag = false;
+ state = Audio::STOP;
+ _framePos = 0;
+ playPos = 0;
+ cmdQueue.clear();
+ }
+
+//---------------------------------------------------------
+// exitDummyAudio
+//---------------------------------------------------------
+
+void exitDummyAudio()
+{
+ if(dummyAudio)
+ delete dummyAudio;
+ dummyAudio = NULL;
+ audioDevice = NULL;
+}
+
+//---------------------------------------------------------
+// initDummyAudio
+//---------------------------------------------------------
+
+bool initDummyAudio()
+ {
+ dummyAudio = new DummyAudioDevice();
+ audioDevice = dummyAudio;
+ return false;
+ }
+
+//---------------------------------------------------------
+// outputPorts
+//---------------------------------------------------------
+
+std::list<QString> DummyAudioDevice::outputPorts(bool midi, int /*aliases*/)
+ {
+ std::list<QString> clientList;
+ if(!midi)
+ {
+ clientList.push_back(QString("output1"));
+ clientList.push_back(QString("output2"));
+ }
+ return clientList;
+ }
+
+//---------------------------------------------------------
+// inputPorts
+//---------------------------------------------------------
+
+std::list<QString> DummyAudioDevice::inputPorts(bool midi, int /*aliases*/)
+ {
+ std::list<QString> clientList;
+ if(!midi)
+ {
+ clientList.push_back(QString("input1"));
+ clientList.push_back(QString("input2"));
+ }
+ return clientList;
+ }
+
+//---------------------------------------------------------
+// dummyLoop
+//---------------------------------------------------------
+
+static void* dummyLoop(void* ptr)
+ {
+ //unsigned int tickRate = 25;
+
+ // p3.3.30
+ //sampleRate = 25600;
+ sampleRate = config.dummyAudioSampleRate;
+ //segmentSize = dummyFrames;
+ segmentSize = config.dummyAudioBufSize;
+ //unsigned int tickRate = sampleRate / dummyFrames;
+ unsigned int tickRate = sampleRate / segmentSize;
+
+ AlsaTimer timer;
+ fprintf(stderr, "Get alsa timer for dummy driver:\n");
+ timer.setFindBestTimer(false);
+ int fd = timer.initTimer();
+ if (fd==-1) {
+ // QMessageBox::critical( 0, /*tr*/(QString("Failed to start timer for dummy audio driver!")),
+ // /*tr*/(QString("No functional timer was available.\n"
+ // "Alsa timer not available, check if module snd_timer is available and /dev/snd/timer is available")));
+ fprintf(stderr, "Failed to start timer for dummy audio driver! No functional timer was available.\n"
+ "Alsa timer not available, check if module snd_timer is available and /dev/snd/timer is available\n");
+ pthread_exit(0);
+ }
+
+ /* Depending on nature of the timer, the requested tickRate might not
+ * be available. The return value is the nearest available frequency,
+ * so use this to reset our dummpy sampleRate to keep everything
+ * consistent.
+ */
+ tickRate = timer.setTimerFreq( /*250*/ tickRate );
+
+ // p3.3.31
+ // If it didn't work, get the actual rate.
+ if(tickRate == 0)
+ tickRate = timer.getTimerFreq();
+
+ sampleRate = tickRate * segmentSize;
+ timer.startTimer();
+
+ DummyAudioDevice *drvPtr = (DummyAudioDevice *)ptr;
+
+ pollfd myPollFd;
+
+ myPollFd.fd = fd;
+ myPollFd.events = POLLIN;
+
+ /*
+ doSetuid();
+ struct sched_param rt_param;
+ int rv;
+ memset(&rt_param, 0, sizeof(sched_param));
+ int type;
+ rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
+ if (rv != 0)
+ perror("get scheduler parameter");
+ if (type != SCHED_FIFO) {
+ fprintf(stderr, "Driver thread not running SCHED_FIFO, trying to set...\n");
+
+ memset(&rt_param, 0, sizeof(sched_param));
+ //rt_param.sched_priority = 1;
+ rt_param.sched_priority = realtimePriority();
+ rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
+ if (rv != 0)
+ perror("set realtime scheduler");
+ memset(&rt_param, 0, sizeof(sched_param));
+ rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
+ if (rv != 0)
+ perror("get scheduler parameter");
+ if (type == SCHED_FIFO) {
+ drvPtr->setRealTime();
+ fprintf(stderr, "Thread succesfully set to SCHED_FIFO\n");
+ }
+ else {
+ fprintf(stderr, "Unable to set thread to SCHED_FIFO\n");
+ }
+ }
+ undoSetuid();
+ */
+
+#ifndef __APPLE__
+ doSetuid();
+ //if (realTimePriority) {
+ if (realTimeScheduling) {
+ //
+ // check if we really got realtime priviledges
+ //
+ int policy;
+ if ((policy = sched_getscheduler (0)) < 0) {
+ printf("cannot get current client scheduler for audio dummy thread: %s!\n", strerror(errno));
+ }
+ else
+ {
+ if (policy != SCHED_FIFO)
+ printf("audio dummy thread _NOT_ running SCHED_FIFO\n");
+ else if (debugMsg) {
+ struct sched_param rt_param;
+ memset(&rt_param, 0, sizeof(sched_param));
+ int type;
+ int rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
+ if (rv == -1)
+ perror("get scheduler parameter");
+ printf("audio dummy thread running SCHED_FIFO priority %d\n",
+ rt_param.sched_priority);
+ }
+ }
+ }
+ undoSetuid();
+#endif
+
+ /* unsigned long tick = 0;*/ // prevent compiler warning: unused variable
+ for (;;) {
+ int _pollWait = 10; // ms
+ unsigned long count = 0;
+ while (count < 1 /*250/tickRate*/) // will loop until the next tick occurs
+ {
+ /*int n = */ poll(&myPollFd, 1 /* npfd */, _pollWait);
+ count += timer.getTimerTicks();
+ while (drvPtr->cmdQueue.size())
+ {
+ Msg &msg = drvPtr->cmdQueue.back();
+ drvPtr->cmdQueue.pop_back();
+ switch(msg.cmd) {
+ case trSeek:
+ {
+ //printf("trSeek\n");
+ drvPtr->playPos = msg.arg;
+ Audio::State tempState = drvPtr->state;
+ drvPtr->state = Audio::START_PLAY;
+ audio->sync(drvPtr->state, msg.arg);
+ drvPtr->state = tempState;
+ }
+ break;
+ case trStart:
+ {
+ //printf("trStart\n");
+ drvPtr->state = Audio::START_PLAY;
+ audio->sync(drvPtr->state, msg.arg);
+ drvPtr->state = Audio::PLAY;
+ }
+ break;
+ case trStop:
+ break;
+ default:
+ printf("dummyLoop: Unknown command!\n");
+ }
+ }
+ }
+ audio->process(segmentSize);
+ int increment = segmentSize; // 1 //tickRate / sampleRate * segmentSize;
+ drvPtr->_framePos+=increment;
+ if (drvPtr->state == Audio::PLAY)
+ {
+ drvPtr->playPos+=increment;
+ }
+ }
+ timer.stopTimer();
+ pthread_exit(0);
+ }
+
+//void DummyAudioDevice::start()
+void DummyAudioDevice::start(int priority)
+ {
+ //realTimePriority = priority;
+ _realTimePriority = priority;
+ pthread_attr_t* attributes = 0;
+
+ //if (priority) {
+ if (realTimeScheduling && priority > 0) {
+ attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
+ pthread_attr_init(attributes);
+
+ if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) {
+ printf("cannot set FIFO scheduling class for RT thread\n");
+ }
+ if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) {
+ printf("Cannot set scheduling scope for RT thread\n");
+ }
+ struct sched_param rt_param;
+ memset(&rt_param, 0, sizeof(rt_param));
+ rt_param.sched_priority = priority;
+ if (pthread_attr_setschedparam (attributes, &rt_param)) {
+ printf("Cannot set scheduling priority %d for RT thread (%s)\n",
+ priority, strerror(errno));
+ }
+ }
+
+ //pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
+ //pthread_attr_init(attributes);
+ if (pthread_create(&dummyThread, attributes, ::dummyLoop, this))
+ perror("creating thread failed:");
+ if (priority)
+ pthread_attr_destroy(attributes);
+ }
+
+void DummyAudioDevice::stop ()
+ {
+ pthread_cancel(dummyThread);
+ pthread_join(dummyThread, 0);
+ dummyThread = 0;
+ }
+
diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp
new file mode 100644
index 00000000..2c5081fc
--- /dev/null
+++ b/muse2/muse/driver/jack.cpp
@@ -0,0 +1,2173 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: jack.cpp,v 1.30.2.17 2009/12/20 05:00:35 terminator356 Exp $
+// (C) Copyright 2002 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include "config.h"
+#include <string>
+#include <set>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+//#include <time.h>
+#include <unistd.h>
+#include <jack/midiport.h>
+#include <string.h>
+
+#include "audio.h"
+#include "globals.h"
+#include "song.h"
+#include "jackaudio.h"
+#include "track.h"
+#include "pos.h"
+#include "tempo.h"
+#include "sync.h"
+#include "utils.h"
+
+#include "midi.h"
+#include "mididev.h"
+#include "mpevent.h"
+
+#include "jackmidi.h"
+
+
+#define JACK_DEBUG 0
+
+//#include "errorhandler.h"
+
+#ifndef RTCAP
+extern void doSetuid();
+extern void undoSetuid();
+#endif
+
+#ifdef VST_SUPPORT
+#include <fst.h>
+#endif
+
+//extern int jackmidi_pi[2];
+//extern int jackmidi_po[2];
+
+//jack_port_t *midi_port_in[JACK_MIDI_CHANNELS];
+//jack_port_t *midi_port_out[JACK_MIDI_CHANNELS];
+
+//muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS];
+//muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS];
+
+JackAudioDevice* jackAudio;
+
+//---------------------------------------------------------
+// checkJackClient - make sure client is valid
+//---------------------------------------------------------
+inline bool checkJackClient(jack_client_t* _client)
+ {
+ if (_client == NULL) {
+ printf("Panic! no _client!\n");
+ return false;
+ }
+ return true;
+ }
+//---------------------------------------------------------
+// checkAudioDevice - make sure audioDevice exists
+//---------------------------------------------------------
+bool checkAudioDevice()
+ {
+ if (audioDevice == NULL) {
+ printf("Muse:checkAudioDevice: no audioDevice\n");
+ return false;
+ }
+ return true;
+ }
+
+
+//---------------------------------------------------------
+// jack_thread_init
+//---------------------------------------------------------
+
+static void jack_thread_init (void* ) // data
+ {
+ doSetuid();
+ /*
+ if (jackAudio->isRealtime()) {
+ struct sched_param rt_param;
+ int rv;
+ memset(&rt_param, 0, sizeof(sched_param));
+ int type;
+ rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
+ if (rv != 0)
+ perror("get scheduler parameter");
+ if (type != SCHED_FIFO) {
+ fprintf(stderr, "JACK thread not running SCHED_FIFO, try to set...\n");
+
+ memset(&rt_param, 0, sizeof(sched_param));
+ rt_param.sched_priority = 1;
+ rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
+ if (rv != 0)
+ perror("set realtime scheduler");
+ memset(&rt_param, 0, sizeof(sched_param));
+ rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
+ if (rv != 0)
+ perror("get scheduler parameter");
+ if (type != SCHED_FIFO)
+ fprintf(stderr, "JACK still not running FIFO !?!\n"
+ "======reliable RT operation not possible!!======\n");
+ else
+ fprintf(stderr, "JACK thread succesfully set to SCHED_FIFO\n");
+ }
+ }
+ */
+#ifdef VST_SUPPORT
+ if (loadVST)
+ fst_adopt_thread();
+#endif
+ undoSetuid();
+ }
+
+/*
+//---------------------------------------------------------
+// processAudio + Midi
+// JACK callback
+//---------------------------------------------------------
+void
+print_triplet(unsigned char *data)
+{
+ int a,b,c;
+ a = b = c = 0;
+ memcpy(&a, data, 1);
+ memcpy(&b, data+1, 1);
+ memcpy(&c, data+2, 1);
+ fprintf(stderr, "%x,%x,%x", a, b, c);
+}
+*/
+
+/*
+void handle_jack_midi_in_events(jack_nframes_t frames)
+{
+ char buf = 0;
+ int i,j;
+ jack_midi_event_t midi_event;
+ unsigned char t,n,v;
+
+ for(j = 0; j < JACK_MIDI_CHANNELS; j++){
+ void *midi_buffer_in = jack_port_get_buffer(midi_port_in[j], frames);
+ int event_count = jack_midi_get_event_count(midi_buffer_in);
+
+ for(i = 0; i < event_count; i++){
+ jack_midi_event_get(&midi_event, midi_buffer_in, i);
+ t = midi_event.buffer[0];
+ n = midi_event.buffer[1];
+ v = midi_event.buffer[2];
+ if(((*(midi_event.buffer) & 0xf0)) == 0x90){
+ fprintf(stderr, "jack-midi-in-event: ON_ time=%d %u ", midi_event.time,
+ midi_event.size);
+ print_triplet(midi_event.buffer);
+ fprintf(stderr, "\n");
+ }else if(((*(midi_event.buffer)) & 0xf0) == 0x80){
+ fprintf(stderr, "jack-midi-in-event: OFF time=%d %u ", midi_event.time,
+ midi_event.size);
+ print_triplet(midi_event.buffer);
+ fprintf(stderr, "\n");
+ }else{
+ fprintf(stderr, "jack-midi-in-event: ??? time=%d %u ", midi_event.time,
+ midi_event.size);
+ print_triplet(midi_event.buffer);
+ fprintf(stderr, "\n");
+ }
+ jack_midi_in_data[j].buffer[0] = t;
+ jack_midi_in_data[j].buffer[1] = n;
+ jack_midi_in_data[j].buffer[2] = v;
+ jack_midi_in_data[j].buffer[3] = 1;
+ fprintf(stderr, "handle_jack_midi_in_events() w\n");
+ write(jackmidi_pi[1], &buf, 1);
+ fprintf(stderr, "handle_jack_midi_in_events() wd\n");
+ }
+ }
+}
+
+void handle_jack_midi_out_events(jack_nframes_t frames)
+{
+ unsigned char *data;
+ void *port_buf;
+ int i,j,n,x;
+
+ //for(i = 0; i < JACK_MIDI_CHANNELS; i++){
+ for(i = 0; i < JACK_MIDI_CHANNELS; ++i){
+ // jack-midi-clear any old events
+ while(jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] == 2){
+ port_buf = jack_port_get_buffer(midi_port_out[i], frames);
+ jack_midi_clear_buffer(port_buf);
+ jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] = 0;
+ // point the take to the next slot
+ jack_midi_out_data[i].take++;
+ if(jack_midi_out_data[i].take >= JACK_MIDI_BUFFER_SIZE){
+ jack_midi_out_data[i].take = 0;
+ }
+ }
+ // check if any incoming midi-events from muse
+ if(jack_midi_out_data[i].give != jack_midi_out_data[i].take){
+
+ if(jack_midi_out_data[i].give > jack_midi_out_data[i].take){
+ n = jack_midi_out_data[i].give - jack_midi_out_data[i].take;
+ }else{
+ n = jack_midi_out_data[i].give +
+ (JACK_MIDI_BUFFER_SIZE - jack_midi_out_data[i].take);
+ }
+ port_buf = jack_port_get_buffer(midi_port_out[i], frames);
+ jack_midi_clear_buffer(port_buf);
+ // FIX: midi events has different sizes, compare note-on to
+ // program-change. We should first walk over the events
+ // counting the size.
+ //data = jack_midi_event_reserve(port_buf, 0, n*3);
+ //x = jack_midi_out_data[i].take;
+ //for(j = 0; j < n; j++){
+ // data[j*3+0] = jack_midi_out_data[i].buffer[x*4+0];
+ // data[j*3+1] = jack_midi_out_data[i].buffer[x*4+1];
+ // data[j*3+2] = jack_midi_out_data[i].buffer[x*4+2];
+ // after having copied the buffer over to the jack-buffer,
+ // mark the muses midi-out buffer as 'need-cleaning'
+ // jack_midi_out_data[i].buffer[x*4+3] = 2;
+ // x++;
+ // if(x >= JACK_MIDI_BUFFER_SIZE){
+ // x = 0;
+ // }
+ //}
+
+ x = jack_midi_out_data[i].take;
+ for(j = 0; j < n; ++j)
+ {
+ data = jack_midi_event_reserve(port_buf, 0, 3);
+ if(data == 0)
+ {
+ fprintf(stderr, "handle_jack_midi_out_events: buffer overflow, event lost\n");
+ // Can do no more processing. Just return.
+ return;
+ }
+ data[0] = jack_midi_out_data[i].buffer[x*4+0];
+ data[1] = jack_midi_out_data[i].buffer[x*4+1];
+ data[2] = jack_midi_out_data[i].buffer[x*4+2];
+ // after having copied the buffer over to the jack-buffer,
+ // mark the muses midi-out buffer as 'need-cleaning'
+ jack_midi_out_data[i].buffer[x*4+3] = 2;
+ x++;
+ if(x >= JACK_MIDI_BUFFER_SIZE){
+ x = 0;
+ }
+ }
+
+ }
+ }
+}
+*/
+
+//static int processAudio(jack_nframes_t frames, void*)
+int JackAudioDevice::processAudio(jack_nframes_t frames, void*)
+{
+ jackAudio->_frameCounter += frames;
+
+/// handle_jack_midi_in_events(frames);
+/// handle_jack_midi_out_events(frames);
+
+// if (JACK_DEBUG)
+// printf("processAudio - >>>>\n");
+ segmentSize = frames;
+ if (audio->isRunning())
+ audio->process((unsigned long)frames);
+ else {
+ if (debugMsg)
+ puts("jack calling when audio is disconnected!\n");
+ }
+// if (JACK_DEBUG)
+// printf("processAudio - <<<<\n");
+ return 0;
+}
+
+//---------------------------------------------------------
+// processSync
+// return TRUE (non-zero) when ready to roll.
+//---------------------------------------------------------
+
+static int processSync(jack_transport_state_t state, jack_position_t* pos, void*)
+ {
+ if (JACK_DEBUG)
+ printf("processSync()\n");
+
+ if(!useJackTransport.value())
+ return 1;
+
+ int audioState = Audio::STOP;
+ switch (state) {
+ case JackTransportStopped:
+ audioState = Audio::STOP;
+ break;
+ case JackTransportLooping:
+ case JackTransportRolling:
+ audioState = Audio::PLAY;
+ break;
+ case JackTransportStarting:
+ //printf("processSync JackTransportStarting\n");
+
+ audioState = Audio::START_PLAY;
+ break;
+ //case JackTransportNetStarting:
+ // FIXME: Quick and dirty hack to support both Jack-1 and Jack-2
+ // Really need a config check of version...
+ case 4:
+ //printf("processSync JackTransportNetStarting\n");
+
+ audioState = Audio::START_PLAY;
+ break;
+ }
+
+ unsigned frame = pos->frame;
+ //printf("processSync valid:%d frame:%d\n", pos->valid, frame);
+
+ // p3.3.23
+ //printf("Jack processSync() before audio->sync frame:%d\n", frame);
+ //return audio->sync(audioState, frame);
+ int rv = audio->sync(audioState, frame);
+ //printf("Jack processSync() after audio->sync frame:%d\n", frame);
+ return rv;
+ }
+
+//---------------------------------------------------------
+// timebase_callback
+//---------------------------------------------------------
+
+static void timebase_callback(jack_transport_state_t /* state */,
+ jack_nframes_t /* nframes */,
+ jack_position_t* pos,
+ int /* new_pos */,
+ void*)
+ {
+ //printf("Jack timebase_callback pos->frame:%u audio->tickPos:%d song->cpos:%d\n", pos->frame, audio->tickPos(), song->cpos());
+
+ // p3.3.27
+ //Pos p(pos->frame, false);
+ Pos p(extSyncFlag.value() ? audio->tickPos() : pos->frame, extSyncFlag.value() ? true : false);
+ // Can't use song pos - it is only updated every (slow) GUI heartbeat !
+ //Pos p(extSyncFlag.value() ? song->cpos() : pos->frame, extSyncFlag.value() ? true : false);
+
+ pos->valid = JackPositionBBT;
+ p.mbt(&pos->bar, &pos->beat, &pos->tick);
+ pos->bar++;
+ pos->beat++;
+ pos->bar_start_tick = Pos(pos->bar, 0, 0).tick();
+
+ //
+ // dummy:
+ //
+
+ // p3.3.26
+ //pos->beats_per_bar = 4;
+ //pos->beat_type = 4;
+ //pos->ticks_per_beat = 384;
+ //
+ /* // From example client transport.c :
+ float time_beats_per_bar = 4.0;
+ float time_beat_type = 0.25; // Huh? Inverted? From docs: "Time signature 'denominator'"
+ double time_ticks_per_beat = 1920.0; // Huh? Ticks per beat should be 24 etc. not 384 or 1920 etc. Otherwise it would be called 'frames_per_beat'.
+ double time_beats_per_minute = 120.0;
+ */
+ //
+ int z, n;
+ sigmap.timesig(p.tick(), z, n);
+ pos->beats_per_bar = z;
+ pos->beat_type = n;
+ //pos->ticks_per_beat = config.division;
+ pos->ticks_per_beat = 24;
+
+ int tempo = tempomap.tempo(p.tick());
+ pos->beats_per_minute = (60000000.0 / tempo) * tempomap.globalTempo()/100.0;
+ }
+
+//---------------------------------------------------------
+// processShutdown
+//---------------------------------------------------------
+
+static void processShutdown(void*)
+ {
+ if (JACK_DEBUG)
+ printf("processShutdown()\n");
+ //printf("processShutdown\n");
+ jackAudio->nullify_client();
+ audio->shutdown();
+
+ int c=0;
+ while(midiSeqRunning == true) {
+ if(c++ >10) {
+ fprintf(stderr, "sequencer still running, something is very wrong.\n");
+ break;
+ }
+ sleep(1);
+ }
+ delete jackAudio;
+ jackAudio=0;
+ audioDevice=0;
+ }
+
+//---------------------------------------------------------
+// jackError
+//---------------------------------------------------------
+
+static void jackError(const char *s)
+ {
+ //error->logError( "JACK ERROR: %s\n", s);
+ fprintf(stderr,"JACK ERROR: %s\n", s);
+ }
+
+//---------------------------------------------------------
+// noJackError
+//---------------------------------------------------------
+
+static void noJackError(const char* /* s */)
+ {
+ }
+
+//---------------------------------------------------------
+// JackAudioDevice
+//---------------------------------------------------------
+
+JackAudioDevice::JackAudioDevice(jack_client_t* cl, char* name)
+ : AudioDevice()
+ {
+ _frameCounter = 0;
+ //JackAudioDevice::jackStarted=false;
+ strcpy(jackRegisteredName, name);
+ _client = cl;
+ dummyState = Audio::STOP;
+ dummyPos = 0;
+ }
+
+//---------------------------------------------------------
+// ~JackAudioDevice
+//---------------------------------------------------------
+
+JackAudioDevice::~JackAudioDevice()
+ {
+ if (JACK_DEBUG)
+ printf("~JackAudioDevice()\n");
+ if (_client) {
+
+ /*
+ // p3.3.35
+ for(int i = 0; i < JACK_MIDI_CHANNELS; i++)
+ {
+ if(midi_port_in[i])
+ jack_port_unregister(_client, midi_port_in[i]);
+ if(midi_port_out[i])
+ jack_port_unregister(_client, midi_port_out[i]);
+ }
+ */
+
+ if (jack_client_close(_client)) {
+ //error->logError("jack_client_close() failed: %s\n", strerror(errno));
+ fprintf(stderr,"jack_client_close() failed: %s\n", strerror(errno));
+ }
+ }
+ if (JACK_DEBUG)
+ printf("~JackAudioDevice() after jack_client_close()\n");
+ }
+
+//---------------------------------------------------------
+// realtimePriority
+// return zero if not running realtime
+// can only be called if JACK client thread is already
+// running
+//---------------------------------------------------------
+
+int JackAudioDevice::realtimePriority() const
+ {
+ pthread_t t = jack_client_thread_id(_client);
+ int policy;
+ struct sched_param param;
+ memset(&param, 0, sizeof(param));
+ int rv = pthread_getschedparam(t, &policy, &param);
+ if (rv) {
+ perror("MusE: JackAudioDevice::realtimePriority: Error: Get jack schedule parameter");
+ return 0;
+ }
+ if (policy != SCHED_FIFO) {
+ printf("MusE: JackAudioDevice::realtimePriority: JACK is not running realtime\n");
+ return 0;
+ }
+ return param.sched_priority;
+ }
+
+/*
+//---------------------------------------------------------
+// getJackName()
+//---------------------------------------------------------
+
+char* JackAudioDevice::getJackName()
+ {
+ return jackRegisteredName;
+ }
+*/
+
+/*
+//---------------------------------------------------------
+// clientName()
+//---------------------------------------------------------
+
+const char* JackAudioDevice::clientName()
+{
+ //if(_client)
+ // return jack_get_client_name(_client);
+ //else
+ // return "MusE";
+ return jackRegisteredName;
+}
+*/
+
+//---------------------------------------------------------
+// initJackAudio
+// return true if JACK not found
+//---------------------------------------------------------
+
+bool initJackAudio()
+ {
+ /*
+ // p3.3.35
+ for(int i = 0; i < JACK_MIDI_CHANNELS; i++)
+ {
+ midi_port_in[i] = 0;
+ midi_port_out[i] = 0;
+ }
+ */
+
+ if (JACK_DEBUG)
+ printf("initJackAudio()\n");
+ if (debugMsg) {
+ fprintf(stderr,"initJackAudio()\n");
+ jack_set_error_function(jackError);
+ }
+ else
+ jack_set_error_function(noJackError);
+ doSetuid();
+
+ //jack_client_t* client = 0;
+ //int i = 0;
+ //char jackIdString[8];
+ //for (i = 0; i < 5; ++i) {
+ // sprintf(jackIdString, "MusE-%d", i+1);
+ //client = jack_client_new(jackIdString);
+ // client = jack_client_open(jackIdString, JackNoStartServer, 0);
+ // if (client)
+ // break;
+ // }
+ //if (i == 5)
+ // return true;
+ jack_status_t status;
+ jack_client_t* client = jack_client_open("MusE", JackNoStartServer, &status);
+ if (!client) {
+ if (status & JackServerStarted)
+ printf("jack server started...\n");
+ if (status & JackServerFailed)
+ printf("cannot connect to jack server\n");
+ if (status & JackServerError)
+ printf("communication with jack server failed\n");
+ if (status & JackShmFailure)
+ printf("jack cannot access shared memory\n");
+ if (status & JackVersionError)
+ printf("jack server has wrong version\n");
+ printf("cannot create jack client\n");
+ undoSetuid(); // p3.3.51
+ return true;
+ }
+
+ if (debugMsg)
+ fprintf(stderr, "initJackAudio(): client %s opened.\n", jack_get_client_name(client));
+ if (client) {
+ jack_set_error_function(jackError);
+ //jackAudio = new JackAudioDevice(client, jackIdString);
+ jackAudio = new JackAudioDevice(client, jack_get_client_name(client));
+ if (debugMsg)
+ fprintf(stderr, "initJackAudio(): registering client...\n");
+ jackAudio->registerClient();
+ sampleRate = jack_get_sample_rate(client);
+ segmentSize = jack_get_buffer_size(client);
+ jack_set_thread_init_callback(client, (JackThreadInitCallback) jack_thread_init, 0);
+ //jack_set_timebase_callback(client, 0, (JackTimebaseCallback) timebase_callback, 0);
+ }
+ undoSetuid();
+
+ /*
+ // setup midi input/output
+ //memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
+ //memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
+ if(client){
+ for(i = 0; i < JACK_MIDI_CHANNELS; i++)
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-in-%d", i+1);
+ midi_port_in[i] = jack_port_register(client, buf,
+ JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsInput, 0);
+ if(midi_port_in[i] == NULL){
+ fprintf(stderr, "failed to register jack-midi-in\n");
+ exit(-1);
+ }
+ snprintf(buf, 80, "muse-jack-midi-out-%d", i+1);
+ midi_port_out[i] = jack_port_register(client, buf,
+ JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsOutput, 0);
+ if(midi_port_out == NULL)
+ {
+ fprintf(stderr, "failed to register jack-midi-out\n");
+ exit(-1);
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "WARNING NO muse-jack midi connection\n");
+ }
+ */
+
+ if (client) {
+ audioDevice = jackAudio;
+ jackAudio->scanMidiPorts();
+ return false;
+ }
+ return true;
+ }
+
+static int bufsize_callback(jack_nframes_t n, void*)
+ {
+ printf("JACK: buffersize changed %d\n", n);
+ return 0;
+ }
+
+//---------------------------------------------------------
+// freewheel_callback
+//---------------------------------------------------------
+
+static void freewheel_callback(int starting, void*)
+ {
+ if (debugMsg || JACK_DEBUG)
+ printf("JACK: freewheel_callback: starting%d\n", starting);
+ audio->setFreewheel(starting);
+ }
+
+static int srate_callback(jack_nframes_t n, void*)
+ {
+ if (debugMsg || JACK_DEBUG)
+ printf("JACK: sample rate changed: %d\n", n);
+ return 0;
+ }
+
+//---------------------------------------------------------
+// registration_callback
+//---------------------------------------------------------
+
+static void registration_callback(jack_port_id_t, int, void*)
+{
+ if(debugMsg || JACK_DEBUG)
+ printf("JACK: registration changed\n");
+
+ audio->sendMsgToGui('R');
+}
+
+//---------------------------------------------------------
+// JackAudioDevice::registrationChanged
+// this is called from song in gui context triggered
+// by registration_callback()
+//---------------------------------------------------------
+
+void JackAudioDevice::registrationChanged()
+{
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::registrationChanged()\n");
+
+ // Rescan.
+ scanMidiPorts();
+ // Connect the Jack midi client ports to the device ports.
+ //connectJackMidiPorts();
+}
+
+//---------------------------------------------------------
+// JackAudioDevice::connectJackMidiPorts
+//---------------------------------------------------------
+
+void JackAudioDevice::connectJackMidiPorts()
+{
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::connectJackMidiPorts()\n");
+
+ for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i);
+ //if(!mjd)
+ MidiDevice* md = *i;
+ if(md->deviceType() != MidiDevice::JACK_MIDI)
+ continue;
+
+ void* port = md->clientPort();
+ if(md->rwFlags() & 1)
+ {
+ RouteList* rl = md->outRoutes();
+ for (iRoute r = rl->begin(); r != rl->end(); ++r)
+ connect(port, r->jackPort);
+ }
+ else
+ if(md->rwFlags() & 2)
+ {
+ RouteList* rl = md->inRoutes();
+ for (iRoute r = rl->begin(); r != rl->end(); ++r)
+ connect(r->jackPort, port);
+ }
+ }
+
+
+ /*
+ const char* type = JACK_DEFAULT_MIDI_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, 0);
+ for (const char** p = ports; p && *p; ++p)
+ {
+ jack_port_t* port = jack_port_by_name(_client, *p);
+ if(!port)
+ continue;
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf(" ignoring own port: %s\n", *p);
+ continue;
+ }
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+ strncpy(buffer, *p, nsz);
+ // Ignore the MusE Jack port.
+ //if(strncmp(buffer, "MusE", 4) == 0)
+ // continue;
+
+ if(debugMsg)
+ printf(" found port: %s ", buffer);
+
+ // If there are aliases for this port, use the first one - much better for identifying.
+ //char a1[nsz];
+ char a2[nsz];
+ char* aliases[2];
+ //aliases[0] = a1;
+ aliases[0] = buffer;
+ aliases[1] = a2;
+ // To disable aliases, just rem this line.
+ jack_port_get_aliases(port, aliases);
+ //int na = jack_port_get_aliases(port, aliases);
+ //char* namep = (na >= 1) ? aliases[0] : buffer;
+ char* namep = aliases[0];
+
+ if(debugMsg)
+ printf("alias: %s\n", aliases[0]);
+
+ //int flags = 0;
+ int pf = jack_port_flags(port);
+ // If Jack port can send data to us...
+ //if(pf & JackPortIsOutput)
+ // Mark as input capable.
+ // flags |= 2;
+ // If Jack port can receive data from us...
+ //if(pf & JackPortIsInput)
+ // Mark as output capable.
+ // flags |= 1;
+
+ //JackPort jp(0, QString(buffer), flags);
+ //portList.append(jp);
+
+ QString name(namep);
+
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::graphChanged %s\n", name.latin1());
+
+ for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
+ {
+ // Is it a Jack midi device?
+ MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*imd);
+ if(!mjd)
+ continue;
+
+ //if(dev->name() != name)
+ // continue;
+
+ // Is this port the one created for the Jack midi device?
+ if(!mjd->clientJackPort() || (mjd->clientJackPort() != port))
+ continue;
+
+ jack_port_t* devport = jack_port_by_name(_client, mjd->name().latin1());
+ if(!devport)
+ continue;
+
+ int ofl = mjd->openFlags();
+
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::graphChanged found MidiJackDevice:%s\n", mjd->name().latin1());
+
+ // Note docs say it can't be both input and output. src, dest
+ // If Jack port can receive data from us and we actually want to...
+ if((pf & JackPortIsOutput) && (ofl & 1))
+ {
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::graphChanged connecting MusE output\n");
+ audioDevice->connect(port, devport);
+ }
+ else
+ // If Jack port can send data to us and we actually want it...
+ if((pf & JackPortIsInput) && (ofl & 2))
+ {
+ if(JACK_DEBUG)
+ printf("JackAudioDevice::graphChanged connecting MusE input\n");
+ audioDevice->connect(devport, port);
+ }
+
+ break;
+ }
+ }
+
+ if(ports)
+ free(ports);
+
+ */
+}
+//---------------------------------------------------------
+// client_registration_callback
+//---------------------------------------------------------
+
+static void client_registration_callback(const char *name, int isRegister, void*)
+ {
+ if (debugMsg || JACK_DEBUG)
+ printf("JACK: client registration changed:%s register:%d\n", name, isRegister);
+ }
+
+//---------------------------------------------------------
+// port_connect_callback
+//---------------------------------------------------------
+
+static void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int isConnect, void*)
+ {
+ if (debugMsg || JACK_DEBUG)
+ {
+ //jack_port_t* ap = jack_port_by_id(_client, a);
+ //jack_port_t* bp = jack_port_by_id(_client, b);
+ //printf("JACK: port connections changed: A:%d:%s B:%d:%s isConnect:%d\n", a, jack_port_name(ap), b, jack_port_name(bp), isConnect);
+ printf("JACK: port connections changed: A:%d B:%d isConnect:%d\n", a, b, isConnect);
+ }
+ }
+
+//---------------------------------------------------------
+// graph_callback
+// this is called from jack when the connections
+// changed
+//---------------------------------------------------------
+
+static int graph_callback(void*)
+ {
+ if (JACK_DEBUG)
+ printf("graph_callback()\n");
+ // we cannot call JackAudioDevice::graphChanged() from this
+ // context, so we send a message to the gui thread which in turn
+ // calls graphChanged()
+ audio->sendMsgToGui('C');
+ if (debugMsg)
+ printf("JACK: graph changed\n");
+ return 0;
+ }
+
+//---------------------------------------------------------
+// JackAudioDevice::graphChanged
+// this is called from song in gui context triggered
+// by graph_callback()
+//---------------------------------------------------------
+
+void JackAudioDevice::graphChanged()
+{
+ if (JACK_DEBUG)
+ printf("graphChanged()\n");
+ if(!checkJackClient(_client)) return;
+ InputList* il = song->inputs();
+ for (iAudioInput ii = il->begin(); ii != il->end(); ++ii) {
+ AudioInput* it = *ii;
+ int channels = it->channels();
+ for (int channel = 0; channel < channels; ++channel) {
+ jack_port_t* port = (jack_port_t*)(it->jackPort(channel));
+ if (port == 0)
+ continue;
+ const char** ports = jack_port_get_all_connections(_client, port);
+ RouteList* rl = it->inRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0;i < 20;i++) {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ if (irl->channel != channel)
+ continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ //printf("portname=%s\n", portName);
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ //Route(portName, false, channel),
+ Route(portName, false, channel, Route::JACK_ROUTE),
+ Route(it, channel)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports) {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ if (irl->channel != channel)
+ continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ //Route(*pn, false, channel),
+ Route(*pn, false, channel, Route::JACK_ROUTE),
+ Route(it, channel)
+ );
+ }
+ ++pn;
+ }
+
+ // p3.3.37
+ //delete ports;
+ free(ports);
+
+ ports = NULL;
+ }
+ }
+ }
+ OutputList* ol = song->outputs();
+ for (iAudioOutput ii = ol->begin(); ii != ol->end(); ++ii) {
+ AudioOutput* it = *ii;
+ int channels = it->channels();
+ for (int channel = 0; channel < channels; ++channel) {
+ jack_port_t* port = (jack_port_t*)(it->jackPort(channel));
+ if (port == 0)
+ continue;
+ const char** ports = jack_port_get_all_connections(_client, port);
+ RouteList* rl = it->outRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0; i < 20 ; i++) {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ if (irl->channel != channel)
+ continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ Route(it, channel),
+ //Route(portName, false, channel)
+ Route(portName, false, channel, Route::JACK_ROUTE)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports) {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ if (irl->channel != channel)
+ continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ Route(it, channel),
+ //Route(*pn, false, channel)
+ Route(*pn, false, channel, Route::JACK_ROUTE)
+ );
+ }
+ ++pn;
+ }
+
+ // p3.3.37
+ //delete ports;
+ free(ports);
+
+ ports = NULL;
+ }
+ }
+ }
+
+ for (iMidiDevice ii = midiDevices.begin(); ii != midiDevices.end(); ++ii)
+ {
+ MidiDevice* md = *ii;
+ if(md->deviceType() != MidiDevice::JACK_MIDI)
+ continue;
+
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*ii);
+ //if(!mjd)
+ // continue;
+ //for (int channel = 0; channel < channels; ++channel)
+ //{
+ jack_port_t* port = (jack_port_t*)md->clientPort();
+ if (port == 0)
+ continue;
+ const char** ports = jack_port_get_all_connections(_client, port);
+
+ //---------------------------------------
+ // outputs
+ //---------------------------------------
+
+ if(md->rwFlags() & 1) // Writable
+ {
+ RouteList* rl = md->outRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0; i < 20 ; i++)
+ {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ //Route(it, channel),
+ //Route(mjd),
+ Route(md, -1),
+ //Route(portName, false, channel)
+ //Route(portName, false, -1)
+ Route(portName, false, -1, Route::JACK_ROUTE)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports)
+ {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ //Route(it, channel),
+ //Route(mjd),
+ Route(md, -1),
+ //Route(*pn, false, channel)
+ //Route(*pn, false, -1)
+ Route(*pn, false, -1, Route::JACK_ROUTE)
+ );
+ }
+ ++pn;
+ }
+
+ // p3.3.37
+ //delete ports;
+ //free(ports);
+
+ //ports = NULL;
+ }
+ }
+
+
+ //------------------------
+ // Inputs
+ //------------------------
+
+ if(md->rwFlags() & 2) // Readable
+ {
+ RouteList* rl = md->inRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0; i < 20 ; i++)
+ {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ //Route(portName, false, channel),
+ //Route(portName, false, -1),
+ Route(portName, false, -1, Route::JACK_ROUTE),
+ //Route(it, channel)
+ //Route(mjd)
+ Route(md, -1)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports)
+ {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ //Route(*pn, false, channel),
+ //Route(*pn, false, -1),
+ Route(*pn, false, -1, Route::JACK_ROUTE),
+ //Route(it, channel)
+ //Route(mjd)
+ Route(md, -1)
+ );
+ }
+ ++pn;
+ }
+ }
+ }
+ if(ports)
+ // Done with ports. Free them.
+ //delete ports;
+ free(ports);
+
+ ports = NULL;
+ }
+}
+
+//static int xrun_callback(void*)
+// {
+// printf("JACK: xrun\n");
+// return 0;
+// }
+
+//---------------------------------------------------------
+// register
+//---------------------------------------------------------
+
+void JackAudioDevice::registerClient()
+ {
+ if (JACK_DEBUG)
+ printf("registerClient()\n");
+ if(!checkJackClient(_client)) return;
+ jack_set_process_callback(_client, processAudio, 0);
+ jack_set_sync_callback(_client, processSync, 0);
+ // FIXME: FIXME:
+ // Added by Tim. p3.3.20
+ // Did not help. Seek during play: Jack keeps switching to STOP state after about 1-2 seconds timeout if sync is holding it up.
+ // Nothing in MusE seems to be telling it to stop.
+ jack_set_sync_timeout(_client, 5000000); // Change default 2 to 5 second sync timeout because prefetch may be very slow esp. with resampling !
+
+ jack_on_shutdown(_client, processShutdown, 0);
+ jack_set_buffer_size_callback(_client, bufsize_callback, 0);
+ jack_set_sample_rate_callback(_client, srate_callback, 0);
+ jack_set_port_registration_callback(_client, registration_callback, 0);
+ // p3.3.37
+ jack_set_client_registration_callback(_client, client_registration_callback, 0);
+ jack_set_port_connect_callback(_client, port_connect_callback, 0);
+
+ jack_set_graph_order_callback(_client, graph_callback, 0);
+// jack_set_xrun_callback(client, xrun_callback, 0);
+ jack_set_freewheel_callback (_client, freewheel_callback, 0);
+ }
+
+//---------------------------------------------------------
+// registerInPort
+//---------------------------------------------------------
+
+//void* JackAudioDevice::registerInPort(const char* name)
+void* JackAudioDevice::registerInPort(const char* name, bool midi)
+ {
+ if (JACK_DEBUG)
+ printf("registerInPort()\n");
+ if(!checkJackClient(_client)) return NULL;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ //void* p = jack_port_register(_client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+ void* p = jack_port_register(_client, name, type, JackPortIsInput, 0);
+// printf("JACK: registerInPort: <%s> %p\n", name, p);
+ return p;
+ }
+
+//---------------------------------------------------------
+// registerOutPort
+//---------------------------------------------------------
+
+//void* JackAudioDevice::registerOutPort(const char* name)
+void* JackAudioDevice::registerOutPort(const char* name, bool midi)
+ {
+ if (JACK_DEBUG)
+ printf("registerOutPort()\n");
+ if(!checkJackClient(_client)) return NULL;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ //void* p = jack_port_register(_client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ void* p = jack_port_register(_client, name, type, JackPortIsOutput, 0);
+// printf("JACK: registerOutPort: <%s> %p\n", name, p);
+ return p;
+ }
+
+//---------------------------------------------------------
+// exitJackAudio
+//---------------------------------------------------------
+
+void exitJackAudio()
+ {
+ if (JACK_DEBUG)
+ printf("exitJackAudio()\n");
+ if (jackAudio)
+ delete jackAudio;
+
+ if (JACK_DEBUG)
+ printf("exitJackAudio() after delete jackAudio\n");
+
+ // Added by Tim. p3.3.14
+ audioDevice = NULL;
+
+ }
+
+//---------------------------------------------------------
+// connect
+//---------------------------------------------------------
+
+void JackAudioDevice::connect(void* src, void* dst)
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::connect()\n");
+ if(!checkJackClient(_client)) return;
+ const char* sn = jack_port_name((jack_port_t*) src);
+ const char* dn = jack_port_name((jack_port_t*) dst);
+ if (sn == 0 || dn == 0) {
+ fprintf(stderr, "JackAudio::connect: unknown jack ports\n");
+ return;
+ }
+ int err = jack_connect(_client, sn, dn);
+ //if (jack_connect(_client, sn, dn)) {
+ if (err) {
+ fprintf(stderr, "jack connect <%s>%p - <%s>%p failed with err:%d\n",
+ sn, src, dn, dst, err);
+ }
+ else
+ if (JACK_DEBUG)
+ {
+ fprintf(stderr, "jack connect <%s>%p - <%s>%p succeeded\n",
+ sn, src, dn, dst);
+ }
+}
+
+//---------------------------------------------------------
+// disconnect
+//---------------------------------------------------------
+
+void JackAudioDevice::disconnect(void* src, void* dst)
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::disconnect()\n");
+ if(!checkJackClient(_client)) return;
+ const char* sn = jack_port_name((jack_port_t*) src);
+ const char* dn = jack_port_name((jack_port_t*) dst);
+ if (sn == 0 || dn == 0) {
+ fprintf(stderr, "JackAudio::disconnect: unknown jack ports\n");
+ return;
+ }
+ int err = jack_disconnect(_client, sn, dn);
+ //if (jack_disconnect(_client, sn, dn)) {
+ if (err) {
+ fprintf(stderr, "jack disconnect <%s> - <%s> failed with err:%d\n",
+ sn, dn, err);
+ }
+ else
+ if (JACK_DEBUG)
+ {
+ fprintf(stderr, "jack disconnect <%s> - <%s> succeeded\n",
+ sn, dn);
+ }
+}
+
+//---------------------------------------------------------
+// start
+//---------------------------------------------------------
+
+//void JackAudioDevice::start()
+void JackAudioDevice::start(int /*priority*/)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::start()\n");
+ if(!checkJackClient(_client)) return;
+
+ doSetuid();
+
+ if (jack_activate(_client)) {
+ undoSetuid(); // p3.3.51
+ fprintf (stderr, "JACK: cannot activate client\n");
+ exit(-1);
+ }
+ /* connect the ports. Note: you can't do this before
+ the client is activated, because we can't allow
+ connections to be made to clients that aren't
+ running.
+ */
+
+ InputList* il = song->inputs();
+ for (iAudioInput i = il->begin(); i != il->end(); ++i) {
+ AudioInput* ai = *i;
+ int channel = ai->channels();
+ for (int ch = 0; ch < channel; ++ch) {
+ RouteList* rl = ai->inRoutes();
+ void* port = ai->jackPort(ch);
+ for (iRoute ir = rl->begin(); ir != rl->end(); ++ir) {
+ if (ir->channel == ch)
+ connect(ir->jackPort, port);
+ }
+ }
+ }
+ OutputList* ol = song->outputs();
+ for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) {
+ AudioOutput* ai = *i;
+ int channel = ai->channels();
+ for (int ch = 0; ch < channel; ++ch) {
+ RouteList* rl = ai->outRoutes();
+ void* port = ai->jackPort(ch);
+ for (iRoute r = rl->begin(); r != rl->end(); ++r) {
+ if (r->channel == ch) {
+ connect(port, r->jackPort);
+ }
+ }
+ }
+ }
+
+ // p3.3.37
+ // Connect the Jack midi client ports to device ports.
+ connectJackMidiPorts();
+
+ undoSetuid();
+
+ //MUSE_DEBUG("JackAudioDevice::start()\n");
+ fflush(stdin);
+ //JackAudioDevice::jackStarted=true;
+ }
+
+//---------------------------------------------------------
+// stop
+//---------------------------------------------------------
+
+void JackAudioDevice::stop()
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::stop()\n");
+ if(!checkJackClient(_client)) return;
+ if (jack_deactivate(_client)) {
+ fprintf (stderr, "cannot deactivate client\n");
+ }
+ //JackAudioDevice::jackStarted=false;
+ }
+
+//---------------------------------------------------------
+// transportQuery
+//---------------------------------------------------------
+
+jack_transport_state_t JackAudioDevice::transportQuery(jack_position_t* pos)
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::transportQuery pos:%d\n", (unsigned int)pos->frame);
+
+ // TODO: Compose and return a state if MusE is disengaged from Jack transport.
+
+ return jack_transport_query(_client, pos);
+}
+
+//---------------------------------------------------------
+// getCurFrame
+//---------------------------------------------------------
+
+unsigned int JackAudioDevice::getCurFrame()
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::getCurFrame pos.frame:%d\n", pos.frame);
+
+ if(!useJackTransport.value())
+ return (unsigned int)dummyPos;
+
+ return pos.frame;
+}
+
+//---------------------------------------------------------
+// framePos
+//---------------------------------------------------------
+
+int JackAudioDevice::framePos() const
+ {
+ //if(!useJackTransport.value())
+ //{
+ // if (JACK_DEBUG)
+ // printf("JackAudioDevice::framePos dummyPos:%d\n", dummyPos);
+ // return dummyPos;
+ //}
+
+ if(!checkJackClient(_client)) return 0;
+ jack_nframes_t n = jack_frame_time(_client);
+
+ //if (JACK_DEBUG)
+ // printf("JackAudioDevice::framePos jack frame:%d\n", (int)n);
+
+ return (int)n;
+ }
+
+#if 0
+//---------------------------------------------------------
+// framesSinceCycleStart
+//---------------------------------------------------------
+
+int JackAudioDevice::framesSinceCycleStart() const
+ {
+ jack_nframes_t n = jack_frames_since_cycle_start(client);
+ return (int)n;
+ }
+
+//---------------------------------------------------------
+// framesDelay
+// TODO
+//---------------------------------------------------------
+
+int JackAudioDevice::frameDelay() const
+ {
+ jack_nframes_t n = (segmentSize * (segmentCount-1)) - jack_frames_since_cycle_start(client);
+ return (int)n;
+ }
+#endif
+
+//---------------------------------------------------------
+// outputPorts
+//---------------------------------------------------------
+
+std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::outputPorts()\n");
+ std::list<QString> clientList;
+ if(!checkJackClient(_client)) return clientList;
+ QString qname;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput);
+ for (const char** p = ports; p && *p; ++p) {
+ jack_port_t* port = jack_port_by_name(_client, *p);
+ //int flags = jack_port_flags(port);
+ //if (!(flags & JackPortIsOutput))
+ // continue;
+ //char buffer[128];
+
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+
+ strncpy(buffer, *p, nsz);
+ //if (strncmp(buffer, "MusE", 4) == 0)
+ //{
+ // if(debugMsg)
+ // printf("JackAudioDevice::outputPorts ignoring own MusE port: %s\n", *p);
+ // continue;
+ //}
+
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf("JackAudioDevice::outputPorts ignoring own port: %s\n", *p);
+ continue;
+ }
+
+ // p3.3.38
+ if((aliases == 0) || (aliases == 1))
+ {
+ //char a1[nsz];
+ char a2[nsz];
+ char* al[2];
+ //aliases[0] = a1;
+ al[0] = buffer;
+ al[1] = a2;
+ int na = jack_port_get_aliases(port, al);
+ int a = aliases;
+ if(a >= na)
+ {
+ a = na;
+ if(a > 0)
+ a--;
+ }
+ qname = QString(al[a]);
+ }
+ else
+ qname = QString(buffer);
+
+ //clientList.push_back(QString(buffer));
+ clientList.push_back(qname);
+ }
+
+ // p3.3.37
+ if(ports)
+ free(ports);
+
+ return clientList;
+ }
+
+//---------------------------------------------------------
+// inputPorts
+//---------------------------------------------------------
+
+std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::inputPorts()\n");
+ std::list<QString> clientList;
+ if(!checkJackClient(_client)) return clientList;
+ QString qname;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput);
+ for (const char** p = ports; p && *p; ++p) {
+ jack_port_t* port = jack_port_by_name(_client, *p);
+ //int flags = jack_port_flags(port);
+ //if (!(flags & JackPortIsInput))
+ // continue;
+ //char buffer[128];
+
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+
+ strncpy(buffer, *p, nsz);
+ //if (strncmp(buffer, "MusE", 4) == 0)
+ //{
+ // if(debugMsg)
+ // printf("JackAudioDevice::inputPorts ignoring own MusE port: %s\n", *p);
+ // continue;
+ //}
+
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf("JackAudioDevice::inputPorts ignoring own port: %s\n", *p);
+ continue;
+ }
+
+ // p3.3.38
+ if((aliases == 0) || (aliases == 1))
+ {
+ //char a1[nsz];
+ char a2[nsz];
+ char* al[2];
+ //aliases[0] = a1;
+ al[0] = buffer;
+ al[1] = a2;
+ int na = jack_port_get_aliases(port, al);
+ int a = aliases;
+ if(a >= na)
+ {
+ a = na;
+ if(a > 0)
+ a--;
+ }
+ qname = QString(al[a]);
+ }
+ else
+ qname = QString(buffer);
+
+ //clientList.push_back(QString(buffer));
+ clientList.push_back(qname);
+ }
+
+ // p3.3.37
+ if(ports)
+ free(ports);
+
+ return clientList;
+ }
+
+//---------------------------------------------------------
+// portName
+//---------------------------------------------------------
+
+QString JackAudioDevice::portName(void* port)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::portName(\n");
+ if(!checkJackClient(_client)) return "";
+ if (!port)
+ return "";
+
+ QString s(jack_port_name((jack_port_t*)port));
+ //printf("Jack::portName %p %s\n", port, s.latin1());
+ return s;
+ }
+
+//---------------------------------------------------------
+// unregisterPort
+//---------------------------------------------------------
+
+void JackAudioDevice::unregisterPort(void* p)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::unregisterPort(\n");
+ if(!checkJackClient(_client)) return;
+// printf("JACK: unregister Port\n");
+ jack_port_unregister(_client, (jack_port_t*)p);
+ }
+
+//---------------------------------------------------------
+// getState
+//---------------------------------------------------------
+
+int JackAudioDevice::getState()
+ {
+ // If we're not using Jack's transport, just return current state.
+ if(!useJackTransport.value())
+ {
+ //pos.valid = jack_position_bits_t(0);
+ //pos.frame = audio->pos().frame();
+ //return audio->getState();
+ //if (JACK_DEBUG)
+ // printf("JackAudioDevice::getState dummyState:%d\n", dummyState);
+ return dummyState;
+ }
+
+ //if (JACK_DEBUG)
+ // printf("JackAudioDevice::getState ()\n");
+ if(!checkJackClient(_client)) return 0;
+ transportState = jack_transport_query(_client, &pos);
+ //if (JACK_DEBUG)
+ // printf("JackAudioDevice::getState transportState:%d\n", transportState);
+
+ switch (transportState) {
+ case JackTransportStopped:
+ return Audio::STOP;
+ case JackTransportLooping:
+ case JackTransportRolling:
+ return Audio::PLAY;
+ case JackTransportStarting:
+ //printf("JackAudioDevice::getState JackTransportStarting\n");
+
+ return Audio::START_PLAY;
+ //case JackTransportNetStarting:
+ // FIXME: Quick and dirty hack to support both Jack-1 and Jack-2
+ // Really need a config check of version...
+ case 4:
+ //printf("JackAudioDevice::getState JackTransportNetStarting\n");
+
+ return Audio::START_PLAY;
+ break;
+ default:
+ return Audio::STOP;
+ }
+ }
+
+//---------------------------------------------------------
+// setFreewheel
+//---------------------------------------------------------
+
+void JackAudioDevice::setFreewheel(bool f)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::setFreewheel(\n");
+ if(!checkJackClient(_client)) return;
+// printf("JACK: setFreewheel %d\n", f);
+ jack_set_freewheel(_client, f);
+ }
+
+//---------------------------------------------------------
+// dummySync
+//---------------------------------------------------------
+
+bool JackAudioDevice::dummySync(int state)
+{
+ // Roughly segment time length.
+ //timespec ts = { 0, (1000000000 * segmentSize) / sampleRate }; // In nanoseconds.
+ unsigned int sl = (1000000 * segmentSize) / sampleRate; // In microseconds.
+
+ double ct = curTime();
+ // Wait for a default maximum of 5 seconds.
+ // Similar to how Jack is supposed to wait a default of 2 seconds for slow clients.
+ // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here.
+ while((curTime() - ct) < 5.0)
+ {
+ // Is MusE audio ready to roll?
+ if(audio->sync(state, dummyPos))
+ return true;
+
+ // Not ready. Wait a 'segment', try again...
+ //nanosleep(&ts, NULL);
+ usleep(sl); // usleep is supposed to be obsolete!
+ }
+
+ //if(JACK_DEBUG)
+ printf("JackAudioDevice::dummySync Sync timeout - audio not ready!\n");
+
+ return false;
+}
+
+//---------------------------------------------------------
+// startTransport
+//---------------------------------------------------------
+
+void JackAudioDevice::startTransport()
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::startTransport()\n");
+
+ // If we're not using Jack's transport, just pass PLAY and current frame along
+ // as if processSync was called.
+ if(!useJackTransport.value())
+ {
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready to roll?
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ // MusE audio is ready to roll. Let's play.
+ dummyState = Audio::PLAY;
+ return;
+ }
+
+ // Ready or not, we gotta roll. Similar to how Jack is supposed to roll anyway.
+ dummyState = Audio::PLAY;
+ return;
+ }
+
+ if(!checkJackClient(_client)) return;
+// printf("JACK: startTransport\n");
+ jack_transport_start(_client);
+ }
+
+//---------------------------------------------------------
+// stopTransport
+//---------------------------------------------------------
+
+void JackAudioDevice::stopTransport()
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::stopTransport()\n");
+
+ dummyState = Audio::STOP;
+
+ if(!useJackTransport.value())
+ {
+ //dummyState = Audio::STOP;
+ return;
+ }
+
+ if(!checkJackClient(_client)) return;
+ if (transportState != JackTransportStopped) {
+ // printf("JACK: stopTransport\n");
+ jack_transport_stop(_client);
+ transportState=JackTransportStopped;
+ }
+ }
+
+//---------------------------------------------------------
+// seekTransport
+//---------------------------------------------------------
+
+void JackAudioDevice::seekTransport(unsigned frame)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::seekTransport() frame:%d\n", frame);
+
+ dummyPos = frame;
+ if(!useJackTransport.value())
+ {
+ // If we're not using Jack's transport, just pass the current state and new frame along
+ // as if processSync was called.
+ //dummyPos = frame;
+ int tempState = dummyState;
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready yet?
+ //audio->sync(dummyState, dummyPos);
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ dummyState = tempState;
+ return;
+ }
+
+ // Not ready, resume previous state anyway.
+ // FIXME: Observed: Seek during play: Jack transport STOPs on timeout.
+ // Docs say when starting play, transport will roll anyway, ready or not (observed),
+ // but don't mention what should happen on seek during play.
+ // And setting the slow-sync timeout doesn't seem to do anything!
+ //dummyState = tempState;
+ dummyState = Audio::STOP;
+ return;
+ }
+
+ if(!checkJackClient(_client)) return;
+// printf("JACK: seekTransport %d\n", frame);
+ jack_transport_locate(_client, frame);
+ }
+
+//---------------------------------------------------------
+// seekTransport
+//---------------------------------------------------------
+
+void JackAudioDevice::seekTransport(const Pos &p)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame());
+
+ dummyPos = p.frame();
+ if(!useJackTransport.value())
+ {
+ // If we're not using Jack's transport, just pass the current state and new frame along
+ // as if processSync was called.
+ //dummyPos = p.frame();
+ int tempState = dummyState;
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready yet?
+ //audio->sync(dummyState, dummyPos);
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ dummyState = tempState;
+ return;
+ }
+
+ // Not ready, resume previous state anyway.
+ // FIXME: See fixme in other seekTransport...
+ //dummyState = tempState;
+ dummyState = Audio::STOP;
+ return;
+ }
+
+ if(!checkJackClient(_client)) return;
+
+ /*
+ jack_position_t jp;
+ jp.valid = JackPositionBBT;
+ p.mbt(&jp.bar, &jp.beat, &jp.tick);
+ jp.bar++;
+ jp.beat++;
+ jp.bar_start_tick = Pos(jp.bar, 0, 0).tick();
+ //
+ // dummy:
+ //
+ jp.beats_per_bar = 4;
+ jp.beat_type = 4;
+ jp.ticks_per_beat = 384;
+ int tempo = tempomap.tempo(p.tick());
+ jp.beats_per_minute = (60000000.0 / tempo) * tempomap.globalTempo()/100.0;
+
+ jack_transport_reposition(_client, &jp);
+ */
+ jack_transport_locate(_client, p.frame());
+ }
+
+//---------------------------------------------------------
+// findPort
+//---------------------------------------------------------
+
+void* JackAudioDevice::findPort(const char* name)
+ {
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::findPort(\n");
+ if(!checkJackClient(_client)) return NULL;
+ void* p = jack_port_by_name(_client, name);
+// printf("Jack::findPort <%s>, %p\n", name, p);
+ return p;
+ }
+
+//---------------------------------------------------------
+// setMaster
+//---------------------------------------------------------
+
+int JackAudioDevice::setMaster(bool f)
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::setMaster val:%d\n", f);
+ if(!checkJackClient(_client))
+ return 0;
+
+ int r = 0;
+ if(f)
+ {
+ if(useJackTransport.value())
+ {
+ // Make Muse the Jack timebase master. Do it unconditionally (second param = 0).
+ r = jack_set_timebase_callback(_client, 0, (JackTimebaseCallback) timebase_callback, 0);
+ if(debugMsg || JACK_DEBUG)
+ {
+ if(r)
+ printf("JackAudioDevice::setMaster jack_set_timebase_callback failed: result:%d\n", r);
+ }
+ }
+ else
+ {
+ r = 1;
+ printf("JackAudioDevice::setMaster cannot set master because useJackTransport is false\n");
+ }
+ }
+ else
+ {
+ r = jack_release_timebase(_client);
+ if(debugMsg || JACK_DEBUG)
+ {
+ if(r)
+ printf("JackAudioDevice::setMaster jack_release_timebase failed: result:%d\n", r);
+ }
+ }
+ return r;
+}
+
+//---------------------------------------------------------
+// scanMidiPorts
+//---------------------------------------------------------
+
+void JackAudioDevice::scanMidiPorts()
+{
+ if(debugMsg)
+ printf("JackAudioDevice::scanMidiPorts:\n");
+
+/*
+ const char* type = JACK_DEFAULT_MIDI_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, 0);
+
+ std::set<std::string> names;
+ for (const char** p = ports; p && *p; ++p)
+ {
+ jack_port_t* port = jack_port_by_name(_client, *p);
+ if(!port)
+ continue;
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf(" ignoring own port: %s\n", *p);
+ continue;
+ }
+
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+ strncpy(buffer, *p, nsz);
+ // Ignore the MusE Jack port.
+ //if(strncmp(buffer, "MusE", 4) == 0)
+ // continue;
+
+ if(debugMsg)
+ printf(" found port: %s ", buffer);
+
+ // If there are aliases for this port, use the first one - much better for identifying.
+ //char a1[nsz];
+ char a2[nsz];
+ char* aliases[2];
+ //aliases[0] = a1;
+ aliases[0] = buffer;
+ aliases[1] = a2;
+ // To disable aliases, just rem this line.
+ jack_port_get_aliases(port, aliases);
+ //int na = jack_port_get_aliases(port, aliases);
+ //char* namep = (na >= 1) ? aliases[0] : buffer;
+ //char* namep = aliases[0];
+ //names.insert(std::string(*p));
+ if(debugMsg)
+ printf("alias: %s\n", aliases[0]);
+
+ names.insert(std::string(aliases[0]));
+ }
+ if(ports)
+ free(ports);
+
+ std::list<MidiDevice*> to_del;
+ for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
+ {
+ // Only Jack midi devices.
+ if(dynamic_cast<MidiJackDevice*>(*imd) == 0)
+ continue;
+ if(names.find(std::string((*imd)->name().latin1())) == names.end())
+ to_del.push_back(*imd);
+ }
+
+ for(std::list<MidiDevice*>::iterator imd = to_del.begin(); imd != to_del.end(); ++imd)
+ {
+ if(debugMsg)
+ printf(" removing port device:%s\n", (*imd)->name().latin1());
+ midiDevices.remove(*imd);
+ // This will close (and unregister) the client port.
+ delete (*imd);
+ }
+
+ //for (const char** p = ports; p && *p; ++p)
+ for(std::set<std::string>::iterator is = names.begin(); is != names.end(); ++is)
+ {
+ //jack_port_t* port = jack_port_by_name(_client, *p);
+ jack_port_t* port = jack_port_by_name(_client, is->c_str());
+ if(!port)
+ continue;
+*/
+
+ /*
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+ //strncpy(buffer, *p, nsz);
+ strncpy(buffer, is->c_str(), nsz);
+ // Ignore the MusE Jack port.
+ //if(strncmp(buffer, "MusE", 4) == 0)
+ // continue;
+
+ // If there are aliases for this port, use the first one - much better for identifying.
+ //char a1[nsz];
+ char a2[nsz];
+ char* aliases[2];
+ //aliases[0] = a1;
+ aliases[0] = buffer;
+ aliases[1] = a2;
+ // To disable aliases, just rem this line.
+ jack_port_get_aliases(port, aliases);
+ //int na = jack_port_get_aliases(port, aliases);
+ //char* namep = (na >= 1) ? aliases[0] : buffer;
+ char* namep = aliases[0];
+ QString qname(namep);
+ */
+
+/*
+ QString qname(is->c_str());
+
+ // Port already exists?
+ if(midiDevices.find(qname))
+ continue;
+
+ int flags = 0;
+ int pf = jack_port_flags(port);
+ // If Jack port can send data to us...
+ if(pf & JackPortIsOutput)
+ // Mark as input capable.
+ flags |= 2;
+ // If Jack port can receive data from us...
+ if(pf & JackPortIsInput)
+ // Mark as output capable.
+ flags |= 1;
+
+ //JackPort jp(0, QString(buffer), flags);
+ //portList.append(jp);
+
+ if(debugMsg)
+ printf(" adding port device:%s\n", qname.latin1());
+
+ MidiJackDevice* dev = new MidiJackDevice(0, qname);
+ dev->setrwFlags(flags);
+ midiDevices.add(dev);
+ }
+*/
+}
+
diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h
new file mode 100644
index 00000000..d3132efe
--- /dev/null
+++ b/muse2/muse/driver/jackaudio.h
@@ -0,0 +1,97 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: jackaudio.h,v 1.20.2.4 2009/12/20 05:00:35 terminator356 Exp $
+// (C) Copyright 2002 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __JACKAUDIO_H__
+#define __JACKAUDIO_H__
+
+#include <jack/jack.h>
+#include "audiodev.h"
+
+class MidiPlayEvent;
+
+//---------------------------------------------------------
+// JackAudioDevice
+//---------------------------------------------------------
+bool checkAudioDevice();
+
+class JackAudioDevice : public AudioDevice {
+
+ jack_client_t* _client;
+ double sampleTime;
+ int samplePos;
+ jack_transport_state_t transportState;
+ jack_position_t pos;
+ char jackRegisteredName[16];
+ int dummyState;
+ int dummyPos;
+ // Free-running frame counter incremented always in process.
+ jack_nframes_t _frameCounter;
+
+ static int processAudio(jack_nframes_t frames, void*);
+
+ public:
+ JackAudioDevice(jack_client_t* cl, char * jack_id_string);
+ virtual ~JackAudioDevice();
+ virtual void nullify_client() { _client = 0; }
+
+ virtual inline int deviceType() { return JACK_AUDIO; } // p3.3.52
+
+ void scanMidiPorts();
+
+ //virtual void start();
+ virtual void start(int);
+ virtual void stop ();
+ virtual bool dummySync(int state); // Artificial sync when not using Jack transport.
+
+ virtual int framePos() const;
+ virtual unsigned frameTime() const { return _frameCounter; }
+
+ virtual float* getBuffer(void* port, unsigned long nframes) {
+ return (float*)jack_port_get_buffer((jack_port_t*)port, nframes);
+ }
+
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1);
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);
+
+ virtual void registerClient();
+ virtual const char* clientName() { return jackRegisteredName; }
+
+ //virtual void* registerOutPort(const char* name);
+ //virtual void* registerInPort(const char* name);
+ virtual void* registerOutPort(const char* /*name*/, bool /*midi*/);
+ virtual void* registerInPort(const char* /*name*/, bool /*midi*/);
+
+ //virtual char* getJackName();
+
+ virtual void unregisterPort(void*);
+ virtual void connect(void*, void*);
+ virtual void disconnect(void*, void*);
+ virtual int connections(void* clientPort) { return jack_port_connected((jack_port_t*)clientPort); }
+ virtual void setPortName(void* p, const char* n) { jack_port_set_name((jack_port_t*)p, n); }
+ virtual void* findPort(const char* name);
+ virtual QString portName(void* port);
+ virtual int getState();
+ virtual unsigned int getCurFrame();
+ virtual bool isRealtime() { return jack_is_realtime(_client); }
+ virtual int realtimePriority() const;
+ virtual void startTransport();
+ virtual void stopTransport();
+ virtual void seekTransport(unsigned frame);
+ virtual void seekTransport(const Pos &p);
+ virtual void setFreewheel(bool f);
+ jack_transport_state_t transportQuery(jack_position_t* pos);
+ void graphChanged();
+ void registrationChanged();
+ void connectJackMidiPorts();
+
+ virtual int setMaster(bool f);
+
+ //static bool jackStarted;
+ };
+
+#endif
+
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
new file mode 100644
index 00000000..4e871a2f
--- /dev/null
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -0,0 +1,1563 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: jackmidi.cpp,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $
+// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
+//=========================================================
+
+//#include <qt.h>
+#include <qstring.h>
+#include <stdio.h>
+
+#include <jack/jack.h>
+//#include <jack/midiport.h>
+
+#include "jackmidi.h"
+#include "song.h"
+#include "globals.h"
+#include "midi.h"
+#include "mididev.h"
+#include "../midiport.h"
+#include "../midiseq.h"
+#include "../midictrl.h"
+#include "../audio.h"
+#include "mpevent.h"
+//#include "sync.h"
+#include "audiodev.h"
+#include "../mplugins/midiitransform.h"
+#include "../mplugins/mitplugin.h"
+#include "xml.h"
+
+// Turn on debug messages.
+//#define JACK_MIDI_DEBUG
+
+extern unsigned int volatile lastExtMidiSyncTick;
+
+///int jackmidi_pi[2];
+///int jackmidi_po[2];
+
+//extern muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS];
+//extern muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS];
+///extern jack_port_t *midi_port_in[JACK_MIDI_CHANNELS];
+///extern jack_port_t *midi_port_out[JACK_MIDI_CHANNELS];
+
+///MidiJackDevice* gmdev = NULL;
+
+///int* jackSeq;
+//static snd_seq_addr_t musePort;
+
+//int MidiJackDevice::_nextOutIdNum = 0;
+//int MidiJackDevice::_nextInIdNum = 0;
+
+//int JackMidiPortList::_nextOutIdNum = 0;
+//int JackMidiPortList::_nextInIdNum = 0;
+
+//JackMidiPortList jackMidiClientPorts;
+
+
+/*
+//---------------------------------------------------------
+// JackMidiPortList
+//---------------------------------------------------------
+
+JackMidiPortList::JackMidiPortList()
+{
+
+}
+
+JackMidiPortList::~JackMidiPortList()
+{
+
+}
+
+iJackMidiPort JackMidiPortList::createClientPort(int flags) // 1 = writable, 2 = readable - do not mix
+{
+ if(flags & 1)
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
+ jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-out\n");
+ //return QString("Could not register jack-midi-out client port");
+ return end();
+ }
+ else
+ {
+ JackMidiPort jmp(_client_jackport, QString(buf), flags);
+ _nextOutIdNum++;
+ return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
+ }
+ }
+ else
+ if(flags & 2)
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
+ jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-in\n");
+ return end();
+ }
+ else
+ {
+ JackMidiPort jmp(_client_jackport, QString(buf), flags);
+ _nextInIdNum++;
+ return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
+ }
+ }
+ return end();
+}
+
+// Return true if removed.
+bool JackMidiPortList::removeClientPort(jack_port_t* port)
+{
+ iJackMidiPort ijp = find(port);
+ if(ijp == end())
+ return false;
+
+ // Is output?
+ if(ijp->second._flags & 1)
+ _nextOutIdNum--;
+ // Is input?
+ if(ijp->second._flags & 2)
+ _nextInIdNum--;
+
+ erase(ijp);
+
+ audioDevice->unregisterPort(port);
+
+ return true;
+}
+*/
+
+//---------------------------------------------------------
+// MidiJackDevice
+//---------------------------------------------------------
+
+//MidiJackDevice::MidiJackDevice(const int& a, const QString& n)
+MidiJackDevice::MidiJackDevice(jack_port_t* jack_port, const QString& n)
+ : MidiDevice(n)
+{
+ //_client_jackport = 0;
+ _client_jackport = jack_port;
+ //adr = a;
+ init();
+}
+
+MidiJackDevice::~MidiJackDevice()
+{
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::~MidiJackDevice()\n");
+ #endif
+ if(_client_jackport)
+ audioDevice->unregisterPort(_client_jackport);
+ //close();
+}
+
+/*
+//---------------------------------------------------------
+// select[RW]fd
+//---------------------------------------------------------
+
+int MidiJackDevice::selectRfd()
+{
+ return jackmidi_pi[0];
+}
+
+int MidiJackDevice::selectWfd()
+{
+ return jackmidi_po[0];
+}
+*/
+
+//---------------------------------------------------------
+// createJackMidiDevice
+// If name parameter is blank, creates a new (locally) unique one.
+//---------------------------------------------------------
+
+//QString MidiJackDevice::createJackMidiDevice(int rwflags) // 1:Writable 2: Readable. Do not mix.
+MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable. Do not mix.
+{
+/// _openFlags &= _rwFlags; // restrict to available bits
+
+/// #ifdef JACK_MIDI_DEBUG
+/// printf("MidiJackDevice::open %s\n", name.latin1());
+/// #endif
+
+ //jack_port_t* jp = jack_port_by_name(_client, name().latin1());
+/// jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
+
+/// if(!jp)
+/// {
+/// printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().latin1());
+/// _writeEnable = false;
+/// _readEnable = false;
+/// return QString("Jack midi port not found");
+/// }
+
+/// int pf = jack_port_flags(jp);
+
+ //if(!name.isEmpty())
+ //{
+ // Does not work.
+ // if(audioDevice->findPort(name.latin1()))
+ // {
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Given port name %s already exists!\n", name.latin1());
+ // return 0;
+ // }
+ //}
+
+ jack_port_t* client_jackport = NULL;
+ //char buf[80];
+
+
+ // If Jack port can receive data from us and we actually want to...
+ //if((pf & JackPortIsInput) && (_openFlags & 1))
+ if(rwflags & 1)
+ {
+ if(name.isEmpty())
+ {
+ //snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
+ for(int i = 0; ; ++i)
+ {
+ //snprintf(buf, 80, "midi-out-%d", i);
+ name.sprintf("midi-out-%d", i);
+
+ if(!midiDevices.find(name))
+ {
+ // Does not work.
+ //if(!audioDevice->findPort(buf))
+ // break;
+ //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(client_jackport)
+ break;
+ }
+ else
+ break;
+ }
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
+ return 0;
+ }
+ }
+ //name = QString(buf);
+ }
+ else
+ {
+ if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.latin1());
+ return 0;
+ }
+ }
+ }
+ /*
+ else
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ for(int i = 0; ; ++i)
+ {
+ snprintf(buf, 80, "midi-out-%d", i);
+ // Does not work!
+ //if(!audioDevice->findPort(buf))
+ // break;
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(client_jackport)
+ break;
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
+ return 0;
+ }
+ }
+ name = QString(buf);
+ }
+ }
+ */
+
+ //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ //if(client_jackport == NULL)
+ //{
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client output port %s\n", name.latin1());
+ // return 0;
+ //}
+ //else
+ // _nextOutIdNum++;
+
+ }
+ else // Note docs say it can't be both input and output.
+ // If Jack port can send data to us and we actually want it...
+ //if((pf & JackPortIsOutput) && (_openFlags & 2))
+ if(rwflags & 2)
+ {
+ if(name.isEmpty())
+ {
+ //snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
+ for(int i = 0; ; ++i)
+ {
+ //snprintf(buf, 80, "midi-in-%d", i);
+ name.sprintf("midi-in-%d", i);
+
+ if(!midiDevices.find(name))
+ {
+ // Does not work.
+ //if(!audioDevice->findPort(buf))
+ // break;
+ //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
+ if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+ if(client_jackport)
+ break;
+ }
+ else
+ break;
+ }
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused input port name!\n");
+ return 0;
+ }
+ }
+ //name = QString(buf);
+ }
+ else
+ {
+ if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.latin1());
+ return 0;
+ }
+ }
+ }
+
+ //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+
+ //if(client_jackport == NULL)
+ //{
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client input port %s\n", name.latin1());
+ //_readEnable = false;
+ //return QString("Could not register jack-midi-in client port");
+ // return 0;
+ //}
+ //else
+ // _nextInIdNum++;
+
+ }
+
+ //if(client_jackport == NULL) // p3.3.52 Removed. Allow the device to be created even if Jack isn't running.
+ // return 0;
+
+ MidiJackDevice* dev = new MidiJackDevice(client_jackport, name);
+ dev->setrwFlags(rwflags);
+ midiDevices.add(dev);
+ return dev;
+}
+
+//---------------------------------------------------------
+// setName
+//---------------------------------------------------------
+
+void MidiJackDevice::setName(const QString& s)
+{
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::setName %s new name:%s\n", name().latin1(), s.latin1());
+ #endif
+ _name = s;
+ if(clientPort()) // p3.3.52 Added check.
+ audioDevice->setPortName(clientPort(), s.latin1());
+}
+
+//---------------------------------------------------------
+// open
+//---------------------------------------------------------
+
+QString MidiJackDevice::open()
+{
+ _openFlags &= _rwFlags; // restrict to available bits
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::open %s\n", name().latin1());
+ #endif
+
+ /*
+ //jack_port_t* jp = jack_port_by_name(_client, name().latin1());
+ jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
+
+ if(!jp)
+ {
+ printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().latin1());
+ _writeEnable = false;
+ _readEnable = false;
+ return QString("Jack midi port not found");
+ }
+
+ int pf = jack_port_flags(jp);
+
+ // If Jack port can receive data from us and we actually want to...
+ if((pf & JackPortIsInput) && (_openFlags & 1))
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
+ _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-out\n");
+ _writeEnable = false;
+ return QString("Could not register jack-midi-out client port");
+ }
+ else
+ {
+ _nextOutIdNum++;
+ // src, dest
+ ///audioDevice->connect(_client_jackport, jp);
+ _writeEnable = true;
+ }
+ }
+ else // Note docs say it can't be both input and output.
+ // If Jack port can send data to us and we actually want it...
+ if((pf & JackPortIsOutput) && (_openFlags & 2))
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
+ _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-in\n");
+ _readEnable = false;
+ return QString("Could not register jack-midi-in client port");
+ }
+ else
+ {
+ _nextInIdNum++;
+ ///audioDevice->connect(jp, _client_jackport);
+ _readEnable = true;
+ }
+ }
+ */
+
+ _writeEnable = bool(_openFlags & 1);
+ _readEnable = bool(_openFlags & 2);
+
+ return QString("OK");
+}
+
+//---------------------------------------------------------
+// close
+//---------------------------------------------------------
+
+void MidiJackDevice::close()
+{
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::close %s\n", name().latin1());
+ #endif
+
+ /*
+ if(_client_jackport)
+ {
+ int pf = jack_port_flags(_client_jackport);
+
+ if(pf & JackPortIsOutput)
+ _nextOutIdNum--;
+ else
+ if(pf & JackPortIsInput)
+ _nextInIdNum--;
+ audioDevice->unregisterPort(_client_jackport);
+ _client_jackport = 0;
+ _writeEnable = false;
+ _readEnable = false;
+ return;
+ }
+ */
+
+ _writeEnable = false;
+ _readEnable = false;
+
+ /*
+ //jack_port_t* jp = jack_port_by_name(_client, name().latin1());
+ jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
+
+ if(!jp)
+ {
+ printf("MidiJackDevice::close: Jack midi port %s not found!\n", name().latin1());
+ _writeEnable = false;
+ _readEnable = false;
+ return;
+ }
+
+ //int pf = jack_port_flags(jp);
+
+ // If Jack port can receive data from us and we actually want to...
+ //if((pf & JackPortIsInput) && (_openFlags & 1))
+ if(jack_port_connected_to(midi_port_out[0], name().latin1()))
+ {
+ // src, dest
+/// audioDevice->disconnect(midi_port_out[0], jp);
+ _writeEnable = false;
+ }
+ else // Note docs say it can't be both input and output.
+ // If Jack port can send data to us and we actually want it...
+ //if((pf & JackPortIsOutput) && (_openFlags & 2))
+ if(jack_port_connected_to(midi_port_in[0], name().latin1()))
+ {
+/// audioDevice->disconnect(jp, midi_port_in[0]);
+ _readEnable = false;
+ }
+ */
+}
+
+//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void MidiJackDevice::writeRouting(int level, Xml& xml) const
+{
+ // p3.3.45
+ // If this device is not actually in use by the song, do not write any routes.
+ // This prevents bogus routes from being saved and propagated in the med file.
+ if(midiPort() == -1)
+ return;
+
+ QString s;
+ if(rwFlags() & 2) // Readable
+ {
+ //RouteList* rl = _inRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", r->name());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ s = QT_TR_NOOP("source");
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+
+ //s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name()));
+ xml.tag(level, s);
+
+ //xml.strTag(level, "dstNode", name());
+ //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ //xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1());
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+
+ //xml.tag(level++, "Route");
+ xml.tag(level++, s);
+
+ /*
+ //xml.strTag(level, "srcNode", name());
+ if(r->channel != -1)
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, r->channel, name().latin1());
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, r->channel, name().latin1());
+ else
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ */
+ //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).latin1());
+
+ /*
+ //xml.strTag(level, "dstNode", r->name());
+ if(r->channel != -1)
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1());
+ }
+ else
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ }
+ */
+
+ s = QT_TR_NOOP("dest");
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType());
+ else
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+
+ //s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(Xml::xmlString(r->name()));
+ xml.tag(level, s);
+
+
+ xml.etag(level--, "Route");
+ }
+ }
+
+ /*
+ else
+ if(rwFlags() & 1) // Writable
+ {
+ //RouteList* rl = _outRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", name());
+ //if(r->channel != -1)
+ // xml.tag(level, "srcNode type=\"%d\" channel=\"%d\" name=\"%s\"", Route::JACK_MIDI_ROUTE, r->channel, name().latin1());
+ //else
+ xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+
+ //xml.strTag(level, "dstNode", r->name());
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ */
+}
+
+//---------------------------------------------------------
+// putEvent
+//---------------------------------------------------------
+
+/* FIX: if we fail to transmit the event,
+ * we return false (indicating OK). Otherwise
+ * it seems muse will retry forever
+ */
+bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& /*event*/)
+{
+ /*
+ int give, channel = event.channel();
+ int x;
+
+ if(channel >= JACK_MIDI_CHANNELS) return false;
+
+ // buffer up events, because jack eats them in chunks, if
+ // the buffer is full, there isn't so much to do, than
+ // drop the event
+
+ give = jack_midi_out_data[channel].give;
+ if(jack_midi_out_data[channel].buffer[give*4+3]){
+ fprintf(stderr, "WARNING: muse-to-jack midi-buffer is full, channel=%u\n", channel);
+ return false;
+ }
+ // copy event(note-on etc..), pitch and volume
+ // see http://www.midi.org/techspecs/midimessages.php
+ switch(event.type()){
+ case ME_NOTEOFF:
+ jack_midi_out_data[channel].buffer[give*4+0] = 0x80;
+ jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
+ jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
+ break;
+ case ME_NOTEON:
+ jack_midi_out_data[channel].buffer[give*4+0] = 0x90;
+ jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
+ jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
+ break;
+ case ME_CONTROLLER:
+ jack_midi_out_data[channel].buffer[give*4+0] = 0xb0;
+ jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
+ jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
+ break;
+ case ME_PROGRAM:
+ jack_midi_out_data[channel].buffer[give*4+0] = 0xc0;
+ jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
+ jack_midi_out_data[channel].buffer[give*4+2] = 0;
+ break;
+ case ME_PITCHBEND:
+ jack_midi_out_data[channel].buffer[give*4+0] = 0xE0;
+ // convert muse pitch-bend to midi standard
+ x = 0x2000 + event.dataA();
+ jack_midi_out_data[channel].buffer[give*4+1] = x & 0x7f;
+ jack_midi_out_data[channel].buffer[give*4+2] = (x >> 8) & 0x7f;
+ break;
+ default:
+ fprintf(stderr, "jack-midi-out %u WARNING: unknown event %x\n", channel, event.type());
+ return false;
+ }
+ jack_midi_out_data[channel].buffer[give*4+3] = 1; // mark state of this slot
+ // finally increase give position
+ give++;
+ if(give >= JACK_MIDI_BUFFER_SIZE){
+ give = 0;
+ }
+ jack_midi_out_data[channel].give = give;
+ return false;
+ */
+
+ return false;
+}
+
+/*
+//---------------------------------------------------------
+// putEvent
+// return false if event is delivered
+//---------------------------------------------------------
+
+bool MidiJackDevice::putEvent(int* event)
+{
+ int *y; y = event;
+ return false;
+}
+*/
+
+//---------------------------------------------------------
+// recordEvent
+//---------------------------------------------------------
+
+void MidiJackDevice::recordEvent(MidiRecordEvent& event)
+ {
+ // Set the loop number which the event came in at.
+ //if(audio->isRecording())
+ if(audio->isPlaying())
+ event.setLoopNum(audio->loopCount());
+
+ if (midiInputTrace) {
+ printf("Jack MidiInput: ");
+ event.dump();
+ }
+
+ int typ = event.type();
+
+ if(_port != -1)
+ {
+ int idin = midiPorts[_port].syncInfo().idIn();
+
+ //---------------------------------------------------
+ // filter some SYSEX events
+ //---------------------------------------------------
+
+ if (typ == ME_SYSEX) {
+ const unsigned char* p = event.data();
+ int n = event.len();
+ if (n >= 4) {
+ if ((p[0] == 0x7f)
+ //&& ((p[1] == 0x7f) || (p[1] == rxDeviceId))) {
+ && ((p[1] == 0x7f) || (idin == 0x7f) || (p[1] == idin))) {
+ if (p[2] == 0x06) {
+ //mmcInput(p, n);
+ midiSeq->mmcInput(_port, p, n);
+ return;
+ }
+ if (p[2] == 0x01) {
+ //mtcInputFull(p, n);
+ midiSeq->mtcInputFull(_port, p, n);
+ return;
+ }
+ }
+ else if (p[0] == 0x7e) {
+ //nonRealtimeSystemSysex(p, n);
+ midiSeq->nonRealtimeSystemSysex(_port, p, n);
+ return;
+ }
+ }
+ }
+ else
+ // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
+ midiPorts[_port].syncInfo().trigActDetect(event.channel());
+ }
+
+ //
+ // process midi event input filtering and
+ // transformation
+ //
+
+ processMidiInputTransformPlugins(event);
+
+ if (filterEvent(event, midiRecordType, false))
+ return;
+
+ if (!applyMidiInputTransformation(event)) {
+ if (midiInputTrace)
+ printf(" midi input transformation: event filtered\n");
+ return;
+ }
+
+ //
+ // transfer noteOn events to gui for step recording and keyboard
+ // remote control
+ //
+ if (typ == ME_NOTEON) {
+ int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
+ song->putEvent(pv);
+ }
+
+ //if(_recordFifo.put(MidiPlayEvent(event)))
+ // printf("MidiJackDevice::recordEvent: fifo overflow\n");
+
+ // p3.3.38
+ // Do not bother recording if it is NOT actually being used by a port.
+ // Because from this point on, process handles things, by selected port.
+ if(_port == -1)
+ return;
+
+ // Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
+ unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel();
+ if(_recordFifo[ch].put(MidiPlayEvent(event)))
+ printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch);
+ }
+
+//---------------------------------------------------------
+// midiReceived
+//---------------------------------------------------------
+
+void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
+ {
+ MidiRecordEvent event;
+ event.setB(0);
+
+ // NOTE: From MusE-2. Not done here in Muse-1 (yet).
+ // move all events 2*segmentSize into the future to get
+ // jitterfree playback
+ //
+ // cycle n-1 n n+1
+ // -+----------+----------+----------+-
+ // ^ ^ ^
+ // catch process play
+ //
+// const SeqTime* st = audio->seqTime();
+
+ //unsigned curFrame = st->startFrame() + segmentSize;
+// unsigned curFrame = st->lastFrameTime;
+ //int frameOffset = audio->getFrameOffset();
+ unsigned pos = audio->pos().frame();
+
+ //event.setTime(pos + ev->time);
+ event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time));
+
+ event.setChannel(*(ev->buffer) & 0xf);
+ int type = *(ev->buffer) & 0xf0;
+ int a = *(ev->buffer + 1) & 0x7f;
+ int b = *(ev->buffer + 2) & 0x7f;
+ event.setType(type);
+ switch(type) {
+ case ME_NOTEON:
+ case ME_NOTEOFF:
+ case ME_CONTROLLER:
+ event.setA(*(ev->buffer + 1));
+ event.setB(*(ev->buffer + 2));
+ break;
+ case ME_PROGRAM:
+ case ME_AFTERTOUCH:
+ event.setA(*(ev->buffer + 1));
+ break;
+
+ case ME_PITCHBEND:
+ event.setA(((b << 7) + a) - 8192);
+ break;
+
+ case ME_SYSEX:
+ {
+ int type = *(ev->buffer) & 0xff;
+ switch(type)
+ {
+ case ME_SYSEX:
+
+ // TODO: Deal with large sysex, which are broken up into chunks!
+ // For now, do not accept if the last byte is not EOX, meaning it's a chunk with more chunks to follow.
+ if(*(((unsigned char*)ev->buffer) + ev->size - 1) != ME_SYSEX_END)
+ {
+ printf("MidiJackDevice::eventReceived sysex chunks not supported!\n");
+ return;
+ }
+
+ //event.setTime(0); // mark as used
+ event.setType(ME_SYSEX);
+ event.setData((unsigned char*)(ev->buffer + 1), ev->size - 2);
+ break;
+ case ME_MTC_QUARTER:
+ if(_port != -1)
+ midiSeq->mtcInputQuarter(_port, *(ev->buffer + 1));
+ return;
+ case ME_SONGPOS:
+ if(_port != -1)
+ midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) >> 2 )); // LSB then MSB
+ return;
+ //case ME_SONGSEL:
+ //case ME_TUNE_REQ:
+ //case ME_SENSE:
+ case ME_CLOCK:
+ case ME_TICK:
+ case ME_START:
+ case ME_CONTINUE:
+ case ME_STOP:
+ if(_port != -1)
+ midiSeq->realtimeSystemInput(_port, type);
+ return;
+ //case ME_SYSEX_END:
+ //break;
+ // return;
+ default:
+ printf("MidiJackDevice::eventReceived unsupported system event 0x%02x\n", type);
+ return;
+ }
+ }
+ //return;
+ break;
+ default:
+ printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type);
+ //printf("MidiJackDevice::eventReceived unknown event 0x%02x size:%d buf:0x%02x 0x%02x 0x%02x ...0x%02x\n", type, ev->size, *(ev->buffer), *(ev->buffer + 1), *(ev->buffer + 2), *(ev->buffer + (ev->size - 1)));
+ return;
+ }
+
+ if (midiInputTrace) {
+ printf("MidiInput<%s>: ", name().latin1());
+ event.dump();
+ }
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::eventReceived time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+ #endif
+
+ // Let recordEvent handle it from here, with timestamps, filtering, gui triggering etc.
+ recordEvent(event);
+ }
+
+//---------------------------------------------------------
+// collectMidiEvents
+//---------------------------------------------------------
+
+void MidiJackDevice::collectMidiEvents()
+{
+ if(!_readEnable)
+ return;
+
+ if(!_client_jackport)
+ return;
+ void* port_buf = jack_port_get_buffer(_client_jackport, segmentSize);
+
+ jack_midi_event_t event;
+ jack_nframes_t eventCount = jack_midi_get_event_count(port_buf);
+ for (jack_nframes_t i = 0; i < eventCount; ++i)
+ {
+ jack_midi_event_get(&event, port_buf, i);
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::collectMidiEvents number:%d time:%d\n", i, event.time);
+ #endif
+
+ eventReceived(&event);
+ }
+}
+
+//---------------------------------------------------------
+// putEvent
+// return true if event cannot be delivered
+//---------------------------------------------------------
+
+bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)
+{
+ if(!_writeEnable)
+ //return true;
+ return false;
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::putEvent time:%d type:%d ch:%d A:%d B:%d\n", ev.time(), ev.type(), ev.channel(), ev.dataA(), ev.dataB());
+ #endif
+
+ bool rv = eventFifo.put(ev);
+ if(rv)
+ printf("MidiJackDevice::putEvent: port overflow\n");
+
+ return rv;
+}
+
+//---------------------------------------------------------
+// queueEvent
+// return true if successful
+//---------------------------------------------------------
+
+//void JackAudioDevice::putEvent(Port port, const MidiEvent& e)
+bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
+//bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
+{
+ // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
+ // No big deal if not. Not used for now.
+ //int port = e.port();
+
+ //if(port >= JACK_MIDI_CHANNELS)
+ // return false;
+
+ //if (midiOutputTrace) {
+ // printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data());
+ // e.dump();
+ // }
+
+ //if(debugMsg)
+ // printf("MidiJackDevice::queueEvent\n");
+
+ if(!_client_jackport)
+ return false;
+ void* pb = jack_port_get_buffer(_client_jackport, segmentSize);
+
+ //unsigned frameCounter = ->frameTime();
+ int frameOffset = audio->getFrameOffset();
+ unsigned pos = audio->pos().frame();
+ int ft = e.time() - frameOffset - pos;
+
+ if (ft < 0)
+ ft = 0;
+ if (ft >= (int)segmentSize) {
+ printf("MidiJackDevice::queueEvent: Event time:%d out of range. offset:%d ft:%d (seg=%d)\n", e.time(), frameOffset, ft, segmentSize);
+ if (ft > (int)segmentSize)
+ ft = segmentSize - 1;
+ }
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
+ #endif
+
+ switch(e.type()) {
+ case ME_NOTEON:
+ case ME_NOTEOFF:
+ case ME_POLYAFTER:
+ case ME_CONTROLLER:
+ case ME_PITCHBEND:
+ {
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent note on/off polyafter controller or pitch\n");
+ #endif
+
+ unsigned char* p = jack_midi_event_reserve(pb, ft, 3);
+ if (p == 0) {
+ fprintf(stderr, "MidiJackDevice::queueEvent #1: buffer overflow, event lost\n");
+ return false;
+ }
+ p[0] = e.type() | e.channel();
+ p[1] = e.dataA();
+ p[2] = e.dataB();
+ }
+ break;
+
+ case ME_PROGRAM:
+ case ME_AFTERTOUCH:
+ {
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent program or aftertouch\n");
+ #endif
+
+ unsigned char* p = jack_midi_event_reserve(pb, ft, 2);
+ if (p == 0) {
+ fprintf(stderr, "MidiJackDevice::queueEvent #2: buffer overflow, event lost\n");
+ return false;
+ }
+ p[0] = e.type() | e.channel();
+ p[1] = e.dataA();
+ }
+ break;
+ case ME_SYSEX:
+ {
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent sysex\n");
+ #endif
+
+ const unsigned char* data = e.data();
+ int len = e.len();
+ unsigned char* p = jack_midi_event_reserve(pb, ft, len+2);
+ if (p == 0) {
+ fprintf(stderr, "MidiJackDevice::queueEvent #3: buffer overflow, event lost\n");
+ return false;
+ }
+ p[0] = 0xf0;
+ p[len+1] = 0xf7;
+ memcpy(p+1, data, len);
+ }
+ break;
+ case ME_SONGPOS:
+ case ME_CLOCK:
+ case ME_START:
+ case ME_CONTINUE:
+ case ME_STOP:
+ printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------
+// processEvent
+//---------------------------------------------------------
+
+void MidiJackDevice::processEvent(const MidiPlayEvent& event)
+{
+ //int frameOffset = audio->getFrameOffset();
+ //unsigned pos = audio->pos().frame();
+
+ int chn = event.channel();
+ unsigned t = event.time();
+ int a = event.dataA();
+ int b = event.dataB();
+ // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
+ // No big deal if not. Not used for now.
+ int port = event.port();
+
+ // TODO: No sub-tick playback resolution yet, with external sync.
+ // Just do this 'standard midi 64T timing thing' for now until we figure out more precise external timings.
+ // Does require relatively short audio buffers, in order to catch the resolution, but buffer <= 256 should be OK...
+ // Tested OK so far with 128.
+ if(extSyncFlag.value())
+ t = audio->getFrameOffset() + audio->pos().frame();
+ //t = frameOffset + pos;
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+ #endif
+
+ if(event.type() == ME_PROGRAM)
+ {
+ // don't output program changes for GM drum channel
+ //if (!(song->mtype() == MT_GM && chn == 9)) {
+ int hb = (a >> 16) & 0xff;
+ int lb = (a >> 8) & 0xff;
+ int pr = a & 0x7f;
+
+ // p3.3.44
+ //printf("MidiJackDevice::processEvent ME_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n",
+ // event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
+
+ if (hb != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ if (lb != 0xff)
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0));
+ // }
+ }
+ else
+ if(event.type() == ME_PITCHBEND)
+ {
+ int v = a + 8192;
+ // p3.3.44
+ //printf("MidiJackDevice::processEvent ME_PITCHBEND v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+
+ queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
+ }
+ else
+ if(event.type() == ME_CONTROLLER)
+ {
+ //int a = event.dataA();
+ //int b = event.dataB();
+ // Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
+ // No big deal if not. Not used for now.
+ //int port = event.port();
+
+ int nvh = 0xff;
+ int nvl = 0xff;
+ if(_port != -1)
+ {
+ int nv = midiPorts[_port].nullSendValue();
+ if(nv != -1)
+ {
+ nvh = (nv >> 8) & 0xff;
+ nvl = nv & 0xff;
+ }
+ }
+
+ if(a == CTRL_PITCH)
+ {
+ int v = b + 8192;
+ // p3.3.44
+ //printf("MidiJackDevice::processEvent CTRL_PITCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+
+ queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
+ }
+ else if (a == CTRL_PROGRAM)
+ {
+ // don't output program changes for GM drum channel
+ //if (!(song->mtype() == MT_GM && chn == 9)) {
+ int hb = (b >> 16) & 0xff;
+ int lb = (b >> 8) & 0xff;
+ int pr = b & 0x7f;
+
+ // p3.3.44
+ //printf("MidiJackDevice::processEvent CTRL_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n",
+ // event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
+
+ if (hb != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ if (lb != 0xff)
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0));
+ // }
+ }
+ /*
+ else if (a == CTRL_MASTER_VOLUME)
+ {
+ unsigned char sysex[] = {
+ 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00
+ };
+ sysex[1] = deviceId();
+ sysex[4] = b & 0x7f;
+ sysex[5] = (b >> 7) & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6));
+ }
+ */
+ else if (a < CTRL_14_OFFSET)
+ { // 7 Bit Controller
+ queueEvent(event);
+ //queueEvent(museport, MidiPlayEvent(t, port, chn, event));
+ }
+ else if (a < CTRL_RPN_OFFSET)
+ { // 14 bit high resolution controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ int dataH = (b >> 7) & 0x7f;
+ int dataL = b & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH));
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL));
+ }
+ else if (a < CTRL_NRPN_OFFSET)
+ { // RPN 7-Bit Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
+
+ t += 3;
+ // Select null parameters so that subsequent data controller events do not upset the last *RPN controller.
+ //sendNullRPNParams(chn, false);
+ if(nvh != 0xff)
+ {
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
+ t += 1;
+ }
+ if(nvl != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
+ }
+ //else if (a < CTRL_RPN14_OFFSET)
+ else if (a < CTRL_INTERNAL_OFFSET)
+ { // NRPN 7-Bit Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
+
+ t += 3;
+ //sendNullRPNParams(chn, true);
+ if(nvh != 0xff)
+ {
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
+ t += 1;
+ }
+ if(nvl != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
+ }
+ else if (a < CTRL_NRPN14_OFFSET)
+ { // RPN14 Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ int dataH = (b >> 7) & 0x7f;
+ int dataL = b & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+
+ t += 4;
+ //sendNullRPNParams(chn, false);
+ if(nvh != 0xff)
+ {
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
+ t += 1;
+ }
+ if(nvl != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
+ }
+ else if (a < CTRL_NONE_OFFSET)
+ { // NRPN14 Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ int dataH = (b >> 7) & 0x7f;
+ int dataL = b & 0x7f;
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+
+ t += 4;
+ //sendNullRPNParams(chn, true);
+ if(nvh != 0xff)
+ {
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
+ t += 1;
+ }
+ if(nvl != 0xff)
+ queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
+ }
+ else
+ {
+ printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a);
+ }
+ }
+ else
+ {
+ queueEvent(event);
+ //queueEvent(MidiPlayEvent(t, port, chn, event));
+ }
+}
+
+//---------------------------------------------------------
+// processMidi called from audio process only.
+//---------------------------------------------------------
+
+void MidiJackDevice::processMidi()
+{
+ if(!_client_jackport)
+ return;
+ void* port_buf = jack_port_get_buffer(_client_jackport, segmentSize);
+ jack_midi_clear_buffer(port_buf);
+
+ while(!eventFifo.isEmpty())
+ {
+ MidiPlayEvent e(eventFifo.get());
+ int evTime = e.time();
+ // Is event marked to be played immediately?
+ if(evTime == 0)
+ {
+ // Nothing to do but stamp the event to be queued for frame 0+.
+ //e.setTime(frameOffset + pos);
+ e.setTime(audio->getFrameOffset() + audio->pos().frame());
+ }
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::processMidi eventFifo time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
+ #endif
+
+ //el->insert(eventFifo.get());
+ //el->insert(e);
+ processEvent(e);
+ }
+
+ MPEventList* el = playEvents();
+ if(el->empty())
+ return;
+
+ iMPEvent i = nextPlayEvent();
+ for(; i != el->end(); ++i)
+ {
+ // p3.3.39 Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
+ // Same code as in MidiPort::sendEvent()
+ if(_port != -1)
+ {
+ MidiPort* mp = &midiPorts[_port];
+ if(i->type() == ME_CONTROLLER)
+ {
+ int da = i->dataA();
+ int db = i->dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+ if(!mp->setHwCtrlState(i->channel(), da, db))
+ continue;
+ //mp->setHwCtrlState(i->channel(), da, db);
+ }
+ else
+ if(i->type() == ME_PITCHBEND)
+ {
+ // p3.3.44
+ //printf("MidiJackDevice::processMidi playEvents ME_PITCHBEND time:%d type:%d ch:%d A:%d B:%d\n", (*i).time(), (*i).type(), (*i).channel(), (*i).dataA(), (*i).dataB());
+
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA());
+ if(!mp->setHwCtrlState(i->channel(), CTRL_PITCH, da))
+ continue;
+ //mp->setHwCtrlState(i->channel(), CTRL_PITCH, da);
+
+ //(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
+ }
+ else
+ if(i->type() == ME_PROGRAM)
+ {
+ if(!mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA()))
+ continue;
+ //mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA());
+ }
+ }
+
+ processEvent(*i);
+ }
+
+ setNextPlayEvent(i);
+}
+
+//---------------------------------------------------------
+// initMidiJack
+// return true on error
+//---------------------------------------------------------
+
+bool initMidiJack()
+{
+ /*
+ int adr = 0;
+
+ memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
+ memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
+
+ MidiJackDevice* dev = new MidiJackDevice(adr, QString("jack-midi"));
+ dev->setrwFlags(3); // set read and write flags
+
+ if(pipe(jackmidi_pi) < 0){
+ fprintf(stderr, "cant create midi-jack input pipe\n");
+ }
+ if(pipe(jackmidi_po) < 0){
+ fprintf(stderr, "cant create midi-jack output pipe\n");
+ }
+
+ midiDevices.add(dev);
+
+ gmdev = dev; // proclaim the global jack-midi instance
+
+ //jackScanMidiPorts();
+ */
+
+ return false;
+}
+
+/*
+struct JackPort {
+ int adr;
+ //char* name;
+ QString name;
+ int flags;
+ //JackPort(int a, const char* s, int f) {
+ JackPort(int a, const QString& s, int f) {
+ adr = a;
+ //name = strdup(s);
+ name = QString(s);
+ flags = f;
+ }
+ };
+
+
+static std::list<JackPort> portList;
+
+//---------------------------------------------------------
+// jackScanMidiPorts
+//---------------------------------------------------------
+
+void jackScanMidiPorts()
+{
+ int adr;
+ const char* name;
+
+ portList.clear();
+ adr = 0;
+ name = strdup("namex");
+ portList.push_back(JackPort(adr, name, 0));
+ //
+ // check for devices to add
+ //
+ for (std::list<JackPort>::iterator k = portList.begin(); k != portList.end(); ++k) {
+ iMidiDevice i = midiDevices.begin();
+ for (;i != midiDevices.end(); ++i) {
+ //MidiJackDevice* d = dynamic_cast<MidiJackDevice*>(*i);
+ break;
+ //if (d == 0) continue;
+ //if ((k->adr.client == d->adr.client) && (k->adr.port == d->adr.port)) {
+ // break;
+ //}
+ }
+ if (i == midiDevices.end()) {
+ // add device
+ MidiJackDevice* dev = new MidiJackDevice(k->adr, QString(k->name));
+ dev->setrwFlags(k->flags);
+ midiDevices.add(dev);
+ }
+ }
+}
+*/
+
+/*
+//---------------------------------------------------------
+// processInput
+//---------------------------------------------------------
+static void handle_jack_midi_in(int channel)
+{
+ MidiRecordEvent event;
+ int t,n,v;
+ t = jack_midi_in_data[channel].buffer[0];
+ n = jack_midi_in_data[channel].buffer[1];
+ v = jack_midi_in_data[channel].buffer[2];
+
+ event.setType(0); // mark as unused
+ event.setPort(gmdev->midiPort());
+ event.setB(0);
+
+ if(t == 0x90){ // note on
+ fprintf(stderr, "jackProcessMidiInput note-on\n");
+ event.setChannel(channel);
+ event.setType(ME_NOTEON);
+ event.setA(n);
+ event.setB(v);
+ }else if (t == 0x80){ // note off
+ fprintf(stderr, "jackProcessMidiInput note-off\n");
+ event.setChannel(channel);
+ event.setType(ME_NOTEOFF);
+ event.setA(n);
+ event.setB(v);
+ }else{
+ fprintf(stderr, "WARNING: unknown midi-in on channel %d: %x,%x,%x\n",
+ channel, t, n, v);
+ return;
+ }
+ if(event.type()){
+ gmdev->recordEvent(event);
+ midiPorts[gmdev->midiPort()].syncInfo().trigActDetect(event.channel());
+ }
+}
+
+void MidiJackDevice::processInput()
+{
+ char buf;
+ int i,s;
+ read(gmdev->selectRfd(), &buf, 1);
+
+ s = 1;
+ for(i = 0; i < JACK_MIDI_CHANNELS; i++){
+ if(jack_midi_in_data[i].buffer[3]){
+ s = 0;
+ handle_jack_midi_in(i);
+ jack_midi_in_data[i].buffer[3] = 0;
+ }
+ }
+}
+
+*/
diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h
new file mode 100644
index 00000000..12b967a9
--- /dev/null
+++ b/muse2/muse/driver/jackmidi.h
@@ -0,0 +1,156 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: jackmidi.h,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $
+// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __JACKMIDI_H__
+#define __JACKMIDI_H__
+
+//#include <config.h>
+
+#include <map>
+
+#include <jack/jack.h>
+#include <jack/midiport.h>
+
+#include "mididev.h"
+#include "route.h"
+
+class QString;
+class MidiFifo;
+class MidiRecordEvent;
+class MidiPlayEvent;
+//class RouteList;
+class Xml;
+
+// Turn on to show multiple devices, work in progress,
+// not working fully yet, can't seem to connect...
+#define JACK_MIDI_SHOW_MULTIPLE_DEVICES
+
+// It appears one client port per remote port will be necessary.
+// Jack doesn't seem to like manipulation of non-local ports buffers.
+#define JACK_MIDI_USE_MULTIPLE_CLIENT_PORTS
+
+/* jack-midi channels */
+//#define JACK_MIDI_CHANNELS 32
+
+/* jack-midi buffer size */
+//#define JACK_MIDI_BUFFER_SIZE 32
+
+/*
+typedef struct {
+ int give;
+ int take;
+ // 32 parallel midi events, where each event contains three
+ // midi-bytes and one busy-byte
+ char buffer[4 * JACK_MIDI_BUFFER_SIZE];
+} muse_jack_midi_buffer;
+*/
+
+/*
+struct JackMidiPort
+{
+ jack_port_t* _jackPort;
+ QString _name;
+ int _flags; // 1 = writable, 2 = readable - do not mix
+ JackMidiPort(jack_port_t* jp, const QString& s, int f)
+ {
+ _jackPort = jp;
+ _name = QString(s);
+ _flags = f;
+ }
+};
+
+typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::iterator iJackMidiPort;
+typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::const_iterator ciJackMidiPort;
+
+class JackMidiPortList : public std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >
+{
+ private:
+ static int _nextOutIdNum;
+ static int _nextInIdNum;
+
+ public:
+ JackMidiPortList();
+ ~JackMidiPortList();
+ iJackMidiPort createClientPort(int flags);
+ bool removeClientPort(jack_port_t* port);
+};
+
+extern JackMidiPortList jackMidiClientPorts;
+*/
+
+//---------------------------------------------------------
+// MidiJackDevice
+//---------------------------------------------------------
+
+class MidiJackDevice : public MidiDevice {
+ public:
+ //int adr;
+
+ private:
+ // fifo for midi events sent from gui
+ // direct to midi port:
+ MidiFifo eventFifo;
+
+ //static int _nextOutIdNum;
+ //static int _nextInIdNum;
+
+ jack_port_t* _client_jackport;
+ //RouteList _routes;
+
+ virtual QString open();
+ virtual void close();
+ //bool putEvent(int*);
+
+ void processEvent(const MidiPlayEvent&);
+ // Port is not midi port, it is the port(s) created for MusE.
+ bool queueEvent(const MidiPlayEvent&);
+
+ virtual bool putMidiEvent(const MidiPlayEvent&);
+ //bool sendEvent(const MidiPlayEvent&);
+
+ void eventReceived(jack_midi_event_t*);
+
+ public:
+ MidiJackDevice() {}
+ //MidiJackDevice(const int&, const QString& name);
+ MidiJackDevice(jack_port_t* jack_port, const QString& name);
+
+ static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix.
+
+ virtual inline int deviceType() { return JACK_MIDI; }
+
+ virtual void setName(const QString&);
+
+ virtual void processMidi();
+ virtual ~MidiJackDevice();
+ //virtual int selectRfd();
+ //virtual int selectWfd();
+ //virtual void processInput();
+
+ virtual void recordEvent(MidiRecordEvent&);
+
+ virtual bool putEvent(const MidiPlayEvent&);
+ virtual void collectMidiEvents();
+
+ //virtual jack_port_t* jackPort() { return _jackport; }
+ //virtual jack_port_t* clientJackPort() { return _client_jackport; }
+ virtual void* clientPort() { return (void*)_client_jackport; }
+
+ //RouteList* routes() { return &_routes; }
+ //bool noRoute() const { return _routes.empty(); }
+ virtual void writeRouting(int, Xml&) const;
+ };
+
+extern bool initMidiJack();
+//extern int jackSelectRfd();
+//extern int jackSelectWfd();
+//extern void jackProcessMidiInput();
+//extern void jackScanMidiPorts();
+
+#endif
+
+
diff --git a/muse2/muse/driver/rtctimer.cpp b/muse2/muse/driver/rtctimer.cpp
new file mode 100644
index 00000000..1a3cefa6
--- /dev/null
+++ b/muse2/muse/driver/rtctimer.cpp
@@ -0,0 +1,155 @@
+ //=========================================================
+ // MusE
+ // Linux Music Editor
+ // $Id: rtctimer.cpp,v 1.1.2.11 2009/03/09 02:05:18 terminator356 Exp $
+ //
+ // Most code moved from midiseq.cpp by Werner Schweer.
+ //
+ // (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+ // (C) Copyright -2004 Werner Schweer (werner@seh.de)
+ //=========================================================
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#else
+#include <linux/rtc.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+
+#include "rtctimer.h"
+#include "globals.h"
+#include "gconfig.h"
+
+
+RtcTimer::RtcTimer()
+ {
+ timerFd = -1;
+ }
+
+RtcTimer::~RtcTimer()
+ {
+ if (timerFd != -1)
+ close(timerFd);
+ }
+
+signed int RtcTimer::initTimer()
+ {
+ if(TIMER_DEBUG)
+ printf("RtcTimer::initTimer()\n");
+ if (timerFd != -1) {
+ fprintf(stderr,"RtcTimer::initTimer(): called on initialised timer!\n");
+ return -1;
+ }
+ doSetuid();
+
+ timerFd = ::open("/dev/rtc", O_RDONLY);
+ if (timerFd == -1) {
+ fprintf(stderr, "fatal error: open /dev/rtc failed: %s\n", strerror(errno));
+ fprintf(stderr, "hint: check if 'rtc' kernel module is loaded, or used by something else\n");
+ undoSetuid();
+ return timerFd;
+ }
+ if (!setTimerFreq(config.rtcTicks)) {
+ // unable to set timer frequency
+ return -1;
+ }
+ // check if timer really works, start and stop it once.
+ if (!startTimer()) {
+ return -1;
+ }
+ if (!stopTimer()) {
+ return -1;
+ }
+ return timerFd;
+ }
+
+unsigned int RtcTimer::setTimerResolution(unsigned int resolution)
+ {
+ if(TIMER_DEBUG)
+ printf("RtcTimer::setTimerResolution(%d)\n",resolution);
+ /* The RTC can take power-of-two frequencies from 2 to 8196 Hz.
+ * It doesn't really have a resolution as such.
+ */
+ return 0;
+ }
+
+unsigned int RtcTimer::setTimerFreq(unsigned int freq)
+ {
+ int rc = ioctl(timerFd, RTC_IRQP_SET, freq);
+ if (rc == -1) {
+ fprintf(stderr, "RtcTimer::setTimerFreq(): cannot set tick on /dev/rtc: %s\n",
+ strerror(errno));
+ fprintf(stderr, " precise timer not available\n");
+ return 0;
+ }
+ return freq;
+ }
+
+unsigned int RtcTimer::getTimerResolution()
+ {
+ /* The RTC doesn't really work with a set resolution as such.
+ * Not sure how this fits into things yet.
+ */
+ return 0;
+ }
+
+unsigned int RtcTimer::getTimerFreq()
+ {
+ unsigned int freq;
+ int rv = ioctl(timerFd, RTC_IRQP_READ, &freq);
+ if (rv < 1)
+ return 0;
+ return freq;
+ }
+
+bool RtcTimer::startTimer()
+ {
+ if(TIMER_DEBUG)
+ printf("RtcTimer::startTimer()\n");
+ if (timerFd == -1) {
+ fprintf(stderr, "RtcTimer::startTimer(): no timer open to start!\n");
+ return false;
+ }
+ if (ioctl(timerFd, RTC_PIE_ON, 0) == -1) {
+ perror("MidiThread: start: RTC_PIE_ON failed");
+ undoSetuid();
+ return false;
+ }
+ return true;
+ }
+
+bool RtcTimer::stopTimer()
+ {
+ if(TIMER_DEBUG)
+ printf("RtcTimer::stopTimer\n");
+ if (timerFd != -1) {
+ ioctl(timerFd, RTC_PIE_OFF, 0);
+ }
+ else {
+ fprintf(stderr,"RtcTimer::stopTimer(): no RTC to stop!\n");
+ return false;
+ }
+ return true;
+ }
+
+unsigned int RtcTimer::getTimerTicks(bool /*printTicks*/)// prevent compiler warning: unused parameter
+ {
+ if(TIMER_DEBUG)
+ printf("getTimerTicks()\n");
+ unsigned long int nn;
+ if (timerFd==-1) {
+ fprintf(stderr,"RtcTimer::getTimerTicks(): no RTC open to read!\n");
+ return 0;
+ }
+ if (read(timerFd, &nn, sizeof(unsigned long)) != sizeof(unsigned long)) {
+ fprintf(stderr,"RtcTimer::getTimerTicks(): error reading RTC\n");
+ return 0;
+ }
+ return nn;
+ }
diff --git a/muse2/muse/driver/rtctimer.h b/muse2/muse/driver/rtctimer.h
new file mode 100644
index 00000000..fa58b032
--- /dev/null
+++ b/muse2/muse/driver/rtctimer.h
@@ -0,0 +1,44 @@
+ //=========================================================
+ // MusE
+ // Linux Music Editor
+ // $Id: rtctimer.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $
+ //
+ // Most code moved from midiseq.cpp
+ //
+ // (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+ // (C) Copyright -2004 Werner Schweer (werner@seh.de)
+ //=========================================================
+
+#ifndef __RTCTIMER_H__
+#define __RTCTIMER_H__
+
+#include "timerdev.h"
+
+
+//---------------------------------------------------------
+// AlsaTimer
+//---------------------------------------------------------
+
+class RtcTimer : public Timer{
+
+
+ public:
+ RtcTimer();
+ virtual ~RtcTimer();
+
+ virtual signed int initTimer();
+ virtual unsigned int setTimerResolution(unsigned int resolution);
+ virtual unsigned int getTimerResolution();
+ virtual unsigned int setTimerFreq(unsigned int tick);
+ virtual unsigned int getTimerFreq();
+
+ virtual bool startTimer();
+ virtual bool stopTimer();
+ virtual unsigned int getTimerTicks(bool printTicks=false);
+
+ private:
+ int timerFd;
+
+};
+
+#endif //__ALSATIMER_H__
diff --git a/muse2/muse/driver/timerdev.h b/muse2/muse/driver/timerdev.h
new file mode 100644
index 00000000..944bc213
--- /dev/null
+++ b/muse2/muse/driver/timerdev.h
@@ -0,0 +1,41 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: timerdev.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $
+//
+// Plenty of code borrowed from timer.c example in
+// alsalib 1.0.7
+//
+// (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+//=========================================================
+
+#ifndef __TIMERDEV_H__
+#define __TIMERDEV_H__
+
+#include "alsa/asoundlib.h"
+
+#define TIMER_DEBUG 0
+
+//---------------------------------------------------------
+// AlsaTimer
+//---------------------------------------------------------
+
+class Timer {
+
+ public:
+ Timer() {};
+ virtual ~Timer() {};
+
+ virtual signed int initTimer() = 0;
+ virtual unsigned int setTimerResolution(unsigned int resolution) = 0;
+ virtual unsigned int getTimerResolution() = 0;
+ virtual unsigned int setTimerFreq(unsigned int freq) = 0;
+ virtual unsigned int getTimerFreq() = 0;
+
+ virtual bool startTimer() = 0;
+ virtual bool stopTimer() = 0;
+ virtual unsigned int getTimerTicks(bool printTicks = false) = 0;
+
+};
+
+#endif //__ALSATIMER_H__