aboutsummaryrefslogtreecommitdiff
path: root/chuck
diff options
context:
space:
mode:
Diffstat (limited to 'chuck')
-rw-r--r--chuck/Makefile41
-rw-r--r--chuck/patches/0001-correctly-handle-debug-flags-if-CHUCK_DEBUG-y-build-.patch158
-rw-r--r--chuck/patches/0002-added-.gitignore.patch27
-rw-r--r--chuck/patches/0003-allow-opening-arbitrary-numbers-of-output-input-chan.patch91
-rw-r--r--chuck/patches/0004-install-chuck-headers-for-building-Chugins.patch25
-rw-r--r--chuck/patches/0005-allow-declaring-string-references.patch27
-rw-r--r--chuck/patches/0006-when-comparing-types-consider-arrays-of-the-same-dep.patch32
-rw-r--r--chuck/patches/0007-prevent-unused-return-value-warning.patch35
-rw-r--r--chuck/patches/0008-ensure-that-chuck-is-linked-against-manually-built-l.patch25
-rw-r--r--chuck/patches/0009-revised-LiSa-performing-various-optimizations-and-fi.patch308
-rw-r--r--chuck/patches/0010-LiSa-fixes-new-features-and-clean-up.patch1073
-rw-r--r--chuck/patches/0011-use-mono-LiSa-only-for-my-setup-no-need-to-submit-pa.patch25
-rw-r--r--chuck/patches/0012-allow-unary-minus-on-durations.patch43
-rw-r--r--chuck/patches/0013-crosscompile.patch35
14 files changed, 1945 insertions, 0 deletions
diff --git a/chuck/Makefile b/chuck/Makefile
new file mode 100644
index 0000000..bd1993d
--- /dev/null
+++ b/chuck/Makefile
@@ -0,0 +1,41 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=chuck
+PKG_VERSION:=1.3.1.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=chuck-$(PKG_VERSION).tgz
+PKG_SOURCE_URL:=http://chuck.cs.princeton.edu/release/files
+PKG_MD5SUM:=fb8e0c9f06a51dbec168982497bd2b07
+
+PKG_BUILD_DIR=$(BUILD_DIR)/chuck-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/chuck
+ SECTION:=lang
+ CATEGORY:=Languages
+ DEPENDS:= +alsa-lib +libsndfile +libpthread
+ TITLE:=ChucK Programming Language
+ URL:=http://http://chuck.cs.princeton.edu/
+endef
+
+define Package/chuck/description
+ChucK Programming Language
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+ $(CONFIGURE_VARS) \
+ $(MAKE) -C $(PKG_BUILD_DIR)/src \
+ linux-alsa
+endef
+
+define Package/chuck/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/chuck $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,chuck))
diff --git a/chuck/patches/0001-correctly-handle-debug-flags-if-CHUCK_DEBUG-y-build-.patch b/chuck/patches/0001-correctly-handle-debug-flags-if-CHUCK_DEBUG-y-build-.patch
new file mode 100644
index 0000000..aab42a7
--- /dev/null
+++ b/chuck/patches/0001-correctly-handle-debug-flags-if-CHUCK_DEBUG-y-build-.patch
@@ -0,0 +1,158 @@
+From 1f8d875b53b36f6f0dd6599d70deea55eb17c19e Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:11:42 +0200
+Subject: [PATCH 01/12] correctly handle debug flags (if CHUCK_DEBUG=y, build with -O0)
+
+did it for all makefiles so it can be submitted as a patch
+ * according to Makefile best-practices, such flags should normally not be touched my the build system but they should instead be
+set by the package maintainer using the CFLAGS environment variable
+---
+ makefile | 2 +-
+ makefile.alsa | 2 +-
+ makefile.audicle | 6 ++++--
+ makefile.jack | 2 +-
+ makefile.oss | 2 +-
+ makefile.rl | 6 ++++--
+ makefile.skot | 2 +-
+ makefile.vicon | 6 ++++--
+ makefile.win32 | 2 +-
+ 9 files changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/src/makefile b/src/makefile
+index 8afb2db..aa87fe9 100644
+--- a/src/makefile
++++ b/src/makefile
+@@ -33,7 +33,7 @@ CFLAGS+= -D__CHUCK_STAT_TRACK__
+ endif
+
+ ifneq ($(CHUCK_DEBUG),)
+-CFLAGS+= -g
++CFLAGS+= -g -O0
+ else
+ CFLAGS+= -O3
+ endif
+diff --git a/src/makefile.alsa b/src/makefile.alsa
+index f267207..f66e3ac 100644
+--- a/src/makefile.alsa
++++ b/src/makefile.alsa
+@@ -1,4 +1,4 @@
+
+-CFLAGS+= -D__LINUX_ALSA__ -O3 -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
++CFLAGS+= -D__LINUX_ALSA__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
+ LDFLAGS+= -lasound -lstdc++ -ldl -lm -lsndfile -lpthread
+
+diff --git a/src/makefile.audicle b/src/makefile.audicle
+index 7e26071..2cbe5cc 100644
+--- a/src/makefile.audicle
++++ b/src/makefile.audicle
+@@ -3,12 +3,14 @@ CXX=gcc
+ LEX=flex
+ YACC=bison
+ INCLUDES=
+-FLAGS=-D__MACOSX_CORE__ -D__CHUCK_STAT_TRACK__ -DAJAY -O3 -c
++FLAGS=-D__MACOSX_CORE__ -D__CHUCK_STAT_TRACK__ -DAJAY -c
+ LIBS=-framework CoreAudio -framework CoreMIDI -framework CoreFoundation -framework Carbon -framework IOKit -lstdc++ -lm
+ SF_OBJ=util_sndfile.o
+
+ ifneq ($(CHUCK_DEBUG),)
+-FLAGS+= -g
++FLAGS+= -g -O0
++else
++FLAGS+= -O3
+ endif
+
+ ifneq ($(CHUCK_STRICT),)
+diff --git a/src/makefile.jack b/src/makefile.jack
+index 464c1b7..e09939a 100644
+--- a/src/makefile.jack
++++ b/src/makefile.jack
+@@ -1,4 +1,4 @@
+
+-CFLAGS+= -D__UNIX_JACK__ -D__LINUX_JACK__ -O3 -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
++CFLAGS+= -D__UNIX_JACK__ -D__LINUX_JACK__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
+ LDFLAGS+= -lasound -ljack -lstdc++ -ldl -lm -lsndfile -lpthread
+
+diff --git a/src/makefile.oss b/src/makefile.oss
+index b25bb3a..f3edf10 100644
+--- a/src/makefile.oss
++++ b/src/makefile.oss
+@@ -1,4 +1,4 @@
+
+-CFLAGS+= -D__LINUX_OSS__ -O3 -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
++CFLAGS+= -D__LINUX_OSS__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
+ LDFLAGS+= -lpthread -lstdc++ -ldl -lm -lsndfile
+
+diff --git a/src/makefile.rl b/src/makefile.rl
+index cc12f75..47bf543 100644
+--- a/src/makefile.rl
++++ b/src/makefile.rl
+@@ -4,7 +4,7 @@ CXX_LINK=g++
+ LEX=flex
+ YACC=bison
+ INCLUDES=
+-FLAGS=-D__MACOSX_CORE__ -D__USE_READLINE__ -O3 -c
++FLAGS=-D__MACOSX_CORE__ -D__USE_READLINE__ -c
+ LIBS=-framework CoreAudio -framework CoreMIDI -framework CoreFoundation -lstdc++ -lm -lreadline
+ SF_OBJ=util_sndfile.o
+
+@@ -13,7 +13,9 @@ FLAGS+= -D__CHUCK_STAT_TRACK__
+ endif
+
+ ifneq ($(CHUCK_DEBUG),)
+-FLAGS+= -g
++FLAGS+= -g -O0
++else
++FLAGS+= -O3
+ endif
+
+ ifneq ($(CHUCK_STRICT),)
+diff --git a/src/makefile.skot b/src/makefile.skot
+index 23ac594..d1b7383 100644
+--- a/src/makefile.skot
++++ b/src/makefile.skot
+@@ -16,7 +16,7 @@ FLAGS+= -D__CHUCK_STAT_TRACK__
+ endif
+
+ ifneq ($(CHUCK_DEBUG),)
+-FLAGS+= -g
++FLAGS+= -g -O0
+ else
+ FLAGS+= -O3
+ endif
+diff --git a/src/makefile.vicon b/src/makefile.vicon
+index cf8bf97..d0b898c 100644
+--- a/src/makefile.vicon
++++ b/src/makefile.vicon
+@@ -3,12 +3,14 @@ CXX=gcc
+ LEX=flex
+ YACC=bison
+ INCLUDES=-I/usr/include/directx/
+-FLAGS=-D__WINDOWS_DS__ -D__WINDOWS_PTHREAD__ -DAJAY $(INCLUDES) -O3 -c
++FLAGS=-D__WINDOWS_DS__ -D__WINDOWS_PTHREAD__ -DAJAY $(INCLUDES) -c
+ LIBS=-ldsound -ldxguid -lwinmm -lstdc++ -lm
+ SF_OBJ=util_sndfile.o
+
+ ifneq ($(CHUCK_DEBUG),)
+-FLAGS+= -g
++FLAGS+= -g -O0
++else
++FLAGS+= -O3
+ endif
+
+ ifneq ($(CHUCK_STRICT),)
+diff --git a/src/makefile.win32 b/src/makefile.win32
+index 148c81f..2f64c5d 100644
+--- a/src/makefile.win32
++++ b/src/makefile.win32
+@@ -10,7 +10,7 @@ LDFLAGS=-ldsound -ldinput -ldxguid -lwinmm -lstdc++ -lm -lole32
+ CSRCS+= util_sndfile.c
+
+ ifneq ($(CHUCK_DEBUG),)
+-CFLAGS+= -g
++CFLAGS+= -g -O0
+ else
+ CFLAGS+= -O3
+ endif
+--
+1.7.1
+
diff --git a/chuck/patches/0002-added-.gitignore.patch b/chuck/patches/0002-added-.gitignore.patch
new file mode 100644
index 0000000..15e833d
--- /dev/null
+++ b/chuck/patches/0002-added-.gitignore.patch
@@ -0,0 +1,27 @@
+From ced8afbafed3688b771a4a773c4a11bb72371a0b Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:14:29 +0200
+Subject: [PATCH 02/12] added .gitignore
+
+---
+ .gitignore | 8 ++++++++
+ 1 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 .gitignore
+
+diff --git a/src/.gitignore b/src/.gitignore
+new file mode 100644
+index 0000000..ffe77af
+--- /dev/null
++++ b/src/.gitignore
+@@ -0,0 +1,8 @@
++*.o
++*.d
++chuck
++
++chuck.output
++chuck.tab.c
++chuck.tab.h
++chuck.yy.c
+--
+1.7.1
+
diff --git a/chuck/patches/0003-allow-opening-arbitrary-numbers-of-output-input-chan.patch b/chuck/patches/0003-allow-opening-arbitrary-numbers-of-output-input-chan.patch
new file mode 100644
index 0000000..101a499
--- /dev/null
+++ b/chuck/patches/0003-allow-opening-arbitrary-numbers-of-output-input-chan.patch
@@ -0,0 +1,91 @@
+From 20d64be2aa8ed346a337a78a68423c4a769c32ea Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:15:52 +0200
+Subject: [PATCH 03/12] allow opening arbitrary numbers of output/input channels (jack backend)
+
+also don't connect them automatically (done by my Jack patchbay)
+---
+ RtAudio/RtAudio.cpp | 6 ++++++
+ digiio_rtaudio.cpp | 4 ++++
+ 2 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/src/RtAudio/RtAudio.cpp b/src/RtAudio/RtAudio.cpp
+index 1dec41b..5aa2b8a 100644
+--- a/src/RtAudio/RtAudio.cpp
++++ b/src/RtAudio/RtAudio.cpp
+@@ -2095,9 +2095,12 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
+
+ // Count the available ports containing the client name as device
+ // channels. Jack "input ports" equal RtAudio output channels.
++#if 0
+ unsigned int nChannels = 0;
++#endif
+ unsigned long flag = JackPortIsInput;
+ if ( mode == INPUT ) flag = JackPortIsOutput;
++#if 0
+ ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
+ if ( ports ) {
+ while ( ports[ nChannels ] ) nChannels++;
+@@ -2110,6 +2113,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
++#endif
+
+ // Check the jack server sample rate.
+ unsigned int jackRate = jack_get_sample_rate( client );
+@@ -2352,6 +2356,7 @@ void RtApiJack :: startStream( void )
+ goto unlock;
+ }
+
++#if 0
+ const char **ports;
+
+ // Get the list of available ports.
+@@ -2400,6 +2405,7 @@ void RtApiJack :: startStream( void )
+ }
+ free(ports);
+ }
++#endif
+
+ handle->drainCounter = 0;
+ handle->internalDrain = false;
+diff --git a/src/digiio_rtaudio.cpp b/src/digiio_rtaudio.cpp
+index d509181..c0bd35c 100644
+--- a/src/digiio_rtaudio.cpp
++++ b/src/digiio_rtaudio.cpp
+@@ -511,6 +511,7 @@ BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
+ {
+ // get the default
+ m_dac_n = m_rtaudio->getDefaultOutputDevice();
++#if 0
+
+ // ensure correct channel count if default device is requested
+ RtAudio::DeviceInfo device_info = m_rtaudio->getDeviceInfo(m_dac_n);
+@@ -538,6 +539,7 @@ BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
+ return m_init = FALSE;
+ }
+ }
++#endif
+ }
+ else
+ {
+@@ -551,6 +553,7 @@ BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
+ if( m_adc_n == 0 )
+ {
+ m_adc_n = m_rtaudio->getDefaultInputDevice();
++#if 0
+
+ // ensure correct channel count if default device is requested
+ RtAudio::DeviceInfo device_info = m_rtaudio->getDeviceInfo(m_adc_n);
+@@ -577,6 +580,7 @@ BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
+ return m_init = FALSE;
+ }
+ }
++#endif
+ }
+ else
+ {
+--
+1.7.1
+
diff --git a/chuck/patches/0004-install-chuck-headers-for-building-Chugins.patch b/chuck/patches/0004-install-chuck-headers-for-building-Chugins.patch
new file mode 100644
index 0000000..69be6f9
--- /dev/null
+++ b/chuck/patches/0004-install-chuck-headers-for-building-Chugins.patch
@@ -0,0 +1,25 @@
+From 58a8dbd6ce4e548407c92be1dd392e7f437e3862 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:17:56 +0200
+Subject: [PATCH 04/12] install chuck headers (for building Chugins)
+
+---
+ makefile | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/src/makefile b/src/makefile
+index aa87fe9..077b879 100644
+--- a/src/makefile
++++ b/src/makefile
+@@ -9,6 +9,8 @@ current:
+ install:
+ cp $(wildcard chuck chuck.exe) $(DESTDIR)/
+ chmod 755 $(DESTDIR)/$(wildcard chuck chuck.exe)
++ mkdir -p /usr/include/chuck
++ cp *.h /usr/include/chuck
+
+ ifneq ($(CK_TARGET),)
+ .DEFAULT_GOAL:=$(CK_TARGET)
+--
+1.7.1
+
diff --git a/chuck/patches/0005-allow-declaring-string-references.patch b/chuck/patches/0005-allow-declaring-string-references.patch
new file mode 100644
index 0000000..3b2ab36
--- /dev/null
+++ b/chuck/patches/0005-allow-declaring-string-references.patch
@@ -0,0 +1,27 @@
+From 9a84ba63d847024bb045d7a6c5362b63310071a8 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:20:15 +0200
+Subject: [PATCH 05/12] allow declaring "string" references
+
+tested, didn't experience any issues
+---
+ chuck_scan.cpp | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/src/chuck_scan.cpp b/src/chuck_scan.cpp
+index 916b579..b85b373 100644
+--- a/src/chuck_scan.cpp
++++ b/src/chuck_scan.cpp
+@@ -2173,7 +2173,8 @@ t_CKBOOL type_engine_scan2_exp_decl( Chuck_Env * env, a_Exp_Decl decl )
+ }
+
+ // primitive
+- if( (isprim( type ) || isa( type, &t_string )) && decl->type->ref ) // TODO: string
++ if( (isprim( type ) /*|| isa( type, &t_string )*/)
++ && decl->type->ref ) // TODO: string
+ {
+ EM_error2( decl->linepos,
+ "cannot declare references (@) of primitive type '%s'...",
+--
+1.7.1
+
diff --git a/chuck/patches/0006-when-comparing-types-consider-arrays-of-the-same-dep.patch b/chuck/patches/0006-when-comparing-types-consider-arrays-of-the-same-dep.patch
new file mode 100644
index 0000000..f0f8a45
--- /dev/null
+++ b/chuck/patches/0006-when-comparing-types-consider-arrays-of-the-same-dep.patch
@@ -0,0 +1,32 @@
+From d143313380e55196b8d34500047ed52b6930c72d Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:21:58 +0200
+Subject: [PATCH 06/12] when comparing types consider arrays of the same depth and descended type as compatible
+
+---
+ chuck_type.cpp | 9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/src/chuck_type.cpp b/src/chuck_type.cpp
+index c1aa326..4f817b8 100644
+--- a/src/chuck_type.cpp
++++ b/src/chuck_type.cpp
+@@ -4091,6 +4091,15 @@ t_CKBOOL operator <=( const Chuck_Type & lhs, const Chuck_Type & rhs )
+ curr = curr->parent;
+ }
+
++ // if both are arrays of the same depth
++ if( lhs.array_type && rhs.array_type &&
++ lhs.array_depth == rhs.array_depth )
++ {
++ // if lhs array type is a child of rhs array type
++ for( curr = lhs.array_type->parent; curr; curr = curr->parent )
++ if( *curr == *rhs.array_type ) return TRUE;
++ }
++
+ // if lhs is null and rhs is a object
+ if( lhs == t_null && (rhs <= t_object) ) return TRUE;
+
+--
+1.7.1
+
diff --git a/chuck/patches/0007-prevent-unused-return-value-warning.patch b/chuck/patches/0007-prevent-unused-return-value-warning.patch
new file mode 100644
index 0000000..dd5e94d
--- /dev/null
+++ b/chuck/patches/0007-prevent-unused-return-value-warning.patch
@@ -0,0 +1,35 @@
+From 006521d0799aecc18f83b9fa22604169145c64ed Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 17:43:56 +0200
+Subject: [PATCH 07/12] prevent unused-return-value warning
+
+ordinarily, the return value of every fseek/fwrite/fread should be checked
+---
+ ugen_stk.cpp | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/src/ugen_stk.cpp b/src/ugen_stk.cpp
+index f63eb6e..3a92ca2 100644
+--- a/src/ugen_stk.cpp
++++ b/src/ugen_stk.cpp
+@@ -17333,7 +17333,8 @@ void WvOut :: closeMatFile( void )
+
+ SINT32 headsize, temp;
+ fseek(fd, 132, SEEK_SET); // jump to header size
+- fread(&headsize, 4, 1, fd);
++ if( fread(&headsize, 4, 1, fd) < 4 ) goto close;
++
+ temp = headsize;
+ headsize += (SINT32) (totalCount * 8 * channels);
+ fseek(fd, 132, SEEK_SET);
+@@ -17344,6 +17345,7 @@ void WvOut :: closeMatFile( void )
+ temp = totalCount * 8 * channels;
+ fwrite(&temp, 4, 1, fd);
+
++ close:
+ fclose(fd);
+ }
+
+--
+1.7.1
+
diff --git a/chuck/patches/0008-ensure-that-chuck-is-linked-against-manually-built-l.patch b/chuck/patches/0008-ensure-that-chuck-is-linked-against-manually-built-l.patch
new file mode 100644
index 0000000..6487149
--- /dev/null
+++ b/chuck/patches/0008-ensure-that-chuck-is-linked-against-manually-built-l.patch
@@ -0,0 +1,25 @@
+From 713870b2d28ad236481341c5714b325fa82fa038 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Fri, 7 Sep 2012 20:43:43 +0200
+Subject: [PATCH 08/12] ensure that chuck is linked against manually built libjack
+
+previously the manually built libjack was found at runtime but not linked to at compile-time
+---
+ makefile.jack | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/src/makefile.jack b/src/makefile.jack
+index e09939a..a64ef3b 100644
+--- a/src/makefile.jack
++++ b/src/makefile.jack
+@@ -1,4 +1,7 @@
+
++CFLAGS+= -I/usr/local/include
++LDFLAGS+= -L/usr/local/lib
++
+ CFLAGS+= -D__UNIX_JACK__ -D__LINUX_JACK__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__
+ LDFLAGS+= -lasound -ljack -lstdc++ -ldl -lm -lsndfile -lpthread
+
+--
+1.7.1
+
diff --git a/chuck/patches/0009-revised-LiSa-performing-various-optimizations-and-fi.patch b/chuck/patches/0009-revised-LiSa-performing-various-optimizations-and-fi.patch
new file mode 100644
index 0000000..7fcf507
--- /dev/null
+++ b/chuck/patches/0009-revised-LiSa-performing-various-optimizations-and-fi.patch
@@ -0,0 +1,308 @@
+From dad4ab47c2b008f6cf946e268d8b49702e017af3 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Sat, 8 Sep 2012 02:43:38 +0200
+Subject: [PATCH 09/12] revised LiSa, performing various optimizations and fixing a lot of bugs introduced with v1.3.0.0
+
+ * properly support multi-channels by using tickf. fixes expressions like "LiSa => Gain g" which are now properly chucked
+ * prevent unnecessary copying of output samples
+ * prevent generating output samples if buffer is unitialized (size unset)
+ * use LiSa_channels macro instead of class attribute - should allow the compiler to perform loop unrolling in the time-critical tick/tickf functions
+ * allow mono LiSa as a compile time option (#define LiSa_channels 1). useful for increasing performance where absolutely necessary.
+ * initialize all voices' channel gain with 1 instead of setting the gain to 0.707 for the first two channels (resulted in lower gain for existing pre-v1.3.0.0 LiSa patches)
+ * fixed memleak on LiSa destruction and buffer resize
+ * initialize newly allocated buffers (don't know why this didn't cause any trouble)
+ * fixed tracking modes 1 and 2 which were completely broken beginning with v1.3.0.0!!!!
+---
+ ugen_xxx.cpp | 154 ++++++++++++++++++++++++++++++----------------------------
+ ugen_xxx.h | 1 +
+ 2 files changed, 81 insertions(+), 74 deletions(-)
+
+diff --git a/src/ugen_xxx.cpp b/src/ugen_xxx.cpp
+index c634473..dfb1bca 100644
+--- a/src/ugen_xxx.cpp
++++ b/src/ugen_xxx.cpp
+@@ -857,17 +857,15 @@ error:
+ }
+
+
+-
++#define LiSa_channels 8 //max channels for multichannel LiSa
+
+ // LiSa (live sampling data offset)
+-//static t_CKUINT LiSaBasic_offset_data = 0;
+ static t_CKUINT LiSaMulti_offset_data = 0;
+
+ //-----------------------------------------------------------------------------
+ // name: lisa_query()
+ // desc: ...
+ //-----------------------------------------------------------------------------
+-#define LiSa_channels 8 //max channels for multichannel LiSa
+ DLL_QUERY lisa_query( Chuck_DL_Query * QUERY )
+ {
+ Chuck_Env * env = Chuck_Env::instance();
+@@ -878,21 +876,20 @@ DLL_QUERY lisa_query( Chuck_DL_Query * QUERY )
+ // - probably don't need the others anymore....
+ // author: Dan Trueman (dan /at/ music.princeton.edu)
+ //---------------------------------------------------------------------
+-
+-
+- if( !type_engine_import_ugen_begin( env, "LiSa", "UGen_Stereo", env->global(),
++
++#if LiSa_channels == 1
++ if( !type_engine_import_ugen_begin( env, "LiSa", "UGen", env->global(),
+ LiSaMulti_ctor, LiSaMulti_dtor,
+- LiSaMulti_tick, LiSaMulti_pmsg, 1, LiSa_channels ))
++ LiSaMulti_tick, LiSaMulti_pmsg ))
+ return FALSE;
+-
+-
+- /*
+- if( !type_engine_import_ugen_begin( env, "LiSa", "UGen", env->global(),
++#else /* LiSa_channels > 1 */
++ if( !type_engine_import_ugen_begin( env, "LiSa", "UGen_Stereo", env->global(),
+ LiSaMulti_ctor, LiSaMulti_dtor,
+- LiSaMulti_tick, LiSaMulti_pmsg))
++ NULL, LiSaMulti_tickf,
++ LiSaMulti_pmsg, 1, LiSa_channels ))
+ return FALSE;
+- */
+-
++#endif
++
+ // set/get buffer size
+ func = make_new_mfun( "dur", "duration", LiSaMulti_size );
+ func->add_arg( "dur", "val" );
+@@ -3556,7 +3553,6 @@ LiSa updates/fixes:
+ struct LiSaMulti_data
+ {
+ SAMPLE * mdata;
+- SAMPLE * outsamples; //samples by channel to send out
+ t_CKINT mdata_len;
+ t_CKINT maxvoices;
+ t_CKINT loop_start[LiSa_MAXVOICES], loop_end[LiSa_MAXVOICES], loop_end_rec;
+@@ -3575,18 +3571,24 @@ struct LiSaMulti_data
+ t_CKBOOL rampup[LiSa_MAXVOICES], rampdown[LiSa_MAXVOICES];
+
+ t_CKINT track;
+-
+- t_CKINT num_chans;
++
++ ~LiSaMulti_data()
++ {
++ SAFE_DELETE( mdata );
++ }
+
+ // allocate memory, length in samples
+ inline int buffer_alloc(t_CKINT length)
+ {
+- mdata = (SAMPLE *)malloc((length + 1) * sizeof(SAMPLE)); //extra sample for safety....
++ SAFE_DELETE( mdata );
++
++ mdata = new SAMPLE[length + 1]; //extra sample for safety....
+ if(!mdata) {
+ fprintf(stderr, "LiSaBasic: unable to allocate memory!\n");
+ return false;
+ }
+-
++ clear_buf();
++
+ mdata_len = length;
+ maxvoices = 10; // default; user can set
+ rec_ramplen = 0.;
+@@ -3614,11 +3616,9 @@ struct LiSaMulti_data
+ rampup_len_inv[i] = rampdown_len_inv[i] = 1.;
+ rampctr[i] = 0.;
+
+- for(t_CKINT j=2; j<num_chans; j++) {
++ for(t_CKINT j=0; j<LiSa_channels; j++) {
+ channelGain[i][j] = 1.;
+ }
+- channelGain[i][0] = 0.707;
+- channelGain[i][1] = 0.707;
+ }
+
+ return true;
+@@ -3796,44 +3796,53 @@ struct LiSaMulti_data
+ //for simple stereo panning of a particular voice, and...
+ // l.channelGain(voice, channel, gain)
+ //to set the gain for a particular voice going to a particular channel; good for >2 voices (like 6 channels!)
+- inline SAMPLE * tick_multi( SAMPLE in)
++ inline void tick_multi(SAMPLE in, SAMPLE *out)
+ {
++ for( t_CKINT i = 0; i < LiSa_channels; i++ ) out[i] = SILENCE;
+
+- SAMPLE tempsample = 0.;
++ switch( track )
++ {
++ case 0:
++ recordSamp( in );
++ for( t_CKINT i = 0; i < maxvoices; i++ )
++ {
++ if( play[i] )
++ {
++ SAMPLE tempsample = getNextSamp( i );
++ for( t_CKINT j = 0; j < LiSa_channels; j++ )
++ out[j] += tempsample * channelGain[i][j]; //channelGain should return gain for voice i in channel j
++ }
++ }
++ break;
+
+- for(t_CKINT i=0;i<num_chans;i++) outsamples[i] = 0.;
+-
+- if(!mdata) return outsamples;
+-
+- recordSamp(in);
+-
+- if(track==0) {
+- for (t_CKINT i=0; i<maxvoices; i++) {
+- if(play[i]) {
+- tempsample = getNextSamp(i);
+- for(t_CKINT j=0;j<num_chans;j++) {
+- //outsamples[j] += tempsample; //mono for now, testing...
+- outsamples[j] += tempsample * channelGain[i][j]; //channelGain should return gain for voice i in channel j
+- }
+- }
++ case 1:
++ if( in < 0. ) in = -in;
++ for( t_CKINT i = 0; i < maxvoices; i++ )
++ {
++ if( play[i] )
++ {
++ SAMPLE tempsample = getSamp( (t_CKDOUBLE)in * (loop_end[i] - loop_start[i]) + loop_start[i], i );
++ for( t_CKINT j = 0; j < LiSa_channels; j++ )
++ out[j] += tempsample * channelGain[i][j];
++ }
+ }
+- } else if(track==1) {
+- if(in<0.) in = -in;
+- for (t_CKINT i=0; i<maxvoices; i++) {
+- if(play[i]) tempsample += getSamp((t_CKDOUBLE)in * (loop_end[i] - loop_start[i]) + loop_start[i], i);
+- }
+- } else if(track==2 && play[0]) {
+- if(in<0.) in = -in; //only use voice 0 when tracking with durs.
+- tempsample = getSamp( (t_CKDOUBLE)in, 0 );
+- }
++ break;
+
+- return outsamples;
++ case 2:
++ if( in < 0. ) in = -in; //only use voice 0 when tracking with durs.
++ if( play[0] )
++ {
++ SAMPLE tempsample = getSamp( (t_CKDOUBLE)in, 0 );
++ for( t_CKINT j = 0; j < LiSa_channels; j++ )
++ out[j] = tempsample * channelGain[0][j];
++ }
++ break;
++ }
+ }
+
+ inline void clear_buf()
+ {
+- for (t_CKINT i = 0; i < mdata_len; i++)
+- mdata[i] = 0.;
++ memset( mdata, 0, mdata_len*sizeof(SAMPLE) );
+ }
+
+ inline t_CKINT get_free_voice()
+@@ -3907,16 +3916,7 @@ CK_DLL_CTOR( LiSaMulti_ctor )
+ LiSaMulti_data * f = new LiSaMulti_data;
+ memset( f, 0, sizeof(LiSaMulti_data) );
+
+- Chuck_UGen * ugen = (Chuck_UGen *)SELF;
+- f->num_chans = ugen->m_multi_chan_size;
+- //fprintf(stderr, "LiSa: number of channels = %d\n", f->num_chans);
+- f->outsamples = new SAMPLE[f->num_chans];
+- memset( f->outsamples, 0, (f->num_chans)*sizeof(SAMPLE) );
+-
+ OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data) = (t_CKUINT)f;
+-
+-
+-
+ }
+
+
+@@ -3941,18 +3941,24 @@ CK_DLL_DTOR( LiSaMulti_dtor )
+ //-----------------------------------------------------------------------------
+ CK_DLL_TICK( LiSaMulti_tick )
+ {
+- Chuck_UGen * ugen = (Chuck_UGen *)SELF;
+-
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- SAMPLE * temp_out_samples = d->tick_multi( in );
+-
+- for( t_CKUINT i = 0; i < ugen->m_multi_chan_size; i++ )
+- ugen->m_multi_chan[i]->m_sum = ugen->m_multi_chan[i]->m_current = temp_out_samples[i]; //yay this works!
+- //out[i] = temp_out_samples[i];
+-
++ if( !d->mdata ) return FALSE;
++
++ d->tick_multi( in, out );
++
+ return TRUE;
+ }
+
++CK_DLL_TICKF( LiSaMulti_tickf )
++{
++ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
++ if( !d->mdata ) return FALSE;
++
++ for( t_CKUINT frame = 0; frame < nframes; frame++ )
++ d->tick_multi( in[frame], out + frame*LiSa_channels );
++
++ return TRUE;
++}
+
+ //-----------------------------------------------------------------------------
+ // name: LiSaMulti_size()
+@@ -4462,14 +4468,14 @@ CK_DLL_CTRL( LiSaMulti_ctrl_voicepan )
+
+ t_CKINT i;
+
+- for(i=0; i<d->num_chans; i++) d->channelGain[which][i] = 0.;
++ for(i=0; i<LiSa_channels; i++) d->channelGain[which][i] = 0.;
+
+- for(i=0; i<d->num_chans; i++) {
++ for(i=0; i<LiSa_channels; i++) {
+ t_CKINT panTrunc = (t_CKINT)d->voicePan[which];
+ //fprintf(stderr, "panTrunc = %d, panFloat = %f, i = %d\n", panTrunc, d->voicePan[which], i);
+ if(i == panTrunc) {
+ d->channelGain[which][i] = 1. - ( d->voicePan[which] - (t_CKFLOAT)i );
+- if(i == d->num_chans - 1) {
++ if(i == LiSa_channels - 1) {
+ d->channelGain[which][0] = 1. - d->channelGain[which][i];
+ d->channelGain[which][0] = sqrt(d->channelGain[which][0]);
+ }
+@@ -4510,14 +4516,14 @@ CK_DLL_CTRL( LiSaMulti_ctrl_voicepan0 )
+
+ t_CKINT i;
+
+- for(i=0; i<d->num_chans; i++) d->channelGain[which][i] = 0.;
++ for(i=0; i<LiSa_channels; i++) d->channelGain[which][i] = 0.;
+
+- for(i=0; i<d->num_chans; i++) {
++ for(i=0; i<LiSa_channels; i++) {
+ t_CKINT panTrunc = (t_CKINT)d->voicePan[which];
+ //fprintf(stderr, "panTrunc = %d, panFloat = %f, i = %d\n", panTrunc, d->voicePan[which], i);
+ if(i == panTrunc) {
+ d->channelGain[which][i] = 1. - ( d->voicePan[which] - (t_CKFLOAT)i );
+- if(i == d->num_chans - 1) {
++ if(i == LiSa_channels - 1) {
+ d->channelGain[which][0] = 1. - d->channelGain[which][i];
+ d->channelGain[which][0] = sqrt(d->channelGain[which][0]);
+ }
+diff --git a/src/ugen_xxx.h b/src/ugen_xxx.h
+index 8e18af6..e0663ee 100644
+--- a/src/ugen_xxx.h
++++ b/src/ugen_xxx.h
+@@ -189,6 +189,7 @@ CK_DLL_CGET( sndbuf_cget_valueAt );
+ CK_DLL_CTOR( LiSaMulti_ctor );
+ CK_DLL_DTOR( LiSaMulti_dtor );
+ CK_DLL_TICK( LiSaMulti_tick );
++CK_DLL_TICKF( LiSaMulti_tickf );
+ CK_DLL_PMSG( LiSaMulti_pmsg );
+ CK_DLL_CTRL( LiSaMulti_size );
+ CK_DLL_CTRL( LiSaMulti_cget_size );
+--
+1.7.1
+
diff --git a/chuck/patches/0010-LiSa-fixes-new-features-and-clean-up.patch b/chuck/patches/0010-LiSa-fixes-new-features-and-clean-up.patch
new file mode 100644
index 0000000..3adc120
--- /dev/null
+++ b/chuck/patches/0010-LiSa-fixes-new-features-and-clean-up.patch
@@ -0,0 +1,1073 @@
+From d77b79446964fca0149bbaadc0e8354d92d6fafa Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Thu, 13 Sep 2012 01:47:37 +0200
+Subject: [PATCH 10/12] LiSa fixes, new features and clean up
+
+ * always check whether buffer is allocated (size set) if necessary fixing easy to provoke segfaults
+ * when configuring check values for validity (e.g. lisa.track())
+ * for every configuration parameter accepting a duration: support negative durations (translate to "from the end of the buffer") and durations longer than the buffer (translate to "from the beginning of the buffer")
+ * might be arbitrarily large
+ * tracking mode 1/2: accept input data < 0, or longer than buffer
+ * tracking mode 1: fixed playing whithout loop-playing (and arbitrarily set loop points)
+ * tracking mode 2: use all voices
+ * support loop start > loop end: loop over end of buffer/beginning of buffer
+etc.
+---
+ ugen_xxx.cpp | 668 ++++++++++++++++++++++++++++++++++------------------------
+ 1 files changed, 391 insertions(+), 277 deletions(-)
+
+diff --git a/src/ugen_xxx.cpp b/src/ugen_xxx.cpp
+index dfb1bca..17e39d6 100644
+--- a/src/ugen_xxx.cpp
++++ b/src/ugen_xxx.cpp
+@@ -51,6 +51,7 @@
+ #include "chuck_vm.h"
+ #include "chuck_globals.h"
+ #include "chuck_instr.h"
++#include "chuck_errmsg.h"
+
+ #include <fstream>
+ using namespace std;
+@@ -3556,6 +3557,7 @@ struct LiSaMulti_data
+ t_CKINT mdata_len;
+ t_CKINT maxvoices;
+ t_CKINT loop_start[LiSa_MAXVOICES], loop_end[LiSa_MAXVOICES], loop_end_rec;
++ t_CKINT loop_len[LiSa_MAXVOICES]; // caching of frequently used values
+ t_CKINT rindex; // record and play indices
+ t_CKBOOL record, looprec, loopplay[LiSa_MAXVOICES], reset, append, play[LiSa_MAXVOICES], bi[LiSa_MAXVOICES];
+ t_CKFLOAT coeff; // feedback coeff
+@@ -3577,51 +3579,118 @@ struct LiSaMulti_data
+ SAFE_DELETE( mdata );
+ }
+
++ inline t_CKDOUBLE normalize_index(t_CKDOUBLE index)
++ {
++ while( index < 0 ) index += mdata_len;
++ while( index >= mdata_len ) index -= mdata_len;
++
++ return index;
++ }
++
++ inline t_CKINT get_safe_voice(t_CKINT voice)
++ {
++ if (voice < 0 || voice >= maxvoices)
++ {
++ EM_error2( 0, "LiSa: Requesting invalid voice number %d (MAXVOICES=%d)",
++ voice, LiSa_MAXVOICES);
++ return 0;
++ }
++
++ return voice;
++ }
++
++ void update_cache(t_CKINT which = 0)
++ {
++ if( loop_start[which] <= loop_end[which] )
++ loop_len[which] = loop_end[which] - loop_start[which];
++ else /* loop_start[which] > loop_end[which] */
++ loop_len[which] = mdata_len - loop_start[which] + loop_end[which];
++
++ loop_len[which]++;
++ }
++
++ inline t_CKDUR set_loop_start(t_CKDUR v, t_CKINT which = 0)
++ {
++ if( !mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set loop start on uninitialized buffer; ignoring" );
++ return 0.;
++ }
++
++ loop_start[which] = (t_CKINT)normalize_index( (t_CKDOUBLE)v );
++ update_cache( which );
++
++ return (t_CKDUR)loop_start[which];
++ }
++ inline t_CKDUR set_loop_end(t_CKDUR v, t_CKINT which = 0)
++ {
++ if( !mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set loop end on uninitialized buffer; ignoring" );
++ return 0.;
++ }
++
++ loop_end[which] = (t_CKINT)normalize_index( (t_CKDOUBLE)v );
++ update_cache( which );
++
++ return (t_CKDUR)loop_end[which];
++ }
++
+ // allocate memory, length in samples
+- inline int buffer_alloc(t_CKINT length)
++ inline t_CKDUR buffer_alloc(t_CKDUR length)
+ {
++ if( (t_CKINT)length > LiSa_MAXBUFSIZE )
++ {
++ EM_error2( 0, "LiSa: Buffer size request too large, resizing to %d",
++ LiSa_MAXBUFSIZE );
++ length = LiSa_MAXBUFSIZE;
++ }
++
+ SAFE_DELETE( mdata );
++ mdata_len = 0;
+
+- mdata = new SAMPLE[length + 1]; //extra sample for safety....
+- if(!mdata) {
+- fprintf(stderr, "LiSaBasic: unable to allocate memory!\n");
+- return false;
++ mdata = new SAMPLE[(t_CKINT)length];
++ if( !mdata )
++ {
++ EM_error2( 0, "LiSa: Unable to allocate memory!");
++ return 0.;
+ }
++
++ mdata_len = (t_CKINT)length;
+ clear_buf();
+
+- mdata_len = length;
+ maxvoices = 10; // default; user can set
+ rec_ramplen = 0.;
+ rec_ramplen_inv = 1.;
+-
++
+ track = 0;
+-
+- for (t_CKINT i=0; i < LiSa_MAXVOICES; i++) {
++
++ for( t_CKINT i = 0; i < LiSa_MAXVOICES; i++ )
++ {
+ loop_start[i] = 0;
+- //loop_end[i] = length - 1; //no idea why i had this
+- loop_end[i] = length;
+- loop_end_rec = length;
+-
++ loop_end[i] = mdata_len - 1;
++ loop_end_rec = mdata_len - 1;
++
+ pindex[i] = rindex = 0;
+ play[i] = record = bi[i] = false;
+ looprec = loopplay[i] = true;
+ coeff = 0.;
+ p_inc[i] = 1.;
+- voiceGain[i] = 1.;
+- voicePan[i] = 0.5;
+-
++ voiceGain[i] = 1.;
++ voicePan[i] = 0.5;
++
+ // ramp stuff
+ rampup[i] = rampdown[i] = false;
+ rampup_len[i] = rampdown_len[i] = 0.;
+ rampup_len_inv[i] = rampdown_len_inv[i] = 1.;
+ rampctr[i] = 0.;
+-
+- for(t_CKINT j=0; j<LiSa_channels; j++) {
+- channelGain[i][j] = 1.;
+- }
++
++ for( t_CKINT j = 0; j < LiSa_channels; j++ ) channelGain[i][j] = 1.;
++
++ update_cache( i );
+ }
+-
+- return true;
++
++ return (t_CKDUR)mdata_len;
+ }
+
+ // dump a sample into the buffer; retain existing sample, scaled by "coeff"
+@@ -3658,98 +3727,126 @@ struct LiSaMulti_data
+ rindex++;
+ }
+ }
+-
++
++ inline bool isInLoop(t_CKDOUBLE where, t_CKINT which = 0)
++ {
++ if( loop_start[which] <= loop_end[which] )
++ return where >= loop_start[which] && where <= loop_end[which];
++ else
++ return where >= loop_start[which] || where <= loop_end[which];
++ }
++
+ // grab a sample from the buffer, with linear interpolation (add prc's SINC interp later)
+ // increment play index
+- // which specifies voice number
+- inline SAMPLE getNextSamp(t_CKINT which)
++ // which specifies voice number
++ inline SAMPLE getNextSamp(t_CKINT which = 0)
+ {
+ // constrain
+- if(loopplay[which]) {
+- if(bi[which]) { // change direction if bidirectional mode
+- if(pindex[which] >= loop_end[which] || pindex[which] < loop_start[which]) { //should be >= ?
+- pindex[which] -= p_inc[which];
+- p_inc[which] = -p_inc[which];
+- }
++ if( loopplay[which] )
++ {
++ bool wasOutsideLoop = false;
++
++ if ( loop_start[which] == loop_end[which] )
++ {
++ pindex[which] = loop_start[which];
++ }
++ else if ( loop_start[which] < loop_end[which] )
++ {
++ wasOutsideLoop = pindex[which] < loop_start[which] ||
++ pindex[which] > loop_end[which];
++
++ while( pindex[which] > loop_end[which] )
++ pindex[which] -= loop_len[which];
++ while( pindex[which] < loop_start[which] )
++ pindex[which] += loop_len[which];
+ }
+- if( loop_start[which] == loop_end[which] ) pindex[which] = loop_start[which]; //catch this condition to avoid infinite while loops
+- else {
+- while(pindex[which] >= loop_end[which]) pindex[which] = loop_start[which] + (pindex[which] - loop_end[which]); //again, >=?
+- while(pindex[which] < loop_start[which]) pindex[which] = loop_end[which] - (loop_start[which] - pindex[which]);
+- }
+-
+- } else if(pindex[which] >= mdata_len || pindex[which] < 0) { //should be >=, no?
+- play[which] = 0;
++ else /* loop_start[which] > loop_end[which] */
++ {
++ pindex[which] = normalize_index( pindex[which] );
++
++ wasOutsideLoop = pindex[which] < loop_start[which] &&
++ pindex[which] > loop_end[which];
++
++ if( wasOutsideLoop )
++ {
++ if( p_inc[which] > 0 )
++ {
++ /* after loop end */
++ while( pindex[which] > 0 )
++ pindex[which] -= loop_len[which];
++ pindex[which] += mdata_len;
++ }
++ else
++ {
++ /* before loop start */
++ while( pindex[which] < mdata_len )
++ pindex[which] += loop_len[which];
++ pindex[which] -= mdata_len;
++ }
++ }
++ }
++
++ // change direction if bidirectional mode
++ if( bi[which] && wasOutsideLoop ) p_inc[which] *= -1;
++ }
++ /* !loopplay[which] */
++ else if( pindex[which] >= mdata_len || pindex[which] < 0 )
++ {
++ play[which] = false;
+ //fprintf(stderr, "turning voice %d off!\n", which);
+- return (SAMPLE) 0.;
++ return SILENCE;
+ }
+-
++
+ // interp
+- t_CKINT whereTrunc = (t_CKINT) pindex[which];
++ t_CKINT whereTrunc = (t_CKINT)pindex[which];
+ t_CKDOUBLE whereFrac = pindex[which] - (t_CKDOUBLE)whereTrunc;
+ t_CKINT whereNext = whereTrunc + 1;
+-
+- if (loopplay[which]) {
+- if((whereNext) >= loop_end[which]) {
+- whereNext = loop_start[which];
+- }
+- if((whereTrunc) >= loop_end[which]) {
+- whereTrunc = loop_start[which];
+- }
+- } else {
+- if((whereTrunc) >= mdata_len) {
+- whereTrunc = mdata_len - 1; //should correct this, in case we've overshot by more than 1 sample
+- whereNext = 0;
+- }
+- if((whereNext) >= mdata_len) {
+- whereNext = 0;
+- }
+- }
+-
++
++ if( whereNext == mdata_len ) whereNext = 0;
++
++ if( loopplay[which] && !isInLoop( whereNext, which ) )
++ whereNext = loop_start[which];
++
+ pindex[which] += p_inc[which];
+-
++
+ t_CKDOUBLE outsample;
+- outsample = (t_CKDOUBLE)mdata[whereTrunc] + (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
+-
++ outsample = (t_CKDOUBLE)mdata[whereTrunc] +
++ (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
++
+ // ramp stuff
+- if(rampup[which]) {
++ if( rampup[which] )
++ {
+ outsample *= rampctr[which]++ * rampup_len_inv[which]; //remove divide
+- if(rampctr[which] >= rampup_len[which]) rampup[which] = false;
++ rampup[which] = rampctr[which] < rampup_len[which];
+ }
+- else if(rampdown[which]) {
++ else if( rampdown[which] )
++ {
+ outsample *= (rampdown_len[which] - rampctr[which]++) * rampdown_len_inv[which];
+- if(rampctr[which] >= rampdown_len[which]) {
+- rampdown[which] = false;
+- play[which] = false;
+- }
++ play[which] = rampdown[which] = rampctr[which] < rampdown_len[which];
+ }
+-
+- outsample *= voiceGain[which];
+-
+- return (SAMPLE)outsample;
++
++ return (SAMPLE)(outsample * voiceGain[which]);
+ }
+
+ // grab a sample from the buffer, with linear interpolation (add prc's SINC interp later)
+ // given a position within the buffer
+- inline SAMPLE getSamp(t_CKDOUBLE where, t_CKINT which)
++ inline SAMPLE getSamp(t_CKDOUBLE where, t_CKINT which = 0)
+ {
+- // constrain
+- if(where > loop_end[which]) where = loop_end[which];
+- if(where < loop_start[which]) where = loop_start[which];
+-
+ // interp
+- t_CKINT whereTrunc = (t_CKINT) where;
++ t_CKINT whereTrunc = (t_CKINT)where;
+ t_CKDOUBLE whereFrac = where - (t_CKDOUBLE)whereTrunc;
+ t_CKINT whereNext = whereTrunc + 1;
+-
+- if((whereNext) == loop_end[which]) whereNext = loop_start[which];
++
++ if( whereNext == mdata_len ) whereNext = 0;
++
++ if( loopplay[which] && !isInLoop( whereNext, which ) )
++ whereNext = loop_start[which];
+
+ t_CKDOUBLE outsample;
+- outsample = (t_CKDOUBLE)mdata[whereTrunc] + (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
+- outsample *= voiceGain[which];
+-
+- //add voiceGain ctl here; return (SAMPLE)vgain[which]*outsample;
+- return (SAMPLE)outsample;
++ outsample = (t_CKDOUBLE)mdata[whereTrunc] +
++ (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
++
++ return (SAMPLE)(outsample * voiceGain[which]);
+ }
+
+ // ramp stuff
+@@ -3792,6 +3889,11 @@ struct LiSaMulti_data
+ //fprintf ( stderr, "rec_ramplen = %f, inv = %f \n", rec_ramplen, rec_ramplen_inv );
+ }
+
++ inline void mix_voice(SAMPLE sample, t_CKINT which, SAMPLE *out)
++ {
++ for( t_CKINT i = 0; i < LiSa_channels; i++ )
++ out[i] += sample * channelGain[which][i];
++ }
+
+ //for simple stereo panning of a particular voice, and...
+ // l.channelGain(voice, channel, gain)
+@@ -3805,44 +3907,39 @@ struct LiSaMulti_data
+ case 0:
+ recordSamp( in );
+ for( t_CKINT i = 0; i < maxvoices; i++ )
+- {
+- if( play[i] )
+- {
+- SAMPLE tempsample = getNextSamp( i );
+- for( t_CKINT j = 0; j < LiSa_channels; j++ )
+- out[j] += tempsample * channelGain[i][j]; //channelGain should return gain for voice i in channel j
+- }
+- }
++ if( play[i] ) mix_voice( getNextSamp( i ), i, out );
+ break;
+
+ case 1:
+- if( in < 0. ) in = -in;
++ case 2:
+ for( t_CKINT i = 0; i < maxvoices; i++ )
+ {
+ if( play[i] )
+ {
+- SAMPLE tempsample = getSamp( (t_CKDOUBLE)in * (loop_end[i] - loop_start[i]) + loop_start[i], i );
+- for( t_CKINT j = 0; j < LiSa_channels; j++ )
+- out[j] += tempsample * channelGain[i][j];
++ t_CKDOUBLE where;
++
++ if( track == 2 )
++ where = (t_CKDOUBLE)in;
++ else if( loopplay[i] )
++ where = (t_CKDOUBLE)in*loop_len[i] + loop_start[i];
++ else
++ where = (t_CKDOUBLE)in*mdata_len;
++
++ mix_voice( getSamp( normalize_index( where ), i ), i, out );
+ }
+ }
+ break;
+
+- case 2:
+- if( in < 0. ) in = -in; //only use voice 0 when tracking with durs.
+- if( play[0] )
+- {
+- SAMPLE tempsample = getSamp( (t_CKDOUBLE)in, 0 );
+- for( t_CKINT j = 0; j < LiSa_channels; j++ )
+- out[j] = tempsample * channelGain[0][j];
+- }
++ default:
++ /* shouldn't happen */
+ break;
+ }
+ }
+
+ inline void clear_buf()
+ {
+- memset( mdata, 0, mdata_len*sizeof(SAMPLE) );
++ if( mdata )
++ memset( mdata, 0, mdata_len*sizeof(SAMPLE) );
+ }
+
+ inline t_CKINT get_free_voice()
+@@ -3856,40 +3953,59 @@ struct LiSaMulti_data
+ }
+
+ //stick sample in record buffer
+- inline void pokeSample( SAMPLE insample, t_CKINT index ) {
+-
+- if ( index >= mdata_len || index < 0 ) {
+- index = 0;
+- fprintf(stderr, "LiSa: trying to put sample out of buffer range; ignoring");
+- } else mdata[index] = insample;
+-
+- }
++ inline void pokeSample( SAMPLE insample, t_CKINT index )
++ {
++ mdata[index] = insample;
++ }
+
+ //grab sample directly from record buffer, with linear interpolation
+- inline SAMPLE grabSample ( t_CKDOUBLE where ) {
+-
+- if ( where > mdata_len || where < 0 ) {
+- where = 0;
+- fprintf(stderr, "LiSa: trying to grab sample out of buffer range; ignoring");
+- return 0.;
+- } else {
+-
+- // interp
+- t_CKINT whereTrunc = (t_CKINT) where;
+- t_CKDOUBLE whereFrac = where - (t_CKDOUBLE)whereTrunc;
+- t_CKINT whereNext = whereTrunc + 1;
+-
+- if((whereNext) == mdata_len) whereNext = 0;
++ inline SAMPLE grabSample( t_CKDOUBLE where )
++ {
++ // interp
++ t_CKINT whereTrunc = (t_CKINT) where;
++ t_CKDOUBLE whereFrac = where - (t_CKDOUBLE)whereTrunc;
++ t_CKINT whereNext = whereTrunc + 1;
+
+- t_CKDOUBLE outsample;
+- outsample = (t_CKDOUBLE)mdata[whereTrunc] + (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
+-
+- //add voiceGain ctl here; return (SAMPLE)vgain[which]*outsample;
+- return (SAMPLE)outsample;
+-
+- }
+- }
+-
++ if( whereNext == mdata_len ) whereNext = 0;
++
++ t_CKDOUBLE outsample;
++ outsample = (t_CKDOUBLE)mdata[whereTrunc] + (t_CKDOUBLE)(mdata[whereNext] - mdata[whereTrunc]) * whereFrac;
++
++ return (SAMPLE)outsample;
++ }
++
++ t_CKFLOAT set_voice_pan(t_CKFLOAT pan, t_CKINT which = 0)
++ {
++ voicePan[which] = pan;
++
++ for( t_CKINT i = 0; i < LiSa_channels; i++ ) channelGain[which][i] = 0.;
++
++ for( t_CKINT i = 0; i < LiSa_channels; i++ )
++ {
++ t_CKINT panTrunc = (t_CKINT)voicePan[which];
++ //fprintf(stderr, "panTrunc = %d, panFloat = %f, i = %d\n", panTrunc, voicePan[which], i);
++ if( i == panTrunc )
++ {
++ channelGain[which][i] = 1. - ( voicePan[which] - (t_CKFLOAT)i );
++ if( i == LiSa_channels - 1 )
++ {
++ channelGain[which][0] = 1. - channelGain[which][i];
++ channelGain[which][0] = sqrt( channelGain[which][0] );
++ }
++ else
++ {
++ channelGain[which][i+1] = 1. - channelGain[which][i];
++ channelGain[which][i+1] = sqrt( channelGain[which][i+1] );
++ }
++
++ channelGain[which][i] = sqrt( channelGain[which][i] );
++ }
++
++ //fprintf(stderr, "gain for channel %d and voice %d = %f\n", i, which, channelGain[which][i]);
++ }
++
++ return pan;
++ }
+ };
+
+
+@@ -3967,14 +4083,8 @@ CK_DLL_TICKF( LiSaMulti_tickf )
+ CK_DLL_CTRL( LiSaMulti_size )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKDUR buflen = GET_NEXT_DUR(ARGS);
+- if (buflen > LiSa_MAXBUFSIZE) {
+- fprintf(stderr, "LiSa: buffer size request too large, resizing\n");
+- buflen = LiSa_MAXBUFSIZE;
+- }
+- d->buffer_alloc((t_CKINT)buflen);
+-
+- RETURN->v_dur = (t_CKDUR)buflen;
++
++ RETURN->v_dur = d->buffer_alloc( GET_NEXT_DUR(ARGS) );
+ }
+
+ CK_DLL_CGET( LiSaMulti_cget_size )
+@@ -4005,7 +4115,7 @@ CK_DLL_CTRL( LiSaMulti_start_record )
+ CK_DLL_CTRL( LiSaMulti_start_play )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ d->play[which] = GET_NEXT_INT(ARGS);
+ //fprintf(stderr, "voice %d playing = %d\n", which, d->play[which]);
+
+@@ -4044,7 +4154,7 @@ CK_DLL_CTRL( LiSaMulti_start_play0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rate )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ d->p_inc[which] = (t_CKDOUBLE)GET_NEXT_FLOAT(ARGS);
+
+ //fprintf(stderr, "setting voice %d rate to %f\n", which, d->p_inc[which]);
+@@ -4071,7 +4181,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_rate0 )
+ CK_DLL_CTRL( LiSaMulti_cget_rate )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ //fprintf(stderr, "setting voice %d rate to %f\n", which, d->p_inc[which]);
+
+ RETURN->v_float = d->p_inc[which];
+@@ -4093,8 +4203,8 @@ CK_DLL_CTRL( LiSaMulti_cget_rate0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_pindex )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
+- d->pindex[which] = (t_CKDOUBLE)GET_NEXT_DUR(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++ d->pindex[which] = d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ RETURN->v_dur = (t_CKDUR)d->pindex[which];
+ }
+@@ -4103,7 +4213,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_pindex )
+ CK_DLL_CTRL( LiSaMulti_ctrl_pindex0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- d->pindex[0] = (t_CKDOUBLE)GET_NEXT_DUR(ARGS);
++ d->pindex[0] = d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ RETURN->v_dur = (t_CKDUR)d->pindex[0];
+ }
+@@ -4116,7 +4226,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_pindex0 )
+ CK_DLL_CGET( LiSaMulti_cget_pindex )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+ RETURN->v_dur = (t_CKDUR)d->pindex[which];
+@@ -4139,7 +4249,7 @@ CK_DLL_CGET( LiSaMulti_cget_pindex0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rindex )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- d->rindex = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
++ d->rindex = (t_CKINT)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ RETURN->v_dur = (t_CKDUR)d->rindex;
+ }
+@@ -4165,23 +4275,17 @@ CK_DLL_CGET( LiSaMulti_cget_rindex )
+ CK_DLL_CTRL( LiSaMulti_ctrl_lstart )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
+- d->loop_start[which] = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
+-
+- if (d->loop_start[which] < 0) d->loop_start[which] = 0;
+-
+- RETURN->v_dur = (t_CKDUR)d->loop_start[which];
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++
++ RETURN->v_dur = d->set_loop_start( GET_NEXT_DUR(ARGS), which );
+ }
+
+
+ CK_DLL_CTRL( LiSaMulti_ctrl_lstart0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- d->loop_start[0] = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
+-
+- if (d->loop_start[0] < 0) d->loop_start[0] = 0;
+-
+- RETURN->v_dur = (t_CKDUR)d->loop_start[0];
++
++ RETURN->v_dur = d->set_loop_start( GET_NEXT_DUR(ARGS) );
+ }
+
+
+@@ -4193,7 +4297,7 @@ CK_DLL_CGET( LiSaMulti_cget_lstart )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ // return
+ RETURN->v_dur = (t_CKDUR)d->loop_start[which];
+ }
+@@ -4215,25 +4319,17 @@ CK_DLL_CGET( LiSaMulti_cget_lstart0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_lend )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
+- d->loop_end[which] = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
+-
+- //check to make sure loop_end is not too large
+- if (d->loop_end[which] >= d->mdata_len) d->loop_end[which] = d->mdata_len - 1;
+-
+- RETURN->v_dur = (t_CKDUR)d->loop_end[which];
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++
++ RETURN->v_dur = d->set_loop_end( GET_NEXT_DUR(ARGS), which );
+ }
+
+
+ CK_DLL_CTRL( LiSaMulti_ctrl_lend0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- d->loop_end[0] = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
+-
+- //check to make sure loop_end is not too large
+- if (d->loop_end[0] >= d->mdata_len) d->loop_end[0] = d->mdata_len - 1;
+-
+- RETURN->v_dur = (t_CKDUR)d->loop_end[0];
++
++ RETURN->v_dur = d->set_loop_end( GET_NEXT_DUR(ARGS) );
+ }
+
+
+@@ -4244,7 +4340,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_lend0 )
+ CK_DLL_CGET( LiSaMulti_cget_lend )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+ RETURN->v_dur = (t_CKDUR)d->loop_end[which];
+@@ -4267,7 +4363,7 @@ CK_DLL_CGET( LiSaMulti_cget_lend0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_loop )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ d->loopplay[which] = (t_CKBOOL)GET_NEXT_INT(ARGS);
+ }
+
+@@ -4288,7 +4384,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_loop0 )
+ CK_DLL_CGET( LiSaMulti_cget_loop )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+ RETURN->v_int = (t_CKINT)d->loopplay[which];
+@@ -4311,7 +4407,7 @@ CK_DLL_CGET( LiSaMulti_cget_loop0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_bi )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ d->bi[which] = (t_CKBOOL)GET_NEXT_INT(ARGS);
+
+ RETURN->v_int = (t_CKINT)d->bi[which];
+@@ -4334,7 +4430,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_bi0 )
+ CK_DLL_CGET( LiSaMulti_cget_bi )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+ RETURN->v_int = (t_CKINT)d->bi[which];
+@@ -4357,8 +4453,15 @@ CK_DLL_CGET( LiSaMulti_cget_bi0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_loop_end_rec )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- d->loop_end_rec = /* gewang-> */(t_CKINT)GET_NEXT_DUR(ARGS);
+-
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set loop recording end on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ d->loop_end_rec = (t_CKINT)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
++
+ RETURN->v_dur = (t_CKDUR)d->loop_end_rec;
+ }
+
+@@ -4408,11 +4511,18 @@ CK_DLL_CGET( LiSaMulti_cget_loop_rec )
+ CK_DLL_CTRL( LiSaMulti_ctrl_sample )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- SAMPLE sample_in = (SAMPLE)GET_NEXT_FLOAT(ARGS);
+- int index_in = (t_CKINT)GET_NEXT_DUR(ARGS);
+-
+- d->pokeSample( sample_in, index_in );
+-
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to put sample into uninitialized buffer; ignoring" );
++ RETURN->v_float = 0.;
++ return;
++ }
++
++ SAMPLE sample_in = (SAMPLE)GET_NEXT_FLOAT(ARGS);
++ t_CKINT index_in = (t_CKINT)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
++
++ d->pokeSample( sample_in, index_in );
++
+ RETURN->v_float = (t_CKFLOAT)sample_in; //pass input through
+ }
+
+@@ -4423,7 +4533,14 @@ CK_DLL_CTRL( LiSaMulti_ctrl_sample )
+ CK_DLL_CGET( LiSaMulti_cget_sample )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- double index_in = (t_CKDOUBLE)GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to grab sample from uninitialized buffer; ignoring" );
++ RETURN->v_float = 0.;
++ return;
++ }
++
++ t_CKDOUBLE index_in = d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+ // return
+ RETURN->v_float = (t_CKFLOAT)d->grabSample( index_in ); //change this to getSamp for interpolation
+ }
+@@ -4436,7 +4553,7 @@ CK_DLL_CGET( LiSaMulti_cget_sample )
+ CK_DLL_CTRL( LiSaMulti_ctrl_voicegain )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+ d->voiceGain[which] = (t_CKDOUBLE)GET_NEXT_FLOAT(ARGS);
+
+ RETURN->v_float = (t_CKFLOAT)d->voiceGain[which];
+@@ -4450,7 +4567,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_voicegain )
+ CK_DLL_CGET( LiSaMulti_cget_voicegain )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+ RETURN->v_float = (t_CKFLOAT)d->voiceGain[which];
+@@ -4463,35 +4580,10 @@ CK_DLL_CGET( LiSaMulti_cget_voicegain )
+ CK_DLL_CTRL( LiSaMulti_ctrl_voicepan )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
+- d->voicePan[which] = (t_CKFLOAT)GET_NEXT_FLOAT(ARGS);
+-
+- t_CKINT i;
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++ t_CKFLOAT pan = GET_NEXT_FLOAT(ARGS);
+
+- for(i=0; i<LiSa_channels; i++) d->channelGain[which][i] = 0.;
+-
+- for(i=0; i<LiSa_channels; i++) {
+- t_CKINT panTrunc = (t_CKINT)d->voicePan[which];
+- //fprintf(stderr, "panTrunc = %d, panFloat = %f, i = %d\n", panTrunc, d->voicePan[which], i);
+- if(i == panTrunc) {
+- d->channelGain[which][i] = 1. - ( d->voicePan[which] - (t_CKFLOAT)i );
+- if(i == LiSa_channels - 1) {
+- d->channelGain[which][0] = 1. - d->channelGain[which][i];
+- d->channelGain[which][0] = sqrt(d->channelGain[which][0]);
+- }
+- else {
+- d->channelGain[which][i+1] = 1. - d->channelGain[which][i];
+- d->channelGain[which][i+1] = sqrt(d->channelGain[which][i+1]);
+- }
+-
+- d->channelGain[which][i] = sqrt(d->channelGain[which][i]);
+-
+- }
+-
+- //fprintf(stderr, "gain for channel %d and voice %d = %f\n", i, which, d->channelGain[which][i]);
+- }
+-
+- RETURN->v_float = (t_CKFLOAT)d->voicePan[which];
++ RETURN->v_float = d->set_voice_pan( pan, which );
+ }
+
+
+@@ -4502,44 +4594,18 @@ CK_DLL_CTRL( LiSaMulti_ctrl_voicepan )
+ CK_DLL_CGET( LiSaMulti_cget_voicepan )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = GET_NEXT_INT(ARGS);
++ t_CKINT which = d->get_safe_voice( GET_NEXT_INT(ARGS) );
+
+ // return
+- RETURN->v_float = (t_CKFLOAT)d->voicePan[which];
++ RETURN->v_float = d->voicePan[which];
+ }
+
+ CK_DLL_CTRL( LiSaMulti_ctrl_voicepan0 )
+ {
+- LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT which = 0; //voice 0 for this one
+- d->voicePan[which] = (t_CKFLOAT)GET_NEXT_FLOAT(ARGS);
+-
+- t_CKINT i;
++ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
++ t_CKFLOAT pan = GET_NEXT_FLOAT(ARGS);
+
+- for(i=0; i<LiSa_channels; i++) d->channelGain[which][i] = 0.;
+-
+- for(i=0; i<LiSa_channels; i++) {
+- t_CKINT panTrunc = (t_CKINT)d->voicePan[which];
+- //fprintf(stderr, "panTrunc = %d, panFloat = %f, i = %d\n", panTrunc, d->voicePan[which], i);
+- if(i == panTrunc) {
+- d->channelGain[which][i] = 1. - ( d->voicePan[which] - (t_CKFLOAT)i );
+- if(i == LiSa_channels - 1) {
+- d->channelGain[which][0] = 1. - d->channelGain[which][i];
+- d->channelGain[which][0] = sqrt(d->channelGain[which][0]);
+- }
+- else {
+- d->channelGain[which][i+1] = 1. - d->channelGain[which][i];
+- d->channelGain[which][i+1] = sqrt(d->channelGain[which][i+1]);
+- }
+-
+- d->channelGain[which][i] = sqrt(d->channelGain[which][i]);
+-
+- }
+-
+- //fprintf(stderr, "gain for channel %d and voice %d = %f\n", i, which, d->channelGain[which][i]);
+- }
+-
+- RETURN->v_float = (t_CKFLOAT)d->voicePan[which];
++ RETURN->v_float = d->set_voice_pan( pan );
+ }
+
+ CK_DLL_CGET( LiSaMulti_cget_voicepan0 )
+@@ -4547,7 +4613,7 @@ CK_DLL_CGET( LiSaMulti_cget_voicepan0 )
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+
+ // return
+- RETURN->v_float = (t_CKFLOAT)d->voicePan[0];
++ RETURN->v_float = d->voicePan[0];
+ }
+
+ //-----------------------------------------------------------------------------
+@@ -4608,8 +4674,15 @@ CK_DLL_CGET( LiSaMulti_cget_voice )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rampup )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT voice = GET_NEXT_INT(ARGS);
+- t_CKDUR len = GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set ramp up length on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ t_CKINT voice = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++ t_CKDUR len = (t_CKDUR)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ d->ramp_up(voice, len);
+
+@@ -4620,7 +4693,14 @@ CK_DLL_CTRL( LiSaMulti_ctrl_rampup )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rampup0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKDUR len = GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set ramp up length on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ t_CKDUR len = (t_CKDUR)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ d->ramp_up(0, len);
+
+@@ -4635,19 +4715,33 @@ CK_DLL_CTRL( LiSaMulti_ctrl_rampup0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rampdown )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT voice = GET_NEXT_INT(ARGS);
+- t_CKDUR len = GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set ramp down length on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ t_CKINT voice = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++ t_CKDUR len = (t_CKDUR)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ d->ramp_down(voice, len);
+
+- RETURN->v_dur = (t_CKDUR)len;
++ RETURN->v_dur = (t_CKDUR)len;
+ }
+
+
+ CK_DLL_CTRL( LiSaMulti_ctrl_rampdown0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKDUR len = GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set ramp down length on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ t_CKDUR len = (t_CKDUR)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+
+ d->ramp_down(0, len);
+
+@@ -4662,7 +4756,14 @@ CK_DLL_CTRL( LiSaMulti_ctrl_rampdown0 )
+ CK_DLL_CTRL( LiSaMulti_ctrl_rec_ramplen )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKDUR newramplen = GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to set recording ramp length on uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
++
++ t_CKDUR newramplen = (t_CKDUR)d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
+ d->set_rec_ramplen(newramplen);
+
+ RETURN->v_dur = (t_CKDUR)newramplen;
+@@ -4679,7 +4780,7 @@ CK_DLL_CTRL( LiSaMulti_ctrl_maxvoices )
+ d->maxvoices = GET_NEXT_INT(ARGS);
+ if( d->maxvoices > LiSa_MAXVOICES) {
+ d->maxvoices = LiSa_MAXVOICES;
+- fprintf(stderr, "LiSa: MAXVOICES limited to %d.\n", LiSa_MAXVOICES);
++ EM_error2( 0, "LiSa: MAXVOICES limited to %d", LiSa_MAXVOICES );
+ }
+ RETURN->v_int = d->maxvoices;
+ }
+@@ -4705,21 +4806,33 @@ CK_DLL_CGET( LiSaMulti_cget_maxvoices )
+ CK_DLL_CGET( LiSaMulti_cget_value )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT voice = GET_NEXT_INT(ARGS);
+- t_CKDOUBLE where = (t_CKDOUBLE) GET_NEXT_DUR(ARGS);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to grab value from uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
+
+- // return
+- RETURN->v_dur = (t_CKDUR)d->getSamp(where, voice);
++ t_CKINT voice = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++ t_CKDOUBLE where = d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
++
++ RETURN->v_dur = (t_CKDUR)d->getSamp( where, voice );
+ }
+
+
+ CK_DLL_CGET( LiSaMulti_cget_value0 )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
++ if( !d->mdata )
++ {
++ EM_error2( 0, "LiSa: Trying to grab value from uninitialized buffer; ignoring" );
++ RETURN->v_dur = 0.;
++ return;
++ }
+
+- t_CKDOUBLE where = (t_CKDOUBLE) GET_NEXT_DUR(ARGS);
+- // return
+- RETURN->v_dur = (t_CKDUR)d->getSamp(where, 0);
++ t_CKDOUBLE where = d->normalize_index( (t_CKDOUBLE)GET_NEXT_DUR(ARGS) );
++
++ RETURN->v_dur = (t_CKDUR)d->getSamp( where );
+ }
+
+
+@@ -4731,6 +4844,11 @@ CK_DLL_CTRL( LiSaMulti_ctrl_track )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+ d->track = (t_CKINT)GET_NEXT_INT(ARGS);
++ if( d->track < 0 || d->track > 2 )
++ {
++ EM_error2( 0, "LiSa: Invalid tracking mode %d; using 0", d->track );
++ d->track = 0;
++ }
+
+ RETURN->v_int = d->track;
+ }
+@@ -4756,12 +4874,8 @@ CK_DLL_CGET( LiSaMulti_cget_track )
+ CK_DLL_CGET( LiSaMulti_cget_playing )
+ {
+ LiSaMulti_data * d = (LiSaMulti_data *)OBJ_MEMBER_UINT(SELF, LiSaMulti_offset_data);
+- t_CKINT voice = GET_NEXT_INT(ARGS);
+- if(voice >= d->maxvoices) {
+- fprintf(stderr, "LiSa: requesting info greater than MAXVOICES %d.\n", LiSa_MAXVOICES);
+- voice = 0;
+- }
+-
++ t_CKINT voice = d->get_safe_voice( GET_NEXT_INT(ARGS) );
++
+ // return
+ RETURN->v_int = d->play[voice];
+ }
+--
+1.7.1
+
diff --git a/chuck/patches/0011-use-mono-LiSa-only-for-my-setup-no-need-to-submit-pa.patch b/chuck/patches/0011-use-mono-LiSa-only-for-my-setup-no-need-to-submit-pa.patch
new file mode 100644
index 0000000..3073dbb
--- /dev/null
+++ b/chuck/patches/0011-use-mono-LiSa-only-for-my-setup-no-need-to-submit-pa.patch
@@ -0,0 +1,25 @@
+From 2bec62a6c1053fd2007540b1028e991b1e539424 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Sat, 8 Sep 2012 04:00:06 +0200
+Subject: [PATCH 11/12] use mono LiSa (only for my setup, no need to submit patch)
+
+---
+ ugen_xxx.cpp | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/src/ugen_xxx.cpp b/src/ugen_xxx.cpp
+index 17e39d6..f57bd9d 100644
+--- a/src/ugen_xxx.cpp
++++ b/src/ugen_xxx.cpp
+@@ -858,7 +858,7 @@ error:
+ }
+
+
+-#define LiSa_channels 8 //max channels for multichannel LiSa
++#define LiSa_channels 1 //max channels for multichannel LiSa
+
+ // LiSa (live sampling data offset)
+ static t_CKUINT LiSaMulti_offset_data = 0;
+--
+1.7.1
+
diff --git a/chuck/patches/0012-allow-unary-minus-on-durations.patch b/chuck/patches/0012-allow-unary-minus-on-durations.patch
new file mode 100644
index 0000000..5380e97
--- /dev/null
+++ b/chuck/patches/0012-allow-unary-minus-on-durations.patch
@@ -0,0 +1,43 @@
+From ab1269fde46f8a0c32e4ce5ba45de9e38442f6e3 Mon Sep 17 00:00:00 2001
+From: Robin Haberkorn <robin.haberkorn@googlemail.com>
+Date: Wed, 12 Sep 2012 22:58:07 +0200
+Subject: [PATCH 12/12] allow unary minus on durations
+
+there is no reason why "-1*samp" should works but not "-samp"
+---
+ chuck_emit.cpp | 3 ++-
+ chuck_type.cpp | 4 ++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/chuck_emit.cpp b/src/chuck_emit.cpp
+index 60cacc5..fdc7d9b 100644
+--- a/src/chuck_emit.cpp
++++ b/src/chuck_emit.cpp
+@@ -2590,7 +2590,8 @@ t_CKBOOL emit_engine_emit_exp_unary( Chuck_Emitter * emit, a_Exp_Unary unary )
+ // negate
+ if( equals( unary->exp->type, &t_int ) )
+ emit->append( new Chuck_Instr_Negate_int );
+- else if( equals( unary->exp->type, &t_float ) )
++ else if( equals( unary->exp->type, &t_float ) ||
++ equals( unary->exp->type, &t_dur ) )
+ emit->append( new Chuck_Instr_Negate_double );
+ else
+ {
+diff --git a/src/chuck_type.cpp b/src/chuck_type.cpp
+index 4f817b8..3b642d1 100644
+--- a/src/chuck_type.cpp
++++ b/src/chuck_type.cpp
+@@ -2041,8 +2041,8 @@ t_CKTYPE type_engine_check_exp_unary( Chuck_Env * env, a_Exp_Unary unary )
+ break;
+
+ case ae_op_minus:
+- // float
+- if( isa( t, &t_float ) ) return t;
++ // duration, float
++ if( isa( t, &t_dur ) || isa( t, &t_float ) ) return t;
+ case ae_op_tilda:
+ case ae_op_exclamation:
+ // int
+--
+1.7.1
+
diff --git a/chuck/patches/0013-crosscompile.patch b/chuck/patches/0013-crosscompile.patch
new file mode 100644
index 0000000..fed5a82
--- /dev/null
+++ b/chuck/patches/0013-crosscompile.patch
@@ -0,0 +1,35 @@
+diff --git a/makefile b/makefile
+index 077b879..134b492 100644
+--- a/src/makefile
++++ b/src/makefile
+@@ -24,11 +24,11 @@ osx linux-oss linux-jack linux-alsa win32 osx-rl: chuck
+
+ CK_VERSION=1.3.1.1
+
+-LEX=flex
+-YACC=bison
+-CC=gcc
+-CXX=gcc
+-LD=g++
++LEX?=flex
++YACC?=bison
++CC?=gcc
++CXX?=g++
++LD=$(CXX)
+
+ ifneq ($(CHUCK_STAT),)
+ CFLAGS+= -D__CHUCK_STAT_TRACK__
+@@ -120,11 +120,11 @@ chuck.yy.c: chuck.lex
+ $(LEX) -ochuck.yy.c chuck.lex
+
+ $(COBJS): %.o: %.c
+- $(CC) $(CFLAGS) $(ARCHOPTS) -c $< -o $@
++ $(CC) $(CFLAGS) $(CPPFLAGS) $(ARCHOPTS) -c $< -o $@
+ @$(CC) -MM $(CFLAGSDEPEND) $< > $*.d
+
+ $(CXXOBJS): %.o: %.cpp
+- $(CXX) $(CFLAGS) $(ARCHOPTS) -c $< -o $@
++ $(CXX) $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(ARCHOPTS) -c $< -o $@
+ @$(CXX) -MM $(CFLAGSDEPEND) $< > $*.d
+
+ clean: