diff -Nru qmidiarp-0.4.2/aclocal.m4 qmidiarp-0.4.5/aclocal.m4 --- qmidiarp-0.4.2/aclocal.m4 2011-07-09 15:48:15.000000000 +0000 +++ qmidiarp-0.4.5/aclocal.m4 2012-01-21 17:28:54.000000000 +0000 @@ -1,7 +1,8 @@ -# generated automatically by aclocal 1.11.1 -*- Autoconf -*- +# generated automatically by aclocal 1.11.2 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. # This file 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. @@ -179,12 +180,15 @@ fi[]dnl ])# PKG_CHECK_MODULES -# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software +# Foundation, Inc. # # This file 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. +# serial 1 + # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been @@ -194,7 +198,7 @@ [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.1], [], +m4_if([$1], [1.11.2], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -210,19 +214,21 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.1])dnl +[AM_AUTOMAKE_VERSION([1.11.2])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file 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. +# serial 1 + # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. @@ -270,13 +276,13 @@ # AM_COND_IF -*- Autoconf -*- -# Copyright (C) 2008 Free Software Foundation, Inc. +# Copyright (C) 2008, 2010 Free Software Foundation, Inc. # # This file 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. -# serial 1 +# serial 3 # _AM_COND_IF # _AM_COND_ELSE @@ -290,15 +296,15 @@ # AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) # --------------------------------------- -# If the shell condition matching COND is true, execute IF-TRUE, -# otherwise execute IF-FALSE. Allow automake to learn about conditional -# instantiating macros (the AC_CONFIG_FOOS). +# If the shell condition COND is true, execute IF-TRUE, otherwise execute +# IF-FALSE. Allow automake to learn about conditional instantiating macros +# (the AC_CONFIG_FOOS). AC_DEFUN([AM_COND_IF], [m4_ifndef([_AM_COND_VALUE_$1], [m4_fatal([$0: no such condition "$1"])])dnl _AM_COND_IF([$1])dnl -if _AM_COND_VALUE_$1; then - m4_default([$2], [:]) +if test -z "$$1_TRUE"; then : + m4_n([$2])[]dnl m4_ifval([$3], [_AM_COND_ELSE([$1])dnl else @@ -344,14 +350,14 @@ Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 -# Free Software Foundation, Inc. +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, +# 2010, 2011 Free Software Foundation, Inc. # # This file 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. -# serial 10 +# serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, @@ -391,6 +397,7 @@ # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. + rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. @@ -455,7 +462,7 @@ break fi ;; - msvisualcpp | msvcmsys) + msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. @@ -520,10 +527,13 @@ if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' + am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- @@ -745,12 +755,15 @@ done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, +# Inc. # # This file 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. +# serial 1 + # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. @@ -882,12 +895,15 @@ fi ]) -# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, +# Inc. # # This file 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. +# serial 1 + # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. @@ -910,13 +926,14 @@ # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software +# Foundation, Inc. # # This file 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. -# serial 4 +# serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- @@ -924,13 +941,13 @@ [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) -# ------------------------------ +# -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) -# ---------------------------------- +# ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) @@ -1006,12 +1023,14 @@ fi AC_MSG_RESULT(yes)]) -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file 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. +# serial 1 + # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't @@ -1034,13 +1053,13 @@ INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file 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. -# serial 2 +# serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- @@ -1049,7 +1068,7 @@ AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- +# -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) diff -Nru qmidiarp-0.4.2/AUTHORS qmidiarp-0.4.5/AUTHORS --- qmidiarp-0.4.2/AUTHORS 2011-05-29 18:18:19.000000000 +0000 +++ qmidiarp-0.4.5/AUTHORS 2011-11-07 20:48:40.000000000 +0000 @@ -2,10 +2,10 @@ --------------------------------- Frank Kober +Nedko Arnaudov Guido Scholz Matthias Nagorni - Translations --------------------------------- Robert Dietrich - de diff -Nru qmidiarp-0.4.2/configure qmidiarp-0.4.5/configure --- qmidiarp-0.4.2/configure 2011-07-09 15:48:17.000000000 +0000 +++ qmidiarp-0.4.5/configure 2012-01-21 17:28:55.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for qmidiarp 0.4.2. +# Generated by GNU Autoconf 2.68 for qmidiarp 0.4.5. # # Report bugs to . # @@ -560,8 +560,8 @@ # Identity of this package. PACKAGE_NAME='qmidiarp' PACKAGE_TARNAME='qmidiarp' -PACKAGE_VERSION='0.4.2' -PACKAGE_STRING='qmidiarp 0.4.2' +PACKAGE_VERSION='0.4.5' +PACKAGE_STRING='qmidiarp 0.4.5' PACKAGE_BUGREPORT='qmidiarp-devel@lists.sourceforge.net' PACKAGE_URL='' @@ -631,6 +631,7 @@ am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE +am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE @@ -766,6 +767,7 @@ enable_doxygen_ps enable_doxygen_pdf enable_dependency_tracking +enable_translations ' ac_precious_vars='build_alias host_alias @@ -1327,7 +1329,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures qmidiarp 0.4.2 to adapt to many kinds of systems. +\`configure' configures qmidiarp 0.4.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1393,7 +1395,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of qmidiarp 0.4.2:";; + short | recursive ) echo "Configuration of qmidiarp 0.4.5:";; esac cat <<\_ACEOF @@ -1414,6 +1416,7 @@ --enable-doxygen-pdf generate doxygen PDF documentation --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors + --enable-translations enable translation file generation (default=yes) Some influential environment variables: DOXYGEN_PAPER_SIZE @@ -1502,7 +1505,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -qmidiarp configure 0.4.2 +qmidiarp configure 0.4.5 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1963,7 +1966,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by qmidiarp $as_me 0.4.2, which was +It was created by qmidiarp $as_me 0.4.5, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2781,7 +2784,7 @@ # Define the identity of the package. PACKAGE='qmidiarp' - VERSION='0.4.2' + VERSION='0.4.5' cat >>confdefs.h <<_ACEOF @@ -5321,6 +5324,7 @@ if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' + am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= @@ -5345,6 +5349,7 @@ # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. + rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. @@ -5404,7 +5409,7 @@ break fi ;; - msvisualcpp | msvcmsys) + msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. @@ -6012,6 +6017,7 @@ # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. + rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. @@ -6071,7 +6077,7 @@ break fi ;; - msvisualcpp | msvcmsys) + msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. @@ -6682,8 +6688,16 @@ as_fn_error $? "cannot find 'moc', please install the Qt4 development tools package." "$LINENO" 5 fi -enable_translations=true - if test x$enable_translations = xtrue; then +# Enable translations. +# Check whether --enable-translations was given. +if test "${enable_translations+set}" = set; then : + enableval=$enable_translations; ac_translations="$enableval" +else + ac_translations="yes" +fi + + + if test "x$ac_translations" = "xyes"; then ENABLE_TRANSLATIONS_TRUE= ENABLE_TRANSLATIONS_FALSE='#' else @@ -6692,7 +6706,7 @@ fi -if test x$enable_translations = xtrue; then +if test -z "$ENABLE_TRANSLATIONS_TRUE"; then : for ac_prog in lupdate-qt4 lupdate do @@ -6797,8 +6811,8 @@ fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: transaltions are disabled" >&5 -$as_echo "$as_me: transaltions are disabled" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: translations are disabled" >&5 +$as_echo "$as_me: translations are disabled" >&6;} fi # Checks for header files. @@ -7654,6 +7668,21 @@ # Checks for header files. +ac_fn_c_check_header_mongrel "$LINENO" "jack/session.h" "ac_cv_header_jack_session_h" "$ac_includes_default" +if test "x$ac_cv_header_jack_session_h" = xyes; then : + jack_session_found="yes" +else + jack_session_found="no" +fi + + +if test "$jack_session_found" = "yes"; then + +$as_echo "#define JACK_SESSION 1" >>confdefs.h + +fi + + # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. @@ -8305,7 +8334,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by qmidiarp $as_me 0.4.2, which was +This file was extended by qmidiarp $as_me 0.4.5, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -8371,7 +8400,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -qmidiarp config.status 0.4.2 +qmidiarp config.status 0.4.5 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" @@ -9237,3 +9266,12 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + +echo +if test "x$ac_translations" = "xno" ; then +echo "Translation file generation disabled." +echo "Use ./configure --enable-translations=yes to enable." +else +echo "Translation file generation enabled." +fi +echo diff -Nru qmidiarp-0.4.2/configure.ac qmidiarp-0.4.5/configure.ac --- qmidiarp-0.4.2/configure.ac 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/configure.ac 2012-01-21 17:28:24.000000000 +0000 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. dnl AC_PREREQ([2.63]) -AC_INIT([qmidiarp], [0.4.2], [qmidiarp-devel@lists.sourceforge.net]) +AC_INIT([qmidiarp], [0.4.5], [qmidiarp-devel@lists.sourceforge.net]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS(src/config.h) AM_INIT_AUTOMAKE([dist-bzip2]) @@ -65,8 +65,13 @@ [cannot find 'moc', please install the Qt4 development tools package.]) fi -enable_translations=true -AM_CONDITIONAL([ENABLE_TRANSLATIONS], [test x$enable_translations = xtrue]) +# Enable translations. +AC_ARG_ENABLE(translations, + AC_HELP_STRING([--enable-translations], [enable translation file generation (default=yes)]), + [ac_translations="$enableval"], + [ac_translations="yes"]) + +AM_CONDITIONAL([ENABLE_TRANSLATIONS], [test "x$ac_translations" = "xyes"]) AM_COND_IF([ENABLE_TRANSLATIONS],[ dnl check for lupdate @@ -82,7 +87,7 @@ AC_MSG_ERROR( [cannot find 'lrelease', please install the Qt4 development tools package.]) fi -], [AC_MSG_NOTICE([transaltions are disabled])]) +], [AC_MSG_NOTICE([translations are disabled])]) # Checks for header files. AC_HEADER_STDC @@ -102,6 +107,12 @@ # Checks for header files. +AC_CHECK_HEADER(jack/session.h, jack_session_found="yes", jack_session_found="no") +if test "$jack_session_found" = "yes"; then + AC_DEFINE(JACK_SESSION, 1, [Define to enable jack session support]) +fi + + # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. @@ -111,3 +122,12 @@ AC_CONFIG_FILES([src/pixmaps/Makefile] [man/Makefile] [man/fr/Makefile]) AC_CONFIG_FILES([man/de/Makefile]) AC_OUTPUT + +echo +if test "x$ac_translations" = "xno" ; then +echo "Translation file generation disabled." +echo "Use ./configure --enable-translations=yes to enable." +else +echo "Translation file generation enabled." +fi +echo diff -Nru qmidiarp-0.4.2/debian/changelog qmidiarp-0.4.5/debian/changelog --- qmidiarp-0.4.2/debian/changelog 2011-07-10 09:32:35.000000000 +0000 +++ qmidiarp-0.4.5/debian/changelog 2012-01-31 00:08:19.000000000 +0000 @@ -1,3 +1,44 @@ +qmidiarp (0.4.5-1) unstable; urgency=low + + * New upstream release. + - Fixed Bugs + + JACK Transport start with ALSA backend was broken in 0.4.4 + + Event forwarding port index was uninitialized in JACK MIDI backend + + * Added patch fixing desktop file + * Added patch fixing few syntax and spelling errors in man pages + + -- Jaromír Mikeš Mon, 30 Jan 2012 23:41:28 +0100 + +qmidiarp (0.4.4-1) unstable; urgency=low + + * New upstream release: + - New Features: + + JACK MIDI backend doesn't require Jack Transport anymore + - Improvements: + + Better usability of the sequencer loop marker + + Improved LFO offset slider behavior + + Quantization to the minimum stepwidth in Arp modules active when + changes in Arp patterns occur + - Fixed Bugs + + Crash on startup in JACK MIDI mode on certain systems + + When cloning modules, the current play direction wasn't copied + + Unmatched MIDI event forwarding didn't work with Arp modules + + Typo in english manpage + + -- Alessio Treglia Tue, 27 Dec 2011 02:10:30 +0100 + +qmidiarp (0.4.3-1) unstable; urgency=low + + [ Jaromír Mikeš ] + * New upstream release. + * Add myself as uploader. + + [ Alessio Treglia ] + * Set DM-Upload-Allowed: yes + + -- Alessio Treglia Sat, 03 Dec 2011 17:56:44 +0100 + qmidiarp (0.4.2-1) unstable; urgency=low * New upstream release. diff -Nru qmidiarp-0.4.2/debian/control qmidiarp-0.4.5/debian/control --- qmidiarp-0.4.2/debian/control 2011-06-01 11:03:36.000000000 +0000 +++ qmidiarp-0.4.5/debian/control 2012-01-31 00:03:44.000000000 +0000 @@ -2,7 +2,8 @@ Section: sound Priority: optional Maintainer: Debian Multimedia Maintainers -Uploaders: Alessio Treglia +Uploaders: Alessio Treglia , + Jaromír Mikeš Build-Depends: debhelper (>= 7.0.50~), dh-autoreconf, libqt4-dev, @@ -12,6 +13,7 @@ python-scour Homepage: http://qmidiarp.sourceforge.net/ Standards-Version: 3.9.2 +DM-Upload-Allowed: yes Vcs-Git: git://git.debian.org/pkg-multimedia/qmidiarp.git Vcs-Browser: http://git.debian.org/?p=pkg-multimedia/qmidiarp.git diff -Nru qmidiarp-0.4.2/debian/copyright qmidiarp-0.4.5/debian/copyright --- qmidiarp-0.4.2/debian/copyright 2011-06-01 11:00:51.000000000 +0000 +++ qmidiarp-0.4.5/debian/copyright 2012-01-31 00:03:44.000000000 +0000 @@ -1,12 +1,10 @@ -Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=166 +Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=202 Upstream-Name: QMidiArp Upstream-Contact: Matthias Nagorni Frank Kober Guido Scholz Source: https://sourceforge.net/projects/qmidiarp/files -Copyright: 2009, 2010, 2011 -License: GPL-2+ Files: * Copyright: @@ -17,7 +15,9 @@ License: GPL-2+ Files: debian/* -Copyright: 2011 Alessio Treglia +Copyright: + 2011 Alessio Treglia + 2011 Jaromír Mikeš License: GPL-2+ License: GPL-2+ @@ -30,10 +30,11 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +Comment: + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. or point your web browser to http://www.gnu.org. -Comment: On Debian systems, the complete text of the GNU General - Public License can be found in `/usr/share/common-licenses/GPL-2'. + . + On Debian systems, the full text of the GNU General Public + License can be found in the file `/usr/share/common-licenses/GPL-2'. diff -Nru qmidiarp-0.4.2/debian/patches/01-desktop-file.patch qmidiarp-0.4.5/debian/patches/01-desktop-file.patch --- qmidiarp-0.4.2/debian/patches/01-desktop-file.patch 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/debian/patches/01-desktop-file.patch 2012-01-31 00:03:44.000000000 +0000 @@ -0,0 +1,16 @@ +Description: + Patch removes encoding line from desktop file, + it is deprecated now. +Author: Jaromír Mikeš +Forwarded: yes + +Index: qmidiarp/qmidiarp.desktop +=================================================================== +--- qmidiarp.orig/qmidiarp.desktop 2012-01-31 00:00:21.569606723 +0100 ++++ qmidiarp/qmidiarp.desktop 2012-01-31 00:04:21.721600451 +0100 +@@ -1,5 +1,4 @@ + [Desktop Entry] +-Encoding=UTF-8 + Type=Application + Categories=AudioVideo;X-Sound;Midi;Audio;AudioVideoEditing;X-Jack;X-Midi; + Name=QMidiArp diff -Nru qmidiarp-0.4.2/debian/patches/02-man-pages.patch qmidiarp-0.4.5/debian/patches/02-man-pages.patch --- qmidiarp-0.4.2/debian/patches/02-man-pages.patch 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/debian/patches/02-man-pages.patch 2012-01-31 00:03:44.000000000 +0000 @@ -0,0 +1,76 @@ +Description: + Patch fix few syntax and spelling errors in man pages. +Author: Jaromír Mikeš +Forwarded: yes + +Index: qmidiarp/man/de/qmidiarp.1 +=================================================================== +--- qmidiarp.orig/man/de/qmidiarp.1 2012-01-31 00:33:29.000000000 +0100 ++++ qmidiarp/man/de/qmidiarp.1 2012-01-31 00:37:18.437548827 +0100 +@@ -46,7 +46,7 @@ + + .SS "Allgemeine Funktion" + Wenn keine Startoptionen angegeben werden, startet QMidiArp als JACK MIDI +-client mit einem MIDI-Eingang und zwei MIDI-Ausgängen. Durch die -a ++client mit einem MIDI\-Eingang und zwei MIDI\-Ausgängen. Durch die \-a + Option wird QMidiArp als ALSA client gestartet. + + Ein neuer Arpeggiator, Sequenzer oder LFO wird erzeugt durch Klicken auf +@@ -365,7 +365,7 @@ + Welle kann durch losgelassene Tasten gestoppt werden wenn + .B Note Off + Signal am Eingang mit dem entsprechenden +-.Kanal ++.B Kanal + empfangen wird. + .PP + .B "LFO Ausgangs-Feld" +Index: qmidiarp/man/fr/qmidiarp.1 +=================================================================== +--- qmidiarp.orig/man/fr/qmidiarp.1 2012-01-31 00:33:29.000000000 +0100 ++++ qmidiarp/man/fr/qmidiarp.1 2012-01-31 00:36:54.165549461 +0100 +@@ -51,7 +51,7 @@ + .SS "Fonctionnement Général" + Si aucune option est spécifiée au démarrage, QMidiArp utilise devient un + client JACK MIDI et cré un port d'entrée ainsi que deux ports de sortie. +-Si l'on démarre QMidiArp avec l'option -a, le système MIDI est ALSA. ++Si l'on démarre QMidiArp avec l'option \-a, le système MIDI est ALSA. + En cliquant sur les boutons + .B Nouvel Arpège..., Nouveau LFO... + ou +@@ -346,7 +346,7 @@ + être arrêtée en cas de touches relachées, donc à la réception d'un signal + .B Note Off + à l'entrée avec le +-.Canal ++.B Canal + correspondant. + .PP + .B "Le champ Sortie du LFO" +Index: qmidiarp/man/qmidiarp.1 +=================================================================== +--- qmidiarp.orig/man/qmidiarp.1 2012-01-31 00:33:29.000000000 +0100 ++++ qmidiarp/man/qmidiarp.1 2012-01-31 00:36:54.165549461 +0100 +@@ -49,7 +49,7 @@ + .SS "General Operation" + When no commandline options are given, QMidiArp starts as a JACK MIDI + client with an input port and two output ports. For starting QMidiArp as +-an ALSA client, use the -a option. ++an ALSA client, use the \-a option. + A new arpeggiator or LFO module can be created by + clicking one of the + .B Add Arp..., Add LFO... +@@ -434,11 +434,11 @@ + channel and port as the Seq module. + + .SS "Settings" +-The Settings window allows to configure if and to which port incoming ++The Settings window allows one to configure if and to which port incoming + events that do not match any module's input filter are forwarded ( + .B unmatched + events). It also +-allows to set whether incoming controller events are recognized for ++allows one to set whether incoming controller events are recognized for + muting and controlling + the modules separately. If this option is set, QMidiArp will recognize + MIDI control events that can be attributed to different parameters (see diff -Nru qmidiarp-0.4.2/debian/patches/series qmidiarp-0.4.5/debian/patches/series --- qmidiarp-0.4.2/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/debian/patches/series 2012-01-31 00:03:44.000000000 +0000 @@ -0,0 +1,2 @@ +01-desktop-file.patch +02-man-pages.patch diff -Nru qmidiarp-0.4.2/Doxyfile qmidiarp-0.4.5/Doxyfile --- qmidiarp-0.4.2/Doxyfile 2011-07-10 08:10:22.000000000 +0000 +++ qmidiarp-0.4.5/Doxyfile 2011-09-01 19:09:39.000000000 +0000 @@ -31,7 +31,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.4.2 +PROJECT_NUMBER = 0.4.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer @@ -327,7 +327,7 @@ # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. -EXTRACT_PRIVATE = YES +EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. @@ -375,7 +375,7 @@ # If set to NO (the default) these declarations will be included in the # documentation. -HIDE_FRIEND_COMPOUNDS = NO +HIDE_FRIEND_COMPOUNDS = YES # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. diff -Nru qmidiarp-0.4.2/examples/demo.qma qmidiarp-0.4.5/examples/demo.qma --- qmidiarp-0.4.2/examples/demo.qma 2011-01-03 22:25:02.000000000 +0000 +++ qmidiarp-0.4.5/examples/demo.qma 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -0 0 -0 0 0 -Arp 1 -0 1 -0 127 -0 127 -0 0 -51 63 0 -d(012)>h(123)>d(012)hh(23)(42)(12)(43)>d012342 -EOP -Arp 2 -0 1 -0 127 -0 127 -1 0 -59 70 0 -++01>h22 -EOP -Arp 3 -0 1 -0 127 -0 127 -2 0 -38 67 0 --0-0+0-0h+0-0 -EOP diff -Nru qmidiarp-0.4.2/examples/demo.qmax qmidiarp-0.4.5/examples/demo.qmax --- qmidiarp-0.4.2/examples/demo.qmax 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/examples/demo.qmax 2011-11-20 16:28:38.000000000 +0000 @@ -0,0 +1,115 @@ + + + + + 100 + + 1 + 0 + 0 + 0 + 1 + + + 0 + 0 + 0 + + + + + + + d(012)>h(123)>d(012)<d(234)>hh(23)(42)(12)(43)>d012342 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 51 + 63 + 0 + + + 0 + 0 + + + + + + ++01>h2<d3h4d3>2 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 59 + 70 + 0 + + + 0 + 0 + + + + + + -0-0+0-0h+0-0 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 38 + 67 + 0 + + + 0 + 0 + + + + + + 000000ff00000000fd00000002000000020000024900000105fc0100000008fc00000000000002520000000000fffffffa000000000200000001fb0000000a005300650071003a00310100000000ffffffff0000000000000000fc00000000000002280000000000fffffffa000000000100000001fb0000000a005300650071003a00330100000000ffffffff0000000000000000fb0000000a005300650071003a0032010000022e000002280000000000000000fc00000000000002420000000000fffffffa000000010100000002fb0000001800670072006f006f0076006500570069006400670065007402000000430000003e0000015700000088fb0000000a004c0046004f003a00320100000000ffffffff0000000000000000fb0000000a004100720070003a00320100000225000001540000000000000000fb0000000a004100720070003a00310100000000000002520000000000000000fb0000000a004c0046004f003a00310100000000000002520000000000000000fc00000000000002490000016a00fffffffa000000000100000003fb00000014004100720070003a0020004100720070002000310100000000ffffffff0000016a00fffffffb00000014004100720070003a0020004100720070002000320100000000ffffffff0000016a00fffffffb00000014004100720070003a0020004100720070002000330100000000ffffffff0000016a00ffffff0000000300000379000000e6fc0100000002fb00000012006c006f0067005700690064006700650074020000000c0000012100000194000001a9fb00000014007000610073007300570069006400670065007402000002b80000005800000190000000c8000002490000000100000004000000040000000800000008fc0000000100000002000000020000001600660069006c00650054006f006f006c0042006100720100000000ffffffff00000000000000000000001c0063006f006e00740072006f006c0054006f006f006c0042006100720100000084ffffffff0000000000000000 + + diff -Nru qmidiarp-0.4.2/examples/demo_up_down.qma qmidiarp-0.4.5/examples/demo_up_down.qma --- qmidiarp-0.4.2/examples/demo_up_down.qma 2011-01-03 22:25:02.000000000 +0000 +++ qmidiarp-0.4.5/examples/demo_up_down.qma 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -0 0 -0 0 0 -Arp 1 -0 1 -0 127 -0 127 -0 0 -51 70 100 ->>01 -EOP -Arp 2 -0 2 -0 127 -0 127 -0 0 -30 80 100 ->-0 -EOP -Arp 3 -0 1 -0 127 -0 127 -0 0 -30 90 100 ->>>++02 -EOP -Arp 4 -0 0 -0 127 -0 127 -0 0 -20 70 100 ---0011 -EOP diff -Nru qmidiarp-0.4.2/examples/demo_up_down.qmax qmidiarp-0.4.5/examples/demo_up_down.qmax --- qmidiarp-0.4.2/examples/demo_up_down.qmax 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/examples/demo_up_down.qmax 2011-11-20 16:28:57.000000000 +0000 @@ -0,0 +1,145 @@ + + + + + 100 + + 1 + 0 + 0 + 0 + 1 + + + 0 + 0 + 0 + + + + + + + >>01 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 51 + 70 + 100 + + + 0 + 0 + + + + + + >-0 + 2 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 30 + 80 + 100 + + + 0 + 0 + + + + + + >>>++02 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 30 + 90 + 100 + + + 0 + 0 + + + + + + --0011 + 0 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 20 + 70 + 100 + + + 0 + 0 + + + + + + 000000ff00000000fd00000002000000020000024900000140fc0100000008fc00000000000002520000000000fffffffa000000000200000001fb0000000a005300650071003a00310100000000ffffffff0000000000000000fc00000000000002280000000000fffffffa000000000100000001fb0000000a005300650071003a00330100000000ffffffff0000000000000000fb0000000a005300650071003a0032010000022e000002280000000000000000fc00000000000002420000000000fffffffa000000010100000002fb0000001800670072006f006f0076006500570069006400670065007402000000430000003e0000015700000088fb0000000a004c0046004f003a00320100000000ffffffff0000000000000000fb0000000a004100720070003a00320100000225000001540000000000000000fb0000000a004100720070003a00310100000000000002520000000000000000fb0000000a004c0046004f003a00310100000000000002520000000000000000fc00000000000002490000016a00fffffffa000000000100000004fb00000014004100720070003a0020004100720070002000310100000000ffffffff0000016a00fffffffb00000014004100720070003a0020004100720070002000320100000000ffffffff0000016a00fffffffb00000014004100720070003a0020004100720070002000330100000000ffffffff0000016a00fffffffb00000014004100720070003a0020004100720070002000340100000000ffffffff0000016a00ffffff0000000300000379000000e6fc0100000002fb00000012006c006f0067005700690064006700650074020000000c0000012100000194000001a9fb00000014007000610073007300570069006400670065007402000002b80000005800000190000000c8000002490000000000000004000000040000000800000008fc0000000100000002000000020000001600660069006c00650054006f006f006c0042006100720100000000ffffffff00000000000000000000001c0063006f006e00740072006f006c0054006f006f006c0042006100720100000084ffffffff0000000000000000 + + diff -Nru qmidiarp-0.4.2/examples/Makefile.am qmidiarp-0.4.5/examples/Makefile.am --- qmidiarp-0.4.2/examples/Makefile.am 2011-01-03 22:25:02.000000000 +0000 +++ qmidiarp-0.4.5/examples/Makefile.am 2011-11-20 16:30:43.000000000 +0000 @@ -2,5 +2,5 @@ examplesdatadir = $(pkgdatadir)/examples dist_examplesdata_DATA = \ - demo.qma demo_up_down.qma old_arp.qma demo_seqlfo.qmax \ + demo.qmax demo_up_down.qmax old_arp.qmax demo_seqlfo.qmax \ demo_seqlfo2.qmax diff -Nru qmidiarp-0.4.2/examples/Makefile.in qmidiarp-0.4.5/examples/Makefile.in --- qmidiarp-0.4.2/examples/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/examples/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -69,6 +69,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(examplesdatadir)" DATA = $(dist_examplesdata_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -200,7 +206,7 @@ top_srcdir = @top_srcdir@ examplesdatadir = $(pkgdatadir)/examples dist_examplesdata_DATA = \ - demo.qma demo_up_down.qma old_arp.qma demo_seqlfo.qmax \ + demo.qmax demo_up_down.qmax old_arp.qmax demo_seqlfo.qmax \ demo_seqlfo2.qmax all: all-am @@ -253,9 +259,7 @@ @$(NORMAL_UNINSTALL) @list='$(dist_examplesdata_DATA)'; test -n "$(examplesdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(examplesdatadir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(examplesdatadir)" && rm -f $$files + dir='$(DESTDIR)$(examplesdatadir)'; $(am__uninstall_files_from_dir) tags: TAGS TAGS: @@ -310,10 +314,15 @@ 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/examples/old_arp.qma qmidiarp-0.4.5/examples/old_arp.qma --- qmidiarp-0.4.2/examples/old_arp.qma 2011-01-03 22:25:02.000000000 +0000 +++ qmidiarp-0.4.5/examples/old_arp.qma 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -0 0 -0 0 0 -Arp 1 -0 1 -0 127 -0 127 -0 1 -0 0 0 ->>///////0\\\\\0+//////0\\\\\\\-00+0-00+0-00+0-00+0-0 -EOP diff -Nru qmidiarp-0.4.2/examples/old_arp.qmax qmidiarp-0.4.5/examples/old_arp.qmax --- qmidiarp-0.4.2/examples/old_arp.qmax 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/examples/old_arp.qmax 2011-11-20 16:29:47.000000000 +0000 @@ -0,0 +1,55 @@ + + + + + 100 + + 1 + 0 + 0 + 0 + 1 + + + 0 + 0 + 0 + + + + + + + >>///////0\\\\\0+//////0\\\\\\\-00+0-00+0-00+0-00+0-0 + 1 + 0 + 0 + + + 0 + 0 + 127 + 0 + 127 + + + 0 + 0 + 0 + + + 0 + 0 + 0 + + + 0 + 0 + + + + + + 000000ff00000000fd0000000200000002000001c6000000edfc0100000009fc00000000000002520000000000fffffffa000000000200000001fb0000000a005300650071003a00310100000000ffffffff0000000000000000fc00000000000002280000000000fffffffa000000000100000001fb0000000a005300650071003a00330100000000ffffffff0000000000000000fb0000000a005300650071003a0032010000022e000002280000000000000000fc00000000000002420000000000fffffffa000000010100000002fb0000001800670072006f006f0076006500570069006400670065007402000000430000003e0000015700000088fb0000000a004c0046004f003a00320100000000ffffffff0000000000000000fb0000000a004100720070003a00320100000225000001540000000000000000fb0000000a004100720070003a00310100000000000002520000000000000000fb0000000a004c0046004f003a00310100000000000002520000000000000000fc00000000000002490000000000fffffffa000000000100000002fb00000014004100720070003a0020004100720070002000320100000000ffffffff0000000000000000fb00000014004100720070003a0020004100720070002000330100000000ffffffff0000000000000000fb00000014004100720070003a0020004100720070002000310100000000000001c60000016a00ffffff0000000300000379000000e6fc0100000002fb00000012006c006f0067005700690064006700650074020000000c0000012100000194000001a9fb00000014007000610073007300570069006400670065007402000002b80000005800000190000000c8000001c60000000000000004000000040000000800000008fc0000000100000002000000020000001600660069006c00650054006f006f006c0042006100720100000000ffffffff00000000000000000000001c0063006f006e00740072006f006c0054006f006f006c0042006100720100000084ffffffff0000000000000000 + + diff -Nru qmidiarp-0.4.2/Makefile.in qmidiarp-0.4.5/Makefile.in --- qmidiarp-0.4.2/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -109,6 +109,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(applicationsdir)" \ "$(DESTDIR)$(svgdatadir)" DATA = $(dist_applications_DATA) $(dist_svgdata_DATA) @@ -155,6 +161,8 @@ DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -318,7 +326,7 @@ all: all-recursive .SUFFIXES: -am--refresh: +am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/aminclude.am $(am__configure_deps) @for dep in $?; do \ @@ -369,9 +377,7 @@ @$(NORMAL_UNINSTALL) @list='$(dist_applications_DATA)'; test -n "$(applicationsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(applicationsdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(applicationsdir)" && rm -f $$files + dir='$(DESTDIR)$(applicationsdir)'; $(am__uninstall_files_from_dir) install-dist_svgdataDATA: $(dist_svgdata_DATA) @$(NORMAL_INSTALL) test -z "$(svgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(svgdatadir)" @@ -389,9 +395,7 @@ @$(NORMAL_UNINSTALL) @list='$(dist_svgdata_DATA)'; test -n "$(svgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(svgdatadir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(svgdatadir)" && rm -f $$files + dir='$(DESTDIR)$(svgdatadir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -599,7 +603,7 @@ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir @@ -607,7 +611,7 @@ $(am__remove_distdir) dist-xz: distdir - tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir @@ -625,7 +629,7 @@ dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then @@ -658,6 +662,7 @@ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ @@ -686,8 +691,16 @@ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: - @$(am__cd) '$(distuninstallcheck_dir)' \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ @@ -721,10 +734,15 @@ installcheck: installcheck-recursive 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/man/de/Makefile.in qmidiarp-0.4.5/man/de/Makefile.in --- qmidiarp-0.4.2/man/de/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/man/de/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -69,6 +69,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(deman1datadir)" DATA = $(dist_deman1data_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -250,9 +256,7 @@ @$(NORMAL_UNINSTALL) @list='$(dist_deman1data_DATA)'; test -n "$(deman1datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(deman1datadir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(deman1datadir)" && rm -f $$files + dir='$(DESTDIR)$(deman1datadir)'; $(am__uninstall_files_from_dir) tags: TAGS TAGS: @@ -307,10 +311,15 @@ 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/man/de/qmidiarp.1 qmidiarp-0.4.5/man/de/qmidiarp.1 --- qmidiarp-0.4.2/man/de/qmidiarp.1 2011-06-03 14:24:46.000000000 +0000 +++ qmidiarp-0.4.5/man/de/qmidiarp.1 2011-12-22 09:13:38.000000000 +0000 @@ -1,4 +1,4 @@ -.\" +.\" .\" Handbuchseite für qmidiarp .\" zu bearbeiten mit: .\" groff -man -Tascii qmidiarp.1 | less @@ -6,7 +6,7 @@ .\" Eine Druckform kann erzeugt werden mit: .\" groff -t -e -mandoc -Tps qmidiarp.1 > qmidiarp.ps .\" -.TH QMIDIARP 1 2009-11-20 +.TH QMIDIARP 1 2011-11-10 .SH NAME qmidiarp \- MIDI Arpeggiator, Sequenzer und LFO @@ -14,18 +14,19 @@ .br .B qmidiarp [\fIOPTION\fR] [\fIfile\fR] -.br +.br .B qmidiarp { -.B \-\-help -| +.B \-\-help +| .B \-\-version } .SH BESCHREIBUNG QMidiArp -ist ein erweiterter Arpeggiator, Stepsequenzer und MIDI LFO für den -ALSA-Sequenzer. Er kann beliebig viele Module parallel ausführen. +ist ein erweiterter Arpeggiator, Stepsequenzer und MIDI LFO. Er kann +beliebig viele Module parallel ausführen. QMidiArp läuft je nach option +entweder mit JACK MIDI oder ALSA MIDI. Die Arpeggiatormodule erzeugen Sequenzen in Abhängigkeit von den Noten, die üblicherweise von einem MIDI-Keyboard oder einem Sequenzer an deren Eingang geschickt werden. Die Stepsequenzermodule sind angelehnt an die @@ -35,45 +36,50 @@ Dauer. Jedes Modul besitzt ein Filter für eingehende Noten und sein Ausgabeport bzw. Ausgabekanal kann frei eingestellt werden. Da die Module auf einer gemeinsamen Sequenzerschiene arbeiten, sind sie -automatisch zueinander synchron. QMidiArp arbeitet mit einer -internen Zeitauflösung von 192 ticks per beat. +automatisch zueinander synchron. QMidiArp arbeitet mit einer +internen Zeitauflösung von 192 ticks per beat. Die Queue kann mit einer externen MIDI-Echtzeituhr oder mit JACK Transport synchronisiert werden. -QMidiArp verfügt ebenso über ein Protokoll-Werkzeug, welches eingehende +QMidiArp verfügt ebenso über ein Protokoll-Werkzeug, welches eingehende MIDI Ereignisse abhängig von ihrem Typ in verschiedenen Farben darstellt. QMidiArp benutzt den Qt4 Toolkit. .SS "Allgemeine Funktion" +Wenn keine Startoptionen angegeben werden, startet QMidiArp als JACK MIDI +client mit einem MIDI-Eingang und zwei MIDI-Ausgängen. Durch die -a +Option wird QMidiArp als ALSA client gestartet. + Ein neuer Arpeggiator, Sequenzer oder LFO wird erzeugt durch Klicken auf .B Modul-->Neuer Arp..., Modul-->Neuer Sequenzer..., -oder -.B Modul-->Neuer LFO... -in der Werkzeugleiste oder im Menu +oder +.B Modul-->Neuer LFO... +in der Werkzeugleiste oder im Menu .I Modul. Ein neuer Reiter mit dem gewählten Modul erscheint im Hauptbedienfenster. -Module können mit den entsprechenden Symbolen der Werkzeugleiste oder +Module können mit den entsprechenden Symbolen der Werkzeugleiste oder Menüfunktionen umbenannt oder gelöscht werden. Die Module können vom Hauptfenster gelöst und parallel dargestellt und gesteuert werden. Hierzu klickt man auf das Symbol rechts oben in der Titelleiste jedes Moduls. Durch erneutes klicken dieses Symbols werden die Module wieder in die Reiterleiste eingefügt. Die Module können auch nebeneinander im Hauptfenster -angeordnet werden, wenn man das Hauptfenster vor dem Einfügen eines +angeordnet werden, wenn man das Hauptfenster vor dem Einfügen eines Moduls genügend vergrößert. Alle Einstellungen (d.h. alle Module, deren Parameter sowie alle sonstigen Änderungen, die unter .B Ansicht-->Einstellungen -getätigt wurden) können in einer QMidiArp-XML-Datei (.qmax) gespeichert -und von dort wieder geladen werden. Das -.B Tempo +getätigt wurden) können in einer QMidiArp-XML-Datei (.qmax) gespeichert +und von dort wieder geladen werden. Das +.B Tempo kann in beats pro Minute (BPM) eingestellt werden und gilt für alle Module. Die Queue wird mit dem blauen Pfeilsymbol gestartet/gestoppt. -.SS "MIDI-Clock-Betrieb" -QMidiArp kann eingehende MIDI-Realtime-Clock Signale als Taktquelle +.SS "MIDI-Clock-Betrieb" (nur mit ALSA MIDI verfügbar) +Im ALSA MIDI Modus benutzt QMidiArp sein eigenes Timing, kann aber +wahlweise eingehende MIDI-Realtime-Clock Signale als Taktquelle und Start/Stop-Signale verwenden. Sobald der -.B "MIDI-Uhr"-Knopf +.B "MIDI-Uhr"-Knopf rechts vom Tempo-Wahlfeld betätigt wird, wird der ALSA-Sequenzer gestoppt und QMidiArp @@ -81,39 +87,39 @@ die an QMidiArp's MIDI-Eingang angeschlossen wurde. Sobald dieses Signal eintrifft, wird die Sequenzerzeugung mit der MIDI-Taktvorgabe der externen Quelle gestartet. -Der Sequenzer/Arpeggiator hält an, sobald ein +Der Sequenzer/Arpeggiator hält an, sobald ein "MIDI Clock Stop"\-Signal empfangen wird. Während des -"MIDI-Clock-Betriebs" sind die QMidiArp-eigenen Start/Stop-Funktionen -sowie das Hinzufügen oder Laden weiterer Module gesperrt. Sie werden -erst bei erneutem Klick auf das MIDI-Uhrsymbol wieder verfügbar. Die -Synchronisation mit der externen Quelle funktioniert am besten, wenn das -.B Tempo -von QMidiArp mit dem der externen Quelle übereinstimmt. Das externe -Tempo wird jedoch bei laufendem Sequenzer gemessen, sodaß ab dem -zweiten Start die Synchronisation funktioniert, auch wenn das +"MIDI-Clock-Betriebs" sind die QMidiArp-eigenen Start/Stop-Funktionen +sowie das Hinzufügen oder Laden weiterer Module gesperrt. Sie werden +erst bei erneutem Klick auf das MIDI-Uhrsymbol wieder verfügbar. Die +Synchronisation mit der externen Quelle funktioniert am besten, wenn das +.B Tempo +von QMidiArp mit dem der externen Quelle übereinstimmt. Das externe +Tempo wird jedoch bei laufendem Sequenzer gemessen, sodaß ab dem +zweiten Start die Synchronisation funktioniert, auch wenn das ursprüngliche Tempo nicht übereinstimmt. .SS "JACK Transport Client-Betrieb" -Wird das -.B Jack Transport Connect +Wird das +.B Jack Transport Connect Icon angeklickt, so versucht QMidiArp eine Verbindung mit einem laufenden JACK server. Wenn diese gelingt, agiert QMidiArp als Jack Transport Client, d.h. das Tempo und die Synchronisierung wird von einem JACK Transport Master bereitgestellt. Hierbei startet QMidiArp seinen eigenen Sequenzer -neu bei jedem Jack Transport Start, unabhängig von der anfänglichen +neu bei jedem Jack Transport Start, unabhängig von der anfänglichen Transportposition. Dies gilt ebenfalls bei einer Schleife des JACK Transportbandes. Der Jack Betrieb wird automatisch deaktiviert, wenn kein -Jack server gefunden werden kann. +Jack server gefunden werden kann. .PP -Bemerkung: Die Zustände der MIDI Clock and Jack Transport Modi werden -beim Abspeichern in der QMidiArp Session Datei mit abgespeichert und -beim Öffnen dieser wiederhergestellt. +Bemerkung: Die Zustände der MIDI Clock and Jack Transport Modi werden +beim Abspeichern in der QMidiArp Session Datei mit abgespeichert und +beim Öffnen dieser wiederhergestellt. .SS "Arpeggiatormodule" QMidiArp's Arpeggiatormodule können komplexe Sequenzen produzieren, die von den auf dem Keyboard gespielten Noten abgeleitet werden. Die entstehende Sequenz hängt vom Arpeggio-Muster und von den Modulparametern ab. QMidiArp's -Arpeggiatoren wurden inspiriert durch den MAP1 hardware Arpeggiator von +Arpeggiatoren wurden inspiriert durch den MAP1 hardware Arpeggiator von Rudi Linhard. .PP .B Eingangs- and Ausgangsfelder @@ -123,30 +129,30 @@ und ein .B Ausgangs-Feld. Das Eingangsfeld definiert den Notenbereich und den MIDI-Kanal, für den -der jeweilige Arp empfänglich sein soll. +der jeweilige Arp empfänglich sein soll. Noten, die dieses Filter passieren, werden nach Tonhöhe sortiert dem internen Notenpuffer des Arpeggiators zugefügt. Noten, die nicht vom Filter erfasst werden, können entweder verworfen oder an einen bestimmten Port weitergeleitet werden (siehe -.B Ansicht-->Einstellungen). -Das Feld -.B Ausgang +.B Ansicht-->Einstellungen). +Das Feld +.B Ausgang enthält die Einstellungen für -.B MIDI-Kanal +.B MIDI-Kanal und -.B Ausgabeport, -an den der Arpeggiator seine Noten sendet. +.B Ausgabeport, +an den der Arpeggiator seine Noten sendet. .PP .B "Arpeggiator-Muster" .PP Arpeggio-Muster können im .B Muster- Feld gewählt und geändert werden. Bereits definierte -.B Arpeggio-Vorlagen +.B Arpeggio-Vorlagen können via Drop-Down-Menü ausgewählt werden. Das gerade aktive Muster wird im Stile einer "Piano-Stanzrolle" dargestellt, in der die Basisnoten als Streifen erscheinen. Die Position der Streifen in vertikaler Richtung -entspricht dem jeweiligen Notenwert. Oktavenübergänge (siehe +entspricht dem jeweiligen Notenwert. Oktavenübergänge (siehe .B Arpeggio-Vorlagen bearbeiten ) werden als hervorgehobenene horizontale Linien dargestellt. Die tatsächlich gesendeten Noten hängen ab von den empfangenen Eingangsnoten. @@ -154,13 +160,13 @@ Noten zugeordnet. Zum Beispiel bedeutet ein einzelner Streifen im unteren Teil der Grafik ("Simple"\-Muster), daß beim ersten Durchlauf durch das Muster die unterste empfangene Note gespielt wird. -Wenn ein Akkord auf dem Keyboard gespielt wird, und nur eine Note im -Muster definiert ist, wird beim ersten Durchlauf die unterste Note +Wenn ein Akkord auf dem Keyboard gespielt wird, und nur eine Note im +Muster definiert ist, wird beim ersten Durchlauf die unterste Note gespielt und die Noten der folgenden Durchläufe von dem eingestellten -"Wiederholungsmodus" bestimmt. -Wenn das Muster mehrere übereinander liegende Streifen enthält +"Wiederholungsmodus" bestimmt. +Wenn das Muster mehrere übereinander liegende Streifen enthält (Akkord-Modus), werden auf dem Keyboard gespielte Akkorde auch als -Akkorde gesendet. Die maximale Polyphonie der gesendeten Akkorde +Akkorde gesendet. Die maximale Polyphonie der gesendeten Akkorde entspricht der Anzahl der übereinander liegenden Streifen. .PP .B Wiederholungsmodus @@ -168,22 +174,22 @@ Der .B Wiederholungsmodus bestimmt das Verhalten der Arpeggios über mehrere Durchläufe des -Musters hinweg. Er ist entscheidend, wenn die Anzahl der auf dem Keyboard +Musters hinweg. Er ist entscheidend, wenn die Anzahl der auf dem Keyboard gespielten Noten die Anzahl der Noten im Muster übersteigt. Wenn -"Aufsteigend" gewählt ist, wird bei jedem Durchlauf die nächst höhere +"Aufsteigend" gewählt ist, wird bei jedem Durchlauf die nächst höhere Note des Keyboard-Akkordes gespielt. Ist "Absteigend" gewählt, so wird die nächst tiefere Note gespielt. Wenn nur eine Note im Muster vorhanden -ist, erzeugt dies ein klassisches lineares Arpeggio. So kann man selbst -mit einfachen Mustern wie "01" oder "0" ein komplettes Arpeggio leicht +ist, erzeugt dies ein klassisches lineares Arpeggio. So kann man selbst +mit einfachen Mustern wie "01" oder "0" ein komplettes Arpeggio leicht erzeugen. Wenn der Wiederholungsmodus "Statisch" gewählt ist, ist dieser klassische Arpeggio-Modus deaktiviert, und die gesendeten Noten -bleiben konstant. +bleiben konstant. .PP .B "Triggermodus (Verhalten bei neuer Stakato-Note)" .PP -QMidiArp's Arpeggiatoren besitzen drei Startmodi. Steht der Modus auf +QMidiArp's Arpeggiatoren besitzen drei Startmodi. Steht der Modus auf "Durchspielen", so läuft die Sequenz synchron zur internen oder externen -Uhr ununterbrochen weiter, unabhängig von dem Moment, in dem neue Tasten +Uhr ununterbrochen weiter, unabhängig von dem Moment, in dem neue Tasten gedrückt werden. Bei "Neustart" wird die Sequenzposition zum Start zurückgeschickt, wenn eine neue Taste stakato gespielt wird. Dies geschieht aber ohne das Timing des Sequenzers zu beeinflussen. Nur im @@ -194,7 +200,7 @@ .PP Die Arpeggio-Muster sind durch eine Text-Sequenz definiert, die einerseits die Noten selbst als Zahlen von 0...9 enthält, aber andererseits auch -Steuersymbole zur Änderung von Tempo, Anschlagsdynamik, Oktave und +Steuersymbole zur Änderung von Tempo, Anschlagsdynamik, Oktave und Akkord-Modus. Durch Anwählen des Symbols .B Muster bearbeiten im Muster-Feld macht man das momentane Muster als Text sichtbar und @@ -207,9 +213,9 @@ .B Muster löschen Symbols aus der Liste entfernt werden. Alle Muster-Vorlagen werden beim Speichern eines neuen Musters unmittelbar -in die .qmidiarprc Ressourcen-Datei geschrieben, und eventuell vorhandenen -weiteren Arpeggiatoren in der Reiterleiste zur Verfügung gestellt. -Die Vorlagenliste wird beim Starten von QMidiArp geladen. +in die .qmidiarprc Ressourcen-Datei geschrieben, und eventuell vorhandenen +weiteren Arpeggiatoren in der Reiterleiste zur Verfügung gestellt. +Die Vorlagenliste wird beim Starten von QMidiArp geladen. Die Syntax des Muster-Textes ist folgende: @@ -220,8 +226,8 @@ > : doppeltes Tempo < : halbes Tempo . : Standard-Tempo -( ) : Beginn und Ende des Akkord Modus, - z.B. erzeugt (012) einen Akkord der untersten drei Noten + ( ) : Beginn und Ende des Akkord Modus, + z.B. erzeugt (012) einen Akkord der untersten drei Noten / : Anschlag erhöhen um 20% \\ : Anschlag senken um 20% d : doppelte Notenlänge @@ -230,37 +236,37 @@ Die Wirkung Steuersymbole bleibt bis zum Ende eines Muster-Durchlaufes bestehen. Das Symbol > erhöht zum Beispiel das Tempo aller folgenden -Noten im Muster bis zu seinem Ende. Beim nächsten Durchlauf des Musters +Noten im Muster bis zu seinem Ende. Beim nächsten Durchlauf des Musters wird das Tempo dann wieder auf seinen Ausgangswert (Viertelnoten) -geschaltet. +geschaltet. .PP .B Zufallsfunktion .PP Das Timing, der Anschlag und die Länge der gesendeten Noten können mit -Hilfe der Zufallsfunktionen zu Abweichungen gebracht werden. Diese +Hilfe der Zufallsfunktionen zu Abweichungen gebracht werden. Diese werden mit den entsprechenden Reglern im Feld .B Zufall eingestellt. Man kann dadurch den Arpeggiator weniger mechanisch -klingen lassen. Bei höheren Werten erzeugt man interessante Akzente -innerhalb der Muster. +klingen lassen. Bei höheren Werten erzeugt man interessante Akzente +innerhalb der Muster. .PP .B Hüllkurve .PP -QMidiArp kann der Anschlagsdynamik der Arpeggios eine Hüllkurve +QMidiArp kann der Anschlagsdynamik der Arpeggios eine Hüllkurve überlagern, um langsame Übergänge von Akkordmustern zu erzeugen. -Die Funktion dieser Hüllkurve wird durch -.B Attack +Die Funktion dieser Hüllkurve wird durch +.B Attack \-Zeit und .B Release \-Zeit definiert. Wird eine von Null verschiedene Attackzeit gewählt, so -werden die Anschläge der gesendeten Noten während der Attackzeit von +werden die Anschläge der gesendeten Noten während der Attackzeit von Null bis zu ihrem eigentlichen Wert hochgefahren. Ist eine Releasezeit -verschieden von Null eingestellt, so werden die losgelassenen Noten -weiterhin gesendet, und ihre Anschlagsdynamik wird während der -Releasezeit auf Null heruntergefahren. Erst dann wird die Note aus dem -internen Puffer entfernt. Die Hüllkurven-Funktion hat nur dann Wirkung, -wenn der angesteuerte Klang anschlagsempfindlich ist. Sie funktioniert -am besten mit Mustern mit hoher Polyphonie, zum Beispiel "Chord Oct 16 A". +verschieden von Null eingestellt, so werden die losgelassenen Noten +weiterhin gesendet, und ihre Anschlagsdynamik wird während der +Releasezeit auf Null heruntergefahren. Erst dann wird die Note aus dem +internen Puffer entfernt. Die Hüllkurven-Funktion hat nur dann Wirkung, +wenn der angesteuerte Klang anschlagsempfindlich ist. Sie funktioniert +am besten mit Mustern mit hoher Polyphonie, zum Beispiel "Chord Oct 16 A". .PP .B Groove .PP @@ -268,13 +274,13 @@ .B Groove \-Regler erlauben es, Noten innerhalb eines Taktes linear zu verschieben in ihrer Zeit, Länge und ihrem Anschlag. Dies kann benutzt werden, um -Swing-Rythmen und Akzente zu erzeugen, oder um den Akzent auf eine -bestimmte Stelle jedes Taktes zu setzen. Die Groove-Einstellungen gelten +Swing-Rythmen und Akzente zu erzeugen, oder um den Akzent auf eine +bestimmte Stelle jedes Taktes zu setzen. Die Groove-Einstellungen gelten für alle Arpeggios in der Reiterleiste. .SS "LFO-Module" Parallel zu den Arpeggiatoren kann QMidiArp auch MIDI-Steuerdaten in Form -von Niederfrequenz-Oszillatoren (LFOs) an einen zugeordneten Ausgang +von Niederfrequenz-Oszillatoren (LFOs) an einen zugeordneten Ausgang schicken. Die LFO-Daten bestehen aus MIDI-Controller-Signalen, die mit den Arpeggiator-Sequenzen synchron sind. Der Sequenzer muss gestartet werden, damit die LFOs Daten produzieren. Jedes LFO-Modul hat ein @@ -283,9 +289,9 @@ .B Ausgangs- Feld, um den MIDI-Kanal, ALSA-Ausgangsport und die ID des zu erzeugenden Controllers einzustellen. Die folgenden Wellenformen stehen im Moment -zur Verfügung: Sinus, Sägezahn steigend, Dreieck, Sägezahn fallend, -Rechteck und Frei. -Die +zur Verfügung: Sinus, Sägezahn steigend, Dreieck, Sägezahn fallend, +Rechteck und Frei. +Die .B Frequenz der LFOs wird in Vielfachen und Teilern des Sequenzer- .B Tempos @@ -294,16 +300,16 @@ als 1 gewählt werden, muss auch die .B Länge der Wellenform angepaßt werden, um eine volle Welle zu erzeugen. Die -zeitliche +zeitliche .B Auflösung -der LFOs bestimmt die Anzahl der Signale, die in jedem Vierteltakt -ausgegeben werden. Die höchste Auflösung beträgt 192 Signale pro +der LFOs bestimmt die Anzahl der Signale, die in jedem Vierteltakt +ausgegeben werden. Die höchste Auflösung beträgt 192 Signale pro Vierteltakt. Niedrige Werte der .B Auflösung führen zu hörbar rythmischen Controller-Änderungen, während höhere Auflösungen zu mehr und mehr kontinuierlichen Wellenformen führen. -.B Amplitude +.B Amplitude und .B Offset der Wellenform können von 0...127 eingestellt werden. @@ -313,7 +319,7 @@ .PP Einzelne Punkte der Wellenform kann man mit der .I rechten Maustaste -stumm schalten. Stummgeschaltete Wellenform-Punkte erscheinen in +stumm schalten. Stummgeschaltete Wellenform-Punkte erscheinen in dunklerer Farbe. .PP .B Freie Wellenform @@ -323,64 +329,90 @@ gewählt wird, kann die Wellenform mit der .I linken Maustaste in der Wellenform-Graphik gezeichnet werden. Beim Modifizieren einer -errechneten Wellenform wird diese automatisch in die freie Form kopiert. Dies überschreibt die vorhergehende freie Wellenform mit -der gerade dargestellten Form. Wie alle LFO-Funktionen kann auch das +errechneten Wellenform wird diese automatisch in die freie Form kopiert. +Dies überschreibt die vorhergehende freie Wellenform mit +der gerade dargestellten Form. Wie alle LFO-Funktionen kann auch das Zeichnen oder Stummschalten bei laufendem Sequenzer geschehen. .PP +.B Abspielrichtung und Wiederholungsmodus +.PP +Die folgenden Abspielmodi stehen zur Verfügung + + ->_> : Vorwärts und wiederholen + <_<- : Rückwärts und wiederholen + ->_< : Hin und her und wiederholen + >_<- : Her und hin und wiederholen + ->_| : Forwärts Einzeldurchlauf + |_<- : Rückwärts Einzeldurchlauf + +Die Änderungen des Abspielmodus werden sofort angewandt. + +.PP .B Aufnahme .PP -Controller-Daten, die das Filter im Eingang passieren, können +Controller-Daten, die das Filter im Eingang passieren, können kontinuierlich aufgezeichnet werden durch wählen des .B Aufnehmen Knopfes. Dieser Knopf ist selbst über MIDI ansteuerbar (siehe MIDI Learn) und QMidiArp wird somit zu einem einfachen Control-Looper/Sampler. - +.PP +.B LFO Eingangsfeld +Im Eingangsfeld kann man den +.B MIDI CC +wählen der aufzunehmen ist. Man kann außerdem einstellen, wie der LFO +auf eingehende Noten reagiert. So wie die Arpeggiatoren kann der +LFO bei Notenempfang neugestartet oder getriggert werden, und die LFO +Welle kann durch losgelassene Tasten gestoppt werden wenn +.B Note Off +Signal am Eingang mit dem entsprechenden +.Kanal +empfangen wird. .PP .B "LFO Ausgangs-Feld" .PP Das LFO Ausgangs-Feld enthält die Einstellungen für -.B Ausgang, +.B Ausgang, .B Kanal -und -.B Controller -ID der LFO-Daten jedes LFO-Reiters. Es erlaubt auch ein komplettes -Stummschalten jedes LFOs durch Klicken des -.B Stumm +und +.B Controller +ID der LFO-Daten jedes LFO-Reiters. Es erlaubt auch ein komplettes +Stummschalten jedes LFOs durch Klicken des +.B Stumm Knopfes. .SS "Step-Sequenzer-Module" Durch klicken auf -.B "Neuer Sequenzer..." +.B "Neuer Sequenzer..." in der Werkzeugleiste wird ein neues -.B Seq +.B Seq Modul hinzugefügt. Jedes dieser Module erzeugt eine einfache, lineare und monophone Sequenz, ähnlich wie die ersten Hardware-Analogsequenzer. -So wie die LFOs sind auch die Seq Module bei laufendem Sequenzer -steuerbar, ebenfalls ähnlich einem analogen Stepsequenzer. +So wie die LFOs sind auch die Seq Module bei laufendem Sequenzer +steuerbar, ebenfalls ähnlich einem analogen Stepsequenzer. .PP .B Programmieren einer Sequenz .PP -So wie bei den LFO-Modulen, kann man Sequenzen programmieren, in dem man -mit der linken Maustaste in der grafischen Darstellung jede Notenhöhe +So wie bei den LFO-Modulen, kann man Sequenzen programmieren, in dem man +mit der linken Maustaste in der grafischen Darstellung jede Notenhöhe einstellt. Es steht ein Notenbereich von 4 Oktaven zur Verfügung, wobei die niedrigste Note ein C2 ist, wenn die globale Stimmung auf Null steht. -Die +Die .B Länge der Sequenz kann zwischen 1 und 8 Vierteltakten liegen. Die -zeitliche -.B Auflösung +zeitliche +.B Auflösung wird zwischen 1 und 16 Noten pro Vierteltakt eingestellt. Eine Auflösung von 4 bedeutet daher, daß der Sequenzer Sechzehntel-Noten spielt. Eine Sequenz kann ebenfalls direkt über eine Tastatur eingegeben werden -mit Hilfe der +mit Hilfe der .B Aufnahme Funktion. Durch Anklicken des .B Aufnahme Knopfes werden auf einer angeschlossenen Tastatur gespielte Noten Schritt -für Schritt aufgenommen, beginnend mit der zuletzt geänderten Note in +für Schritt aufgenommen, beginnend mit der zuletzt geänderten Note in der Sequenz. Hierzu muß der Noteneingang des Moduls aktiviert sein. Die -Programmierung kann auch bei laufendem Sequenzer geschehen. +Programmierung kann auch bei laufendem Sequenzer geschehen. .PP .B Regler für alle Noten @@ -399,19 +431,19 @@ .B Eingangs-Feld bestimmen, wie die über den einstellbaren MIDI- .B Kanal -empfangenen Noten verarbeitet werden. Wenn +empfangenen Noten verarbeitet werden. Wenn .B Note -angekreuzt ist, wird die komplette Sequenz beim nächsten Durchlauf auf +angekreuzt ist, wird die komplette Sequenz beim nächsten Durchlauf auf die Tonhöhe der empfangenen Note transponiert. Wenn zusätzlich .B Anschlag angekreuzt ist, werden auch die Anschlagsdynamik-Daten der empfangenen Noten auf die Sequenz übertragen, und die gesendeten Noten bekommen dieselbe Anschlagsdynamik wie die auf der Tastatur gespielte Note. -Weitere Optionen des Eingangsfeldes steuern das Start- und -Stop-Verhalten der Sequenz beim Empfang von Noten. +Weitere Optionen des Eingangsfeldes steuern das Start- und +Stop-Verhalten der Sequenz beim Empfang von Noten. .B Neustart -verursacht ein Zurücksetzen der Sequenz an den Start, jedoch ohne den -Rhythmus zu unterbrechen. Nur wenn +verursacht ein Zurücksetzen der Sequenz an den Start, jedoch ohne den +Rhythmus zu unterbrechen. Nur wenn .B Trigger angewählt ist, startet die Sequenz exakt mit dem Timing der angeschlagenen Note. @@ -425,7 +457,7 @@ .B Ausgangs-Feld der Seq-Module ist das gleiche wie das der Arpeggiator- oder LFO-Module. .PP -Man kann die Sequenz mit Akzenten versehen, wenn man zusätzlich ein +Man kann die Sequenz mit Akzenten versehen, wenn man zusätzlich ein LFO-Modul aufbaut, welches an denselben Kanal und Ausgang zum Beispiel Filterfrequenz-Controller schickt (CC#74). @@ -434,16 +466,16 @@ diejenigen Signale weitergeleitet werden, die von keinem der Module verarbeitet werden ( .B unpassende -Signale). Hier wird auch bestimmt, ob empfangene MIDI Steuersignale -(Control events) benutzt werden, um die Module zu steuern (siehe +Signale). Hier wird auch bestimmt, ob empfangene MIDI Steuersignale +(Control events) benutzt werden, um die Module zu steuern (siehe B.MIDI-Steuerung). Durch Ankreuzen des Kästchens .B Kompakte Darstellung der Module -werden alle folgenden erzeugten Module in einer Platzsparenden Art +werden alle folgenden erzeugten Module in einer Platzsparenden Art dargestellt, um eine bessere Parallel-Darstellung auf dem Schreibtisch zu ermöglichen. .PP -Die -.B Einstellungen +Die +.B Einstellungen werden zusammen mit den Moduldaten in der .qmax-Datei gespeichert. .SS MIDI-Steuerung @@ -451,23 +483,21 @@ .B Module steuerbar über MIDI Controller im .B Einstellungen -Fenster aktiviert ist. Für die folgenden Parameter ist eine MIDI-Steuerung -möglich. Seq-Module: Stummschaltung, Anschlag und Notenlänge. LFO-Module: -Stummschaltung, Amplitude und Offset. Arp-Module: Stummschaltung. +Fenster aktiviert ist. .PP .B Lernen von MIDI .PP -Die Steuerungen werden durch Rechtsklick auf ein entsprechendes -Steuerelement zugeordnet. Durch Auswählen von +Die Steuerungen werden durch Rechtsklick auf ein entsprechendes +Steuerelement zugeordnet. Durch Auswählen von .B Lernen von MIDI wartet QMidiArp auf ein MIDI-Steuerungssignal, was zum Beispiel von einem -angeschlossenen Controller gesendet wird. Das erste eingehende +angeschlossenen Controller gesendet wird. Das erste eingehende Steuerungssignal wird dann dem entsprechenden Element zugeordnet. Es können auch mehrere MIDI-Steuerungen einem einzelnen Element zugeordnet -werden. -Wird +werden. +Wird .B MIDI-Steuerungen vergessen -ausgewählt, so werden alle Zuordnungen entfernt. Durch Auswahl von +ausgewählt, so werden alle Zuordnungen entfernt. Durch Auswahl von .B MIDI Lernen abbrechen wird der Lernprozeß beendet. .PP @@ -475,57 +505,57 @@ interpretiert, d.h. bei jedem eingehenden Controller-Wert von 127 wird der Stummschaltungsknopf umgeschaltet. Dies kann im .B Steuerungseditor -nachfolgend geändert werden. +nachfolgend geändert werden. .PP .B Steuerungs-Editor .PP -Dieses Fenster wird durch Auswahl von +Dieses Fenster wird durch Auswahl von .B MIDI-Steuerungen -im +im .I Ansicht Menu geöffnet. Jede zugeordnete Steuerung kann in der dargestellten Tabelle geändert oder entfernt werden. Die Stummschaltungs-Funktion -hat hierbei eine Besonderheit. Wenn die min und max Werte +hat hierbei eine Besonderheit. Wenn die min und max Werte .I identisch -sind, so wird die Stummschaltung -.I umgeschaltet, -wenn der eingestellte Wert von dem zugeordneten Controller übermittelt -wird. Sind min und max voneinander +sind, so wird die Stummschaltung +.I umgeschaltet, +wenn der eingestellte Wert von dem zugeordneten Controller übermittelt +wird. Sind min und max voneinander .I verschieden, so wird das entsprechende Modul beim Eingehen des min-Wertes -stummgeschaltet und bei Eingehen des max-Wertes lautgeschaltet. +stummgeschaltet und bei Eingehen des max-Wertes lautgeschaltet. .PP Bei klicken auf .B Entfernen wird die ausgewählte Zeile aus der Tabelle entfernt. .B Wiederherstellen lädt die momentane Steuerungsbelegung neu. -.B Cancel -verläßt den Steuerungseditor und verwirft die Änderungen, und nur durch +.B Cancel +verläßt den Steuerungseditor und verwirft die Änderungen, und nur durch klicken auf .B OK werden die Änderungen wirksam. .SS "Protokoll" Das Protokoll-Fenster zeichnet empfangene MIDI-Daten mit Zeitinformation -auf und stellt diese als Liste dar. -Das -.I Protokoll +auf und stellt diese als Liste dar. +Das +.I Protokoll wird zu Beginn am unteren Ende des Programmfensters angezeigt und kann verborgen oder als separates Fenster frei beweglich auf der Arbeitsfläche platziert werden. Das Aufzeichnen der MIDI-Signale kann generell abgeschaltet oder auch selektiv für Signale der MIDI-Echtzeituhr -eingeschaltet werden. +eingeschaltet werden. .SS Beispieldateien Es gibt zurzeit drei Beispiel-Arpeggios. Das Arpeggio demo.qma ist ursprünglich für die folgende Klang-Auswahl -gedacht: Ch 1: Marimba, Ch 2: Celesta, Ch 3: Acoustic Bass, +gedacht: Ch 1: Marimba, Ch 2: Celesta, Ch 3: Acoustic Bass, aber man kann interessante Ergebnisse auch mit einer anderen Instrument- Belegung erhalten. .PP -Das demo_seqlfo.qmax Beispiel zeigt die parallele Benutzung der neuen +Das demo_seqlfo.qmax Beispiel zeigt die parallele Benutzung der neuen Sequenzer- und LFO-Module. Die Ausgänge sollten an perkussive Synthesizer Sounds geschickt werden. Die LFOs sind für eine Filterfrequenz-Steuerung vorgesehen, die über den MIDI-Standard-Controller #CC74 geschieht. @@ -545,17 +575,20 @@ .BI \-\-version Gibt die Programmversion aus und beendet das Programm. .TP +.BI \-\-alsa +ALSA MIDI Treiber verwenden +.TP +.BI \-\-jack +JACK MIDI Treiber verwenden (default) +.TP .B Datei Name einer QMidiArp-Datei (.qmax) zu Öffnen beim Start des Programms. .SH DATEIEN .I *.qmax .RS -QMidiArp-XML-Dateien, enthalten Daten aller Module sowie Einstellungen +QMidiArp-XML-Dateien, enthalten Daten aller Module sowie Einstellungen im XML-Textformat. -.RE -.I *.qma -.RS -Ehemalige QMidiArp-Dateien in einem reinen Textformat. + .SH BEISPIELE Eine Beispieldatei kann in einem der folgenden Verzeichnisse gefunden werden: @@ -563,13 +596,13 @@ oder .I /usr/local/share/qmidiarp .SH BEMERKUNGEN -Fehler und Warnungen werden nach +Fehler und Warnungen werden nach .BR stderr (3) geschrieben. .SH UNTERSTÜTZUNG qmidiarp-devel@lists.sourceforge.net .SH AUTOREN -Frank Kober and Guido Scholz, Matthias Nagorni. Das Original dieser -Handbuchseite wurde von Frank Kober +Frank Kober, Nedko Arnaudov, Guido Scholz, Matthias Nagorni. Das Original +dieser Handbuchseite wurde von Frank Kober geschrieben; die deutsche Übersetzung wurde von Robert Dietrich angefertigt. diff -Nru qmidiarp-0.4.2/man/fr/Makefile.in qmidiarp-0.4.5/man/fr/Makefile.in --- qmidiarp-0.4.2/man/fr/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/man/fr/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -69,6 +69,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(frman1datadir)" DATA = $(dist_frman1data_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -250,9 +256,7 @@ @$(NORMAL_UNINSTALL) @list='$(dist_frman1data_DATA)'; test -n "$(frman1datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(frman1datadir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(frman1datadir)" && rm -f $$files + dir='$(DESTDIR)$(frman1datadir)'; $(am__uninstall_files_from_dir) tags: TAGS TAGS: @@ -307,10 +311,15 @@ 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/man/fr/qmidiarp.1 qmidiarp-0.4.5/man/fr/qmidiarp.1 --- qmidiarp-0.4.2/man/fr/qmidiarp.1 2011-05-29 18:18:19.000000000 +0000 +++ qmidiarp-0.4.5/man/fr/qmidiarp.1 2011-12-22 09:14:38.000000000 +0000 @@ -1,4 +1,4 @@ -.\" +.\" .\" Page de manuel pour qmidiarp .\" Traiter avec: .\" groff -man -Tascii qmidiarp.1 | less @@ -6,7 +6,7 @@ .\" Une version imprimable peut être obtenue par: .\" groff -t -e -mandoc -Tps qmidiarp.1 > qmidiarp.ps .\" -.TH QMIDIARP 1 2009-11-06 +.TH QMIDIARP 1 2011-11-10 .SH NOM qmidiarp \- Arpégiateur et LFO MIDI pour le séquenceur ALSA @@ -14,51 +14,55 @@ .br .B qmidiarp [\fIOPTION\fR] [\fIfile\fR] -.br +.br .B qmidiarp { -.B \-\-help -| +.B \-\-help +| .B \-\-version } .SH DESCRIPTION QMidiArp -est un arpégiateur, séquenceur linéaire programmable et oscillateur à -basse fréquence (LFO) MIDI avancé pour le séquenceur ALSA. Un -nombre illimité d'arpégiateurs, séquenceurs et LFOs peuvent être définis -comme modules pour fonctionner en parallèle. Les modules arpégiateurs +est un arpégiateur, séquenceur linéaire programmable et oscillateur à +basse fréquence (LFO) MIDI avancé. Selon l'option choisi il utilise +JACK MIDI ou ALSA MIDI. Un +nombre illimité d'arpégiateurs, séquenceurs et LFOs peuvent être définis +comme modules pour fonctionner en parallèle. Les modules arpégiateurs produisent des séquences de notes dépendant des notes reçues sur leur -port d'entrée, qui est typiquement connecté à un clavier MIDI ou un -séquenceur. Les modules séquenceurs sont similaires aux premiers +port d'entrée, qui est typiquement connecté à un clavier MIDI ou un +séquenceur. Les modules séquenceurs sont similaires aux premiers séquenceurs analogiques, linéaires, monophoniques et ajustables en étant en marche. Les LFOs MIDI, de manière indépendante, produisent des données de contrôleur MIDI avec forme d'onde, résolution temporelle, amplitude et durée ajustables. Pour chaque module, un filtre d'entrée -est disponible. Le port de sortie et le canal MIDI peuvent être -attribués pour chaque module indépendamment. Puisque les modules +est disponible. Le port de sortie et le canal MIDI peuvent être +attribués pour chaque module indépendamment. Puisque les modules utilisent un séquenceur commun, ils sont automatiquement synchronisés entre eux. QMidiArp fonctionne avec une résolution interne de 192 ticks -par quart de mesure (beat). La queue peut être synchronisée à une +par quart de mesure (beat). La queue peut être synchronisée à une horologe MIDI entrant ou en tant que client JACK Transport. La plupart -des contrôles de QMidiArp est accessible par contrôle MIDI via un -mécanisme d'apprentissage par menu contextuel. +des contrôles de QMidiArp est accessible par contrôle MIDI via un +mécanisme d'apprentissage par menu contextuel. QMidiArp possède également un outil de journalisation d'évênements MIDI -entrants. +entrants. QMidiArp utilise les bibliothèques du kit Qt4. .SS "Fonctionnement Général" +Si aucune option est spécifiée au démarrage, QMidiArp utilise devient un +client JACK MIDI et cré un port d'entrée ainsi que deux ports de sortie. +Si l'on démarre QMidiArp avec l'option -a, le système MIDI est ALSA. En cliquant sur les boutons -.B Nouvel Arpège..., Nouveau LFO... +.B Nouvel Arpège..., Nouveau LFO... ou .B Nouveau Séquenceur... le module choisi apparaît en tant qu'onglet dans la zone principale. Les modules peuvent être renommés ou supprimés avec les boutons et fonctions de menu correspondants. Le montage entier contenant tous les arpèges et -LFOs de la barre d'onglets ainsi que les définitions de la -fenêtre -.B Paramètres -peuvent être sauvegardées dans un fichier XML QMidiArp (.qmax). Les +LFOs de la barre d'onglets ainsi que les définitions de la +fenêtre +.B Paramètres +peuvent être sauvegardées dans un fichier XML QMidiArp (.qmax). Les modules peuvent être détachées en tant que fenêtres indépendantes pour les contrôler et visualiser en parallèle. Le .B tempo @@ -66,41 +70,41 @@ en unités de beats par minute (bpm). La queue du séquenceur est démarrée en cliquant sur le bouton indiquant une flêche bleue. -.SS "Fonctionnement en mode MIDI Clock" -QMidiArp peut utiliser les évênements MIDI clock entrant en tant +.SS "Fonctionnement en mode MIDI Clock" (disponible uniquement pour ALSA) +QMidiArp peut utiliser les évênements MIDI clock entrant en tant que source d'horologe et de contrôle start/stop. -Si le +Si le .B bouton MIDI clock -à droite de la boîte de réglage du tempo est enfoncé, +à droite de la boîte de réglage du tempo est enfoncé, la queue du séquenceur est arrêtée et QMidiArp attendra la réception d'un évênement "MIDI Clock Start" d'une source -externe connectée à son entrée MIDI. Une fois cet évênement reçu, +externe connectée à son entrée MIDI. Une fois cet évênement reçu, la queue est démarrée en utilisant les évênements d'horologe MIDI comme source. La synchronisation fonctionne au mieux si le tempo de la source externe correspond à peu près à celui de QMidiArp. La queue s'arrêtera sur réception d'un évênement MIDI Clock Stop. Pendant le fonctionnement -en mode MIDI Clock, les fonctions internes de start/stop ainsi que -l'ajout ou le chargement de fichiers sont desactivées. Elles sont -réactivées en cliquant sur le bouton MIDI Clock à nouveau. +en mode MIDI Clock, les fonctions internes de start/stop ainsi que +l'ajout ou le chargement de fichiers sont desactivées. Elles sont +réactivées en cliquant sur le bouton MIDI Clock à nouveau. .SS "Fonctionnement en tant que client JACK Transport" -Lorsqu'on appuye sur le bouton +Lorsqu'on appuye sur le bouton .B Connecter à Jack Transport, -QMidiArp essaiera de se connecter à un serveur JACK en marche. Il +QMidiArp essaiera de se connecter à un serveur JACK en marche. Il fonctionnera ensuite en tant que client Jack Transport, c'est à dire, le -tempo sera déduit d'un maître Jack Transport et la synchronisation sera -maintenue. Le séquenceur de QMidiArp redémarrera à zéro à chaque fois +tempo sera déduit d'un maître Jack Transport et la synchronisation sera +maintenue. Le séquenceur de QMidiArp redémarrera à zéro à chaque fois que le maître Jack transport est mis en marche, indépendamment de la position initiale de Jack Transport. Ceci s'applique également quand Jack -Transport fonctionne en boucle. Le bouton Jack Transport se relâche -automatiquement lors d'une déconnextion de Jack, par exemple si Jack -n'est plus actif. +Transport fonctionne en boucle. Le bouton Jack Transport se relâche +automatiquement lors d'une déconnextion de Jack, par exemple si Jack +n'est plus actif. .PP Note: Les états des boutons MIDI Clock et Jack Transport sont sauvegardés dans le fichier de session QMidiArp à chaque enregistrement et deviennent -actifs ou inactifs à chaque ouverture d'une session. +actifs ou inactifs à chaque ouverture d'une session. .SS "Les Modules Arpégiateur" Les arpégiateurs de QMidiArp produisent des séquences de notes qui @@ -110,86 +114,86 @@ .PP .B Les champs Entrée et Sortie .PP -Chaque arpégiateur possède un champ +Chaque arpégiateur possède un champ .B Entrée et un champ .B Sortie. Le champ d'entrée définit la gamme de notes et le canal MIDI auxquels l'arpeggiator est assigné. Les notes qui passent par ce filtre sont -triées par leur hauteur et ajoutées au tampon interne de notes de -l'arpégiateur. Les notes ne passant par aucun filtre peuvent être -acheminées à un port MIDI défini dans la fenêtre +triées par leur hauteur et ajoutées au tampon interne de notes de +l'arpégiateur. Les notes ne passant par aucun filtre peuvent être +acheminées à un port MIDI défini dans la fenêtre .B Paramètres -ou ignorées. Le champ +ou ignorées. Le champ .B Sortie -contient les réglages du +contient les réglages du .B canal MIDI -et du -.B port de sortie +et du +.B port de sortie auxquels les notes de l'arpège seront envoyées. .PP .B "Motifs d'arpège" .PP Le motif de l'arpège peut être sélectionné et édité dans le champ .B Motif. -Les motifs prédéfinis -.B (presets) +Les motifs prédéfinis +.B (presets) sont accessibles d'un menu déroulant. Le motif actif est affiché dans un écran dédié montrant les notes de base comme traits. L'échelle verticale -de cet écran correspond à l'index des notes dans le motif. Les +de cet écran correspond à l'index des notes dans le motif. Les changements d'octave (voir .B Editer les motifs d'arpège) -sont affichés comme des séparateurs horizontaux supplémentaires. Les -notes sortant de l'arpéggiateur dépendent des notes reçues à l'entrée, -qui sont attribuées par ordre ascendant aux notes de base définies dans -le motif. Par exemple, un trait unique en bas de l'écran d'affichage +sont affichés comme des séparateurs horizontaux supplémentaires. Les +notes sortant de l'arpéggiateur dépendent des notes reçues à l'entrée, +qui sont attribuées par ordre ascendant aux notes de base définies dans +le motif. Par exemple, un trait unique en bas de l'écran d'affichage (presets "simple") signifie qu'au premier passage, la note la plus basse jouée sur le clavier est produite. Si plusieurs notes sont appuyées sur -le clavier et si seulement une note est présente dans le motif, c'est le -.B mode de répétition -qui détermine la séquence de notes jouées à la sortie. Si le motif -contient des traits de note empîlés (mode accord), les accords joués sur -le clavier deviennent aussi des accords à la sortie avec une polyphonie +le clavier et si seulement une note est présente dans le motif, c'est le +.B mode de répétition +qui détermine la séquence de notes jouées à la sortie. Si le motif +contient des traits de note empîlés (mode accord), les accords joués sur +le clavier deviennent aussi des accords à la sortie avec une polyphonie dans la limite du nombre de notes définies dans cette pîle. .PP .B Mode de répétition .PP -Le mode de répétition +Le mode de répétition définit le comportement de l'arpège sur plusieurs répétitions du motif quand le nombre de notes jouées sur le clavier dépasse le nombre de notes présentes dans le motif, par exemple avec une seule note dans le motif mais un accord de trois notes joué sur le clavier. Avec le -.B mode de répétition -"Monte", la note produite est incrémentée à chaque répétition vers la -prochaine note +.B mode de répétition +"Monte", la note produite est incrémentée à chaque répétition vers la +prochaine note jouée sur le clavier. Avec le mode "Descend", la prochaine note plus basse est jouée. Avec une seule note présente dans le motif, ceci -produit un arpège classique linéaire. Ainsi, même avec des motifs -simples comme "01" ou "0", on génère des arpèges complets. En revanche, -avec le mode de répétition "Statique", les notes à la sortie seront +produit un arpège classique linéaire. Ainsi, même avec des motifs +simples comme "01" ou "0", on génère des arpèges complets. En revanche, +avec le mode de répétition "Statique", les notes à la sortie seront constantes. .PP .B Mode de Déclenchement .PP Les arpégiateurs de QMidiArp possèdent trois modes de déclenchement -par le clavier d'entrée. En mode "Continu", le motif est répété en +par le clavier d'entrée. En mode "Continu", le motif est répété en permanence en synchronisation avec le séquenceur interne sans tenir -compte du moment où les notes sont jouées. Le mode "Redémarre" +compte du moment où les notes sont jouées. Le mode "Redémarre" permet de garder cette quantisation mais en renvoyant la séquence au -point de départ à chaque nouvelle note jouée en stakato. Enfin, le -mode "Déclenche" produit le démarrage de l'arpégiateur au moment où -une note stakato est jouée. +point de départ à chaque nouvelle note jouée en stakato. Enfin, le +mode "Déclenche" produit le démarrage de l'arpégiateur au moment où +une note stakato est jouée. .PP .B "Editer les motifs d'arpège" .PP -Les motifs d'arpège de QMidiArp sont définis par une séquence de -caractères contenant les notes même ainsi que des caractères de +Les motifs d'arpège de QMidiArp sont définis par une séquence de +caractères contenant les notes même ainsi que des caractères de contrôle pour des changements de tempo, de vélocité, de durée, d'octave, et de mode accord. En appuyant sur le bouton -.B Editer le motif, +.B Editer le motif, le preset de motif apparaît sous forme d'un champ de texte modifiable. -Le motif modifié peut être sauvegardé dans la liste des motifs +Le motif modifié peut être sauvegardé dans la liste des motifs prédéfinis en cliquant le bouton .B Mémoriser le motif. Le motif actif peut être supprimé de la liste en cliquant sur le bouton @@ -205,43 +209,42 @@ > : Double tempo < : Demi tempo . : Retour au tempo standard: un quart de mesure - -( ) : Mode accord début / fin + ( ) : Mode accord début / fin e.g. (012) produit un accord des trois - notes les plus basses dans le tampon + notes les plus basses dans le tampon / : Augmente la vélocité de 20% \\ : Diminue la vélocité de 20% d : Double durée de note h : Demi durée de note p : Pause -Tous les contrôles sont valides jusqu'à la fin du motif. +Tous les contrôles sont valides jusqu'à la fin du motif. Par exemple, le contrôle > doublera la vitesse de l'arpège pour toutes -les notes suivantes dans le motif jusqu'à la prochaine répétition à -laquelle la vitesse reprendra à un quart de mesure. +les notes suivantes dans le motif jusqu'à la prochaine répétition à +laquelle la vitesse reprendra à un quart de mesure. .PP .B Randomisation .PP -Le rythme, la vélocité et la durée des notes produites peuvent être +Le rythme, la vélocité et la durée des notes produites peuvent être randomisés par les réglettes du champ .B Randomisation. -Ces réglages peuvent être utilisés pour produire des motifs moins +Ces réglages peuvent être utilisés pour produire des motifs moins mécaniques, mais à des valeurs plus élevées, ils ajoutent des accents intéressants au motif joué. .PP .B Enveloppe .PP -QMidiArp peut superposer une fonction d'enveloppe aux vélocités des +QMidiArp peut superposer une fonction d'enveloppe aux vélocités des arpèges. La dynamique de cette enveloppe est définie par les réglettes -.B Attack +.B Attack et .B Release. -En ajustant un temps d'"attack" non-nul, les vélocités de notes à la -sortie sont incrémentées pendant le temps d'attack défini en secondes. -Si un temps "release" est spécifié, les notes relâchées sont gardées dans -le tampon, et leur vélocité est linéairement diminuée jusqu'à la fin du -temps "release". Cette fonction n'a un effet sur le son que si le -synthétiseur connecté à la sortie produit des sons sensibles à la +En ajustant un temps d'"attack" non-nul, les vélocités de notes à la +sortie sont incrémentées pendant le temps d'attack défini en secondes. +Si un temps "release" est spécifié, les notes relâchées sont gardées dans +le tampon, et leur vélocité est linéairement diminuée jusqu'à la fin du +temps "release". Cette fonction n'a un effet sur le son que si le +synthétiseur connecté à la sortie produit des sons sensibles à la vélocité. Elle fonctionne aux mieux avec des motifs à haute polyphonie comme par exemple le motif "Chord Oct 16 A". .PP @@ -250,12 +253,12 @@ Les réglettes de la fenêtre .B Groove permettent de contrôler un décalage linéaire du rythme, de la durée des -notes et de leur vélocité à l'intérieur de chaque quart de mesure du -motif. Ceci permet de créer un rythme du type swing ou d'accentuer le +notes et de leur vélocité à l'intérieur de chaque quart de mesure du +motif. Ceci permet de créer un rythme du type swing ou d'accentuer le motif. Les ajustements Groove sont valables pour tous les arpégiateurs simultanément. .PP -Les modules arpégiateurs de QMidiArp ont été inspiré par l'arpégiateur +Les modules arpégiateurs de QMidiArp ont été inspiré par l'arpégiateur matériel MAP1 par Rudi Linhard. .SS "Les modules LFO" @@ -263,74 +266,101 @@ peut envoyer des données de contrôle MIDI sous forme d'un oscillateur à basse fréquence (LFO) à une sortie spécifiée. Les données LFO sont des évênements MIDI envoyés en synchronie avec la queue de l'arpégiateur. -La queue doit être en état démarré pour activer les LFOs. +La queue doit être en état démarré pour activer les LFOs. Chaque module LFO possède un champ .B forme d'onde pour définir la forme des données produites et un champ .B Sortie -pour définir leur canal MIDI, port ALSA ainsi que le numéro de -contrôleur à produire. Actuellement, la forme d'onde peut être choisie -entre Sinus, Scie montant, Scie descendant, Triangle, Créneau et Libre. -La +pour définir leur canal MIDI, port ALSA ainsi que le numéro de +contrôleur à produire. Actuellement, la forme d'onde peut être choisie +entre Sinus, Scie montant, Scie descendant, Triangle, Créneau et Libre. +La .B fréquence du LFO est définie en multiples et diviseurs du .B tempo de l'arpégiateur, une fréquence de 1 produit une onde entière à chaque -quart de mesure. Si l'on spécifie des fréquences plus basses, la -longueur de la table d'onde doit être ajustée en conséquence si l'on -souhaite produire un cycle d'onde complet. La -.B résolution -temporelle du LFO détermine le nombre d'évênements produits à chaque +quart de mesure. Si l'on spécifie des fréquences plus basses, la +longueur de la table d'onde doit être ajustée en conséquence si l'on +souhaite produire un cycle d'onde complet. La +.B résolution +temporelle du LFO détermine le nombre d'évênements produits à chaque quart de temps. Elle peut aller de 1 à 192 évênements par quart de temps. -.B L'amplitude +.B L'amplitude et .B l'offset de l'onde peuvent être spécifiés entre 0 et 127. A basse résolution -temporelle, le LFO produira des changements rythmiques du contrôle, +temporelle, le LFO produira des changements rythmiques du contrôle, tandis que des résolutions élevées mènent à des ondes de plus en plus continues. .PP .B Rendre muet l'onde point par point .PP On peut retenir l'emission d'un point individuel sur la forme d'onde -en cliquant avec le -.I bouton droit -de la souris à l'endroit correspondant dans l'écran d'affichage de +en cliquant avec le +.I bouton droit +de la souris à l'endroit correspondant dans l'écran d'affichage de l'onde. Les points muets de l'onde sont affichés en couleur sombre. .PP .B Formes Libres .PP En sélectionnant la forme .B Libre, -l'onde peut être dessinée ou modifiée avec le -.I bouton gauche +l'onde peut être dessinée ou modifiée avec le +.I bouton gauche de la souris. Lorqu'on tente à modifier une forme calculée, elle est -automatiquement copiée vers la forme libre, et la forme libre précédente +automatiquement copiée vers la forme libre, et la forme libre précédente est écrasée. -Toutes les opérations du LFO incluant le dessin peuvent être faites +Toutes les opérations du LFO incluant le dessin peuvent être faites pendant que le transport est en marche. .PP +.B Direction de lecture et répétition +.PP +The play mode can be switched between: + + + ->_> : En avant et répéter + <_<- : En arrière et répéter + ->_< : Aller-retour et répéter + >_<- : Retour-aller et répéter + ->_| : Un seul aller + |_<- : Un seul retour + +Les changements faits dans ces contrôles s'appliquent immédiatement. + +.PP .B Enregistrement .PP Les données de contrôle MIDI reçues à l'entrée peuvent être enregistrées en continue en appuyant sur le bouton .B Enregistrer. -Ce bouton est lui-même contrôlable par MIDI (c.f. +Ce bouton est lui-même contrôlable par MIDI (c.f. .B Apprentissage MIDI) et QMidiArp est ainsi utilisable comme Looper et séquenceur de contrôles. .PP +.B "Le champ Entrée du LFO" +Le champ d'entrée permet de spécifier le contrôleur +.B MIDI CC +à enregistrer. On spécifie ici également comment le module réagit en cas +de réception de notes à l'entrée. Comme les arpégiateurs, le LFO peut +être redémarré ou déclenché (triggé), et la production de données peut +être arrêtée en cas de touches relachées, donc à la réception d'un signal +.B Note Off +à l'entrée avec le +.Canal +correspondant. +.PP .B "Le champ Sortie du LFO" .PP -Ce champ contient les réglages du -.B port, +Ce champ contient les réglages du +.B port, .B canal et -.B contrôleur -des données produites. Il permet également de rendre muet le module +.B contrôleur +des données produites. Il permet également de rendre muet le module entièrement. .SS "Les modules séquenceurs" -En cliquant sur le bouton +En cliquant sur le bouton .B "Nouveau Séquenceur..." dans la barre de contrôle, un nouveau module .B Seq @@ -341,22 +371,22 @@ .PP .B Programmer une séquence .PP -Comme les modules LFO de QMidiArp, le séquenceur peut être programmé en +Comme les modules LFO de QMidiArp, le séquenceur peut être programmé en ajustant les notes avec le bouton gauche de la souris sur l'écran -d'affichage. La gamme d'octaves est fixée à 4, la note la plus basse -étant C2, si la transposition globale est zéro. Les notes peuvent être +d'affichage. La gamme d'octaves est fixée à 4, la note la plus basse +étant C2, si la transposition globale est zéro. Les notes peuvent être rendues muettes avec le bouton droit de la souris. La .B durée de la séquence peut être ajustée entre 1 et 8 beats (quarts de mesure), -la résolution temporelle entre 1 et 16 par beat. Une +la résolution temporelle entre 1 et 16 par beat. Une résolution de 4 produit 4 notes par beat, donc des notes double croche. On peut aussi programmer des séquences en utilisant la fonction .B Enregistrer. -Si le bouton -.B Enregistrer -est enfoncé, les notes reçues sur le port d'entrée sont enregistrées +Si le bouton +.B Enregistrer +est enfoncé, les notes reçues sur le port d'entrée sont enregistrées pas à pas commençant par la dernière note modifiée. La séquence peut -être programmée avec la queue de séquenceur en marche. +être programmée avec la queue de séquenceur en marche. .PP .B Contrôler la séquence globalement .PP @@ -386,7 +416,7 @@ définit également le comportement de déclenchement de la séquence en cas de réception de notes à l'entrée. .B Redémarre -renvoie la séquence à son début, mais sans interrompre le rythme. La +renvoie la séquence à son début, mais sans interrompre le rythme. La séquence est re-déclenchée avec le timing des notes jouées seulement si .B Trigger @@ -394,12 +424,12 @@ .B Note Off arretera la séquence avec une note relachée, et .B Boucle -doit être cochée pour une répétition permanente au lieu d'un seul +doit être cochée pour une répétition permanente au lieu d'un seul passage. Le champ .B Sortie -est équivalent à celui des arpégiateurs et LFOs. -.PP +est équivalent à celui des arpégiateurs et LFOs. +.PP On peut produire des accents dans une séquence en ajoutant des modules LFO en parallèle aux modules Seq. Pour ceci, il suffit que le LFO envoie ses données vers le même port et canal MIDI que les modules Seq. @@ -412,18 +442,18 @@ est contrôlable par des contrôleurs MIDI. En cochant la case .B Style compact d'affichage des modules tous les nouveaux modules créés auront une apparence économique en place -pour la distribution sur le bureau de l'ordinateur. +pour la distribution sur le bureau de l'ordinateur. .PP -Tous les ajustements faits dans le dialogue +Tous les ajustements faits dans le dialogue .B Paramètres sont sauvegardés avec les données des modules dans le fichier .qmax. .SS Contrôle MIDI -QMidiArp accepte les évênements de contrôle MIDI, si l'option +QMidiArp accepte les évênements de contrôle MIDI, si l'option .B Modules contrôlables par MIDI est cochée dans le dialogue .B Settings. -Le contrôle par MIDI est dispobible pour les modules Seq +Le contrôle par MIDI est dispobible pour les modules Seq (boutons muets, vélocité, durée des notes), les modules LFO (boutons muets, amplitude, décalage) et les modules d'arpège (boutons muets). @@ -431,16 +461,16 @@ .B Apprentissage MIDI .PP Les contrôleurs peuvent être attribués par un clic de droite sur l'élément -de contrôle correspondant, et en sélectionnant +de contrôle correspondant, et en sélectionnant .B Apprendre du MIDI. QMidiArp attendra ensuite la réception d'un évênement de contrôle MIDI (envoyé par exemple à partir d'une réglette d'une surface de contrôle). -Lors de la première réception d'un tel évênement, ce contrôleur est -acheminé vers l'élément de contrôle sélectionné. Il est possible -d'attribuer plusieurs contrôleurs MIDI à un seul élément. Lorsqu'on -sélectionne +Lors de la première réception d'un tel évênement, ce contrôleur est +acheminé vers l'élément de contrôle sélectionné. Il est possible +d'attribuer plusieurs contrôleurs MIDI à un seul élément. Lorsqu'on +sélectionne .B Oublier les contrôleurs, -toutes les attributions de cet élément seront supprimées. Si l'on choisit +toutes les attributions de cet élément seront supprimées. Si l'on choisit .B Annuler l'apprentissage, QMidiArp n'attendra plus d'évênements de contrôle MIDI. .PP @@ -452,44 +482,44 @@ .PP Pour modifier les contrôles attribués, on choisit .B Contrôles MIDI -dans le menu +dans le menu .I Affichage. -Les propriétés de chaque contrôle MIDI peuvent être modifiées dans le -tableau de cette fenêtre. Les contrôleurs de -.B boutons -ont un fonctionnement spécifique. Si les valeurs min et max sont -.I identiques, +Les propriétés de chaque contrôle MIDI peuvent être modifiées dans le +tableau de cette fenêtre. Les contrôleurs de +.B boutons +ont un fonctionnement spécifique. Si les valeurs min et max sont +.I identiques, le contrôleur fonctionnera en tant que "toggle". Si min et max sont .I différents, -le module devient muet lors de la réception de min (case muet +le module devient muet lors de la réception de min (case muet .I cochée) -et devient actif lors de la réception d'une valeur de max. +et devient actif lors de la réception d'une valeur de max. .PP -Lorsqu'on appuye sur +Lorsqu'on appuye sur .B Supprimer, la ligne sélectionnée est effacée, et le bouton .B Rétablir -recharge les attributions actuelles. Toutes les modifications faites -dans ce tableau sont appliquées sur appui du bouton +recharge les attributions actuelles. Toutes les modifications faites +dans ce tableau sont appliquées sur appui du bouton .B OK alors que .B Cancel -annule les changements. +annule les changements. .SS "Journal" La fenêtre du -.B Journal -d'évênements liste les évênements MIDI entrants. Les évênements sont -affichés en couleur dépendant de leur type. -Le journal est affiché dans la partie inférieure du logiciel par défaut, +.B Journal +d'évênements liste les évênements MIDI entrants. Les évênements sont +affichés en couleur dépendant de leur type. +Le journal est affiché dans la partie inférieure du logiciel par défaut, mais il peut être caché ou détaché en tant que fenêtre indépendante. -La journalisation peut être desactivée entièrement ou uniquement pour +La journalisation peut être desactivée entièrement ou uniquement pour les évênements d'horologe MIDI. .SS Fichiers d'exemple -Il y a actuellement trois fichiers de démonstration de l'arpégiateur. +Il y a actuellement trois fichiers de démonstration de l'arpégiateur. Le fichier demo.qma a été conçu pour être utilisé avec des sons de type -suivant: Canal 1: Marimba, Canal 2: Celesta, Canal 3: Basse acoustique, +suivant: Canal 1: Marimba, Canal 2: Celesta, Canal 3: Basse acoustique, mais on peut obtenir des résultats intéressants en employant d'autres types de son. .PP @@ -497,49 +527,51 @@ Seq et LFO fonctionnant en parallèle. Les sorties des séquenceurs devraient être connectées à des synthétiseurs et des sons percussifs. Les LFO produisent des données destinées aux fréquences de filtres -(cutoffs) qui ont le contrôleur MIDI standard CC#74. Le synthétiseur +(cutoffs) qui ont le contrôleur MIDI standard CC#74. Le synthétiseur ZynAddSubFX par Paul Nasca réagit à ces contrôleurs, et ses presets "Bass 1" ou "Plucked 3" fonctionnenet bien avec cette démonstration. .SH OPTIONS .TP .B \-\-portCount -Définir le nombre de ports ALSA disponibles égal à . La valeur +Définir le nombre de ports ALSA disponibles égal à . La valeur par défaut est 2. .TP -.B \-\-help -Affiche les options de ligne de commande disponibles et quitte le +.B \-\-help +Affiche les options de ligne de commande disponibles et quitte le programme. .TP -.B \-\-version +.B \-\-version Affiche l'information de version du programme et quitte celui-ci. .TP +.BI \-\-alsa +Utiliser le pilote ALSA MIDI +.TP +.BI \-\-jack +Utiliser le pilote JACK MIDI (par défaut) +.TP .B fichier -Nom d'un fichier QMidiArp (.qmax) valide à charger au démarrage du +Nom d'un fichier QMidiArp (.qmax) valide à charger au démarrage du programme. .SH FICHIERS .I *.qmax .RS Fichiers XML QMidiArp contenant les données au format texte XML. -.RE -.I *.qma -.RS -Anciens fichiers QMidiArp au format plein texte. .SH EXEMPLES -Les fichiers d'exemple de QMidiArp se situent dans +Les fichiers d'exemple de QMidiArp se situent dans .I /usr/share/qmidiarp ou dans .I /usr/local/share/qmidiarp .SH NOTES -Les erreurs et avertissements sont écrits dans +Les erreurs et avertissements sont écrits dans .BR stderr (3). .PP .SH SUPPORT qmidiarp-devel@lists.sourceforge.net .SH AUTEURS -Frank Kober, Guido Scholz et Matthias Nagorni. Cette page de manuel -a été écrite par +Frank Kober, Nedko Arnaudov, Guido Scholz et Matthias Nagorni. Cette +page de manuel a été écrite par Frank Kober . diff -Nru qmidiarp-0.4.2/man/Makefile.in qmidiarp-0.4.5/man/Makefile.in --- qmidiarp-0.4.2/man/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/man/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -75,6 +75,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff @@ -309,9 +315,7 @@ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ - test -z "$$files" || { \ - echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -537,10 +541,15 @@ installcheck: installcheck-recursive 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/man/qmidiarp.1 qmidiarp-0.4.5/man/qmidiarp.1 --- qmidiarp-0.4.2/man/qmidiarp.1 2011-05-29 18:18:19.000000000 +0000 +++ qmidiarp-0.4.5/man/qmidiarp.1 2011-12-22 09:12:33.000000000 +0000 @@ -1,4 +1,4 @@ -.\" +.\" .\" Manual page for qmidiarp .\" Process with: .\" groff -man -Tascii qmidiarp.1 | less @@ -6,7 +6,7 @@ .\" Get a printable version with: .\" groff -t -e -mandoc -Tps qmidiarp.1 > qmidiarp.ps .\" -.TH QMIDIARP 1 2009-10-20 +.TH QMIDIARP 1 2011-11-07 .SH NAME qmidiarp \- MIDI arpeggiator and LFO @@ -14,41 +14,44 @@ .br .B qmidiarp [\fIOPTION\fR] [\fIfile\fR] -.br +.br .B qmidiarp { -.B \-\-help -| +.B \-\-help +| .B \-\-version } .SH DESCRIPTION QMidiArp -is an advanced MIDI arpeggiator, programmable step sequencer and LFO for -the ALSA sequencer. It can -hold any number of arpeggiator or LFO modules running in parallel. The +is an advanced MIDI arpeggiator, programmable step sequencer and LFO. +It runs with either JACK MIDI or ALSA MIDI. It can +hold any number of arpeggiator or LFO modules running in parallel. The arpeggiator modules produce sequences depending on the notes sent to -their input port, which is typically connected to a keyboard or another -sequencer. The step sequencer modules allow to create simple linear, -monophonic and globally transposable sequences similar to the first +their input port, which is typically connected to a keyboard or another +sequencer. The step sequencer modules allow to create simple linear, +monophonic and globally transposable sequences similar to the first analog sequencers. The MIDI LFOs independently produce MIDI controller data of adjustable waveform, time resolution, -amplitude and duration. For each module, an input note filter is -available, and the output port and channel can be set independently. -Since the modules use a common sequencer queue, they are automatically +amplitude and duration. For each module, an input note filter is +available, and the output port and channel can be set independently. +Since the modules use a common sequencer queue, they are automatically in sync with each other. QMidiArp works with an internal tick resolution -of 192 ticks per beat. The queue can be synchronized to an incoming MIDI +of 192 ticks per beat. The queue can be synchronized to an incoming MIDI realtime clock or as a JACK transport client. Most of the relevant control elements are accessible via MIDI controller through a MIDI-learn infrastructure. QMidiArp -also has a log tool displaying the history of incoming MIDI events in +also has a log tool displaying the history of incoming MIDI events in colors depending on their type. QMidiArp is based on the Qt4 toolkit. .SS "General Operation" +When no commandline options are given, QMidiArp starts as a JACK MIDI +client with an input port and two output ports. For starting QMidiArp as +an ALSA client, use the -a option. A new arpeggiator or LFO module can be created by -clicking one of the +clicking one of the .B Add Arp..., Add LFO... or .B Add Step Sequencer... @@ -60,122 +63,123 @@ on the icon on the left side of each module title bar. They can also be aligned side-by-side within the same window if the main window is stretched sufficiently before reinserting a module. The entire -setup containing all arps, sequences and LFOs in the tab bar along with -the parameters set in the -.B Settings +setup containing all arps, sequences and LFOs in the tab bar along with +the parameters set in the +.B Settings window can be saved to or loaded from -a QMidiArp XML file (.qmax). The -.B tempo +a QMidiArp XML file (.qmax). The +.B tempo of the queue can be set in beats per minute and -affects all modules. The queue is started and stopped by -the blue arrow button. +affects all modules. The queue is started and stopped by +the blue arrow button. -.SS "MIDI Clock operation" -QMidiArp can use incoming MIDI clock events as clock and start/stop +.SS "MIDI Clock operation (ALSA MIDI only)" +In ALSA mode, QMidiArp runs using its own clock and tempo, but it can +optionally use incoming MIDI clock events as clock and start/stop control source. -If the -.B MIDI clock button -right of the tempo box is pressed, the running ALSA queue is stopped, +If the +.B MIDI clock button +right of the tempo box is pressed, the running ALSA queue is stopped, and QMidiArp -will wait for an incoming "MIDI Clock Start" event from an external +will wait for an incoming "MIDI Clock Start" event from an external source connected to QMidiArp's MIDI input. Once this event is received, the queue is started using MIDI realtime clock events as clock -source. QMidiArp will best remain in sync with the incoming -MIDI clock if its internal tempo value (see above) approximately +source. QMidiArp will best remain in sync with the incoming +MIDI clock if its internal tempo value (see above) approximately corresponds to that of the incoming clock. The MIDI clock tempo is, -however, measured while the queue is running. Therefore, if the tempos of -the MIDI clock and that of QMidiArp differ, synchronization should -become stable from the second queue start. The queue will stop when a -MIDI Clock Stop event is received. During MIDI Clock operation, -QMidiArp's own clock start and stop functions as well as adding or -loading new setups are disabled. They are enabled again by -unchecking the MIDI clock button. +however, measured while the queue is running. Therefore, if the tempos of +the MIDI clock and that of QMidiArp differ, synchronization should +become stable from the second queue start. The queue will stop when a +MIDI Clock Stop event is received. During MIDI Clock operation, +QMidiArp's own clock start and stop functions as well as adding or +loading new setups are disabled. They are enabled again by +unchecking the MIDI clock button. .SS "JACK Transport Client Operation" -When the -.B Jack Transport Connect -button is pressed, QMidiArp will try to connect to a running Jack server +When the +.B Jack Transport Connect +button is pressed, QMidiArp will try to connect to a running Jack server and then function -as a Jack Transport client, i.e. set its tempo and remain synchronized +as a Jack Transport client, i.e. set its tempo and remain synchronized to a running Jack Transport master. Note that QMidiArp will restart -its queue from zero whenever Jack transport is starting regardless of +its queue from zero whenever Jack transport is starting regardless of Jack Transport's position. This also applies in case of a looping Jack Transport queue. The Jack button will be released automatically if QMidiArp gets disconnected from Jack by a possible Jack shutdown or -if Jack is not available at connection time. +if Jack is not available at connection time. .PP -Note: MIDI Clock and Jack Transport button states will be saved with the +Note: MIDI Clock and Jack Transport button states will be saved with the QMidiArp session file, and get active or inactive when a new session -file is loaded. +file is loaded. .SS "Arpeggiator Modules" QMidiArp's arpeggiators can produce complex patterns derived from the -notes played on a MIDI keyboard. QMidiArp's arpeggiator modules +notes played on a MIDI keyboard. QMidiArp's arpeggiator modules were inspired by the MAP1 hardware arpeggiator by Rudi Linhard. .PP .B Input and Output panels .PP -Each arpeggiator has an -.B Input -and an +Each arpeggiator has an +.B Input +and an .B Output -panel. The Input panel -defines the note range and the MIDI channel to which the arp is +panel. The Input panel +defines the note range and the MIDI channel to which the arp is assigned. Notes that pass this Input filter are sorted by pitch and added to the internal note buffer of the arpeggiator. Incoming notes that do not match any filter can either be -discarded or forwarded to a selectable MIDI port (see +discarded or forwarded to a selectable MIDI port (see .B Settings -). The -.B Output -panel holds settings for the -.B MIDI channel -and -.B output port -to which the arpeggiator notes will be sent. +). The +.B Output +panel holds settings for the +.B MIDI channel +and +.B output port +to which the arpeggiator notes will be sent. .PP .B "Arpeggiator Patterns" .PP -Arpeggio patterns can be selected and edited in the +Arpeggio patterns can be selected and edited in the .B Pattern -panel. -.B Pattern presets +panel. +.B Pattern presets are selectable from a combo box. The currently active pattern is displayed as a piano roll type screen showing the -base notes as streaks. The y-scale of the graphics -window corresponds to the index of the notes in the pattern. Octave -changes (see +base notes as streaks. The y-scale of the graphics +window corresponds to the index of the notes in the pattern. Octave +changes (see .B Editing patterns -) are shown as additional horizontal lines. -The notes that are eventually sent depend on the input notes received -by the arpeggiator. The received notes notes are attributed in ascending -order to the notes defined in the pattern. For example, a single streak +) are shown as additional horizontal lines. +The notes that are eventually sent depend on the input notes received +by the arpeggiator. The received notes notes are attributed in ascending +order to the notes defined in the pattern. For example, a single streak on the bottom of the arp display ("simple" presets) means that at -the first pass through the pattern, the lowermost note played on the +the first pass through the pattern, the lowermost note played on the keyboard is played. If a chord is played on the keyboard and only one note is present in the pattern, only the lowermost pressed note is output at -the first pass through the pattern. For the following repetitions of -the pattern, the chosen "repeat mode" is used to determine the -following notes. -If the pattern contains stacked note streaks (chord mode), chords played -on the keyboard are also output as chords with polyphony up to the +the first pass through the pattern. For the following repetitions of +the pattern, the chosen "repeat mode" is used to determine the +following notes. +If the pattern contains stacked note streaks (chord mode), chords played +on the keyboard are also output as chords with polyphony up to the number of notes defined in the stack. .PP .B Repeat Mode .PP -This setting defines the behavior of the arpeggio over several repetitions +This setting defines the behavior of the arpeggio over several repetitions of the pattern when the number of notes pressed on the keyboard is higher than the number of notes present in the pattern. -When -.B Repeat Mode +When +.B Repeat Mode is "Up", the next higher note played on the keyboard is played at each repetition. With "Down", the next lower note is played. With a single -note present in the arp pattern, this creates classical linear -arpeggios. This way even simple patterns like "01" (or even "0") will +note present in the arp pattern, this creates classical linear +arpeggios. This way even simple patterns like "01" (or even "0") will generate a complete arpeggio. When "Static" is selected, this classical arpeggio mode will -be disabled, and the output notes remain constant. +be disabled, and the output notes remain constant. .PP .B "Trigger mode" .PP @@ -183,30 +187,30 @@ the arp running continuously in synchronization with the internal or external clock source. Even when new notes are played, they will be output quantized to the running queue. "Kbd restart" will cause a reset -of the playhead position upon the next note to be output, but the +of the playhead position upon the next note to be output, but the output pattern stays quantized to the queue. When "Kbd trigger" is selected, each new note played in stakato will trigger the pattern with the timing of the played note. .PP .B "Editing Arp patterns" .PP -Arp patterns are defined by a text sequence containing the notes -themselves as numbers along with control changes for chord, tempo, -velocity and octave changes. When the +Arp patterns are defined by a text sequence containing the notes +themselves as numbers along with control changes for chord, tempo, +velocity and octave changes. When the .B Edit pattern -button in the pattern panel is clicked, the current pattern preset -appears as a -text input line. The edited pattern can be stored in the preset list -by clicking on the +button in the pattern panel is clicked, the current pattern preset +appears as a +text input line. The edited pattern can be stored in the preset list +by clicking on the .B Store pattern -button. The currently active pattern +button. The currently active pattern can be removed from the -preset list by clicking on the +preset list by clicking on the .B Remove pattern button. All preset patterns are immediately saved in the .qmidiarprc -resource file when a pattern is stored or removed, and the new pattern -list is made available to the other arps in the tab bar. Pattern presets -are automatically loaded on each application start. +resource file when a pattern is stored or removed, and the new pattern +list is made available to the other arps in the tab bar. Pattern presets +are automatically loaded on each application start. The syntax for the pattern text is as follows: @@ -217,9 +221,9 @@ > : Double tempo < : Half tempo . : Reset to standard tempo -( ) : Chord, begin..end, - e.g. (012) would be a chord of the - lowermost three notes in the buffer + ( ) : Chord, begin..end, + e.g. (012) would be a chord of the + lowermost three notes in the buffer / : Volume up by 20% \\ : Volume down by 20% d : Double length @@ -234,8 +238,8 @@ .B Random .PP The timing, velocity and length of the output notes can be randomized -using the sliders in the -.B Random +using the sliders in the +.B Random panel. These settings can be used to make the arpeggiator sound less mechanical, but if they are set to higher values, they add interesting accents to the patterns. @@ -243,9 +247,9 @@ .B Envelope .PP QMidiArp can modulate the velocity of the arpeggios with an envelope -function defined by -.B Attack -time and +function defined by +.B Attack +time and .B Release time. If an attack time is set, the velocities of the output notes are ramped up during the @@ -258,47 +262,47 @@ .PP .B Groove .PP -The +The .B Groove -sliders control a linear shift of timing, length and -velocity within each beat of the output pattern. This can be used to -create swing timing and accent. The Groove settings are adjusted for all +sliders control a linear shift of timing, length and +velocity within each beat of the output pattern. This can be used to +create swing timing and accent. The Groove settings are adjusted for all arps simultaneously. .SS "LFO Modules" In parallel to the arps, QMidiArp can send MIDI controller data in form of a low frequency oscillator (LFO) -to the assigned output. The LFO data consist of controller events that -are in sync with the arpeggiator queue. The queue has to be in running -state to enable the LFO. Each LFO module has a -.B waveform -panel to define the shape of the outgoing data and an -.B output +to the assigned output. The LFO data consist of controller events that +are in sync with the arpeggiator queue. The queue has to be in running +state to enable the LFO. Each LFO module has a +.B waveform +panel to define the shape of the outgoing data and an +.B output panel to define MIDI Channel, ALSA port and controller number to be produced. The waveform can currently be set to Sine, -Saw Up, Saw Down, Triangle, Square and Custom. The -.B frequency -of the LFO can be set in muliples and divisors of the arp -.B tempo, +Saw Up, Saw Down, Triangle, Square and Custom. The +.B frequency +of the LFO can be set in muliples and divisors of the arp +.B tempo, such that frequency of 1 produces one full wave per beat. If frequencies lower than 1 are selected, the length of the wavetable has to be adjusted correspondingly -to produce a full wave. The time -.B resolution +to produce a full wave. The time +.B resolution of the LFO determines the number of events produced every beat and -can be adjusted to up to 192 events per beat. -.B Amplitude -and -.B offset -of the waveform can be adjusted from 0...127. Low -.B resolutions -lead to audibly discrete rythmic controller changes whereas higher +can be adjusted to up to 192 events per beat. +.B Amplitude +and +.B offset +of the waveform can be adjusted from 0...127. Low +.B resolutions +lead to audibly discrete rythmic controller changes whereas higher resolution values lead to more continuous waves. .PP .B Muting individual wave points .PP Individual wave points can be muted/unmuted by clicking on -the corresponding location in the wave display with the +the corresponding location in the wave display with the .I right mouse button. A muted wave point is shown in darker color. .PP @@ -308,102 +312,129 @@ .B Custom is selected, the waveform can be drawn with the .I left mouse button -in the waveform display. A calculated waveform is copied to the custom -waveform whenever it is being modified by the mouse. This will overwrite -the previous custom waveform with the currently displayed waveform. As -all LFO operations, drawing and muting can be done while the queue is +in the waveform display. A calculated waveform is copied to the custom +waveform whenever it is being modified by the mouse. This will overwrite +the previous custom waveform with the currently displayed waveform. As +all LFO operations, drawing and muting can be done while the queue is running, and becomes effective immediately. .PP +.B Play direction and looping +.PP +The play mode can be switched between: + + + ->_> : Forward and Loop + <_<- : Backward and Loop + ->_< : Forward and Bounce + >_<- : Backward and Bounce + ->_| : Forward Single shot + |_<- : Backward Single shot + +The direction and loop settings apply immediately when changed on the +fly. +.PP .B Recording .PP -The LFO records incoming controller data as selected in the +The LFO records incoming controller data as selected in the .B Input -panel, when the +panel, when the .B Record button is pressed. Note that the Record button itself can be attributed -to a MIDI toggle controller so that it provides a convenient +to a MIDI toggle controller so that it provides a convenient implementation of a controller motion sampler and looper. .PP +.B LFO Input panel +.PP +The input panel contains settings on which +.B MIDI CC +is to be recorded, how the LFO acts to note events received on the +input. As the arpeggiators, the LFO can be restarted or (re-) triggered +by notes played on the keyboard, and the wave output can be stopped or +not when +.B Note Off +events are received on the input +.B Channel +.PP .B "LFO Output panel" .PP -The LFO output panel contains the -.B port, -.B channel -and -.B controller -number settings of the LFO data produced by each LFO tab. It also allows -.B muting +The LFO output panel contains the +.B port, +.B channel +and +.B controller +number settings of the LFO data produced by each LFO tab. It also allows +.B muting of each LFO after a completed wave cycle. .SS "Step Sequencer Modules" -By clicking -.B "Add Step Sequencer..." -in the control tool bar, a new -.B Seq -module can be added to the tab bar. Each of these modules produce a -simple linear (monophonic) sequence, similar to the first analog +By clicking +.B "Add Step Sequencer..." +in the control tool bar, a new +.B Seq +module can be added to the tab bar. Each of these modules produce a +simple linear (monophonic) sequence, similar to the first analog hardware sequencers. The Seq modules are controllable while running, also in a similar way to analog step sequencers. .PP .B Programming a sequence .PP As QMidiArp's LFO modules, the step sequencer can be programmed -by adjusting notes with left mouse +by adjusting notes with left mouse clicks on the sequence display. The octave range is fixed to 4. The -lowest note is C2 if the global transpose is set to 0. Notes can be -muted with the right mouse click. The sequence -.B length -can be adjusted between 1 and 8 beats, and the time -.B resolution -can be set to values between 1 and 16 per beat. A resolution of 4 means -that 4 notes are output every beat, i.e. sixteenth notes. -The sequence can also be programmed using the +lowest note is C2 if the global transpose is set to 0. Notes can be +muted with the right mouse click. The sequence +.B length +can be adjusted between 1 and 8 beats, and the time +.B resolution +can be set to values between 1 and 16 per beat. A resolution of 4 means +that 4 notes are output every beat, i.e. sixteenth notes. +The sequence can also be programmed using the +.B Record +function. When the .B Record -function. When the -.B Record button is pressed, notes received on the input port will be recorded -step-by-step starting from the last modified note. Programming can be -done on the fly also when the sequencer queue is running. +step-by-step starting from the last modified note. Programming can be +done on the fly also when the sequencer queue is running. .PP .B Controlling the sequence globally .PP -There are sliders to adjust the global -.B velocity -(volume), -.B note length -and -.B transpose +There are sliders to adjust the global +.B velocity +(volume), +.B note length +and +.B transpose of the sequence in semitones. .PP .B Seq Input and Output panels .PP -The Seq +The Seq .B Input panel determines how to handle incoming notes on the MIDI .B Channel -set in the channel box. If +set in the channel box. If .B Note is checked, the sequence will be globally transposed with the incoming -note as transpose value. If +note as transpose value. If .B Velocity -is checked in addition, the sequence will output notes with the same -velocity as that received on its input. The +is checked in addition, the sequence will output notes with the same +velocity as that received on its input. The .B Input panel also determines how the sequence behaves when incoming notes -are received. It can be restarted, triggered and stopped with the -timing of received notes. +are received. It can be restarted, triggered and stopped with the +timing of received notes as the LFO modules. The Seq .B Output -panel is equivalent to that of arpeggiator and LFO modules. -.PP -Note that accents within a pattern can be produced by running LFO -modules in parallel to the Seq module, and by sending to the same +panel is equivalent to that of arpeggiator and LFO modules. +.PP +Note that accents within a pattern can be produced by running LFO +modules in parallel to the Seq module, and by sending to the same channel and port as the Seq module. .SS "Settings" -The Settings window allows to configure if and to which port incoming +The Settings window allows to configure if and to which port incoming events that do not match any module's input filter are forwarded ( .B unmatched events). It also @@ -412,87 +443,85 @@ the modules separately. If this option is set, QMidiArp will recognize MIDI control events that can be attributed to different parameters (see .B MIDI Control -). By checking the +). By checking the .B compact module style -all new created modules will show with small GUI elements to be more +all new created modules will show with small GUI elements to be more economic in space when distributed as separate windows over the desktop. .PP All settings in this dialog are stored along with the module data in the qmax session file. .SS MIDI control -QMidiArp supports MIDI control events if the +QMidiArp supports MIDI control events if the .B Modules controllable by MIDI CC option is checked in the .B Settings -dialog. MIDI control is available for Seq modules (Muting, Velocity, -Note Length), LFO modules (Muting, Amplitude, Offset) and Arp modules -(Muting only). +dialog. .PP .B MIDI Learn .PP Controllers can be attributed by right-clicking on the sliders or -mute checkbox in each module and selecting +mute checkbox in each module and selecting .B MIDI Learn. -QMidiArp will then wait for MIDI control events, -and moving a MIDI controller connected to QMidiArp's input will -attribute this controller to the control item. It is -possible to add several MIDI controllers to one item. If +QMidiArp will then wait for MIDI control events, +and moving a MIDI controller connected to QMidiArp's input will +attribute this controller to the control item. It is +possible to add several MIDI controllers to one item. If .B MIDI Forget -is selected, all controllers for that item are removed. If +is selected, all controllers for that item are removed. If .B Cancel MIDI learning is selected, the learn process is stopped. .PP Note that by default, mute controllers are interpreted as toggles, i.e. -the mute state is toggled on reception of a value of 127 from the +the mute state is toggled on reception of a value of 127 from the attributed controller. .PP .B Control Editor .PP The .B Control Editor -is accessible from the -.I View +is accessible from the +.I View menu. Controls can be edited by MIDI control number, channel, and the -minimum and maximum values that are sent to the control item. Mute -controllers have a special behaviour. If minimum and maximum are +minimum and maximum values that are sent to the control item. Mute +controllers have a special behaviour. If minimum and maximum are .I equal, the controller acts as toggler upon reception of the adjusted value. -If minimum is +If minimum is .I different -from maximum, the corresponding module will be muted upon reception of +from maximum, the corresponding module will be muted upon reception of minimum and unmuted upon reception of maximum as values. .PP If .B Remove is pressed, the currently selected line will be removed, pressing .B Revert -reloads the current controller settings. Pressing -.B Cancel -quits the control editor without applying changes, and only if +reloads the current controller settings. Pressing +.B Cancel +quits the control editor without applying changes, and only if .B OK is pressed, the edited control list becomes active. .SS "Event Log" The -.B Event Log -displays incoming MIDI events. It is displayed in the bottom area by +.B Event Log +displays incoming MIDI events. It is displayed in the bottom area by default, but can be hidden if not -needed or set floating as a top-level window on the desktop. Logging -can also be disabled generally or for MIDI Clock events only. +needed or set floating as a top-level window on the desktop. Logging +can also be disabled generally or for MIDI Clock events only. .SS Example Files -There are currently three demo arpeggios. -The demo.qma arpeggio was intended to be used with the following sound -types: Ch 1: Marimba, Ch 2: Celesta, Ch 3: Acoustic Bass, +There are currently three demo arpeggios. +The demo.qma arpeggio was intended to be used with the following sound +types: Ch 1: Marimba, Ch 2: Celesta, Ch 3: Acoustic Bass, but you can get interesting results if you use other instrument settings. .PP The demo_seqlfo.qmax setup shows the use of the new sequencer and LFO modules playing in parallel. The sequencer outputs should be routed -to percussive synthesizer sounds. The LFO data is intended to act on +to percussive synthesizer sounds. The LFO data is intended to act on filter cutoff, which has the standard controller CC#74. ZynAddSubFX by Paul Nasca reacts on these filter cutoff controllers. The "Bass 1" -and "Plucked 3" presets from this synthesizer work well with this demo +and "Plucked 3" presets from this synthesizer work well with this demo file. .SH OPTIONS @@ -507,27 +536,30 @@ .BI \-\-version Print version information and exit. .TP +.BI \-\-alsa +Use the ALSA MIDI backend +.TP +.BI \-\-jack +Use the JACK MIDI backend (default) +.TP .B file Name of a valid QMidiArp (.qmax) XML file to be loaded on start. .SH FILES .I *.qmax .RS QMidiArp XML files containing session data in XML text format. -.RE -.I *.qma -.RS -Old QMidiArp files in plain text format. + .SH EXAMPLES -Example QMidiArp files can be found in +Example QMidiArp files can be found in .I /usr/share/qmidiarp or in .I /usr/local/share/qmidiarp .SH NOTES -Errors and warnings are written to +Errors and warnings are written to .BR stderr (3). .SH SUPPORT qmidiarp-devel@lists.sourceforge.net .SH AUTHORS -Frank Kober, Guido Scholz and Matthias Nagorni. This +Frank Kober, Nedko Arnaudov, Guido Scholz and Matthias Nagorni. This manual page was written by Frank Kober . diff -Nru qmidiarp-0.4.2/NEWS qmidiarp-0.4.5/NEWS --- qmidiarp-0.4.2/NEWS 2011-07-10 08:05:09.000000000 +0000 +++ qmidiarp-0.4.5/NEWS 2012-01-21 17:20:24.000000000 +0000 @@ -1,3 +1,59 @@ +qmidiarp-0.4.5 (2012-01-21) + +Fixed Bugs + o JACK Transport start with ALSA backend was broken in 0.4.4 + o Event forwarding port index was uninitialized in JACK MIDI backend + + +qmidiarp-0.4.4 (2011-12-24) + +New Features + o JACK MIDI backend doesn't require Jack Transport anymore + +Improvements + o Better usability of the sequencer loop marker + o Improved LFO offset slider behavior + o Quantization to the minimum stepwidth in Arp modules active when + changes in Arp patterns occur + +Fixed Bugs + o Crash on startup in JACK MIDI mode on certain systems + o When cloning modules, the current play direction wasn't copied + o Unmatched MIDI event forwarding didn't work with Arp modules + o Typo in english manpage + + +qmidiarp-0.4.3 (2011-11-20) + +New Features + o Groove functions now work for all modules, not only Arps + o Effect of groove settings is displayed in the Arp/LFO/Seq screen + o LFOs can be triggered and restarted by the keyboard + o When reducing the size of LFO waves or Sequences, the original data + is kept in memory and is also saved to the session file as a whole + o LFO and Seq play direction can now be chosen, and bouncing loops are + possible + o New user positionable loop marker in Seq module. The marker is + placed by left or right mouse click on the bottom cursor line of the + sequencer and represents an additional return/loop point. It can be + removed again by clicking in the bottom left or right area of the + Seq screen. + o Triggered one-shot play of LFO and Seqs improved + o JACK MIDI backend available. This is now default, use the -a option + for getting the ALSA backend + o JACK Session support when using JACK MIDI backend + +Fixed Bugs + o A rounding error led to desync when Arps were used with groove shift + o MIDI controls for Groove did not initialize upon "New..." + o MIDI Controllers assigned to multiple destinations stopped at the + first one encountered and ignored all others + +General Changes + o JACK MIDI is now the default backend, -a option enables ALSA backend + o Obsolete .qma text file import removed + + qmidiarp-0.4.2 (2011-07-10) New Features diff -Nru qmidiarp-0.4.2/qmidiarp.desktop qmidiarp-0.4.5/qmidiarp.desktop --- qmidiarp-0.4.2/qmidiarp.desktop 2011-05-29 18:18:19.000000000 +0000 +++ qmidiarp-0.4.5/qmidiarp.desktop 2011-11-07 21:28:10.000000000 +0000 @@ -5,12 +5,15 @@ Name=QMidiArp Name[de]=QMidiArp Name[fr]=QMidiArp +Name[ru]=QMidiArp GenericName=Arpeggiator-Sequencer-LFO GenericName[de]=Arpeggiator-Sequenzer-LFO GenericName[fr]=Arpégiateur-Séquenceur-LFO +GenericName[ru]=Арпеджиатор, секвенсер и LFO Comment=Arpeggiator-Sequencer-LFO Comment[de]=Arpeggiator-Sequenzer-LFO Comment[fr]=Arpégiateur-Séquenceur-LFO +Comment[ru]=Арпеджиатор, секвенсер и LFO Icon=qmidiarp MimeType=application/qma;application/qmax; Exec=qmidiarp diff -Nru qmidiarp-0.4.2/src/arpscreen.cpp qmidiarp-0.4.5/src/arpscreen.cpp --- qmidiarp-0.4.2/src/arpscreen.cpp 2011-03-26 12:31:07.000000000 +0000 +++ qmidiarp-0.4.5/src/arpscreen.cpp 2011-12-18 18:08:56.000000000 +0000 @@ -61,6 +61,7 @@ double curstep = 0.0; int nlines = 0; int notelen; + int dx = 0; int ypos, xpos; int octYoffset; int w = QWidget::width(); @@ -78,7 +79,10 @@ double minTempo = 1.0; int noctaves = 1; double vel =1.0; - //~ int grooveTmp = 0; + double v = 0; + int grv_cur_sft = 0; + int grv_cur_len = 0; + int grv_cur_vel = 0; int grooveIndex = 0; int chordIndex = 0; l2 = 0; @@ -111,9 +115,9 @@ break; case '>': - stepWidth /= 2.0; + stepWidth *= .5; if (stepWidth < minTempo) - minTempo /= 2.0; + minTempo *= .5; break; case '<': @@ -158,7 +162,7 @@ break; case 'h': - notelen /= 2; + notelen *= .5; break; default: @@ -243,14 +247,13 @@ for (l1 = 0; l1 < patternLen; l1++) { c = a_pattern.at(l1); - //~ grooveTmp = (grooveIndex % 2) ? -grooveTick : grooveTick ; if (c.isDigit()) { nlines = c.digitValue() + 1; if (!chordIndex) { if (chordMode) chordIndex++; - curstep += stepWidth; // * (1.0 + 0.01 * (double)grooveTmp); + curstep += stepWidth; grooveIndex++; } } @@ -269,7 +272,7 @@ break; case '>': - stepWidth /= 2.0; + stepWidth *= .5; break; case '<': @@ -282,7 +285,7 @@ case 'p': if (!chordMode) - curstep += stepWidth; // * (1.0 + 0.01 * (double)grooveTmp); + curstep += stepWidth; grooveIndex++; break; @@ -311,7 +314,7 @@ break; case 'h': - notelen /= 2; + notelen *= .5; break; default: @@ -319,34 +322,33 @@ } } - if (c.isDigit()) - { + grv_cur_sft = ((grooveIndex % 2)) ? 0 : grooveTick ; + grv_cur_len = ((grooveIndex % 2)) ? grooveLength : -grooveLength ; + grv_cur_vel = ((grooveIndex % 2)) ? grooveVelocity : -grooveVelocity ; + + if (c.isDigit()) { octYoffset = (octave - minOctave) * (patternMaxIndex + 1); - x = (curstep - stepWidth) * xscale; - if (nlines > 0) - { + x = (curstep - stepWidth + 0.01 * (double)grv_cur_sft * stepWidth) * xscale; + dx = notelen * (1.0 + 0.005 * (double)grv_cur_len); + v = vel * (1.0 + 0.005 * (double)grv_cur_vel) - .8; + + if (nlines > 0) { pen.setWidth(notestreak_thick); - pen.setColor(QColor(80 + 60 * (vel - 0.8), - 160 + 40 * (vel - 0.8), - 80 + 60 * (vel - 0.8))); + pen.setColor(QColor(80 + 60 * v, 160 + 40 * v, 80 + 60 * v)); p.setPen(pen); ypos = yscale - yscale * (nlines - 1 + octYoffset) / (patternMaxIndex + 1) / noctaves + ARPSCR_VMARG - 3 + notestreak_thick; xpos = ARPSCR_HMARG + x + pen.width() / 2; - p.drawLine(xpos, ypos, - xpos + notelen - pen.width(), ypos); + p.drawLine(xpos, ypos, xpos + dx - pen.width(), ypos); // Cursor if (grooveIndex == currentIndex) { pen.setWidth(notestreak_thick * 2); p.setPen(pen); ypos = h - 2; - xpos = ARPSCR_HMARG + x + pen.width() / 2; - p.drawLine(xpos, ypos, - xpos + notelen - pen.width(), ypos); + p.drawLine(xpos, ypos, xpos + dx - pen.width(), ypos); } pen.setWidth(1); - } } } @@ -364,19 +366,10 @@ update(); } -void ArpScreen::setGrooveTick(int tick) +void ArpScreen::newGrooveValues(int tick, int vel, int length) { grooveTick = tick; - update(); -} -void ArpScreen::setGrooveVelocity(int vel) -{ grooveVelocity = vel; - update(); -} - -void ArpScreen::setGrooveLength(int length) -{ grooveLength = length; update(); } diff -Nru qmidiarp-0.4.2/src/arpscreen.h qmidiarp-0.4.5/src/arpscreen.h --- qmidiarp-0.4.2/src/arpscreen.h 2011-05-29 18:18:19.000000000 +0000 +++ qmidiarp-0.4.5/src/arpscreen.h 2011-09-09 20:31:44.000000000 +0000 @@ -75,9 +75,7 @@ public slots: void updateScreen(const QString&); void updateScreen(int p_index); - void setGrooveTick(int tick); - void setGrooveVelocity(int vel); - void setGrooveLength(int length); + void newGrooveValues(int tick, int vel, int length); void setMuted(bool on); }; diff -Nru qmidiarp-0.4.2/src/arpwidget.cpp qmidiarp-0.4.5/src/arpwidget.cpp --- qmidiarp-0.4.2/src/arpwidget.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/arpwidget.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -319,11 +319,11 @@ envelopeBox = new QGroupBox(tr("Envelope"), this); QVBoxLayout *envelopeBoxLayout = new QVBoxLayout; attackTime = new Slider(0, 20, 1, 1, 0, Qt::Horizontal, - tr("&Attack (s)"), envelopeBox); + tr("&Attack (beats)"), envelopeBox); connect(attackTime, SIGNAL(valueChanged(int)), this, SLOT(updateAttackTime(int))); releaseTime = new Slider(0, 20, 1, 1, 0, Qt::Horizontal, - tr("&Release (s)"), envelopeBox); + tr("&Release (beats)"), envelopeBox); connect(releaseTime, SIGNAL(valueChanged(int)), this, SLOT(updateReleaseTime(int))); @@ -575,78 +575,6 @@ } } -void ArpWidget::readDataText(QTextStream& arpText) -{ - QString qs, qs2; - MidiCC midiCC; - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - chIn->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - repeatPatternThroughChord->setCurrentIndex(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - indexIn[0]->setValue(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - indexIn[1]->setValue(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - rangeIn[0]->setValue(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - rangeIn[1]->setValue(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - channelOut->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - portOut->setCurrentIndex(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - randomTick->setValue(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - randomVelocity->setValue(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - randomLength->setValue(qs2.toInt()); - qs = arpText.readLine(); - if (qs == "MIDICC") - { - qs = arpText.readLine(); - while (qs != "EOCC") { - qs2 = qs.section(' ', 0, 0); - int controlID = qs2.toInt(); - qs2 = qs.section(' ', 1, 1); - int ccnumber = qs2.toInt(); - qs2 = qs.section(' ', 2, 2); - int channel = qs2.toInt(); - qs2 = qs.section(' ', 3, 3); - int min = qs2.toInt(); - qs2 = qs.section(' ', 4, 4); - int max = qs2.toInt(); - midiControl->appendMidiCC(controlID, ccnumber, channel, min, max); - qs = arpText.readLine(); - } - qs = arpText.readLine(); - } - if (qs == "Envelope") - { - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - attackTime->setValue(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - releaseTime->setValue(qs2.toInt()); - qs = arpText.readLine(); - } - while (!arpText.atEnd()) { - qs2 = arpText.readLine(); - - if (qs2.contains("EOP", Qt::CaseSensitivity(TRUE))) { - break; - } - qs += '\n' + qs2; - } - patternText->setText(qs); - modified = false; -} - void ArpWidget::setChIn(int value) { chIn->setCurrentIndex(value); @@ -920,3 +848,42 @@ modified = m; midiControl->setModified(m); } + +void ArpWidget::handleController(int ccnumber, int channel, int value) +{ + bool m; + int min, max, sval; + QVector cclist= midiControl->ccList; + + for (int l2 = 0; l2 < cclist.count(); l2++) { + min = cclist.at(l2).min; + max = cclist.at(l2).max; + + if ((ccnumber == cclist.at(l2).ccnumber) && + (channel == cclist.at(l2).channel)) { + switch (cclist.at(l2).ID) { + case 0: if (min == max) { + if (value == max) { + m = muteOut->isChecked(); + muteOut->setChecked(!m); + } + } + else { + if (value == max) { + muteOut->setChecked(false); + } + if (value == min) { + muteOut->setChecked(true); + } + } + break; + case 1: + sval = min + ((double)value * (max - min) / 127); + selectPatternPreset(sval); + break; + default: + break; + } + } + } +} diff -Nru qmidiarp-0.4.2/src/arpwidget.h qmidiarp-0.4.5/src/arpwidget.h --- qmidiarp-0.4.2/src/arpwidget.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/arpwidget.h 2012-01-21 17:14:21.000000000 +0000 @@ -99,7 +99,7 @@ * instance. * * @param p_midiWorker Associated MidiArp Object - * @param portCount Number of available ALSA MIDI output ports + * @param portCount Number of available MIDI output ports * @param compactStyle If set to True, Widget will use reduced spacing and small fonts * @param mutedAdd If set to True, the module will be added in muted state * @param parent The parent widget of this module, i.e. MainWindow @@ -128,13 +128,6 @@ */ void readData(QXmlStreamReader& xml); /*! -* @brief This function reads all module parameters of this module from an old -* QMidiArp .qma text stream. -* -* @param arpText QTextStream to read from -*/ - void readDataText(QTextStream& arpText); -/*! * @brief This function writes all parameters of this module to an XML stream * passed by the caller, i.e. MainWindow. * @@ -174,6 +167,8 @@ */ void setModified(bool); + int getNextTick() { return midiWorker->nextTick; } + /* SIGNALS */ signals: /*! @brief Emitted to MainWindow::updatePatternPresets saving and deploying modified preset @@ -241,6 +236,8 @@ * */ void setMuted(bool on); + void handleController(int ccnumber, int channel, int value); + int getGrooveIndex() { return midiWorker->getGrooveIndex(); } }; #endif diff -Nru qmidiarp-0.4.2/src/config.h.in qmidiarp-0.4.5/src/config.h.in --- qmidiarp-0.4.2/src/config.h.in 2011-07-09 15:48:25.000000000 +0000 +++ qmidiarp-0.4.5/src/config.h.in 2012-01-21 17:29:21.000000000 +0000 @@ -80,6 +80,9 @@ /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL +/* Define to enable jack session support */ +#undef JACK_SESSION + /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK diff -Nru qmidiarp-0.4.2/src/driverbase.h qmidiarp-0.4.5/src/driverbase.h --- qmidiarp-0.4.2/src/driverbase.h 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/src/driverbase.h 2011-12-04 22:01:21.000000000 +0000 @@ -0,0 +1,154 @@ +/* -*- Mode: C++ ; c-basic-offset: 4 -*- */ +/*! + * @file driverbase.h + * @brief Base class for drivers + * + * @section LICENSE + * + * Copyright 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef DRIVERBASE_H__9383DA6E_DCDB_4840_86DA_6A36E87653D2__INCLUDED +#define DRIVERBASE_H__9383DA6E_DCDB_4840_86DA_6A36E87653D2__INCLUDED + +#include + +class DriverBase : public QThread +{ +public: + + bool useMidiClock, useJackSync; + bool forwardUnmatched, queueStatus; + int portUnmatched; + QString jsFilename; + + virtual void resetTick(unsigned int tick = 0) + { + m_current_tick = tick; + } + + virtual unsigned int getCurrentTick() const + { + return m_current_tick; + } + + virtual void setNextTick(unsigned int next_tick) + { + if (next_tick > m_current_tick) + { + m_next_tick = next_tick; + } + } + + virtual void setTpm(uint64_t ticks_per_minute) + { + m_tpm = ticks_per_minute; + } + + virtual void setUseJackTransport(bool on) + { + useJackSync = on; + } + + virtual void setUseMidiClock(bool on) + { + useMidiClock = on; + } + + virtual void setForwardUnmatched(bool on) + { + forwardUnmatched = on; + } + + virtual void setPortUnmatched(int id) + { + portUnmatched = id; + } + virtual void setTempo(int bpm) + { + tempo = bpm; + internalTempo = bpm; + } + + // duration is in ticks and is valid only for note on events + virtual void sendMidiEvent(MidiEvent ev, int n_tick, unsigned int outport, unsigned int duration = 0) = 0; + virtual bool requestEchoAt(int echoTick, bool echo_from_trig = 0) = 0; + + + virtual void setTransportStatus(bool run) = 0; + virtual int getClientId() = 0; + +protected: + DriverBase( + void * callback_context, + bool (* midi_event_received_callback)(void * context, MidiEvent ev), + void (* tick_callback)(void * context, bool echo_from_trig), + uint64_t backend_rate) + : m_midi_event_received_callback(midi_event_received_callback) + , m_tick_callback(tick_callback) + , m_callback_context(callback_context) + , m_backend_rate(backend_rate) + , m_current_tick(0) + , m_next_tick(0) + , m_tpm(0) + { + } + + uint64_t tickToBackendOffset(unsigned int tick) + { + return (uint64_t)tick * m_backend_rate / m_tpm; + } + + unsigned int backendOffsetToTick(uint64_t backend_offset) + { + return backend_offset * m_tpm / m_backend_rate; + } + + uint64_t getCurrentTickBackendOffset() + { + return tickToBackendOffset(m_current_tick); + } + + uint64_t getNextTickBackendOffset() + { + return tickToBackendOffset(m_next_tick); + } + + bool midi_event_received(MidiEvent ev) + { + return m_midi_event_received_callback(m_callback_context, ev); + } + + void tick_callback(bool echo_from_trig) + { + m_tick_callback(m_callback_context, echo_from_trig); + } + + bool (* m_midi_event_received_callback)(void * context, MidiEvent ev); + void (* m_tick_callback)(void * context, bool echo_from_trig); + void * m_callback_context; + uint64_t m_backend_rate; // samples(?) per minute (granularity) + unsigned int m_current_tick; + unsigned int m_next_tick; + uint64_t m_tpm; // ticks per minute + int tempo, internalTempo; + int portCount; +}; + +#endif // #ifndef DRIVERBASE_H__9383DA6E_DCDB_4840_86DA_6A36E87653D2__INCLUDED diff -Nru qmidiarp-0.4.2/src/engine.cpp qmidiarp-0.4.5/src/engine.cpp --- qmidiarp-0.4.2/src/engine.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/engine.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -1,6 +1,6 @@ /** * @file engine.cpp - * @brief Implements the Engine module management class + * @brief Implementation of the Engine class * * @section LICENSE * @@ -29,8 +29,9 @@ #include "engine.h" -Engine::Engine(GrooveWidget *p_grooveWidget, int p_portCount, QWidget *parent) : QWidget(parent), modified(false) +Engine::Engine(GrooveWidget *p_grooveWidget, int p_portCount, bool p_alsamidi, QWidget *parent) : QThread(parent), modified(false) { + ready = false; grooveWidget = p_grooveWidget; connect(grooveWidget, SIGNAL(newGrooveTick(int)), this, SLOT(setGrooveTick(int))); @@ -41,17 +42,36 @@ connect(grooveWidget->midiControl, SIGNAL(setMidiLearn(int, int, int)), this, SLOT(setMidiLearn(int, int, int))); portCount = p_portCount; - seqDriver = new SeqDriver(&midiArpList, &midiLfoList, &midiSeqList, portCount, this); - connect(seqDriver, SIGNAL(controlEvent(int, int, int)), - this, SLOT(handleController(int, int, int))); + + if (!p_alsamidi) { + driver = new JackDriver(portCount, this, tr_state_cb, midi_event_received_callback, tick_callback); + } + else { + // In case of ALSA MIDI with Jack Transport sync, JackDriver is instantiated with 0 ports + // a pointer to jackSync has to be passed to driver + jackSync = new JackDriver(0, this, tr_state_cb, midi_event_received_callback, tick_callback); + driver = new SeqDriver(jackSync, portCount, this, midi_event_received_callback, tick_callback); + } + midiLearnFlag = false; + midiControllable = true; grooveTick = 0; grooveVelocity = 0; grooveLength = 0; + schedDelayTicks = 2; + status = false; + sendLogEvents = false; + useMidiClock = false; + + resetTicks(0); + ready = true; } -Engine::~Engine(){ +Engine::~Engine() +{ + delete driver; } + //Arp handling void Engine::addMidiArp(MidiArp *midiArp) { @@ -66,8 +86,8 @@ void Engine::removeMidiArp(MidiArp *midiArp) { - if (seqDriver->runArp && (moduleWindowCount() < 1)) { - seqDriver->setQueueStatus(false); + if (status && (moduleWindowCount() < 1)) { + setStatus(false); } int i = midiArpList.indexOf(midiArp); if (i != -1) @@ -133,8 +153,24 @@ void Engine::sendGroove() { - for (int l1 = 0; l1 < midiArpList.count(); l1++) { - midiArpList.at(l1)->newGrooveValues(grooveTick, grooveVelocity, + int l1; + + for (l1 = 0; l1 < midiArpList.count(); l1++) { + midiArp(l1)->newGrooveValues(grooveTick, grooveVelocity, + grooveLength); + arpWidget(l1)->screen->newGrooveValues(grooveTick, grooveVelocity, + grooveLength); + } + for (l1 = 0; l1 < midiSeqList.count(); l1++) { + midiSeq(l1)->newGrooveValues(grooveTick, grooveVelocity, + grooveLength); + seqWidget(l1)->screen->newGrooveValues(grooveTick, grooveVelocity, + grooveLength); + } + for (l1 = 0; l1 < midiLfoList.count(); l1++) { + midiLfo(l1)->newGrooveValues(grooveTick, grooveVelocity, + grooveLength); + lfoWidget(l1)->screen->newGrooveValues(grooveTick, grooveVelocity, grooveLength); } } @@ -154,8 +190,8 @@ void Engine::removeMidiLfo(MidiLfo *midiLfo) { - if (seqDriver->runArp && (moduleWindowCount() < 1)) { - seqDriver->setQueueStatus(false); + if (status && (moduleWindowCount() < 1)) { + setStatus(false); } int i = midiLfoList.indexOf(midiLfo); if (i != -1) @@ -204,8 +240,8 @@ void Engine::removeMidiSeq(MidiSeq *midiSeq) { - if (seqDriver->runArp && (moduleWindowCount() < 1)) { - seqDriver->setQueueStatus(false); + if (status && (moduleWindowCount() < 1)) { + setStatus(false); } int i = midiSeqList.indexOf(midiSeq); if (i != -1) @@ -292,6 +328,19 @@ //general +void Engine::setCompactStyle(bool on) +{ + int l1; + if (on) { + for (l1 = 0; l1 < moduleWindowCount(); l1++) + moduleWindow(l1)->setStyleSheet(COMPACT_STYLE); + } + else { + for (l1 = 0; l1 < moduleWindowCount(); l1++) + moduleWindow(l1)->setStyleSheet(""); + } +} + bool Engine::isModified() { bool arpmodified = false; @@ -315,14 +364,12 @@ break; } - return modified || seqDriver->isModified() - || arpmodified || lfomodified || seqmodified; + return modified || arpmodified || lfomodified || seqmodified; } void Engine::setModified(bool m) { modified = m; - seqDriver->setModified(m); for (int l1 = 0; l1 < arpWidgetCount(); l1++) arpWidget(l1)->setModified(m); @@ -334,284 +381,300 @@ seqWidget(l1)->setModified(m); } +/* All following functions are the core engine of QMidiArp. They need to + * be made realtime-safe. + * They currently call different driver backend functions, which + * can eventually (hopefully) get a jackDriver equivalent, so that + * switching between the driver backends can be done from here. + */ + int Engine::getPortCount() { return(portCount); } -void Engine::runQueue(bool on) +int Engine::getClientId() { - if (midiArpList.count() > 0) - seqDriver->setQueueStatus(on); + return driver->getClientId(); } -int Engine::getAlsaClientId() +void Engine::setStatus(bool on) { - return seqDriver->getAlsaClientId(); -} - -void Engine::handleController(int ccnumber, int channel, int value) -{ - bool m; - int min, max, sval; - QVector cclist; - if (!midiLearnFlag) { - cclist = grooveWidget->midiControl->ccList; - for (int l2 = 0; l2 < cclist.count(); l2++) { - min = cclist.at(l2).min; - max = cclist.at(l2).max; - sval = min + ((double)value * (max - min) / 127); - if ((ccnumber == cclist.at(l2).ccnumber) && - (channel == cclist.at(l2).channel)) { - switch (cclist.at(l2).ID) { - case 0: - grooveWidget->grooveTick->setValue(sval); - return; - break; - - case 1: - grooveWidget->grooveVelocity->setValue(sval); - return; - break; - - case 2: - grooveWidget->grooveLength->setValue(sval); - return; - break; + if (moduleWindowCount()) { + if (!on) { + for (int l1 = 0; l1 < midiArpCount(); l1++) { + midiArp(l1)->clearNoteBuffer(); + } + } + status = on; + resetTicks(0); + driver->setTransportStatus(on); + } +} - default: - break; +void Engine::tick_callback(void * context, bool echo_from_trig) +{ + ((Engine *)context)->echoCallback(echo_from_trig); +} + +void Engine::echoCallback(bool echo_from_trig) +{ + int l1, l2; + QVector note, velocity; + int tick = driver->getCurrentTick(); + int note_tick = 0; + int length; + int outport; + bool isNew; + MidiEvent outEv; + + note.clear(); + velocity.clear(); + + //~ printf(" tick %d ",tick); + //~ printf("nextMinLfoTick %d ",nextMinLfoTick); + //~ printf("nextMinSeqTick %d ",nextMinSeqTick); + //~ printf("nextMinArpTick %d \n",nextMinArpTick); + + //LFO data request and queueing + //add 8 ticks to startoff condition to cope with initial sync imperfections + if (((tick + 8) >= nextMinLfoTick) && (midiLfoCount())) { + for (l1 = 0; l1 < midiLfoCount(); l1++) { + if ((echo_from_trig && midiLfo(l1)->gotKbdTrig) + || (!midiLfo(l1)->gotKbdTrig && !echo_from_trig)) { + if ((tick + 8) >= midiLfo(l1)->nextTick) { + outEv.type = EV_CONTROLLER; + outEv.data = midiLfo(l1)->ccnumber; + outEv.channel = midiLfo(l1)->channelOut; + lfoWidget(l1)->screen->updateScreen(lfoWidget(l1)->getFramePtr()); + midiLfo(l1)->getNextFrame(&lfoData, tick); + outport = midiLfo(l1)->portOut; + if (!midiLfo(l1)->isMuted) { + l2 = 0; + while (lfoData.at(l2).value > -1) { + if (!lfoData.at(l2).muted) { + outEv.value = lfoData.at(l2).value; + driver->sendMidiEvent(outEv, lfoData.at(l2).tick + , outport); + } + l2++; + } + } } } - } - for (int l1 = 0; l1 < arpWidgetCount(); l1++) { - cclist = arpWidget(l1)->midiControl->ccList; - for (int l2 = 0; l2 < cclist.count(); l2++) { - min = cclist.at(l2).min; - max = cclist.at(l2).max; - - if ((ccnumber == cclist.at(l2).ccnumber) && - (channel == cclist.at(l2).channel)) { - switch (cclist.at(l2).ID) { - case 0: if (min == max) { - if (value == max) { - m = arpWidget(l1)->muteOut->isChecked(); - arpWidget(l1)->muteOut->setChecked(!m); - return; - } - } - else { - if (value == max) { - arpWidget(l1)->muteOut->setChecked(false); - } - if (value == min) { - arpWidget(l1)->muteOut->setChecked(true); - } - } - break; - case 1: - sval = min + ((double)value * (max - min) - / 127); - arpWidget(l1)->selectPatternPreset(sval); - return; - break; - default: - break; + if (!l1) + nextMinLfoTick = midiLfo(l1)->nextTick; + else if (midiLfo(l1)->nextTick < nextMinLfoTick) + nextMinLfoTick = midiLfo(l1)->nextTick; + } + driver->requestEchoAt(nextMinLfoTick, 0); + } + + //Seq notes data request and queueing + //add 8 ticks to startoff condition to cope with initial sync imperfections + if (((tick + 8) >= nextMinSeqTick) && (midiSeqCount())) { + for (l1 = 0; l1 < midiSeqCount(); l1++) { + if ((echo_from_trig && midiSeq(l1)->gotKbdTrig) + || (!midiSeq(l1)->gotKbdTrig && !echo_from_trig)) { + if ((tick + 8) >= midiSeq(l1)->nextTick) { + outEv.type = EV_NOTEON; + outEv.value = midiSeq(l1)->vel; + outEv.channel = midiSeq(l1)->channelOut; + seqWidget(l1)->screen->updateScreen(seqWidget(l1)->getCurrentIndex()); + midiSeq(l1)->getNextNote(&seqSample, tick); + length = midiSeq(l1)->notelength; + outport = midiSeq(l1)->portOut; + if ((!midiSeq(l1)->isMuted) && (!seqSample.muted)) { + outEv.data = seqSample.value; + driver->sendMidiEvent(outEv, seqSample.tick, outport, length); } } } - } - - for (int l1 = 0; l1 < lfoWidgetCount(); l1++) { - cclist = lfoWidget(l1)->midiControl->ccList; - for (int l2 = 0; l2 < cclist.count(); l2++) { - min = cclist.at(l2).min; - max = cclist.at(l2).max; - if ((ccnumber == cclist.at(l2).ccnumber) && - (channel == cclist.at(l2).channel)) { - switch (cclist.at(l2).ID) { - case 0: if (min == max) { - if (value == max) { - m = lfoWidget(l1)->muteOut->isChecked(); - lfoWidget(l1)->muteOut->setChecked(!m); - return; - } - } - else { - if (value == max) { - lfoWidget(l1)->muteOut->setChecked(false); - } - if (value == min) { - lfoWidget(l1)->muteOut->setChecked(true); - } - } - break; - - case 1: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->amplitude->setValue(sval); - return; - break; - - case 2: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->offset->setValue(sval); - return; - break; - case 3: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->waveFormBox->setCurrentIndex(sval); - lfoWidget(l1)->updateWaveForm(sval); - return; - break; - case 4: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->freqBox->setCurrentIndex(sval); - lfoWidget(l1)->updateFreq(sval); - return; - break; - case 5: if (min == max) { - if (value == max) { - m = lfoWidget(l1)->recordAction->isChecked(); - lfoWidget(l1)->recordAction->setChecked(!m); - return; - } - } - else { - if (value == max) { - lfoWidget(l1)->recordAction->setChecked(true); - } - if (value == min) { - lfoWidget(l1)->recordAction->setChecked(false); - } - } - break; - case 6: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->resBox->setCurrentIndex(sval); - lfoWidget(l1)->updateRes(sval); - return; - break; - case 7: - sval = min + ((double)value * (max - min) - / 127); - lfoWidget(l1)->sizeBox->setCurrentIndex(sval); - lfoWidget(l1)->updateSize(sval); - return; - break; - - default: - break; + if (!l1) + nextMinSeqTick = midiSeq(l1)->nextTick; + else if (midiSeq(l1)->nextTick < nextMinSeqTick) + nextMinSeqTick = midiSeq(l1)->nextTick; + } + driver->requestEchoAt(nextMinSeqTick, 0); + } + + //Arp Note queueing + if ((tick + 8) >= nextMinArpTick) { + for (l1 = 0; l1 < midiArpCount(); l1++) { + if ((echo_from_trig && midiArp(l1)->gotKbdTrig) + || (!midiArp(l1)->gotKbdTrig && !echo_from_trig)) { + if ((tick + 8) >= midiArp(l1)->nextTick) { + outEv.type = EV_NOTEON; + outEv.channel = midiArp(l1)->channelOut; + midiArp(l1)->newRandomValues(); + midiArp(l1)->prepareCurrentNote(tick + schedDelayTicks); + note = midiArp(l1)->returnNote; + velocity = midiArp(l1)->returnVelocity; + note_tick = midiArp(l1)->returnTick; + length = midiArp(l1)->returnLength * 4; + outport = midiArp(l1)->portOut; + isNew = midiArp(l1)->returnIsNew; + arpWidget(l1)->screen->updateScreen(arpWidget(l1)->getGrooveIndex()); + if (!velocity.isEmpty()) { + if (isNew && velocity.at(0)) { + l2 = 0; + while(note.at(l2) >= 0) { + outEv.data = note.at(l2); + outEv.value = velocity.at(l2); + driver->sendMidiEvent(outEv, note_tick, outport, length); + l2++; + } + } } } } + if (!l1) + nextMinArpTick = midiArp(l1)->nextTick - schedDelayTicks; + else if (midiArp(l1)->nextTick < nextMinArpTick + schedDelayTicks) + nextMinArpTick = midiArp(l1)->nextTick - schedDelayTicks; } - for (int l1 = 0; l1 < seqWidgetCount(); l1++) { - cclist = seqWidget(l1)->midiControl->ccList; - for (int l2 = 0; l2 < cclist.count(); l2++) { - min = cclist.at(l2).min; - max = cclist.at(l2).max; - if ((ccnumber == cclist.at(l2).ccnumber) && - (channel == cclist.at(l2).channel)) { - switch (cclist.at(l2).ID) { - case 0: if (min == max) { - if (value == max) { - m = seqWidget(l1)->muteOut->isChecked(); - seqWidget(l1)->muteOut->setChecked(!m); - return; - } - } - else { - if (value == max) { - seqWidget(l1)->muteOut->setChecked(false); - } - if (value == min) { - seqWidget(l1)->muteOut->setChecked(true); - } - } - break; - - case 1: - sval = min + ((double)value * (max - min) - / 127); - seqWidget(l1)->velocity->setValue(sval); - return; - break; - - case 2: - sval = min + ((double)value * (max - min) - / 127); - seqWidget(l1)->notelength->setValue(sval); - return; - break; - - case 3: if (min == max) { - if (value == max) { - m = seqWidget(l1)->recordAction->isChecked(); - seqWidget(l1)->recordAction->setChecked(!m); - return; - } - } - else { - if (value == max) { - seqWidget(l1)->recordAction->setChecked(true); - } - if (value == min) { - seqWidget(l1)->recordAction->setChecked(false); - } - } - break; - case 4: - sval = min + ((double)value * (max - min) - / 127); - seqWidget(l1)->resBox->setCurrentIndex(sval); - seqWidget(l1)->updateRes(sval); - return; - break; - case 5: - sval = min + ((double)value * (max - min) - / 127); - seqWidget(l1)->sizeBox->setCurrentIndex(sval); - seqWidget(l1)->updateSize(sval); - return; - break; + if (0 > nextMinArpTick) nextMinArpTick = 0; + if (midiArpCount()) driver->requestEchoAt(nextMinArpTick, 0); + } +} - default: - break; - } - } - } +bool Engine::midi_event_received_callback(void * context, MidiEvent ev) +{ + return ((Engine *)context)->eventCallback(ev); +} + +bool Engine::eventCallback(MidiEvent inEv) +{ + bool unmatched; + int l1; + unmatched = true; + int tick = driver->getCurrentTick(); + + /* Does this cost time or other problems? The signal is sent to the LogWidget.*/ + if (sendLogEvents) emit midiEventReceived(inEv, tick); + + if (useMidiClock){ + if (inEv.type == EV_START) { + setStatus(true); + return(false); + } + if (inEv.type == EV_STOP) { + setStatus(false); + return(false); } } - else { - if (midiLearnWindowID == -1) { - grooveWidget->midiControl->appendMidiCC(midiLearnID, - ccnumber, channel, -100, 100); - midiLearnFlag = false; - return; - } - int min = (midiLearnID) ? 0 : 127; //if control is toggle min=max - if (moduleWindow(midiLearnWindowID)->objectName().startsWith("Arp")) { - arpWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, - ccnumber, channel, min, 127); - } - if (moduleWindow(midiLearnWindowID)->objectName().startsWith("LFO")) { - lfoWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, - ccnumber, channel, min, 127); - } - if (moduleWindow(midiLearnWindowID)->objectName().startsWith("Seq")) { - seqWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, - ccnumber, channel, min, 127); + + for (l1 = 0; l1 < midiLfoCount(); l1++) { + unmatched = midiLfo(l1)->handleEvent(inEv, tick); + if (midiLfo(l1)->gotKbdTrig) { + nextMinLfoTick = midiLfo(l1)->nextTick; + driver->requestEchoAt(nextMinLfoTick, true); } + } + for (l1 = 0; l1 < midiSeqCount(); l1++) { + unmatched = midiSeq(l1)->handleEvent(inEv, tick); + if (inEv.type == EV_NOTEON && !unmatched && inEv.value) { + seqWidget(l1)->processNote(inEv.data, inEv.value); + } + if (midiSeq(l1)->gotKbdTrig) { + nextMinSeqTick = midiSeq(l1)->nextTick; + driver->requestEchoAt(nextMinSeqTick, true); + } + } + for (l1 = 0; l1 < midiArpCount(); l1++) { + unmatched = midiArp(l1)->handleEvent(inEv, tick, 1); + if (midiArp(l1)->gotKbdTrig) { + nextMinArpTick = midiArp(l1)->nextTick; + driver->requestEchoAt(nextMinArpTick, true); + } + } + if (inEv.type == EV_CONTROLLER) { + if (midiControllable) { + if (!midiLearnFlag) + sendController(inEv.data, inEv.channel, inEv.value); + else + learnController(inEv.data, inEv.channel); + unmatched = false; + } + } + + return unmatched; +} + +void Engine::sendController(int ccnumber, int channel, int value) +{ + int l1; + + grooveWidget->handleController(ccnumber, channel, value); + + for (l1 = 0; l1 < arpWidgetCount(); l1++) + arpWidget(l1)->handleController(ccnumber, channel, value); + for (l1 = 0; l1 < lfoWidgetCount(); l1++) + lfoWidget(l1)->handleController(ccnumber, channel, value); + for (l1 = 0; l1 < seqWidgetCount(); l1++) + seqWidget(l1)->handleController(ccnumber, channel, value); +} + +void Engine::learnController(int ccnumber, int channel) +{ + if (midiLearnWindowID == -1) { + grooveWidget->midiControl->appendMidiCC(midiLearnID, + ccnumber, channel, -100, 100); midiLearnFlag = false; + return; + } + int min = (midiLearnID) ? 0 : 127; //if control is toggle min=max + if (moduleWindow(midiLearnWindowID)->objectName().startsWith("Arp")) { + arpWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, + ccnumber, channel, min, 127); + } + if (moduleWindow(midiLearnWindowID)->objectName().startsWith("LFO")) { + lfoWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, + ccnumber, channel, min, 127); + } + if (moduleWindow(midiLearnWindowID)->objectName().startsWith("Seq")) { + seqWidget(midiLearnModuleID)->midiControl->appendMidiCC(midiLearnID, + ccnumber, channel, min, 127); + } + + midiLearnFlag = false; +} + +void Engine::resetTicks(int curtick) +{ + int l1; + + for (l1 = 0; l1 < midiArpCount(); l1++) { + midiArp(l1)->foldReleaseTicks(curtick); + midiArp(l1)->initArpTick(0); + midiArp(l1)->nextTick = 0; + } + for (l1 = 0; l1 < midiLfoCount(); l1++) { + midiLfo(l1)->setFramePtr(0); + midiLfo(l1)->nextTick = 0; } + for (l1 = 0; l1 < midiSeqCount(); l1++) { + midiSeq(l1)->setCurrentIndex(0); + midiSeq(l1)->nextTick = 0; + } + nextMinLfoTick = 0; + nextMinSeqTick = 0; + nextMinArpTick = 0; +} + +void Engine::setMidiControllable(bool on) +{ + midiControllable = on; + modified = true; +} + +void Engine::setUseMidiClock(bool on) +{ + setStatus(false); + driver->setUseMidiClock(on); + useMidiClock = on; } void Engine::setMidiLearn(int moduleWindowID, int moduleID, int controlID) @@ -628,15 +691,22 @@ } } -void Engine::setCompactStyle(bool on) +void Engine::setTempo(int bpm) { - int l1; - if (on) { - for (l1 = 0; l1 < moduleWindowCount(); l1++) - moduleWindowList.at(l1)->setStyleSheet(COMPACT_STYLE); - } - else { - for (l1 = 0; l1 < moduleWindowCount(); l1++) - moduleWindowList.at(l1)->setStyleSheet(""); + driver->setTempo(bpm); + modified = true; +} + +void Engine::setSendLogEvents(bool on) +{ + sendLogEvents = on; +} + +void Engine::tr_state_cb(bool on, void *context) +{ + if (((Engine *)context)->ready) { + if (((Engine *)context)->driver->useJackSync) { + ((Engine *)context)->setStatus(on); + } } } diff -Nru qmidiarp-0.4.2/src/engine.h qmidiarp-0.4.5/src/engine.h --- qmidiarp-0.4.2/src/engine.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/engine.h 2012-01-21 17:14:21.000000000 +0000 @@ -1,6 +1,6 @@ /** * @file engine.h - * @brief Member definitions for the Engine module management class. + * @brief Header file for the Engine class * * @section LICENSE * @@ -25,10 +25,11 @@ #ifndef ENGINE_H #define ENGINE_H -#include +#include #include #include #include "seqdriver.h" +#include "jackdriver.h" #include "midiarp.h" #include "arpwidget.h" #include "midilfo.h" @@ -38,18 +39,19 @@ #include "groovewidget.h" /*! - * @brief Manages created module components in lists. Instantiates SeqDriver. + * @brief Core Engine Thread. Instantiates SeqDriver and JackDriver. * * For each module type there is a QList for each of * its components (for example MidiArp and ArpWidget). In parallel there is * a common list for all modules containing their DockWidgets. - * Engine also instantiates the SeqDriver MIDI backend and handles MIDI - * controller events through signaling by SeqDriver. Controllers are - * dispatched to the modules as requiered by their MIDI Learn - * MidiCCList. + * Engine also instantiates the MIDI Driver backend and processes MIDI + * events coming in and going out. It dispatches incoming events to the + * worker modules and schedules resulting events back to the driver. + * Controller events are dispatched to the modules as requiered by their + * MIDI Learn MidiCCList. * */ -class Engine : public QWidget { +class Engine : public QThread { Q_OBJECT @@ -63,17 +65,34 @@ QList seqWidgetList; int portCount; bool modified; - int mute_ccnumber, midiLearnID, midiLearnWindowID, midiLearnModuleID; - bool midi_mutable, midiLearnFlag; + int midiLearnID, midiLearnWindowID, midiLearnModuleID; + bool midiLearnFlag; + bool useMidiClock; + + //From SeqDriver + int schedDelayTicks; + int nextMinLfoTick; + int nextMinSeqTick; + int nextMinArpTick; + QVector lfoData; + Sample seqSample; + bool sendLogEvents; + + static bool midi_event_received_callback(void * context, MidiEvent ev); + static void tick_callback(void * context, bool echo_from_trig); + static void tr_state_cb(bool tr_state, void * context); public: int grooveTick, grooveVelocity, grooveLength; - - public: + bool midiControllable; + bool status; + bool ready; GrooveWidget *grooveWidget; - SeqDriver *seqDriver; + JackDriver *jackSync; + DriverBase *driver; - Engine(GrooveWidget *p_grooveWidget, int p_portCount, QWidget* parent=0); + public: + Engine(GrooveWidget *p_grooveWidget, int p_portCount, bool p_alsamidi, QWidget* parent=0); ~Engine(); int getPortCount(); bool isModified(); @@ -111,10 +130,20 @@ int seqWidgetCount(); MidiSeq *midiSeq(int index); SeqWidget *seqWidget(int index); - int getAlsaClientId(); + int getClientId(); + void setTempo(int bpm); + + signals: +/** + * @brief This signal is connected to the LogWidget::appendEvent() slot + * + * @param ev MidiEvent received by Engine + * @param tick Set to the tick value at which the event was received + */ + void midiEventReceived(MidiEvent ev, int tick); public slots: - void runQueue(bool); + void setStatus(bool); /** * @brief This function is used to set the modified flag, which is queried before * loading a new session file or quitting qmidiarp. @@ -123,13 +152,20 @@ */ void setModified(bool); void updatePatternPresets(const QString& n, const QString& p, int index); - void handleController(int ccnumber, int channel, int value); + void sendController(int ccnumber, int channel, int value); + void learnController(int ccnumber, int channel); void setMidiLearn(int moduleWindowID, int moduleID, int controlID); + void setMidiControllable(bool on); void setCompactStyle(bool on); void setGrooveTick(int grooveTick); void setGrooveVelocity(int grooveVelocity); void setGrooveLength(int grooveLength); void sendGroove(); + void setSendLogEvents(bool on); + void setUseMidiClock(bool on); + bool eventCallback(MidiEvent inEv); + void echoCallback(bool echo_from_trig); + void resetTicks(int curtick); }; #endif diff -Nru qmidiarp-0.4.2/src/groovewidget.cpp qmidiarp-0.4.5/src/groovewidget.cpp --- qmidiarp-0.4.2/src/groovewidget.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/groovewidget.cpp 2011-09-02 21:25:05.000000000 +0000 @@ -90,4 +90,33 @@ { emit(newGrooveLength(val)); } +void GrooveWidget::handleController(int ccnumber, int channel, int value) +{ + int min, max, sval; + QVector cclist= midiControl->ccList; + + for (int l2 = 0; l2 < cclist.count(); l2++) { + min = cclist.at(l2).min; + max = cclist.at(l2).max; + sval = min + ((double)value * (max - min) / 127); + if ((ccnumber == cclist.at(l2).ccnumber) && + (channel == cclist.at(l2).channel)) { + switch (cclist.at(l2).ID) { + case 0: + grooveTick->setValue(sval); + break; + + case 1: + grooveVelocity->setValue(sval); + break; + case 2: + grooveLength->setValue(sval); + break; + + default: + break; + } + } + } +} diff -Nru qmidiarp-0.4.2/src/groovewidget.h qmidiarp-0.4.5/src/groovewidget.h --- qmidiarp-0.4.2/src/groovewidget.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/groovewidget.h 2011-09-02 21:21:35.000000000 +0000 @@ -66,6 +66,7 @@ void updateGrooveVelocity(int); void updateGrooveTick(int); void updateGrooveLength(int); + void handleController(int ccnumber, int channel, int value); }; #endif diff -Nru qmidiarp-0.4.2/src/jackdriver.cpp qmidiarp-0.4.5/src/jackdriver.cpp --- qmidiarp-0.4.2/src/jackdriver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/src/jackdriver.cpp 2012-01-04 23:31:06.000000000 +0000 @@ -0,0 +1,495 @@ +/*! + * @file jackdriver.cpp + * @brief Implements the JackDriver QObject class. + * + * @section LICENSE + * + * Copyright 2009, 2010, 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include "jackdriver.h" +#include + + +JackDriver::JackDriver( + int p_portCount, + void * callback_context, + void (* p_tr_state_cb)(bool j_tr_state, void * context), + bool (* midi_event_received_callback)(void * context, MidiEvent ev), + void (* tick_callback)(void * context, bool echo_from_trig)) + : DriverBase(callback_context, midi_event_received_callback, tick_callback, 60e9) +{ + portCount = p_portCount; + cbContext = callback_context; + trStateCb = p_tr_state_cb; + jackRunning = false; + portUnmatched = 0; + forwardUnmatched = false; + + internalTempo = 120; + +/** Initialize and activate Jack with out_port_count ports if we use + * JACK driver backend, i.e. portCount > 0 */ + if (portCount) { + callJack(portCount); + transportState = getState(); + jSampleRate = jack_get_sample_rate(jack_handle); + setTransportStatus(false); + } + else { + transportState = JackTransportStopped; + } +} +void JackDriver::callJack(int port_count) +{ + if (port_count == -1 && jackRunning) { + deactivateJack(); + if (jack_handle != 0) { + jack_client_close(jack_handle); + jack_handle = 0; + } + } + else if (port_count != -1) { + if (initJack(port_count)) { + emit j_shutdown(); + } + else if (activateJack()) { + emit j_shutdown(); + } + } +} + +JackDriver::~JackDriver() +{ + if (jackRunning) { + deactivateJack(); + } + if (jack_handle != 0) { + jack_client_close(jack_handle); + jack_handle = 0; + } +} + +int JackDriver::initJack(int out_port_count) +{ + char buf[16]; + +#ifdef JACK_SESSION + if (global_jack_session_uuid.isEmpty() || !out_port_count) { + if ((jack_handle = jack_client_open(PACKAGE, JackNullOption, NULL)) == 0) { + qCritical("jack server not running?"); + return 1; + } + } + else if ((jack_handle = jack_client_open(PACKAGE, JackSessionID, NULL, global_jack_session_uuid.data())) == 0) { + qCritical("jack server not running?"); + return 1; + } +#else + if ((jack_handle = jack_client_open(PACKAGE, JackNullOption, NULL)) == 0) { + qCritical("jack server not running?"); + return 1; + } +#endif + + jack_on_shutdown(jack_handle, jack_shutdown, (void *)this); + + jack_set_process_callback(jack_handle, process_callback, (void *)this); + + qWarning("jack process callback registered"); + + if (!out_port_count) return(0); + + // register JACK MIDI input port + if ((in_port = jack_port_register(jack_handle, "in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0)) == 0) { + qCritical("Failed to register JACK MIDI input port."); + return 1; + } + + // register JACK MIDI output ports + for (int l1 = 0; l1 < out_port_count; l1++) + { + snprintf(buf, sizeof(buf), "out %d", l1 + 1); + if ((out_ports[l1] = jack_port_register(jack_handle, buf, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0)) == 0) + { + qCritical("Failed to register JACK MIDI output port."); + return 1; + } + } + +#ifdef JACK_SESSION + jack_set_session_callback(jack_handle, session_callback, (void *)this); + qWarning("Session callback registered"); +#endif + + return(0); +} + +int JackDriver::activateJack() +{ + if (jack_activate(jack_handle)) { + qWarning("cannot activate client"); + jackRunning = false; + return(1); + } + + jackRunning = true; + return(0); +} + +int JackDriver::deactivateJack() +{ + if (!jackRunning) return(0); + + if (jack_deactivate(jack_handle)) { + qWarning("cannot deactivate client"); + return(1); + } + jackRunning = false; + qWarning("jack client deactivated"); + return(0); +} + +void JackDriver::jack_shutdown(void *arg) +{ + JackDriver *rd = (JackDriver *) arg; + rd->setJackRunning(false); + + qWarning("JACK shut down. JACK sync Disabled."); + emit rd->j_shutdown(); +} + +int JackDriver::process_callback(jack_nframes_t nframes, void *arg) +{ + uint i; + uint l1, l2, size; + + JackDriver *rd = (JackDriver *) arg; + uint out_port_count = rd->portCount; + rd->jackTrCheckState(); + + if (!out_port_count) return (0); + + int cur_tempo = rd->tempo; + uint64_t cur_j_frame = rd->curJFrame; + bool forward_unmatched = rd->forwardUnmatched; + int port_unmatched = rd->portUnmatched; + + uint nexttick = 0; + uint tmptick = 0; + uint idx = 0; + int evport; + uint64_t ev_jframe, ev_sample; + uint ev_inframe; + MidiEvent inEv; + inEv.type = 0; + inEv.data = 0; + inEv.channel = 0; + inEv.value = 0; + MidiEvent outEv; + outEv.channel = 0; + + + unsigned char* buffer; + jack_midi_event_t in_event; + jack_nframes_t event_index = 0; + jack_nframes_t j_sample_rate = rd->jSampleRate; + void *in_buf = jack_port_get_buffer(rd->in_port, nframes); + void *out_buf[out_port_count]; + for (l1 = 0; l1 < out_port_count; l1++) { + out_buf[l1] = jack_port_get_buffer(rd->out_ports[l1], nframes); + } + for (l1 = 0; l1 < out_port_count; l1++) { + jack_midi_clear_buffer(out_buf[l1]); + } + + jack_nframes_t event_count = jack_midi_get_event_count(in_buf); + jack_midi_event_get(&in_event, in_buf, 0); + + for(i = 0; i < nframes; i++) { + + /** MIDI Output queue first **/ + size = rd->evTickQueue.size(); + if (size) { /** If we have events, find earliest event tick **/ + idx = 0; + nexttick = rd->evTickQueue.head(); + for (l1 = 0; l1 < size; l1++) { + tmptick = rd->evTickQueue.at(l1); + if (nexttick > tmptick) { + idx = l1; + nexttick = tmptick; + } + } + ev_sample = (uint64_t)j_sample_rate * 60 * nexttick / (TPQN * cur_tempo); + ev_jframe = ev_sample / nframes; + ev_inframe = ev_sample % nframes; + if ((ev_jframe <= cur_j_frame) && (ev_inframe <= i)) { + //qWarning("nexttick %d, ev_frame %d, ev_inframe %d, cur_jframe %d", nexttick, ev_jframe, ev_inframe, cur_j_frame); + outEv = rd->evQueue.takeAt(idx); + evport = rd->evPortQueue.takeAt(idx); + rd->evTickQueue.removeAt(idx); + int k = 0; + if ((ev_jframe) <= cur_j_frame) { + do { + if ((ev_jframe) < cur_j_frame) { + ev_inframe = 0; + } + buffer = jack_midi_event_reserve(out_buf[evport], ev_inframe + k, 3); + k++; + } while (buffer == NULL); + + buffer[2] = outEv.value; /** velocity / value **/ + buffer[1] = outEv.data; /** note / controller **/ + if (outEv.type == EV_NOTEON) buffer[0] = 0x90; + if (outEv.type == EV_CONTROLLER) buffer[0] = 0xb0; + buffer[0] += outEv.channel; + } + } + } + /** MIDI Input handling **/ + while ((in_event.time == i) && (event_index < event_count)) { + + if( ((*(in_event.buffer) & 0xf0)) == 0x90 ) { + inEv.type = EV_NOTEON; + inEv.value = *(in_event.buffer + 2); + } + else if( ((*(in_event.buffer)) & 0xf0) == 0x80 ) { + inEv.type = EV_NOTEON; + inEv.value = 0; + } + else if( ((*(in_event.buffer)) & 0xf0) == 0xa0 ) { + inEv.type = EV_KEYPRESS; + inEv.value = *(in_event.buffer + 2); + } + else if( ((*(in_event.buffer)) & 0xf0) == 0xb0 ) { + inEv.type = EV_CONTROLLER; + inEv.value = *(in_event.buffer + 2); + } + else if( ((*(in_event.buffer)) & 0xf0) == 0xc0 ) { + inEv.type = EV_PGMCHANGE; + inEv.value = *(in_event.buffer + 1); + } + else if( ((*(in_event.buffer)) & 0xf0) == 0xd0 ) { + inEv.type = EV_CHANPRESS; + inEv.value = *(in_event.buffer + 1); + } + else if( ((*(in_event.buffer)) & 0xf0) == 0xe0 ) { + inEv.type = EV_PITCHBEND; + inEv.value = *(in_event.buffer + 2) * 128; + inEv.value += *(in_event.buffer + 1); + inEv.value -= 8192; + } + else inEv.type = EV_NONE; + + inEv.data = *(in_event.buffer + 1); + inEv.channel = (*(in_event.buffer)) & 0x0f; + bool unmatched = rd->midi_event_received(inEv); + + if (unmatched && forward_unmatched) { + buffer = jack_midi_event_reserve(out_buf[port_unmatched], i, in_event.size); + if (buffer) { + for (l2 = 0; l2 < in_event.size; l2++) { + buffer[l2] = *(in_event.buffer + l2); + } + } + } + + event_index++; + if(event_index < event_count) + jack_midi_event_get(&in_event, in_buf, event_index); + } + } + rd->handleEchoes(nframes); + return(0); +} + +#ifdef JACK_SESSION +void JackDriver::session_callback(jack_session_event_t *event, void *arg ) +{ + JackDriver *rd = (JackDriver *) arg; + rd->jsEv = event; + rd->jack_session_event(); +} + +bool JackDriver::jack_session_event() +{ + jsFilename = jsEv->session_dir; + jsFilename += JSFILENAME; + + QString cmd = PACKAGE " ${SESSION_DIR}" JSFILENAME " --jack_session_uuid "; + cmd += jsEv->client_uuid; + cmd += " --portCount "+QString::number(portCount); + emit jsEvent(0); + + jsEv->command_line = strdup(cmd.toAscii()); + + jack_session_reply(jack_handle, jsEv); + + if(jsEv->type == JackSessionSaveAndQuit) emit jsEvent(1); + + jack_session_event_free(jsEv); + + return false; +} +#endif + + +void JackDriver::jackTrCheckState() +{ + if (!useJackSync) return; + + int state = getState(); + + if (transportState == state) return; + + transportState = state; + switch (state){ + case JackTransportStopped: + trStateCb(false, cbContext); + qWarning( "[JackTransportStopped]" ); + break; + + case JackTransportRolling: + trStateCb(true, cbContext); + qWarning( "[JackTransportRolling]" ); + break; + + case JackTransportStarting: + qWarning( "[JackTransportStarting]" ); + break; + + case JackTransportLooping: + qWarning( "[JackTransportLooping]" ); + break; + default: + break; + } +} + +jack_transport_state_t JackDriver::getState() +{ + return jack_transport_query(jack_handle, ¤tPos); +} + +void JackDriver::setJackRunning(bool on) +{ + jackRunning = on; +} + +jack_position_t JackDriver::getCurrentPos() +{ + return currentPos; +} + +void JackDriver::sendMidiEvent(MidiEvent ev, int n_tick, unsigned outport, unsigned duration) +{ + //qWarning("sendMidiEvent([%d, %d, %d, %d], %u, %u) at tick %d", ev.type, ev.channel, ev.data, ev.value, outport, duration, n_tick); + evQueue.append(ev); + evTickQueue.append(n_tick); + evPortQueue.append(outport); + + if ((ev.type == EV_NOTEON) && (ev.value)) { + ev.value = 0; + evQueue.append(ev); + evTickQueue.append(n_tick + duration / 4); + evPortQueue.append(outport); + } +} + +bool JackDriver::requestEchoAt(int echo_tick, bool echo_from_trig) +{ + if ((echo_tick == (int)lastSchedTick) && (echo_tick)) return false; + echoTickQueue.append(echo_tick); + lastSchedTick = echo_tick; + if (echo_from_trig) tick_callback(true); + + return true; + +} + +void JackDriver::handleEchoes(int nframes) +{ + curJFrame++; + + if (!queueStatus) return; + + int l1; + int size = echoTickQueue.size(); + int nexttick, tmptick, idx; + + if (useJackSync) { + m_current_tick = ((uint64_t)currentPos.frame * TPQN * tempo + / (currentPos.frame_rate * 60)) - jackOffsetTick; + } + else { + m_current_tick = (uint64_t)curJFrame * TPQN * tempo * nframes + / (jSampleRate * 60); + } + if (!size) return; + + idx = 0; + nexttick = echoTickQueue.head(); + + for (l1 = 0; l1 < size; l1++) { + tmptick = echoTickQueue.at(l1); + if (nexttick > tmptick) { + idx = l1; + nexttick = tmptick; + } + } + if (m_current_tick >= echoTickQueue.at(idx)) { + echoTickQueue.removeAt(idx); + tick_callback(false); + } +} + +void JackDriver::setTransportStatus(bool on) +{ + jack_position_t jpos = getCurrentPos(); + if (useJackSync) { + if (jpos.beats_per_minute > 0.01) + tempo = (int)jpos.beats_per_minute; + else + tempo = internalTempo; + + jackOffsetTick = (uint64_t)jpos.frame * TPQN + * tempo / (jpos.frame_rate * 60); + } + else { + tempo = internalTempo; + } + + m_current_tick = 0; + + if (on) { + curJFrame = 0; + lastSchedTick = 0; + echoTickQueue.clear(); + evQueue.clear(); + evTickQueue.clear(); + evPortQueue.clear(); + requestEchoAt(0); + qWarning("Internal Transport started"); + } + else { + qWarning("Internal Transport stopped"); + } + + queueStatus = on; +} diff -Nru qmidiarp-0.4.2/src/jackdriver.h qmidiarp-0.4.5/src/jackdriver.h --- qmidiarp-0.4.2/src/jackdriver.h 1970-01-01 00:00:00.000000000 +0000 +++ qmidiarp-0.4.5/src/jackdriver.h 2011-12-07 21:59:44.000000000 +0000 @@ -0,0 +1,122 @@ +/*! + * @file jackdriver.h + * @brief Headers for the JackDriver QObject class. + * + * @section LICENSE + * + * Copyright 2009, 2010, 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#ifndef JACKSYNC_H +#define JACKSYNC_H + +#include +#include +#include "config.h" +#include +#include +#include + +#ifdef JACK_SESSION +#include +#endif + +#include "main.h" +#include "driverbase.h" + +/*! + * The JackDriver class is a QObject providing access to the MIDI interface + * of the Jack Audio Connection Kit (JACK) transport system. It provides + * functions to register and initialise a jack client and to read the + * current frame position of a transport master. It establishes input and + * output ports if requested and implements a sequencer queue based on + * QQueue objects. + * + * @brief QObject class implementing a JACK MIDI and transport interface. + */ +class JackDriver : public DriverBase +{ + Q_OBJECT + + private: + static int process_callback(jack_nframes_t nframes, void *arg); + static void jack_shutdown(void *arg); +#ifdef JACK_SESSION + static void session_callback(jack_session_event_t *ev, void *arg); +#endif + void update_ports(); + + jack_port_t * in_port; + jack_port_t * out_ports[MAX_PORTS]; + + bool jackRunning; + int transportState; + uint lastSchedTick; + uint jackOffsetTick; + uint64_t curJFrame; + QQueue echoTickQueue; + QQueue evQueue; + QQueue evTickQueue; + QQueue evPortQueue; + jack_client_t *jack_handle; + jack_position_t currentPos; + void handleEchoes(int nframes); + +#ifdef JACK_SESSION + public: + jack_session_event_t *jsEv; + bool jack_session_event(); +#endif + + + public: + JackDriver(int p_portCount, + void * callback_context, + void (* p_tr_state_cb)(bool j_tr_state, void * context), + bool (* midi_event_received_callback)(void * context, MidiEvent ev), + void (* tick_callback)(void * context, bool echo_from_trig)); + ~JackDriver(); + + void (* trStateCb)(bool j_tr_state, void * context); + void * cbContext; + + signals: + void j_shutdown(); + void jsEvent(int type); + + public: + jack_nframes_t jSampleRate; + bool isRunning() { return jackRunning; } + int initJack(int out_port_count); + int activateJack(); + int deactivateJack(); + + void setJackRunning(bool on); + + void sendMidiEvent(MidiEvent ev, int n_tick, unsigned int outport, unsigned int duration = 0); + jack_transport_state_t getState(); + void jackTrCheckState(); + jack_position_t getCurrentPos(); + bool requestEchoAt(int echoTick, bool echo_from_trig = 0); + void setTransportStatus(bool run); + int getClientId() {return 0; } + void callJack(int port_count); +}; + + +#endif diff -Nru qmidiarp-0.4.2/src/jacksync.cpp qmidiarp-0.4.5/src/jacksync.cpp --- qmidiarp-0.4.2/src/jacksync.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/jacksync.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -/*! - * @file jacksync.cpp - * @brief Implements the JackSync QObject class. - * - * @section LICENSE - * - * Copyright 2009, 2010, 2011 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include "jacksync.h" -#include "config.h" - - -JackSync::JackSync(void (* p_tr_state_cb)(bool j_tr_state, void * context), - void * p_cb_context) -{ - transportState = JackTransportStopped; - cbContext = p_cb_context; - trStateCb = p_tr_state_cb; - } - -JackSync::~JackSync() -{ - if (jackRunning) { - deactivateJack(); - } - if (jack_handle != 0) { - jack_client_close(jack_handle); - jack_handle = 0; - } -} - -int JackSync::initJack() -{ - if ((jack_handle = jack_client_open(PACKAGE, JackNullOption, NULL)) == 0) { - qCritical("jack server not running?"); - return 1; - } - - jack_on_shutdown(jack_handle, jack_shutdown, (void *)this); - - jack_set_process_callback(jack_handle, process_callback, (void *)this); - - qWarning("jack process callback registered"); - - return(0); -} - -int JackSync::activateJack() -{ - if (jack_activate(jack_handle)) { - qWarning("cannot activate client"); - jackRunning = false; - return(1); - } - - jackRunning = true; - return(0); -} - -int JackSync::deactivateJack() -{ - if (jackRunning) { - if (jack_deactivate(jack_handle)) { - qWarning("cannot deactivate client"); - return(1); - } - jackRunning = false; - qWarning("jack client deactivated"); - } - return(0); -} - -void JackSync::jack_shutdown(void *arg) -{ - JackSync *rd = (JackSync *) arg; - rd->setJackRunning(false); - - qWarning("JACK shut down. JACK sync Disabled."); - emit rd->j_shutdown(); -} - -int JackSync::process_callback(jack_nframes_t nframes, void *arg) -{ - ((JackSync *)arg)->jackTrCheckState(); - return(0); -} - -void JackSync::jackTrCheckState() -{ - int state = getState(); - - if (transportState == state) return; - - transportState = state; - switch (state){ - case JackTransportStopped: - trStateCb(false, cbContext); - qWarning( "[JackTransportStopped]" ); - break; - - case JackTransportRolling: - trStateCb(true, cbContext); - qWarning( "[JackTransportRolling]" ); - break; - - case JackTransportStarting: - qWarning( "[JackTransportStarting]" ); - break; - - case JackTransportLooping: - qWarning( "[JackTransportLooping]" ); - break; - default: - break; - } -} - -jack_transport_state_t JackSync::getState() -{ - return jack_transport_query(jack_handle, ¤tPos); -} - -void JackSync::setJackRunning(bool on) -{ - jackRunning = on; -} - -jack_position_t JackSync::getCurrentPos() -{ - return currentPos; -} diff -Nru qmidiarp-0.4.2/src/jacksync.h qmidiarp-0.4.5/src/jacksync.h --- qmidiarp-0.4.2/src/jacksync.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/jacksync.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/*! - * @file jacksync.h - * @brief Headers for the JackSync QObject class. - * - * @section LICENSE - * - * Copyright 2009, 2010, 2011 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ -#ifndef JACKSYNC_H -#define JACKSYNC_H - -#include -#include -#include - -/*! - * The JackSync class is a QObject providing access to the transport status - * of the Jack Audio Connection Kit (JACK) transport system. It provides - * functions to register and initialise a jack client and to read the - * current frame position of a transport master. - * - * @brief QObject class providing access to jack transport status. - */ -class JackSync : public QObject -{ - Q_OBJECT - - private: - static int process_callback(jack_nframes_t nframes, void *arg); - static void jack_shutdown(void *arg); - - bool jackRunning; - int transportState; - jack_client_t *jack_handle; - jack_position_t currentPos; - - - public: - JackSync(void (* p_tr_state_cb)(bool j_tr_state, void * context), - void * p_cb_context); - ~JackSync(); - - void (* trStateCb)(bool j_tr_state, void * context); - void * cbContext; - - signals: - void j_shutdown(); - - public: - bool isRunning() { return jackRunning; } - int initJack(); - int activateJack(); - int deactivateJack(); - - void setJackRunning(bool on); - - jack_transport_state_t getState(); - void jackTrCheckState(); - jack_position_t getCurrentPos(); -}; - - -#endif diff -Nru qmidiarp-0.4.2/src/lfoscreen.cpp qmidiarp-0.4.5/src/lfoscreen.cpp --- qmidiarp-0.4.2/src/lfoscreen.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/lfoscreen.cpp 2012-01-11 22:18:36.000000000 +0000 @@ -38,6 +38,9 @@ mouseY = 0; xMax = LFOSCR_HMARG; currentIndex = 0; + grooveTick = 0; + grooveVelocity = 0; + grooveLength = 0; isMuted = false; } @@ -66,6 +69,7 @@ int x, x1; int beatRes = 1; int beatDiv = 0; + int grooveTmp = 0; l2 = 0; //Grid @@ -128,9 +132,10 @@ pen.setWidth(notestreak_thick); p.setPen(pen); + grooveTmp = (beatRes < 32) ? grooveTick : 0; for (l1 = 0; l1 < npoints; l1++) { - x = l1 * xscale * nsteps / npoints; + x = (l1 + .01 * (double)grooveTmp * (l1 % 2)) * nsteps * xscale / npoints; ypos = yscale - yscale * p_data.at(l1).value / 128 + LFOSCR_VMARG; xpos = LFOSCR_HMARG + x + pen.width() / 2; @@ -149,7 +154,7 @@ pen.setWidth(notestreak_thick * 2); pen.setColor(QColor(200, 180, 70)); p.setPen(pen); - x = currentIndex * xscale * (int)nsteps / npoints; + x = (currentIndex + .01 * (double)grooveTmp * (currentIndex % 2)) * xscale * (int)nsteps / npoints; xpos = LFOSCR_HMARG + x + pen.width() / 2; p.drawLine(xpos, h - 2, xpos + (xscale / beatRes) - pen.width(), h - 2); @@ -240,6 +245,14 @@ recordMode = on; } +void LfoScreen::newGrooveValues(int tick, int vel, int length) +{ + grooveTick = tick; + grooveVelocity = vel; + grooveLength = length; + update(); +} + QSize LfoScreen::sizeHint() const { return QSize(LFOSCR_MIN_W, LFOSCR_MIN_H); diff -Nru qmidiarp-0.4.2/src/lfoscreen.h qmidiarp-0.4.5/src/lfoscreen.h --- qmidiarp-0.4.2/src/lfoscreen.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/lfoscreen.h 2011-10-31 10:13:36.000000000 +0000 @@ -62,6 +62,7 @@ private: //QTimer *timer; QVector p_data, data; + int grooveTick, grooveVelocity, grooveLength; int mouseX, mouseY, mouseW; int w, h; int xMax; @@ -91,6 +92,7 @@ void mousePressEvent(QMouseEvent* event); void setRecord(bool on); void wheelEvent(QWheelEvent* event); + void newGrooveValues(int tick, int vel, int length); void setMuted(bool on); }; diff -Nru qmidiarp-0.4.2/src/lfowidget.cpp qmidiarp-0.4.5/src/lfowidget.cpp --- qmidiarp-0.4.2/src/lfowidget.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/lfowidget.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -51,7 +51,7 @@ int l1; QStringList midiCCNames; midiCCNames << "MuteToggle" << "Amplitude" << "Offset" << "WaveForm" << "Frequency" - << "RecordToggle"<< "Resolution"<< "Size" << "unknown"; + << "RecordToggle"<< "Resolution"<< "Size" << "LoopMode" << "unknown"; midiControl = new MidiControl(midiCCNames); manageBox = new ManageBox("LFO:", true, this); @@ -59,6 +59,28 @@ // Input group box on right top QGroupBox *inBox = new QGroupBox(tr("Input"), this); + QLabel *enableNoteOffLabel = new QLabel(tr("&Note Off"),inBox); + enableNoteOff = new QCheckBox(this); + connect(enableNoteOff, SIGNAL(toggled(bool)), this, SLOT(updateEnableNoteOff(bool))); + enableNoteOffLabel->setBuddy(enableNoteOff); + enableNoteOff->setToolTip(tr("Stop output when Note is released")); + + QLabel *enableRestartByKbdLabel = new QLabel(tr("&Restart"),inBox); + enableRestartByKbd = new QCheckBox(this); + connect(enableRestartByKbd, SIGNAL(toggled(bool)), this, SLOT(updateEnableRestartByKbd(bool))); + enableRestartByKbdLabel->setBuddy(enableRestartByKbd); + enableRestartByKbd->setToolTip(tr("Restart sequence when a new note is received")); + + QLabel *enableTrigByKbdLabel = new QLabel(tr("&Trigger"),inBox); + enableTrigByKbd = new QCheckBox(this); + connect(enableTrigByKbd, SIGNAL(toggled(bool)), this, SLOT(updateEnableTrigByKbd(bool))); + enableTrigByKbdLabel->setBuddy(enableTrigByKbd); + enableTrigByKbd->setToolTip(tr("Retrigger sequence when a new note is received")); + + enableNoteOff->setChecked(false); + enableRestartByKbd->setChecked(false); + enableTrigByKbd->setChecked(false); + QLabel *ccnumberInLabel = new QLabel(tr("MIDI &CC#"), inBox); ccnumberInBox = new QSpinBox(inBox); ccnumberInLabel->setBuddy(ccnumberInBox); @@ -80,8 +102,14 @@ inBoxLayout->addWidget(ccnumberInLabel, 0, 0); inBoxLayout->addWidget(ccnumberInBox, 0, 1); - inBoxLayout->addWidget(chInLabel, 2, 0); - inBoxLayout->addWidget(chIn, 2, 1); + inBoxLayout->addWidget(enableNoteOffLabel, 1, 0); + inBoxLayout->addWidget(enableNoteOff, 1, 1); + inBoxLayout->addWidget(enableRestartByKbdLabel, 2, 0); + inBoxLayout->addWidget(enableRestartByKbd, 2, 1); + inBoxLayout->addWidget(enableTrigByKbdLabel, 3, 0); + inBoxLayout->addWidget(enableTrigByKbd, 3, 1); + inBoxLayout->addWidget(chInLabel, 4, 0); + inBoxLayout->addWidget(chIn, 4, 1); if (compactStyle) { inBoxLayout->setSpacing(1); inBoxLayout->setMargin(2); @@ -225,6 +253,18 @@ SLOT(updateSize(int))); midiControl->addMidiLearnMenu(sizeBox, 7); + loopBox = new QComboBox(waveBox); + names.clear(); + names << "->_>" << " <_<-" << "->_<" << " >_<-" << "->_|" << " |_<-"; + loopBox->insertItems(0, names); + loopBox->setCurrentIndex(0); + loopBox->setToolTip(tr("Loop, bounce or play once going forward or backward")); + loopBox->setMinimumContentsLength(5); + connect(loopBox, SIGNAL(activated(int)), this, + SLOT(updateLoop(int))); + midiControl->addMidiLearnMenu(loopBox, 8); + + QLabel *recordButtonLabel = new QLabel(tr("Re&cord"), waveBox); recordAction = new QAction(QIcon(seqrecord_xpm), tr("Re&cord"), waveBox); recordAction->setToolTip(tr("Record incoming controller")); @@ -258,8 +298,9 @@ } QGridLayout *paramBoxLayout = new QGridLayout; - paramBoxLayout->addWidget(recordButtonLabel, 0, 0); - paramBoxLayout->addWidget(recordButton, 0, 1); + paramBoxLayout->addWidget(loopBox, 0, 0, 1, 2); + paramBoxLayout->addWidget(recordButtonLabel, 1, 0); + paramBoxLayout->addWidget(recordButton, 1, 1); paramBoxLayout->addWidget(waveFormBoxLabel, 0, 2); paramBoxLayout->addWidget(waveFormBox, 0, 3); paramBoxLayout->addWidget(freqBoxLabel, 1, 2); @@ -314,6 +355,12 @@ xml.writeStartElement(manageBox->name.left(3)); xml.writeAttribute("name", manageBox->name.mid(manageBox->name.indexOf(':') + 1)); xml.writeStartElement("input"); + xml.writeTextElement("enableNoteOff", QString::number( + midiWorker->enableNoteOff)); + xml.writeTextElement("restartByKbd", QString::number( + midiWorker->restartByKbd)); + xml.writeTextElement("trigByKbd", QString::number( + midiWorker->trigByKbd)); xml.writeTextElement("channel", QString::number( midiWorker->chIn)); xml.writeTextElement("ccnumber", QString::number( @@ -332,6 +379,8 @@ xml.writeEndElement(); xml.writeStartElement("waveParams"); + xml.writeTextElement("loopmode", QString::number( + loopBox->currentIndex())); xml.writeTextElement("waveform", QString::number( waveFormBox->currentIndex())); xml.writeTextElement("frequency", QString::number( @@ -387,6 +436,12 @@ xml.readNext(); if (xml.isEndElement()) break; + if (xml.name() == "enableNoteOff") + enableNoteOff->setChecked(xml.readElementText().toInt()); + else if (xml.name() == "restartByKbd") + enableRestartByKbd->setChecked(xml.readElementText().toInt()); + else if (xml.name() == "trigByKbd") + enableTrigByKbd->setChecked(xml.readElementText().toInt()); if (xml.name() == "channel") { tmp = xml.readElementText().toInt(); chIn->setCurrentIndex(tmp); @@ -426,7 +481,12 @@ xml.readNext(); if (xml.isEndElement()) break; - if (xml.name() == "waveform") + if (xml.name() == "loopmode") { + tmp = xml.readElementText().toInt(); + loopBox->setCurrentIndex(tmp); + updateLoop(tmp); + } + else if (xml.name() == "waveform") wvtmp = xml.readElementText().toInt(); else if (xml.name() == "frequency") { tmp = xml.readElementText().toInt(); @@ -515,91 +575,6 @@ } } -void LfoWidget::readDataText(QTextStream& arpText) -{ - QString qs, qs2; - int l1, lt, wvtmp; - Sample sample; - - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - channelOut->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - portOut->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - ccnumberBox->setValue(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - freqBox->setCurrentIndex(qs2.toInt()); - updateFreq(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - resBox->setCurrentIndex(qs2.toInt()); - updateRes(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - sizeBox->setCurrentIndex(qs2.toInt()); - updateSize(qs2.toInt()); - qs2 = qs.section(' ', 3, 3); - amplitude->setValue(qs2.toInt()); - qs2 = qs.section(' ', 4, 4); - offset->setValue(qs2.toInt()); - qs = arpText.readLine(); - if (qs == "MIDICC") - { - qs = arpText.readLine(); - while (qs != "EOCC") { - qs2 = qs.section(' ', 0, 0); - int controlID = qs2.toInt(); - qs2 = qs.section(' ', 1, 1); - int ccnumber = qs2.toInt(); - qs2 = qs.section(' ', 2, 2); - int channel = qs2.toInt(); - qs2 = qs.section(' ', 3, 3); - int min = qs2.toInt(); - qs2 = qs.section(' ', 4, 4); - int max = qs2.toInt(); - midiControl->appendMidiCC(controlID, ccnumber, channel, min, max); - qs = arpText.readLine(); - } - qs = arpText.readLine(); - } - - wvtmp = qs.toInt(); - - // Read Mute Mask - int step = TPQN / midiWorker->res; - qs = arpText.readLine(); - if (qs.isEmpty() || (qs == "EOP")) return; - qs2 = qs.section(' ', 0, 0); - midiWorker->muteMask.clear(); - l1 = 0; - while (qs2 !="EOM") { - midiWorker->muteMask.append(qs2.toInt()); - l1++; - if (!(l1%32)) qs = arpText.readLine(); - qs2 = qs.section(' ', l1%32, l1%32); - } - - // Read Custom Waveform - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - midiWorker->customWave.clear(); - l1 = 0; - lt = 0; - while (qs2 !="EOW") { - sample.value=qs2.toInt(); - sample.tick = lt; - sample.muted = midiWorker->muteMask.at(l1); - midiWorker->customWave.append(sample); - lt+=step; - l1++; - if (!(l1%16)) qs = arpText.readLine(); - qs2 = qs.section(' ', l1%16, l1%16); - } - waveFormBox->setCurrentIndex(wvtmp); - updateWaveForm(wvtmp); - modified = false; -} - void LfoWidget::loadWaveForms() { waveForms << tr("Sine") << tr("Saw up") << tr("Triangle") @@ -629,6 +604,23 @@ midiWorker->ccnumberIn = val; modified = true; } +void LfoWidget::updateEnableNoteOff(bool on) +{ + midiWorker->enableNoteOff = on; + modified = true; +} + +void LfoWidget::updateEnableRestartByKbd(bool on) +{ + midiWorker->restartByKbd = on; + modified = true; +} + +void LfoWidget::updateEnableTrigByKbd(bool on) +{ + midiWorker->trigByKbd = on; + modified = true; +} void LfoWidget::updateWaveForm(int val) { @@ -669,6 +661,7 @@ midiWorker->updateResolution(lfoResValues[val]); midiWorker->getData(&data); screen->updateScreen(data); + newCustomOffset(); modified = true; } @@ -678,6 +671,14 @@ midiWorker->updateSize(sizeBox->currentText().toInt()); midiWorker->getData(&data); screen->updateScreen(data); + newCustomOffset(); + modified = true; +} + +void LfoWidget::updateLoop(int val) +{ + if (val > 5) return; + midiWorker->updateLoop(val); modified = true; } @@ -709,7 +710,9 @@ { int min = 127; int value; - for (int l1 = 0; l1 < data.count() - 1; l1++) { + const int npoints = sizeBox->currentText().toInt() + * resBox->currentText().toInt(); + for (int l1 = 0; l1 < npoints; l1++) { value = data.at(l1).value; if (value < min) min = value; } @@ -814,6 +817,10 @@ { int tmp; + enableNoteOff->setChecked(fromWidget->enableNoteOff->isChecked()); + enableRestartByKbd->setChecked(fromWidget->enableRestartByKbd->isChecked()); + enableTrigByKbd->setChecked(fromWidget->enableTrigByKbd->isChecked()); + tmp = fromWidget->chIn->currentIndex(); chIn->setCurrentIndex(tmp); updateChIn(tmp); @@ -837,6 +844,9 @@ tmp = fromWidget->sizeBox->currentIndex(); sizeBox->setCurrentIndex(tmp); updateSize(tmp); + tmp = fromWidget->loopBox->currentIndex(); + loopBox->setCurrentIndex(tmp); + updateLoop(tmp); tmp = fromWidget->freqBox->currentIndex(); freqBox->setCurrentIndex(tmp); updateFreq(tmp); @@ -861,3 +871,88 @@ { return midiWorker->customWave; } + +void LfoWidget::handleController(int ccnumber, int channel, int value) +{ + bool m; + int min, max, sval; + QVector cclist= midiControl->ccList; + + for (int l2 = 0; l2 < cclist.count(); l2++) { + min = cclist.at(l2).min; + max = cclist.at(l2).max; + if ((ccnumber == cclist.at(l2).ccnumber) && + (channel == cclist.at(l2).channel)) { + switch (cclist.at(l2).ID) { + case 0: if (min == max) { + if (value == max) { + m = muteOut->isChecked(); + muteOut->setChecked(!m); + } + } + else { + if (value == max) { + muteOut->setChecked(false); + } + if (value == min) { + muteOut->setChecked(true); + } + } + break; + + case 1: + sval = min + ((double)value * (max - min) / 127); + amplitude->setValue(sval); + break; + + case 2: + sval = min + ((double)value * (max - min) / 127); + offset->setValue(sval); + break; + case 3: + sval = min + ((double)value * (max - min) / 127); + waveFormBox->setCurrentIndex(sval); + updateWaveForm(sval); + break; + case 4: + sval = min + ((double)value * (max - min) / 127); + freqBox->setCurrentIndex(sval); + updateFreq(sval); + break; + case 5: if (min == max) { + if (value == max) { + m = recordAction->isChecked(); + recordAction->setChecked(!m); + } + } + else { + if (value == max) { + recordAction->setChecked(true); + } + if (value == min) { + recordAction->setChecked(false); + } + } + break; + case 6: + sval = min + ((double)value * (max - min) / 127); + resBox->setCurrentIndex(sval); + updateRes(sval); + break; + case 7: + sval = min + ((double)value * (max - min) / 127); + sizeBox->setCurrentIndex(sval); + updateSize(sval); + break; + case 8: + sval = min + ((double)value * (max - min) / 127); + loopBox->setCurrentIndex(sval); + updateLoop(sval); + break; + + default: + break; + } + } + } +} diff -Nru qmidiarp-0.4.2/src/lfowidget.h qmidiarp-0.4.5/src/lfowidget.h --- qmidiarp-0.4.2/src/lfowidget.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/lfowidget.h 2012-01-21 17:14:21.000000000 +0000 @@ -111,7 +111,7 @@ * instance. * * @param p_midiWorker Associated MidiLfo Object - * @param portCount Number of available ALSA MIDI output ports + * @param portCount Number of available MIDI output ports * @param compactStyle If set to True, Widget will use reduced spacing and small fonts * @param mutedAdd If set to True, the module will be added in muted state * @param parent The parent widget of this module, i.e. MainWindow @@ -128,10 +128,13 @@ QComboBox *chIn; QSpinBox *ccnumberInBox; QSpinBox *ccnumberBox; - // Output channel / port (ALSA Sequencer) QComboBox *channelOut, *portOut; QComboBox *resBox, *sizeBox; + QComboBox *loopBox; QCheckBox *muteOut; + QCheckBox *enableNoteOff; + QCheckBox *enableRestartByKbd; + QCheckBox *enableTrigByKbd; Slider *frequency, *amplitude, *offset; QAction *recordAction; QComboBox *waveFormBox, *freqBox; @@ -154,13 +157,6 @@ */ void readData(QXmlStreamReader& xml); /*! -* @brief This function reads all LFO parameters of this module from an old -* QMidiArp .qma text stream. -* -* @param arpText QTextStream to read from -*/ - void readDataText(QTextStream& arpText); -/*! * @brief This function writes all parameters of this LFO to an XML stream * passed by the caller, i.e. MainWindow. * @@ -212,6 +208,9 @@ void updateCcnumberIn(int value); void updateScreen(int value); void setRecord(bool on); + void updateEnableNoteOff(bool on); + void updateEnableRestartByKbd(bool on); + void updateEnableTrigByKbd(bool on); /*! * @brief Slot for the LfoWidget::waveFormBox combobox setting the waveform @@ -239,6 +238,15 @@ */ void updateSize(int); /*! +* @brief Slot for the LfoWidget::loopBox combobox. Sets the loop mode +* of the LFO. +* +* It sets MidiLfo::reverse, MidiLfo::pingpong and MidiLfo::enableLoop +* @param val Combination index ranging from 0 to 5 +* +*/ + void updateLoop(int); +/*! * @brief Slot for the LfoWidget::ccnumberBox spinbox setting the output * controller CC number of this module. * @param val CC number to send data to @@ -353,6 +361,11 @@ * */ void setMuted(bool on); + + int getFramePtr() { return midiWorker->getFramePtr(); } + int getNextTick() { return midiWorker->nextTick; } + bool getReverse() { return midiWorker->reverse; } + void handleController(int ccnumber, int channel, int value); }; #endif diff -Nru qmidiarp-0.4.2/src/logwidget.cpp qmidiarp-0.4.5/src/logwidget.cpp --- qmidiarp-0.4.2/src/logwidget.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/logwidget.cpp 2011-08-29 18:32:25.000000000 +0000 @@ -26,15 +26,12 @@ #include #include #include -#include -#include #include -#include #include -#include #include "logwidget.h" + LogWidget::LogWidget(QWidget *parent) : QWidget(parent) { logActive = false; @@ -74,7 +71,7 @@ { } -void LogWidget::appendEvent(MidiEvent ev) { +void LogWidget::appendEvent(MidiEvent ev, int tick) { QString qs, qs2; @@ -83,33 +80,33 @@ } switch (ev.type) { case EV_NOTEON: - qs.sprintf("Ch %2d, Note On %3d, Vel %3d", + qs.sprintf("Ch %2d, Note On %3d, Vel %3d, tick %d", ev.channel + 1, - ev.data, ev.value); + ev.data, ev.value, tick); break; case EV_NOTEOFF: - qs.sprintf("Ch %2d, Note Off %3d", ev.channel+1, - ev.data); + qs.sprintf("Ch %2d, Note Off %3d, tick %d", ev.channel+1, + ev.data, tick); break; case EV_CONTROLLER: logText->setTextColor(QColor(100,160,0)); - qs.sprintf("Ch %2d, Ctrl %3d, Val %3d", ev.channel+1, - ev.data, ev.value); + qs.sprintf("Ch %2d, Ctrl %3d, Val %3d, tick %d", ev.channel+1, + ev.data, ev.value, tick); break; case EV_PITCHBEND: logText->setTextColor(QColor(100,0,255)); - qs.sprintf("Ch %2d, Pitch %5d", ev.channel+1, - ev.value); + qs.sprintf("Ch %2d, Pitch %5d, tick %d", ev.channel+1, + ev.value, tick); break; case EV_PGMCHANGE: logText->setTextColor(QColor(0,100,100)); - qs.sprintf("Ch %2d, PrgChg %5d", ev.channel+1, - ev.value); + qs.sprintf("Ch %2d, PrgChg %5d, tick %d", ev.channel+1, + ev.value, tick); break; case EV_CLOCK: if (logMidiActive) { logText->setTextColor(QColor(150,150,150)); - qs = tr("MIDI Clock"); + qs = tr("MIDI Clock, tick"); } break; case EV_START: diff -Nru qmidiarp-0.4.2/src/logwidget.h qmidiarp-0.4.5/src/logwidget.h --- qmidiarp-0.4.2/src/logwidget.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/logwidget.h 2011-08-29 18:32:25.000000000 +0000 @@ -26,14 +26,12 @@ #define LOGWIDGET_H #include +#include #include #include #include -#include #include -#include #include -#include #include "midievent.h" @@ -71,7 +69,7 @@ public slots: void logMidiToggle(bool on); void enableLogToggle(bool on); - void appendEvent(MidiEvent ev); + void appendEvent(MidiEvent ev, int tick); void appendText(const QString&); void clear(); }; diff -Nru qmidiarp-0.4.2/src/main.cpp qmidiarp-0.4.5/src/main.cpp --- qmidiarp-0.4.2/src/main.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/main.cpp 2011-11-07 20:44:13.000000000 +0000 @@ -3,7 +3,7 @@ * * Handles commandline arguments and options before MainWindow * construction. - * @mainpage A MIDI Arpeggiator, LFO and Step Sequencer for ALSA + * @mainpage A MIDI Arpeggiator, LFO and Step Sequencer * @section Description * This attempts to give an overview of the architecture of this * software. @@ -46,22 +46,34 @@ static struct option options[] = { {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, + {"alsa", 0, 0, 'a'}, + {"jack", 0, 0, 'j'}, + {"jack_session_uuid", required_argument, 0, 'U' }, {"portCount", 1, 0, 'p'}, {0, 0, 0, 0} }; +QString global_jack_session_uuid = ""; + int main(int argc, char *argv[]) { int getopt_return; int option_index; int portCount = 2; + bool alsamidi = false; + QString s; + QTextStream out(stdout); - while ((getopt_return = getopt_long(argc, argv, "vhp:", options, + while ((getopt_return = getopt_long(argc, argv, "vhajUp:", options, &option_index)) >= 0) { switch(getopt_return) { case 'v': - out << ABOUTMSG; + s = QString(ABOUTMSG); + s.replace(QString("
"), QString("\n")); + s.replace(QString("

"), QString("\n")); + s.remove(QRegExp("<[^>]*>")); + out << s; out.flush(); exit(EXIT_SUCCESS); @@ -73,11 +85,25 @@ "Print application version" << endl; out << " -h, --help " "Print this message" << endl; + out << " -a, --alsa " + "Use ALSA MIDI interface" << endl; + out << " -j, --jack " + "Use JACK MIDI interface (default)" << endl; out << QString(" -p, --portCount " "Number of output ports [%1]").arg(portCount) << endl; out.flush(); exit(EXIT_SUCCESS); + case 'a': + alsamidi = true; + break; + + case 'j': + alsamidi = false; + break; + case 'U': + global_jack_session_uuid = QString(optarg); + break; case 'p': portCount = atoi(optarg); if (portCount > MAX_PORTS) @@ -106,7 +132,7 @@ app.installTranslator(&qmidiarpTr); #endif - MainWindow* qmidiarp = new MainWindow(portCount); + MainWindow* qmidiarp = new MainWindow(portCount, alsamidi); if (optind < argc) { QFileInfo fi(argv[optind]); if (fi.exists()) diff -Nru qmidiarp-0.4.2/src/main.h qmidiarp-0.4.5/src/main.h --- qmidiarp-0.4.2/src/main.h 2011-03-26 12:31:07.000000000 +0000 +++ qmidiarp-0.4.5/src/main.h 2011-12-25 18:52:35.000000000 +0000 @@ -26,6 +26,8 @@ #include "midievent.h" +extern QString global_jack_session_uuid; + #define CT_FOOTSW 0x40 @@ -38,6 +40,8 @@ #define MAXCHORD 33 #define QMARCNAME ".qmidiarprc" +#define JSFILENAME "js_saved.qmax" + #define COMPACT_STYLE "QLabel { font: 7pt; } \ QComboBox { font: 7pt; max-height: 15px;} \ QToolButton { max-height: 20px;} \ diff -Nru qmidiarp-0.4.2/src/mainwindow.cpp qmidiarp-0.4.5/src/mainwindow.cpp --- qmidiarp-0.4.2/src/mainwindow.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/mainwindow.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -69,22 +69,24 @@ int MainWindow::sigpipe[2]; -MainWindow::MainWindow(int p_portCount) +MainWindow::MainWindow(int p_portCount, bool p_alsamidi) { filename = ""; lastDir = QDir::homePath(); + alsaMidi = p_alsamidi; grooveWidget = new GrooveWidget(this); grooveWindow = new QDockWidget(tr("Groove"), this); grooveWindow->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); - grooveWindow->setWidget(grooveWidget);; + grooveWindow->setWidget(grooveWidget); grooveWindow->setObjectName("grooveWidget"); grooveWindow->setVisible(true); addDockWidget(Qt::BottomDockWidgetArea, grooveWindow); - engine = new Engine(grooveWidget, p_portCount, this); + engine = new Engine(grooveWidget, p_portCount, alsaMidi, this); + if (!alsaMidi) connect(engine->driver, SIGNAL(jsEvent(int)), this, SLOT(jsAction(int))); midiCCTable = new MidiCCTable(engine, this); @@ -97,17 +99,14 @@ logWindow->setObjectName("logWidget"); addDockWidget(Qt::BottomDockWidgetArea, logWindow); qRegisterMetaType("MidiEvent"); - connect(engine->seqDriver, SIGNAL(midiEvent(MidiEvent)), - logWidget, SLOT(appendEvent(MidiEvent))); + connect(engine, SIGNAL(midiEventReceived(MidiEvent, int)), + logWidget, SLOT(appendEvent(MidiEvent, int))); connect(logWidget, SIGNAL(sendLogEvents(bool)), - engine->seqDriver, SLOT(setSendLogEvents(bool))); + engine, SLOT(setSendLogEvents(bool))); passWidget = new PassWidget(engine, p_portCount, this); - connect(this, SIGNAL(runQueue(bool)), - engine->seqDriver, SLOT(setQueueStatus(bool))); - addArpAction = new QAction(QIcon(arpadd_xpm), tr("&New Arp..."), this); addArpAction->setShortcut(QKeySequence(tr("Ctrl+A", "Module|New Arp"))); addArpAction->setToolTip(tr("Add new arpeggiator to tab bar")); @@ -151,7 +150,7 @@ connect(fileQuitAction, SIGNAL(triggered()), this, SLOT(close())); runAction = new QAction(QIcon(play_xpm), tr("&Run with internal clock"), this); - connect(runAction, SIGNAL(toggled(bool)), this, SLOT(updateRunQueue(bool))); + connect(runAction, SIGNAL(toggled(bool)), this, SLOT(updateTransportStatus(bool))); runAction->setCheckable(true); runAction->setChecked(false); runAction->setDisabled(true); @@ -176,15 +175,20 @@ jackSyncAction = new QAction(QIcon(jacktr_xpm), tr("&Connect to Jack Transport"), this); jackSyncAction->setCheckable(true); - jackSyncAction->setChecked(false); - jackSyncAction->setDisabled(true); connect(jackSyncAction, SIGNAL(toggled(bool)), this, SLOT(jackSyncToggle(bool))); - connect(engine->seqDriver, SIGNAL(jackShutdown(bool)), - jackSyncAction, SLOT(setChecked(bool))); - + if (alsaMidi) { + connect(engine->jackSync, SIGNAL(j_shutdown()), this, + SLOT(jackShutdown())); + } + else { + connect(engine->driver, SIGNAL(j_shutdown()), this, + SLOT(jackShutdown())); + } + jackSyncAction->setChecked(false); + jackSyncAction->setDisabled(true); - updateRunQueue(false); + updateTransportStatus(false); QAction* viewLogAction = logWindow->toggleViewAction(); viewLogAction->setIcon(QIcon(eventlog_xpm)); @@ -298,12 +302,12 @@ if (filename.isEmpty()) setWindowTitle(QString("%1 (%2)") .arg(APP_NAME) - .arg(engine->getAlsaClientId())); + .arg(engine->getClientId())); else setWindowTitle(QString("%1 - %2 (%3)") .arg(filename) .arg(APP_NAME) - .arg(engine->getAlsaClientId())); + .arg(engine->getClientId())); } void MainWindow::helpAbout() @@ -359,12 +363,9 @@ { int count, widgetID; MidiArp *midiWorker = new MidiArp(); - engine->addMidiArp(midiWorker); ArpWidget *moduleWidget = new ArpWidget(midiWorker, engine->getPortCount(), passWidget->compactStyle, passWidget->mutedAdd, this); - connect(midiWorker, SIGNAL(nextStep(int)), - moduleWidget->screen, SLOT(updateScreen(int))); connect(moduleWidget, SIGNAL(presetsChanged(const QString&, const QString&, int)), this, SLOT(updatePatternPresets(const QString&, const @@ -376,18 +377,12 @@ connect(moduleWidget->midiControl, SIGNAL(setMidiLearn(int, int, int)), engine, SLOT(setMidiLearn(int, int, int))); - connect(grooveWidget, SIGNAL(newGrooveTick(int)), - moduleWidget->screen, SLOT(setGrooveTick(int))); - connect(grooveWidget, SIGNAL(newGrooveVelocity(int)), - moduleWidget->screen, SLOT(setGrooveVelocity(int))); - connect(grooveWidget, SIGNAL(newGrooveLength(int)), - moduleWidget->screen, SLOT(setGrooveLength(int))); - widgetID = engine->arpWidgetCount(); moduleWidget->manageBox->name = name; moduleWidget->manageBox->ID = widgetID; moduleWidget->midiControl->ID = widgetID; + engine->addMidiArp(midiWorker); engine->addArpWidget(moduleWidget); engine->sendGroove(); @@ -403,12 +398,9 @@ { int widgetID, count; MidiLfo *midiWorker = new MidiLfo(); - engine->addMidiLfo(midiWorker); LfoWidget *moduleWidget = new LfoWidget(midiWorker, engine->getPortCount(), passWidget->compactStyle, passWidget->mutedAdd, this); - connect(midiWorker, SIGNAL(nextStep(int)), - moduleWidget, SLOT(updateScreen(int))); connect(moduleWidget->manageBox, SIGNAL(moduleRemove(int)), this, SLOT(removeLfo(int))); connect(moduleWidget->manageBox, SIGNAL(moduleClone(int)), this, SLOT(cloneLfo(int))); @@ -422,6 +414,7 @@ moduleWidget->manageBox->ID = widgetID; moduleWidget->midiControl->ID = widgetID; + engine->addMidiLfo(midiWorker); engine->addLfoWidget(moduleWidget); count = engine->moduleWindowCount(); moduleWidget->manageBox->parentDockID = count; @@ -435,26 +428,22 @@ { int widgetID, count; MidiSeq *midiWorker = new MidiSeq(); - engine->addMidiSeq(midiWorker); SeqWidget *moduleWidget = new SeqWidget(midiWorker, engine->getPortCount(), passWidget->compactStyle, passWidget->mutedAdd, this); - connect(midiWorker, SIGNAL(nextStep(int)), - moduleWidget->screen, SLOT(updateScreen(int))); connect(moduleWidget->manageBox, SIGNAL(moduleRemove(int)), this, SLOT(removeSeq(int))); connect(moduleWidget->manageBox, SIGNAL(moduleClone(int)), this, SLOT(cloneSeq(int))); connect(moduleWidget->manageBox, SIGNAL(dockRename(const QString&, int)), this, SLOT(renameDock(const QString&, int))); connect(moduleWidget->midiControl, SIGNAL(setMidiLearn(int, int, int)), engine, SLOT(setMidiLearn(int, int, int))); - connect(midiWorker, SIGNAL(noteEvent(int, int)), - moduleWidget, SLOT(processNote(int, int))); widgetID = engine->seqWidgetCount(); moduleWidget->manageBox->name = name; moduleWidget->manageBox->ID = widgetID; moduleWidget->midiControl->ID = widgetID; + engine->addMidiSeq(midiWorker); engine->addSeqWidget(moduleWidget); count = engine->moduleWindowCount(); moduleWidget->manageBox->parentDockID = count; @@ -468,12 +457,9 @@ { int widgetID, count; MidiLfo *midiWorker = new MidiLfo(); - engine->addMidiLfo(midiWorker); LfoWidget *moduleWidget = new LfoWidget(midiWorker, engine->getPortCount(), passWidget->compactStyle, passWidget->mutedAdd, this); - connect(midiWorker, SIGNAL(nextStep(int)), - moduleWidget, SLOT(updateScreen(int))); connect(moduleWidget->manageBox, SIGNAL(moduleRemove(int)), this, SLOT(removeLfo(int))); connect(moduleWidget->manageBox, SIGNAL(moduleClone(int)), this, SLOT(cloneLfo(int))); @@ -488,14 +474,16 @@ moduleWidget->midiControl->ID = widgetID; moduleWidget->copyParamsFrom(engine->lfoWidget(ID)); - + midiWorker->reverse = engine->lfoWidget(ID)->getReverse(); + midiWorker->setFramePtr(engine->lfoWidget(ID)->getFramePtr()); + midiWorker->nextTick = engine->lfoWidget(ID)->getNextTick(); + engine->addMidiLfo(midiWorker); engine->addLfoWidget(moduleWidget); count = engine->moduleWindowCount(); moduleWidget->manageBox->parentDockID = count; moduleWidget->midiControl->parentDockID = count; appendDock(moduleWidget, moduleWidget->manageBox->name, count); - checkIfFirstModule(); } void MainWindow::cloneSeq(int ID) @@ -504,20 +492,15 @@ QString name; MidiSeq *midiWorker = new MidiSeq(); - engine->addMidiSeq(midiWorker); SeqWidget *moduleWidget = new SeqWidget(midiWorker, engine->getPortCount(), passWidget->compactStyle, passWidget->mutedAdd, this); - connect(midiWorker, SIGNAL(nextStep(int)), - moduleWidget->screen, SLOT(updateScreen(int))); connect(moduleWidget->manageBox, SIGNAL(moduleRemove(int)), this, SLOT(removeSeq(int))); connect(moduleWidget->manageBox, SIGNAL(moduleClone(int)), this, SLOT(cloneSeq(int))); connect(moduleWidget->manageBox, SIGNAL(dockRename(const QString&, int)), this, SLOT(renameDock(const QString&, int))); connect(moduleWidget->midiControl, SIGNAL(setMidiLearn(int, int, int)), engine, SLOT(setMidiLearn(int, int, int))); - connect(midiWorker, SIGNAL(noteEvent(int, int)), - moduleWidget, SLOT(processNote(int, int))); widgetID = engine->seqWidgetCount(); moduleWidget->manageBox->name = engine->seqWidget(ID)->manageBox->name + "_0"; @@ -525,12 +508,16 @@ moduleWidget->midiControl->ID = widgetID; moduleWidget->copyParamsFrom(engine->seqWidget(ID)); - + midiWorker->reverse = engine->lfoWidget(ID)->getReverse(); + midiWorker->setCurrentIndex(engine->seqWidget(ID)->getCurrentIndex()); + midiWorker->nextTick = engine->seqWidget(ID)->getNextTick(); + engine->addMidiSeq(midiWorker); engine->addSeqWidget(moduleWidget); count = engine->moduleWindowCount(); moduleWidget->manageBox->parentDockID = count; moduleWidget->midiControl->parentDockID = count; appendDock(moduleWidget, moduleWidget->manageBox->name, count); + } void MainWindow::appendDock(QWidget *moduleWidget, const QString &name, int count) @@ -603,7 +590,7 @@ void MainWindow::clear() { - updateRunQueue(false); + updateTransportStatus(false); jackSyncToggle(false); while (engine->midiArpCount()) { @@ -617,6 +604,8 @@ while (engine->midiSeqCount()) { removeSeq(engine->midiSeqCount() - 1); } + + grooveWidget->midiControl->ccList.clear(); } void MainWindow::fileNew() @@ -639,15 +628,11 @@ { QString fn = QFileDialog::getOpenFileName(this, tr("Open arpeggiator file"), lastDir, - tr("QMidiArp XML files") + " (*" + FILEEXT + ");;" - + tr("Old QMidiArp files") + " (*.qma)"); + tr("QMidiArp XML files") + " (*" + FILEEXT + ")"); if (fn.isEmpty()) return; - if (fn.endsWith(".qma")) - openTextFile(fn); - - else if (fn.endsWith(FILEEXT)) + if (fn.endsWith(FILEEXT)) openFile(fn); } @@ -719,10 +704,14 @@ break; if (xml.name() == "midiControlEnabled") passWidget->cbuttonCheck->setChecked(xml.readElementText().toInt()); - else if (xml.name() == "midiClockEnabled") - midiClockAction->setChecked(xml.readElementText().toInt()); - else if (xml.name() == "jackSyncEnabled") - jackSyncAction->setChecked(xml.readElementText().toInt()); + else if (xml.name() == "midiClockEnabled") { + bool tmp = xml.readElementText().toInt(); + if (alsaMidi) midiClockAction->setChecked(tmp); + } + else if (xml.name() == "jackSyncEnabled") { + bool tmp = xml.readElementText().toInt(); + jackSyncAction->setChecked(tmp); + } else if (xml.name() == "forwardUnmatched") passWidget->setForward(xml.readElementText().toInt()); else if (xml.name() == "forwardPort") @@ -807,110 +796,6 @@ } } -void MainWindow::openTextFile(const QString& fn) -{ - QString line, qs, qs2; - bool midiclocktmp = false; - int c = 0; - - lastDir = fn.left(fn.lastIndexOf('/')); - - QFile f(fn); - if (!f.open(QIODevice::ReadOnly)) { - QMessageBox::warning(this, APP_NAME, - tr("Could not read from file '%1'.").arg(fn)); - return; - } - - clear(); - filename = fn; - - QTextStream loadText(&f); - qs = loadText.readLine(); - if (qs == "Tempo") - { - qs = loadText.readLine(); - tempoSpin->setValue(qs.toInt()); - qs = loadText.readLine(); - } - if (qs == "MIDI Control") - { - qs = loadText.readLine(); - qs2 = qs.section(' ', 0, 0); - passWidget->cbuttonCheck->setChecked(qs2.toInt()); - qs = loadText.readLine(); - } - if (qs == "MIDI Clock") - { - qs = loadText.readLine(); - qs2 = qs.section(' ', 0, 0); - midiclocktmp = qs2.toInt(); - qs = loadText.readLine(); - } - qs2 = qs.section(' ', 0, 0); - passWidget->setForward(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - passWidget->setPortUnmatched(qs2.toInt() + 1); - qs = loadText.readLine(); - qs2 = qs.section(' ', 0, 0); - - grooveWidget->grooveTick->setValue(qs2.toInt()); - // engine->seqDriver->setGrooveTick(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - grooveWidget->grooveVelocity->setValue(qs2.toInt()); - // engine->seqDriver->setGrooveVelocity(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - grooveWidget->grooveLength->setValue(qs2.toInt()); - // engine->seqDriver->setGrooveLength(qs2.toInt()); - - while (!loadText.atEnd()) { - qs = loadText.readLine(); - if (qs.startsWith("GUI")) - break; - if (qs.startsWith("Seq:")) - c = 1; - if (qs.startsWith("LFO:")) - c = 2; - if (qs.startsWith("Arp:")) - c = 3; - - switch (c) { - case 1: - addSeq(qs); - engine->seqWidget(engine->midiSeqCount() - 1)->readDataText(loadText); - break; - case 2: - addLfo(qs); - engine->lfoWidget(engine->midiLfoCount() - 1)->readDataText(loadText); - break; - case 3: - addArp(qs); - engine->arpWidget(engine->midiArpCount() - 1)->readDataText(loadText); - break; - default: - qs = "Arp: " + qs; - addArp(qs); - engine->arpWidget(engine->midiArpCount() - 1)->readDataText(loadText); - break; - } - } - - if (qs.startsWith("GUI")) { - qs = loadText.readLine(); - QByteArray array = QByteArray::fromHex(qs.toLatin1()); - restoreState(array); - } - - midiClockAction->setChecked(midiclocktmp); - - filename.append("x"); - QMessageBox::warning(this, APP_NAME, - tr("The QMidiArp text file was imported. If you save this file, \ -it will be saved using the newer xml format under the name\n '%1'.").arg(filename)); - - updateWindowTitle(); -} - void MainWindow::fileSave() { if (filename.isEmpty()) @@ -951,13 +836,13 @@ xml.writeTextElement("midiControlEnabled", QString::number((int)passWidget->cbuttonCheck->isChecked())); xml.writeTextElement("midiClockEnabled", - QString::number((int)engine->seqDriver->use_midiclock)); + QString::number((int)engine->driver->useMidiClock)); xml.writeTextElement("jackSyncEnabled", - QString::number((int)engine->seqDriver->use_jacksync)); + QString::number((int)engine->driver->useJackSync)); xml.writeTextElement("forwardUnmatched", - QString::number((int)engine->seqDriver->forwardUnmatched)); + QString::number((int)engine->driver->forwardUnmatched)); xml.writeTextElement("forwardPort", - QString::number(engine->seqDriver->portUnmatched)); + QString::number(engine->driver->portUnmatched)); xml.writeEndElement(); xml.writeStartElement("groove"); @@ -1085,25 +970,24 @@ void MainWindow::updateTempo(int p_tempo) { - engine->seqDriver->setQueueTempo(p_tempo); - engine->setModified(true); + engine->setTempo(p_tempo); } -void MainWindow::updateRunQueue(bool on) +void MainWindow::updateTransportStatus(bool on) { - emit(runQueue(on)); + engine->setStatus(on); tempoSpin->setDisabled(on); } -void MainWindow::resetQueue() +void MainWindow::resetTransport() { - engine->seqDriver->setQueueStatus(engine->seqDriver->runArp); + engine->setStatus(engine->status); } void MainWindow::midiClockToggle(bool on) { if (on) jackSyncAction->setChecked(false); - engine->seqDriver->setUseMidiClock(on); + engine->setUseMidiClock(on); setGUIforExtSync(on); } @@ -1111,18 +995,27 @@ { if (on) midiClockAction->setChecked(false); setGUIforExtSync(on); - engine->seqDriver->setUseJackTransport(on); + engine->driver->setUseJackTransport(on); +} + +void MainWindow::jackShutdown() +{ + engine->setStatus(false); + jackSyncAction->setChecked(false); + jackSyncAction->setDisabled(true); } void MainWindow::setGUIforExtSync(bool on) { runAction->setDisabled(on); tempoSpin->setDisabled(on); + /* addArpAction->setDisabled(on); addLfoAction->setDisabled(on); addSeqAction->setDisabled(on); fileOpenAction->setDisabled(on); fileRecentlyOpenedFiles->setDisabled(on); + * */ } bool MainWindow::checkRcFile() @@ -1330,7 +1223,7 @@ void MainWindow::checkIfFirstModule() { if (engine->moduleWindowCount() == 1) { - midiClockAction->setEnabled(true); + if (alsaMidi) midiClockAction->setEnabled(true); jackSyncAction->setEnabled(true); runAction->setEnabled(!(midiClockAction->isChecked() || jackSyncAction->isChecked())); @@ -1406,6 +1299,22 @@ } } +void MainWindow::jsAction(int evtype) +{ + if (!evtype) { + filename = engine->driver->jsFilename; + qWarning("JACK Session request to save"); + lastDir = filename.left(filename.lastIndexOf('/')); + updateWindowTitle(); + bool result = saveFile(); + if (!result) qWarning("Warning: JACK Session File save failed"); + } + else if (evtype == 1) + { + close(); + } +} + void MainWindow::ctb_update_orientation(Qt::Orientation orient) { if (orient == Qt::Vertical) { diff -Nru qmidiarp-0.4.2/src/mainwindow.h qmidiarp-0.4.5/src/mainwindow.h --- qmidiarp-0.4.2/src/mainwindow.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/mainwindow.h 2012-01-21 17:14:21.000000000 +0000 @@ -42,11 +42,17 @@ #include "groovewidget.h" #include "config.h" +#ifdef JACK_SESSION +#include +#endif + + static const char ABOUTMSG[] = "

" APP_NAME " " PACKAGE_VERSION "

" - "

(C) 2002-2003 Matthias Nagorni (SuSE AG Nuremberg)
" - "(C) 2009-2011 Frank Kober
" - "(C) 2009 Guido Scholz

" + "

(C) 2009-2011 Frank Kober
" + "(C) 2011 Nedko Arnaudov
" + "(C) 2009 Guido Scholz
" + "(C) 2002-2003 Matthias Nagorni (SuSE AG Nuremberg)

" "

For getting support please type man qmidiarp or go to
" "" "http://qmidiarp.sourceforge.net

" @@ -68,6 +74,7 @@ private: static int sigpipe[2]; + bool alsaMidi; QSpinBox *tempoSpin; PassWidget *passWidget; GrooveWidget *grooveWidget; @@ -262,7 +269,7 @@ * * It removes all module components, i.e. the Midi workers, UI widgets * and DockWidgets. It disconnects jack transport and stops the -* ALSA Queue if running. +* transport if running. */ void clear(); /*! @@ -279,11 +286,11 @@ */ void setGUIforExtSync(bool on); /*! -* @brief This function restarts the Queue if it is running and does +* @brief This function restarts the transport position if rolling and does * nothing if it is stopped * */ - void resetQueue(); + void resetTransport(); /*! @brief Handler for system signals (SIGUSR1, SIGINT...). * This function writes a message to the pipe and leaves as soon as possible @@ -318,9 +325,9 @@ /* PUBLIC MEMBERS */ public: /*! -* @param p_portCount Number of registered ALSA output ports +* @param p_portCount Number of registered MIDI output ports */ - MainWindow(int p_portCount); + MainWindow(int p_portCount, bool p_alsamidi); ~MainWindow(); /*! * @brief This function opens a QMidiArp XML session file for reading @@ -335,19 +342,10 @@ * @param fn File name to open including its absolute path */ void openFile(const QString&); -/*! -* @brief This function opens and reads an old QMidiArp .qma text file. -* -* It displays a warning for conversion upon next MainWindow::fileSave. -* It is called by MainWindow::fileOpen. -* @param fn File name to open including its absolute path -*/ - void openTextFile(const QString&); /* SIGNALS */ signals: void newTempo(int); - void runQueue(bool); /* PUBLIC SLOTS */ public slots: @@ -449,7 +447,7 @@ * @param on True to set Queue to running state or to restart * */ - void updateRunQueue(bool on); + void updateTransportStatus(bool on); /*! @brief Slot for midiClock ToolButton. * This function toggles SeqDriver between MIDI Clock and internal clock * operation. @@ -461,12 +459,18 @@ /*! @brief Slot for jackSync ToolButton. * This function toggles SeqDriver between Jack Transport and internal * clock operation. -* @param on True sets seqDriver to JACK Transport operation, false +* @param on True sets driver to JACK Transport operation, false * returns to internal clock. * * @see jackSyncToggle */ void jackSyncToggle(bool on); +/*! @brief Slot for the JackDriver::j_shutdown() signal. +* This function switches the sync to internal clock operation and +* deactivates the Jack Transport Action. +* @see jackSyncToggle +*/ + void jackShutdown(); /*! @brief Slot for "Midi Controllers" menu action. This function displays * the MidiCC Dialog window. */ @@ -501,7 +505,8 @@ * It is called by the constructor MainWindow::MainWindow * @see recentFileActivated, addRecentlyOpenedFile */ - void setupRecentFilesMenu();/*! @brief Slot to give response to an incoming pipe message (Ladish L1). + void setupRecentFilesMenu(); +/*! @brief Slot to give response to an incoming pipe message (Ladish L1). * * This function calls fileSave upon reception of SIGUSR1 and close upon * reception of SIGINT. @@ -509,6 +514,11 @@ */ void signalAction(int); +/*! @brief Slot to give response to an incoming Jack Session event. + * + * @param ev Type of the event (internal to QMidiarp) +*/ + void jsAction(int ev); void ctb_update_orientation(Qt::Orientation orient); void ftb_update_orientation(Qt::Orientation orient); }; diff -Nru qmidiarp-0.4.2/src/Makefile.am qmidiarp-0.4.5/src/Makefile.am --- qmidiarp-0.4.2/src/Makefile.am 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/Makefile.am 2012-01-21 17:14:21.000000000 +0000 @@ -21,7 +21,7 @@ midicctable_moc.cpp \ midicontrol_moc.cpp \ passwidget_moc.cpp \ - jacksync_moc.cpp \ + jackdriver_moc.cpp \ seqdriver_moc.cpp \ slider_moc.cpp @@ -44,8 +44,9 @@ midicctable.cpp midicctable.h \ midicontrol.cpp midicontrol.h \ midievent.h \ + driverbase.h \ passwidget.cpp passwidget.h \ - jacksync.cpp jacksync.h \ + jackdriver.cpp jackdriver.h \ seqdriver.cpp seqdriver.h \ slider.cpp slider.h diff -Nru qmidiarp-0.4.2/src/Makefile.in qmidiarp-0.4.5/src/Makefile.in --- qmidiarp-0.4.2/src/Makefile.in 2011-07-09 15:48:16.000000000 +0000 +++ qmidiarp-0.4.5/src/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -54,8 +54,8 @@ groovewidget.$(OBJEXT) mainwindow.$(OBJEXT) \ logwidget.$(OBJEXT) main.$(OBJEXT) midiarp.$(OBJEXT) \ midilfo.$(OBJEXT) midiseq.$(OBJEXT) midicctable.$(OBJEXT) \ - midicontrol.$(OBJEXT) passwidget.$(OBJEXT) jacksync.$(OBJEXT) \ - seqdriver.$(OBJEXT) slider.$(OBJEXT) + midicontrol.$(OBJEXT) passwidget.$(OBJEXT) \ + jackdriver.$(OBJEXT) seqdriver.$(OBJEXT) slider.$(OBJEXT) nodist_qmidiarp_OBJECTS = engine_moc.$(OBJEXT) arpscreen_moc.$(OBJEXT) \ lfoscreen_moc.$(OBJEXT) seqscreen_moc.$(OBJEXT) \ arpwidget_moc.$(OBJEXT) lfowidget_moc.$(OBJEXT) \ @@ -64,7 +64,7 @@ logwidget_moc.$(OBJEXT) midiarp_moc.$(OBJEXT) \ midilfo_moc.$(OBJEXT) midiseq_moc.$(OBJEXT) \ midicctable_moc.$(OBJEXT) midicontrol_moc.$(OBJEXT) \ - passwidget_moc.$(OBJEXT) jacksync_moc.$(OBJEXT) \ + passwidget_moc.$(OBJEXT) jackdriver_moc.$(OBJEXT) \ seqdriver_moc.$(OBJEXT) slider_moc.$(OBJEXT) qmidiarp_OBJECTS = $(am_qmidiarp_OBJECTS) $(nodist_qmidiarp_OBJECTS) am__DEPENDENCIES_1 = @@ -112,6 +112,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } DATA = $(translations_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive @@ -294,7 +300,7 @@ midicctable_moc.cpp \ midicontrol_moc.cpp \ passwidget_moc.cpp \ - jacksync_moc.cpp \ + jackdriver_moc.cpp \ seqdriver_moc.cpp \ slider_moc.cpp @@ -317,8 +323,9 @@ midicctable.cpp midicctable.h \ midicontrol.cpp midicontrol.h \ midievent.h \ + driverbase.h \ passwidget.cpp passwidget.h \ - jacksync.cpp jacksync.h \ + jackdriver.cpp jackdriver.h \ seqdriver.cpp seqdriver.h \ slider.cpp slider.h @@ -384,10 +391,8 @@ $(am__aclocal_m4_deps): config.h: stamp-h1 - @if test ! -f $@; then \ - rm -f stamp-h1; \ - $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ - else :; fi + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 @@ -454,8 +459,8 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine_moc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/groovewidget.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/groovewidget_moc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jacksync.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jacksync_moc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jackdriver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jackdriver_moc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfoscreen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfoscreen_moc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfowidget.Po@am__quote@ @@ -518,9 +523,7 @@ @$(NORMAL_UNINSTALL) @list='$(translations_DATA)'; test -n "$(translationsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(translationsdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(translationsdir)" && rm -f $$files + dir='$(DESTDIR)$(translationsdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -733,10 +736,15 @@ installcheck: installcheck-recursive 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/src/midiarp.cpp qmidiarp-0.4.5/src/midiarp.cpp --- qmidiarp-0.4.2/src/midiarp.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/midiarp.cpp 2011-12-19 19:25:50.000000000 +0000 @@ -27,9 +27,62 @@ #include #include "midiarp.h" +/* +#include "lockfree.h" + +// this class must be implemented in such way +// so that its copy (= operator) is realtime safe +class MidiEngine +{ +public: + int foo; +}; +*/ MidiArp::MidiArp() { + /* + // this simulates access from the two threads + // lock congestion is simulated by attempt to update + // when LockedData destructor is not called + { + LockFreeStore store; // store for the two instances of MidiEngine + const MidiEngine * rdata(store); // pointer to the read-only store, to be used from the seq/jack driver thread + + // write to the writable store + { + LockedData ldata(store); // lock the writable store, destructor will unlock it + ldata->foo = 1; // write access the writable store (lock obtained) + qWarning("gui: %d", ldata->foo); // read access to the writable store (lock obtained) + } // ldata gets out of the scope and its destructor is called. this results in unlock of the writable store + + // attempt update the read-only store and report whether the update succeeded + // should succeed because the writable store is not locked + qWarning("update %s", store.try_lockfree_update() ? "complete" : "not complete (gui thread locked)"); + // print the data in the read-only store + qWarning("seq: %d", rdata->foo); + + // write to the writable store + { + LockedData ldata(store); + ldata->foo = 2; + qWarning("gui: %d", ldata->foo); + + // attempt update the read-only store and report whether the update succeeded + // should fail because the writable store is locked + qWarning("update %s", store.try_lockfree_update() ? "complete" : "not complete (gui thread locked)"); + qWarning("seq: %d (data locked by gui)", rdata->foo); + } + + // print the data in the read-only store before the update + qWarning("seq: %d (before update)", rdata->foo); + // attempt update the read-only store and report whether the update succeeded + // should succeed because the writable store is not locked + qWarning("update %s", store.try_lockfree_update() ? "complete" : "not complete (gui thread locked)"); + // print the data in the read-only store after the update + qWarning("seq: %d (after update)", rdata->foo); + } +*/ for (int l1 = 0; l1 < 2; l1++) { rangeIn[l1] = (l1) ? 127 : 0; indexIn[l1] = (l1) ? 127 : 0; @@ -39,9 +92,13 @@ channelOut = 0; noteBufPtr = 0; noteCount = 0; + releaseNoteCount = 0; restartByKbd = false; trigByKbd = false; + gotKbdTrig = false; + restartFlag = false; stepWidth = 1.0; // stepWidth relative to global queue stepWidth + minStepWidth = 1.0; len = 0.5; // note length vel = 0.8; // velocity relative to global velocity noteIndex[0] = 0; @@ -52,7 +109,7 @@ newCurrent = false; newNext = false; currentNoteTick = 0; - nextNoteTick = 0; + nextTick = 0; patternMaxIndex = 0; noteOfs = 0; arpTick = 0; @@ -64,13 +121,13 @@ randomVelocityAmp = 0; randomLengthAmp = 0; grooveTick = 0; + newGrooveTick = 0; grooveVelocity = 0; grooveLength = 0; repeatPatternThroughChord = 1; isMuted = false; attack_time = 0.0; release_time = 0.0; - queueTempo = 100.0; sustain = false; sustainBuffer.clear(); latch_mode = false; @@ -81,7 +138,6 @@ } MidiArp::~MidiArp(){ - wait(); } void MidiArp::setMuted(bool on) @@ -89,97 +145,108 @@ isMuted = on; } -bool MidiArp::wantEvent(MidiEvent event) { - - if (event.channel != chIn) return(false); - if ((event.type == EV_CONTROLLER) && (event.data != CT_FOOTSW)) return(false); - if (event.type == EV_NOTEON) { - if (((event.data < indexIn[0]) || (event.data > indexIn[1])) - || ((event.value < rangeIn[0]) || (event.value > rangeIn[1]))) { - return(false); - } - } - return(true); -} - -void MidiArp::handleNoteOn(int note, int velocity, int tick) +bool MidiArp::handleEvent(MidiEvent inEv, int tick, int keep_rel) { - mutex.lock(); int bufPtr, index; - if (!getPressedNoteCount()) { - purgeLatchBuffer(); - if (restartByKbd) advancePatternIndex(true); - if (trigByKbd) initArpTick(tick); + if (inEv.channel != chIn) return(true); + if ((inEv.type == EV_CONTROLLER) && (inEv.data == CT_FOOTSW)) { + setSustain((inEv.value == 127), tick); + return(false); } - // modify buffer that is not accessed by arpeggio output - bufPtr = (noteBufPtr) ? 0 : 1; - if (!noteCount || (note > notes[bufPtr][0][noteCount - 1])) - index = noteCount; - else { - index = 0; - while (note > notes[bufPtr][0][index]) index++; + if (inEv.type != EV_NOTEON) return(true); + if (((inEv.data < indexIn[0]) || (inEv.data > indexIn[1])) + || ((inEv.value < rangeIn[0]) || (inEv.value > rangeIn[1]))) { + return(true); + } + + if (inEv.value) { + // This is a NOTE ON event + if (!getPressedNoteCount()) { + purgeLatchBuffer(); + if (restartByKbd) restartFlag = true; + if (trigByKbd) { + initArpTick(tick); + // if we have been triggered, remove pending release notes + if (release_time > 0) { + for (int l1 = 0; l1 < noteCount; l1++) { + if (notes[noteBufPtr][3][l1]) + removeNote(¬es[noteBufPtr][0][l1], -1, 0); + releaseNoteCount--; + } + } - for (int l3 = 0; l3 < 4; l3++) { - for (int l2 = noteCount; l2 > index; l2--) { - notes[bufPtr][l3][l2] = notes[bufPtr][l3][l2 - 1]; } } - } - notes[bufPtr][0][index] = note; - notes[bufPtr][1][index] = velocity; - notes[bufPtr][2][index] = tick; - notes[bufPtr][3][index] = 0; - noteCount++; - - if (repeatPatternThroughChord == 2) noteOfs = noteCount - 1; - copyNoteBuffer(); - mutex.unlock(); -} + // modify buffer that is not accessed by arpeggio output + bufPtr = (noteBufPtr) ? 0 : 1; -void MidiArp::handleNoteOff(int note, int tick, int keep_rel) -{ - int bufPtr, index; - - // modify buffer that is not accessed by arpeggio output - bufPtr = (noteBufPtr) ? 0 : 1; - if (!noteCount) { - return; - } - if (sustain) { - sustainBuffer.append(note); - return; - } + if (!noteCount || (inEv.data > notes[bufPtr][0][noteCount - 1])) + index = noteCount; + else { + index = 0; + while (inEv.data > notes[bufPtr][0][index]) index++; - if (latch_mode) { - latchBuffer.append(note); - if (latchBuffer.count() == noteCount) { - latchTimer->stop(); + for (int l3 = 0; l3 < 4; l3++) { + for (int l2 = noteCount; l2 > index; l2--) { + notes[bufPtr][l3][l2] = notes[bufPtr][l3][l2 - 1]; + } + } } - else { - latchTimer->start(200); + notes[bufPtr][0][index] = inEv.data; + notes[bufPtr][1][index] = inEv.value; + notes[bufPtr][2][index] = tick; + notes[bufPtr][3][index] = 0; + noteCount++; + + if (repeatPatternThroughChord == 2) noteOfs = noteCount - 1; + if ((trigByKbd && (noteCount == 1))) { + nextTick = tick + 2; //schedDelayTicks; + gotKbdTrig = true; } - return; } + else { + // This is a NOTE OFF event + // modify buffer that is not accessed by arpeggio output + bufPtr = (noteBufPtr) ? 0 : 1; + if (!noteCount) { + return(false); + } + if (sustain) { + sustainBuffer.append(inEv.data); + return(false); + } - if ((!keep_rel) || (!release_time)) { - //definitely remove from buffer - if (note == notes[bufPtr][0][noteCount - 1]) { - //note is on top of buffer: only decrement noteCount - noteCount--; - if (repeatPatternThroughChord == 2) noteOfs = noteCount - 1; + if (latch_mode) { + latchBuffer.append(inEv.data); + if (latchBuffer.count() == noteCount) { + latchTimer->stop(); + } + else { + latchTimer->start(200); + } + return(false); } - else { - //note is not on top: take out the note and pull down all above - index = 0; - while ((index < noteCount) && (note > notes[bufPtr][0][index])) index++; - deleteNoteAt(index, bufPtr); + + if ((!keep_rel) || (!release_time)) { + //definitely remove from buffer + if (inEv.data == notes[bufPtr][0][noteCount - 1]) { + //note is on top of buffer: only decrement noteCount + noteCount--; + if (repeatPatternThroughChord == 2) noteOfs = noteCount - 1; + } + else { + //note is not on top: take out the note and pull down all above + index = 0; + while ((index < noteCount) && (inEv.data > notes[bufPtr][0][index])) index++; + deleteNoteAt(index, bufPtr); + } } + else tagAsReleased(inEv.data, tick, bufPtr); } - else tagAsReleased(note, tick, bufPtr); - copyNoteBuffer(); + return(false); } void MidiArp::removeNote(int *noteptr, int tick, int keep_rel) @@ -244,6 +311,7 @@ notes[bufPtr][3][l1] = 1; notes[bufPtr][2][l1] = tick; } + releaseNoteCount++; } void MidiArp::copyNoteBuffer() @@ -272,7 +340,7 @@ tmpIndex[1] = -1; gotCC = false; pause = false; - + if (restartFlag) advancePatternIndex(true); if (!patternIndex) initLoop(); do { @@ -313,7 +381,7 @@ octave=0; break; case '>': - stepWidth /= 2.0; + stepWidth *= .5; break; case '<': stepWidth *= 2.0; @@ -328,10 +396,10 @@ vel -= 0.2; break; case 'd': - len *= 2; + len *= 2.0; break; case 'h': - len /= 2; + len *= .5; break; } } @@ -339,7 +407,6 @@ } while (advancePatternIndex(false) && (gotCC || chordMode)); l1 = 0; - if (noteCount) do { noteIndex[l1] = (noteCount) ? tmpIndex[l1] % noteCount : 0; note[l1] = clip(notes[noteBufPtr][0][noteIndex[l1]] @@ -349,8 +416,7 @@ if ((release_time > 0) && (notes[noteBufPtr][3][noteIndex[l1]])) { releasefn = 1.0 - (double)(arpTick - notes[noteBufPtr][2][noteIndex[l1]]) - / release_time / (double)TPQN - * 60 / queueTempo; + / (release_time * (double)TPQN * 2); if (releasefn < 0.0) releasefn = 0.0; } @@ -360,8 +426,7 @@ if (!notes[noteBufPtr][3][noteIndex[l1]]) { attackfn = (double)(arpTick - notes[noteBufPtr][2][noteIndex[l1]]) - / attack_time / (double)TPQN - * 60 / queueTempo; + / (attack_time * (double)TPQN * 2); if (attackfn > 1.0) attackfn = 1.0; old_attackfn[noteIndex[l1]] = attackfn; @@ -374,13 +439,13 @@ * vel * (1.0 + 0.005 * (double)(randomVelocity + grooveTmp)) * releasefn * attackfn, 0, 127, &outOfRange); - if ((notes[noteBufPtr][3][noteIndex[l1]]) && (!velocity[l1])) - + if ((notes[noteBufPtr][3][noteIndex[l1]]) && (!velocity[l1])) { removeNote(¬es[noteBufPtr][0][noteIndex[l1]], -1, 0); - - else - + releaseNoteCount--; + } + else { l1++; + } } while ((tmpIndex[l1] >= 0) && (l1 < MAXCHORD - 1) && (l1 < noteCount)); @@ -389,9 +454,22 @@ *length = clip(len * stepWidth * (double)TPQN * (1.0 + 0.005 * (double)(randomLength + grooveTmp)), 2, 1000000, &outOfRange); - grooveTmp = (grooveIndex % 2) ? -grooveTick : grooveTick; - arpTick += stepWidth * (double)TPQN - * (1.0 + 0.005 * (double)grooveTmp); + + if (!grooveIndex) grooveTick = newGrooveTick; + grooveTmp = TPQN * stepWidth * grooveTick * 0.01; + /* pairwise application of new groove shift */ + if (grooveIndex % 2) { + grooveTmp = -grooveTmp; + grooveTick = newGrooveTick; + } + arpTick += stepWidth * TPQN + grooveTmp; + + if (!trigByKbd && !grooveIndex && !grooveTick) { + /* round-up to current resolution (quantize) */ + arpTick/= (TPQN * minStepWidth); + arpTick*= (TPQN * minStepWidth); + } + *tick = arpTick + clip(stepWidth * 0.25 * (double)randomTick, 0, 1000, &outOfRange); @@ -399,7 +477,6 @@ velocity[0] = 0; } grooveIndex++; - emit nextStep(grooveIndex); } bool MidiArp::advancePatternIndex(bool reset) @@ -409,6 +486,7 @@ } if ((patternIndex >= patternLen) || reset) { patternIndex = 0; + restartFlag = false; switch (repeatPatternThroughChord) { case 1: noteOfs++; @@ -440,46 +518,11 @@ grooveIndex = 0; } -void MidiArp::prepareNextNote(int askedTick) -{ - int l1 = 0; - returnNote.clear(); - returnVelocity.clear(); - - nextNoteTick = askedTick; - while ((nextNote[l1] >= 0) && (l1 < MAXCHORD - 1)) { - returnNote.append(nextNote[l1]); - returnVelocity.append(nextVelocity[l1]); - l1++; - } - returnNote.append(-1); // mark end of chord - returnLength = nextLength; - returnIsNew = newNext; - newNext = false; -} - -int MidiArp::getNextNoteTick() -{ - return(nextNoteTick); -} - -bool MidiArp::wantTrigByKbd() -{ - bool on = ((getPressedNoteCount() == 1) && trigByKbd); - return(on); -} - void MidiArp::prepareCurrentNote(int askedTick) { + gotKbdTrig = false; currentTick = askedTick; - start(Priority(6)); - wait(); -} - -void MidiArp::run() -{ int l1 = 0; - mutex.lock(); updateNotes(); returnTick = currentNoteTick; returnNote.clear(); @@ -494,7 +537,6 @@ returnLength = currentLength; returnIsNew = newCurrent; newCurrent = false; - mutex.unlock(); } void MidiArp::updateNotes() @@ -503,8 +545,8 @@ //allow 8 ticks of tolerance for echo tick for external sync if ((currentTick + 8) >= currentNoteTick) { - currentNoteTick = nextNoteTick; - getNote(&nextNoteTick, nextNote, nextVelocity, &nextLength); + currentNoteTick = nextTick; + getNote(&nextTick, nextNote, nextVelocity, &nextLength); while ((nextNote[l1] >= 0) && (l1 < MAXCHORD - 1)) { currentNote[l1] = nextNote[l1]; currentVelocity[l1] = nextVelocity[l1]; @@ -521,7 +563,6 @@ { int bufPtr, l2; - mutex.lock(); bufPtr = (noteBufPtr) ? 0 : 1; for (l2 = 0; l2 < noteCount; l2++) { @@ -529,7 +570,6 @@ } copyNoteBuffer(); - mutex.unlock(); } void MidiArp::initArpTick(int tick) @@ -537,7 +577,7 @@ arpTick = tick; currentVelocity[0] = 0; currentNoteTick = tick; - nextNoteTick = tick; + nextTick = tick; nextVelocity[0] = 0; noteIndex[0] = -1; patternIndex = 0; @@ -546,13 +586,14 @@ void MidiArp::updatePattern(const QString& p_pattern) { - mutex.lock(); int l1; QChar c; pattern = p_pattern; patternLen = pattern.length(); patternMaxIndex = 0; + minStepWidth = 1.0; + if (patternLen) { c = (pattern.at(patternLen - 1)); @@ -570,11 +611,13 @@ if (c.isDigit() && (c.digitValue() > patternMaxIndex)) { patternMaxIndex = c.digitValue(); } + if (c == '>') minStepWidth *= .5; + if (c == '<') minStepWidth *= 2.; } + patternIndex = 0; grooveIndex = 0; noteOfs = 0; - mutex.unlock(); } int MidiArp::clip(int value, int min, int max, bool *outOfRange) @@ -594,14 +637,12 @@ void MidiArp::newRandomValues() { - mutex.lock(); randomTick = (double)randomTickAmp * (0.5 - (double)random() / (double)RAND_MAX); randomVelocity = (double)randomVelocityAmp * (0.5 - (double)random() / (double)RAND_MAX); randomLength = (double)randomLengthAmp * (0.5 - (double)random() / (double)RAND_MAX); - mutex.unlock(); } void MidiArp::updateRandomTickAmp(int val) @@ -629,41 +670,22 @@ release_time = (double)val; } -void MidiArp::updateQueueTempo(int val) -{ - queueTempo = (double)val; -} - void MidiArp::updateTriggerMode(int val) { - switch (val) { - case 0: - trigByKbd = false; - restartByKbd = false; - break; - case 1: - trigByKbd = false; - restartByKbd = true; - break; - case 2: - trigByKbd = true; - restartByKbd = true; - break; - default: - trigByKbd = false; - restartByKbd = false; - } + trigByKbd = val&2; + restartByKbd = val&1 || val&2; } void MidiArp::clearNoteBuffer() { noteCount = 0; latchBuffer.clear(); + releaseNoteCount = 0; } int MidiArp::getPressedNoteCount() { - int c = noteCount - latchBuffer.count(); + int c = noteCount - latchBuffer.count() - releaseNoteCount; return(c); } @@ -703,9 +725,7 @@ void MidiArp::newGrooveValues(int p_grooveTick, int p_grooveVelocity, int p_grooveLength) { - mutex.lock(); - grooveTick = p_grooveTick; + newGrooveTick = p_grooveTick; grooveVelocity = p_grooveVelocity; grooveLength = p_grooveLength; - mutex.unlock(); } diff -Nru qmidiarp-0.4.2/src/midiarp.h qmidiarp-0.4.5/src/midiarp.h --- qmidiarp-0.4.2/src/midiarp.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/midiarp.h 2012-01-21 17:14:21.000000000 +0000 @@ -26,7 +26,7 @@ #define MIDIARP_H #include -#include +#include #include #include #include @@ -35,12 +35,12 @@ /*! * @brief MIDI worker class for the Arpeggiator Module. Implements the - * functions providing note arpeggiation as a QThread. + * functions providing note arpeggiation as a QWidget. * * The parameters of MidiArp are controlled by the ArpWidget class. - * A pointer to MidiArp is passed to the SeqDriver thread, which calls + * A pointer to MidiArp is passed to the Engine, which calls * the MidiArp::prepareCurrentNote member as a function of the position of - * the ALSA queue. MidiArp will then call its + * the Driver queue. MidiArp will then call its * internal MidiArp::getNote function which produces an array of notes * stored in its internal output buffer. The notes in the array depend * on the active MidiArp::pattern, envelope, random and groove settings. @@ -48,15 +48,15 @@ * (tick and length), note values and velocity values. MidiArp::getNote * also advances the pattern index and emits the MidiArp::nextStep signal * to update the cursor position in the graphical ArpScreen display part - * of ArpWidget. SeqDriver then - * accesses this output buffer and sends it to the ALSA queue. SeqDriver + * of ArpWidget. Engine then + * accesses this output buffer and sends it to the Driver queue. Engine * also calls MidiArp::handleNoteOn and MidiArp::handleNoteOff. These members * manage the arpeggiator input note buffer - * also part of this class. Notes received on the ALSA input port will - * therefore be added or removed from the buffer as SeqDriver transfers + * also part of this class. Notes received on the MIDI input port will + * therefore be added or removed from the buffer as Engine transfers * them to this class. */ -class MidiArp : public QThread { +class MidiArp : public QWidget { Q_OBJECT @@ -65,22 +65,24 @@ @see MidiArp::updateNotes */ int nextVelocity[MAXCHORD]; /*!< Holds the associated velocities to be output next @see MidiArp::updateNotes, MidiArp::nextNote */ - int currentNoteTick, nextNoteTick, currentTick, arpTick; + int currentNoteTick, currentTick, arpTick; int currentNote[MAXCHORD], currentVelocity[MAXCHORD]; int currentLength, nextLength; bool newCurrent, newNext, chordMode; - int grooveTick, grooveVelocity, grooveLength, grooveIndex; + bool restartFlag; /*!< Signals frameptr reset on next getNextFrame() call */ + int patternIndex; /*!< Holds the current position within the pattern text*/ + int grooveIndex; /*!< Holds the current position within the sequence*/ + int newGrooveTick, grooveTick, grooveVelocity, grooveLength; int randomTick, randomVelocity, randomLength; - double queueTempo; double stepWidth, len, vel; - + double minStepWidth; /*!< Holds the minimum step width of the pattern for quantization purposes*/ QVector sustainBuffer; /*!< Holds released note values when MidiArp::sustain is True */ QVector latchBuffer; /*!< Holds released note values when MidiArp::latch_mode is True */ QTimer *latchTimer; /*!< Is started when a note is released and causes MidiArp::purgeLatchBuffer after a delay of 200ms except when another released note is detected before. */ bool sustain, latch_mode; - int octave, noteIndex[MAXCHORD], patternIndex; + int octave, noteIndex[MAXCHORD]; /*! @brief The input note buffer array of the Arpeggiator, which has * two array copies. * @@ -110,9 +112,7 @@ int patternLen; /*!< Length of the arp text pattern */ int patternMaxIndex;/*!< Maximum number of stacked notes in the pattern */ int noteOfs; /*!< The current index in a chord. @see repeatPatternThroughChord */ - - QMutex mutex; - + int releaseNoteCount; /*!< The number of notes currently in release stage */ /** * @brief This function resets all attributes the pattern @@ -137,7 +137,7 @@ * @brief This function updates the current note arrays with new values * obtained from MidiArp::getNote * - * It is called by MidiArp::run and calls MidiArp::getNote if the given + * It is called by Engine::echoCallback() and calls MidiArp::getNote if the given * timing is ahead of the last timing information. It then transfers the * MidiArp::nextNote and MidiArp::nextVelocity arrays into * MidiArp::currentNote and MidiArp::currentVelocity. @@ -159,17 +159,7 @@ */ void getNote(int *tick, int note[], int velocity[], int *length); /** - * @brief This function is currently not in use. - * - * It transfers the content of the MidiArp::nextNote array to - * MidiArp::returnNote, MidiArp::returnVelocity and MidiArp::returnTick. - * - * @param askedTick The timing value in ticks, for which the next note - * information is queried. - */ - void prepareNextNote(int askedTick); -/** - * @brief This function returns the number of notes present at the ALSA + * @brief This function returns the number of notes present at the MIDI * input port. * * This is the number of notes currently pressed on the keyboard. Note @@ -177,11 +167,11 @@ * number, since it can contain notes in release state or in the * MidiArp::latchBuffer. * - * @return Number of notes present at the ALSA input port. + * @return Number of notes present at the MIDI input port. */ int getPressedNoteCount(); /** - * @brief This function returns the number of notes present at the ALSA + * @brief This function returns the number of notes present at the MIDI * input port. * * This is the number of notes currently pressed on the keyboard. Note @@ -189,7 +179,7 @@ * number, since it can contain notes in release state or in the * MidiArp::latchBuffer. * - * @return Number of notes present at the ALSA input port. + * @return Number of notes present at the MIDI input port. */ void removeNote(int *noteptr, int tick, int keep_rel); /** @@ -243,6 +233,7 @@ bool isMuted; /*!< Mute state set by ArpWidget */ bool restartByKbd; /*!< If True, restart pattern at 0 upon new received note, set by ArpWidget */ bool trigByKbd; /*!< If True, trigger current note tick by tick of received note, set by ArpWidget */ + bool gotKbdTrig; int repeatPatternThroughChord; /*!< Repeat mode "Static", "Up", "Down", set by ArpWidget */ double attack_time;/*!< Attack time in seconds, set by ArpWidget */ double release_time;/*!< Release time in seconds, set by ArpWidget */ @@ -256,6 +247,7 @@ int returnTick; /*!< Holds the time in internal ticks of the currently active arpeggio step */ int returnLength; /*!< Holds the note length of the currently active arpeggio step */ int returnIsNew; + int nextTick; public: MidiArp(); @@ -266,104 +258,45 @@ void updateRandomVelocityAmp(int); void updateRandomLengthAmp(int); void updateAttackTime(int); - void updateQueueTempo(int); void updateReleaseTime(int); /*! @brief This function sets MidiArp::isMuted, which is checked by - * SeqDriver and which suppresses data output globally if set to True. + * Engine and which suppresses data output globally if set to True. * - * @param on Set to True to suppress data output to ALSA + * @param on Set to True to suppress data output to the Driver */ void setMuted(bool); /** - * @brief This function checks whether an ALSA event is eligible for this - * module. - * - * Its response depends on the input filter settings, i.e. note range, - * velocity range and channel. - * - * @param inEv MidiEvent event to check - * @return True if inEv is in the input range of the module - */ - bool wantEvent(MidiEvent event); -/** - * @brief This function checks whether this module is set to keyboard - * trigger mode. - * - * Its response depends on MidiArp::trigByKbd and whether there are notes - * pressed on the keyboard, i.e. whether the note was played stakato. - * - * @return True if the module accepts to be triggered - */ - bool wantTrigByKbd(); -/** - * @brief This function does the actions related to a newly received note. - * - * It is called by SeqDriver when a new note is received on the ALSA input port. - * The MidiArp::latchBuffer is purged if the note was played stakato. - * Depending on the trigger settings, the Arp's timing is reset to - * that of the note tick and/or the pattern index is reset. The note with - * its attributes will then be inserted in the MidiArp::notes buffer, which - * is sorted in accending note value order, and MidiArp::copyNoteBuffer is - * called. - * - * @param note The note value of the received note - * @param velocity The note velocity - * @param tick The time the note was received in internal ticks - */ - void handleNoteOn(int note, int velocity, int tick); -/** - * @brief This function does the actions related to a note release detected - * on the ALSA input port. - * - * It is called by SeqDriver when a NOTE_OFF event is received. The function - * will go through checks regarding MidiArp::latchMode and MidiArp::sustain - * and add the note to the respective MidiArp::latchBuffer and/or - * MidiArp::sustainBuffer if required. If not, the note is either tagged - * as released (provided MidiArp::release_time is set) or removed from - * the buffer. The latter depends on the keep_rel argument. + * @brief This function does the actions related to a newly received event. * - * @param note The note value of the received note - * @param tick The time the note was released in internal ticks - * @param keep_rel Set this flag to 1 if the note is to be kept in the buffer - * along with the release tick and tagged as a released note. 0 otherwise for - * definite removal from the buffer. + * It is called by Engine when a new event is received on the MIDI input port. + + * @param inEv MidiEvent to check and process or not + * @param tick The time the event was received in internal ticks + * @return True if inEv is in not the input range of the module (event is unmatched) */ - void handleNoteOff(int note, int tick, int keep_rel); + bool handleEvent(MidiEvent inEv, int tick, int keep_rel = 0); /** * @brief This function represents the external interface to the * core of the arpeggiator engine. * - * It is called by SeqDriver when a previously scheduled SND_SEQ_ECHO - * event is received on the ALSA port. + * It is called by Engine when a previously scheduled echo + * event is received from the driver. * It starts the MidiArp::run thread. In the thread, MidiArp::getNote * is called, which does the note processing depending on the * MidiArp::pattern and * leading to new data in MidiArp::returnNote, MidiArp::returnVelocity, - * MidiArp::returnLength. SeqDriver then accesses this data directly - * and outputs it to the ALSA queue. + * MidiArp::returnLength. Engine then accesses this data directly + * and outputs it to the Driver's queue. * * @param askedTick the timing of the note(s) to be output * */ void prepareCurrentNote(int askedTick); /** - * @brief This function returns the timing of the next note to be - * calculated and played out in internal ticks. - * - * It is called by SeqDriver immediately after accessing the current note - * data. This next note timing information is used to - * schedule a so called echo event which will trigger the next call to - * prepareCurrentNote followed by an output of note data to the ALSA - * queue. - * - * @return The timing of the next coming note in internal ticks. - */ - int getNextNoteTick(); -/** * @brief This function resets the pattern index and sets the current * timing of the arpeggio to currentTick. * - * It is called by SeqDriver when the ALSA queue is started, or when + * It is called by Engine when the transport is started, or when * a stakato note is received while MidiArp::restartByKbd is set. * * @param currentTick The timing in internal ticks, relative to which @@ -402,7 +335,7 @@ */ void newGrooveValues(int p_grooveTick, int p_grooveVelocity, int p_grooveLength); - /*! @brief Set by SeqDriver when MidiCC #64 is received. + /*! @brief Set by Engine when MidiCC #64 is received. * * Will cause notes remaining in MidiArp::sustainBuffer until * set to false. @@ -423,31 +356,13 @@ void purgeSustainBuffer(int sustick); /*! @brief sets MidiArp::noteCount to zero and clears MidiArp::latchBuffer. */ void clearNoteBuffer(); -/** - * @brief This is the thread main function, which calls - * MidiArp::updateNotes(). - * - * It then copies the newly calculated MidiArp::currentNote - * and MidiArp::currentVelocity arrays into the return - * members, which can then be accessed - * by the SeqDriver::run thread. - */ - void run(); - - signals: -/** - * @brief Emitted to ArpScreen::update at every arpeggio step. - * - * It causes update of the cursor position and pattern display. - * @param patternIndex The current index position in the MidiArp::pattern. - */ - void nextStep(int patternIndex); public slots: /*! @brief Slot for MidiArp::latchTimer. Calls MidiArp::removeNote for * all notes in MidiArp::latchBuffer and then clears latchBuffer. */ void purgeLatchBuffer(); + int getGrooveIndex() { return grooveIndex; } }; diff -Nru qmidiarp-0.4.2/src/midilfo.cpp qmidiarp-0.4.5/src/midilfo.cpp --- qmidiarp-0.4.2/src/midilfo.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/midilfo.cpp 2011-12-17 19:40:19.000000000 +0000 @@ -28,6 +28,16 @@ MidiLfo::MidiLfo() { + enableNoteOff = false; + trigByKbd = false; + gotKbdTrig = false; + restartByKbd = false; + enableLoop = true; + curLoopMode = 0; + seqFinished = false; + restartFlag = false; + noteCount = 0; + queueTempo = 100.0; amp = 0; offs = 0; @@ -44,6 +54,10 @@ isMuted = false; recordMode = false; isRecording = false; + reverse = false; + pingpong = false; + backward = false; + reflect = false; recValue = 0; int l1 = 0; int lt = 0; @@ -63,6 +77,11 @@ lastMouseLoc = 0; lastMouseY = 0; frameptr = 0; + nextTick = 0; + grooveTick = 0; + newGrooveTick = 0; + grooveVelocity = 0; + grooveLength = 0; } MidiLfo::~MidiLfo(){ @@ -73,7 +92,7 @@ isMuted = on; } -void MidiLfo::getNextFrame(QVector *p_data) +void MidiLfo::getNextFrame(QVector *p_data, int tick) { //this function is called by seqdriver and returns one sample //if res <= LFO_FRAMELIMIT. If res > LFO_FRAMELIMIT, a frame is output @@ -81,25 +100,35 @@ QVector frame; Sample sample; - int step = TPQN / res; - int npoints = size * res; + const int step = TPQN / res; + const int npoints = size * res; int lt, l1; int framelimit; int framesize; int index; frame.clear(); + gotKbdTrig = false; if (isRecording) framelimit = 32; else framelimit = LFO_FRAMELIMIT; framesize = res / framelimit; - l1 = 0; - lt = 0; + if (!framesize) framesize = 1; + if (restartFlag) setFramePtr(0); + if (!frameptr) grooveTick = newGrooveTick; + + l1 = 0; + lt = nextTick; do { - index = (l1 + frameptr) % npoints; + if (reverse) { + index = (framesize - 1 - l1 + frameptr) % npoints; + } + else { + index = (l1 + frameptr) % npoints; + } sample = data.at(index); if (isRecording) { - if (!framesize) { + if (framesize < 2) { sample.value = recValue; } else { @@ -114,20 +143,60 @@ customWave.replace(index, sample); } sample.tick = lt; + if (seqFinished) sample.muted = true; frame.append(sample); lt+=step; l1++; } while ((l1 < framesize) & (l1 < npoints)); + reflect = pingpong; + + if (reverse) { + frameptr-=l1; + if (frameptr < 0) { + if (!enableLoop) seqFinished = true; + frameptr = npoints - l1; + if (reflect || !backward) { + reverse = false; + frameptr = 0; + } + } + } + else { + frameptr+=l1; + if (frameptr >= npoints) { + if (!enableLoop) seqFinished = true; + frameptr = 0; + if (reflect || backward) { + reverse = true; + frameptr = npoints - l1; + } + } + } + + int cur_grv_sft = 0.01 * (grooveTick * step); + /** pairwise application of new groove shift */ + if (!(frameptr % 2)) { + cur_grv_sft = -cur_grv_sft; + grooveTick = newGrooveTick; + } + if (res > 16) cur_grv_sft = 0; + lastSampleValue = recValue; + nextTick = lt + cur_grv_sft; + if (nextTick < (tick - lt)) nextTick = tick; sample.value = -1; - sample.tick = lt; + sample.tick = nextTick; frame.append(sample); - emit nextStep(frameptr); - frameptr += l1; - frameptr %= npoints; + if (!trigByKbd && !(frameptr % 2) && !grooveTick) { + /** round-up to current resolution (quantize) */ + nextTick/= (step * framesize); + nextTick*= (step * framesize); + } + + if (seqFinished) frameptr = 0; *p_data = frame; } @@ -137,13 +206,13 @@ //this function returns the full LFO wave Sample sample; + const int step = TPQN / res; + const int npoints = size * res; int l1 = 0; int lt = 0; - int step = TPQN / res; int val = 0; int tempval; bool cl = false; - int npoints = size * res; QVector tmpdata; //res: number of events per beat //size: size of waveform in beats @@ -213,8 +282,8 @@ } break; case 5: //custom - lt = step * customWave.count(); - tmpdata = customWave; + lt = step * npoints; + tmpdata = customWave.mid(0, npoints); break; default: break; @@ -274,6 +343,14 @@ resizeAll(); } +void MidiLfo::updateLoop(int val) +{ + backward = val&1; + pingpong = val&2; + enableLoop = !(val&4); + curLoopMode = val; +} + void MidiLfo::updateQueueTempo(int val) { queueTempo = (double)val; @@ -315,20 +392,24 @@ int lt = 0; int l1 = 0; int os; - int step = TPQN / res; + const int step = TPQN / res; + const int npoints = res * size; Sample sample; - frameptr%=(res * size); + frameptr%=npoints; + os = customWave.count(); - customWave.resize(size * res); - muteMask.resize(size * res); - for (l1 = 0; l1 < customWave.count(); l1++) { - if (l1 >= os) muteMask.replace(l1, muteMask.at(l1 % os)); - sample = customWave.at(l1 % os); - sample.tick = lt; - sample.muted = muteMask.at(l1); - customWave.replace(l1, sample); - lt+=step; + if (os < npoints) { + customWave.resize(npoints); + muteMask.resize(npoints); + for (l1 = 0; l1 < npoints; l1++) { + if (l1 >= os) muteMask.replace(l1, muteMask.at(l1 % os)); + sample = customWave.at(l1 % os); + sample.tick = lt; + sample.muted = muteMask.at(l1); + customWave.replace(l1, sample); + lt+=step; + } } } @@ -344,7 +425,7 @@ void MidiLfo::updateCustomWaveOffset(int cwoffs) { Sample sample; - const int count = customWave.count(); + const int count = res * size; int l1 = 0; bool cl = false; @@ -398,9 +479,15 @@ } while (lastMouseLoc != loc); } -void MidiLfo::resetFramePtr() +void MidiLfo::setFramePtr(int idx) { - frameptr = 0; + frameptr = idx; + if (!idx) { + reverse = curLoopMode&1; + seqFinished = (enableNoteOff && !noteCount); + restartFlag = false; + if (reverse) frameptr = res * size - 1; + } } void MidiLfo::record(int value) @@ -409,10 +496,41 @@ isRecording = true; } -bool MidiLfo::wantEvent(MidiEvent inEv) +bool MidiLfo::handleEvent(MidiEvent inEv, int tick) +{ + + if (!recordMode && (inEv.type == EV_CONTROLLER)) return(true); + if (inEv.channel != chIn) return(true); + if ((inEv.type == EV_CONTROLLER) && (inEv.data != ccnumberIn)) return(true); + + if ((inEv.type == EV_CONTROLLER) && recordMode) record(inEv.value); + else if (inEv.type != EV_NOTEON) return (true); + + if (inEv.value) { + /*This is a NOTE ON event*/ + if (restartByKbd && !noteCount) restartFlag = true; + seqFinished = false; + noteCount++; + if ((trigByKbd && (noteCount == 1))) { + nextTick = tick + 2; //schedDelayTicks; + gotKbdTrig = true; + } + } + else { + /*This is a NOTE OFF event*/ + if (enableNoteOff && (noteCount == 1)) seqFinished = true; + if (noteCount) noteCount--; + } + return(false); +} + +void MidiLfo::newGrooveValues(int p_grooveTick, int p_grooveVelocity, + int p_grooveLength) { - if (!recordMode) return(false); - if (inEv.channel != chIn) return(false); - if (inEv.data != ccnumberIn) return(false); - return(true); + // grooveTick is only updated on pair steps to keep quantization + // newGrooveTick stores the GUI value temporarily + newGrooveTick = p_grooveTick; + grooveVelocity = p_grooveVelocity; + grooveLength = p_grooveLength; } + diff -Nru qmidiarp-0.4.2/src/midilfo.h qmidiarp-0.4.5/src/midilfo.h --- qmidiarp-0.4.2/src/midilfo.h 2011-03-24 20:30:18.000000000 +0000 +++ qmidiarp-0.4.5/src/midilfo.h 2011-12-18 19:58:07.000000000 +0000 @@ -29,7 +29,6 @@ #include #include #include -#include #include #ifndef SAMPLE_H @@ -49,9 +48,9 @@ * for controller data as a QObject. * * The parameters of MidiLfo are controlled by the LfoWidget class. - * A pointer to MidiLfo is passed to the SeqDriver thread, which calls + * A pointer to MidiLfo is passed to the Engine, which calls * the MidiLfo::getNextFrame member as a function of the position of - * the ALSA queue. MidiLfo will return an array of controller values + * the Driver's queue. MidiLfo will return an array of controller values * representing a frame of its internal MidiLfo::data buffer. This frame * has size 1 except for resolution higher than 16th notes. * The MidiLfo::data buffer is populated by the MidiLfo::getData function @@ -66,12 +65,18 @@ Q_OBJECT private: - double queueTempo; /*!< current tempo of the ALSA queue, not in use here */ + double queueTempo; /*!< current tempo of the transport, not in use here */ int lastMouseLoc; /*!< The X location of the last modification of the wave, used for interpolation*/ int lastMouseY; /*!< The Y location at the last modification of the wave, used for interpolation*/ int frameptr; /*!< position of the currently output frame in the MidiArp::data waveform */ + bool backward; /*!< True when the sequence should start backward */ + bool pingpong; /*!< True when the play direction should alternate */ + bool reflect; /*!< True when the current play direction will change at the next reflect point */ + int curLoopMode; /*!< Local storage of the currently active Loop mode */ int recValue; int lastSampleValue; + bool seqFinished; /*!< When True, all output events are muted, used when NOTE OFF is received */ + int noteCount; /*!< The number of keys currently pressed on keyboard */ /** * @brief This function allows forcing an integer value within the * specified range (clip). @@ -93,8 +98,16 @@ void updateCustomWaveOffset(int cwoffs); public: - int portOut; /*!< ALSA output port number */ - int channelOut; /*!< ALSA output channel */ + bool enableNoteOff; + bool enableVelIn; + bool restartByKbd; + bool trigByKbd; + bool enableLoop; + bool gotKbdTrig; + bool restartFlag; /*!< Signals frameptr reset on next getNextFrame() call */ + bool reverse; /*!< True when the current play direction is backwards */ + int portOut; /*!< MIDI output port number */ + int channelOut; /*!< MIDI output channel */ bool recordMode, isRecording; int old_res; int ccnumber; /*!< MIDI Controller CC number to output */ @@ -110,6 +123,8 @@ @par 4: Square @par 5: Use Custom Wave */ int cwmin; /*!< The minimum of MidiLfo::customWave */ + int nextTick; + int newGrooveTick, grooveTick, grooveVelocity, grooveLength, grooveIndex; QVector customWave; /*!< Vector of Sample points holding the custom drawn wave */ QVector muteMask; /*!< Vector of booleans with mute state information for each wave point */ @@ -122,12 +137,13 @@ void updateOffset(int); void updateResolution(int); void updateSize(int); + void updateLoop(int); void updateQueueTempo(int); void record(int value); /*! @brief This function sets MidiLfo::isMuted, which is checked by - * SeqDriver and which suppresses data output globally if set to True. + * Engine and which suppresses data output globally if set to True. * - * @param on Set to True to suppress data output to ALSA + * @param on Set to True to suppress data output to the Driver */ void setMuted(bool on); /*! @brief This function sets the (controller) value of one point of the @@ -180,22 +196,22 @@ * while in calculated waveform mode. (MidiLfo::waveFormIndex 1 ... 4). */ void copyToCustom(); -/*! @brief This function resets the MidiLfo::frameptr to zero. +/*! @brief This function sets the MidiLfo::frameptr to the given value. * - * It is called when the ALSA queue starts. + * It is called when the Transport starts. + * @param idx Index to which the frameptr is set */ - void resetFramePtr(); + void setFramePtr(int idx); /** - * @brief This function checks whether an ALSA event is eligible for this - * module. + * @brief This function does the actions related to a newly received event. * - * Its response depends on the input filter settings, i.e. note, - * velocity and channel. - * - * @param inEv MidiEvent to check - * @return True if inEv is in the input range of the module + * It is called by Engine when a new event is received on the MIDI input port. + + * @param inEv MidiEvent to check and process or not + * @param tick The time the event was received in internal ticks + * @return True if inEv is in not the input range of the module (event is unmatched) */ - bool wantEvent(MidiEvent inEv); + bool handleEvent(MidiEvent inEv, int tick); /*! @brief This function is the main calculator for the data contained * in a waveform. * @@ -212,7 +228,7 @@ * * @param *p_data reference to an array the frame is copied to */ - void getNextFrame(QVector *p_data); + void getNextFrame(QVector *p_data, int tick); /*! @brief This function toggles the mute state of one point of the * MidiLfo::muteMask array. * @@ -227,9 +243,17 @@ * @see MidiLfo::setMutePoint */ bool toggleMutePoint(double mouseX); - - signals: - void nextStep(int frameptr); +/** + * @brief This function copies the new values transferred from the + * GrooveWidget into variables used by MidiArp::getNote. + * + * @param p_grooveTick Groove amount for timing displacements + * @param p_grooveVelocity Groove amount for velocity variations + * @param p_grooveLength Groove amount for note length variations + */ + void newGrooveValues(int p_grooveTick, int p_grooveVelocity, + int p_grooveLength); + int getFramePtr() { return frameptr;} }; #endif diff -Nru qmidiarp-0.4.2/src/midiseq.cpp qmidiarp-0.4.5/src/midiseq.cpp --- qmidiarp-0.4.2/src/midiseq.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/midiseq.cpp 2011-12-23 13:06:18.000000000 +0000 @@ -34,10 +34,18 @@ recordMode = false; trigByKbd = false; restartByKbd = false; - enableLoop = false; + enableLoop = true; + gotKbdTrig = false; currentRecStep = 0; seqFinished = false; + reverse = false; + pingpong = false; + backward = false; + reflect = false; + restartFlag = false; + curLoopMode = 0; noteCount = 0; + loopMarker = 0; nOctaves = 4; baseOctave = 3; @@ -53,6 +61,11 @@ channelOut = 0; waveFormIndex = 0; currentIndex = 0; + nextTick = 0; + grooveTick = 0; + newGrooveTick = 0; + grooveVelocity = 0; + grooveLength = 0; isMuted = false; int lt = 0; int l1 = 0; @@ -77,65 +90,136 @@ isMuted = on; } -bool MidiSeq::wantEvent(MidiEvent inEv) { - - if ((inEv.type != EV_NOTEON) && (inEv.type != EV_CONTROLLER)) return(false); - - if (inEv.channel != chIn) return(false); - - if ((inEv.type == EV_NOTEON)) { - if ((inEv.data < 36) || (inEv.data >= 84)) return(false); - } - return(true); -} - -void MidiSeq::handleNote(int note, int velocity, int tick) +bool MidiSeq::handleEvent(MidiEvent inEv, int tick) { - if (recordMode) recordNote(note); - - else { - if (velocity) { - /**This is a NOTE ON event*/ - if (enableNoteIn) updateTranspose(note - 60); - if (restartByKbd && !noteCount) currentIndex = 0; - if (enableVelIn) updateVelocity(velocity); - seqFinished = false; - noteCount++; + if (inEv.type != EV_NOTEON) return(true); + if (inEv.channel != chIn) return(true); + if ((inEv.data < 36) || (inEv.data >= 84)) return(true); + + if (inEv.value) { + /*This is a NOTE ON event*/ + if (recordMode) { + recordNote(inEv.data); + return(false); } - else { - /**This is a NOTE OFF event*/ - if (enableNoteOff && (noteCount == 1)) seqFinished = true; - if (noteCount) noteCount--; + if (enableNoteIn) updateTranspose(inEv.data - 60); + if (restartByKbd && !noteCount) restartFlag = true; + if (enableVelIn) updateVelocity(inEv.value); + seqFinished = false; + noteCount++; + if ((trigByKbd && (noteCount == 1))) { + nextTick = tick + 2; //schedDelayTicks; + gotKbdTrig = true; } } + else { + /*This is a NOTE OFF event*/ + if (enableNoteOff && (noteCount == 1)) seqFinished = true; + if (noteCount) noteCount--; + } - if (velocity) emit noteEvent(note, velocity); + return(false); } -bool MidiSeq::wantTrigByKbd() +void MidiSeq::getNextNote(Sample *p_sample, int tick) { - bool on = (trigByKbd && (noteCount == 1)); - return(on); -} + const int frame_nticks = TPQN / res; + Sample sample; + int cur_grv_sft; + gotKbdTrig = false; + if (restartFlag) setCurrentIndex(0); + if (!currentIndex) grooveTick = newGrooveTick; -void MidiSeq::getNextNote(Sample *p_sample) -{ - Sample sample; sample = customWave.at(currentIndex); - emit nextStep(currentIndex); - currentIndex++; - currentIndex %= (size * res); - if (!enableLoop && !currentIndex) seqFinished = true; - if (seqFinished) sample.muted = true; + advancePatternIndex(); + + if (nextTick < (tick - frame_nticks)) nextTick = tick; + + sample.value+=transp; + sample.tick = nextTick; + + + cur_grv_sft = 0.01 * (grooveTick * frame_nticks); + + /* pairwise application of new groove shift */ + if (!(currentIndex % 2)) { + cur_grv_sft = -cur_grv_sft; + grooveTick = newGrooveTick; + } + nextTick += frame_nticks + cur_grv_sft; + + if (!trigByKbd && !(currentIndex % 2)) { + /* round-up to current resolution (quantize) */ + nextTick/=frame_nticks; + nextTick*=frame_nticks; + } + + if (seqFinished) { + sample.muted = true; + currentIndex = 0; + } *p_sample = sample; } +void MidiSeq::advancePatternIndex() +{ + const int npoints = res * size; + int pivot = abs(loopMarker); + reflect = pingpong; + + if (reverse) { + currentIndex--; + if (!pivot) pivot = npoints; + if (currentIndex == -1) { + if (!enableLoop) seqFinished = true; + if (reflect || !backward) { + reverse = false; + currentIndex = 0; + } + else currentIndex = pivot - 1; + } + else if (currentIndex == pivot - 1) { + if (!enableLoop) seqFinished = true; + if (loopMarker < 0) reflect = true; + if (loopMarker > 0) reflect = false; + if (reflect) { + reverse = false; + currentIndex = pivot; + } + else currentIndex = npoints - 1; + } + } + else { + currentIndex++; + if (currentIndex == npoints) { + if (!enableLoop) seqFinished = true; + if (reflect || backward) { + reverse = true; + currentIndex = npoints - 1; + } + else currentIndex = pivot; + } + else if ((currentIndex == pivot)) { + if (!pivot) pivot = npoints; + if (!enableLoop) seqFinished = true; + if (loopMarker > 0) reflect = true; + if (loopMarker < 0) reflect = false; + if (reflect) { + reverse = true; + currentIndex = pivot - 1; + } + else currentIndex = 0; + } + } +} + void MidiSeq::getData(QVector *p_data) { Sample sample; int lt = 0; - int step = TPQN / res; + const int step = TPQN / res; + const int npoints = res * size; //res: number of events per beat //size: size of waveform in beats @@ -144,8 +228,8 @@ switch(waveFormIndex) { case 0: //custom - lt = step * customWave.count(); - data = customWave; + lt = step * npoints; + data = customWave.mid(0, npoints); break; default: break; @@ -176,6 +260,14 @@ waveFormIndex = val; } +void MidiSeq::updateLoop(int val) +{ + backward = val&1; + pingpong = val&2; + enableLoop = !(val&4); + curLoopMode = val; +} + void MidiSeq::updateVelocity(int val) { vel = val; @@ -204,6 +296,14 @@ setRecordedNote(12 * (mouseY * nOctaves + baseOctave)); } +void MidiSeq::setLoopMarker(double mouseX) +{ + const int npoints = res * size; + if (mouseX > 0) loopMarker = mouseX * (double)npoints + .5; + else loopMarker = mouseX * (double)npoints - .5; + if (abs(loopMarker) >= npoints) loopMarker = 0; +} + void MidiSeq::setRecordMode(int on) { recordMode = on; @@ -224,22 +324,26 @@ int lt = 0; int l1 = 0; int os; - int step = TPQN / res; + const int step = TPQN / res; + const int npoints = res * size; Sample sample; - currentIndex%=(res * size); + currentIndex%=npoints; + currentRecStep%=npoints; + os = customWave.count(); - customWave.resize(size * res); - muteMask.resize(size * res); - for (l1 = 0; l1 < customWave.count(); l1++) { - if (l1 >= os) muteMask.replace(l1, muteMask.at(l1 % os)); - sample = customWave.at(l1 % os); - sample.tick = lt; - sample.muted = muteMask.at(l1); - customWave.replace(l1, sample); - lt+=step; + if (os < npoints) { + customWave.resize(npoints); + muteMask.resize(npoints); + for (l1 = 0; l1 < npoints; l1++) { + if (l1 >= os) muteMask.replace(l1, muteMask.at(l1 % os)); + sample = customWave.at(l1 % os); + sample.tick = lt; + sample.muted = muteMask.at(l1); + customWave.replace(l1, sample); + lt+=step; + } } - currentRecStep %= (res * size); } void MidiSeq::copyToCustom() @@ -282,8 +386,27 @@ void MidiSeq::setCurrentIndex(int ix) { currentIndex=ix; + if (!ix) { - seqFinished = false; - noteCount = 0; + seqFinished = (enableNoteOff && !noteCount); + restartFlag = false; + if (backward) { + reverse = true; + if (loopMarker) currentIndex = abs(loopMarker) - 1; + else currentIndex = res * size - 1; + } + else reverse = false; + + reflect = pingpong; } } + +void MidiSeq::newGrooveValues(int p_grooveTick, int p_grooveVelocity, + int p_grooveLength) +{ + // grooveTick is only updated on pair steps to keep quantization + // newGrooveTick stores the GUI value temporarily + newGrooveTick = p_grooveTick; + grooveVelocity = p_grooveVelocity; + grooveLength = p_grooveLength; +} diff -Nru qmidiarp-0.4.2/src/midiseq.h qmidiarp-0.4.5/src/midiseq.h --- qmidiarp-0.4.2/src/midiseq.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/midiseq.h 2011-12-18 19:59:17.000000000 +0000 @@ -50,7 +50,7 @@ * The parameters of MidiSeq are controlled by the SeqWidget class. * A pointer to MidiSeq is passed to the SeqDriver thread, which calls * the MidiSeq::getNextNote member as a function of the position of - * the ALSA queue. MidiSeq will return a note from its internal + * the Driver's queue. MidiSeq will return a note from its internal * MidiSeq::data buffer. The MidiSeq::data buffer is populated by the * MidiSeq::getData function at each modification done via * the SeqWidget. It is modified by drawing a sequence of notes on the @@ -67,6 +67,10 @@ double queueTempo; int lastMouseLoc; int currentIndex; + bool backward; /*!< True when the sequence should start backward */ + bool pingpong; /*!< True when the play direction should alternate */ + bool reflect; /*!< True when the current play direction will change at the next reflect point */ + int curLoopMode; /*!< Local storage of the currently active Loop mode */ int noteCount; bool recordMode; bool seqFinished; @@ -81,6 +85,13 @@ * @return The value clipped within the range */ int clip(int value, int min, int max, bool *outOfRange); +/** + * @brief This function calulates the next MidiSeq::currentIndex as a + * function of the current value, play direction, loop marker position + * and orientation. It is called by MidiSeq::getNextNote() so that upon + * every new output note, the sequence pointer advances. + */ + void advancePatternIndex(); public: int chIn; /**< Channel of input events */ @@ -90,14 +101,20 @@ bool restartByKbd; bool trigByKbd; bool enableLoop; + bool gotKbdTrig; + bool restartFlag; /*!< Signals frameptr reset on next getNextFrame() call */ + bool reverse; /*!< True when the current play direction is backwards */ int portOut; /**< Output port index */ int channelOut; bool isMuted; int vel, transp, notelength; int size, res, waveFormIndex; int currentRecStep; + int loopMarker; + int nextTick; int nOctaves; int baseOctave; + int newGrooveTick, grooveTick, grooveVelocity, grooveLength, grooveIndex; QVector customWave; QVector muteMask; @@ -106,6 +123,7 @@ ~MidiSeq(); void updateWaveForm(int val); void updateVelocity(int); + void updateLoop(int); void updateTranspose(int); void updateQueueTempo(int); @@ -113,29 +131,19 @@ /*! @brief This function sets MidiLfo::isMuted, which is checked by * SeqDriver and which suppresses data output globally if set to True. * - * @param on Set to True to suppress data output to ALSA + * @param on Set to True to suppress data output to the Driver */ void setMuted(bool); /** - * @brief This function checks whether this module is set to keyboard - * trigger mode. - * - * Its response depends on MidiSeq::restartByKbd and (TODO) whether there are notes - * pressed on the keyboard, i.e. whether the note was played stakato. - * - * @return True if the module accepts to be triggered - */ - bool wantTrigByKbd(); -/** * @brief This function does the actions related to a newly received note. * - * It is called by SeqDriver when a new note is received on the ALSA input port. + * It is called by Engine when a new note is received on the MIDI input port. * @param note The note value of the received note * @param velocity The note velocity * @param tick The time the note was received in internal ticks */ - void handleNote(int note, int velocity, int tick); + bool handleEvent(MidiEvent inEv, int tick); /*! @brief This function sets the (controller) value of one point of the * MidiSeq::customWave array. It is used for handling drawing functionality. * @@ -152,6 +160,19 @@ * @see MidiSeq::toggleMutePoint(), MidiSeq::setMutePoint() */ void setCustomWavePoint(double mouseX, double mouseY); +/*! @brief This function sets the MidiSeq::loopMarker member variable + * used as a supplemental return point within the sequence. It is called + * by SeqWidget::mousePressed(). + * The normalized mouse coordinates are scaled to the waveform size and + * resolution. + * + * @param mouseX Normalized horizontal location of the mouse on the + * SeqScreen (0.0 ... 1.0). If the mouseX parameter is negative, the + * marker acts to the left, whereas it acts to the right when mouseX is + * positive. If mouseX is zero, the loopMarker will be removed. + * @see MidiSeq::toggleMutePoint(), MidiSeq::setMutePoint() + */ + void setLoopMarker(double mouseX); /*! @brief This function sets the mute state of one point of the * MidiSeq::muteMask array to the given state. * @@ -183,17 +204,6 @@ void setRecordMode(int on); void setRecordedNote(int note); -/** - * @brief This function checks whether an ALSA event is eligible for this - * module. - * - * Its response depends on the input filter settings, i.e. note, - * velocity and channel. - * - * @param inEv MidiEvent event to check - * @return True if inEv is in the input range of the module - */ - bool wantEvent(MidiEvent inEv); /*! @brief This function is called upon every change of parameters in * SeqWidget or upon input by mouse clicks on the SeqScreen. * @@ -209,7 +219,7 @@ * * @param p_sample reference to a Sample structure receiving the data point */ - void getNextNote(Sample *p_sample); + void getNextNote(Sample *p_sample, int tick); /*! @brief This function toggles the mute state of one point of the * MidiSeq::muteMask array. * @@ -222,11 +232,19 @@ * @see MidiSeq::setMutePoint */ bool toggleMutePoint(double); - void setCurrentIndex(int ix); +/** + * @brief This function copies the new values transferred from the + * GrooveWidget into variables used by MidiArp::getNote. + * + * @param p_grooveTick Groove amount for timing displacements + * @param p_grooveVelocity Groove amount for velocity variations + * @param p_grooveLength Groove amount for note length variations + */ + void newGrooveValues(int p_grooveTick, int p_grooveVelocity, + int p_grooveLength); - signals: - void nextStep(int currentIndex); - void noteEvent(int note, int velocity); + void setCurrentIndex(int ix); + int getCurrentIndex() {return currentIndex; } }; diff -Nru qmidiarp-0.4.2/src/passwidget.cpp qmidiarp-0.4.5/src/passwidget.cpp --- qmidiarp-0.4.2/src/passwidget.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/passwidget.cpp 2011-08-30 16:59:35.000000000 +0000 @@ -95,13 +95,13 @@ void PassWidget::updateForward(bool on) { - engine->seqDriver->setForwardUnmatched(on); + engine->driver->setForwardUnmatched(on); portUnmatchedSpin->setDisabled(!on); } void PassWidget::updatePortUnmatched(int id) { - engine->seqDriver->setPortUnmatched(id); + engine->driver->setPortUnmatched(id); } void PassWidget::setForward(bool on) @@ -117,7 +117,7 @@ void PassWidget::updateControlSetting(bool on) { - engine->seqDriver->setMidiControllable(on); + engine->setMidiControllable(on); } void PassWidget::updateCompactStyle(bool on) diff -Nru qmidiarp-0.4.2/src/pixmaps/Makefile.in qmidiarp-0.4.5/src/pixmaps/Makefile.in --- qmidiarp-0.4.2/src/pixmaps/Makefile.in 2011-07-09 15:51:28.000000000 +0000 +++ qmidiarp-0.4.5/src/pixmaps/Makefile.in 2012-01-21 17:28:56.000000000 +0000 @@ -1,9 +1,9 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.11.2 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. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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. @@ -267,10 +267,15 @@ 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 + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: diff -Nru qmidiarp-0.4.2/src/seqdriver.cpp qmidiarp-0.4.5/src/seqdriver.cpp --- qmidiarp-0.4.2/src/seqdriver.cpp 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/seqdriver.cpp 2011-12-25 22:14:43.000000000 +0000 @@ -30,10 +30,14 @@ #include "config.h" -SeqDriver::SeqDriver(QList *p_midiArpList, - QList *p_midiLfoList, QList *p_midiSeqList, - int p_portCount, QWidget *parent) - : QThread(parent), modified(false) +SeqDriver::SeqDriver( + JackDriver *p_jackSync, + int p_portCount, + void * callback_context, + bool (* midi_event_received_callback)(void * context, MidiEvent ev), + void (* tick_callback)(void * context, bool echo_from_trig)) + : DriverBase(callback_context, midi_event_received_callback, tick_callback, 60e9) + , jackSync(p_jackSync) { int err; char buf[16]; @@ -77,34 +81,31 @@ } } - midiArpList = p_midiArpList; - midiLfoList = p_midiLfoList; - midiSeqList = p_midiSeqList; - portUnmatched = 0; forwardUnmatched = false; - runArp = false; - startQueue = false; - use_jacksync = false; - use_midiclock = false; - midi_controllable = true; - sendLogEvents = false; - - internal_tempo = 100; - schedDelayTicks = 2; + lastSchedTick = 0; + m_current_tick = 0; + jackOffsetTick = 0; - resetTicks(); + queueStatus = false; + startQueue = false; + useJackSync = false; + useMidiClock = false; + midiTick = 0; + lastRatioTick = 0; + + internalTempo = 120; + initTempo(); + clockRatio = 60e9/TPQN/tempo; - gotArpKbdTrig = false; - gotSeqKbdTrig = false; threadAbort = false; start(Priority(6)); } SeqDriver::~SeqDriver(){ - if (use_jacksync) setUseJackTransport(false); + if (useJackSync) setUseJackTransport(false); threadAbort = true; wait(); @@ -114,10 +115,9 @@ void SeqDriver::run() { snd_seq_event_t *evIn; - bool unmatched; - bool fallback = false; + bool unmatched = true; MidiEvent inEv; - int pollR = 0; + int pollr = 0; int nfds; struct pollfd *pfds; @@ -128,35 +128,54 @@ while ((poll >= 0) && (!threadAbort)) { - pollR = poll(pfds, nfds, 200); - while (pollR > 0) { + pollr = poll(pfds, nfds, 200); + while (pollr > 0) { snd_seq_event_input(seq_handle, &evIn); inEv.type = evIn->type; inEv.data = evIn->data.note.note; + inEv.channel = 0; + inEv.value = 0; - if ((inEv.type == EV_CLOCK)&& use_midiclock) { + if ((inEv.type == EV_CLOCK)&& useMidiClock) { midiTick++; - tick = midiTick*TPQN/MIDICLK_TPQN; - if ((tick > nextMinLfoTick) && (midiLfoList->count())) { - fallback = true; + m_current_tick = midiTick*TPQN/MIDICLK_TPQN; + } + if (((inEv.type == EV_ECHO) || startQueue) && queueStatus) { + startQueue = false; + unmatched = false; + realTime = evIn->time.time; + if (useMidiClock) { + m_current_tick = midiTick*TPQN/MIDICLK_TPQN; + if (midiTick > lastRatioTick + 3 || !midiTick) { + calcClockRatio(); + lastRatioTick = midiTick; + } } - if ((tick > nextMinSeqTick) && (midiSeqList->count())) { - fallback = true; + else if (useJackSync) { + jPos = jackSync->getCurrentPos(); + if (jPos.beats_per_minute > 0) + tempo = jPos.beats_per_minute; + + m_current_tick = (long)jPos.frame * TPQN + / jPos.frame_rate * tempo / 60. + - jackOffsetTick; + calcClockRatio(); } - } - if (((inEv.type == EV_ECHO) || startQueue || fallback) && runArp) { - fallback = false; - real_time = evIn->time.time; - handleEcho(inEv); + else { + clockRatio = 60e9/TPQN/tempo; + m_current_tick = deltaToTick(aTimeToDelta(&realTime)); + } + + tick_callback((inEv.data)); } else { unmatched = true; inEv.channel = evIn->data.control.channel; if ((inEv.type == EV_NOTEON) || (inEv.type == EV_NOTEOFF)) { - real_time = evIn->time.time; + realTime = evIn->time.time; inEv.data = evIn->data.note.note; if (inEv.type == EV_NOTEON) { inEv.value = evIn->data.note.velocity; @@ -165,14 +184,18 @@ inEv.value = 0; inEv.type = EV_NOTEON; } + getTime(); + m_current_tick = deltaToTick(aTimeToDelta(&tmpTime)); } else inEv.value = evIn->data.control.value; if (inEv.type == EV_CONTROLLER) { inEv.data = evIn->data.control.param; + getTime(); + m_current_tick = deltaToTick(aTimeToDelta(&tmpTime)); } - unmatched = (handleEvent(inEv) && unmatched); + unmatched = midi_event_received(inEv); if (forwardUnmatched && unmatched) { snd_seq_ev_set_subs(evIn); @@ -180,316 +203,39 @@ snd_seq_ev_set_source(evIn, portid_out[portUnmatched]); snd_seq_event_output_direct(seq_handle, evIn); } - - if (sendLogEvents) emit midiEvent(inEv); - } - if (!runArp) tick = 0; //some events still come in after queue stop - pollR = snd_seq_event_input_pending(seq_handle, 0); - } - } -} - -void SeqDriver::handleEcho(MidiEvent inEv) -{ - int l1, l2; - QVector note, velocity; - int note_tick = 0; - int length; - int outport; - int seqtransp; - bool isNew; - MidiEvent outEv; - int frame_nticks = 0; - jack_position_t jpos; - - note.clear(); - velocity.clear(); - - if (use_midiclock) { - tick = midiTick*TPQN/MIDICLK_TPQN; - calcClockRatio(); - } - else if (use_jacksync) { - if (jackSync->isRunning()) { - - jpos = jackSync->getCurrentPos(); - if (jpos.beats_per_minute > 0) - tempo = jpos.beats_per_minute; - - tick = (uint64_t)jpos.frame * TPQN - * tempo / (jpos.frame_rate * 60) - - jack_offset_tick; - calcClockRatio(); - } - } - else { - m_ratio = 60e9/TPQN/tempo; - tick = deltaToTick(aTimeToDelta(&real_time)); - } - - - //~ printf(" tick %d ",tick); - //~ printf("nextMinLfoTick %d ",nextMinLfoTick); - //~ printf("nextMinSeqTick %d ",nextMinSeqTick); - //~ printf("nextMinArpTick %d \n",nextMinArpTick); - //~ printf("midiTick %d ",midiTick); - //~ printf("m_ratio %f ",m_ratio); - //~ printf("Jack Beat %d\n", jpos.beat); - //~ printf("Jack Frame %d \n ", (int)jpos.frame); - //~ printf("Jack BBT offset %d\n", (int)jpos.bbt_offset); - if (tick < 0) setQueueStatus(true); - startQueue = false; - - //LFO data request and queueing - //add 8 ticks to startoff condition to cope with initial sync imperfections - if (((tick + 8) >= nextMinLfoTick) && (midiLfoList->count())) { - for (l1 = 0; l1 < midiLfoList->count(); l1++) { - if ((tick + 8) >= nextLfoTick[l1]) { - outEv.type = EV_CONTROLLER; - outEv.data = midiLfoList->at(l1)->ccnumber; - outEv.channel = midiLfoList->at(l1)->channelOut; - midiLfoList->at(l1)->getNextFrame(&lfoData); - frame_nticks = lfoData.last().tick; - outport = midiLfoList->at(l1)->portOut; - if (!midiLfoList->at(l1)->isMuted) { - l2 = 0; - while (lfoData.at(l2).value > -1) { - if (!lfoData.at(l2).muted) { - outEv.value = lfoData.at(l2).value; - schedEvent(outEv, nextLfoTick[l1] + lfoData.at(l2).tick - , outport); - } - l2++; - } - } - nextLfoTick[l1] += frame_nticks; - /** round-up to current resolution (quantize) */ - nextLfoTick[l1]/= frame_nticks; - nextLfoTick[l1]*= frame_nticks; - } - if (!l1) - nextMinLfoTick = nextLfoTick[l1]; - else if (nextLfoTick[l1] < nextMinLfoTick) - nextMinLfoTick = nextLfoTick[l1]; - } - if (midiLfoList->count()) requestEchoAt(nextMinLfoTick); - } - - //Seq notes data request and queueing - //add 8 ticks to startoff condition to cope with initial sync imperfections - if (((tick + 8) >= nextMinSeqTick) && (midiSeqList->count())) { - for (l1 = 0; l1 < midiSeqList->count(); l1++) { - if ((gotSeqKbdTrig && (inEv.data == 2) && midiSeqList->at(l1)->wantTrigByKbd()) - || (!gotSeqKbdTrig && (inEv.data == 0))) { - gotSeqKbdTrig = false; - if ((tick + 8) >= nextSeqTick[l1]) { - outEv.type = EV_NOTEON; - outEv.value = midiSeqList->at(l1)->vel; - outEv.channel = midiSeqList->at(l1)->channelOut; - midiSeqList->at(l1)->getNextNote(&seqSample); - frame_nticks = TPQN / midiSeqList->at(l1)->res; - length = midiSeqList->at(l1)->notelength; - seqtransp = midiSeqList->at(l1)->transp; - outport = midiSeqList->at(l1)->portOut; - if (!midiSeqList->at(l1)->isMuted) { - if (!seqSample.muted) { - outEv.data = seqSample.value + seqtransp; - schedEvent(outEv, nextSeqTick[l1], outport, length); - } - } - nextSeqTick[l1]+=frame_nticks; - if (!midiSeqList->at(l1)->trigByKbd) { - /** round-up to current resolution (quantize) */ - nextSeqTick[l1]/=frame_nticks; - nextSeqTick[l1]*=frame_nticks; - } - } - } - if (!l1) - nextMinSeqTick = nextSeqTick[l1]; - else if (nextSeqTick[l1] < nextMinSeqTick) - nextMinSeqTick = nextSeqTick[l1]; - } - if (midiSeqList->count()) requestEchoAt(nextMinSeqTick, 0); - } - - //Arp Note queueing - if ((tick + 8) >= nextMinArpTick) { - for (l1 = 0; l1 < midiArpList->count(); l1++) { - if ((gotArpKbdTrig && (inEv.data == 2) && midiArpList->at(l1)->wantTrigByKbd()) - || (!gotArpKbdTrig && (inEv.data == 0))) { - gotArpKbdTrig = false; - if ((tick + 8) >= nextArpTick[l1]) { - outEv.type = EV_NOTEON; - outEv.channel = midiArpList->at(l1)->channelOut; - midiArpList->at(l1)->newRandomValues(); - midiArpList->at(l1)->updateQueueTempo(tempo); - midiArpList->at(l1)->prepareCurrentNote(tick + schedDelayTicks); - note = midiArpList->at(l1)->returnNote; - velocity = midiArpList->at(l1)->returnVelocity; - note_tick = midiArpList->at(l1)->returnTick; - length = midiArpList->at(l1)->returnLength * 4; - outport = midiArpList->at(l1)->portOut; - isNew = midiArpList->at(l1)->returnIsNew; - if (!velocity.isEmpty()) { - if (isNew && velocity.at(0)) { - l2 = 0; - while(note.at(l2) >= 0) { - outEv.data = note.at(l2); - outEv.value = velocity.at(l2); - schedEvent(outEv, note_tick, outport, length); - l2++; - } - } - } - nextArpTick[l1] = midiArpList->at(l1)->getNextNoteTick(); - } } - if (!l1) - nextMinArpTick = nextArpTick[l1] - schedDelayTicks; - else if (nextArpTick[l1] < nextMinArpTick + schedDelayTicks) - nextMinArpTick = nextArpTick[l1] - schedDelayTicks; + if (!queueStatus) m_current_tick = 0; //some events still come in after queue stop + pollr = snd_seq_event_input_pending(seq_handle, 0); } - - if (0 > nextMinArpTick) nextMinArpTick = 0; - if (midiArpList->count()) requestEchoAt(nextMinArpTick, 0); } } -bool SeqDriver::handleEvent(MidiEvent inEv) +void SeqDriver::initTempo() { - bool unmatched; - int l1; - unmatched = true; + if (useJackSync) { + jPos = jackSync->getCurrentPos(); + if (jPos.beats_per_minute > 0) + tempo = jPos.beats_per_minute; + else + tempo = internalTempo; - if (inEv.type == EV_CONTROLLER) { - - if (inEv.data == CT_FOOTSW) { - for (l1 = 0; l1 < midiArpList->count(); l1++) { - if (midiArpList->at(l1)->wantEvent(inEv)) { - midiArpList->at(l1)->setSustain((inEv.value == 127), tick); - unmatched = false; - } - } - } - else { - //Does any LFO want to record this? - for (l1 = 0; l1 < midiLfoList->count(); l1++) { - if (midiLfoList->at(l1)->wantEvent(inEv)) { - midiLfoList->at(l1)->record(inEv.value); - unmatched = false; - } - } - if (midi_controllable) { - emit controlEvent(inEv.data, inEv.channel, inEv.value); - unmatched = false; - } - } - return unmatched; + jackOffsetTick = (uint64_t)jPos.frame * TPQN + * tempo / (jPos.frame_rate * 60); + clockRatio = 60e9/TPQN/tempo; } - - if (inEv.type == EV_NOTEON) { - - for (l1 = 0; l1 < midiSeqList->count(); l1++) { - if (midiSeqList->at(l1)->wantEvent(inEv)) { - unmatched = false; - getTime(); - tick = deltaToTick(aTimeToDelta(&tmptime)); - midiSeqList->at(l1)->handleNote(inEv.data, inEv.value, tick); - - if (inEv.value && midiSeqList->at(l1)->wantTrigByKbd()) { - nextMinSeqTick = tick; - nextSeqTick[l1] = nextMinSeqTick + schedDelayTicks; - gotSeqKbdTrig = true; - requestEchoAt(nextMinSeqTick, 2); - } - } - } - for (l1 = 0; l1 < midiArpList->count(); l1++) { - if (midiArpList->at(l1)->wantEvent(inEv)) { - unmatched = false; - if (inEv.value) { - getTime(); - tick = deltaToTick(aTimeToDelta(&tmptime)); - midiArpList->at(l1)->handleNoteOn(inEv.data, inEv.value, tick); - - if (midiArpList->at(l1)->wantTrigByKbd()) { - nextMinArpTick = tick; - nextArpTick[l1] = nextMinArpTick + schedDelayTicks; - gotArpKbdTrig = true; - requestEchoAt(nextMinArpTick, 2); - } - } - else { - midiArpList->at(l1)->handleNoteOff(inEv.data, tick, 1); - } - } - } - return unmatched; - } - - if (use_midiclock){ - if ((inEv.type == EV_START) || (inEv.type == EV_CONTINUE)){ - setQueueStatus(true); - } - if (inEv.type == EV_STOP) { - setQueueStatus(false); - } - return unmatched; + else { + tempo = internalTempo; + clockRatio = 60e9/TPQN/tempo; } - return unmatched; -} - -void SeqDriver::resetTicks() -{ - int l1; - - for (l1 = 0; l1 < midiArpList->count(); l1++) { - midiArpList->at(l1)->foldReleaseTicks(tick); - midiArpList->at(l1)->initArpTick(0); - } - for (l1 = 0; l1 < midiLfoList->count(); l1++) { - midiLfoList->at(l1)->resetFramePtr(); - } - for (l1 = 0; l1 < midiSeqList->count(); l1++) { - midiSeqList->at(l1)->setCurrentIndex(0); - } - for (l1 = 0; l1 < 20; l1++) { - nextArpTick[l1] = 0; - nextLfoTick[l1] = 0; - nextSeqTick[l1] = 0; - } - nextMinLfoTick = 0; - nextMinSeqTick = 0; - nextMinArpTick = 0; - lastSchedTick = 0; - jack_offset_tick = 0; - - if (use_midiclock) { + if (useMidiClock) { midiTick = 0; + lastRatioTick = 0; } - else if (use_jacksync) { - if (jackSync->isRunning()) { - jack_position_t jpos = jackSync->getCurrentPos(); - if (jpos.beats_per_minute > 0) - tempo = jpos.beats_per_minute; - else - tempo = internal_tempo; - jack_offset_tick = (uint64_t)jpos.frame * TPQN - * tempo / (jpos.frame_rate * 60); - m_ratio = 60e9/TPQN/tempo; - } - } - else { - tempo = internal_tempo; - m_ratio = 60e9/TPQN/tempo; - } - - tick = 0; } -void SeqDriver::schedEvent(MidiEvent outEv, int n_tick, int outport, int length) +void SeqDriver::sendMidiEvent(MidiEvent outEv, int n_tick, unsigned outport, unsigned length) { + //~ qWarning("sendMidiEvent([%d, %d, %d, %d], %u, %u) at tick %d", ev.type, ev.channel, ev.data, ev.value, outport, duration, n_tick); snd_seq_event_t ev; snd_seq_ev_clear(&ev); @@ -509,39 +255,26 @@ snd_seq_event_output_direct(seq_handle, &ev); } -bool SeqDriver::requestEchoAt(int echoTick, int infotag) +bool SeqDriver::requestEchoAt(int echo_tick, bool echo_from_trig) { - if ((echoTick == lastSchedTick) && (echoTick)) return false; - - lastSchedTick = echoTick; + if ((echo_tick == lastSchedTick) && (echo_tick)) return false; + lastSchedTick = echo_tick; snd_seq_event_t ev; snd_seq_ev_clear(&ev); ev.type = SND_SEQ_EVENT_ECHO; - ev.data.note.note = infotag; - snd_seq_ev_schedule_real(&ev, queue_id, 0, deltaToATime(tickToDelta(echoTick))); + ev.data.note.note = echo_from_trig; + snd_seq_ev_schedule_real(&ev, queue_id, 0, deltaToATime(tickToDelta(echo_tick))); snd_seq_ev_set_dest(&ev, clientid, portid_in); snd_seq_event_output_direct(seq_handle, &ev); return true; } -void SeqDriver::setForwardUnmatched(bool on) -{ - forwardUnmatched = on; - modified = true; -} - -void SeqDriver::setPortUnmatched(int id) -{ - portUnmatched = id; - modified = true; -} - -void SeqDriver::setQueueTempo(int bpm) +void SeqDriver::setTempo(int bpm) { tempo = bpm; - internal_tempo = bpm; - m_ratio = 60e9/TPQN/tempo; + internalTempo = bpm; + clockRatio = 60e9/TPQN/tempo; } void SeqDriver::getTime() @@ -553,18 +286,17 @@ const snd_seq_real_time_t* current_time = snd_seq_queue_status_get_real_time(status); - tmptime = *current_time; + tmpTime = *current_time; snd_seq_queue_status_free(status); } -void SeqDriver::setQueueStatus(bool run) +void SeqDriver::setTransportStatus(bool run) { if (run) { - - runArp = true; + queueStatus = true; startQueue = true; - resetTicks(); + initTempo(); snd_seq_start_queue(seq_handle, queue_id, NULL); snd_seq_drain_output(seq_handle); @@ -574,11 +306,7 @@ qWarning("Alsa Queue started"); } else { - runArp = false; - // snd_seq_drop_output(seq_handle); - for (int l1 = 0; l1 < midiArpList->count(); l1++) { - midiArpList->at(l1)->clearNoteBuffer(); - } + queueStatus = false; snd_seq_remove_events_t *remove_ev; snd_seq_remove_events_malloc(&remove_ev); @@ -590,70 +318,26 @@ snd_seq_stop_queue(seq_handle, queue_id, NULL); - tick = 0; + m_current_tick = 0; qWarning("Alsa Queue stopped"); } } -void SeqDriver::setUseJackTransport(bool on) -{ - if (on) { - jackSync = new JackSync(tr_state_cb, this); - jackSync->setParent(this); - connect(jackSync, SIGNAL(j_shutdown()), - this, SLOT(jackShutdown())); - use_jacksync = true; - - if (jackSync->initJack()) { - emit jackShutdown(false); - return; - } - else if (jackSync->activateJack()) { - emit jackShutdown(false); - return; - } - } - else { - if (use_jacksync) { - jackSync->deactivateJack(); - delete jackSync; - use_jacksync = false; - } - } -} - -void SeqDriver::jackShutdown() -{ - setQueueStatus(false); - emit jackShutdown(false); -} - void SeqDriver::setUseMidiClock(bool on) { - m_ratio = 60e9/TPQN/tempo; - setQueueStatus(false); - use_midiclock = on; -} - -void SeqDriver::setModified(bool m) -{ - modified = m; -} - -bool SeqDriver::isModified() -{ - return modified; + clockRatio = 60e9/TPQN/tempo; + useMidiClock = on; } double SeqDriver::tickToDelta(int tick) { - return (double)m_ratio * tick; + return (double)clockRatio * tick; } int SeqDriver::deltaToTick(double curtime) { - return (int)(curtime / m_ratio + .5); + return (int)(curtime / clockRatio); } double SeqDriver::aTimeToDelta(snd_seq_real_time_t* atime) @@ -670,34 +354,31 @@ void SeqDriver::calcClockRatio() { - double old_m_ratio = m_ratio; + double old_clock_ratio = clockRatio; - if (tick > 0) { - m_ratio = aTimeToDelta(&real_time)/tick; + if (m_current_tick > 0) { + clockRatio = aTimeToDelta(&realTime)/m_current_tick; } - if ((m_ratio == 0) || (m_ratio > 60e9 / tempo)) { - m_ratio = old_m_ratio; + if ((clockRatio == 0) || (clockRatio > 60e9 / tempo)) { + clockRatio = old_clock_ratio; } + clockRatio += old_clock_ratio; + clockRatio *= .5; } -int SeqDriver::getAlsaClientId() +int SeqDriver::getClientId() { return clientid; } -void SeqDriver::setMidiControllable(bool on) -{ - midi_controllable = on; - modified = true; -} - -void SeqDriver::setSendLogEvents(bool on) -{ - sendLogEvents = on; - modified = true; -} - -void SeqDriver::tr_state_cb(bool on, void *context) +void SeqDriver::setUseJackTransport(bool on) { - ((SeqDriver *)context)->setQueueStatus(on); + if (on) { + jackSync->callJack(0); + jackSync->useJackSync = true; + } + else { + jackSync->callJack(-1); + } + useJackSync = on; } diff -Nru qmidiarp-0.4.2/src/seqdriver.h qmidiarp-0.4.5/src/seqdriver.h --- qmidiarp-0.4.2/src/seqdriver.h 2011-07-09 15:25:08.000000000 +0000 +++ qmidiarp-0.4.5/src/seqdriver.h 2011-12-20 17:58:06.000000000 +0000 @@ -29,27 +29,25 @@ #include #include -#include "jacksync.h" +#include "jackdriver.h" #include "midiarp.h" #include "midilfo.h" #include "midiseq.h" #include "main.h" +#include "driverbase.h" -/*! @brief ALSA sequencer backend QThread class. Also creates JackSync +/*! @brief ALSA sequencer backend QThread class. Also creates JackDriver * * SeqDriver is created by Engine at the moment of program start. Its * constructor registers ALSA seq input port and the requested number of - * output ports. I also creates a JackSync instance whose ports are only - * created when the SeqDriver::setUseJackTransport member is called. - * Pointers to the MIDI workers MidiLfo, MidiSeq are passed to SeqDriver - * as arguments. + * output ports. It is called with a portless JackDriver instance. * The SeqDriver::run() thread is the ALSA sequencer "callback" process * handling all incoming and outgoing sequencer events. - * When the SeqDriver::setQueueStatus() member is called with True argument, + * When the SeqDriver::setTransportStatus() member is called with True argument, * a so called "echo event" is scheduled with zero time. Echo events go back * to the callback process and allow output and reception of sequencer * events depending on the ALSA queue timing. Depending on the event types, - * the MIDI worker interfaces are called in series and return their + * the Engine and its modules are called in series and return their * data to be output to the queue. After the data output, a new echo * event is requested for the next MIDI event to be output, which will * again call the SeqDriver::run() thread, and so on. @@ -60,37 +58,18 @@ * is rescaled to a simpler tick-based timing, which is currently 192 tpqn * using the SeqDriver::deltaToTick and SeqDriver::tickToDelta functions. */ -class SeqDriver : public QThread { +class SeqDriver : public DriverBase { Q_OBJECT private: - int portCount; - QList *midiArpList; - QList *midiLfoList; - QList *midiSeqList; snd_seq_t *seq_handle; int clientid; int portid_out[MAX_PORTS]; - int lfoMinPacketSize; - int seqMinPacketSize; int portid_in; int queue_id; bool startQueue; - bool modified; - bool midi_controllable; bool threadAbort; - bool gotArpKbdTrig; - bool gotSeqKbdTrig; - bool sendLogEvents; - int tick, jack_offset_tick, schedDelayTicks; - int lastSchedTick; - int nextLfoTick[20], nextMinLfoTick; - int nextSeqTick[20], nextMinSeqTick; - int nextArpTick[20], nextMinArpTick; - int tempo, internal_tempo; - QVector lfoData; - Sample seqSample; double tickToDelta(int tick); int deltaToTick (double curtime); @@ -98,58 +77,42 @@ const snd_seq_real_time_t* deltaToATime(double curtime); void calcClockRatio(); - void schedEvent(MidiEvent outEv, int n_tick, int outport, int length = 0); - bool requestEchoAt(int echoTick, int infotag = 1); - bool handleEvent(MidiEvent inEv); - void handleEcho(MidiEvent inEv); - void resetTicks(); + void initTempo(); - JackSync *jackSync; + JackDriver *jackSync; + jack_position_t jPos; int midiTick; - double m_ratio; /* duration of one tick, in nanoseconds; based on current tempo */ - snd_seq_real_time_t delta, real_time; - snd_seq_real_time_t tmptime; + int lastRatioTick; + int lastSchedTick; + int jackOffsetTick; + + double clockRatio; /* duration of one tick, in nanoseconds; based on current tempo */ + snd_seq_real_time_t delta, realTime; + snd_seq_real_time_t tmpTime; - static void tr_state_cb(bool tr_state, void * context); public: - bool forwardUnmatched, runQueueIfArp, runArp; - int portUnmatched; - bool use_midiclock, use_jacksync, trigByKbd; + void sendMidiEvent(MidiEvent ev, int n_tick, unsigned int outport, unsigned int duration = 0); + bool requestEchoAt(int echoTick, bool echo_from_trig = 0); public: -/*! @param p_midiArpList List of pointers to each MidiArp worker - * @param p_midiLfoList List of pointers to each MidiLfo worker - * @param p_midiSeqList List of pointers to each MidiSeq worker - * @param parent QWidget ID of the parent Widget - */ - SeqDriver(QList *p_midiArpList, - QList *p_midiLfoList, - QList *p_midiSeqList, int p_portCount, QWidget* parent=0); + SeqDriver( + JackDriver *p_jackSync, + int p_portCount, + void * callback_context, + bool (* midi_event_received_callback)(void * context, MidiEvent ev), + void (* tick_callback)(void * context, bool echo_from_trig)); ~SeqDriver(); void getTime(); - bool isModified(); - void setModified(bool); - int getAlsaClientId(); + int getClientId(); /** overloaded over DriverBase */ void run(); - signals: - void midiEvent(MidiEvent ev); - void controlEvent(int ccnumber, int channel, int value); - void jackShutdown(bool); //boolean is passed to main toolbar - //jackSync button - public slots: - void setForwardUnmatched(bool on); - void setPortUnmatched(int id); - void setQueueStatus(bool run); - void setQueueTempo(int bpm); - void setUseMidiClock(bool on); - void setMidiControllable(bool on); - void setUseJackTransport(bool on); - void setSendLogEvents(bool on); - void jackShutdown(); + void setTransportStatus(bool run); /** is pure in DriverBase */ + void setTempo(int bpm); /** overloaded over DriverBase */ + void setUseMidiClock(bool on); /** overloaded over DriverBase */ + void setUseJackTransport(bool on); /** overloaded over DriverBase */ }; #endif diff -Nru qmidiarp-0.4.2/src/seqscreen.cpp qmidiarp-0.4.5/src/seqscreen.cpp --- qmidiarp-0.4.2/src/seqscreen.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/seqscreen.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -40,8 +40,12 @@ baseOctave = 3; nOctaves= 4; recordMode = false; - currentRecStep = false; + currentRecStep = 0; + loopMarker = 0; currentIndex = 0; + grooveTick = 0; + grooveVelocity = 0; + grooveLength = 0; isMuted = false; } @@ -170,8 +174,7 @@ pen.setWidth(notestreak_thick); p.setPen(pen); for (l1 = 0; l1 < npoints; l1++) { - - x = l1 * xscale * nsteps / npoints; + x = (l1 + .01 * (double)grooveTick * (l1 % 2)) * nsteps * xscale / npoints; tmpval = p_data.at(l1).value; if ((tmpval >= 12 * baseOctave) && (tmpval < 12 * maxOctave)) { ypos = yscale - yscale @@ -180,12 +183,11 @@ xpos = SEQSCR_HMARG + x + pen.width() / 2; if (p_data.at(l1).muted) { pen.setColor(QColor(5, 40, 100)); - p.setPen(pen); } else { pen.setColor(QColor(50, 130, 180)); - p.setPen(pen); } + p.setPen(pen); p.drawLine(xpos, ypos, xpos + (xscale / beatRes) - pen.width(), ypos); } @@ -194,18 +196,35 @@ pen.setWidth(2); pen.setColor(QColor(50, 160, 220)); p.setPen(pen); - p.drawLine(SEQSCR_HMARG / 2, ypos, - SEQSCR_HMARG *2 / 3, ypos); + p.drawLine(SEQSCR_HMARG / 2, ypos, SEQSCR_HMARG *2 / 3, ypos); // Cursor pen.setWidth(notestreak_thick); pen.setColor(QColor(50, 180, 220)); p.setPen(pen); - x = currentIndex * xscale * (int)nsteps / npoints; + x = (currentIndex + .01 * (double)grooveTick * (currentIndex % 2)) + * xscale * (int)nsteps / npoints; xpos = SEQSCR_HMARG + x + pen.width() / 2; p.drawLine(xpos, h - 2, xpos + (xscale / beatRes) - pen.width(), h - 2); - + // Loop Marker + if (loopMarker) { + QPolygon trg; + pen.setWidth(2); + pen.setColor(QColor(80, 250, 120)); + p.setPen(pen); + x = abs(loopMarker) * xscale * (int)nsteps / npoints; + xpos = SEQSCR_HMARG + x + pen.width() / 2; + ypos = h - SEQSCR_VMARG; + tmpval = SEQSCR_VMARG / 2; + trg << QPoint(xpos, ypos); + if (loopMarker > 0) + trg << QPoint(xpos - tmpval, ypos + tmpval); + else + trg << QPoint(xpos + tmpval, ypos + tmpval); + trg << QPoint(xpos, h); + p.drawPolygon(trg, Qt::WindingFill); + } } void SeqScreen::updateScreen(const QVector& data) @@ -220,6 +239,14 @@ update(); } +void SeqScreen::newGrooveValues(int tick, int vel, int length) +{ + grooveTick = tick; + grooveVelocity = vel; + grooveLength = length; + update(); +} + void SeqScreen::setMuted(bool on) { isMuted = on; @@ -245,10 +272,6 @@ { mouseX = event->x(); mouseY = event->y(); - if ((mouseX < SEQSCR_HMARG)|| (mouseX >= w - SEQSCR_HMARG)) - return; - if ((mouseY <= SEQSCR_VMARG)|| (mouseY > h - SEQSCR_VMARG)) - return; emit mousePressed(((double)mouseX - SEQSCR_HMARG) / (w - 2 * SEQSCR_HMARG), 1. - ((double)mouseY - SEQSCR_VMARG) / @@ -265,6 +288,12 @@ currentRecStep = recStep; } +void SeqScreen::setLoopMarker(int pos) +{ + loopMarker = pos; + update(); +} + QSize SeqScreen::sizeHint() const { return QSize(SEQSCR_MIN_W, SEQSCR_MIN_H); diff -Nru qmidiarp-0.4.2/src/seqscreen.h qmidiarp-0.4.5/src/seqscreen.h --- qmidiarp-0.4.2/src/seqscreen.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/seqscreen.h 2012-01-21 10:04:54.000000000 +0000 @@ -36,8 +36,8 @@ #include "midiseq.h" #define SEQSCR_MIN_W 180 -#define SEQSCR_MIN_H 212 -#define SEQSCR_VMARG 10 +#define SEQSCR_MIN_H 216 +#define SEQSCR_VMARG 14 #define SEQSCR_HMARG 20 /*! @brief Drawing widget for visualization of sequences using QPainter @@ -60,12 +60,15 @@ private: //QTimer *timer; QVector p_data, data; + int grooveTick, grooveVelocity, grooveLength; int mouseX, mouseY; int w, h; bool recordMode; int currentRecStep; int currentIndex; + int loopMarker; bool isMuted; + QPointF trg[3]; protected: virtual void paintEvent(QPaintEvent *); @@ -88,6 +91,8 @@ void mousePressEvent(QMouseEvent* event); void setRecordMode(bool on); void setCurrentRecStep(int currentRecStep); + void setLoopMarker(int pos); + void newGrooveValues(int tick, int vel, int length); void setMuted(bool on); }; diff -Nru qmidiarp-0.4.2/src/seqwidget.cpp qmidiarp-0.4.5/src/seqwidget.cpp --- qmidiarp-0.4.2/src/seqwidget.cpp 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/seqwidget.cpp 2012-01-21 17:14:21.000000000 +0000 @@ -42,7 +42,7 @@ int l1; QStringList midiCCNames; midiCCNames << "MuteToggle" << "Velocity" << "NoteLength" - << "RecordToggle" << "Resolution"<< "Size" << "unknown"; + << "RecordToggle" << "Resolution"<< "Size" << "LoopMode" << "unknown"; midiControl = new MidiControl(midiCCNames); manageBox = new ManageBox("Seq:", true, this); @@ -52,7 +52,8 @@ QSignalMapper *dispSignalMapper = new QSignalMapper(this); QLabel *dispLabel[4]; - QString dispText[4] = {tr("&Full"), tr("&Upper"), tr("&Mid"), tr("&Lower")}; + QString dispText[4] = {tr("&F"), tr("&U"), tr("&M"), tr("&L")}; + QString dispToolTip[4] = {tr("Full"), tr("Upper"), tr("Mid"), tr("Lower")}; QGridLayout *dispBoxLayout = new QGridLayout; for (int l1 = 0; l1 < 4; l1++) { @@ -62,8 +63,9 @@ dispSignalMapper->setMapping(dispVert[l1], l1); dispVert[l1]->setAutoExclusive(true); dispLabel[l1]->setBuddy(dispVert[l1]); - dispBoxLayout->addWidget(dispLabel[l1], l1, 0); - dispBoxLayout->addWidget(dispVert[l1], l1, 1); + dispVert[l1]->setToolTip(dispToolTip[l1]); + dispBoxLayout->addWidget(dispLabel[l1], 0, l1); + dispBoxLayout->addWidget(dispVert[l1], 1, l1); } dispVert[0]->setChecked(true); @@ -114,18 +116,11 @@ enableTrigByKbdLabel->setBuddy(enableTrigByKbd); enableTrigByKbd->setToolTip(tr("Retrigger sequence when a new note is received")); - QLabel *enableLoopLabel = new QLabel(tr("&Loop"),inBox); - enableLoop = new QCheckBox(this); - connect(enableLoop, SIGNAL(toggled(bool)), this, SLOT(updateEnableLoop(bool))); - enableLoopLabel->setBuddy(enableLoop); - enableLoop->setToolTip(tr("Play sequence as loop instead of a single run")); - enableNoteIn->setChecked(true); enableNoteOff->setChecked(false); enableVelIn->setChecked(true); enableRestartByKbd->setChecked(false); enableTrigByKbd->setChecked(false); - enableLoop->setChecked(true); QLabel *chInLabel = new QLabel(tr("&Channel"), inBox); chIn = new QComboBox(inBox); @@ -145,10 +140,8 @@ inBoxLayout->addWidget(enableRestartByKbd, 3, 1); inBoxLayout->addWidget(enableTrigByKbdLabel, 4, 0); inBoxLayout->addWidget(enableTrigByKbd, 4, 1); - inBoxLayout->addWidget(enableLoopLabel, 5, 0); - inBoxLayout->addWidget(enableLoop, 5, 1); - inBoxLayout->addWidget(chInLabel, 6, 0); - inBoxLayout->addWidget(chIn, 6, 1); + inBoxLayout->addWidget(chInLabel, 5, 0); + inBoxLayout->addWidget(chIn, 5, 1); if (compactStyle) { inBoxLayout->setSpacing(1); inBoxLayout->setMargin(2); @@ -227,6 +220,18 @@ connect(waveFormBox, SIGNAL(activated(int)), this, SLOT(updateWaveForm(int))); + loopBox = new QComboBox(seqBox); + QStringList names; + names.clear(); + names << "->_>" << " <_<-" << "->_<" << " >_<-" << "->_|" << " |_<-"; + loopBox->insertItems(0, names); + loopBox->setCurrentIndex(0); + loopBox->setToolTip(tr("Loop, bounce or play once going forward or backward")); + loopBox->setMinimumContentsLength(5); + connect(loopBox, SIGNAL(activated(int)), this, + SLOT(updateLoop(int))); + midiControl->addMidiLearnMenu(loopBox, 6); + QLabel *recordButtonLabel = new QLabel(tr("Re&cord"), seqBox); recordAction = new QAction(QIcon(seqrecord_xpm), tr("Re&cord"), seqBox); recordAction->setToolTip(tr("Record step by step")); @@ -241,7 +246,6 @@ seqBox); resBox = new QComboBox(seqBox); resBoxLabel->setBuddy(resBox); - QStringList names; names.clear(); names << "1" << "2" << "4" << "8" << "16"; resBox->insertItems(0, names); @@ -302,15 +306,16 @@ } QGridLayout *paramBoxLayout = new QGridLayout; - paramBoxLayout->addWidget(waveFormBoxLabel, 0, 0); - paramBoxLayout->addWidget(waveFormBox, 0, 1); - paramBoxLayout->addWidget(recordButtonLabel, 1, 0); - paramBoxLayout->addWidget(recordButton, 1, 1); - paramBoxLayout->addWidget(resBoxLabel, 2, 0); - paramBoxLayout->addWidget(resBox, 2, 1); - paramBoxLayout->addWidget(sizeBoxLabel, 3, 0); - paramBoxLayout->addWidget(sizeBox, 3, 1); - paramBoxLayout->setRowStretch(4, 1); + paramBoxLayout->addWidget(loopBox, 0, 0, 1, 2); + paramBoxLayout->addWidget(waveFormBoxLabel, 1, 0); + paramBoxLayout->addWidget(waveFormBox, 1, 1); + paramBoxLayout->addWidget(recordButtonLabel, 2, 0); + paramBoxLayout->addWidget(recordButton, 2, 1); + paramBoxLayout->addWidget(resBoxLabel, 3, 0); + paramBoxLayout->addWidget(resBox, 3, 1); + paramBoxLayout->addWidget(sizeBoxLabel, 4, 0); + paramBoxLayout->addWidget(sizeBox, 4, 1); + paramBoxLayout->setRowStretch(5, 1); QGridLayout* seqBoxLayout = new QGridLayout; seqBoxLayout->addWidget(screen, 0, 0, 1, 2); @@ -368,8 +373,6 @@ midiWorker->restartByKbd)); xml.writeTextElement("trigByKbd", QString::number( midiWorker->trigByKbd)); - xml.writeTextElement("enableLoop", QString::number( - midiWorker->enableLoop)); xml.writeTextElement("channel", QString::number( midiWorker->chIn)); xml.writeEndElement(); @@ -384,6 +387,8 @@ xml.writeEndElement(); xml.writeStartElement("seqParams"); + xml.writeTextElement("loopmode", QString::number( + loopBox->currentIndex())); xml.writeTextElement("resolution", QString::number( resBox->currentIndex())); xml.writeTextElement("size", QString::number( @@ -414,6 +419,8 @@ } xml.writeStartElement("sequence"); xml.writeTextElement("data", tempArray.toHex()); + xml.writeTextElement("loopmarker", QString::number( + getLoopMarker())); xml.writeEndElement(); midiControl->writeData(xml); @@ -457,8 +464,6 @@ enableRestartByKbd->setChecked(xml.readElementText().toInt()); else if (xml.name() == "trigByKbd") enableTrigByKbd->setChecked(xml.readElementText().toInt()); - else if (xml.name() == "enableLoop") - enableLoop->setChecked(xml.readElementText().toInt()); else if (xml.name() == "channel") { tmp = xml.readElementText().toInt(); chIn->setCurrentIndex(tmp); @@ -494,6 +499,11 @@ xml.readNext(); if (xml.isEndElement()) break; + if (xml.name() == "loopmode") { + tmp = xml.readElementText().toInt(); + loopBox->setCurrentIndex(tmp); + updateLoop(tmp); + } else if (xml.name() == "resolution") { tmp = xml.readElementText().toInt(); resBox->setCurrentIndex(tmp); @@ -555,6 +565,11 @@ lt+=step; } } + else if (xml.name() == "loopmarker") { + tmp = xml.readElementText().toInt(); + midiWorker->loopMarker = tmp; + screen->setLoopMarker(tmp); + } else skipXmlElement(xml); } } @@ -585,95 +600,6 @@ } } -void SeqWidget::readDataText(QTextStream& arpText) -{ - QString qs, qs2; - int l1, lt, wvtmp; - Sample sample; - - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - enableNoteIn->setChecked(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - enableVelIn->setChecked(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - chIn->setCurrentIndex(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - channelOut->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - portOut->setCurrentIndex(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - notelength->setValue(qs2.toInt()); - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - resBox->setCurrentIndex(qs2.toInt()); - updateRes(qs2.toInt()); - qs2 = qs.section(' ', 1, 1); - sizeBox->setCurrentIndex(qs2.toInt()); - updateSize(qs2.toInt()); - qs2 = qs.section(' ', 2, 2); - velocity->setValue(qs2.toInt()); - qs2 = qs.section(' ', 3, 3); - transpose->setValue(qs2.toInt()); - qs = arpText.readLine(); - if (qs == "MIDICC") - { - qs = arpText.readLine(); - while (qs != "EOCC") { - qs2 = qs.section(' ', 0, 0); - int controlID = qs2.toInt(); - qs2 = qs.section(' ', 1, 1); - int ccnumber = qs2.toInt(); - qs2 = qs.section(' ', 2, 2); - int channel = qs2.toInt(); - qs2 = qs.section(' ', 3, 3); - int min = qs2.toInt(); - qs2 = qs.section(' ', 4, 4); - int max = qs2.toInt(); - midiControl->appendMidiCC(controlID, ccnumber, channel, min, max); - qs = arpText.readLine(); - } - qs = arpText.readLine(); - } - - wvtmp = qs.toInt(); - - // Read Mute Mask - int step = TPQN / midiWorker->res; - qs = arpText.readLine(); - if (qs.isEmpty() || (qs == "EOP")) return; - qs2 = qs.section(' ', 0, 0); - midiWorker->muteMask.clear(); - l1 = 0; - while (qs2 !="EOM") { - midiWorker->muteMask.append(qs2.toInt()); - l1++; - if (!(l1%32)) qs = arpText.readLine(); - qs2 = qs.section(' ', l1%32, l1%32); - } - - // Read Custom Waveform - qs = arpText.readLine(); - qs2 = qs.section(' ', 0, 0); - midiWorker->customWave.clear(); - l1 = 0; - lt = 0; - while (qs2 !="EOS") { - sample.value=qs2.toInt(); - sample.tick = lt; - sample.muted = midiWorker->muteMask.at(l1); - midiWorker->customWave.append(sample); - lt+=step; - l1++; - if (!(l1%16)) qs = arpText.readLine(); - qs2 = qs.section(' ', l1%16, l1%16); - } - waveFormBox->setCurrentIndex(wvtmp); - updateWaveForm(wvtmp); - modified = false; -} - void SeqWidget::loadWaveForms() { waveForms << tr("Custom"); @@ -733,12 +659,6 @@ modified = true; } -void SeqWidget::updateEnableLoop(bool on) -{ - midiWorker->enableLoop = on; - modified = true; -} - void SeqWidget::updateNoteLength(int val) { midiWorker->notelength = val + val; @@ -784,6 +704,14 @@ modified = true; } +void SeqWidget::updateLoop(int val) +{ + if (val > 5) return; + midiWorker->updateLoop(val); + modified = true; +} + + void SeqWidget::updateVelocity(int val) { midiWorker->vel = val; @@ -819,6 +747,7 @@ void SeqWidget::mouseMoved(double mouseX, double mouseY, int buttons) { + if ((mouseX > 1) || (mouseX < 0) || (mouseY > 1)) return; if (buttons == 2) { midiWorker->setMutePoint(mouseX, lastMute); } @@ -833,6 +762,17 @@ void SeqWidget::mousePressed(double mouseX, double mouseY, int buttons) { + if (mouseY < 0) { + if (mouseX < 0) mouseX = 0; + if (buttons == 2) mouseX = - mouseX; + midiWorker->setLoopMarker(mouseX); + screen->setLoopMarker(midiWorker->loopMarker); + modified = true; + return; + } + + if ((mouseX > 1) || (mouseX < 0) || (mouseY > 1)) return; + if (buttons == 2) { lastMute = midiWorker->toggleMutePoint(mouseX); } else { @@ -934,7 +874,6 @@ enableVelIn->setChecked(fromWidget->enableVelIn->isChecked()); enableRestartByKbd->setChecked(fromWidget->enableRestartByKbd->isChecked()); enableTrigByKbd->setChecked(fromWidget->enableTrigByKbd->isChecked()); - enableLoop->setChecked(fromWidget->enableLoop->isChecked()); tmp = fromWidget->chIn->currentIndex(); chIn->setCurrentIndex(tmp); @@ -952,6 +891,9 @@ tmp = fromWidget->sizeBox->currentIndex(); sizeBox->setCurrentIndex(tmp); updateSize(tmp); + tmp = fromWidget->loopBox->currentIndex(); + loopBox->setCurrentIndex(tmp); + updateLoop(tmp); tmp = fromWidget->velocity->value(); updateVelocity(tmp); @@ -966,6 +908,9 @@ for (int l1 = 0; l1 < midiWorker->customWave.count(); l1++) { midiWorker->muteMask.append(midiWorker->customWave.at(l1).muted); } + tmp = fromWidget->getLoopMarker(); + midiWorker->loopMarker = tmp; + screen->setLoopMarker(tmp); midiControl->setCcList(fromWidget->midiControl->ccList); muteOut->setChecked(true); updateWaveForm(0); @@ -975,3 +920,80 @@ { return midiWorker->customWave; } + +void SeqWidget::handleController(int ccnumber, int channel, int value) +{ + bool m; + int min, max, sval; + QVector cclist= midiControl->ccList; + + for (int l2 = 0; l2 < cclist.count(); l2++) { + min = cclist.at(l2).min; + max = cclist.at(l2).max; + if ((ccnumber == cclist.at(l2).ccnumber) && + (channel == cclist.at(l2).channel)) { + switch (cclist.at(l2).ID) { + case 0: if (min == max) { + if (value == max) { + m = muteOut->isChecked(); + muteOut->setChecked(!m); + } + } + else { + if (value == max) { + muteOut->setChecked(false); + } + if (value == min) { + muteOut->setChecked(true); + } + } + break; + + case 1: + sval = min + ((double)value * (max - min) / 127); + velocity->setValue(sval); + break; + + case 2: + sval = min + ((double)value * (max - min) / 127); + notelength->setValue(sval); + break; + + case 3: if (min == max) { + if (value == max) { + m = recordAction->isChecked(); + recordAction->setChecked(!m); + return; + } + } + else { + if (value == max) { + recordAction->setChecked(true); + } + if (value == min) { + recordAction->setChecked(false); + } + } + break; + case 4: + sval = min + ((double)value * (max - min) / 127); + resBox->setCurrentIndex(sval); + updateRes(sval); + break; + case 5: + sval = min + ((double)value * (max - min) / 127); + sizeBox->setCurrentIndex(sval); + updateSize(sval); + break; + case 6: + sval = min + ((double)value * (max - min) / 127); + loopBox->setCurrentIndex(sval); + updateLoop(sval); + break; + + default: + break; + } + } + } +} diff -Nru qmidiarp-0.4.2/src/seqwidget.h qmidiarp-0.4.5/src/seqwidget.h --- qmidiarp-0.4.2/src/seqwidget.h 2011-07-09 10:33:33.000000000 +0000 +++ qmidiarp-0.4.5/src/seqwidget.h 2012-01-21 17:14:21.000000000 +0000 @@ -99,7 +99,7 @@ * instance. * * @param p_midiWorker Associated MidiSeq Object - * @param portCount Number of available ALSA MIDI output ports + * @param portCount Number of available MIDI output ports * @param compactStyle If set to True, Widget will use reduced spacing and small fonts * @param mutedAdd If set to True, the module will be added in muted state * @param parent The parent widget of this module, i.e. MainWindow @@ -116,13 +116,13 @@ QComboBox *chIn; QComboBox *channelOut, *portOut; QComboBox *waveFormBox, *resBox, *sizeBox, *freqBox; + QComboBox *loopBox; QCheckBox *muteOut; QCheckBox *enableNoteIn; QCheckBox *enableNoteOff; QCheckBox *enableVelIn; QCheckBox *enableRestartByKbd; QCheckBox *enableTrigByKbd; - QCheckBox *enableLoop; QCheckBox *dispVert[4]; Slider *velocity, *transpose, *notelength; QAction *recordAction; @@ -148,13 +148,6 @@ */ void readData(QXmlStreamReader& xml); /*! -* @brief This function reads all module parameters of this module from an old -* QMidiArp .qma text stream. -* -* @param arpText QTextStream to read from -*/ - void readDataText(QTextStream& arpText); -/*! * @brief This function writes all parameters of this module to an XML stream * passed by the caller, i.e. MainWindow. * @@ -228,6 +221,15 @@ */ void updateSize(int); /*! +* @brief Slot for the SeqWidget::loopBox combobox. Sets the loop mode +* of the sequencer. +* +* It sets MidiSeq::reverse, MidiSeq::pingpong and MidiSeq::enableLoop +* @param val Combination index ranging from 0 to 5 +* +*/ + void updateLoop(int); +/*! * @brief Slot for the SeqWidget::velocity slider. Sets the note velocity * of the sequencer. * @@ -251,7 +253,6 @@ void updateEnableNoteOff(bool on); void updateEnableRestartByKbd(bool on); void updateEnableTrigByKbd(bool on); - void updateEnableLoop(bool on); void setRecord(bool on); void setDispVert(int mode); void updateDispVert(int mode); @@ -344,6 +345,12 @@ * */ void setMuted(bool on); + + int getCurrentIndex() { return midiWorker->getCurrentIndex(); } + int getLoopMarker() { return midiWorker->loopMarker; } + int getNextTick() { return midiWorker->nextTick; } + bool getReverse() { return midiWorker->reverse; } + void handleController(int ccnumber, int channel, int value); }; #endif diff -Nru qmidiarp-0.4.2/src/translations/qmidiarp_cs.ts qmidiarp-0.4.5/src/translations/qmidiarp_cs.ts --- qmidiarp-0.4.2/src/translations/qmidiarp_cs.ts 2011-07-09 17:30:05.000000000 +0000 +++ qmidiarp-0.4.5/src/translations/qmidiarp_cs.ts 2012-01-21 17:29:21.000000000 +0000 @@ -30,18 +30,6 @@ &Ztlumit - MIDI &Learn - &Učení se MIDI - - - Cancel MIDI &Learning - Zrušit &učení se MIDI - - - MIDI &Forget - &Zapomenutí nastavení MIDI - - &Port &Přípojka @@ -92,73 +80,27 @@ &Držet noty - - Note Filter - ACTIVE - Notový filtr - ČINNÝ - - - Arp through chord - Arpeggio bei Akkord - - - 0..9 note played on keyboard, ascending order -( ) chord mode on/off - + - octave up/down - < . > tempo up/reset/down - d h note length up/down - / \ velocity up/down - p pause - 0..9 gespielte Note in aufsteigender Anordnung -( ) Akkord-Modus ein/aus - + - Octave auf/ab - < . > Tempo auf/ab - d h Notenlänge auf/ab - / \ Geschwindigkeit auf/ab - p Pause - - - &Attack (s) - &Náběh (s) + &Attack (beats) + &Náběh (beats) - &Release (s) - &Uvolnění (s) + &Release (beats) + &Uvolnění (beats) + + + + Note Filter - ACTIVE + Notový filtr - ČINNÝ - + Random Náhodný - &Rename... - Pře&jmenovat... - - - Ctrl+R - Module|Rename - Strg+R - - - Rename this Arp - Přejmenovat tento arpeggiator - - - &Delete... - S&mazat... - - - Ctrl+Del - Module|Delete - Strg+Del - - - Delete this Arp - Smazat tento arpeggiator - - Repeat mode Režim opakování @@ -202,54 +144,42 @@ - + Envelope Obálka - Delete "%1"? - Smazat "%1"? - - - New Name - Nový název - - - Could not write to resource file - Konnte Ressourcendatei nicht speichern - - - + Could not read from resource file Nepodařilo se číst ze zdrojového souboru - + Random - ACTIVE Náhodný - ČINNÝ - + Envelope - ACTIVE Obálka - ČINNÁ - + %1: Store pattern %1: Uložit vzor - + New pattern Nový vzor - + Arp pattern Vzor pro arpeggiator - + Remove "%1"? Odstranit "%1"? @@ -305,221 +235,196 @@ LfoWidget - + Output Výstup - + &Mute &Ztlumit - - + + MIDI &CC# - + MIDI Controller number sent to output Číslo ovladače MIDI poslaného do výstupu - + C&hannel &Kanál - + &Port &Přípojka - &Rename... - Pře&jmenovat... - - - Rename this LFO - Přejmenovat tento nízkokmitočtový oscilátor (LFO) - - - &Delete... - S&mazat... - - - Delete this LFO - Smazat tento nízkokmitočtový oscilátor (LFO) - - Input Vstup - + MIDI Controller number to record Číslo ovladače MIDI pro nahrávání - + &Channel &Каnál - MIDI &Learn - &Učení se MIDI - - - Cancel MIDI &Learning - Zrušit &učení se MIDI + + Wave + Vlna - MIDI &Forget - &Zapomenutí nastavení MIDI + + Waveform Basis + Základ tvaru vlny - - Wave - Vlna + + Right button to mute points +Left button to draw custom wave +Wheel to change offset + Pravé tlačítko myši: ztlumení jednotlivých bodů +Levé tlačítko myši: kreslení tvaru vlny +Kolečko myši: změna posunu - Right button to mute points, left button to draw custom wave - Rechte Maustaste: Stummschalten einzelner Punkte, linke Maustaste: Zeichnen der Wellenform + + &Note Off + &Nota vypnuta - - Waveform Basis - Základ tvaru vlny + + Stop output when Note is released + Zastavit výstup, když je nota vydána - &Frequency (cycles/beat) - &Frequenz (Zyklen/Takt) + + &Restart + &Spustit znovu - Frequency: Number of wave cycles produced every beat - Frequenz: Anzahl der erzeugten Wellenzyklen pro beat + + Restart sequence when a new note is received + Spustit sekvenci znovu, když je nota přijata - &Resolution (events/beat) - &Auflösung (Signale/Takt) + + &Trigger + &Spoušť - Resolution: Number of events produced every beat - Auflösung: Anzahl der pro Takt erzeugten MIDI Signale + + Retrigger sequence when a new note is received + Spustit sekvenci znovu, když je přijata nová nota - &Length (beats) - Län&ge (Takte) + &Loop + &Smyčka - - Right button to mute points -Left button to draw custom wave -Wheel to change offset - Pravé tlačítko myši: ztlumení jednotlivých bodů -Levé tlačítko myši: kreslení tvaru vlny -Kolečko myši: změna posunu + Play sequence as loop instead of a single run + Přehrávat sekvenci ve smyčce namísto jednoho přehrání - + &Frequency &Kmitočet - + Frequency (cycles/beat): Number of wave cycles produced every beat Kmitočet (cyklů za dobu): Počet vytvořených vlnových cyklů za čtvrťový takt - + &Resolution &Rozlišení - + Resolution (events/beat): Number of events produced every beat Rozlišení (události (signály) za dobu): Počet signálů MIDI vytvořených za čtvrťový takt - + &Length &Délka - + Length of LFO wave in beats Délka tvaru vlny LFO ve čtvrťových taktech - &Copy to custom wave - &In die freie Wellenform kopieren + + Loop, bounce or play once going forward or backward + Opakovat, hrát tam a zpět nebo jen jednou, dopředu nebo dozadu - - + + Re&cord &Nahrát - + Record incoming controller Nahrát příchozí ovladač - + &Amplitude Ro&zkmit - + &Offset Pos&un - + Sine Sinus - + Saw up Pila nahoru - + Triangle Trojúhelník - + Saw down Pila dolů - + Square Čtverec - + Custom Vlastní - Delete "%1"? - Smazat "%1"? - - - New Name - Nový název - - - &MIDI CC# - &MIDI CC# - - - + &Waveform &Tvar vlny @@ -527,42 +432,42 @@ LogWidget - + &Enable Log &Povolit zápis - + Log &MIDI Clock Zachycovat hodiny &MIDI - + &Clear &Smazat - - MIDI Clock - Hodiny MIDI + + MIDI Clock, tick + Hodiny MIDI, tick - + MIDI Start (Transport) Začátek hodin MIDI (Transport) - + MIDI Continue (Transport) Pokračování MIDI (Transport) - + MIDI Stop (Transport) Zastavení MIDI (Transport) - + Unknown event type Neznámá událost (signál) MIDI @@ -570,380 +475,326 @@ MainWindow - + Event Log Zápis událostí - Settings - Einstellungen - - - + Groove Groove - + &New LFO... &Nový LFO... - + &New Sequencer... &Nový sekvencer... - + Ctrl+T Module|New Sequencer Ctrl+T - + Add new Sequencer to tab bar Přidat nový sekvencer do pruhu s kartami - &Rename... - &Umbenennen... - - - Rename this module - Dieses Modul umbenennen - - - &Delete... - &Löschen... - - - Delete this module - Dieses Modul löschen - - - + &New &Nový - + Create new arpeggiator file Vytvořit nový soubor s arpeggiatorem - + &Open... &Otevřít... - + &Save &Uložit - + Save current arpeggiator file Uložit nynější soubor s arpeggiatorem - + Save &as... Uložit &jako... - + Save current arpeggiator file with new name Uložit nynější soubor s arpeggiatorem pod novým názvem - + &Quit &Ukončit - + Ctrl+Q File|Quit Ctrl+Q - + Quit application Ukončit program - + &Run with internal clock &Spustit/Zastavit s vnitřními hodinami - + &Connect to Jack Transport Spojit s &Jack Transport - + Ctrl+H View|Event Log Ctrl+H - + &Groove Settings Nastavení &Groove - + Ctrl+G View|Groove Ctrl+G - + Mod&ule Mod&ul - + &Recently opened files Naposledy otevřené sou&bory - + &MIDI Controllers... Ovladače &MIDI... - + &File Toolbar Nástrojový pruh pro &soubor - + &Control Toolbar Nástrojový pruh pro &ovládání - - - + + + %1 %1 - + Add MIDI LFO Přidat MIDI LFO - + Add Step Sequencer Přidat krokový sekvencer - + QMidiArp XML files Soubory QMidiArp XML - Old QMidiArp files - Soubory textové soubory QMidiArp + Soubory textové soubory QMidiArp - - + Could not read from file '%1'. Nepodařilo se číst ze souboru '%1'. - + This is not a valid xml file for Toto není platný soubor XML pro - The QMidiArp text file was imported. If you save this file, it will be saved using the newer xml format under the name '%1'. - Textový soubor QMidiArp byl zaveden. Při novém ukládání bude tento uložen v novém formátu xml pod názvem + Textový soubor QMidiArp byl zaveden. Při novém ukládání bude tento uložen v novém formátu xml pod názvem '%1'. - + Could not write to file '%1'. Nepodařilo se zapsat do souboru '%1'. - + Unnamed file was changed. Save changes? Nepojmenovaný soubor byl změněn. Uložit změny? - + File '%1' was changed. Save changes? Soubor '%1' byl změněn. Uložit změny? - + Save changes Uložit změny - + Could not read from resource file Nepodařilo se číst ze zdrojového souboru - &Run - &Start - - - + &Use incoming MIDI Clock &Použít příchozí signál hodin MIDI - + &Event Log &Zápis událostí - Ctrl+L - View|Event Log - Strg+L - - - + &Settings &Nastavení - + Ctrl+P View|Settings Ctrl+P - + &About Qt... &O Qt... - + About %1 O %1 - + About Qt O Qt - + Add MIDI Arpeggiator Přidat MIDI arpeggiator - New Name - Neuer Name - - - Remove "%1"? - "%1" löschen? - - - - + + Open arpeggiator file Otevřít soubor s arpeggiatorem - + Tempo of internal clock Tempo vnitřních hodin - + Not a QMidiArp xml file. Není souborem XML QMidiArp. - + Save arpeggiator Uložit arpeggiator - + QMidiArp files Soubory QMidiArp - + Could not write to resource file Nepodařilo se zapsat do zdrojového souboru - + &New Arp... &Nový arpeggiator... - + Add new arpeggiator to tab bar Přidat nový arpeggiator do pruhu s kartami - + Add new LFO to tab bar Přidat nový LFO do pruhu s kartami - + Ctrl+A Module|New Arp Ctrl+A - + Ctrl+L Module|New LFO Ctrl+L - Ctrl+R - Module|Rename - Strg+R - - - Ctrl+Del - Module|Delete - Strg+Del - - - + &File &Soubor - + &View &Pohled - &Module - &Modul - - - + &Help &Nápověda - + &About %1... &O %1... @@ -1080,320 +931,231 @@ Settings - Nastavení - - - &Modules mutable by MIDI controller starting at CC# - &Module stummschaltbar durch MIDI controller beginnend mit CC# - - - &Arps mutable by MIDI CC starting at CC# - &Arps stummschaltbar durch MIDI CC beginnend mit CC# - - - Incoming MIDI &Clock rate (tpb) - Kadenz der eingehenden MIDI &Clock (tpb) - SeqWidget - + Transpose the sequence following incoming notes Převést sekvenci skrz příchozí noty - + Output Výstup - + &Mute &Ztlumit - MIDI &Learn - &Učení se MIDI - - - Cancel MIDI &Learning - Zrušit &učení se MIDI - - Display Zobrazit - &Full - &Plný + &Plný - &Upper - &Horní + &Horní - &Mid - &Střední + &Střední - &Lower - &Dolní + &Dolní - + &Note Off &Nota vypnuta - + Stop output when Note is released Zastavit výstup, když je nota vydána - + &Restart &Spustit znovu - + Restart sequence when a new note is received Spustit sekvenci znovu, když je nota přijata - + &Trigger &Spoušť - + Retrigger sequence when a new note is received Spustit sekvenci znovu, když je přijata nová nota - &Loop - &Smyčka + &Smyčka - Play sequence as loop instead of a single run - Přehrávat sekvenci ve smyčce namísto jednoho přehrání + Přehrávat sekvenci ve smyčce namísto jednoho přehrání - MIDI &Forget - &Zapomenutí nastavení MIDI - - - + Sequence Sekvence - + &Sequence &Sekvence - + Preset Number Číslo přednastavení - - + + Re&cord &Nahrát - + Record step by step Příchozí noty nahrávat krok za krokem - + Resolution (notes/beat): Number of notes produced every beat Rozlišení (not za dobu): Počet not zahraných za čtvrťový takt - + Length of Sequence in beats Délka sekvence ve čtvrťových taktech - C&opy to new wave - &Kopírovat do nové vlny - - - + Veloc&ity &Rychlost - Delete "%1"? - Smazat "%1"? + + N&ote Length + Délka n&oty - New Name - Nový název + + &Velocity + &Rychlost - &Copy to new wave - In neue Wellenform &kopieren + + &F + &P - Velo&city - An&schlag + + &U + &H - - N&ote Length - Délka n&oty + + &M + &S - - &Velocity - &Rychlost + + &L + &D - &Rename... - Pře&jmenovat... + + Full + Plný - Rename this Sequencer - Přejmenovat tento sekvencer + + Upper + Horní - &Delete... - S&mazat... + + Mid + Střední - Delete this Sequencer - Smazat tento sekvencer + + Lower + Dolní - + Input Vstup - + &Note &Nota - + Set sequence velocity to that of incoming notes Nastavit rychlost sekvence na rychlost příchozích not - + &Channel &Каnál - &Note Length - &Notenlänge + + Loop, bounce or play once going forward or backward + Opakovat, hrát tam a zpět nebo jen jednou, dopředu nebo dozadu - + &Transpose &Převést - &MIDI CC# - &MIDI CC# - - - MIDI Controller number sent to output - Nummer des gesendeten MIDI Controllers - - - + &Port &Přípojka - + C&hannel &Kanál - Wave - Welle - - - + Right button to mute points, left button to draw custom wave Pravé tlačítko myši: ztlumení jednotlivých bodů, levé tlačítko myši: kreslení tvaru vlny - &Waveform - &Wellenform - - - Waveform Basis - Wellenformbasis - - - &Frequency - &Frequenz - - - Frequency (cycles/beat): Number of wave cycles produced every beat - Frequenz (Zyklen pro beat): Anzahl der erzeugten Wellenzyklen pro Vierteltakt - - - + &Resolution &Rozlišení - Resolution (events/beat): Number of events produced every beat - Auflösung (Signale/beat): Anzahl der pro Vierteltakt erzeugten MIDI Signale - - - + &Length &Délka - &Copy to custom wave - &In die freie Wellenform kopieren - - - &Amplitude - Am&plitude - - - &Offset - &Offset - - - Sine - Sinus - - - Saw up - Sägezahn auf - - - Triangle - Dreieck - - - Saw down - Sägezahn ab - - - Square - Rechteck - - - + Custom Vlastní diff -Nru qmidiarp-0.4.2/src/translations/qmidiarp_de.ts qmidiarp-0.4.5/src/translations/qmidiarp_de.ts --- qmidiarp-0.4.2/src/translations/qmidiarp_de.ts 2011-07-09 15:48:25.000000000 +0000 +++ qmidiarp-0.4.5/src/translations/qmidiarp_de.ts 2012-01-21 17:29:21.000000000 +0000 @@ -30,18 +30,6 @@ &Stumm - MIDI &Learn - &Lerne von MIDI - - - Cancel MIDI &Learning - MIDI-Lernen &Abbrechen - - - MIDI &Forget - MIDI-Steuerungen &vergessen - - &Port Anschl&uss @@ -92,73 +80,27 @@ &Noten ha&lten - - Note Filter - ACTIVE - Notenfilter - AKTIV - - - Arp through chord - Arpeggio bei Akkord - - - 0..9 note played on keyboard, ascending order -( ) chord mode on/off - + - octave up/down - < . > tempo up/reset/down - d h note length up/down - / \ velocity up/down - p pause - 0..9 gespielte Note in aufsteigender Anordnung -( ) Akkord-Modus ein/aus - + - Octave auf/ab - < . > Tempo auf/ab - d h Notenlänge auf/ab - / \ Geschwindigkeit auf/ab - p Pause - - - &Attack (s) - A&ttack (s) + &Attack (beats) + - &Release (s) + &Release (beats) + + Note Filter - ACTIVE + Notenfilter - AKTIV + + - + Random Zufall - &Rename... - &Umbenennen... - - - Ctrl+R - Module|Rename - Strg+R - - - Rename this Arp - Diesen arpeggiator umbenennen - - - &Delete... - &Löschen... - - - Ctrl+Del - Module|Delete - Strg+Del - - - Delete this Arp - Diesen Arpeggiator löschen - - Repeat mode Wiederholungsmodus @@ -202,54 +144,42 @@ - + Envelope Hüllkurve - Delete "%1"? - "%1" löschen? - - - New Name - Neuer Name - - - Could not write to resource file - Konnte Ressourcendatei nicht speichern - - - + Could not read from resource file Konnte Ressourcendatei nicht einlesen - + Random - ACTIVE Zufall - AKTIV - + Envelope - ACTIVE Hüllkurve - AKTIV - + %1: Store pattern %1: Muster speichern - + New pattern Neues Muster - + Arp pattern Arp-Muster - + Remove "%1"? "%1" löschen? @@ -305,229 +235,196 @@ LfoWidget - + Output Ausgang - + &Mute &Stumm - - + + MIDI &CC# - + MIDI Controller number sent to output Nummer des gesendeten MIDI Controllers - + C&hannel &Kanal - + &Port An&schluss - &Clone... - &Duplizieren... - - - Duplicate this LFO in muted state - Diesen LFO in stummem Zustand duplizieren - - - &Rename... - &Umbenennen... - - - Rename this LFO - Diesen LFO umbenennen - - - &Delete... - &Löschen... - - - Delete this LFO - Diesen LFO löschen - - Input Eingang - + MIDI Controller number to record Die aufzunehmende MIDI Controller ID - + &Channel &Kanal - MIDI &Learn - &Lerne von MIDI - - - Cancel MIDI &Learning - MIDI-Lernen &Abbrechen + + Wave + Welle - MIDI &Forget - MIDI-Steuerungen &vergessen + + Waveform Basis + Wellenformbasis - - Wave - Welle + + Right button to mute points +Left button to draw custom wave +Wheel to change offset + Rechte Maustaste: Stummschalten einzelner Punkte +Linke Maustaste: Zeichnen der Wellenform +Mausrad: Verschieben des Offsets - Right button to mute points, left button to draw custom wave - Rechte Maustaste: Stummschalten einzelner Punkte, linke Maustaste: Zeichnen der Wellenform + + &Note Off + - - Waveform Basis - Wellenformbasis + + Stop output when Note is released + Keine Noten senden wenn die Taste losgelassen wird - &Frequency (cycles/beat) - &Frequenz (Zyklen/Takt) + + &Restart + &Neustarten - Frequency: Number of wave cycles produced every beat - Frequenz: Anzahl der erzeugten Wellenzyklen pro beat + + Restart sequence when a new note is received + Die Sequenz neu starten wenn eine neue Note empfangen wird - &Resolution (events/beat) - &Auflösung (Signale/Takt) + + &Trigger + - Resolution: Number of events produced every beat - Auflösung: Anzahl der pro Takt erzeugten MIDI Signale + + Retrigger sequence when a new note is received + Die Sequenz mit dem timing der empfangenen Noten starten (triggern) - &Length (beats) - Län&ge (Takte) + &Loop + &Schleife - - Right button to mute points -Left button to draw custom wave -Wheel to change offset - Rechte Maustaste: Stummschalten einzelner Punkte -Linke Maustaste: Zeichnen der Wellenform -Mausrad: Verschieben des Offsets + Play sequence as loop instead of a single run + Die Sequenz ständig wiederholen anstatt sie nur einmal zu spielen - + &Frequency &Frequenz - + Frequency (cycles/beat): Number of wave cycles produced every beat Frequenz (Zyklen pro beat): Anzahl der erzeugten Wellenzyklen pro Vierteltakt - + &Resolution &Auflösung - + Resolution (events/beat): Number of events produced every beat Auflösung (Signale/beat): Anzahl der pro Vierteltakt erzeugten MIDI Signale - + &Length &Dauer - + Length of LFO wave in beats Länge der LFO Wellenform in Vierteltakten - &Copy to custom wave - &In die freie Wellenform kopieren + + Loop, bounce or play once going forward or backward + Wiederholen, hin- und zurück oder nur einmal spielen, vorwärts oder rückwärts - - + + Re&cord &Aufnahme - + Record incoming controller Eingehenden MIDI controller aufzeichnen - + &Amplitude Am&plitude - + &Offset &Offset - + Sine Sinus - + Saw up Sägezahn auf - + Triangle Dreieck - + Saw down Sägezahn ab - + Square Rechteck - + Custom Frei - Delete "%1"? - "%1" löschen? - - - New Name - Neuer Name - - - &MIDI CC# - &MIDI CC# - - - + &Waveform &Wellenform @@ -535,42 +432,42 @@ LogWidget - + &Enable Log &Protokollieren - + Log &MIDI Clock &MIDI Clock aufzeichnen - + &Clear &Löschen - - MIDI Clock - MIDI Clock + + MIDI Clock, tick + - + MIDI Start (Transport) MIDI Clock Start (Transport) - + MIDI Continue (Transport) MIDI Continue (Transport) - + MIDI Stop (Transport) MIDI Stop (Transport) - + Unknown event type Unbekanntes MIDI-Signal @@ -578,380 +475,326 @@ MainWindow - + Event Log Protokoll - Settings - Einstellungen - - - + Groove Groove - + &New LFO... &Neuer LFO... - + &New Sequencer... &Neuer Sequenzer... - + Ctrl+T Module|New Sequencer Strg+T - + Add new Sequencer to tab bar Neuen Sequenzer hinzufügen - &Rename... - &Umbenennen... - - - Rename this module - Dieses Modul umbenennen - - - &Delete... - &Löschen... - - - Delete this module - Dieses Modul löschen - - - + &New &Neu - + Create new arpeggiator file Neue Arpeggiator-Zusammenstellung erzeugen - + &Open... &Öffnen... - + &Save &Speichern - + Save current arpeggiator file Aktuelle Arpeggiator-Zusammenstellung speichern - + Save &as... Speichern &unter... - + Save current arpeggiator file with new name Aktuelle Arpeggiator-Zusammenstellung unter neuem Namen speichern - + &Quit &Beenden - + Ctrl+Q File|Quit Strg+Q - + Quit application Die Anwendung beenden - + &Run with internal clock &Start/Stop mit interner Uhr - + &Connect to Jack Transport Mit &Jack Transport verbinden - + Ctrl+H View|Event Log Strg+H - + &Groove Settings &Groove - + Ctrl+G View|Groove Strg+G - + Mod&ule Mod&ul - + &Recently opened files &Zuletzt geöffnete Dateien - + &MIDI Controllers... &MIDI-Steuerungen... - + &File Toolbar &Dateien Werkzeugleiste - + &Control Toolbar &Steuerungsleiste - - - + + + %1 - + Add MIDI LFO MIDI LFO hinzufügen - + Add Step Sequencer Sequenzer hinzufügen - + QMidiArp XML files QMidiArp XML Dateien - Old QMidiArp files - Alte QMidiArp Textdateien + Alte QMidiArp Textdateien - - + Could not read from file '%1'. Konnte die Datei '%1' nicht lesen. - + This is not a valid xml file for Dies ist keine gültige xml Datei für - The QMidiArp text file was imported. If you save this file, it will be saved using the newer xml format under the name '%1'. - Die QMidiArp Textdatei wurde importiert. Beim nächsten Speichern wird diese im neueren xml Format gespeichert unter dem Namen + Die QMidiArp Textdatei wurde importiert. Beim nächsten Speichern wird diese im neueren xml Format gespeichert unter dem Namen '%1'. - + Could not write to file '%1'. Konnte in die Datei '%1' nicht schreiben. - + Unnamed file was changed. Save changes? Die unbenannte Datei wurde verändert. Die Änderungen speichern? - + File '%1' was changed. Save changes? Die Datei '%1' wurde verändert. Die Änderungen speichern? - + Save changes Änderungen speichern - + Could not read from resource file Konnte Ressourcendatei nicht einlesen - &Run - &Start - - - + &Use incoming MIDI Clock &Eingehendes MIDI Clock Signal nutzen - + &Event Log &Protokoll - Ctrl+L - View|Event Log - Strg+L - - - + &Settings &Einstellungen - + Ctrl+P View|Settings Strg+P - + &About Qt... &Über Qt... - + About %1 Über %1 - + About Qt Über Qt - + Add MIDI Arpeggiator MIDI-Arpeggiator hinzufügen - New Name - Neuer Name - - - Remove "%1"? - "%1" löschen? - - - - + + Open arpeggiator file Arpeggiator-Datei öffnen - + Tempo of internal clock Tempo der internen Uhr - + Not a QMidiArp xml file. Keine QMidiArp xml Datei. - + Save arpeggiator Arpeggiator Speichern - + QMidiArp files QMidiArp Dateien - + Could not write to resource file Konnte Ressourcendatei nicht speichern - + &New Arp... &Neuer Arp... - + Add new arpeggiator to tab bar Neuen Arpeggiator hinzufügen - + Add new LFO to tab bar Neuen LFO hinzufügen - + Ctrl+A Module|New Arp Strg+A - + Ctrl+L Module|New LFO Strg+L - Ctrl+R - Module|Rename - Strg+R - - - Ctrl+Del - Module|Delete - Strg+Del - - - + &File &Datei - + &View &Ansicht - &Module - &Modul - - - + &Help &Hilfe - + &About %1... &Über %1... @@ -1088,328 +931,231 @@ Settings - Einstellungen - - - &Modules mutable by MIDI controller starting at CC# - &Module stummschaltbar durch MIDI controller beginnend mit CC# - - - &Arps mutable by MIDI CC starting at CC# - &Arps stummschaltbar durch MIDI CC beginnend mit CC# - - - Incoming MIDI &Clock rate (tpb) - Kadenz der eingehenden MIDI &Clock (tpb) - SeqWidget - + Transpose the sequence following incoming notes Die Sequenz durch eingehende Note transponieren - + Output Ausgang - + &Mute &Stumm - MIDI &Learn - &Lerne von MIDI - - - Cancel MIDI &Learning - MIDI-Lernen &Abbrechen - - - Duplicate this Sequencer in muted state - Diesen Sequenzer in stummem Zustand duplizieren - - Display Ansicht - &Full - &Voll + &Voll - &Upper - &Oben + &Oben - &Mid - &Mitte + &Mitte - &Lower - &Unten + &Unten - + &Note Off - + Stop output when Note is released Keine Noten senden wenn die Taste losgelassen wird - + &Restart &Neustarten - + Restart sequence when a new note is received Die Sequenz neu starten wenn eine neue Note empfangen wird - + &Trigger - + Retrigger sequence when a new note is received Die Sequenz mit dem timing der empfangenen Noten starten (triggern) - &Loop - &Schleife + &Schleife - Play sequence as loop instead of a single run - Die Sequenz ständig wiederholen anstatt sie nur einmal zu spielen - - - MIDI &Forget - MIDI-Steuerungen &vergessen + Die Sequenz ständig wiederholen anstatt sie nur einmal zu spielen - + Sequence Sequenz - + &Sequence &Sequenz - + Preset Number Preset Index - - + + Re&cord &Aufnahme - + Record step by step Eingehende Noten Schritt für Schritt aufnehmen - + Resolution (notes/beat): Number of notes produced every beat Auflösung (Noten/Beat): Zahl der in jedem Vierteltakt gespielten Noten - + Length of Sequence in beats Länge der Sequenz in Vierteltakten - C&opy to new wave - In neue Wellenform &kopieren - - - + Veloc&ity An&schlag - Delete "%1"? - "%1" löschen? - - - New Name - Neuer Name + + N&ote Length + N&otenlänge - &Copy to new wave - In neue Wellenform &kopieren + + &Velocity + &Anschlag - Velo&city - An&schlag + + &F + &V - - N&ote Length - N&otenlänge + + &U + &O - - &Velocity - &Anschlag + + &M + &M - &Clone... - &Duplizieren... + + &L + &U - &Rename... - &Umbenennen... + + Full + Voll - Rename this Sequencer - Diesen Sequenzer umbenennen + + Upper + Oben - &Delete... - &Löschen... + + Mid + Mitte - Delete this Sequencer - Diesen Sequenzer löschen + + Lower + Unten - + Input Eingang - + &Note &Note - + Set sequence velocity to that of incoming notes Anschlag der Sequenz folgt dem der eingehende Noten - + &Channel &Kanal - &Note Length - &Notenlänge + + Loop, bounce or play once going forward or backward + Wiederholen, hin- und zurück oder nur einmal spielen, vorwärts oder rückwärts - + &Transpose &Transponieren - &MIDI CC# - &MIDI CC# - - - MIDI Controller number sent to output - Nummer des gesendeten MIDI Controllers - - - + &Port Anschl&uß - + C&hannel Ka&nal - Wave - Welle - - - + Right button to mute points, left button to draw custom wave Rechte Maustaste: Stummschalten einzelner Punkte, linke Maustaste: Zeichnen der Wellenform - &Waveform - &Wellenform - - - Waveform Basis - Wellenformbasis - - - &Frequency - &Frequenz - - - Frequency (cycles/beat): Number of wave cycles produced every beat - Frequenz (Zyklen pro beat): Anzahl der erzeugten Wellenzyklen pro Vierteltakt - - - + &Resolution &Auflösung - Resolution (events/beat): Number of events produced every beat - Auflösung (Signale/beat): Anzahl der pro Vierteltakt erzeugten MIDI Signale - - - + &Length &Dauer - &Copy to custom wave - &In die freie Wellenform kopieren - - - &Amplitude - Am&plitude - - - &Offset - &Offset - - - Sine - Sinus - - - Saw up - Sägezahn auf - - - Triangle - Dreieck - - - Saw down - Sägezahn ab - - - Square - Rechteck - - - + Custom Frei diff -Nru qmidiarp-0.4.2/src/translations/qmidiarp_es.ts qmidiarp-0.4.5/src/translations/qmidiarp_es.ts --- qmidiarp-0.4.2/src/translations/qmidiarp_es.ts 2011-07-09 21:19:38.000000000 +0000 +++ qmidiarp-0.4.5/src/translations/qmidiarp_es.ts 2012-01-21 17:29:21.000000000 +0000 @@ -4,22 +4,6 @@ ArpWidget - &Rename... - &Renombrar... - - - Rename this Arp - Renombrar este arpegiador - - - &Delete... - &Borrar... - - - Delete this Arp - Borrar este arpegiador - - Input Entrada @@ -56,18 +40,6 @@ &Silenciar - MIDI &Learn - &Aprendizaje MIDI - - - Cancel MIDI &Learning - &Cancelar aprendizaje MIDI - - - MIDI &Forget - &Olvidar MIDI - - &Port &Puerto @@ -166,7 +138,7 @@ - + Random Al azar @@ -187,19 +159,19 @@ - + Envelope Envoltura - &Attack (s) - &Ataque (s) + &Attack (beats) + &Ataque (beats) - &Release (s) - &Liberación (es) + &Release (beats) + &Liberación (beats) @@ -207,48 +179,40 @@ Filtro de notas - ACTIVO - + Could not read from resource file No se ha podido leer el archivo de recursos - + Random - ACTIVE Aleatorización - ACTIVADA - + Envelope - ACTIVE Envoltura - ACTIVADA - + %1: Store pattern %1: Guardar patrón - + New pattern Nuevo patrón - + Arp pattern Patrón de Arp - + Remove "%1"? ¿Borrar "%1"? - - Delete "%1"? - ¿Eliminar "%1"? - - - New Name - Nuevo nombre - GrooveWidget @@ -271,86 +235,96 @@ LfoWidget - &Rename... - &Renombrar... + + Output + Salida - Rename this LFO - Renombrar este LFO + + &Mute + &Silenciar - &Delete... - &Borrar... + + + MIDI &CC# + MIDI &CC# - Delete this LFO - Borrar este LFO + + Input + Entrada - - Output - Salida + + &Note Off + Desconectar &Nota - - &Mute - &Silenciar + + Stop output when Note is released + Parar la salida cuando la nota sea liberada - Cancel MIDI &Learning - &Cancelar aprendizaje MIDI + + &Restart + &Reinicio - MIDI &Learn - &Aprendizaje MIDI + + Restart sequence when a new note is received + Reiniciar la secuencia cuando una nueva nota sea recibida - MIDI &Forget - &Olvidar MIDI + + &Trigger + &Disparador - - - MIDI &CC# - MIDI &CC# + + Retrigger sequence when a new note is received + Volver a disparar la secuencia cuando una nueva nota sea recibida - - Input - Entrada + &Loop + &Bucle - + Play sequence as loop instead of a single run + Reproducir la secuencia en bucle en lugar de una vez + + + MIDI Controller number to record Número de controlador MIDI a grabar - + &Channel &Canal - + MIDI Controller number sent to output Número de controlador MIDI enviado a la salida - + &Port &Puerto - + C&hannel &Canal - + Wave Onda - + Right button to mute points Left button to draw custom wave Wheel to change offset @@ -359,144 +333,141 @@ Rueda para cambiar desplazamiento - + &Waveform &Forma de onda - + Waveform Basis Forma de onda base - + &Frequency &Frecuencia - + Frequency (cycles/beat): Number of wave cycles produced every beat Frecuencia (ciclos/tiempo): Numero de ciclos de onda producidos en cada tiempo - + &Resolution &Resolución - + Resolution (events/beat): Number of events produced every beat Resolución (eventos/tiempo): Número de eventos producidos por cada tiempo - + &Length &Longitud - + Length of LFO wave in beats Longitud de la onda LFO en tiempos - - + + Loop, bounce or play once going forward or backward + + + + + Re&cord &Grabar - + Record incoming controller Grabar controlador entrante - + &Amplitude &Amplitud - + &Offset &Desplazamiento - + Sine Seno - + Saw up Sierra hacia arriba - + Triangle Triángulo - + Saw down Sierra hacia abajo - + Square Cuadrado - + Custom Personalizado - - Delete "%1"? - ¿Eliminar "%1"? - - - New Name - Nuevo nombre - LogWidget - + &Enable Log &Habilitar registro - + Log &MIDI Clock Registrar reloj &MIDI - + &Clear &Limpiar - - MIDI Clock - Reloj MIDI + + MIDI Clock, tick + Reloj MIDI, tick - + MIDI Start (Transport) MIDI Iniciar (transporte) - + MIDI Continue (Transport) MIDI Continuar (transporte) - + MIDI Stop (Transport) MIDI Parar (transporte) - + Unknown event type Tipo de evento desconocido @@ -504,327 +475,324 @@ MainWindow - + Event Log Registro de eventos - + Groove Groove - + &New Arp... &Nuevo Arp... - + Ctrl+A Module|New Arp Ctrl+A - + Add new arpeggiator to tab bar Añadir nuevo arpegiador a la barra de pestañas - + &New LFO... &Nuevo LFO... - + Ctrl+L Module|New LFO Ctrl+L - + Add new LFO to tab bar Añadir nuevo LFO a la barra de pestañas - + &New Sequencer... &Nuevo secuenciador... - + Ctrl+T Module|New Sequencer Ctrl+T - + Add new Sequencer to tab bar Añadir nuevo secuenciador a la barra de pestañas - + &New &Nuevo - + Create new arpeggiator file Crear nuevo archivo de arpegiador - + &Open... &Abrir... - - + + Open arpeggiator file Abrir archivo de arpegiador - + &Save &Guardar - + Save current arpeggiator file Guardar archivo de arpegiador actual - + Save &as... Guardar &como... - + Save current arpeggiator file with new name Guardar archivo de arpegiador actual con un nuevo nombre - + &Quit &Terminar - + Ctrl+Q File|Quit Ctrl+Q - + Quit application Terminar la aplicación - + &Run with internal clock &Ejecutar con reloj interno - + Tempo of internal clock Tempo del reloj interno - + &Use incoming MIDI Clock &Utlizar recepción de reloj MIDI - + &Connect to Jack Transport &Conectar con el transporte de Jack - + &Event Log &Registro de eventos - + Ctrl+H View|Event Log Ctrl+H - + &Groove Settings Preferencias de &Groove - + Ctrl+G View|Groove Ctrl+G - + &Settings &Preferencias - + Ctrl+P View|Settings Ctrl+P - + &File &Archivo - + &View &Vista - + Mod&ule &Módulo - + &Help A&yuda - + &Recently opened files Archivos abiertos &recientemente - + &MIDI Controllers... Controladores &MIDI... - + &About %1... &Acerca de %1... - + &About Qt... Acerca de &Qt... - + &File Toolbar Barra de herramientas de &archivo - + &Control Toolbar Barra de herramientas de &Control - + About %1 Acerca de %1 - + About Qt Acerca de Qt - + Add MIDI Arpeggiator Añadir arpegiador MIDI - - - + + + %1 %1 - + Add MIDI LFO Añadir LFO MIDI - + Add Step Sequencer Añadir secuenciador de pasos - + QMidiArp XML files Archivos XML de QMidiArp - Old QMidiArp files - Archivos antiguos de QMidiArp + Archivos antiguos de QMidiArp - - + Could not read from file '%1'. No se ha podido leer el archivo '%1'. - + Not a QMidiArp xml file. No es un archivo XML de QMidiArp. - + This is not a valid xml file for Este no es un archivo XML válido para - The QMidiArp text file was imported. If you save this file, it will be saved using the newer xml format under the name '%1'. - El archivo de texto de QMidiArp ha sido importado. Si se guarda este archivo, será almacenado utilizando el nuevo formato XML bajo el nombre + El archivo de texto de QMidiArp ha sido importado. Si se guarda este archivo, será almacenado utilizando el nuevo formato XML bajo el nombre '%1'. - + Could not write to file '%1'. No se ha podido grabar el archivo '%1'. - + Save arpeggiator Guardar arpegiador - + QMidiArp files Archivos de QMidiArp - + Unnamed file was changed. Save changes? El archivo sin nombre ha cambiado. ¿Guardarlo? - + File '%1' was changed. Save changes? Archivo '%1' ha cambiado. ¿Guardarlo? - + Save changes Guardar cambios - + Could not read from resource file No se ha podido leer el archivo de recursos - + Could not write to resource file No se ha podido guardar el archivo de recursos @@ -965,230 +933,229 @@ SeqWidget - &Rename... - &Renombrar... - - - Rename this Sequencer - Renombrar este secuenciador - - - &Delete... - &Borrar... - - - Delete this Sequencer - Borrar este secuenciador - - - + Input Entrada - + &Note &Nota - + Transpose the sequence following incoming notes Transportar la secuencia siguiendo las notas siguientes - + &Velocity &Velocidad - + Set sequence velocity to that of incoming notes Establecer la velocidad de la secuencia igual a las notas recibidas - + &Channel &Canal - + Output Salida - + &Mute &Silenciar - Cancel MIDI &Learning - &Cancelar aprendizaje MIDI - - Display Mostrar - &Full - &Todo + &Todo - &Upper - &Superior + &Superior - &Mid - &Medio + &Medio - &Lower - &Inferior + &Inferior - + &Note Off Desconectar &Nota - + Stop output when Note is released Parar la salida cuando la nota sea liberada - + &Restart &Reinicio - + Restart sequence when a new note is received Reiniciar la secuencia cuando una nueva nota sea recibida - + &Trigger &Disparador - + Retrigger sequence when a new note is received Volver a disparar la secuencia cuando una nueva nota sea recibida - &Loop - &Bucle + &Bucle - Play sequence as loop instead of a single run - Reproducir la secuencia en bucle en lugar de una vez + Reproducir la secuencia en bucle en lugar de una vez - MIDI &Learn - &Aprendizaje MIDI + + &F + &T - MIDI &Forget - &Olvidar MIDI + + &U + &S + + + + &M + &M - + + &L + &I + + + + Full + Todo + + + + Upper + Superior + + + + Mid + Medio + + + + Lower + Inferior + + + &Port &Puerto - + C&hannel &Canal - + Sequence Secuencia - + Right button to mute points, left button to draw custom wave Botón derecho para silenciar puntos, botón izquierdo para dibujar onda personalizada - + &Sequence &Secuencia - + Preset Number Número de patrón - - + + Loop, bounce or play once going forward or backward + + + + + Re&cord &Grabar - + Record step by step Grabar paso a paso - + &Resolution &Resolución - + Resolution (notes/beat): Number of notes produced every beat Resolución (notas/tiempo): número de notas producidas por cada tiempo - + &Length &Longitud - + Length of Sequence in beats Longitud de la secuencia en tiempos - C&opy to new wave - C&opiar a nueva onda - - - + Veloc&ity &Velocidad - + N&ote Length &Longitud de nota - + &Transpose &Transportar - + Custom Personalizado - - Delete "%1"? - ¿Eliminar "%1"? - - - New Name - Nuevo nombre - diff -Nru qmidiarp-0.4.2/src/translations/qmidiarp_fr.ts qmidiarp-0.4.5/src/translations/qmidiarp_fr.ts --- qmidiarp-0.4.2/src/translations/qmidiarp_fr.ts 2011-07-09 15:48:25.000000000 +0000 +++ qmidiarp-0.4.5/src/translations/qmidiarp_fr.ts 2012-01-21 17:29:22.000000000 +0000 @@ -49,38 +49,8 @@ Preset de motif - Arp through chord - Arpège dans l'accord - - - 0..9 note played on keyboard, ascending order -( ) chord mode on/off - + - octave up/down - < . > tempo up/reset/down - d h note length up/down - / \ velocity up/down - p pause - 0..9 note joué sur le clavier, ordre ascendant -( ) mode accord act/désact -+ - octave sup/inf -< ; > accel/décel -d h durée de note augm/dim -/ \ vél augm/dim - p pause - - - - &Attack (s) - - - - - &Release (s) - - - - + Random Randomisation @@ -111,46 +81,42 @@ - + Envelope Enveloppe - Could not write to resource file - Erreur d'écriture du fichier ressources - - - + Could not read from resource file Erreur de lecture du fichier ressources - + Random - ACTIVE Randomisation - ACTIVE - + Envelope - ACTIVE Enveloppe - ACTIVE - + %1: Store pattern %1: Mémoriser le motif - + New pattern Nouveau motif - + Arp pattern Motif d'arpège - + Remove "%1"? Supprimer "%1"? @@ -160,22 +126,6 @@ &Canal - &Rename... - &Renommer... - - - Rename this Arp - Renommer cet arpégiateur - - - &Delete... - &Supprimer... - - - Delete this Arp - Supprimer cet arpégiateur - - Note Filter @@ -192,18 +142,6 @@ &Muet - MIDI &Learn - &Apprendre du MIDI - - - Cancel MIDI &Learning - &Annuler l'apprentissage - - - MIDI &Forget - &Oublier les contrôleurs MIDI - - C&hannel C&anal @@ -261,17 +199,19 @@ p pause - - Note Filter - ACTIVE - Filtre - AKTIF + + &Attack (beats) + - Delete "%1"? - Supprimer "%1"? + + &Release (beats) + - New Name - Nouveau nom + + Note Filter - ACTIVE + Filtre - AKTIF @@ -295,272 +235,239 @@ LfoWidget - + Output Sortie - + &Mute &Muet - - + + MIDI &CC# - + MIDI Controller number sent to output Numéro du contrôleur envoyé à la sortie - + C&hannel C&anal - + &Port - &Clone... - &Dupliquer... - - - Duplicate this LFO in muted state - Dupliquer ce LFO en état muet - - - &Rename... - &Renommer... - - - Rename this LFO - Renommer ce LFO - - - &Delete... - &Supprimer... - - - Delete this LFO - Supprimer ce LFO - - Input Entrée - + MIDI Controller number to record Le numéro du contrôleur MIDI à enregistrer - + &Channel &Canal - MIDI &Learn - &Apprendre du MIDI - - - Cancel MIDI &Learning - &Annuler l'apprentissage - - - MIDI &Forget - &Oublier les contrôleurs MIDI - - - + Wave Forme - Right button to mute points, left button to draw custom wave - Bouton droit de la souris pour rendre muet chaque point, bouton gauche pour dessiner la forme d'onde - - - + &Waveform Forme d'&onde - + Waveform Basis Base de la forme d'onde - &Frequency (cycles/beat) - Fré&quence (cycles/beat) + + Right button to mute points +Left button to draw custom wave +Wheel to change offset + Bouton droit de la souris pour rendre muet chaque point +Bouton gauche pour dessiner la forme d'onde +Molette pour changer l'offset + + + + &Note Off + + + + + Stop output when Note is released + Arrêter l'envoi de notes quand la touche est relâchée + + + + &Restart + &Redémarre - Frequency: Number of wave cycles produced every beat - Fréquence: Nombre de cycles d'onde produits à chaque quart de temps + + Restart sequence when a new note is received + Redémarrer la séquence au départ quand une nouvelle note est reçue - &Resolution (events/beat) - &Résolution (points/beat) + + &Trigger + - Resolution: Number of events produced every beat - Résolution: Nomber d'évênements produits à chaque quart de temps + + Retrigger sequence when a new note is received + Déclencher la séquence avec le timing des notes reçues - &Length (beats) - &Longueur (beats) + &Loop + &Boucle - - Right button to mute points -Left button to draw custom wave -Wheel to change offset - Bouton droit de la souris pour rendre muet chaque point -Bouton gauche pour dessiner la forme d'onde -Molette pour changer l'offset + Play sequence as loop instead of a single run + Jouer la séquence en boucle au lieu d'un passage unique - + &Frequency &Fréquence - + Frequency (cycles/beat): Number of wave cycles produced every beat Fréquence (cycles/beat): Nombre de cycles d'onde produits à chaque quart de temps - + &Resolution &Résolution - + Resolution (events/beat): Number of events produced every beat Résolution (év/beat): Nombre d'évênements produits à chaque quart de temps - + &Length &Durée - + Length of LFO wave in beats Longueur de la forme d'onde du LFO en quarts de temps (beats) - &Copy to custom wave - &Copier dans la forme d'onde libre + + Loop, bounce or play once going forward or backward + Répéter, jouer aller-retour ou jouer une seule fois, avant ou arrière - - + + Re&cord &Enregistrer - + Record incoming controller Enregistrer les évênements contrôleurs reçus à l'entrée - + &Amplitude - + &Offset &Décalage - + Sine Sinus - + Saw up Scie montant - + Triangle - + Saw down Scie descendant - + Square Créneau - + Custom Libre - - Delete "%1"? - Supprimer "%1"? - - - New Name - Nouveau nom - - - &MIDI CC# - &MIDI CC# - LogWidget - + &Enable Log &Activer le journal - + Log &MIDI Clock Rapporter l'horologe &MIDI - + &Clear &Vider - - MIDI Clock + + MIDI Clock, tick - + MIDI Start (Transport) - + MIDI Continue (Transport) - + MIDI Stop (Transport) - + Unknown event type Evênement inconnu @@ -568,361 +475,326 @@ MainWindow - + Event Log Journal - Settings - Paramètres - - - + Groove Groove - + &New LFO... &Nouveau LFO... - + &New Sequencer... &Nouveau Séquenceur... - + Ctrl+T Module|New Sequencer Ctrl+T - + Add new Sequencer to tab bar Ajouter un nouveau séquenceur - &Rename... - &Renommer... - - - Rename this module - Renommer ce module - - - &Delete... - &Supprimer... - - - Delete this module - Supprimer ce module - - - + &New &Nouveau - + Create new arpeggiator file Créer un nouveau fichier d'arpège - + &Open... &Ouvrir... - + &Save &Enregistrer - + Save current arpeggiator file Enregistrer les arpèges actuels dans un fichier - + Save &as... Enregistrer &sous... - + Save current arpeggiator file with new name Enregistrer les arpèges actuels avec un nouveau nom - + &Quit &Quitter - + Ctrl+Q File|Quit - + Quit application Quitter l'application - + &Run with internal clock &Start/Stop avec horologe interne - + &Connect to Jack Transport Connecter à &Jack Transport - + Ctrl+H View|Event Log Ctrl+H - + &Groove Settings &Groove - + Ctrl+G View|Groove - + Mod&ule - + &Recently opened files Fichiers &récemment ouverts - + &MIDI Controllers... &Contrôles MIDI... - + &File Toolbar Barre d'outils &Fichier - + &Control Toolbar &Barre de contrôle - - - + + + %1 - + Add MIDI LFO Ajouter un LFO MIDI - + Add Step Sequencer Ajouter un séquenceur - + QMidiArp XML files Fichiers QMidiArp XML - Old QMidiArp files - Vieux fichiers texte QMidiArp + Vieux fichiers texte QMidiArp - - + Could not read from file '%1'. Erreur lors de la lecture du fichier '%1'. - + This is not a valid xml file for Ceci n'est pas un fichier xml valide pour - The QMidiArp text file was imported. If you save this file, it will be saved using the newer xml format under the name '%1'. - Le fichier texte QMidiArp a été importé. A la prochaine sauvegarde, il sera écrit au format xml actuel sous le nom + Le fichier texte QMidiArp a été importé. A la prochaine sauvegarde, il sera écrit au format xml actuel sous le nom '%1'. - + Could not write to file '%1'. Erreur lors de l'écriture du fichier '%1'. - + Unnamed file was changed. Save changes? Le fichier sans nom a été modifié. Enregistrer les modifications? - + File '%1' was changed. Save changes? Le fichier '%1' a été modifié. Enregistrer les modifications? - + Save changes Enregistrer les modifications - + Could not read from resource file Erreur de lecture du fichier ressources - + &New Arp... &Nouvel Arpège... - &Run - &Start/Stop - - - + &Use incoming MIDI Clock &Utiliser MIDI Clock entrant - + &Event Log &Journal - + &Settings &Paramètres - + Ctrl+P View|Settings - + &About Qt... &A propos de Qt... - + About %1 A propos de %1 - + About Qt A propos de Qt - + Add MIDI Arpeggiator Ajouter un arpège MIDI - New Name - Nouveau nom - - - Remove "%1"? - Supprimer "%1"? - - - - + + Open arpeggiator file Ouvrir un fichier arpège - + Not a QMidiArp xml file. Pas un fichier xml QMidiArp. - + Save arpeggiator Enregistrer l'arpège - + QMidiArp files Fichiers QMidiArp - + Could not write to resource file Erreur d'écriture du fichier ressources - + Add new arpeggiator to tab bar Ajouter un nouvel arpège à la barre d'onglets - + Add new LFO to tab bar Ajouter un nouveau LFO à la barre d'onglets - + Ctrl+A Module|New Arp - + Ctrl+L Module|New LFO - + Tempo of internal clock Tempo de l'horologe interne - + &File &Fichier - + &View &Affichage - + &Help &Aide - + &About %1... &A propos de %1... @@ -1059,320 +931,231 @@ Settings - Paramètres - - - &Modules mutable by MIDI controller starting at CC# - &Rendre les modules &muets par contrôleur MIDI commençant par CC# - - - &Arps mutable by MIDI CC starting at CC# - &Rendre les arpèges muet par CC MIDI commençant par CC# - - - Incoming MIDI &Clock rate (tpb) - Cadence MIDI &Clock entrant (tbp) - SeqWidget - + Transpose the sequence following incoming notes Transposer la séquence suivant les notes entrants - + Output Sortie - + &Mute M&uet - MIDI &Learn - &Apprendre du MIDI - - - Cancel MIDI &Learning - &Annuler l'apprentissage - - - Duplicate this Sequencer in muted state - Dupliquer ce séquenceur en état muet - - Display Affichage - &Full - &Plein + &Plein - &Upper - &Haut + &Haut - &Mid - &Milieu + &Milieu - &Lower - &Bas + &Bas - + &Note Off - + Stop output when Note is released Arrêter l'envoi de notes quand la touche est relâchée - + &Restart &Redémarre - + Restart sequence when a new note is received Redémarrer la séquence au départ quand une nouvelle note est reçue - + &Trigger - + Retrigger sequence when a new note is received Déclencher la séquence avec le timing des notes reçues - &Loop - &Boucle + &Boucle - Play sequence as loop instead of a single run - Jouer la séquence en boucle au lieu d'un passage unique - - - MIDI &Forget - &Oublier les contrôleurs MIDI + Jouer la séquence en boucle au lieu d'un passage unique - + Sequence Séquence - + &Sequence &Séquence - + Preset Number Index Preset - - + + Re&cord &Enregistrer - + Record step by step Enregistrer pas à pas les notes de l'entrée - + Resolution (notes/beat): Number of notes produced every beat Résolution (notes/beat): Nombre de notes produites à chaque quart de mesure - + Length of Sequence in beats Durée de la séquence en quarts de mesure - C&opy to new wave - C&opier dans la forme d'onde libre - - - + Veloc&ity Véloc&ité - Delete "%1"? - Supprimer "%1"? - - - New Name - Nouveau nom + + N&ote Length + Du&rée des Notes - &Copy to new wave - &Copier dans une nouvelle forme d'onde + + &Velocity + &Vélocité - Velo&city - Vélo&cité + + &F + &P - - N&ote Length - Du&rée des Notes + + &U + &H - - &Velocity - &Vélocité + + &M + &M - &Clone... - &Dupliquer... + + &L + &B - &Rename... - &Renommer... + + Full + Plein - Rename this Sequencer - Renommer ce séquenceur + + Upper + Haut - &Delete... - &Supprimer... + + Mid + Milieu - Delete this Sequencer - Supprimer ce séquenceur + + Lower + Bas - + Input Entrée - + &Note &Note - + Set sequence velocity to that of incoming notes La vélocité de la séquence suit celle des notes à l'entrée - + &Channel &Canal - &Note Length - &Durée des notes + + Loop, bounce or play once going forward or backward + Répéter, jouer aller-retour ou jouer une seule fois, avant ou arrière - + &Transpose &Transposer - &MIDI CC# - &MIDI CC# - - - MIDI Controller number sent to output - Numéro du contrôleur envoyé à la sortie - - - + &Port - + C&hannel Cana&l - Wave - Forme - - - + Right button to mute points, left button to draw custom wave Bouton droit de la souris pour rendre muet chaque point, bouton gauche pour dessiner la forme d'onde - &Waveform - Forme d'&onde - - - Waveform Basis - Base de la forme d'onde - - - &Frequency - &Fréquence - - - Frequency (cycles/beat): Number of wave cycles produced every beat - Fréquence (cycles/beat): Nombre de cycles d'onde produits à chaque quart de temps - - - + &Resolution &Résolution - Resolution (events/beat): Number of events produced every beat - Résolution (év/beat): Nombre d'évênements produits à chaque quart de temps - - - + &Length &Durée - &Copy to custom wave - &Copier dans la forme d'onde libre - - - &Offset - &Décalage - - - Sine - Sinus - - - Saw up - Scie montant - - - Saw down - Scie descendant - - - Square - Créneau - - - + Custom Libre