changeset 285:d1762728ea4b trunk

[svn] Timidity support, via external contractor dai+audacious@cdr.jp.
author nenolod
date Wed, 14 Dec 2005 08:51:51 -0800
parents 763afa52f416
children 6975fc4f5d3b
files Plugins/Input/Makefile.am Plugins/Input/timidity/Makefile.am Plugins/Input/timidity/libtimidity/Makefile.am Plugins/Input/timidity/libtimidity/common.c Plugins/Input/timidity/libtimidity/common.h Plugins/Input/timidity/libtimidity/dls1.h Plugins/Input/timidity/libtimidity/dls2.h Plugins/Input/timidity/libtimidity/instrum.c Plugins/Input/timidity/libtimidity/instrum.h Plugins/Input/timidity/libtimidity/instrum_dls.c Plugins/Input/timidity/libtimidity/instrum_dls.h Plugins/Input/timidity/libtimidity/mix.c Plugins/Input/timidity/libtimidity/mix.h Plugins/Input/timidity/libtimidity/options.h Plugins/Input/timidity/libtimidity/output.c Plugins/Input/timidity/libtimidity/output.h Plugins/Input/timidity/libtimidity/playmidi.c Plugins/Input/timidity/libtimidity/playmidi.h Plugins/Input/timidity/libtimidity/readmidi.c Plugins/Input/timidity/libtimidity/readmidi.h Plugins/Input/timidity/libtimidity/resample.c Plugins/Input/timidity/libtimidity/resample.h Plugins/Input/timidity/libtimidity/stream.c Plugins/Input/timidity/libtimidity/tables.c Plugins/Input/timidity/libtimidity/tables.h Plugins/Input/timidity/libtimidity/timidity.c Plugins/Input/timidity/libtimidity/timidity.h Plugins/Input/timidity/libtimidity/timidity_internal.h Plugins/Input/timidity/src/Makefile.am Plugins/Input/timidity/src/callbacks.c Plugins/Input/timidity/src/callbacks.h Plugins/Input/timidity/src/interface.c Plugins/Input/timidity/src/interface.h Plugins/Input/timidity/src/xmms-timidity.c Plugins/Input/timidity/src/xmms-timidity.h configure.ac
diffstat 36 files changed, 7789 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Input/Makefile.am	Wed Dec 14 08:35:56 2005 -0800
+++ b/Plugins/Input/Makefile.am	Wed Dec 14 08:51:51 2005 -0800
@@ -1,2 +1,2 @@
-ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console wma
+ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console wma timidity
 SUBDIRS = $(INPUT_PLUGINS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/Makefile.am	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,3 @@
+if ENABLE_TIMIDITY
+SUBDIRS = libtimidity src
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/Makefile.am	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,28 @@
+noinst_LTLIBRARIES = libtimidity.la
+
+libtimidity_la_SOURCES = \
+	common.c \
+	common.h \
+	dls1.h \
+	dls2.h \
+	instrum.c \
+	instrum_dls.c \
+	instrum_dls.h \
+	instrum.h \
+	mix.c \
+	mix.h \
+	options.h \
+	output.c \
+	output.h \
+	playmidi.c \
+	playmidi.h \
+	readmidi.c \
+	readmidi.h \
+	resample.c \
+	resample.h \
+	stream.c \
+	tables.c \
+	tables.h \
+	timidity.c \
+	timidity.h \
+	timidity_internal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/common.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,137 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   common.c
+
+   */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* I guess "rb" should be right for any libc */
+#define OPEN_MODE "rb"
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "common.h"
+
+/* The paths in this list will be tried whenever we're reading a file */
+static PathList *pathlist = NULL; /* This is a linked list */
+
+/* This is meant to find and open files for reading */
+FILE *open_file(char *name)
+{
+  FILE *fp;
+
+  if (!name || !(*name))
+    {
+      DEBUG_MSG("Attempted to open nameless file.\n");
+      return 0;
+    }
+
+  /* First try the given name */
+
+  DEBUG_MSG("Trying to open %s\n", name);
+  if ((fp = fopen(name, OPEN_MODE)))
+    return fp;
+
+  if (name[0] != PATH_SEP)
+  {
+    char current_filename[1024];
+    PathList *plp = pathlist;
+    int l;
+
+    while (plp)  /* Try along the path then */
+      {
+	*current_filename = 0;
+	l = strlen(plp->path);
+	if(l)
+	  {
+	    strcpy(current_filename, plp->path);
+	    if(current_filename[l - 1] != PATH_SEP)
+	    {
+	      current_filename[l] = PATH_SEP;
+	      current_filename[l + 1] = '\0';
+	    }
+	  }
+	strcat(current_filename, name);
+	DEBUG_MSG("Trying to open %s\n", current_filename);
+	if ((fp = fopen(current_filename, OPEN_MODE)))
+	  return fp;
+	plp = plp->next;
+      }
+  }
+  
+  /* Nothing could be opened. */
+  DEBUG_MSG("Could not open %s\n", name);
+  return 0;
+}
+
+/* This'll allocate memory or die. */
+void *safe_malloc(size_t count)
+{
+  void *p;
+
+  p = malloc(count);
+  if (p == NULL)
+    DEBUG_MSG("Sorry. Couldn't malloc %d bytes.\n", count);
+
+  return p;
+}
+
+/* This adds a directory to the path list */
+void add_to_pathlist(char *s)
+{
+  PathList *plp = safe_malloc(sizeof(PathList));
+
+  if (plp == NULL)
+      return;
+
+  plp->path = safe_malloc(strlen(s) + 1);
+  if (plp->path == NULL)
+  {
+      free(plp);
+      return;
+  }
+
+  strcpy(plp->path, s);
+  plp->next = pathlist;
+  pathlist = plp;
+}
+
+void free_pathlist(void)
+{
+    PathList *plp = pathlist;
+    PathList *next;
+
+    while (plp)
+    {
+	next = plp->next;
+	free(plp->path);
+	free(plp);
+	plp = next;
+    }
+    pathlist = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/common.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,32 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   common.h
+*/
+
+typedef struct {
+  char *path;
+  void *next;
+} PathList;
+
+extern FILE *open_file(char *name);
+extern void add_to_pathlist(char *s);
+extern void *safe_malloc(size_t count);
+extern void free_pathlist(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/dls1.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,266 @@
+/*==========================================================================;
+//
+//  dls1.h
+//
+//
+//  Description:
+//
+//  Interface defines and structures for the Instrument Collection Form
+//  RIFF DLS.
+//
+//
+//  Written by Sonic Foundry 1996.  Released for public use.
+//
+//=========================================================================*/
+
+#ifndef _INC_DLS1
+#define _INC_DLS1
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+//
+// Layout of an instrument collection:
+//
+//
+// RIFF [] 'DLS ' [dlid,colh,INSTLIST,WAVEPOOL,INFOLIST]
+//
+// INSTLIST
+// LIST [] 'lins'
+//               LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+//               LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+//               LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+//
+// RGNLIST
+// LIST [] 'lrgn' 
+//               LIST [] 'rgn '  [rgnh,wsmp,wlnk,ARTLIST]
+//               LIST [] 'rgn '  [rgnh,wsmp,wlnk,ARTLIST]
+//               LIST [] 'rgn '  [rgnh,wsmp,wlnk,ARTLIST]
+//
+// ARTLIST
+// LIST [] 'lart'
+//         'art1' level 1 Articulation connection graph
+//         'art2' level 2 Articulation connection graph
+//         '3rd1' Possible 3rd party articulation structure 1
+//         '3rd2' Possible 3rd party articulation structure 2 .... and so on
+//
+// WAVEPOOL 
+// ptbl [] [pool table]
+// LIST [] 'wvpl'
+//               [path],
+//               [path],
+//               LIST [] 'wave' [dlid,RIFFWAVE]
+//               LIST [] 'wave' [dlid,RIFFWAVE]
+//               LIST [] 'wave' [dlid,RIFFWAVE]
+//               LIST [] 'wave' [dlid,RIFFWAVE]
+//               LIST [] 'wave' [dlid,RIFFWAVE]
+//
+// INFOLIST
+// LIST [] 'INFO' 
+//               'icmt' 'One of those crazy comments.'
+//               'icop' 'Copyright (C) 1996 Sonic Foundry'
+//
+/////////////////////////////////////////////////////////////////////////*/
+
+
+/*/////////////////////////////////////////////////////////////////////////
+// FOURCC's used in the DLS file
+/////////////////////////////////////////////////////////////////////////*/
+
+#define FOURCC_DLS   mmioFOURCC('D','L','S',' ')
+#define FOURCC_DLID  mmioFOURCC('d','l','i','d')
+#define FOURCC_COLH  mmioFOURCC('c','o','l','h')
+#define FOURCC_WVPL  mmioFOURCC('w','v','p','l')
+#define FOURCC_PTBL  mmioFOURCC('p','t','b','l')
+#define FOURCC_PATH  mmioFOURCC('p','a','t','h')
+#define FOURCC_wave  mmioFOURCC('w','a','v','e')
+#define FOURCC_LINS  mmioFOURCC('l','i','n','s')
+#define FOURCC_INS   mmioFOURCC('i','n','s',' ')
+#define FOURCC_INSH  mmioFOURCC('i','n','s','h')
+#define FOURCC_LRGN  mmioFOURCC('l','r','g','n')
+#define FOURCC_RGN   mmioFOURCC('r','g','n',' ')
+#define FOURCC_RGNH  mmioFOURCC('r','g','n','h')
+#define FOURCC_LART  mmioFOURCC('l','a','r','t')
+#define FOURCC_ART1  mmioFOURCC('a','r','t','1')
+#define FOURCC_WLNK  mmioFOURCC('w','l','n','k')
+#define FOURCC_WSMP  mmioFOURCC('w','s','m','p')
+#define FOURCC_VERS  mmioFOURCC('v','e','r','s')
+
+/*/////////////////////////////////////////////////////////////////////////
+// Articulation connection graph definitions 
+/////////////////////////////////////////////////////////////////////////*/
+
+/* Generic Sources */
+#define CONN_SRC_NONE              0x0000
+#define CONN_SRC_LFO               0x0001
+#define CONN_SRC_KEYONVELOCITY     0x0002
+#define CONN_SRC_KEYNUMBER         0x0003
+#define CONN_SRC_EG1               0x0004
+#define CONN_SRC_EG2               0x0005
+#define CONN_SRC_PITCHWHEEL        0x0006
+
+/* Midi Controllers 0-127 */
+#define CONN_SRC_CC1               0x0081
+#define CONN_SRC_CC7               0x0087
+#define CONN_SRC_CC10              0x008a
+#define CONN_SRC_CC11              0x008b
+
+/* Generic Destinations */
+#define CONN_DST_NONE              0x0000
+#define CONN_DST_ATTENUATION       0x0001
+#define CONN_DST_PITCH             0x0003
+#define CONN_DST_PAN               0x0004
+
+/* LFO Destinations */
+#define CONN_DST_LFO_FREQUENCY     0x0104
+#define CONN_DST_LFO_STARTDELAY    0x0105
+
+/* EG1 Destinations */
+#define CONN_DST_EG1_ATTACKTIME    0x0206
+#define CONN_DST_EG1_DECAYTIME     0x0207
+#define CONN_DST_EG1_RELEASETIME   0x0209
+#define CONN_DST_EG1_SUSTAINLEVEL  0x020a
+
+/* EG2 Destinations */
+#define CONN_DST_EG2_ATTACKTIME    0x030a
+#define CONN_DST_EG2_DECAYTIME     0x030b
+#define CONN_DST_EG2_RELEASETIME   0x030d
+#define CONN_DST_EG2_SUSTAINLEVEL  0x030e
+
+#define CONN_TRN_NONE              0x0000
+#define CONN_TRN_CONCAVE           0x0001
+
+typedef struct _DLSID {
+  ULONG    ulData1;
+  USHORT   usData2;
+  USHORT   usData3;
+  BYTE     abData4[8];
+} DLSID, FAR *LPDLSID;
+
+typedef struct _DLSVERSION {
+  DWORD    dwVersionMS;
+  DWORD    dwVersionLS;
+} DLSVERSION, FAR *LPDLSVERSION;
+                   
+
+typedef struct _CONNECTION {
+  USHORT   usSource;
+  USHORT   usControl;
+  USHORT   usDestination;
+  USHORT   usTransform;
+  LONG     lScale;
+} CONNECTION, FAR *LPCONNECTION;
+
+
+/* Level 1 Articulation Data */
+
+typedef struct _CONNECTIONLIST {
+  ULONG    cbSize;            /* size of the connection list structure */
+  ULONG    cConnections;      /* count of connections in the list */
+} CONNECTIONLIST, FAR *LPCONNECTIONLIST;
+
+
+
+/*/////////////////////////////////////////////////////////////////////////
+// Generic type defines for regions and instruments
+/////////////////////////////////////////////////////////////////////////*/
+
+typedef struct _RGNRANGE {
+  USHORT usLow;
+  USHORT usHigh;
+} RGNRANGE, FAR * LPRGNRANGE;
+
+#define F_INSTRUMENT_DRUMS      0x80000000
+
+typedef struct _MIDILOCALE {
+  ULONG ulBank;
+  ULONG ulInstrument;
+} MIDILOCALE, FAR *LPMIDILOCALE;
+
+/*/////////////////////////////////////////////////////////////////////////
+// Header structures found in an DLS file for collection, instruments, and
+// regions.
+/////////////////////////////////////////////////////////////////////////*/
+
+#define F_RGN_OPTION_SELFNONEXCLUSIVE  0x0001
+
+typedef struct _RGNHEADER {
+  RGNRANGE RangeKey;            /* Key range  */
+  RGNRANGE RangeVelocity;       /* Velocity Range  */
+  USHORT   fusOptions;          /* Synthesis options for this range */
+  USHORT   usKeyGroup;          /* Key grouping for non simultaneous play */
+                                /* 0 = no group, 1 up is group */
+                                /* for Level 1 only groups 1-15 are allowed */
+} RGNHEADER, FAR *LPRGNHEADER;
+
+typedef struct _INSTHEADER {
+  ULONG      cRegions;          /* Count of regions in this instrument */
+  MIDILOCALE Locale;            /* Intended MIDI locale of this instrument */
+} INSTHEADER, FAR *LPINSTHEADER;
+
+typedef struct _DLSHEADER {
+  ULONG      cInstruments;      /* Count of instruments in the collection */
+} DLSHEADER, FAR *LPDLSHEADER;
+
+/*////////////////////////////////////////////////////////////////////////////
+// definitions for the Wave link structure
+////////////////////////////////////////////////////////////////////////////*/
+
+/* ****  For level 1 only WAVELINK_CHANNEL_MONO is valid  **** */
+/* ulChannel allows for up to 32 channels of audio with each bit position */
+/* specifiying a channel of playback */
+
+#define WAVELINK_CHANNEL_LEFT    0x0001l
+#define WAVELINK_CHANNEL_RIGHT   0x0002l
+
+#define F_WAVELINK_PHASE_MASTER  0x0001
+
+typedef struct _WAVELINK { /* any paths or links are stored right after struct */
+  USHORT   fusOptions;     /* options flags for this wave */
+  USHORT   usPhaseGroup;   /* Phase grouping for locking channels */
+  ULONG    ulChannel;      /* channel placement */
+  ULONG    ulTableIndex;   /* index into the wave pool table, 0 based */
+} WAVELINK, FAR *LPWAVELINK;
+
+#define POOL_CUE_NULL  0xffffffffl
+
+typedef struct _POOLCUE { 
+  ULONG    ulOffset;       /* Offset to the entry in the list */
+} POOLCUE, FAR *LPPOOLCUE;
+
+typedef struct _POOLTABLE {
+  ULONG    cbSize;            /* size of the pool table structure */
+  ULONG    cCues;             /* count of cues in the list */
+} POOLTABLE, FAR *LPPOOLTABLE;
+
+/*////////////////////////////////////////////////////////////////////////////
+// Structures for the "wsmp" chunk
+////////////////////////////////////////////////////////////////////////////*/
+
+#define F_WSMP_NO_TRUNCATION     0x0001l
+#define F_WSMP_NO_COMPRESSION    0x0002l
+
+
+typedef struct _rwsmp {
+  ULONG   cbSize;
+  USHORT  usUnityNote;         /* MIDI Unity Playback Note */
+  SHORT   sFineTune;           /* Fine Tune in log tuning */
+  LONG    lAttenuation;        /* Overall Attenuation to be applied to data */
+  ULONG   fulOptions;          /* Flag options  */
+  ULONG   cSampleLoops;        /* Count of Sample loops, 0 loops is one shot */
+} WSMPL, FAR *LPWSMPL;
+
+
+/* This loop type is a normal forward playing loop which is continually */
+/* played until the envelope reaches an off threshold in the release */
+/* portion of the volume envelope */
+
+#define WLOOP_TYPE_FORWARD   0
+
+typedef struct _rloop {
+  ULONG cbSize;
+  ULONG ulType;              /* Loop Type */
+  ULONG ulStart;             /* Start of loop in samples */
+  ULONG ulLength;            /* Length of loop in samples */
+} WLOOP, FAR *LPWLOOP;
+
+#endif /*_INC_DLS1 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/dls2.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,130 @@
+/*
+ 
+ 	dls2.h
+ 	
+ 	Description:
+ 
+ 	Interface defines and structures for the DLS2 extensions of DLS.
+ 
+ 
+     Written by Microsoft 1998.  Released for public use.
+ 
+*/
+ 
+#ifndef _INC_DLS2
+#define _INC_DLS2
+ 
+/*
+     FOURCC's used in the DLS2 file, in addition to DLS1 chunks
+*/
+ 
+#define FOURCC_RGN2  mmioFOURCC('r','g','n','2')
+#define FOURCC_LAR2  mmioFOURCC('l','a','r','2')
+#define FOURCC_ART2  mmioFOURCC('a','r','t','2')
+#define FOURCC_CDL   mmioFOURCC('c','d','l',' ')
+#define FOURCC_DLID	 mmioFOURCC('d','l','i','d')
+ 
+/*
+     Articulation connection graph definitions. These are in addition to
+     the definitions in the DLS1 header.
+*/
+ 
+/* Generic Sources (in addition to DLS1 sources. */
+#define CONN_SRC_POLYPRESSURE		0x0007	/* Polyphonic Pressure */
+#define CONN_SRC_CHANNELPRESSURE		0x0008	/* Channel Pressure */
+#define CONN_SRC_VIBRATO			0x0009	/* Vibrato LFO */
+#define CONN_SRC_MONOPRESSURE       	0x000a  /* MIDI Mono pressure */
+ 
+ 
+/* Midi Controllers */
+#define CONN_SRC_CC91			0x00db	/* Reverb Send */
+#define CONN_SRC_CC93			0x00dd	/* Chorus Send */
+ 
+ 
+/* Generic Destinations */
+#define CONN_DST_GAIN			0x0001	/* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */
+#define CONN_DST_KEYNUMBER 0x0005  /* Key Number Generator */
+ 
+/* Audio Channel Output Destinations */
+#define CONN_DST_LEFT			0x0010	/* Left Channel Send */
+#define CONN_DST_RIGHT			0x0011	/* Right Channel Send */
+#define CONN_DST_CENTER			0x0012	/* Center Channel Send */
+#define CONN_DST_LEFTREAR			0x0013	/* Left Rear Channel Send */
+#define CONN_DST_RIGHTREAR			0x0014	/* Right Rear Channel Send */
+#define CONN_DST_LFE_CHANNEL		0x0015	/* LFE Channel Send */
+#define CONN_DST_CHORUS			0x0080	/* Chorus Send */
+#define CONN_DST_REVERB			0x0081	/* Reverb Send */
+ 
+/* Vibrato LFO Destinations */
+#define CONN_DST_VIB_FREQUENCY		0x0114	/* Vibrato Frequency */
+#define CONN_DST_VIB_STARTDELAY		0x0115	/* Vibrato Start Delay */
+ 
+/* EG1 Destinations */
+#define CONN_DST_EG1_DELAYTIME		0x020B	/* EG1 Delay Time */
+#define CONN_DST_EG1_HOLDTIME		0x020C	/* EG1 Hold Time */
+#define CONN_DST_EG1_SHUTDOWNTIME		0x020D	/* EG1 Shutdown Time */
+ 
+ 
+/*	EG2 Destinations */
+#define CONN_DST_EG2_DELAYTIME		0x030F	/* EG2 Delay Time */
+#define CONN_DST_EG2_HOLDTIME		0x0310	/* EG2 Hold Time */
+ 
+ 
+/* Filter Destinations */
+#define CONN_DST_FILTER_CUTOFF		0x0500	/* Filter Cutoff Frequency */
+#define CONN_DST_FILTER_Q			0x0501	/* Filter Resonance */
+ 
+ 
+/* Transforms */
+#define CONN_TRN_CONVEX			0x0002	/* Convex Transform */
+#define CONN_TRN_SWITCH			0x0003	/* Switch Transform */
+ 
+ 
+/*	Conditional chunk operators */
+ #define DLS_CDL_AND			0x0001	/* X = X & Y */
+ #define DLS_CDL_OR			0x0002	/* X = X | Y */
+ #define DLS_CDL_XOR			0x0003	/* X = X ^ Y */
+ #define DLS_CDL_ADD			0x0004	/* X = X + Y */
+ #define DLS_CDL_SUBTRACT		0x0005	/* X = X - Y */
+ #define DLS_CDL_MULTIPLY		0x0006	/* X = X * Y */
+ #define DLS_CDL_DIVIDE		0x0007	/* X = X / Y */
+ #define DLS_CDL_LOGICAL_AND	0x0008	/* X = X && Y */
+ #define DLS_CDL_LOGICAL_OR		0x0009	/* X = X || Y */
+ #define DLS_CDL_LT			0x000A	/* X = (X < Y) */
+ #define DLS_CDL_LE			0x000B	/* X = (X <= Y) */
+ #define DLS_CDL_GT			0x000C	/* X = (X > Y) */
+ #define DLS_CDL_GE			0x000D	/* X = (X >= Y) */
+ #define DLS_CDL_EQ			0x000E	/* X = (X == Y) */
+ #define DLS_CDL_NOT			0x000F	/* X = !X */
+ #define DLS_CDL_CONST		0x0010	/* 32-bit constant */
+ #define DLS_CDL_QUERY		0x0011	/* 32-bit value returned from query */
+ #define DLS_CDL_QUERYSUPPORTED	0x0012	/* Test to see if query is supported by synth */
+ 
+/*
+  Loop and release
+*/
+
+#define WLOOP_TYPE_RELEASE 1
+
+/*
+  WaveLink chunk <wlnk-ck>
+*/
+
+#define F_WAVELINK_MULTICHANNEL 0x0002
+
+
+/*
+  DLSID queries for <cdl-ck>
+*/
+
+DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+
+#endif	/* _INC_DLS2 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/instrum.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,619 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   instrum.c 
+   
+   Code to load and unload GUS-compatible instrument patches.
+
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "instrum_dls.h"
+#include "resample.h"
+#include "tables.h"
+
+static void free_instrument(MidInstrument *ip)
+{
+  MidSample *sp;
+  int i;
+  if (!ip) return;
+  for (i=0; i<ip->samples; i++)
+    {
+      sp=&(ip->sample[i]);
+      free(sp->data);
+    }
+  free(ip->sample);
+  free(ip);
+}
+
+static void free_bank(MidSong *song, int dr, int b)
+{
+  int i;
+  MidToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
+  for (i=0; i<128; i++)
+    if (bank->instrument[i])
+      {
+	/* Not that this could ever happen, of course */
+	if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT)
+	  free_instrument(bank->instrument[i]);
+	bank->instrument[i]=0;
+      }
+}
+
+static sint32 convert_envelope_rate(MidSong *song, uint8 rate)
+{
+  sint32 r;
+  
+  r = 3 - ((rate >> 6) & 0x3);
+  r *= 3;
+  r = (sint32) (rate & 0x3f) << r; /* 6.9 fixed point */
+
+  /* 15.15 fixed point. */
+  r = ((r * 44100) / song->rate) * song->control_ratio;
+
+#ifdef FAST_DECAY
+  return r << 10;
+#else
+  return r << 9;
+#endif
+}
+
+static sint32 convert_envelope_offset(uint8 offset)
+{
+  /* This is not too good... Can anyone tell me what these values mean?
+     Are they GUS-style "exponential" volumes? And what does that mean? */
+
+  /* 15.15 fixed point */
+  return offset << (7+15);
+}
+
+static sint32 convert_tremolo_sweep(MidSong *song, uint8 sweep)
+{
+  if (!sweep)
+    return 0;
+
+  return
+    ((song->control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+      (song->rate * sweep);
+}
+
+static sint32 convert_vibrato_sweep(MidSong *song, uint8 sweep,
+				    sint32 vib_control_ratio)
+{
+  if (!sweep)
+    return 0;
+
+  return
+    (sint32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT)
+	     / (double)(song->rate * sweep));
+
+  /* this was overflowing with seashore.pat
+
+      ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+      (song->rate * sweep); */
+}
+
+static sint32 convert_tremolo_rate(MidSong *song, uint8 rate)
+{
+  return
+    ((SINE_CYCLE_LENGTH * song->control_ratio * rate) << RATE_SHIFT) /
+      (TREMOLO_RATE_TUNING * song->rate);
+}
+
+static sint32 convert_vibrato_rate(MidSong *song, uint8 rate)
+{
+  /* Return a suitable vibrato_control_ratio value */
+  return
+    (VIBRATO_RATE_TUNING * song->rate) / 
+      (rate * 2 * MID_VIBRATO_SAMPLE_INCREMENTS);
+}
+
+static void reverse_data(sint16 *sp, sint32 ls, sint32 le)
+{
+  sint16 s, *ep=sp+le;
+  sp+=ls;
+  le-=ls;
+  le/=2;
+  while (le--)
+    {
+      s=*sp;
+      *sp++=*ep;
+      *ep--=s;
+    }
+}
+
+/* 
+   If panning or note_to_use != -1, it will be used for all samples,
+   instead of the sample-specific values in the instrument file. 
+
+   For note_to_use, any value <0 or >127 will be forced to 0.
+ 
+   For other parameters, 1 means yes, 0 means no, other values are
+   undefined.
+
+   TODO: do reverse loops right */
+static MidInstrument *load_instrument(MidSong *song, char *name, int percussion,
+				   int panning, int amp, int note_to_use,
+				   int strip_loop, int strip_envelope,
+				   int strip_tail)
+{
+  MidInstrument *ip;
+  MidSample *sp;
+  FILE *fp;
+  char tmp[1024];
+  int i,j,noluck=0;
+  static char *patch_ext[] = PATCH_EXT_LIST;
+
+  if (!name) return 0;
+  
+  /* Open patch file */
+  if ((fp=open_file(name)) == NULL)
+    {
+      noluck=1;
+      /* Try with various extensions */
+      for (i=0; patch_ext[i]; i++)
+	{
+	  if (strlen(name)+strlen(patch_ext[i])<1024)
+	    {
+	      strcpy(tmp, name);
+	      strcat(tmp, patch_ext[i]);
+	      if ((fp=open_file(tmp)) != NULL)
+		{
+		  noluck=0;
+		  break;
+		}
+	    }
+	}
+    }
+  
+  if (noluck)
+    {
+      DEBUG_MSG("Instrument `%s' can't be found.\n", name);
+      return 0;
+    }
+      
+  DEBUG_MSG("Loading instrument %s\n", tmp);
+  
+  /* Read some headers and do cursory sanity checks. There are loads
+     of magic offsets. This could be rewritten... */
+
+  if ((239 != fread(tmp, 1, 239, fp)) ||
+      (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
+       memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
+						      differences are */
+    {
+      DEBUG_MSG("%s: not an instrument\n", name);
+      return 0;
+    }
+  
+  if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 
+				       0 means 1 */
+    {
+      DEBUG_MSG("Can't handle patches with %d instruments\n", tmp[82]);
+      return 0;
+    }
+
+  if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
+    {
+      DEBUG_MSG("Can't handle instruments with %d layers\n", tmp[151]);
+      return 0;
+    }
+  
+  ip=safe_malloc(sizeof(MidInstrument));
+  ip->samples = tmp[198];
+  ip->sample = safe_malloc(sizeof(MidSample) * ip->samples);
+  for (i=0; i<ip->samples; i++)
+    {
+
+      uint8 fractions;
+      sint32 tmplong;
+      uint16 tmpshort;
+      uint8 tmpchar;
+
+#define READ_CHAR(thing) \
+      if (1 != fread(&tmpchar, 1, 1, fp)) goto fail; \
+      thing = tmpchar;
+#define READ_SHORT(thing) \
+      if (1 != fread(&tmpshort, 2, 1, fp)) goto fail; \
+      thing = SWAPLE16(tmpshort);
+#define READ_LONG(thing) \
+      if (1 != fread(&tmplong, 4, 1, fp)) goto fail; \
+      thing = SWAPLE32(tmplong);
+
+      fseek(fp, 7, SEEK_CUR); /* Skip the wave name */
+
+      if (1 != fread(&fractions, 1, 1, fp))
+	{
+	fail:
+	  DEBUG_MSG("Error reading sample %d\n", i);
+	  for (j=0; j<i; j++)
+	    free(ip->sample[j].data);
+	  free(ip->sample);
+	  free(ip);
+	  return 0;
+	}
+
+      sp=&(ip->sample[i]);
+      
+      READ_LONG(sp->data_length);
+      READ_LONG(sp->loop_start);
+      READ_LONG(sp->loop_end);
+      READ_SHORT(sp->sample_rate);
+      READ_LONG(sp->low_freq);
+      READ_LONG(sp->high_freq);
+      READ_LONG(sp->root_freq);
+      sp->low_vel = 0;
+      sp->high_vel = 127;
+      fseek(fp, 2, SEEK_CUR); /* Why have a "root frequency" and then
+				    * "tuning"?? */
+      
+      READ_CHAR(tmp[0]);
+
+      if (panning==-1)
+	sp->panning = (tmp[0] * 8 + 4) & 0x7f;
+      else
+	sp->panning=(uint8)(panning & 0x7F);
+
+      /* envelope, tremolo, and vibrato */
+      if (18 != fread(tmp, 1, 18, fp)) goto fail; 
+
+      if (!tmp[13] || !tmp[14])
+	{
+	  sp->tremolo_sweep_increment=
+	    sp->tremolo_phase_increment=sp->tremolo_depth=0;
+	  DEBUG_MSG(" * no tremolo\n");
+	}
+      else
+	{
+	  sp->tremolo_sweep_increment=convert_tremolo_sweep(song, tmp[12]);
+	  sp->tremolo_phase_increment=convert_tremolo_rate(song, tmp[13]);
+	  sp->tremolo_depth=tmp[14];
+	  DEBUG_MSG(" * tremolo: sweep %d, phase %d, depth %d\n",
+	       sp->tremolo_sweep_increment, sp->tremolo_phase_increment,
+	       sp->tremolo_depth);
+	}
+
+      if (!tmp[16] || !tmp[17])
+	{
+	  sp->vibrato_sweep_increment=
+	    sp->vibrato_control_ratio=sp->vibrato_depth=0;
+	  DEBUG_MSG(" * no vibrato\n");
+	}
+      else
+	{
+	  sp->vibrato_control_ratio=convert_vibrato_rate(song, tmp[16]);
+	  sp->vibrato_sweep_increment=
+	    convert_vibrato_sweep(song, tmp[15], sp->vibrato_control_ratio);
+	  sp->vibrato_depth=tmp[17];
+	  DEBUG_MSG(" * vibrato: sweep %d, ctl %d, depth %d\n",
+	       sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
+	       sp->vibrato_depth);
+
+	}
+
+      READ_CHAR(sp->modes);
+
+      fseek(fp, 40, SEEK_CUR); /* skip the useless scale frequency, scale
+				       factor (what's it mean?), and reserved
+				       space */
+
+      /* Mark this as a fixed-pitch instrument if such a deed is desired. */
+      if (note_to_use!=-1)
+	sp->note_to_use=(uint8)(note_to_use);
+      else
+	sp->note_to_use=0;
+      
+      /* seashore.pat in the Midia patch set has no Sustain. I don't
+         understand why, and fixing it by adding the Sustain flag to
+         all looped patches probably breaks something else. We do it
+         anyway. */
+	 
+      if (sp->modes & MODES_LOOPING) 
+	sp->modes |= MODES_SUSTAIN;
+
+      /* Strip any loops and envelopes we're permitted to */
+      if ((strip_loop==1) && 
+	  (sp->modes & (MODES_SUSTAIN | MODES_LOOPING | 
+			MODES_PINGPONG | MODES_REVERSE)))
+	{
+	  DEBUG_MSG(" - Removing loop and/or sustain\n");
+	  sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING | 
+			MODES_PINGPONG | MODES_REVERSE);
+	}
+
+      if (strip_envelope==1)
+	{
+	  if (sp->modes & MODES_ENVELOPE)
+	    DEBUG_MSG(" - Removing envelope\n");
+	  sp->modes &= ~MODES_ENVELOPE;
+	}
+      else if (strip_envelope != 0)
+	{
+	  /* Have to make a guess. */
+	  if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE)))
+	    {
+	      /* No loop? Then what's there to sustain? No envelope needed
+		 either... */
+	      sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE);
+	      DEBUG_MSG(" - No loop, removing sustain and envelope\n");
+	    }
+	  else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100) 
+	    {
+	      /* Envelope rates all maxed out? Envelope end at a high "offset"?
+		 That's a weird envelope. Take it out. */
+	      sp->modes &= ~MODES_ENVELOPE;
+	      DEBUG_MSG(" - Weirdness, removing envelope\n");
+	    }
+	  else if (!(sp->modes & MODES_SUSTAIN))
+	    {
+	      /* No sustain? Then no envelope.  I don't know if this is
+		 justified, but patches without sustain usually don't need the
+		 envelope either... at least the Gravis ones. They're mostly
+		 drums.  I think. */
+	      sp->modes &= ~MODES_ENVELOPE;
+	      DEBUG_MSG(" - No sustain, removing envelope\n");
+	    }
+	}
+
+      for (j=0; j<6; j++)
+	{
+	  sp->envelope_rate[j]=
+	    convert_envelope_rate(song, tmp[j]);
+	  sp->envelope_offset[j]= 
+	    convert_envelope_offset(tmp[6+j]);
+	}
+
+      /* Then read the sample data */
+      sp->data = safe_malloc(sp->data_length);
+      if (1 != fread(sp->data, sp->data_length, 1, fp))
+	goto fail;
+      
+      if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
+	{
+	  sint32 i=sp->data_length;
+	  uint8 *cp=(uint8 *)(sp->data);
+	  uint16 *tmp,*new;
+	  tmp=new=safe_malloc(sp->data_length*2);
+	  while (i--)
+	    *tmp++ = (uint16)(*cp++) << 8;
+	  cp=(uint8 *)(sp->data);
+	  sp->data = (sample_t *)new;
+	  free(cp);
+	  sp->data_length *= 2;
+	  sp->loop_start *= 2;
+	  sp->loop_end *= 2;
+	}
+#ifndef LITTLE_ENDIAN
+      else
+	/* convert to machine byte order */
+	{
+	  sint32 i=sp->data_length/2;
+	  sint16 *tmp=(sint16 *)sp->data,s;
+	  while (i--)
+	    { 
+	      s=SWAPLE16(*tmp);
+	      *tmp++=s;
+	    }
+	}
+#endif
+      
+      if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
+	{
+	  sint32 i=sp->data_length/2;
+	  sint16 *tmp=(sint16 *)sp->data;
+	  while (i--)
+	    *tmp++ ^= 0x8000;
+	}
+
+      /* Reverse reverse loops and pass them off as normal loops */
+      if (sp->modes & MODES_REVERSE)
+	{
+	  sint32 t;
+	  /* The GUS apparently plays reverse loops by reversing the
+	     whole sample. We do the same because the GUS does not SUCK. */
+
+	  DEBUG_MSG("Reverse loop in %s\n", name);
+	  reverse_data((sint16 *)sp->data, 0, sp->data_length/2);
+
+	  t=sp->loop_start;
+	  sp->loop_start=sp->data_length - sp->loop_end;
+	  sp->loop_end=sp->data_length - t;
+
+	  sp->modes &= ~MODES_REVERSE;
+	  sp->modes |= MODES_LOOPING; /* just in case */
+	}
+
+#ifdef ADJUST_SAMPLE_VOLUMES
+      if (amp!=-1)
+	sp->volume=(float)((amp) / 100.0);
+      else
+	{
+	  /* Try to determine a volume scaling factor for the sample.
+	     This is a very crude adjustment, but things sound more
+	     balanced with it. Still, this should be a runtime option. */
+	  sint32 i=sp->data_length/2;
+	  sint16 maxamp=0,a;
+	  sint16 *tmp=(sint16 *)sp->data;
+	  while (i--)
+	    {
+	      a=*tmp++;
+	      if (a<0) a=-a;
+	      if (a>maxamp)
+		maxamp=a;
+	    }
+	  sp->volume=(float)(32768.0 / maxamp);
+	  DEBUG_MSG(" * volume comp: %f\n", sp->volume);
+	}
+#else
+      if (amp!=-1)
+	sp->volume=(double)(amp) / 100.0;
+      else
+	sp->volume=1.0;
+#endif
+
+      sp->data_length /= 2; /* These are in bytes. Convert into samples. */
+      sp->loop_start /= 2;
+      sp->loop_end /= 2;
+
+      /* Then fractional samples */
+      sp->data_length <<= FRACTION_BITS;
+      sp->loop_start <<= FRACTION_BITS;
+      sp->loop_end <<= FRACTION_BITS;
+
+      /* Adjust for fractional loop points. This is a guess. Does anyone
+	 know what "fractions" really stands for? */
+      sp->loop_start |=
+	(fractions & 0x0F) << (FRACTION_BITS-4);
+      sp->loop_end |=
+	((fractions>>4) & 0x0F) << (FRACTION_BITS-4);
+
+      /* If this instrument will always be played on the same note,
+	 and it's not looped, we can resample it now. */
+      if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
+	pre_resample(song, sp);
+
+      if (strip_tail==1)
+	{
+	  /* Let's not really, just say we did. */
+	  DEBUG_MSG(" - Stripping tail\n");
+	  sp->data_length = sp->loop_end;
+	}
+    }
+
+  fclose(fp);
+  return ip;
+}
+
+static int fill_bank(MidSong *song, int dr, int b)
+{
+  int i, errors=0;
+  MidToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
+  if (!bank)
+    {
+      DEBUG_MSG("Huh. Tried to load instruments in non-existent %s %d\n",
+	   (dr) ? "drumset" : "tone bank", b);
+      return 0;
+    }
+  for (i=0; i<128; i++)
+    {
+      if (bank->instrument[i]==MAGIC_LOAD_INSTRUMENT)
+	{
+          bank->instrument[i]=load_instrument_dls(song, dr, b, i);
+          if (bank->instrument[i])
+            {
+              continue;
+            }
+	  if (!(bank->tone[i].name))
+	    {
+	      DEBUG_MSG("No instrument mapped to %s %d, program %d%s\n",
+		   (dr)? "drum set" : "tone bank", b, i, 
+		   (b!=0) ? "" : " - this instrument will not be heard");
+	      if (b!=0)
+		{
+		  /* Mark the corresponding instrument in the default
+		     bank / drumset for loading (if it isn't already) */
+		  if (!dr)
+		    {
+		      if (!(song->tonebank[0]->instrument[i]))
+			song->tonebank[0]->instrument[i] =
+			  MAGIC_LOAD_INSTRUMENT;
+		    }
+		  else
+		    {
+		      if (!(song->drumset[0]->instrument[i]))
+			song->drumset[0]->instrument[i] =
+			  MAGIC_LOAD_INSTRUMENT;
+		    }
+		}
+	      bank->instrument[i] = 0;
+	      errors++;
+	    }
+	  else if (!(bank->instrument[i] =
+		     load_instrument(song,
+				     bank->tone[i].name, 
+				     (dr) ? 1 : 0,
+				     bank->tone[i].pan,
+				     bank->tone[i].amp,
+				     (bank->tone[i].note!=-1) ? 
+				     bank->tone[i].note :
+				     ((dr) ? i : -1),
+				     (bank->tone[i].strip_loop!=-1) ?
+				     bank->tone[i].strip_loop :
+				     ((dr) ? 1 : -1),
+				     (bank->tone[i].strip_envelope != -1) ? 
+				     bank->tone[i].strip_envelope :
+				     ((dr) ? 1 : -1),
+				     bank->tone[i].strip_tail )))
+	    {
+	      DEBUG_MSG("Couldn't load instrument %s (%s %d, program %d)\n",
+		   bank->tone[i].name,
+		   (dr)? "drum set" : "tone bank", b, i);
+	      errors++;
+	    }
+	}
+    }
+  return errors;
+}
+
+int load_missing_instruments(MidSong *song)
+{
+  int i=128,errors=0;
+  while (i--)
+    {
+      if (song->tonebank[i])
+	errors+=fill_bank(song,0,i);
+      if (song->drumset[i])
+	errors+=fill_bank(song,1,i);
+    }
+  return errors;
+}
+
+void free_instruments(MidSong *song)
+{
+  int i=128;
+  while(i--)
+    {
+      if (song->tonebank[i])
+	free_bank(song, 0, i);
+      if (song->drumset[i])
+	free_bank(song, 1, i);
+    }
+}
+
+int set_default_instrument(MidSong *song, char *name)
+{
+  MidInstrument *ip;
+  if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0)))
+    return -1;
+  song->default_instrument = ip;
+  song->default_program = SPECIAL_PROGRAM;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/instrum.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,41 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   instrum.h
+
+   */
+
+/* Bits in modes: */
+#define MODES_16BIT	(1<<0)
+#define MODES_UNSIGNED	(1<<1)
+#define MODES_LOOPING	(1<<2)
+#define MODES_PINGPONG	(1<<3)
+#define MODES_REVERSE	(1<<4)
+#define MODES_SUSTAIN	(1<<5)
+#define MODES_ENVELOPE	(1<<6)
+
+/* A hack to delay instrument loading until after reading the
+   entire MIDI file. */
+#define MAGIC_LOAD_INSTRUMENT ((MidInstrument *) (-1))
+
+#define SPECIAL_PROGRAM -1
+
+extern int load_missing_instruments(MidSong *song);
+extern void free_instruments(MidSong *song);
+extern int set_default_instrument(MidSong *song, char *name);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/instrum_dls.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,1196 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   instrum.h
+
+   */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "instrum.h"
+#include "tables.h"
+#include "common.h"
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+typedef struct _RIFF_Chunk {
+    uint32 magic;
+    uint32 length;
+    uint32 subtype;
+    uint8  *data;
+    struct _RIFF_Chunk *child;
+    struct _RIFF_Chunk *next;
+} RIFF_Chunk;
+
+extern RIFF_Chunk* LoadRIFF(MidIStream *stream);
+extern void FreeRIFF(RIFF_Chunk *chunk);
+extern void PrintRIFF(RIFF_Chunk *chunk, int level);
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+#define RIFF        0x46464952        /* "RIFF" */
+#define LIST        0x5453494c        /* "LIST" */
+
+static RIFF_Chunk *AllocRIFFChunk()
+{
+    RIFF_Chunk *chunk = (RIFF_Chunk *)safe_malloc(sizeof(*chunk));
+    if ( !chunk ) return NULL;
+    memset(chunk, 0, sizeof(*chunk));
+    return chunk;
+}
+
+static void FreeRIFFChunk(RIFF_Chunk *chunk)
+{
+    if ( chunk->child ) {
+        FreeRIFFChunk(chunk->child);
+    }
+    if ( chunk->next ) {
+        FreeRIFFChunk(chunk->next);
+    }
+    free(chunk);
+}
+
+static int ChunkHasSubType(uint32 magic)
+{
+    static uint32 chunk_list[] = {
+        RIFF, LIST
+    };
+    int i;
+    for ( i = 0; i < (sizeof(chunk_list) / sizeof(uint32)); ++i ) {
+        if ( magic == chunk_list[i] ) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int ChunkHasSubChunks(uint32 magic)
+{
+    static uint32 chunk_list[] = {
+        RIFF, LIST
+    };
+    int i;
+    for ( i = 0; i < (sizeof(chunk_list) / sizeof(uint32)); ++i ) {
+        if ( magic == chunk_list[i] ) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static void LoadSubChunks(RIFF_Chunk *chunk, uint8 *data, uint32 left)
+{
+    uint8 *subchunkData;
+    uint32 subchunkDataLen;
+
+    while ( left > 8 ) {
+        RIFF_Chunk *child = AllocRIFFChunk();
+        RIFF_Chunk *next, *prev = NULL;
+        for ( next = chunk->child; next; next = next->next ) {
+            prev = next;
+        }
+        if ( prev ) {
+            prev->next = child;
+        } else {
+            chunk->child = child;
+        }
+            
+        child->magic = (data[0] <<  0) |
+                       (data[1] <<  8) |
+                       (data[2] << 16) |
+                       (data[3] << 24);
+        data += 4;
+        left -= 4;
+        child->length = (data[0] <<  0) |
+                        (data[1] <<  8) |
+                        (data[2] << 16) |
+                        (data[3] << 24);
+        data += 4;
+        left -= 4;
+        child->data = data;
+
+        if ( child->length > left ) {
+            child->length = left;
+        }
+
+        subchunkData = child->data;
+        subchunkDataLen = child->length;
+        if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) {
+            child->subtype = (subchunkData[0] <<  0) |
+                     (subchunkData[1] <<  8) |
+                     (subchunkData[2] << 16) |
+                     (subchunkData[3] << 24);
+            subchunkData += 4;
+            subchunkDataLen -= 4;
+        }
+        if ( ChunkHasSubChunks(child->magic) ) {
+            LoadSubChunks(child, subchunkData, subchunkDataLen);
+        }
+
+        data += child->length;
+        left -= child->length;
+    }
+}
+
+RIFF_Chunk *LoadRIFF(MidIStream *stream)
+{
+    RIFF_Chunk *chunk;
+    uint8 *subchunkData;
+    uint32 subchunkDataLen;
+    uint32 tmpUint32;
+
+    /* Allocate the chunk structure */
+    chunk = AllocRIFFChunk();
+
+    /* Make sure the file is in RIFF format */
+    mid_istream_read(stream, &tmpUint32, sizeof(uint32), 1);
+    chunk->magic = SWAPLE32(tmpUint32);
+    mid_istream_read(stream, &tmpUint32, sizeof(uint32), 1);
+    chunk->length = SWAPLE32(tmpUint32);
+    if ( chunk->magic != RIFF ) {
+        DEBUG_MSG("Not a RIFF file\n");
+        FreeRIFFChunk(chunk);
+        return NULL;
+    }
+    chunk->data = (uint8 *)malloc(chunk->length);
+    if ( chunk->data == NULL ) {
+	DEBUG_MSG("Out of memory\n");
+        FreeRIFFChunk(chunk);
+        return NULL;
+    }
+    if ( mid_istream_read(stream, chunk->data, chunk->length, 1) != 1 ) {
+	DEBUG_MSG("IO error\n");
+        FreeRIFF(chunk);
+        return NULL;
+    }
+    subchunkData = chunk->data;
+    subchunkDataLen = chunk->length;
+    if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) {
+        chunk->subtype = (subchunkData[0] <<  0) |
+                 (subchunkData[1] <<  8) |
+                 (subchunkData[2] << 16) |
+                 (subchunkData[3] << 24);
+        subchunkData += 4;
+        subchunkDataLen -= 4;
+    }
+    if ( ChunkHasSubChunks(chunk->magic) ) {
+        LoadSubChunks(chunk, subchunkData, subchunkDataLen);
+    }
+    return chunk;
+}
+
+void FreeRIFF(RIFF_Chunk *chunk)
+{
+    free(chunk->data);
+    FreeRIFFChunk(chunk);
+}
+
+void PrintRIFF(RIFF_Chunk *chunk, int level)
+{
+    static char prefix[128];
+
+    if ( level == sizeof(prefix)-1 ) {
+        return;
+    }
+    if ( level > 0 ) {
+        prefix[(level-1)*2] = ' ';
+        prefix[(level-1)*2+1] = ' ';
+    }
+    prefix[level*2] = '\0';
+    printf("%sChunk: %c%c%c%c (%d bytes)", prefix,
+        ((chunk->magic >>  0) & 0xFF),
+        ((chunk->magic >>  8) & 0xFF),
+        ((chunk->magic >> 16) & 0xFF),
+        ((chunk->magic >> 24) & 0xFF), chunk->length);
+    if ( chunk->subtype ) {
+        printf(" subtype: %c%c%c%c",
+            ((chunk->subtype >>  0) & 0xFF),
+            ((chunk->subtype >>  8) & 0xFF),
+            ((chunk->subtype >> 16) & 0xFF),
+            ((chunk->subtype >> 24) & 0xFF));
+    }
+    printf("\n");
+    if ( chunk->child ) {
+        printf("%s{\n", prefix);
+        PrintRIFF(chunk->child, level + 1);
+        printf("%s}\n", prefix);
+    }
+    if ( chunk->next ) {
+        PrintRIFF(chunk->next, level);
+    }
+    if ( level > 0 ) {
+        prefix[(level-1)*2] = '\0';
+    }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_dls.h  * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+/* This code is based on the DLS spec version 1.1, available at:
+    http://www.midi.org/about-midi/dls/dlsspec.shtml
+*/
+
+/* Some typedefs so the public dls headers don't need to be modified */
+#define FAR
+typedef uint8   BYTE;
+typedef sint16  SHORT;
+typedef uint16  USHORT;
+typedef uint16  WORD;
+typedef sint32  LONG;
+typedef uint32  ULONG;
+typedef uint32  DWORD;
+#define mmioFOURCC(A, B, C, D)    \
+    (((A) <<  0) | ((B) <<  8) | ((C) << 16) | ((D) << 24))
+#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M)
+
+#include "dls1.h"
+#include "dls2.h"
+
+typedef struct _WaveFMT {
+    WORD wFormatTag;
+    WORD wChannels;
+    DWORD dwSamplesPerSec;
+    DWORD dwAvgBytesPerSec;
+    WORD wBlockAlign;
+    WORD wBitsPerSample;
+} WaveFMT;
+
+typedef struct _DLS_Wave {
+    WaveFMT *format;
+    uint8 *data;
+    uint32 length;
+    WSMPL *wsmp;
+    WLOOP *wsmp_loop;
+} DLS_Wave;
+
+typedef struct _DLS_Region {
+    RGNHEADER *header;
+    WAVELINK *wlnk;
+    WSMPL *wsmp;
+    WLOOP *wsmp_loop;
+    CONNECTIONLIST *art;
+    CONNECTION *artList;
+} DLS_Region;
+
+typedef struct _DLS_Instrument {
+    const char *name;
+    INSTHEADER *header;
+    DLS_Region *regions;
+    CONNECTIONLIST *art;
+    CONNECTION *artList;
+} DLS_Instrument;
+
+struct _MidDLSPatches {
+    struct _RIFF_Chunk *chunk;
+
+    uint32 cInstruments;
+    DLS_Instrument *instruments;
+
+    POOLTABLE *ptbl;
+    POOLCUE *ptblList;
+    DLS_Wave *waveList;
+
+    const char *name;
+    const char *artist;
+    const char *copyright;
+    const char *comments;
+};
+
+extern MidDLSPatches* mid_dlspatches_load(MidIStream *stream);
+extern void mid_dlspatches_free(MidDLSPatches *chunk);
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_dls.c  * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+
+#define FOURCC_LIST    0x5453494c   /* "LIST" */
+#define FOURCC_FMT     0x20746D66   /* "fmt " */
+#define FOURCC_DATA    0x61746164   /* "data" */
+#define FOURCC_INFO    mmioFOURCC('I','N','F','O')
+#define FOURCC_IARL    mmioFOURCC('I','A','R','L')
+#define FOURCC_IART    mmioFOURCC('I','A','R','T')
+#define FOURCC_ICMS    mmioFOURCC('I','C','M','S')
+#define FOURCC_ICMT    mmioFOURCC('I','C','M','T')
+#define FOURCC_ICOP    mmioFOURCC('I','C','O','P')
+#define FOURCC_ICRD    mmioFOURCC('I','C','R','D')
+#define FOURCC_IENG    mmioFOURCC('I','E','N','G')
+#define FOURCC_IGNR    mmioFOURCC('I','G','N','R')
+#define FOURCC_IKEY    mmioFOURCC('I','K','E','Y')
+#define FOURCC_IMED    mmioFOURCC('I','M','E','D')
+#define FOURCC_INAM    mmioFOURCC('I','N','A','M')
+#define FOURCC_IPRD    mmioFOURCC('I','P','R','D')
+#define FOURCC_ISBJ    mmioFOURCC('I','S','B','J')
+#define FOURCC_ISFT    mmioFOURCC('I','S','F','T')
+#define FOURCC_ISRC    mmioFOURCC('I','S','R','C')
+#define FOURCC_ISRF    mmioFOURCC('I','S','R','F')
+#define FOURCC_ITCH    mmioFOURCC('I','T','C','H')
+
+
+static void FreeRegions(DLS_Instrument *instrument)
+{
+    if ( instrument->regions ) {
+        free(instrument->regions);
+    }
+}
+
+static void AllocRegions(DLS_Instrument *instrument)
+{
+    int datalen = (instrument->header->cRegions * sizeof(DLS_Region));
+    FreeRegions(instrument);
+    instrument->regions = (DLS_Region *)malloc(datalen);
+    if ( instrument->regions ) {
+        memset(instrument->regions, 0, datalen);
+    }
+}
+
+static void FreeInstruments(MidDLSPatches *data)
+{
+    if ( data->instruments ) {
+        uint32 i;
+        for ( i = 0; i < data->cInstruments; ++i ) {
+            FreeRegions(&data->instruments[i]);
+        }
+        free(data->instruments);
+    }
+}
+
+static void AllocInstruments(MidDLSPatches *data)
+{
+    int datalen = (data->cInstruments * sizeof(DLS_Instrument));
+    FreeInstruments(data);
+    data->instruments = (DLS_Instrument *)malloc(datalen);
+    if ( data->instruments ) {
+        memset(data->instruments, 0, datalen);
+    }
+}
+
+static void FreeWaveList(MidDLSPatches *data)
+{
+    if ( data->waveList ) {
+        free(data->waveList);
+    }
+}
+
+static void AllocWaveList(MidDLSPatches *data)
+{
+    int datalen = (data->ptbl->cCues * sizeof(DLS_Wave));
+    FreeWaveList(data);
+    data->waveList = (DLS_Wave *)malloc(datalen);
+    if ( data->waveList ) {
+        memset(data->waveList, 0, datalen);
+    }
+}
+
+static void Parse_colh(MidDLSPatches *data, RIFF_Chunk *chunk)
+{
+    data->cInstruments = SWAPLE32(*(uint32 *)chunk->data);
+    AllocInstruments(data);
+}
+
+static void Parse_insh(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+    INSTHEADER *header = (INSTHEADER *)chunk->data;
+    header->cRegions = SWAPLE32(header->cRegions);
+    header->Locale.ulBank = SWAPLE32(header->Locale.ulBank);
+    header->Locale.ulInstrument = SWAPLE32(header->Locale.ulInstrument);
+    instrument->header = header;
+    AllocRegions(instrument);
+}
+
+static void Parse_rgnh(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+    RGNHEADER *header = (RGNHEADER *)chunk->data;
+    header->RangeKey.usLow = SWAPLE16(header->RangeKey.usLow);
+    header->RangeKey.usHigh = SWAPLE16(header->RangeKey.usHigh);
+    header->RangeVelocity.usLow = SWAPLE16(header->RangeVelocity.usLow);
+    header->RangeVelocity.usHigh = SWAPLE16(header->RangeVelocity.usHigh);
+    header->fusOptions = SWAPLE16(header->fusOptions);
+    header->usKeyGroup = SWAPLE16(header->usKeyGroup);
+    region->header = header;
+}
+
+static void Parse_wlnk(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+    WAVELINK *wlnk = (WAVELINK *)chunk->data;
+    wlnk->fusOptions = SWAPLE16(wlnk->fusOptions);
+    wlnk->usPhaseGroup = SWAPLE16(wlnk->usPhaseGroup);
+    wlnk->ulChannel = SWAPLE16(wlnk->ulChannel);
+    wlnk->ulTableIndex = SWAPLE16(wlnk->ulTableIndex);
+    region->wlnk = wlnk;
+}
+
+static void Parse_wsmp(MidDLSPatches *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr)
+{
+    uint32 i;
+    WSMPL *wsmp = (WSMPL *)chunk->data;
+    WLOOP *loop;
+    wsmp->cbSize = SWAPLE32(wsmp->cbSize);
+    wsmp->usUnityNote = SWAPLE16(wsmp->usUnityNote);
+    wsmp->sFineTune = SWAPLE16(wsmp->sFineTune);
+    wsmp->lAttenuation = SWAPLE32(wsmp->lAttenuation);
+    wsmp->fulOptions = SWAPLE32(wsmp->fulOptions);
+    wsmp->cSampleLoops = SWAPLE32(wsmp->cSampleLoops);
+    loop = (WLOOP *)((uint8 *)chunk->data + wsmp->cbSize);
+    *wsmp_ptr = wsmp;
+    *wsmp_loop_ptr = loop;
+    for ( i = 0; i < wsmp->cSampleLoops; ++i ) {
+        loop->cbSize = SWAPLE32(loop->cbSize);
+        loop->ulType = SWAPLE32(loop->ulType);
+        loop->ulStart = SWAPLE32(loop->ulStart);
+        loop->ulLength = SWAPLE32(loop->ulLength);
+        ++loop;
+    }
+}
+
+static void Parse_art(MidDLSPatches *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr)
+{
+    uint32 i;
+    CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data;
+    CONNECTION *artList;
+    art->cbSize = SWAPLE32(art->cbSize);
+    art->cConnections = SWAPLE32(art->cConnections);
+    artList = (CONNECTION *)((uint8 *)chunk->data + art->cbSize);
+    *art_ptr = art;
+    *artList_ptr = artList;
+    for ( i = 0; i < art->cConnections; ++i ) {
+        artList->usSource = SWAPLE16(artList->usSource);
+        artList->usControl = SWAPLE16(artList->usControl);
+        artList->usDestination = SWAPLE16(artList->usDestination);
+        artList->usTransform = SWAPLE16(artList->usTransform);
+        artList->lScale = SWAPLE32(artList->lScale);
+        ++artList;
+    }
+}
+
+static void Parse_lart(MidDLSPatches *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr)
+{
+    /* FIXME: This only supports one set of connections */
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_ART1:
+            case FOURCC_ART2:
+                Parse_art(data, chunk, conn_ptr, connList_ptr);
+                return;
+        }
+    }
+}
+
+static void Parse_rgn(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_RGNH:
+                Parse_rgnh(data, chunk, region);
+                break;
+            case FOURCC_WLNK:
+                Parse_wlnk(data, chunk, region);
+                break;
+            case FOURCC_WSMP:
+                Parse_wsmp(data, chunk, &region->wsmp, &region->wsmp_loop);
+                break;
+            case FOURCC_LART:
+            case FOURCC_LAR2:
+                Parse_lart(data, chunk, &region->art, &region->artList);
+                break;
+        }
+    }
+}
+
+static void Parse_lrgn(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+    uint32 region = 0;
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_RGN:
+            case FOURCC_RGN2:
+                if ( region < instrument->header->cRegions ) {
+                    Parse_rgn(data, chunk, &instrument->regions[region++]);
+                }
+                break;
+        }
+    }
+}
+
+static void Parse_INFO_INS(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_INAM: /* Name */
+                instrument->name = chunk->data;
+                break;
+        }
+    }
+}
+
+static void Parse_ins(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_INSH:
+                Parse_insh(data, chunk, instrument);
+                break;
+            case FOURCC_LRGN:
+                Parse_lrgn(data, chunk, instrument);
+                break;
+            case FOURCC_LART:
+            case FOURCC_LAR2:
+                Parse_lart(data, chunk, &instrument->art, &instrument->artList);
+                break;
+            case FOURCC_INFO:
+                Parse_INFO_INS(data, chunk, instrument);
+                break;
+        }
+    }
+}
+
+static void Parse_lins(MidDLSPatches *data, RIFF_Chunk *chunk)
+{
+    uint32 instrument = 0;
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_INS:
+                if ( instrument < data->cInstruments ) {
+                    Parse_ins(data, chunk, &data->instruments[instrument++]);
+                }
+                break;
+        }
+    }
+}
+
+static void Parse_ptbl(MidDLSPatches *data, RIFF_Chunk *chunk)
+{
+    uint32 i;
+    POOLTABLE *ptbl = (POOLTABLE *)chunk->data;
+    ptbl->cbSize = SWAPLE32(ptbl->cbSize);
+    ptbl->cCues = SWAPLE32(ptbl->cCues);
+    data->ptbl = ptbl;
+    data->ptblList = (POOLCUE *)((uint8 *)chunk->data + ptbl->cbSize);
+    for ( i = 0; i < ptbl->cCues; ++i ) {
+        data->ptblList[i].ulOffset = SWAPLE32(data->ptblList[i].ulOffset);
+    }
+    AllocWaveList(data);
+}
+
+static void Parse_fmt(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+    WaveFMT *fmt = (WaveFMT *)chunk->data;
+    fmt->wFormatTag = SWAPLE16(fmt->wFormatTag);
+    fmt->wChannels = SWAPLE16(fmt->wChannels);
+    fmt->dwSamplesPerSec = SWAPLE32(fmt->dwSamplesPerSec);
+    fmt->dwAvgBytesPerSec = SWAPLE32(fmt->dwAvgBytesPerSec);
+    fmt->wBlockAlign = SWAPLE16(fmt->wBlockAlign);
+    fmt->wBitsPerSample = SWAPLE16(fmt->wBitsPerSample);
+    wave->format = fmt;
+}
+
+static void Parse_data(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+    wave->data = chunk->data;
+    wave->length = chunk->length;
+}
+
+static void Parse_wave(MidDLSPatches *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_FMT:
+                Parse_fmt(data, chunk, wave);
+                break;
+            case FOURCC_DATA:
+                Parse_data(data, chunk, wave);
+                break;
+            case FOURCC_WSMP:
+                Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop);
+                break;
+        }
+    }
+}
+
+static void Parse_wvpl(MidDLSPatches *data, RIFF_Chunk *chunk)
+{
+    uint32 wave = 0;
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_wave:
+                if ( wave < data->ptbl->cCues ) {
+                    Parse_wave(data, chunk, &data->waveList[wave++]);
+                }
+                break;
+        }
+    }
+}
+
+static void Parse_INFO_DLS(MidDLSPatches *data, RIFF_Chunk *chunk)
+{
+    for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_IARL: /* Archival Location */
+                break;
+            case FOURCC_IART: /* Artist */
+                data->artist = chunk->data;
+                break;
+            case FOURCC_ICMS: /* Commisioned */
+                break;
+            case FOURCC_ICMT: /* Comments */
+                data->comments = chunk->data;
+                break;
+            case FOURCC_ICOP: /* Copyright */
+                data->copyright = chunk->data;
+                break;
+            case FOURCC_ICRD: /* Creation Date */
+                break;
+            case FOURCC_IENG: /* Engineer */
+                break;
+            case FOURCC_IGNR: /* Genre */
+                break;
+            case FOURCC_IKEY: /* Keywords */
+                break;
+            case FOURCC_IMED: /* Medium */
+                break;
+            case FOURCC_INAM: /* Name */
+                data->name = chunk->data;
+                break;
+            case FOURCC_IPRD: /* Product */
+                break;
+            case FOURCC_ISBJ: /* Subject */
+                break;
+            case FOURCC_ISFT: /* Software */
+                break;
+            case FOURCC_ISRC: /* Source */
+                break;
+            case FOURCC_ISRF: /* Source Form */
+                break;
+            case FOURCC_ITCH: /* Technician */
+                break;
+        }
+    }
+}
+
+MidDLSPatches *mid_dlspatches_load(MidIStream *stream)
+{
+    RIFF_Chunk *chunk;
+    MidDLSPatches *data = (MidDLSPatches *)safe_malloc(sizeof(*data));
+    if ( !data ) return NULL;
+    memset(data, 0, sizeof(*data));
+
+    data->chunk = LoadRIFF(stream);
+    if ( !data->chunk ) {
+        mid_dlspatches_free(data);
+        return NULL;
+    }
+
+    for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) {
+        uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+        switch(magic) {
+            case FOURCC_COLH:
+                Parse_colh(data, chunk);
+                break;
+            case FOURCC_LINS:
+                Parse_lins(data, chunk);
+                break;
+            case FOURCC_PTBL:
+                Parse_ptbl(data, chunk);
+                break;
+            case FOURCC_WVPL:
+                Parse_wvpl(data, chunk);
+                break;
+            case FOURCC_INFO:
+                Parse_INFO_DLS(data, chunk);
+                break;
+        }
+    }
+    return data;
+}
+
+void mid_dlspatches_free(MidDLSPatches *data)
+{
+    if ( data->chunk ) {
+        FreeRIFF(data->chunk);
+    }
+    FreeInstruments(data);
+    FreeWaveList(data);
+    free(data);
+}
+
+static const char *SourceToString(USHORT usSource)
+{
+    switch(usSource) {
+        case CONN_SRC_NONE:
+            return "NONE";
+        case CONN_SRC_LFO:
+            return "LFO";
+        case CONN_SRC_KEYONVELOCITY:
+            return "KEYONVELOCITY";
+        case CONN_SRC_KEYNUMBER:
+            return "KEYNUMBER";
+        case CONN_SRC_EG1:
+            return "EG1";
+        case CONN_SRC_EG2:
+            return "EG2";
+        case CONN_SRC_PITCHWHEEL:
+            return "PITCHWHEEL";
+        case CONN_SRC_CC1:
+            return "CC1";
+        case CONN_SRC_CC7:
+            return "CC7";
+        case CONN_SRC_CC10:
+            return "CC10";
+        case CONN_SRC_CC11:
+            return "CC11";
+        case CONN_SRC_POLYPRESSURE:
+            return "POLYPRESSURE";
+        case CONN_SRC_CHANNELPRESSURE:
+            return "CHANNELPRESSURE";
+        case CONN_SRC_VIBRATO:
+            return "VIBRATO";
+        case CONN_SRC_MONOPRESSURE:
+            return "MONOPRESSURE";
+        case CONN_SRC_CC91:
+            return "CC91";
+        case CONN_SRC_CC93:
+            return "CC93";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static const char *TransformToString(USHORT usTransform)
+{
+    switch (usTransform) {
+        case CONN_TRN_NONE:
+            return "NONE";
+        case CONN_TRN_CONCAVE:
+            return "CONCAVE";
+        case CONN_TRN_CONVEX:
+            return "CONVEX";
+        case CONN_TRN_SWITCH:
+            return "SWITCH";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static const char *DestinationToString(USHORT usDestination)
+{
+    switch (usDestination) {
+        case CONN_DST_NONE:
+            return "NONE";
+        case CONN_DST_ATTENUATION:
+            return "ATTENUATION";
+        case CONN_DST_PITCH:
+            return "PITCH";
+        case CONN_DST_PAN:
+            return "PAN";
+        case CONN_DST_LFO_FREQUENCY:
+            return "LFO_FREQUENCY";
+        case CONN_DST_LFO_STARTDELAY:
+            return "LFO_STARTDELAY";
+        case CONN_DST_EG1_ATTACKTIME:
+            return "EG1_ATTACKTIME";
+        case CONN_DST_EG1_DECAYTIME:
+            return "EG1_DECAYTIME";
+        case CONN_DST_EG1_RELEASETIME:
+            return "EG1_RELEASETIME";
+        case CONN_DST_EG1_SUSTAINLEVEL:
+            return "EG1_SUSTAINLEVEL";
+        case CONN_DST_EG2_ATTACKTIME:
+            return "EG2_ATTACKTIME";
+        case CONN_DST_EG2_DECAYTIME:
+            return "EG2_DECAYTIME";
+        case CONN_DST_EG2_RELEASETIME:
+            return "EG2_RELEASETIME";
+        case CONN_DST_EG2_SUSTAINLEVEL:
+            return "EG2_SUSTAINLEVEL";
+        case CONN_DST_KEYNUMBER:
+            return "KEYNUMBER";
+        case CONN_DST_LEFT:
+            return "LEFT";
+        case CONN_DST_RIGHT:
+            return "RIGHT";
+        case CONN_DST_CENTER:
+            return "CENTER";
+        case CONN_DST_LEFTREAR:
+            return "LEFTREAR";
+        case CONN_DST_RIGHTREAR:
+            return "RIGHTREAR";
+        case CONN_DST_LFE_CHANNEL:
+            return "LFE_CHANNEL";
+        case CONN_DST_CHORUS:
+            return "CHORUS";
+        case CONN_DST_REVERB:
+            return "REVERB";
+        case CONN_DST_VIB_FREQUENCY:
+            return "VIB_FREQUENCY";
+        case CONN_DST_VIB_STARTDELAY:
+            return "VIB_STARTDELAY";
+        case CONN_DST_EG1_DELAYTIME:
+            return "EG1_DELAYTIME";
+        case CONN_DST_EG1_HOLDTIME:
+            return "EG1_HOLDTIME";
+        case CONN_DST_EG1_SHUTDOWNTIME:
+            return "EG1_SHUTDOWNTIME";
+        case CONN_DST_EG2_DELAYTIME:
+            return "EG2_DELAYTIME";
+        case CONN_DST_EG2_HOLDTIME:
+            return "EG2_HOLDTIME";
+        case CONN_DST_FILTER_CUTOFF:
+            return "FILTER_CUTOFF";
+        case CONN_DST_FILTER_Q:
+            return "FILTER_Q";
+        default:
+            return "UNKOWN";
+    }
+}
+
+static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList)
+{
+    uint32 i;
+    printf("%s Connections:\n", type);
+    for ( i = 0; i < art->cConnections; ++i ) {
+        printf("  Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n",
+            SourceToString(artList[i].usSource),
+            SourceToString(artList[i].usControl),
+            DestinationToString(artList[i].usDestination),
+            TransformToString(artList[i].usTransform),
+            artList[i].lScale);
+    }
+}
+
+static void PrintWave(DLS_Wave *wave, uint32 index)
+{
+    WaveFMT *format = wave->format;
+    if ( format ) {
+        printf("  Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length);
+    }
+    if ( wave->wsmp ) {
+        uint32 i;
+        printf("    wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote);
+        printf("    wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune);
+        printf("    wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation);
+        printf("    wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions);
+        printf("    wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops);
+        for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) {
+            WLOOP *loop = &wave->wsmp_loop[i];
+            printf("    Loop %u:\n", i);
+            printf("      ulStart = %u\n", loop->ulStart);
+            printf("      ulLength = %u\n", loop->ulLength);
+        }
+    }
+}
+
+static void PrintRegion(DLS_Region *region, uint32 index)
+{
+    printf("  Region %u:\n", index);
+    if ( region->header ) {
+        printf("    RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh);
+        printf("    RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh);
+        printf("    fusOptions = 0x%4.4hx\n", region->header->fusOptions);
+        printf("    usKeyGroup = %hu\n", region->header->usKeyGroup);
+    }
+    if ( region->wlnk ) {
+        printf("    wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions);
+        printf("    wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup);
+        printf("    wlnk->ulChannel = %u\n", region->wlnk->ulChannel);
+        printf("    wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex);
+    }
+    if ( region->wsmp ) {
+        uint32 i;
+        printf("    wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote);
+        printf("    wsmp->sFineTune = %hd\n", region->wsmp->sFineTune);
+        printf("    wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation);
+        printf("    wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions);
+        printf("    wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops);
+        for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) {
+            WLOOP *loop = &region->wsmp_loop[i];
+            printf("    Loop %u:\n", i);
+            printf("      ulStart = %u\n", loop->ulStart);
+            printf("      ulLength = %u\n", loop->ulLength);
+        }
+    }
+    if ( region->art && region->art->cConnections > 0 ) {
+        PrintArt("Region", region->art, region->artList);
+    }
+}
+
+static void PrintInstrument(DLS_Instrument *instrument, uint32 index)
+{
+    printf("Instrument %u:\n", index);
+    if ( instrument->name ) {
+        printf("  Name: %s\n", instrument->name);
+    }
+    if ( instrument->header ) {
+        uint32 i;
+        printf("  ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank);
+        printf("  ulInstrument = %u\n", instrument->header->Locale.ulInstrument);
+        printf("  Regions: %u\n", instrument->header->cRegions);
+        for ( i = 0; i < instrument->header->cRegions; ++i ) {
+            PrintRegion(&instrument->regions[i], i);
+        }
+    }
+    if ( instrument->art && instrument->art->cConnections > 0 ) {
+        PrintArt("Instrument", instrument->art, instrument->artList);
+    }
+};
+
+void PrintDLS(MidDLSPatches *data)
+{
+    printf("DLS Data:\n");
+    printf("cInstruments = %u\n", data->cInstruments); 
+    if ( data->instruments ) {
+        uint32 i;
+        for ( i = 0; i < data->cInstruments; ++i ) {
+            PrintInstrument(&data->instruments[i], i);
+        }
+    }
+    if ( data->ptbl && data->ptbl->cCues > 0 ) {
+        uint32 i;
+        printf("Cues: ");
+        for ( i = 0; i < data->ptbl->cCues; ++i ) {
+            if ( i > 0 ) {
+                printf(", ");
+            }
+            printf("%u", data->ptblList[i].ulOffset);
+        }
+        printf("\n");
+    }
+    if ( data->waveList ) {
+        uint32 i;
+        printf("Waves:\n");
+        for ( i = 0; i < data->ptbl->cCues; ++i ) {
+            PrintWave(&data->waveList[i], i);
+        }
+    }
+    if ( data->name ) {
+        printf("Name: %s\n", data->name);
+    }
+    if ( data->artist ) {
+        printf("Artist: %s\n", data->artist);
+    }
+    if ( data->copyright ) {
+        printf("Copyright: %s\n", data->copyright);
+    }
+    if ( data->comments ) {
+        printf("Comments: %s\n", data->comments);
+    }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+
+/* convert timecents to sec */
+static double to_msec(int timecent)
+{
+  if (timecent == 0x80000000 || timecent == 0)
+    return 0.0;
+  return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0);
+}
+
+/* convert decipercent to {0..1} */
+static double to_normalized_percent(int decipercent)
+{
+  return ((double)(decipercent / 65536)) / 1000.0;
+}
+
+/* convert from 8bit value to fractional offset (15.15) */
+static sint32 to_offset(int offset)
+{
+	return (sint32)offset << (7+15);
+}
+
+/* calculate ramp rate in fractional unit;
+ * diff = 8bit, time = msec
+ */
+static sint32 calc_rate(MidSong *song, int diff, int sample_rate, double msec)
+{
+    double rate;
+
+    if(msec < 6)
+      msec = 6;
+    if(diff == 0)
+      diff = 255;
+    diff <<= (7+15);
+    rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec;
+    return (sint32)rate;
+}
+
+static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination)
+{
+  ULONG i;
+  int value = 0;
+  for (i = 0; i < cConnections; ++i) {
+    CONNECTION *conn = &artList[i];
+    if(conn->usDestination == destination) {
+      // The formula for the destination is:
+      // usDestination = usDestination + usTransform(usSource * (usControl * lScale))
+      // Since we are only handling source/control of NONE and identity
+      // transform, this simplifies to: usDestination = usDestination + lScale
+      if (conn->usSource == CONN_SRC_NONE &&
+          conn->usControl == CONN_SRC_NONE &&
+          conn->usTransform == CONN_TRN_NONE)
+        value += conn->lScale;
+    }
+  }
+  return value;
+}
+
+static void load_region_dls(MidSong *song, MidSample *sample, DLS_Instrument *ins, uint32 index)
+{
+  DLS_Region *rgn = &ins->regions[index];
+  DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex];
+
+  sample->low_freq = freq_table[rgn->header->RangeKey.usLow];
+  sample->high_freq = freq_table[rgn->header->RangeKey.usHigh];
+  sample->root_freq = freq_table[rgn->wsmp->usUnityNote];
+  sample->low_vel = rgn->header->RangeVelocity.usLow;
+  sample->high_vel = rgn->header->RangeVelocity.usHigh;
+
+  sample->modes = MODES_16BIT;
+  sample->sample_rate = wave->format->dwSamplesPerSec;
+  sample->data_length = wave->length / 2;
+  sample->data = (sample_t *)safe_malloc(wave->length);
+  memcpy(sample->data, wave->data, wave->length);
+  if (rgn->wsmp->cSampleLoops) {
+    sample->modes |= (MODES_LOOPING|MODES_SUSTAIN);
+    sample->loop_start = rgn->wsmp_loop->ulStart / 2;
+    sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
+  }
+  sample->volume = 1.0f;
+
+  if (sample->modes & MODES_SUSTAIN) {
+    int value;
+    double attack, hold, decay, release; int sustain;
+    CONNECTIONLIST *art = NULL;
+    CONNECTION *artList = NULL;
+
+    if (ins->art && ins->art->cConnections > 0 && ins->artList) {
+      art = ins->art;
+      artList = ins->artList;
+    } else {
+      art = rgn->art;
+      artList = rgn->artList;
+    }
+
+    value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
+    attack = to_msec(value);
+    value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
+    hold = to_msec(value);
+    value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
+    decay = to_msec(value);
+    value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
+    release = to_msec(value);
+    value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
+    sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0);
+    value = load_connection(art->cConnections, artList, CONN_DST_PAN);
+    sample->panning = (int)((0.5 + to_normalized_percent(value)) * 127.0);
+
+/*
+printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
+*/
+
+    sample->envelope_offset[0] = to_offset(255);
+    sample->envelope_rate[0] = calc_rate(song, 255, sample->sample_rate, attack);
+
+    sample->envelope_offset[1] = to_offset(250);
+    sample->envelope_rate[1] = calc_rate(song, 5, sample->sample_rate, hold);
+
+    sample->envelope_offset[2] = to_offset(sustain);
+    sample->envelope_rate[2] = calc_rate(song, 255 - sustain, sample->sample_rate, decay);
+
+    sample->envelope_offset[3] = to_offset(0);
+    sample->envelope_rate[3] = calc_rate(song, 5 + sustain, sample->sample_rate, release);
+
+    sample->envelope_offset[4] = to_offset(0);
+    sample->envelope_rate[4] = to_offset(1);
+
+    sample->envelope_offset[5] = to_offset(0);
+    sample->envelope_rate[5] = to_offset(1);
+
+    sample->modes |= MODES_ENVELOPE;
+  }
+
+  sample->data_length <<= FRACTION_BITS;
+  sample->loop_start <<= FRACTION_BITS;
+  sample->loop_end <<= FRACTION_BITS;
+}
+
+MidInstrument *load_instrument_dls(MidSong *song, int drum, int bank, int instrument)
+{
+  MidInstrument *inst;
+  uint32 i;
+  DLS_Instrument *dls_ins;
+
+  if (!song->patches)
+   return(NULL);
+
+  drum = drum ? 0x80000000 : 0;
+  for (i = 0; i < song->patches->cInstruments; ++i) {
+    dls_ins = &song->patches->instruments[i];
+    if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum &&
+        ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == bank &&
+        dls_ins->header->Locale.ulInstrument == instrument)
+      break;
+  }
+  if (i == song->patches->cInstruments && !bank) {
+    for (i = 0; i < song->patches->cInstruments; ++i) {
+      dls_ins = &song->patches->instruments[i];
+      if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum &&
+          dls_ins->header->Locale.ulInstrument == instrument)
+        break;
+    }
+  }
+  if (i == song->patches->cInstruments) {
+    DEBUG_MSG("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank);
+    return(NULL);
+  }
+
+  inst = (MidInstrument *)safe_malloc(sizeof(*inst));
+  inst->samples = dls_ins->header->cRegions;
+  inst->sample = (MidSample *)safe_malloc(inst->samples * sizeof(*inst->sample));
+  memset(inst->sample, 0, inst->samples * sizeof(*inst->sample));
+/*
+printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples);
+*/
+  for (i = 0; i < dls_ins->header->cRegions; ++i) {
+    load_region_dls(song, &inst->sample[i], dls_ins, i);
+  }
+  return(inst);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/instrum_dls.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,24 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   instrum.h
+
+   */
+
+extern MidInstrument *load_instrument_dls(MidSong *song, int drum, int bank, int instrument);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/mix.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,569 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    Suddenly, you realize that this program is free software; you get
+    an overwhelming urge to 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 another copy of the GNU General Public
+    License along with this program; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    I bet they'll be amazed.
+
+    mix.c */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "tables.h"
+#include "resample.h"
+#include "mix.h"
+
+/* Returns 1 if envelope runs out */
+int recompute_envelope(MidSong *song, int v)
+{
+  int stage;
+
+  stage = song->voice[v].envelope_stage;
+
+  if (stage>5)
+    {
+      /* Envelope ran out. */
+      song->voice[v].status = VOICE_FREE;
+      return 1;
+    }
+
+  if (song->voice[v].sample->modes & MODES_ENVELOPE)
+    {
+      if (song->voice[v].status==VOICE_ON || song->voice[v].status==VOICE_SUSTAINED)
+	{
+	  if (stage>2)
+	    {
+	      /* Freeze envelope until note turns off. Trumpets want this. */
+	      song->voice[v].envelope_increment=0;
+	      return 0;
+	    }
+	}
+    }
+  song->voice[v].envelope_stage=stage+1;
+
+  if (song->voice[v].envelope_volume==song->voice[v].sample->envelope_offset[stage])
+    return recompute_envelope(song, v);
+  song->voice[v].envelope_target = song->voice[v].sample->envelope_offset[stage];
+  song->voice[v].envelope_increment = song->voice[v].sample->envelope_rate[stage];
+  if (song->voice[v].envelope_target < song->voice[v].envelope_volume)
+    song->voice[v].envelope_increment = -song->voice[v].envelope_increment;
+  return 0;
+}
+
+void apply_envelope_to_amp(MidSong *song, int v)
+{
+  float lamp = song->voice[v].left_amp, ramp;
+  sint32 la,ra;
+  if (song->voice[v].panned == PANNED_MYSTERY)
+    {
+      ramp = song->voice[v].right_amp;
+      if (song->voice[v].tremolo_phase_increment)
+	{
+	  lamp *= song->voice[v].tremolo_volume;
+	  ramp *= song->voice[v].tremolo_volume;
+	}
+      if (song->voice[v].sample->modes & MODES_ENVELOPE)
+	{
+	  lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+	  ramp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+	}
+
+      la = (sint32)FSCALE(lamp,AMP_BITS);
+      
+      if (la>MAX_AMP_VALUE)
+	la=MAX_AMP_VALUE;
+
+      ra = (sint32)FSCALE(ramp,AMP_BITS);
+      if (ra>MAX_AMP_VALUE)
+	ra=MAX_AMP_VALUE;
+      
+      song->voice[v].left_mix = la;
+      song->voice[v].right_mix = ra;
+    }
+  else
+    {
+      if (song->voice[v].tremolo_phase_increment)
+	lamp *= song->voice[v].tremolo_volume;
+      if (song->voice[v].sample->modes & MODES_ENVELOPE)
+	lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+
+      la = (sint32)FSCALE(lamp,AMP_BITS);
+
+      if (la>MAX_AMP_VALUE)
+	la=MAX_AMP_VALUE;
+
+      song->voice[v].left_mix = la;
+    }
+}
+
+static int update_envelope(MidSong *song, int v)
+{
+  song->voice[v].envelope_volume += song->voice[v].envelope_increment;
+  /* Why is there no ^^ operator?? */
+  if (((song->voice[v].envelope_increment < 0) &&
+       (song->voice[v].envelope_volume <= song->voice[v].envelope_target)) ||
+      ((song->voice[v].envelope_increment > 0) &&
+	   (song->voice[v].envelope_volume >= song->voice[v].envelope_target)))
+    {
+      song->voice[v].envelope_volume = song->voice[v].envelope_target;
+      if (recompute_envelope(song, v))
+	return 1;
+    }
+  return 0;
+}
+
+static void update_tremolo(MidSong *song, int v)
+{
+  sint32 depth = song->voice[v].sample->tremolo_depth << 7;
+
+  if (song->voice[v].tremolo_sweep)
+    {
+      /* Update sweep position */
+
+      song->voice[v].tremolo_sweep_position += song->voice[v].tremolo_sweep;
+      if (song->voice[v].tremolo_sweep_position >= (1 << SWEEP_SHIFT))
+	song->voice[v].tremolo_sweep=0; /* Swept to max amplitude */
+      else
+	{
+	  /* Need to adjust depth */
+	  depth *= song->voice[v].tremolo_sweep_position;
+	  depth >>= SWEEP_SHIFT;
+	}
+    }
+
+  song->voice[v].tremolo_phase += song->voice[v].tremolo_phase_increment;
+
+  /* if (song->voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<<RATE_SHIFT))
+     song->voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<<RATE_SHIFT;  */
+
+  song->voice[v].tremolo_volume = (float) 
+    (1.0 - FSCALENEG((sine(song->voice[v].tremolo_phase >> RATE_SHIFT) + 1.0)
+		    * depth * TREMOLO_AMPLITUDE_TUNING,
+		    17));
+
+  /* I'm not sure about the +1.0 there -- it makes tremoloed voices'
+     volumes on average the lower the higher the tremolo amplitude. */
+}
+
+/* Returns 1 if the note died */
+static int update_signal(MidSong *song, int v)
+{
+  if (song->voice[v].envelope_increment && update_envelope(song, v))
+    return 1;
+
+  if (song->voice[v].tremolo_phase_increment)
+    update_tremolo(song, v);
+
+  apply_envelope_to_amp(song, v);
+  return 0;
+}
+
+#define MIXATION(a)	*lp++ += (a)*s;
+
+static void mix_mystery_signal(MidSong *song, sample_t *sp, sint32 *lp, int v,
+			       int count)
+{
+  MidVoice *vp = song->voice + v;
+  final_volume_t 
+    left=vp->left_mix, 
+    right=vp->right_mix;
+  int cc;
+  sample_t s;
+
+  if (!(cc = vp->control_counter))
+    {
+      cc = song->control_ratio;
+      if (update_signal(song, v))
+	return;	/* Envelope ran out */
+      left = vp->left_mix;
+      right = vp->right_mix;
+    }
+  
+  while (count)
+    if (cc < count)
+      {
+	count -= cc;
+	while (cc--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    MIXATION(right);
+	  }
+	cc = song->control_ratio;
+	if (update_signal(song, v))
+	  return;	/* Envelope ran out */
+	left = vp->left_mix;
+	right = vp->right_mix;
+      }
+    else
+      {
+	vp->control_counter = cc - count;
+	while (count--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    MIXATION(right);
+	  }
+	return;
+      }
+}
+
+static void mix_center_signal(MidSong *song, sample_t *sp, sint32 *lp, int v,
+			      int count)
+{
+  MidVoice *vp = song->voice + v;
+  final_volume_t 
+    left=vp->left_mix;
+  int cc;
+  sample_t s;
+
+  if (!(cc = vp->control_counter))
+    {
+      cc = song->control_ratio;
+      if (update_signal(song, v))
+	return;	/* Envelope ran out */
+      left = vp->left_mix;
+    }
+  
+  while (count)
+    if (cc < count)
+      {
+	count -= cc;
+	while (cc--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    MIXATION(left);
+	  }
+	cc = song->control_ratio;
+	if (update_signal(song, v))
+	  return;	/* Envelope ran out */
+	left = vp->left_mix;
+      }
+    else
+      {
+	vp->control_counter = cc - count;
+	while (count--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    MIXATION(left);
+	  }
+	return;
+      }
+}
+
+static void mix_single_signal(MidSong *song, sample_t *sp, sint32 *lp, int v,
+			      int count)
+{
+  MidVoice *vp = song->voice + v;
+  final_volume_t 
+    left=vp->left_mix;
+  int cc;
+  sample_t s;
+  
+  if (!(cc = vp->control_counter))
+    {
+      cc = song->control_ratio;
+      if (update_signal(song, v))
+	return;	/* Envelope ran out */
+      left = vp->left_mix;
+    }
+  
+  while (count)
+    if (cc < count)
+      {
+	count -= cc;
+	while (cc--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    lp++;
+	  }
+	cc = song->control_ratio;
+	if (update_signal(song, v))
+	  return;	/* Envelope ran out */
+	left = vp->left_mix;
+      }
+    else
+      {
+	vp->control_counter = cc - count;
+	while (count--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	    lp++;
+	  }
+	return;
+      }
+}
+
+static void mix_mono_signal(MidSong *song, sample_t *sp, sint32 *lp, int v,
+			    int count)
+{
+  MidVoice *vp = song->voice + v;
+  final_volume_t 
+    left=vp->left_mix;
+  int cc;
+  sample_t s;
+  
+  if (!(cc = vp->control_counter))
+    {
+      cc = song->control_ratio;
+      if (update_signal(song, v))
+	return;	/* Envelope ran out */
+      left = vp->left_mix;
+    }
+  
+  while (count)
+    if (cc < count)
+      {
+	count -= cc;
+	while (cc--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	  }
+	cc = song->control_ratio;
+	if (update_signal(song, v))
+	  return;	/* Envelope ran out */
+	left = vp->left_mix;
+      }
+    else
+      {
+	vp->control_counter = cc - count;
+	while (count--)
+	  {
+	    s = *sp++;
+	    MIXATION(left);
+	  }
+	return;
+      }
+}
+
+static void mix_mystery(MidSong *song, sample_t *sp, sint32 *lp, int v, int count)
+{
+  final_volume_t 
+    left = song->voice[v].left_mix, 
+    right = song->voice[v].right_mix;
+  sample_t s;
+  
+  while (count--)
+    {
+      s = *sp++;
+      MIXATION(left);
+      MIXATION(right);
+    }
+}
+
+static void mix_center(MidSong *song, sample_t *sp, sint32 *lp, int v, int count)
+{
+  final_volume_t 
+    left = song->voice[v].left_mix;
+  sample_t s;
+  
+  while (count--)
+    {
+      s = *sp++;
+      MIXATION(left);
+      MIXATION(left);
+    }
+}
+
+static void mix_single(MidSong *song, sample_t *sp, sint32 *lp, int v, int count)
+{
+  final_volume_t 
+    left = song->voice[v].left_mix;
+  sample_t s;
+  
+  while (count--)
+    {
+      s = *sp++;
+      MIXATION(left);
+      lp++;
+    }
+}
+
+static void mix_mono(MidSong *song, sample_t *sp, sint32 *lp, int v, int count)
+{
+  final_volume_t 
+    left = song->voice[v].left_mix;
+  sample_t s;
+  
+  while (count--)
+    {
+      s = *sp++;
+      MIXATION(left);
+    }
+}
+
+/* Ramp a note out in c samples */
+static void ramp_out(MidSong *song, sample_t *sp, sint32 *lp, int v, sint32 c)
+{
+
+  /* should be final_volume_t, but uint8 gives trouble. */
+  sint32 left, right, li, ri;
+
+  sample_t s=0; /* silly warning about uninitialized s */
+
+  /* Fix by James Caldwell */
+  if ( c == 0 ) c = 1;
+  
+  left=song->voice[v].left_mix;
+  li=-(left/c);
+  if (!li) li=-1;
+
+  /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */
+
+  if (!(song->encoding & PE_MONO))
+    {
+      if (song->voice[v].panned==PANNED_MYSTERY)
+	{
+	  right=song->voice[v].right_mix;
+	  ri=-(right/c);
+	  while (c--)
+	    {
+	      left += li;
+	      if (left<0)
+		left=0;
+	      right += ri;
+	      if (right<0)
+		right=0;
+	      s=*sp++;
+	      MIXATION(left);
+	      MIXATION(right);
+	    }
+	}
+      else if (song->voice[v].panned==PANNED_CENTER)
+	{
+	  while (c--)
+	    {
+	      left += li;
+	      if (left<0)
+		return;
+	      s=*sp++;	
+	      MIXATION(left);
+	      MIXATION(left);
+	    }
+	}
+      else if (song->voice[v].panned==PANNED_LEFT)
+	{
+	  while (c--)
+	    {
+	      left += li;
+	      if (left<0)
+		return;
+	      s=*sp++;
+	      MIXATION(left);
+	      lp++;
+	    }
+	}
+      else if (song->voice[v].panned==PANNED_RIGHT)
+	{
+	  while (c--)
+	    {
+	      left += li;
+	      if (left<0)
+		return;
+	      s=*sp++;
+	      lp++;
+	      MIXATION(left);
+	    }
+	}
+    }
+  else
+    {
+      /* Mono output.  */
+      while (c--)
+	{
+	  left += li;
+	  if (left<0)
+	    return;
+	  s=*sp++;
+	  MIXATION(left);
+	}
+    }
+}
+
+
+/**************** interface function ******************/
+
+void mix_voice(MidSong *song, sint32 *buf, int v, sint32 c)
+{
+  MidVoice *vp = song->voice + v;
+  sample_t *sp;
+  if (vp->status==VOICE_DIE)
+    {
+      if (c>=MAX_DIE_TIME)
+	c=MAX_DIE_TIME;
+      sp=resample_voice(song, v, &c);
+      ramp_out(song, sp, buf, v, c);
+      vp->status=VOICE_FREE;
+    }
+  else
+    {
+      sp=resample_voice(song, v, &c);
+      if (song->encoding & PE_MONO)
+	{
+	  /* Mono output. */
+	  if (vp->envelope_increment || vp->tremolo_phase_increment)
+	    mix_mono_signal(song, sp, buf, v, c);
+	  else
+	    mix_mono(song, sp, buf, v, c);
+	}
+      else
+	{
+	  if (vp->panned == PANNED_MYSTERY)
+	    {
+	      if (vp->envelope_increment || vp->tremolo_phase_increment)
+		mix_mystery_signal(song, sp, buf, v, c);
+	      else
+		mix_mystery(song, sp, buf, v, c);
+	    }
+	  else if (vp->panned == PANNED_CENTER)
+	    {
+	      if (vp->envelope_increment || vp->tremolo_phase_increment)
+		mix_center_signal(song, sp, buf, v, c);
+	      else
+		mix_center(song, sp, buf, v, c);
+	    }
+	  else
+	    { 
+	      /* It's either full left or full right. In either case,
+		 every other sample is 0. Just get the offset right: */
+	      if (vp->panned == PANNED_RIGHT) buf++;
+	      
+	      if (vp->envelope_increment || vp->tremolo_phase_increment)
+		mix_single_signal(song, sp, buf, v, c);
+	      else 
+		mix_single(song, sp, buf, v, c);
+	    }
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/mix.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,27 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    In case you haven't heard, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    mix.h
+
+*/
+
+extern void mix_voice(MidSong *song, sint32 *buf, int v, sint32 c);
+extern int recompute_envelope(MidSong *song, int v);
+extern void apply_envelope_to_amp(MidSong *song, int v);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/options.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,113 @@
+/*
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* When a patch file can't be opened, one of these extensions is
+   appended to the filename and the open is tried again.
+ */
+#define PATCH_EXT_LIST { ".pat", 0 }
+
+/* Acoustic Grand Piano seems to be the usual default instrument. */
+#define DEFAULT_PROGRAM 0
+
+/* 9 here is MIDI channel 10, which is the standard percussion channel.
+   Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too. 
+   On the other hand, some files know that 16 is not a drum channel and
+   try to play music on it. This is now a runtime option, so this isn't
+   a critical choice anymore. */
+#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))
+
+/* In percent. */
+#define DEFAULT_AMPLIFICATION 	70
+
+/* Default polyphony */
+#define DEFAULT_VOICES	32
+
+/* 1000 here will give a control ratio of 22:1 with 22 kHz output.
+   Higher CONTROLS_PER_SECOND values allow more accurate rendering
+   of envelopes and tremolo. The cost is CPU time. */
+#define CONTROLS_PER_SECOND 1000
+
+/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay
+   faster) and sounds more like a GUS. There is now a command line
+   option to toggle this as well. */
+#define FAST_DECAY
+
+/* How many bits to use for the fractional part of sample positions.
+   This affects tonal accuracy. The entire position counter must fit
+   in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of
+   a sample is 1048576 samples (2 megabytes in memory). The GUS gets
+   by with just 9 bits and a little help from its friends...
+   "The GUS does not SUCK!!!" -- a happy user :) */
+#define FRACTION_BITS 12
+
+/* For some reason the sample volume is always set to maximum in all
+   patch files. Define this for a crude adjustment that may help
+   equalize instrument volumes. */
+#define ADJUST_SAMPLE_VOLUMES
+
+/* The number of samples to use for ramping out a dying note. Affects
+   click removal. */
+#define MAX_DIE_TIME 20
+
+/**************************************************************************/
+/* Anything below this shouldn't need to be changed unless you're porting
+   to a new machine with other than 32-bit, big-endian words. */
+/**************************************************************************/
+
+/* change FRACTION_BITS above, not these */
+#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS)
+#define FRACTION_MASK (~ INTEGER_MASK)
+
+/* This is enforced by some computations that must fit in an int */
+#define MAX_CONTROL_RATIO 255
+
+#define MAX_AMPLIFICATION 800
+
+/* The TiMidity configuration file */
+#define CONFIG_FILE "timidity.cfg"
+
+/* These affect general volume */
+#define GUARD_BITS 3
+#define AMP_BITS (15-GUARD_BITS)
+
+#define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1)
+
+#define FSCALE(a,b) (float)((a) * (double)(1<<(b)))
+#define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b))))
+
+/* Vibrato and tremolo Choices of the Day */
+#define SWEEP_TUNING 38
+#define VIBRATO_AMPLITUDE_TUNING 1.0L
+#define VIBRATO_RATE_TUNING 38
+#define TREMOLO_AMPLITUDE_TUNING 1.0L
+#define TREMOLO_RATE_TUNING 38
+
+#define SWEEP_SHIFT 16
+#define RATE_SHIFT 5
+
+#ifndef PI
+  #define PI 3.14159265358979323846
+#endif
+
+/* The path separator (D.M.) */
+#ifdef WIN32
+#  define PATH_SEP '\\'
+#else
+#  define PATH_SEP '/'
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/output.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,113 @@
+/* 
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    output.c
+    
+    Audio output (to file / device) functions.
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "output.h"
+
+/*****************************************************************/
+/* Some functions to convert signed 32-bit data to other formats */
+
+void s32tos8(void *dp, sint32 *lp, sint32 c)
+{
+  sint8 *cp=(sint8 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-8-GUARD_BITS);
+      if (l>127) l=127;
+      else if (l<-128) l=-128;
+      *cp++ = (sint8) (l);
+    }
+}
+
+void s32tou8(void *dp, sint32 *lp, sint32 c)
+{
+  uint8 *cp=(uint8 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-8-GUARD_BITS);
+      if (l>127) l=127;
+      else if (l<-128) l=-128;
+      *cp++ = 0x80 ^ ((uint8) l);
+    }
+}
+
+void s32tos16(void *dp, sint32 *lp, sint32 c)
+{
+  sint16 *sp=(sint16 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-16-GUARD_BITS);
+      if (l > 32767) l=32767;
+      else if (l<-32768) l=-32768;
+      *sp++ = (sint16)(l);
+    }
+}
+
+void s32tou16(void *dp, sint32 *lp, sint32 c)
+{
+  uint16 *sp=(uint16 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-16-GUARD_BITS);
+      if (l > 32767) l=32767;
+      else if (l<-32768) l=-32768;
+      *sp++ = 0x8000 ^ (uint16)(l);
+    }
+}
+
+void s32tos16x(void *dp, sint32 *lp, sint32 c)
+{
+  sint16 *sp=(sint16 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-16-GUARD_BITS);
+      if (l > 32767) l=32767;
+      else if (l<-32768) l=-32768;
+      *sp++ = XCHG_SHORT((sint16)(l));
+    }
+}
+
+void s32tou16x(void *dp, sint32 *lp, sint32 c)
+{
+  uint16 *sp=(uint16 *)(dp);
+  sint32 l;
+  while (c--)
+    {
+      l=(*lp++)>>(32-16-GUARD_BITS);
+      if (l > 32767) l=32767;
+      else if (l<-32768) l=-32768;
+      *sp++ = XCHG_SHORT(0x8000 ^ (uint16)(l));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/output.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,56 @@
+/* 
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    output.h
+
+*/
+
+/* Data format encoding bits */
+
+#define PE_MONO 	0x01  /* versus stereo */
+#define PE_SIGNED	0x02  /* versus unsigned */
+#define PE_16BIT 	0x04  /* versus 8-bit */
+
+/* Conversion functions -- These overwrite the sint32 data in *lp with
+   data in another format */
+
+/* 8-bit signed and unsigned*/
+extern void s32tos8(void *dp, sint32 *lp, sint32 c);
+extern void s32tou8(void *dp, sint32 *lp, sint32 c);
+
+/* 16-bit */
+extern void s32tos16(void *dp, sint32 *lp, sint32 c);
+extern void s32tou16(void *dp, sint32 *lp, sint32 c);
+
+/* byte-exchanged 16-bit */
+extern void s32tos16x(void *dp, sint32 *lp, sint32 c);
+extern void s32tou16x(void *dp, sint32 *lp, sint32 c);
+
+/* little-endian and big-endian specific */
+#ifdef LITTLE_ENDIAN
+#define s32tou16l s32tou16
+#define s32tou16b s32tou16x
+#define s32tos16l s32tos16
+#define s32tos16b s32tos16x
+#else
+#define s32tou16l s32tou16x
+#define s32tou16b s32tou16
+#define s32tos16l s32tos16x
+#define s32tos16b s32tos16
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/playmidi.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,804 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    playmidi.c -- random stuff in need of rearrangement
+
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "mix.h"
+#include "tables.h"
+
+static void adjust_amplification(MidSong *song)
+{ 
+  song->master_volume = (float)(song->amplification) / (float)100.0;
+}
+
+static void reset_voices(MidSong *song)
+{
+  int i;
+  for (i=0; i<MID_MAX_VOICES; i++)
+    song->voice[i].status=VOICE_FREE;
+}
+
+/* Process the Reset All Controllers event */
+static void reset_controllers(MidSong *song, int c)
+{
+  song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
+  song->channel[c].expression=127; /* SCC-1 does this. */
+  song->channel[c].sustain=0;
+  song->channel[c].pitchbend=0x2000;
+  song->channel[c].pitchfactor=0; /* to be computed */
+}
+
+static void reset_midi(MidSong *song)
+{
+  int i;
+  for (i=0; i<16; i++)
+    {
+      reset_controllers(song, i);
+      /* The rest of these are unaffected by the Reset All Controllers event */
+      song->channel[i].program=song->default_program;
+      song->channel[i].panning=NO_PANNING;
+      song->channel[i].pitchsens=2;
+      song->channel[i].bank=0; /* tone bank or drum set */
+    }
+  reset_voices(song);
+}
+
+static void select_sample(MidSong *song, int v, MidInstrument *ip, int vel)
+{
+  sint32 f, cdiff, diff;
+  int s,i;
+  MidSample *sp, *closest;
+
+  s=ip->samples;
+  sp=ip->sample;
+
+  if (s==1)
+    {
+      song->voice[v].sample=sp;
+      return;
+    }
+
+  f=song->voice[v].orig_frequency;
+  for (i=0; i<s; i++)
+    {
+      if (sp->low_vel <= vel && sp->high_vel >= vel &&
+          sp->low_freq <= f && sp->high_freq >= f)
+	{
+	  song->voice[v].sample=sp;
+	  return;
+	}
+      sp++;
+    }
+
+  /* 
+     No suitable sample found! We'll select the sample whose root
+     frequency is closest to the one we want. (Actually we should
+     probably convert the low, high, and root frequencies to MIDI note
+     values and compare those.) */
+
+  cdiff=0x7FFFFFFF;
+  closest=sp=ip->sample;
+  for(i=0; i<s; i++)
+    {
+      diff=sp->root_freq - f;
+      if (diff<0) diff=-diff;
+      if (diff<cdiff)
+	{
+	  cdiff=diff;
+	  closest=sp;
+	}
+      sp++;
+    }
+  song->voice[v].sample=closest;
+  return;
+}
+
+static void recompute_freq(MidSong *song, int v)
+{
+  int 
+    sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */
+    pb=song->channel[song->voice[v].channel].pitchbend;
+  double a;
+  
+  if (!song->voice[v].sample->sample_rate)
+    return;
+
+  if (song->voice[v].vibrato_control_ratio)
+    {
+      /* This instrument has vibrato. Invalidate any precomputed
+         sample_increments. */
+
+      int i=MID_VIBRATO_SAMPLE_INCREMENTS;
+      while (i--)
+	song->voice[v].vibrato_sample_increment[i]=0;
+    }
+
+  if (pb==0x2000 || pb<0 || pb>0x3FFF)
+    song->voice[v].frequency = song->voice[v].orig_frequency;
+  else
+    {
+      pb-=0x2000;
+      if (!(song->channel[song->voice[v].channel].pitchfactor))
+	{
+	  /* Damn. Somebody bent the pitch. */
+	  sint32 i=pb*song->channel[song->voice[v].channel].pitchsens;
+	  if (pb<0)
+	    i=-i;
+	  song->channel[song->voice[v].channel].pitchfactor=
+	    (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
+	}
+      if (pb>0)
+	song->voice[v].frequency=
+	  (sint32)(song->channel[song->voice[v].channel].pitchfactor *
+		  (double)(song->voice[v].orig_frequency));
+      else
+	song->voice[v].frequency=
+	  (sint32)((double)(song->voice[v].orig_frequency) /
+		  song->channel[song->voice[v].channel].pitchfactor);
+    }
+
+  a = FSCALE(((double)(song->voice[v].sample->sample_rate) *
+	      (double)(song->voice[v].frequency)) /
+	     ((double)(song->voice[v].sample->root_freq) *
+	      (double)(song->rate)),
+	     FRACTION_BITS);
+
+  if (sign) 
+    a = -a; /* need to preserve the loop direction */
+
+  song->voice[v].sample_increment = (sint32)(a);
+}
+
+static void recompute_amp(MidSong *song, int v)
+{
+  sint32 tempamp;
+
+  /* TODO: use fscale */
+
+  tempamp= (song->voice[v].velocity *
+	    song->channel[song->voice[v].channel].volume * 
+	    song->channel[song->voice[v].channel].expression); /* 21 bits */
+
+  if (!(song->encoding & PE_MONO))
+    {
+      if (song->voice[v].panning > 60 && song->voice[v].panning < 68)
+	{
+	  song->voice[v].panned=PANNED_CENTER;
+
+	  song->voice[v].left_amp=
+	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+		      21);
+	}
+      else if (song->voice[v].panning<5)
+	{
+	  song->voice[v].panned = PANNED_LEFT;
+
+	  song->voice[v].left_amp=
+	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+		      20);
+	}
+      else if (song->voice[v].panning>123)
+	{
+	  song->voice[v].panned = PANNED_RIGHT;
+
+	  song->voice[v].left_amp= /* left_amp will be used */
+	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+		      20);
+	}
+      else
+	{
+	  song->voice[v].panned = PANNED_MYSTERY;
+
+	  song->voice[v].left_amp=
+	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+		      27);
+	  song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning);
+	  song->voice[v].left_amp *= (float)(127 - song->voice[v].panning);
+	}
+    }
+  else
+    {
+      song->voice[v].panned = PANNED_CENTER;
+
+      song->voice[v].left_amp=
+	FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+		  21);
+    }
+}
+
+static void start_note(MidSong *song, MidEvent *e, int i)
+{
+  MidInstrument *ip;
+  int j;
+
+  if (ISDRUMCHANNEL(song, e->channel))
+    {
+      if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a]))
+	{
+	  if (!(ip=song->drumset[0]->instrument[e->a]))
+	    return; /* No instrument? Then we can't play. */
+	}
+      if (ip->samples != 1)
+	{
+	  DEBUG_MSG("Strange: percussion instrument with %d samples!\n",
+		  ip->samples);
+	}
+
+      if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
+	song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
+      else
+	song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
+      
+      /* drums are supposed to have only one sample */
+      song->voice[i].sample = ip->sample;
+    }
+  else
+    {
+      if (song->channel[e->channel].program == SPECIAL_PROGRAM)
+	ip=song->default_instrument;
+      else if (!(ip=song->tonebank[song->channel[e->channel].bank]->
+		 instrument[song->channel[e->channel].program]))
+	{
+	  if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program]))
+	    return; /* No instrument? Then we can't play. */
+	}
+
+      if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
+	song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
+      else
+	song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
+      select_sample(song, i, ip, e->b);
+    }
+
+  song->voice[i].status = VOICE_ON;
+  song->voice[i].channel = e->channel;
+  song->voice[i].note = e->a;
+  song->voice[i].velocity = e->b;
+  song->voice[i].sample_offset = 0;
+  song->voice[i].sample_increment = 0; /* make sure it isn't negative */
+
+  song->voice[i].tremolo_phase = 0;
+  song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment;
+  song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment;
+  song->voice[i].tremolo_sweep_position = 0;
+
+  song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment;
+  song->voice[i].vibrato_sweep_position = 0;
+  song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio;
+  song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0;
+  for (j=0; j<MID_VIBRATO_SAMPLE_INCREMENTS; j++)
+    song->voice[i].vibrato_sample_increment[j] = 0;
+
+  if (song->channel[e->channel].panning != NO_PANNING)
+    song->voice[i].panning = song->channel[e->channel].panning;
+  else
+    song->voice[i].panning = song->voice[i].sample->panning;
+
+  recompute_freq(song, i);
+  recompute_amp(song, i);
+  if (song->voice[i].sample->modes & MODES_ENVELOPE)
+    {
+      /* Ramp up from 0 */
+      song->voice[i].envelope_stage = 0;
+      song->voice[i].envelope_volume = 0;
+      song->voice[i].control_counter = 0;
+      recompute_envelope(song, i);
+      apply_envelope_to_amp(song, i);
+    }
+  else
+    {
+      song->voice[i].envelope_increment = 0;
+      apply_envelope_to_amp(song, i);
+    }
+}
+
+static void kill_note(MidSong *song, int i)
+{
+  song->voice[i].status = VOICE_DIE;
+}
+
+/* Only one instance of a note can be playing on a single channel. */
+static void note_on(MidSong *song)
+{
+  int i = song->voices, lowest=-1; 
+  sint32 lv=0x7FFFFFFF, v;
+  MidEvent *e = song->current_event;
+
+  while (i--)
+    {
+      if (song->voice[i].status == VOICE_FREE)
+	lowest=i; /* Can't get a lower volume than silence */
+      else if (song->voice[i].channel==e->channel && 
+	       (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono))
+	kill_note(song, i);
+    }
+
+  if (lowest != -1)
+    {
+      /* Found a free voice. */
+      start_note(song,e,lowest);
+      return;
+    }
+  
+  /* Look for the decaying note with the lowest volume */
+  i = song->voices;
+  while (i--)
+    {
+      if ((song->voice[i].status != VOICE_ON) &&
+	  (song->voice[i].status != VOICE_DIE))
+	{
+	  v = song->voice[i].left_mix;
+	  if ((song->voice[i].panned == PANNED_MYSTERY)
+	      && (song->voice[i].right_mix > v))
+	    v = song->voice[i].right_mix;
+	  if (v<lv)
+	    {
+	      lv=v;
+	      lowest=i;
+	    }
+	}
+    }
+
+  if (lowest != -1)
+    {
+      /* This can still cause a click, but if we had a free voice to
+	 spare for ramping down this note, we wouldn't need to kill it
+	 in the first place... Still, this needs to be fixed. Perhaps
+	 we could use a reserve of voices to play dying notes only. */
+      
+      song->cut_notes++;
+      song->voice[lowest].status=VOICE_FREE;
+      start_note(song,e,lowest);
+    }
+  else
+    song->lost_notes++;
+}
+
+static void finish_note(MidSong *song, int i)
+{
+  if (song->voice[i].sample->modes & MODES_ENVELOPE)
+    {
+      /* We need to get the envelope out of Sustain stage */
+      song->voice[i].envelope_stage = 3;
+      song->voice[i].status = VOICE_OFF;
+      recompute_envelope(song, i);
+      apply_envelope_to_amp(song, i);
+    }
+  else
+    {
+      /* Set status to OFF so resample_voice() will let this voice out
+         of its loop, if any. In any case, this voice dies when it
+         hits the end of its data (ofs>=data_length). */
+      song->voice[i].status = VOICE_OFF;
+    }
+}
+
+static void note_off(MidSong *song)
+{
+  int i = song->voices;
+  MidEvent *e = song->current_event;
+
+  while (i--)
+    if (song->voice[i].status == VOICE_ON &&
+	song->voice[i].channel == e->channel &&
+	song->voice[i].note == e->a)
+      {
+	if (song->channel[e->channel].sustain)
+	  {
+	    song->voice[i].status = VOICE_SUSTAINED;
+	  }
+	else
+	  finish_note(song, i);
+	return;
+      }
+}
+
+/* Process the All Notes Off event */
+static void all_notes_off(MidSong *song)
+{
+  int i = song->voices;
+  int c = song->current_event->channel;
+
+  DEBUG_MSG("All notes off on channel %d\n", c);
+  while (i--)
+    if (song->voice[i].status == VOICE_ON &&
+	song->voice[i].channel == c)
+      {
+	if (song->channel[c].sustain) 
+	  song->voice[i].status = VOICE_SUSTAINED;
+	else
+	  finish_note(song, i);
+      }
+}
+
+/* Process the All Sounds Off event */
+static void all_sounds_off(MidSong *song)
+{
+  int i = song->voices;
+  int c = song->current_event->channel;
+
+  while (i--)
+    if (song->voice[i].channel == c && 
+	song->voice[i].status != VOICE_FREE &&
+	song->voice[i].status != VOICE_DIE)
+      {
+	kill_note(song, i);
+      }
+}
+
+static void adjust_pressure(MidSong *song)
+{
+  MidEvent *e = song->current_event;
+  int i = song->voices;
+  
+  while (i--)
+    if (song->voice[i].status == VOICE_ON &&
+	song->voice[i].channel == e->channel &&
+	song->voice[i].note == e->a)
+      {
+	song->voice[i].velocity = e->b;
+	recompute_amp(song, i);
+	apply_envelope_to_amp(song, i);
+	return;
+      }
+}
+
+static void drop_sustain(MidSong *song)
+{
+  int i = song->voices;
+  int c = song->current_event->channel;
+
+  while (i--)
+    if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c)
+      finish_note(song, i);
+}
+
+static void adjust_pitchbend(MidSong *song)
+{
+  int c = song->current_event->channel;
+  int i = song->voices;
+  
+  while (i--)
+    if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c)
+      {
+	recompute_freq(song, i);
+      }
+}
+
+static void adjust_volume(MidSong *song)
+{
+  int c = song->current_event->channel;
+  int i = song->voices;
+
+  while (i--)
+    if (song->voice[i].channel == c &&
+	(song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED))
+      {
+	recompute_amp(song, i);
+	apply_envelope_to_amp(song, i);
+      }
+}
+
+static void seek_forward(MidSong *song, sint32 until_time)
+{
+  reset_voices(song);
+  while (song->current_event->time < until_time)
+    {
+      switch(song->current_event->type)
+	{
+	  /* All notes stay off. Just handle the parameter changes. */
+
+	case ME_PITCH_SENS:
+	  song->channel[song->current_event->channel].pitchsens =
+	    song->current_event->a;
+	  song->channel[song->current_event->channel].pitchfactor = 0;
+	  break;
+	  
+	case ME_PITCHWHEEL:
+	  song->channel[song->current_event->channel].pitchbend =
+	    song->current_event->a + song->current_event->b * 128;
+	  song->channel[song->current_event->channel].pitchfactor = 0;
+	  break;
+	  
+	case ME_MAINVOLUME:
+	  song->channel[song->current_event->channel].volume =
+	    song->current_event->a;
+	  break;
+	  
+	case ME_PAN:
+	  song->channel[song->current_event->channel].panning =
+	    song->current_event->a;
+	  break;
+	      
+	case ME_EXPRESSION:
+	  song->channel[song->current_event->channel].expression =
+	    song->current_event->a;
+	  break;
+	  
+	case ME_PROGRAM:
+	  if (ISDRUMCHANNEL(song, song->current_event->channel))
+	    /* Change drum set */
+	    song->channel[song->current_event->channel].bank =
+	      song->current_event->a;
+	  else
+	    song->channel[song->current_event->channel].program =
+	      song->current_event->a;
+	  break;
+
+	case ME_SUSTAIN:
+	  song->channel[song->current_event->channel].sustain =
+	    song->current_event->a;
+	  break;
+
+	case ME_RESET_CONTROLLERS:
+	  reset_controllers(song, song->current_event->channel);
+	  break;
+	      
+	case ME_TONE_BANK:
+	  song->channel[song->current_event->channel].bank =
+	    song->current_event->a;
+	  break;
+	  
+	case ME_EOT:
+	  song->current_sample = song->current_event->time;
+	  return;
+	}
+      song->current_event++;
+    }
+  /*song->current_sample=song->current_event->time;*/
+  if (song->current_event != song->events)
+    song->current_event--;
+  song->current_sample=until_time;
+}
+
+static void skip_to(MidSong *song, sint32 until_time)
+{
+  if (song->current_sample > until_time)
+    song->current_sample = 0;
+
+  reset_midi(song);
+  song->current_event = song->events;
+  
+  if (until_time)
+    seek_forward(song, until_time);
+}
+
+static void do_compute_data(MidSong *song, sint32 count)
+{
+  int i;
+  memset(song->common_buffer, 0, 
+	 (song->encoding & PE_MONO) ? (count * 4) : (count * 8));
+  for (i = 0; i < song->voices; i++)
+    {
+      if(song->voice[i].status != VOICE_FREE)
+					mix_voice(song, song->common_buffer, i, count);
+    }
+  song->current_sample += count;
+}
+
+/* count=0 means flush remaining buffered data to output device, then
+   flush the device itself */
+static void compute_data(MidSong *song, sint8 **stream, sint32 count)
+{
+  int channels;
+
+  if ( song->encoding & PE_MONO )
+    channels = 1;
+  else
+    channels = 2;
+
+  while (count)
+	  {
+			sint32 block = count;
+			if (block > song->buffer_size)
+					block = song->buffer_size;
+      do_compute_data(song, block);
+			song->write(*stream, song->common_buffer, channels * block);
+			*stream += song->bytes_per_sample * block;
+			count -= block;
+		}
+}
+
+void mid_song_start(MidSong *song)
+{
+  song->playing = 1;
+  adjust_amplification(song);
+  skip_to(song, 0);
+}
+
+void mid_song_seek(MidSong *song, uint32 ms)
+{
+    skip_to(song, (ms * (song->rate / 100)) / 10);
+}
+
+uint32 mid_song_get_total_time(MidSong *song)
+{
+  MidEvent *last_event = &song->events[song->groomed_event_count - 1];
+  /* We want last_event->time * 1000 / song->rate */
+  uint32 retvalue = (last_event->time / song->rate) * 1000;
+  retvalue       += (last_event->time % song->rate) * 1000 / song->rate;
+  return retvalue;
+}
+
+uint32 mid_song_get_time(MidSong *song)
+{
+  uint32 retvalue = (song->current_sample / song->rate) * 1000;
+  retvalue       += (song->current_sample % song->rate) * 1000 / song->rate;
+  return retvalue;
+}
+
+char *mid_song_get_meta(MidSong *song, MidSongMetaId what)
+{
+  return song->meta_data[what];
+}
+
+size_t mid_song_read_wave(MidSong *song, void *ptr, size_t size)
+{
+  sint32 start_sample, end_sample, samples;
+
+  if (!song->playing)
+    return 0;
+  
+  samples = size / song->bytes_per_sample;
+  
+  start_sample = song->current_sample;
+  end_sample = song->current_sample+samples;
+  while ( song->current_sample < end_sample ) {
+    /* Handle all events that should happen at this time */
+    while (song->current_event->time <= song->current_sample) {
+      switch(song->current_event->type) {
+
+        /* Effects affecting a single note */
+
+        case ME_NOTEON:
+          if (!(song->current_event->b)) /* Velocity 0? */
+            note_off(song);
+          else
+            note_on(song);
+          break;
+  
+        case ME_NOTEOFF:
+          note_off(song);
+          break;
+  
+        case ME_KEYPRESSURE:
+          adjust_pressure(song);
+          break;
+  
+          /* Effects affecting a single channel */
+  
+        case ME_PITCH_SENS:
+          song->channel[song->current_event->channel].pitchsens =
+	    song->current_event->a;
+          song->channel[song->current_event->channel].pitchfactor = 0;
+          break;
+          
+        case ME_PITCHWHEEL:
+          song->channel[song->current_event->channel].pitchbend =
+            song->current_event->a + song->current_event->b * 128;
+          song->channel[song->current_event->channel].pitchfactor = 0;
+          /* Adjust pitch for notes already playing */
+          adjust_pitchbend(song);
+          break;
+          
+        case ME_MAINVOLUME:
+          song->channel[song->current_event->channel].volume =
+	    song->current_event->a;
+          adjust_volume(song);
+          break;
+          
+        case ME_PAN:
+          song->channel[song->current_event->channel].panning =
+	    song->current_event->a;
+          break;
+          
+        case ME_EXPRESSION:
+          song->channel[song->current_event->channel].expression =
+	    song->current_event->a;
+          adjust_volume(song);
+          break;
+  
+        case ME_PROGRAM:
+          if (ISDRUMCHANNEL(song, song->current_event->channel)) {
+            /* Change drum set */
+            song->channel[song->current_event->channel].bank =
+	      song->current_event->a;
+          }
+          else
+            song->channel[song->current_event->channel].program =
+	      song->current_event->a;
+          break;
+  
+        case ME_SUSTAIN:
+          song->channel[song->current_event->channel].sustain =
+	    song->current_event->a;
+          if (!song->current_event->a)
+            drop_sustain(song);
+          break;
+          
+        case ME_RESET_CONTROLLERS:
+          reset_controllers(song, song->current_event->channel);
+          break;
+  
+        case ME_ALL_NOTES_OFF:
+          all_notes_off(song);
+          break;
+          
+        case ME_ALL_SOUNDS_OFF:
+          all_sounds_off(song);
+          break;
+          
+        case ME_TONE_BANK:
+          song->channel[song->current_event->channel].bank =
+	    song->current_event->a;
+          break;
+  
+        case ME_EOT:
+          /* Give the last notes a couple of seconds to decay  */
+          DEBUG_MSG("Playing time: ~%d seconds\n",
+		  song->current_sample/song->rate+2);
+          DEBUG_MSG("Notes cut: %d\n", song->cut_notes);
+          DEBUG_MSG("Notes lost totally: %d\n", song->lost_notes);
+	  song->playing = 0;
+          return (song->current_sample - start_sample) * song->bytes_per_sample;
+        }
+      song->current_event++;
+    }
+    if (song->current_event->time > end_sample)
+      compute_data(song, (sint8 **)&ptr, end_sample-song->current_sample);
+    else
+      compute_data(song, (sint8 **)&ptr, song->current_event->time-song->current_sample);
+  }
+  return samples * song->bytes_per_sample;
+}
+
+void mid_song_set_volume(MidSong *song, int volume)
+{
+  int i;
+  if (volume > MAX_AMPLIFICATION)
+    song->amplification = MAX_AMPLIFICATION;
+  else
+  if (volume < 0)
+    song->amplification = 0;
+  else
+    song->amplification = volume;
+  adjust_amplification(song);
+  for (i = 0; i < song->voices; i++)
+    if (song->voice[i].status != VOICE_FREE)
+      {
+        recompute_amp(song, i);
+        apply_envelope_to_amp(song, i);
+      }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/playmidi.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,64 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   playmidi.h
+
+   */
+
+/* Midi events */
+#define ME_NONE 	0
+#define ME_NOTEON	1
+#define ME_NOTEOFF	2
+#define ME_KEYPRESSURE	3
+#define ME_MAINVOLUME	4
+#define ME_PAN		5
+#define ME_SUSTAIN	6
+#define ME_EXPRESSION	7
+#define ME_PITCHWHEEL	8
+#define ME_PROGRAM	9
+#define ME_TEMPO	10
+#define ME_PITCH_SENS	11
+
+#define ME_ALL_SOUNDS_OFF	12
+#define ME_RESET_CONTROLLERS	13
+#define ME_ALL_NOTES_OFF	14
+#define ME_TONE_BANK	15
+
+#define ME_LYRIC	16
+
+#define ME_EOT		99
+
+/* Causes the instrument's default panning to be used. */
+#define NO_PANNING -1
+
+/* Voice status options: */
+#define VOICE_FREE 0
+#define VOICE_ON 1
+#define VOICE_SUSTAINED 2
+#define VOICE_OFF 3
+#define VOICE_DIE 4
+
+/* Voice panned options: */
+#define PANNED_MYSTERY 0
+#define PANNED_LEFT 1
+#define PANNED_RIGHT 2
+#define PANNED_CENTER 3
+/* Anything but PANNED_MYSTERY only uses the left volume */
+
+#define ISDRUMCHANNEL(s, c) (((s)->drumchannels & (1<<(c))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/readmidi.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,596 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+
+/* Computes how many (fractional) samples one MIDI delta-time unit contains */
+static void compute_sample_increment(MidSong *song, sint32 tempo,
+				     sint32 divisions)
+{
+  double a;
+  a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) /
+    (double)(divisions);
+
+  song->sample_correction = (sint32)(a) & 0xFFFF;
+  song->sample_increment = (sint32)(a) >> 16;
+
+  DEBUG_MSG("Samples per delta-t: %d (correction %d)\n",
+	  song->sample_increment, song->sample_correction);
+}
+
+/* Read variable-length number (7 bits per byte, MSB first) */
+static sint32 getvl(MidIStream *stream)
+{
+  sint32 l=0;
+  uint8 c;
+  for (;;)
+    {
+      mid_istream_read(stream, &c, 1, 1);
+      l += (c & 0x7f);
+      if (!(c & 0x80)) return l;
+      l<<=7;
+    }
+}
+
+/* Print a string from the file, followed by a newline. Any non-ASCII
+   or unprintable characters will be converted to periods. */
+static int read_meta_data(MidIStream *stream, sint32 len, uint8 type, MidSong *song)
+{
+  char *s=safe_malloc(len+1);
+  MidSongMetaId id;
+  static char *label[] = {
+    "Text event: ", "Text: ", "Copyright: ", "Track name: ",
+    "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};
+
+  if (len != (sint32) mid_istream_read(stream, s, 1, len))
+    {
+      free(s);
+      return -1;
+    }
+  s[len]='\0';
+  while (len--)
+    {
+      if (((unsigned char)s[len])<32)
+	s[len]='.';
+    }
+  DEBUG_MSG("%s%s\n", label[(type > 7) ? 0 : type], s);
+
+  switch (type)
+  {
+    case 1: id = MID_SONG_TEXT; break;
+    case 2: id = MID_SONG_COPYRIGHT; break;
+    default: free(s); s = NULL;
+  }
+  if (s)
+    {
+      if (song->meta_data[id])
+	free(song->meta_data[id]);
+      song->meta_data[id] = s;
+    }
+	
+  return 0;
+}
+
+#define MIDIEVENT(at,t,ch,pa,pb) \
+  new=safe_malloc(sizeof(MidEventList)); \
+  new->event.time=at; new->event.type=t; new->event.channel=ch; \
+  new->event.a=pa; new->event.b=pb; new->next=0;\
+  return new;
+
+#define MAGIC_EOT ((MidEventList *)(-1))
+
+/* Read a MIDI event, returning a freshly allocated element that can
+   be linked to the event list */
+static MidEventList *read_midi_event(MidIStream *stream, MidSong *song)
+{
+  static uint8 laststatus, lastchan;
+  static uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */
+  uint8 me, type, a,b,c;
+  sint32 len;
+  MidEventList *new;
+
+  for (;;)
+    {
+      song->at += getvl(stream);
+      if (mid_istream_read(stream, &me, 1, 1) != 1)
+	{
+	  DEBUG_MSG("read_midi_event: mid_istream_read() failure\n");
+	  return 0;
+	}
+      
+      if(me==0xF0 || me == 0xF7) /* SysEx event */
+	{
+	  len=getvl(stream);
+	  mid_istream_skip(stream, len);
+	}
+      else if(me==0xFF) /* Meta event */
+	{
+	  mid_istream_read(stream, &type, 1, 1);
+	  len=getvl(stream);
+	  if (type>0 && type<16)
+	    {
+	      read_meta_data(stream, len, type, song);
+	    }
+	  else
+	    switch(type)
+	      {
+	      case 0x2F: /* End of Track */
+		return MAGIC_EOT;
+
+	      case 0x51: /* Tempo */
+		mid_istream_read(stream, &a, 1, 1);
+		mid_istream_read(stream, &b, 1, 1);
+		mid_istream_read(stream, &c, 1, 1);
+		MIDIEVENT(song->at, ME_TEMPO, c, a, b);
+		
+	      default:
+		DEBUG_MSG("(Meta event type 0x%02x, length %d)\n", type, len);
+		mid_istream_skip(stream, len);
+		break;
+	      }
+	}
+      else
+	{
+	  a=me;
+	  if (a & 0x80) /* status byte */
+	    {
+	      lastchan=a & 0x0F;
+	      laststatus=(a>>4) & 0x07;
+	      mid_istream_read(stream, &a, 1, 1);
+	      a &= 0x7F;
+	    }
+	  switch(laststatus)
+	    {
+	    case 0: /* Note off */
+	      mid_istream_read(stream, &b, 1, 1);
+	      b &= 0x7F;
+	      MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b);
+
+	    case 1: /* Note on */
+	      mid_istream_read(stream, &b, 1, 1);
+	      b &= 0x7F;
+	      MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b);
+
+	    case 2: /* Key Pressure */
+	      mid_istream_read(stream, &b, 1, 1);
+	      b &= 0x7F;
+	      MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b);
+
+	    case 3: /* Control change */
+	      mid_istream_read(stream, &b, 1, 1);
+	      b &= 0x7F;
+	      {
+		int control=255;
+		switch(a)
+		  {
+		  case 7: control=ME_MAINVOLUME; break;
+		  case 10: control=ME_PAN; break;
+		  case 11: control=ME_EXPRESSION; break;
+		  case 64: control=ME_SUSTAIN; break;
+		  case 120: control=ME_ALL_SOUNDS_OFF; break;
+		  case 121: control=ME_RESET_CONTROLLERS; break;
+		  case 123: control=ME_ALL_NOTES_OFF; break;
+
+		    /* These should be the SCC-1 tone bank switch
+		       commands. I don't know why there are two, or
+		       why the latter only allows switching to bank 0.
+		       Also, some MIDI files use 0 as some sort of
+		       continuous controller. This will cause lots of
+		       warnings about undefined tone banks. */
+		  case 0: control=ME_TONE_BANK; break;
+		  case 32: 
+		    if (b!=0)
+		      DEBUG_MSG("(Strange: tone bank change 0x20%02x)\n", b);
+		    else
+		      control=ME_TONE_BANK;
+		    break;
+
+		  case 100: nrpn=0; rpn_msb[lastchan]=b; break;
+		  case 101: nrpn=0; rpn_lsb[lastchan]=b; break;
+		  case 99: nrpn=1; rpn_msb[lastchan]=b; break;
+		  case 98: nrpn=1; rpn_lsb[lastchan]=b; break;
+		    
+		  case 6:
+		    if (nrpn)
+		      {
+			DEBUG_MSG("(Data entry (MSB) for NRPN %02x,%02x: %d)\n",
+				rpn_msb[lastchan], rpn_lsb[lastchan], b);
+			break;
+		      }
+		    
+		    switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan])
+		      {
+		      case 0x0000: /* Pitch bend sensitivity */
+			control=ME_PITCH_SENS;
+			break;
+
+		      case 0x7F7F: /* RPN reset */
+			/* reset pitch bend sensitivity to 2 */
+			MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0);
+
+		      default:
+			DEBUG_MSG("(Data entry (MSB) for RPN %02x,%02x: %d)\n",
+				rpn_msb[lastchan], rpn_lsb[lastchan], b);
+			break;
+		      }
+		    break;
+		    
+		  default:
+		    DEBUG_MSG("(Control %d: %d)\n", a, b);
+		    break;
+		  }
+		if (control != 255)
+		  { 
+		    MIDIEVENT(song->at, control, lastchan, b, 0); 
+		  }
+	      }
+	      break;
+
+	    case 4: /* Program change */
+	      a &= 0x7f;
+	      MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0);
+
+	    case 5: /* Channel pressure - NOT IMPLEMENTED */
+	      break;
+
+	    case 6: /* Pitch wheel */
+	      mid_istream_read(stream, &b, 1, 1);
+	      b &= 0x7F;
+	      MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b);
+
+	    default: 
+	      DEBUG_MSG("*** Can't happen: status 0x%02X, channel 0x%02X\n",
+		      laststatus, lastchan);
+	      break;
+	    }
+	}
+    }
+  
+  return new;
+}
+
+#undef MIDIEVENT
+
+/* Read a midi track into the linked list, either merging with any previous
+   tracks or appending to them. */
+static int read_track(MidIStream *stream, MidSong *song, int append)
+{
+  MidEventList *meep;
+  MidEventList *next, *new;
+  sint32 len;
+  char tmp[4];
+
+  meep = song->evlist;
+  if (append && meep)
+    {
+      /* find the last event in the list */
+      for (; meep->next; meep=meep->next)
+	;
+      song->at = meep->event.time;
+    }
+  else
+    song->at=0;
+
+  /* Check the formalities */
+  
+  if (mid_istream_read(stream, tmp, 1, 4) != 4 || mid_istream_read(stream, &len, 4, 1) != 1)
+    {
+      DEBUG_MSG("Can't read track header.\n");
+      return -1;
+    }
+  len=SWAPBE32(len);
+  if (memcmp(tmp, "MTrk", 4))
+    {
+      DEBUG_MSG("Corrupt MIDI file.\n");
+      return -2;
+    }
+
+  for (;;)
+    {
+      if (!(new=read_midi_event(stream, song))) /* Some kind of error  */
+	return -2;
+
+      if (new==MAGIC_EOT) /* End-of-track Hack. */
+	{
+	  return 0;
+	}
+
+      next=meep->next;
+      while (next && (next->event.time < new->event.time))
+	{
+	  meep=next;
+	  next=meep->next;
+	}
+	  
+      new->next=next;
+      meep->next=new;
+
+      song->event_count++; /* Count the event. (About one?) */
+      meep=new;
+    }
+}
+
+/* Free the linked event list from memory. */
+static void free_midi_list(MidSong *song)
+{
+  MidEventList *meep, *next;
+  if (!(meep = song->evlist)) return;
+  while (meep)
+    {
+      next=meep->next;
+      free(meep);
+      meep=next;
+    }
+  song->evlist=0;
+}
+
+/* Allocate an array of MidiEvents and fill it from the linked list of
+   events, marking used instruments for loading. Convert event times to
+   samples: handle tempo changes. Strip unnecessary events from the list.
+   Free the linked list. */
+static MidEvent *groom_list(MidSong *song, sint32 divisions,sint32 *eventsp,
+			     sint32 *samplesp)
+{
+  MidEvent *groomed_list, *lp;
+  MidEventList *meep;
+  sint32 i, our_event_count, tempo, skip_this_event, new_value;
+  sint32 sample_cum, samples_to_do, at, st, dt, counting_time;
+
+  int current_bank[16], current_set[16], current_program[16]; 
+  /* Or should each bank have its own current program? */
+
+  for (i=0; i<16; i++)
+    {
+      current_bank[i]=0;
+      current_set[i]=0;
+      current_program[i]=song->default_program;
+    }
+
+  tempo=500000;
+  compute_sample_increment(song, tempo, divisions);
+
+  /* This may allocate a bit more than we need */
+  groomed_list=lp=safe_malloc(sizeof(MidEvent) * (song->event_count+1));
+  meep=song->evlist;
+
+  our_event_count=0;
+  st=at=sample_cum=0;
+  counting_time=2; /* We strip any silence before the first NOTE ON. */
+
+  for (i = 0; i < song->event_count; i++)
+    {
+      skip_this_event=0;
+
+      if (meep->event.type==ME_TEMPO)
+	{
+	  tempo=
+	    meep->event.channel + meep->event.b * 256 + meep->event.a * 65536;
+	  compute_sample_increment(song, tempo, divisions);
+	  skip_this_event=1;
+	}
+      else switch (meep->event.type)
+	{
+	case ME_PROGRAM:
+	  if (ISDRUMCHANNEL(song, meep->event.channel))
+	    {
+	      if (song->drumset[meep->event.a]) /* Is this a defined drumset? */
+		new_value=meep->event.a;
+	      else
+		{
+		  DEBUG_MSG("Drum set %d is undefined\n", meep->event.a);
+		  new_value=meep->event.a=0;
+		}
+	      if (current_set[meep->event.channel] != new_value)
+		current_set[meep->event.channel]=new_value;
+	      else 
+		skip_this_event=1;
+	    }
+	  else
+	    {
+	      new_value=meep->event.a;
+	      if ((current_program[meep->event.channel] != SPECIAL_PROGRAM)
+		  && (current_program[meep->event.channel] != new_value))
+		current_program[meep->event.channel] = new_value;
+	      else
+		skip_this_event=1;
+	    }
+	  break;
+
+	case ME_NOTEON:
+	  if (counting_time)
+	    counting_time=1;
+	  if (ISDRUMCHANNEL(song, meep->event.channel))
+	    {
+	      /* Mark this instrument to be loaded */
+	      if (!(song->drumset[current_set[meep->event.channel]]
+		    ->instrument[meep->event.a]))
+		song->drumset[current_set[meep->event.channel]]
+		  ->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT;
+	    }
+	  else
+	    {
+	      if (current_program[meep->event.channel]==SPECIAL_PROGRAM)
+		break;
+	      /* Mark this instrument to be loaded */
+	      if (!(song->tonebank[current_bank[meep->event.channel]]
+		    ->instrument[current_program[meep->event.channel]]))
+		song->tonebank[current_bank[meep->event.channel]]
+		  ->instrument[current_program[meep->event.channel]] =
+		    MAGIC_LOAD_INSTRUMENT;
+	    }
+	  break;
+
+	case ME_TONE_BANK:
+	  if (ISDRUMCHANNEL(song, meep->event.channel))
+	    {
+	      skip_this_event=1;
+	      break;
+	    }
+	  if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */
+	    new_value=meep->event.a;
+	  else 
+	    {
+	      DEBUG_MSG("Tone bank %d is undefined\n", meep->event.a);
+	      new_value=meep->event.a=0;
+	    }
+	  if (current_bank[meep->event.channel]!=new_value)
+	    current_bank[meep->event.channel]=new_value;
+	  else
+	    skip_this_event=1;
+	  break;
+	}
+
+      /* Recompute time in samples*/
+      if ((dt=meep->event.time - at) && !counting_time)
+	{
+	  samples_to_do = song->sample_increment * dt;
+	  sample_cum += song->sample_correction * dt;
+	  if (sample_cum & 0xFFFF0000)
+	    {
+	      samples_to_do += ((sample_cum >> 16) & 0xFFFF);
+	      sample_cum &= 0x0000FFFF;
+	    }
+	  st += samples_to_do;
+	}
+      else if (counting_time==1) counting_time=0;
+      if (!skip_this_event)
+	{
+	  /* Add the event to the list */
+	  *lp=meep->event;
+	  lp->time=st;
+	  lp++;
+	  our_event_count++;
+	}
+      at=meep->event.time;
+      meep=meep->next;
+    }
+  /* Add an End-of-Track event */
+  lp->time=st;
+  lp->type=ME_EOT;
+  our_event_count++;
+  free_midi_list(song);
+
+  *eventsp=our_event_count;
+  *samplesp=st;
+  return groomed_list;
+}
+
+MidEvent *read_midi_file(MidIStream *stream, MidSong *song, sint32 *count, sint32 *sp)
+{
+  sint32 len, divisions;
+  sint16 format, tracks, divisions_tmp;
+  int i;
+  char tmp[4];
+
+  song->event_count=0;
+  song->at=0;
+  song->evlist=0;
+
+  if (mid_istream_read(stream, tmp, 1, 4) != 4 || mid_istream_read(stream, &len, 4, 1) != 1)
+    {
+      DEBUG_MSG("Not a MIDI file!\n");
+      return 0;
+    }
+  len=SWAPBE32(len);
+  if (memcmp(tmp, "MThd", 4) || len < 6)
+    {
+      DEBUG_MSG("Not a MIDI file!\n");
+      return 0;
+    }
+
+  mid_istream_read(stream, &format, 2, 1);
+  mid_istream_read(stream, &tracks, 2, 1);
+  mid_istream_read(stream, &divisions_tmp, 2, 1);
+  format=SWAPBE16(format);
+  tracks=SWAPBE16(tracks);
+  divisions_tmp=SWAPBE16(divisions_tmp);
+
+  if (divisions_tmp<0)
+    {
+      /* SMPTE time -- totally untested. Got a MIDI file that uses this? */
+      divisions=
+	(sint32)(-(divisions_tmp/256)) * (sint32)(divisions_tmp & 0xFF);
+    }
+  else divisions=(sint32)(divisions_tmp);
+
+  if (len > 6)
+    {
+      DEBUG_MSG("MIDI file header size %u bytes", len);
+      mid_istream_skip(stream, len-6); /* skip the excess */
+    }
+  if (format<0 || format >2)
+    {
+      DEBUG_MSG("Unknown MIDI file format %d\n", format);
+      return 0;
+    }
+  DEBUG_MSG("Format: %d  Tracks: %d  Divisions: %d\n",
+	  format, tracks, divisions);
+
+  /* Put a do-nothing event first in the list for easier processing */
+  song->evlist=safe_malloc(sizeof(MidEventList));
+  song->evlist->event.time=0;
+  song->evlist->event.type=ME_NONE;
+  song->evlist->next=0;
+  song->event_count++;
+
+  switch(format)
+    {
+    case 0:
+      if (read_track(stream, song, 0))
+	{
+	  free_midi_list(song);
+	  return 0;
+	}
+      break;
+
+    case 1:
+      for (i=0; i<tracks; i++)
+	if (read_track(stream, song, 0))
+	  {
+	    free_midi_list(song);
+	    return 0;
+	  }
+      break;
+
+    case 2: /* We simply play the tracks sequentially */
+      for (i=0; i<tracks; i++)
+	if (read_track(stream, song, 1))
+	  {
+	    free_midi_list(song);
+	    return 0;
+	  }
+      break;
+    }
+  return groom_list(song, divisions, count, sp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/readmidi.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,24 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   readmidi.h 
+   
+   */
+
+extern MidEvent *read_midi_file(MidIStream *stream, MidSong *song, sint32 *count, sint32 *sp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/resample.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,608 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    resample.c
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "tables.h"
+#include "resample.h"
+
+/*************** resampling with fixed increment *****************/
+
+static sample_t *rs_plain(MidSong *song, int v, sint32 *countptr)
+{
+
+  /* Play sample until end, then free the voice. */
+
+  sample_t v1, v2;
+  MidVoice 
+    *vp=&(song->voice[v]);
+  sample_t 
+    *dest=song->resample_buffer,
+    *src=vp->sample->data;
+  sint32 
+    ofs=vp->sample_offset,
+    incr=vp->sample_increment,
+    le=vp->sample->data_length,
+    count=*countptr;
+  sint32 i;
+
+  if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
+
+  /* Precalc how many times we should go through the loop.
+     NOTE: Assumes that incr > 0 and that ofs <= le */
+  i = (le - ofs) / incr + 1;
+
+  if (i > count)
+    {
+      i = count;
+      count = 0;
+    } 
+  else count -= i;
+
+  while (i--) 
+    {
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS)+1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+      ofs += incr;
+    }
+
+  if (ofs >= le) 
+    {
+      if (ofs == le)
+	*dest++ = src[ofs >> FRACTION_BITS];
+      vp->status=VOICE_FREE;
+      *countptr-=count+1;
+    }
+  
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_loop(MidSong *song, MidVoice *vp, sint32 count)
+{
+
+  /* Play sample until end-of-loop, skip back and continue. */
+
+  sample_t v1, v2;
+  sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end, 
+    ll=le - vp->sample->loop_start;
+  sample_t
+    *dest=song->resample_buffer,
+    *src=vp->sample->data;
+  sint32 i;
+  
+  while (count) 
+    {
+      if (ofs >= le)
+	/* NOTE: Assumes that ll > incr and that incr > 0. */
+	ofs -= ll;
+      /* Precalc how many times we should go through the loop */
+      i = (le - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+    }
+
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_bidir(MidSong *song, MidVoice *vp, sint32 count)
+{
+  sample_t v1, v2;
+  sint32 
+    ofs=vp->sample_offset,
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end,
+    ls=vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  sint32
+    le2 = le<<1, 
+    ls2 = ls<<1,
+    i;
+  /* Play normally until inside the loop region */
+
+  if (ofs <= ls) 
+    {
+      /* NOTE: Assumes that incr > 0, which is NOT always the case
+	 when doing bidirectional looping.  I have yet to see a case
+	 where both ofs <= ls AND incr < 0, however. */
+      i = (ls - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+    }
+
+  /* Then do the bidirectional looping */
+  
+  while(count) 
+    {
+      /* Precalc how many times we should go through the loop */
+      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (ofs>=le) 
+	{
+	  /* fold the overshoot back in */
+	  ofs = le2 - ofs;
+	  incr *= -1;
+	} 
+      else if (ofs <= ls) 
+	{
+	  ofs = ls2 - ofs;
+	  incr *= -1;
+	}
+    }
+
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+/*********************** vibrato versions ***************************/
+
+/* We only need to compute one half of the vibrato sine cycle */
+static int vib_phase_to_inc_ptr(int phase)
+{
+  if (phase < MID_VIBRATO_SAMPLE_INCREMENTS/2)
+    return MID_VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
+  else if (phase >= 3*MID_VIBRATO_SAMPLE_INCREMENTS/2)
+    return 5*MID_VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
+  else
+    return phase-MID_VIBRATO_SAMPLE_INCREMENTS/2;
+}
+
+static sint32 update_vibrato(MidSong *song, MidVoice *vp, int sign)
+{
+  sint32 depth;
+  int phase, pb;
+  double a;
+
+  if (vp->vibrato_phase++ >= 2*MID_VIBRATO_SAMPLE_INCREMENTS-1)
+    vp->vibrato_phase=0;
+  phase=vib_phase_to_inc_ptr(vp->vibrato_phase);
+  
+  if (vp->vibrato_sample_increment[phase])
+    {
+      if (sign)
+	return -vp->vibrato_sample_increment[phase];
+      else
+	return vp->vibrato_sample_increment[phase];
+    }
+
+  /* Need to compute this sample increment. */
+    
+  depth=vp->sample->vibrato_depth<<7;
+
+  if (vp->vibrato_sweep)
+    {
+      /* Need to update sweep */
+      vp->vibrato_sweep_position += vp->vibrato_sweep;
+      if (vp->vibrato_sweep_position >= (1<<SWEEP_SHIFT))
+	vp->vibrato_sweep=0;
+      else
+	{
+	  /* Adjust depth */
+	  depth *= vp->vibrato_sweep_position;
+	  depth >>= SWEEP_SHIFT;
+	}
+    }
+
+  a = FSCALE(((double)(vp->sample->sample_rate) *
+	      (double)(vp->frequency)) /
+	     ((double)(vp->sample->root_freq) *
+	      (double)(song->rate)),
+	     FRACTION_BITS);
+
+  pb=(int)((sine(vp->vibrato_phase * 
+		 (SINE_CYCLE_LENGTH/(2*MID_VIBRATO_SAMPLE_INCREMENTS)))
+	    * (double)(depth) * VIBRATO_AMPLITUDE_TUNING));
+
+  if (pb<0)
+    {
+      pb=-pb;
+      a /= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
+    }
+  else
+    a *= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
+  
+  /* If the sweep's over, we can store the newly computed sample_increment */
+  if (!vp->vibrato_sweep)
+    vp->vibrato_sample_increment[phase]=(sint32) a;
+
+  if (sign)
+    a = -a; /* need to preserve the loop direction */
+
+  return (sint32) a;
+}
+
+static sample_t *rs_vib_plain(MidSong *song, int v, sint32 *countptr)
+{
+
+  /* Play sample until end, then free the voice. */
+
+  sample_t v1, v2;
+  MidVoice *vp=&(song->voice[v]);
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  sint32 
+    le=vp->sample->data_length,
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment, 
+    count=*countptr;
+  int 
+    cc=vp->vibrato_control_counter;
+
+  /* This has never been tested */
+
+  if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
+
+  while (count--)
+    {
+      if (!cc--)
+	{
+	  cc=vp->vibrato_control_ratio;
+	  incr=update_vibrato(song, vp, 0);
+	}
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS)+1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+      ofs += incr;
+      if (ofs >= le)
+	{
+	  if (ofs == le)
+	    *dest++ = src[ofs >> FRACTION_BITS];
+	  vp->status=VOICE_FREE;
+	  *countptr-=count+1;
+	  break;
+	}
+    }
+  
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_vib_loop(MidSong *song, MidVoice *vp, sint32 count)
+{
+
+  /* Play sample until end-of-loop, skip back and continue. */
+  
+  sample_t v1, v2;
+  sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment, 
+    le=vp->sample->loop_end,
+    ll=le - vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  int 
+    cc=vp->vibrato_control_counter;
+  sint32 i;
+  int
+    vibflag=0;
+
+  while (count) 
+    {
+      /* Hopefully the loop is longer than an increment */
+      if(ofs >= le)
+	ofs -= ll;
+      /* Precalc how many times to go through the loop, taking
+	 the vibrato control ratio into account this time. */
+      i = (le - ofs) / incr + 1;
+      if(i > count) i = count;
+      if(i > cc)
+	{
+	  i = cc;
+	  vibflag = 1;
+	} 
+      else cc -= i;
+      count -= i;
+      while(i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if(vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, 0);
+	  vibflag = 0;
+	}
+    }
+
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_vib_bidir(MidSong *song, MidVoice *vp, sint32 count)
+{
+  sample_t v1, v2;
+  sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end, 
+    ls=vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  int 
+    cc=vp->vibrato_control_counter;
+  sint32
+    le2=le<<1,
+    ls2=ls<<1,
+    i;
+  int
+    vibflag = 0;
+
+  /* Play normally until inside the loop region */
+  while (count && (ofs <= ls)) 
+    {
+      i = (ls - ofs) / incr + 1;
+      if (i > count) i = count;
+      if (i > cc) 
+	{
+	  i = cc;
+	  vibflag = 1;
+	} 
+      else cc -= i;
+      count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, 0);
+	  vibflag = 0;
+	}
+    }
+  
+  /* Then do the bidirectional looping */
+
+  while (count) 
+    {
+      /* Precalc how many times we should go through the loop */
+      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+      if(i > count) i = count;
+      if(i > cc) 
+	{
+	  i = cc;
+	  vibflag = 1;
+	} 
+      else cc -= i;
+      count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, (incr < 0));
+	  vibflag = 0;
+	}
+      if (ofs >= le) 
+	{
+	  /* fold the overshoot back in */
+	  ofs = le2 - ofs;
+	  incr *= -1;
+	} 
+      else if (ofs <= ls) 
+	{
+	  ofs = ls2 - ofs;
+	  incr *= -1;
+	}
+    }
+
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+sample_t *resample_voice(MidSong *song, int v, sint32 *countptr)
+{
+  sint32 ofs;
+  uint8 modes;
+  MidVoice *vp=&(song->voice[v]);
+  
+  if (!(vp->sample->sample_rate))
+    {
+      /* Pre-resampled data -- just update the offset and check if
+         we're out of data. */
+      ofs=vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use
+						 FRACTION_BITS here... */
+      if (*countptr >= (vp->sample->data_length>>FRACTION_BITS) - ofs)
+	{
+	  /* Note finished. Free the voice. */
+	  vp->status = VOICE_FREE;
+	  
+	  /* Let the caller know how much data we had left */
+	  *countptr = (vp->sample->data_length>>FRACTION_BITS) - ofs;
+	}
+      else
+	vp->sample_offset += *countptr << FRACTION_BITS;
+      
+      return vp->sample->data+ofs;
+    }
+
+  /* Need to resample. Use the proper function. */
+  modes=vp->sample->modes;
+
+  if (vp->vibrato_control_ratio)
+    {
+      if ((modes & MODES_LOOPING) &&
+	  ((modes & MODES_ENVELOPE) ||
+	   (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+	{
+	  if (modes & MODES_PINGPONG)
+	    return rs_vib_bidir(song, vp, *countptr);
+	  else
+	    return rs_vib_loop(song, vp, *countptr);
+	}
+      else
+	return rs_vib_plain(song, v, countptr);
+    }
+  else
+    {
+      if ((modes & MODES_LOOPING) &&
+	  ((modes & MODES_ENVELOPE) ||
+	   (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+	{
+	  if (modes & MODES_PINGPONG)
+	    return rs_bidir(song, vp, *countptr);
+	  else
+	    return rs_loop(song, vp, *countptr);
+	}
+      else
+	return rs_plain(song, v, countptr);
+    }
+}
+
+void pre_resample(MidSong *song, MidSample *sp)
+{
+  double a, xdiff;
+  sint32 incr, ofs, newlen, count;
+  sint16 *newdata, *dest, *src = (sint16 *) sp->data;
+  sint16 v1, v2, v3, v4, *vptr;
+#ifdef DEBUG_CHATTER
+  static const char note_name[12][3] =
+  {
+    "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
+  };
+#endif
+
+  DEBUG_MSG(" * pre-resampling for note %d (%s%d)\n",
+	  sp->note_to_use,
+	  note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12);
+
+  a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) /
+    ((double) (sp->root_freq) * song->rate);
+  newlen = (sint32)(sp->data_length / a);
+  dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1));
+
+  count = (newlen >> FRACTION_BITS) - 1;
+  ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count;
+
+  if (--count)
+    *dest++ = src[0];
+
+  /* Since we're pre-processing and this doesn't have to be done in
+     real-time, we go ahead and do the full sliding cubic interpolation. */
+  while (--count)
+    {
+      vptr = src + (ofs >> FRACTION_BITS);
+          /*
+           * Electric Fence to the rescue: Accessing *(vptr - 1) is not a
+           * good thing to do when vptr <= src. (TiMidity++ has a similar
+           * safe-guard here.)
+           */
+      v1 = (vptr > src) ? *(vptr - 1) : 0;
+      v2 = *vptr;
+      v3 = *(vptr + 1);
+      v4 = *(vptr + 2);
+      xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS);
+      *dest++ = (sint16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 +
+      xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4))));
+      ofs += incr;
+    }
+
+  if (ofs & FRACTION_MASK)
+    {
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS) + 1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+    }
+  else
+    *dest++ = src[ofs >> FRACTION_BITS];
+
+  sp->data_length = newlen;
+  sp->loop_start = (sint32)(sp->loop_start / a);
+  sp->loop_end = (sint32)(sp->loop_end / a);
+  free(sp->data);
+  sp->data = (sample_t *) newdata;
+  sp->sample_rate = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/resample.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,24 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    resample.h
+*/
+
+extern sample_t *resample_voice(MidSong *song, int v, sint32 *countptr);
+extern void pre_resample(MidSong *song, MidSample *sp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/stream.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,188 @@
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "string.h"
+
+#include "timidity.h"
+#include "timidity_internal.h"
+#include "common.h"
+
+struct _MidIStream
+{
+  MidIStreamReadFunc read;
+  MidIStreamCloseFunc close;
+  void *ctx;
+};
+
+typedef struct StdIOContext
+{
+  FILE *fp;
+  int autoclose;
+} StdIOContext;
+
+size_t
+stdio_istream_read (void *ctx, void *ptr, size_t size, size_t nmemb)
+{
+  return fread (ptr, size, nmemb, ((StdIOContext *) ctx)->fp);
+}
+
+int
+stdio_istream_close (void *ctx)
+{
+  int ret = 0;
+  if (((StdIOContext *) ctx)->autoclose)
+    ret = fclose (((StdIOContext *) ctx)->fp);
+  free (ctx);
+  return ret;
+}
+
+typedef struct MemContext
+{
+  sint8 *base;
+  sint8 *current;
+  sint8 *end;
+  int autofree;
+} MemContext;
+
+size_t
+mem_istream_read (void *ctx, void *ptr, size_t size, size_t nmemb)
+{
+  MemContext *c;
+  size_t count;
+
+  c = (MemContext *) ctx;
+  count = nmemb;
+
+  if (c->current + count * size > c->end)
+    count = (c->end - c->current) / size;
+
+  memcpy (ptr, c->current, count * size);
+  c->current += count * size;
+
+  return count;
+}
+
+int
+mem_istream_close (void *ctx)
+{
+  if (((MemContext *) ctx)->autofree)
+    free (((MemContext *) ctx)->base);
+  free (ctx);
+  return 0;
+}
+
+MidIStream *
+mid_istream_open_fp (FILE * fp, int autoclose)
+{
+  StdIOContext *ctx;
+  MidIStream *stream;
+
+  stream = safe_malloc (sizeof (MidIStream));
+  if (stream == NULL)
+    return NULL;
+
+  ctx = safe_malloc (sizeof (StdIOContext));
+  if (ctx == NULL)
+    {
+      free (stream);
+      return NULL;
+    }
+  ctx->fp = fp;
+  ctx->autoclose = autoclose;
+
+  stream->ctx = ctx;
+  stream->read = stdio_istream_read;
+  stream->close = stdio_istream_close;
+
+  return stream;
+}
+
+MidIStream *
+mid_istream_open_file (const char *file)
+{
+  FILE *fp;
+
+  fp = fopen (file, "rb");
+  if (fp == NULL)
+    return NULL;
+
+  return mid_istream_open_fp (fp, 1);
+}
+
+MidIStream *
+mid_istream_open_mem (void *mem, size_t size, int autofree)
+{
+  MemContext *ctx;
+  MidIStream *stream;
+
+  stream = safe_malloc (sizeof (MidIStream));
+  if (stream == NULL)
+    return NULL;
+
+  ctx = safe_malloc (sizeof (MemContext));
+  if (ctx == NULL)
+    {
+      free (stream);
+      return NULL;
+    }
+  ctx->base = mem;
+  ctx->current = mem;
+  ctx->end = ((sint8 *) mem) + size;
+  ctx->autofree = autofree;
+
+  stream->ctx = ctx;
+  stream->read = mem_istream_read;
+  stream->close = mem_istream_close;
+
+  return stream;
+}
+
+MidIStream *
+mid_istream_open_callbacks (MidIStreamReadFunc read,
+			    MidIStreamCloseFunc close, void *context)
+{
+  MidIStream *stream;
+
+  stream = safe_malloc (sizeof (MidIStream));
+  if (stream == NULL)
+    return NULL;
+
+  stream->ctx = context;
+  stream->read = read;
+  stream->close = close;
+
+  return stream;
+}
+
+size_t
+mid_istream_read (MidIStream * stream, void *ptr, size_t size, size_t nmemb)
+{
+  return stream->read (stream->ctx, ptr, size, nmemb);
+}
+
+void
+mid_istream_skip (MidIStream * stream, size_t len)
+{
+  size_t c;
+  char tmp[1024];
+  while (len > 0)
+    {
+      c = len;
+      if (c > 1024)
+	c = 1024;
+      len -= c;
+      if (c != mid_istream_read (stream, tmp, 1, c))
+	{
+	  DEBUG_MSG ("mid_istream_skip error\n");
+	}
+    }
+}
+
+int
+mid_istream_close (MidIStream * stream)
+{
+  int ret = stream->close (stream->ctx);
+  free (stream);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/tables.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,214 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "timidity.h"
+#include "tables.h"
+
+const sint32 freq_table[128]=
+{
+ 8176, 8662, 9177, 9723, 
+ 10301, 10913, 11562, 12250, 
+ 12978, 13750, 14568, 15434,
+ 
+ 16352, 17324, 18354, 19445,
+ 20602, 21827, 23125, 24500, 
+ 25957, 27500, 29135, 30868, 
+
+ 32703, 34648, 36708, 38891,
+ 41203, 43654, 46249, 48999,
+ 51913, 55000, 58270, 61735,
+
+ 65406, 69296, 73416, 77782,
+ 82407, 87307, 92499, 97999,
+ 103826, 110000, 116541, 123471,
+
+ 130813, 138591, 146832, 155563,
+ 164814, 174614, 184997, 195998,
+ 207652, 220000, 233082, 246942,
+
+ 261626, 277183, 293665, 311127,
+ 329628, 349228, 369994, 391995,
+ 415305, 440000, 466164, 493883,
+
+ 523251, 554365, 587330, 622254,
+ 659255, 698456, 739989, 783991,
+ 830609, 880000, 932328, 987767,
+
+ 1046502, 1108731, 1174659, 1244508,
+ 1318510, 1396913, 1479978, 1567982,
+ 1661219, 1760000, 1864655, 1975533,
+
+ 2093005, 2217461, 2349318, 2489016,
+ 2637020, 2793826, 2959955, 3135963,
+ 3322438, 3520000, 3729310, 3951066,
+
+ 4186009, 4434922, 4698636, 4978032,
+ 5274041, 5587652, 5919911, 6271927,
+ 6644875, 7040000, 7458620, 7902133,
+
+ 8372018, 8869844, 9397273, 9956063, 
+ 10548082, 11175303, 11839822, 12543854
+};
+
+/* v=2.^((x/127-1) * 6) */
+const double vol_table[128] = 
+{
+ 0.015625, 0.016145143728351113, 0.016682602624583379, 0.017237953096759438,
+ 0.017811790741104401, 0.01840473098076444, 0.019017409725829021, 0.019650484055324921,
+ 0.020304632921913132, 0.020980557880044631, 0.021678983838355849, 0.02240065983711079,
+ 0.023146359851523596, 0.023916883621822989, 0.024713057510949051, 0.025535735390801884,
+ 0.026385799557992876, 0.027264161680080529, 0.028171763773305786, 0.029109579212875332,
+ 0.030078613776876421, 0.031079906724942836, 0.032114531912828696, 0.033183598944085631,
+ 0.034288254360078256, 0.035429682869614412, 0.036609108619508737, 0.037827796507442342,
+ 0.039087053538526394, 0.040388230227024875, 0.041732722044739302, 0.043121970917609151,
+ 0.044557466772132896, 0.046040749133268132, 0.047573408775524545, 0.049157089429020417,
+ 0.050793489542332405, 0.05248436410402918, 0.054231526524842463, 0.056036850582493913,
+ 0.057902272431264008, 0.059829792678457581, 0.061821478529993396, 0.063879466007418645,
+ 0.066005962238725971, 0.068203247825430205, 0.070473679288442961, 0.072819691595368496,
+ 0.075243800771931268, 0.077748606600335793, 0.080336795407452768, 0.083011142945821612,
+ 0.085774517370559328, 0.088629882315368294, 0.091580300070941839, 0.094628934869176312,
+ 0.097779056276712184, 0.10103404270144323, 0.1043973850157546, 0.1078726903003755,
+ 0.11146368571286204, 0.11517422248485852, 0.11900828005242428, 0.12296997032385605,
+ 0.12706354208958254, 0.13129338557886089, 0.13566403716816194, 0.14018018424629392,
+ 0.14484667024148207, 0.14966849981579558, 0.15465084423249356, 0.15979904690204472,
+ 0.16511862911277009, 0.17061529595225433, 0.17629494242587571, 0.18216365977901747,
+ 0.18822774202974024, 0.19449369271892172, 0.20096823188510385, 0.20765830327152621,
+ 0.21457108177307616, 0.22171398113114205, 0.2290946618846218, 0.23672103958561411,
+ 0.2446012932886038, 0.25274387432224471, 0.26115751535314891, 0.26985123975140174,
+ 0.27883437126784744, 0.28811654403352405, 0.29770771289197112, 0.30761816407549192,
+ 0.31785852623682015, 0.32843978184802081, 0.33937327897885317, 0.3506707434672246,
+ 0.36234429149478936, 0.37440644258117928, 0.38687013301080181, 0.39974872970660535,
+ 0.41305604456569134, 0.42680634927214656, 0.44101439060298442, 0.45569540624360722,
+ 0.47086514112975281, 0.48653986433345225, 0.50273638651110641, 0.51947207793239625,
+ 0.53676488710936021, 0.55463336004561792, 0.57309666012638816, 0.59217458867062556,
+ 0.61188760616732485, 0.63225685421876243, 0.65330417821421161, 0.67505215075844849,
+ 0.69752409588017272, 0.72074411404630734, 0.74473710800900605, 0.76952880951308478,
+ 0.79514580689252357, 0.82161557358563286, 0.84896649759946774, 0.87722791195508854,
+ 0.90643012614631979, 0.93660445864574493, 0.96778327049280244, 1
+};
+
+const double bend_fine[256] = {
+ 1, 1.0002256593050698, 1.0004513695322617, 1.0006771306930664, 
+ 1.0009029427989777, 1.0011288058614922, 1.0013547198921082, 1.0015806849023274,
+ 1.0018067009036538, 1.002032767907594, 1.0022588859256572, 1.0024850549693551,
+ 1.0027112750502025, 1.0029375461797159, 1.0031638683694153, 1.0033902416308227,
+ 1.0036166659754628, 1.0038431414148634, 1.0040696679605541, 1.0042962456240678,
+ 1.0045228744169397, 1.0047495543507072, 1.0049762854369111, 1.0052030676870944,
+ 1.0054299011128027, 1.0056567857255843, 1.00588372153699, 1.006110708558573,
+ 1.0063377468018897, 1.0065648362784985, 1.0067919769999607, 1.0070191689778405,
+ 1.0072464122237039, 1.0074737067491204, 1.0077010525656616, 1.0079284496849015,
+ 1.0081558981184175, 1.008383397877789, 1.008610948974598, 1.0088385514204294,
+ 1.0090662052268706, 1.0092939104055114, 1.0095216669679448, 1.0097494749257656,
+ 1.009977334290572, 1.0102052450739643, 1.0104332072875455, 1.0106612209429215,
+ 1.0108892860517005, 1.0111174026254934, 1.0113455706759138, 1.0115737902145781,
+ 1.0118020612531047, 1.0120303838031153, 1.0122587578762337, 1.012487183484087,
+ 1.0127156606383041, 1.0129441893505169, 1.0131727696323602, 1.0134014014954713,
+ 1.0136300849514894, 1.0138588200120575, 1.0140876066888203, 1.0143164449934257,
+ 1.0145453349375237, 1.0147742765327674, 1.0150032697908125, 1.0152323147233171,
+ 1.015461411341942, 1.0156905596583505, 1.0159197596842091, 1.0161490114311862,
+ 1.0163783149109531, 1.0166076701351838, 1.0168370771155553, 1.0170665358637463,
+ 1.0172960463914391, 1.0175256087103179, 1.0177552228320703, 1.0179848887683858,
+ 1.0182146065309567, 1.0184443761314785, 1.0186741975816487, 1.0189040708931674,
+ 1.0191339960777379, 1.0193639731470658, 1.0195940021128593, 1.0198240829868295,
+ 1.0200542157806898, 1.0202844005061564, 1.0205146371749483, 1.0207449257987866,
+ 1.0209752663893958, 1.0212056589585028, 1.0214361035178368, 1.0216666000791297,
+ 1.0218971486541166, 1.0221277492545349, 1.0223584018921241, 1.0225891065786274,
+ 1.0228198633257899, 1.0230506721453596, 1.023281533049087, 1.0235124460487257,
+ 1.0237434111560313, 1.0239744283827625, 1.0242054977406807, 1.0244366192415495,
+ 1.0246677928971357, 1.0248990187192082, 1.025130296719539, 1.0253616269099028,
+ 1.0255930093020766, 1.0258244439078401, 1.0260559307389761, 1.0262874698072693,
+ 1.0265190611245079, 1.0267507047024822, 1.0269824005529853, 1.027214148687813,
+ 1.0274459491187637, 1.0276778018576387, 1.0279097069162415, 1.0281416643063788,
+ 1.0283736740398595, 1.0286057361284953, 1.0288378505841009, 1.0290700174184932,
+ 1.0293022366434921, 1.0295345082709197, 1.0297668323126017, 1.0299992087803651,
+ 1.030231637686041, 1.0304641190414621, 1.0306966528584645, 1.0309292391488862,
+ 1.0311618779245688, 1.0313945691973556, 1.0316273129790936, 1.0318601092816313,
+ 1.0320929581168212, 1.0323258594965172, 1.0325588134325767, 1.0327918199368598,
+ 1.0330248790212284, 1.0332579906975481, 1.0334911549776868, 1.033724371873515,
+ 1.0339576413969056, 1.0341909635597348, 1.0344243383738811, 1.0346577658512259,
+ 1.034891246003653, 1.0351247788430489, 1.0353583643813031, 1.0355920026303078,
+ 1.0358256936019572, 1.0360594373081489, 1.0362932337607829, 1.0365270829717617,
+ 1.0367609849529913, 1.0369949397163791, 1.0372289472738365, 1.0374630076372766,
+ 1.0376971208186156, 1.0379312868297725, 1.0381655056826686, 1.0383997773892284,
+ 1.0386341019613787, 1.0388684794110492, 1.0391029097501721, 1.0393373929906822,
+ 1.0395719291445176, 1.0398065182236185, 1.0400411602399278, 1.0402758552053915,
+ 1.0405106031319582, 1.0407454040315787, 1.0409802579162071, 1.0412151647977996,
+ 1.0414501246883161, 1.0416851375997183, 1.0419202035439705, 1.0421553225330404,
+ 1.042390494578898, 1.042625719693516, 1.0428609978888699, 1.043096329176938,
+ 1.0433317135697009, 1.0435671510791424, 1.0438026417172486, 1.0440381854960086,
+ 1.0442737824274138, 1.044509432523459, 1.044745135796141, 1.0449808922574599,
+ 1.0452167019194181, 1.0454525647940205, 1.0456884808932754, 1.0459244502291931,
+ 1.0461604728137874, 1.0463965486590741, 1.046632677777072, 1.0468688601798024,
+ 1.0471050958792898, 1.047341384887561, 1.0475777272166455, 1.047814122878576,
+ 1.048050571885387, 1.0482870742491166, 1.0485236299818055, 1.0487602390954964,
+ 1.0489969016022356, 1.0492336175140715, 1.0494703868430555, 1.0497072096012419,
+ 1.0499440858006872, 1.0501810154534512, 1.050417998571596, 1.0506550351671864,
+ 1.0508921252522903, 1.0511292688389782, 1.0513664659393229, 1.0516037165654004,
+ 1.0518410207292894, 1.0520783784430709, 1.0523157897188296, 1.0525532545686513,
+ 1.0527907730046264, 1.0530283450388465, 1.0532659706834067, 1.0535036499504049,
+ 1.0537413828519411, 1.0539791694001188, 1.0542170096070436, 1.0544549034848243,
+ 1.0546928510455722, 1.0549308523014012, 1.0551689072644284, 1.0554070159467728,
+ 1.0556451783605572, 1.0558833945179062, 1.0561216644309479, 1.0563599881118126,
+ 1.0565983655726334, 1.0568367968255465, 1.0570752818826903, 1.0573138207562065,
+ 1.057552413458239, 1.0577910600009348, 1.0580297603964437, 1.058268514656918,
+ 1.0585073227945128, 1.0587461848213857, 1.058985100749698, 1.0592240705916123
+};
+
+const double bend_coarse[128] = {
+ 1, 1.0594630943592953, 1.122462048309373, 1.189207115002721,
+ 1.2599210498948732, 1.3348398541700344, 1.4142135623730951, 1.4983070768766815,
+ 1.5874010519681994, 1.681792830507429, 1.7817974362806785, 1.8877486253633868,
+ 2, 2.1189261887185906, 2.244924096618746, 2.3784142300054421,
+ 2.5198420997897464, 2.6696797083400687, 2.8284271247461903, 2.996614153753363,
+ 3.1748021039363992, 3.363585661014858, 3.5635948725613571, 3.7754972507267741,
+ 4, 4.2378523774371812, 4.4898481932374912, 4.7568284600108841,
+ 5.0396841995794928, 5.3393594166801366, 5.6568542494923806, 5.993228307506727,
+ 6.3496042078727974, 6.727171322029716, 7.1271897451227151, 7.5509945014535473,
+ 8, 8.4757047548743625, 8.9796963864749824, 9.5136569200217682,
+ 10.079368399158986, 10.678718833360273, 11.313708498984761, 11.986456615013454,
+ 12.699208415745595, 13.454342644059432, 14.25437949024543, 15.101989002907095,
+ 16, 16.951409509748721, 17.959392772949972, 19.027313840043536,
+ 20.158736798317967, 21.357437666720553, 22.627416997969522, 23.972913230026901,
+ 25.398416831491197, 26.908685288118864, 28.508758980490853, 30.203978005814196,
+ 32, 33.902819019497443, 35.918785545899944, 38.054627680087073,
+ 40.317473596635935, 42.714875333441107, 45.254833995939045, 47.945826460053802,
+ 50.796833662982394, 53.817370576237728, 57.017517960981706, 60.407956011628393,
+ 64, 67.805638038994886, 71.837571091799887, 76.109255360174146,
+ 80.63494719327187, 85.429750666882214, 90.509667991878089, 95.891652920107603,
+ 101.59366732596479, 107.63474115247546, 114.03503592196341, 120.81591202325679,
+ 128, 135.61127607798977, 143.67514218359977, 152.21851072034829,
+ 161.26989438654374, 170.85950133376443, 181.01933598375618, 191.78330584021521,
+ 203.18733465192958, 215.26948230495091, 228.07007184392683, 241.63182404651357,
+ 256, 271.22255215597971, 287.35028436719938, 304.43702144069658,
+ 322.53978877308765, 341.71900266752868, 362.03867196751236, 383.56661168043064,
+ 406.37466930385892, 430.53896460990183, 456.14014368785394, 483.26364809302686,
+ 512, 542.44510431195943, 574.70056873439876, 608.87404288139317,
+ 645.0795775461753, 683.43800533505737, 724.07734393502471, 767.13322336086128,
+ 812.74933860771785, 861.07792921980365, 912.28028737570787, 966.52729618605372,
+ 1024, 1084.8902086239189, 1149.4011374687975, 1217.7480857627863,
+ 1290.1591550923506, 1366.8760106701147, 1448.1546878700494, 1534.2664467217226
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/tables.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,30 @@
+/* 
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    tables.h
+*/
+
+#include <math.h>
+#define sine(x) (sin((2*PI/1024.0) * (x)))
+
+#define SINE_CYCLE_LENGTH 1024
+extern const sint32 freq_table[];
+extern const double vol_table[];
+extern const double bend_fine[];
+extern const double bend_coarse[];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/timidity.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,606 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+	 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "timidity.h"
+#include "timidity_internal.h"
+
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "output.h"
+
+#include "tables.h"
+
+MidToneBank *master_tonebank[128], *master_drumset[128];
+
+static char def_instr_name[256] = "";
+
+#define MAXWORDS 10
+
+/* Quick-and-dirty fgets() replacement. */
+
+static char *__fgets(char *s, int size, FILE *fp)
+{
+    int num_read = 0;
+    int newline = 0;
+
+    while (num_read < size && !newline)
+    {
+	if (fread(&s[num_read], 1, 1, fp) != 1)
+	    break;
+
+	/* Unlike fgets(), don't store newline. Under Windows/DOS we'll
+	 * probably get an extra blank line for every line that's being
+	 * read, but that should be ok.
+	 */
+	if (s[num_read] == '\n' || s[num_read] == '\r')
+	{
+	    s[num_read] = '\0';
+	    newline = 1;
+	}
+	
+	num_read++;
+    }
+
+    s[num_read] = '\0';
+    
+    return (num_read != 0) ? s : NULL;
+}
+
+static int read_config_file(char *name)
+{
+  FILE *fp;
+  char tmp[1024], *w[MAXWORDS], *cp;
+  MidToneBank *bank=0;
+  int i, j, k, line=0, words;
+  static int rcf_count=0;
+
+  if (rcf_count>50)
+  {
+    DEBUG_MSG("Probable source loop in configuration files\n");
+    return (-1);
+  }
+
+  if (!(fp=open_file(name)))
+   return -1;
+
+  while (__fgets(tmp, sizeof(tmp), fp))
+  {
+    line++;
+    w[words=0]=strtok(tmp, " \t\240");
+    if (!w[0]) continue;
+
+        /* Originally the TiMidity++ extensions were prefixed like this */
+    if (strcmp(w[0], "#extension") == 0)
+        words = -1;
+    else if (*w[0] == '#')
+        continue;
+
+    while (w[words] && *w[words] != '#' && (words < MAXWORDS))
+      w[++words]=strtok(0," \t\240");
+
+        /*
+         * TiMidity++ adds a number of extensions to the config file format.
+         * Many of them are completely irrelevant to SDL_sound, but at least
+         * we shouldn't choke on them.
+         *
+         * Unfortunately the documentation for these extensions is often quite
+         * vague, gramatically strange or completely absent.
+         */
+    if (
+           !strcmp(w[0], "comm")      /* "comm" program second        */
+        || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port    */
+        || !strcmp(w[0], "FTPproxy")  /* "FTPproxy" hostname:port     */
+        || !strcmp(w[0], "mailaddr")  /* "mailaddr" your-mail-address */
+        || !strcmp(w[0], "opt")       /* "opt" timidity-options       */
+       )
+    {
+            /*
+             * + "comm" sets some kind of comment -- the documentation is too
+             *   vague for me to understand at this time.
+             * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data
+             *   over a network, rather than from the file system.
+             * + "opt" specifies default options for TiMidity++.
+             *
+             * These are all quite useless for our version of TiMidity, so
+             * they can safely remain no-ops.
+             */
+    } else if (!strcmp(w[0], "timeout")) /* "timeout" program second */
+    {
+            /*
+             * Specifies a timeout value of the program. A number of seconds
+             * before TiMidity kills the note. This may be useful to implement
+             * later, but I don't see any urgent need for it.
+             */
+        DEBUG_MSG("FIXME: Implement \"timeout\" in TiMidity config.\n");
+    } else if (!strcmp(w[0], "copydrumset")  /* "copydrumset" drumset */
+               || !strcmp(w[0], "copybank")) /* "copybank" bank       */
+    {
+            /*
+             * Copies all the settings of the specified drumset or bank to
+             * the current drumset or bank. May be useful later, but not a
+             * high priority.
+             */
+        DEBUG_MSG("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]);
+    } else if (!strcmp(w[0], "undef")) /* "undef" progno */
+    {
+            /*
+             * Undefines the tone "progno" of the current tone bank (or
+             * drum set?). Not a high priority.
+             */
+        DEBUG_MSG("FIXME: Implement \"undef\" in TiMidity config.\n");
+    } else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
+    {
+            /*
+             * Sets the alternate assign for drum set. Whatever that's
+             * supposed to mean.
+             */
+        DEBUG_MSG("FIXME: Implement \"altassign\" in TiMidity config.\n");
+    } else if (!strcmp(w[0], "soundfont")
+               || !strcmp(w[0], "font"))
+    {
+            /*
+             * I can't find any documentation for these, but I guess they're
+             * an alternative way of loading/unloading instruments.
+             * 
+             * "soundfont" sf_file "remove"
+             * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
+             *                     ["reso=" reso] ["amp=" amp]
+             * "font" "exclude" bank preset keynote
+             * "font" "order" order bank preset keynote
+             */
+        DEBUG_MSG("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]);
+    } else if (!strcmp(w[0], "progbase"))
+    {
+            /*
+             * The documentation for this makes absolutely no sense to me, but
+             * apparently it sets some sort of base offset for tone numbers.
+             * Why anyone would want to do this is beyond me.
+             */
+        DEBUG_MSG("FIXME: Implement \"progbase\" in TiMidity config.\n");
+    } else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
+    {
+            /*
+             * This extension is the one we will need to implement, as it is
+             * used by the "eawpats". Unfortunately I cannot find any
+             * documentation whatsoever for it, but it looks like it's used
+             * for remapping one instrument to another somehow.
+             */
+        DEBUG_MSG("FIXME: Implement \"map\" in TiMidity config.\n");
+    }
+
+        /* Standard TiMidity config */
+    
+    else if (!strcmp(w[0], "dir"))
+    {
+      if (words < 2)
+      {
+	DEBUG_MSG("%s: line %d: No directory given\n", name, line);
+	return -2;
+      }
+      for (i=1; i<words; i++)
+	add_to_pathlist(w[i]);
+    }
+    else if (!strcmp(w[0], "source"))
+    {
+      if (words < 2)
+      {
+	DEBUG_MSG("%s: line %d: No file name given\n", name, line);
+	return -2;
+      }
+      for (i=1; i<words; i++)
+      {
+	rcf_count++;
+	read_config_file(w[i]);
+	rcf_count--;
+      }
+    }
+    else if (!strcmp(w[0], "default"))
+    {
+      if (words != 2)
+      {
+	DEBUG_MSG("%s: line %d: Must specify exactly one patch name\n",
+		name, line);
+	return -2;
+      }
+      strncpy(def_instr_name, w[1], 255);
+      def_instr_name[255]='\0';
+    }
+    else if (!strcmp(w[0], "drumset"))
+    {
+      if (words < 2)
+      {
+	DEBUG_MSG("%s: line %d: No drum set number given\n", name, line);
+	return -2;
+      }
+      i=atoi(w[1]);
+      if (i<0 || i>127)
+      {
+	DEBUG_MSG("%s: line %d: Drum set must be between 0 and 127\n",
+		name, line);
+	return -2;
+      }
+      if (!master_drumset[i])
+      {
+	master_drumset[i] = safe_malloc(sizeof(MidToneBank));
+	memset(master_drumset[i], 0, sizeof(MidToneBank));
+	master_drumset[i]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
+	memset(master_drumset[i]->tone, 0, 128 * sizeof(MidToneBankElement));
+      }
+      bank=master_drumset[i];
+    }
+    else if (!strcmp(w[0], "bank"))
+    {
+      if (words < 2)
+      {
+	DEBUG_MSG("%s: line %d: No bank number given\n", name, line);
+	return -2;
+      }
+      i=atoi(w[1]);
+      if (i<0 || i>127)
+      {
+	DEBUG_MSG("%s: line %d: Tone bank must be between 0 and 127\n",
+		name, line);
+	return -2;
+      }
+      if (!master_tonebank[i])
+      {
+	master_tonebank[i] = safe_malloc(sizeof(MidToneBank));
+	memset(master_tonebank[i], 0, sizeof(MidToneBank));
+	master_tonebank[i]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
+	memset(master_tonebank[i]->tone, 0, 128 * sizeof(MidToneBankElement));
+      }
+      bank=master_tonebank[i];
+    }
+    else
+    {
+      if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
+      {
+	DEBUG_MSG("%s: line %d: syntax error\n", name, line);
+	return -2;
+      }
+      i=atoi(w[0]);
+      if (i<0 || i>127)
+      {
+	DEBUG_MSG("%s: line %d: Program must be between 0 and 127\n",
+		name, line);
+	return -2;
+      }
+      if (!bank)
+      {
+	DEBUG_MSG("%s: line %d: Must specify tone bank or drum set before assignment\n",
+		name, line);
+	return -2;
+      }
+      if (bank->tone[i].name)
+	free(bank->tone[i].name);
+      strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
+      bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
+      bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
+      bank->tone[i].strip_tail=-1;
+
+      for (j=2; j<words; j++)
+      {
+	if (!(cp=strchr(w[j], '=')))
+	{
+	  DEBUG_MSG("%s: line %d: bad patch option %s\n", name, line, w[j]);
+	  return -2;
+	}
+	*cp++=0;
+	if (!strcmp(w[j], "amp"))
+	{
+	  k=atoi(cp);
+	  if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
+	  {
+	    DEBUG_MSG("%s: line %d: amplification must be between 0 and %d\n",
+		    name, line, MAX_AMPLIFICATION);
+	    return -2;
+	  }
+	  bank->tone[i].amp=k;
+	}
+	else if (!strcmp(w[j], "note"))
+	{
+	  k=atoi(cp);
+	  if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
+	  {
+	    DEBUG_MSG("%s: line %d: note must be between 0 and 127\n",
+		    name, line);
+	    return -2;
+	  }
+	  bank->tone[i].note=k;
+	}
+	else if (!strcmp(w[j], "pan"))
+	{
+	  if (!strcmp(cp, "center"))
+	    k=64;
+	  else if (!strcmp(cp, "left"))
+	    k=0;
+	  else if (!strcmp(cp, "right"))
+	    k=127;
+	  else
+	    k=((atoi(cp)+100) * 100) / 157;
+	  if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
+	  {
+	    DEBUG_MSG("%s: line %d: panning must be left, right, center, or between -100 and 100\n",
+		    name, line);
+	    return -2;
+	  }
+	  bank->tone[i].pan=k;
+	}
+	else if (!strcmp(w[j], "keep"))
+	{
+	  if (!strcmp(cp, "env"))
+	    bank->tone[i].strip_envelope=0;
+	  else if (!strcmp(cp, "loop"))
+	    bank->tone[i].strip_loop=0;
+	  else
+	  {
+	    DEBUG_MSG("%s: line %d: keep must be env or loop\n", name, line);
+	    return -2;
+	  }
+	}
+	else if (!strcmp(w[j], "strip"))
+	{
+	  if (!strcmp(cp, "env"))
+	    bank->tone[i].strip_envelope=1;
+	  else if (!strcmp(cp, "loop"))
+	    bank->tone[i].strip_loop=1;
+	  else if (!strcmp(cp, "tail"))
+	    bank->tone[i].strip_tail=1;
+	  else
+	  {
+	    DEBUG_MSG("%s: line %d: strip must be env, loop, or tail\n",
+		    name, line);
+	    return -2;
+	  }
+	}
+	else
+	{
+	  DEBUG_MSG("%s: line %d: bad patch option %s\n", name, line, w[j]);
+	  return -2;
+	}
+      }
+    }
+  }
+  fclose(fp);
+  return 0;
+}
+
+int mid_init_no_config()
+{
+  /* Allocate memory for the standard tonebank and drumset */
+  master_tonebank[0] = safe_malloc(sizeof(MidToneBank));
+  memset(master_tonebank[0], 0, sizeof(MidToneBank));
+  master_tonebank[0]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
+  memset(master_tonebank[0]->tone, 0, 128 * sizeof(MidToneBankElement));
+
+  master_drumset[0] = safe_malloc(sizeof(MidToneBank));
+  memset(master_drumset[0], 0, sizeof(MidToneBank));
+  master_drumset[0]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
+  memset(master_drumset[0]->tone, 0, 128 * sizeof(MidToneBankElement));
+
+  return 0;
+}
+
+int mid_init(char *config_file)
+{
+  /* !!! FIXME: This may be ugly, but slightly less so than requiring the
+   *            default search path to have only one element. I think.
+   *
+   *            We only need to include the likely locations for the config
+   *            file itself since that file should contain any other directory
+   *            that needs to be added to the search path.
+   */
+#ifdef WIN32
+  add_to_pathlist("\\TIMIDITY");
+#else
+  add_to_pathlist("/usr/local/lib/timidity");
+  add_to_pathlist("/etc");
+#endif
+
+  mid_init_no_config();
+
+  if (config_file == NULL || *config_file == '\0')
+      config_file = CONFIG_FILE;
+
+  return read_config_file(config_file);
+}
+
+MidSong *mid_song_load_dls(MidIStream *stream, MidDLSPatches *patches, MidSongOptions *options)
+{
+  MidSong *song;
+  int i;
+
+  if (stream == NULL)
+      return NULL;
+  
+  /* Allocate memory for the song */
+  song = (MidSong *)safe_malloc(sizeof(*song));
+  memset(song, 0, sizeof(*song));
+  song->patches = patches;
+
+  for (i = 0; i < 128; i++)
+  {
+    if (master_tonebank[i])
+    {
+      song->tonebank[i] = safe_malloc(sizeof(MidToneBank));
+      memset(song->tonebank[i], 0, sizeof(MidToneBank));
+      song->tonebank[i]->tone = master_tonebank[i]->tone;
+    }
+    if (master_drumset[i])
+    {
+      song->drumset[i] = safe_malloc(sizeof(MidToneBank));
+      memset(song->drumset[i], 0, sizeof(MidToneBank));
+      song->drumset[i]->tone = master_drumset[i]->tone;
+    }
+  }
+
+  song->amplification = DEFAULT_AMPLIFICATION;
+  song->voices = DEFAULT_VOICES;
+  song->drumchannels = DEFAULT_DRUMCHANNELS;
+
+  song->rate = options->rate;
+  song->encoding = 0;
+  if ((options->format & 0xFF) == 16)
+      song->encoding |= PE_16BIT;
+  if (options->format & 0x8000)
+      song->encoding |= PE_SIGNED;
+  if (options->channels == 1)
+      song->encoding |= PE_MONO;
+  switch (options->format) {
+      case MID_AUDIO_S8:
+	  song->write = s32tos8;
+	  break;
+      case MID_AUDIO_U8:
+	  song->write = s32tou8;
+	  break;
+      case MID_AUDIO_S16LSB:
+	  song->write = s32tos16l;
+	  break;
+      case MID_AUDIO_S16MSB:
+	  song->write = s32tos16b;
+	  break;
+      case MID_AUDIO_U16LSB:
+	  song->write = s32tou16l;
+	  break;
+      default:
+	  DEBUG_MSG("Unsupported audio format\n");
+	  song->write = s32tou16l;
+	  break;
+  }
+
+  song->buffer_size = options->buffer_size;
+  song->resample_buffer = safe_malloc(options->buffer_size * sizeof(sample_t));
+  song->common_buffer = safe_malloc(options->buffer_size * 2 * sizeof(sint32));
+
+  song->bytes_per_sample =
+        ((song->encoding & PE_MONO) ? 1 : 2)
+      * ((song->encoding & PE_16BIT) ? 2 : 1);
+  
+  song->control_ratio = options->rate / CONTROLS_PER_SECOND;
+  if (song->control_ratio < 1)
+      song->control_ratio = 1;
+  else if (song->control_ratio > MAX_CONTROL_RATIO)
+      song->control_ratio = MAX_CONTROL_RATIO;
+
+  song->lost_notes = 0;
+  song->cut_notes = 0;
+
+  song->events = read_midi_file(stream, song, &(song->groomed_event_count),
+      &song->samples);
+
+  /* Make sure everything is okay */
+  if (!song->events) {
+    free(song);
+    return(NULL);
+  }
+
+  song->default_instrument = 0;
+  song->default_program = DEFAULT_PROGRAM;
+
+  if (*def_instr_name)
+    set_default_instrument(song, def_instr_name);
+
+  load_missing_instruments(song);
+
+  return(song);
+}
+
+MidSong *mid_song_load(MidIStream *stream, MidSongOptions *options)
+{
+  return mid_song_load_dls(stream, NULL, options);
+}
+
+void mid_song_free(MidSong *song)
+{
+  int i;
+
+  free_instruments(song);
+
+  for (i = 0; i < 128; i++)
+  {
+    if (song->tonebank[i])
+      free(song->tonebank[i]);
+    if (song->drumset[i])
+      free(song->drumset[i]);
+  }
+  
+  free(song->common_buffer);
+  free(song->resample_buffer);
+  free(song->events);
+
+  for (i = 0; i < (sizeof(song->meta_data) / sizeof(song->meta_data[0])); i++)
+  {
+    if (song->meta_data[i])
+      free(song->meta_data[i]);
+  }
+  
+  free(song);
+}
+
+void mid_exit(void)
+{
+  int i, j;
+
+  for (i = 0; i < 128; i++)
+  {
+    if (master_tonebank[i])
+    {
+      MidToneBankElement *e = master_tonebank[i]->tone;
+      if (e != NULL)
+      {
+        for (j = 0; j < 128; j++)
+        {
+          if (e[j].name != NULL)
+            free(e[j].name);
+        }
+        free(e);
+      }
+      free(master_tonebank[i]);
+    }
+    if (master_drumset[i])
+    {
+      MidToneBankElement *e = master_drumset[i]->tone;
+      if (e != NULL)
+      {
+        for (j = 0; j < 128; j++)
+        {
+          if (e[j].name != NULL)
+            free(e[j].name);
+        }
+        free(e);
+      }
+      free(master_drumset[i]);
+    }
+  }
+
+  free_pathlist();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/timidity.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,206 @@
+/*
+
+    libTiMidity -- MIDI to WAVE converter library
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+    Copyright (C) 2004 Konstantin Korikov <lostclus@ua.fm>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef TIMIDITY_H
+#define TIMIDITY_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define LIBTIMIDITY_VERSION_MAJOR 0L
+#define LIBTIMIDITY_VERSION_MINOR 1L
+#define LIBTIMIDITY_PATCHLEVEL    0L
+
+#define LIBTIMIDITY_VERSION \
+        ((LIBTIMIDITY_VERSION_MAJOR<<16)| \
+         (LIBTIMIDITY_VERSION_MINOR<< 8)| \
+         (LIBTIMIDITY_PATCHLEVEL))
+
+/* Audio format flags (defaults to LSB byte order)
+ */
+#define MID_AUDIO_U8        0x0008	/* Unsigned 8-bit samples */
+#define MID_AUDIO_S8        0x8008	/* Signed 8-bit samples */
+#define MID_AUDIO_U16LSB    0x0010	/* Unsigned 16-bit samples */
+#define MID_AUDIO_S16LSB    0x8010	/* Signed 16-bit samples */
+#define MID_AUDIO_U16MSB    0x1010	/* As above, but big-endian byte order */
+#define MID_AUDIO_S16MSB    0x9010	/* As above, but big-endian byte order */
+#define MID_AUDIO_U16       MID_AUDIO_U16LSB
+#define MID_AUDIO_S16       MID_AUDIO_S16LSB
+
+/* Core Library Types
+ */
+  typedef unsigned char uint8;
+  typedef signed char sint8;
+  typedef unsigned short uint16;
+  typedef signed short sint16;
+  typedef unsigned int uint32;
+  typedef signed int sint32;
+
+  typedef size_t (*MidIStreamReadFunc) (void *ctx, void *ptr, size_t size,
+					size_t nmemb);
+  typedef int (*MidIStreamCloseFunc) (void *ctx);
+
+  typedef struct _MidIStream MidIStream;
+  typedef struct _MidDLSPatches MidDLSPatches;
+  typedef struct _MidSong MidSong;
+
+  typedef struct _MidSongOptions MidSongOptions;
+  struct _MidSongOptions
+  {
+    sint32 rate;	  /* DSP frequency -- samples per second */
+    uint16 format;	  /* Audio data format */
+    uint8 channels;	  /* Number of channels: 1 mono, 2 stereo */
+    uint16 buffer_size;	  /* Sample buffer size in samples */
+  };
+
+  typedef enum
+  {
+    MID_SONG_TEXT = 0,
+    MID_SONG_COPYRIGHT = 1
+  } MidSongMetaId;
+
+
+/* Core Library Functions
+ * ======================
+ */
+
+/* Initialize the library. If config_file is NULL
+ * search for configuratin file in default directories
+ */
+  extern int mid_init (char *config_file);
+
+/* Initialize the library without reading any
+ * configuratin file
+ */
+  extern int mid_init_no_config (void);
+
+/* Shutdown the library
+ */
+  extern void mid_exit (void);
+
+
+/* Input Stream Functions
+ * ======================
+ */
+
+/* Create input stream from a file name
+ */
+  extern MidIStream *mid_istream_open_file (const char *file);
+
+/* Create input stream from a file pointer
+ */
+  extern MidIStream *mid_istream_open_fp (FILE * fp, int autoclose);
+
+/* Create input stream from memory
+ */
+  extern MidIStream *mid_istream_open_mem (void *mem, size_t size,
+					   int autofree);
+
+/* Create custom input stream
+ */
+  extern MidIStream *mid_istream_open_callbacks (MidIStreamReadFunc read,
+						 MidIStreamCloseFunc close,
+						 void *context);
+
+/* Read data from input stream
+ */
+  extern size_t mid_istream_read (MidIStream * stream, void *ptr, size_t size,
+				  size_t nmemb);
+
+/* Skip data from input stream
+ */
+  extern void mid_istream_skip (MidIStream * stream, size_t len);
+
+/* Close and destroy input stream
+ */
+  extern int mid_istream_close (MidIStream * stream);
+
+
+/* DLS Pathes Functions
+ * ====================
+ */
+
+/* Load DLS patches
+ */
+  extern MidDLSPatches *mid_dlspatches_load (MidIStream * stream);
+
+/* Destroy DLS patches
+ */
+  extern void mid_dlspatches_free (MidDLSPatches * patches);
+
+
+/* MIDI Song Functions
+ * ===================
+ */
+
+/* Load MIDI song
+ */
+  extern MidSong *mid_song_load (MidIStream * stream,
+				 MidSongOptions * options);
+
+/* Load MIDI song with specified DLS pathes
+ */
+  extern MidSong *mid_song_load_dls (MidIStream * stream,
+				     MidDLSPatches * patches,
+				     MidSongOptions * options);
+
+/* Set song amplification value
+ */
+  extern void mid_song_set_volume (MidSong * song, int volume);
+
+/* Seek song to the start position and initialize conversion
+ */
+  extern void mid_song_start (MidSong * song);
+
+/* Read WAVE data
+ */
+  extern size_t mid_song_read_wave (MidSong * song, void *ptr, size_t size);
+
+/* Seek song to specified offset in millseconds
+ */
+  extern void mid_song_seek (MidSong * song, uint32 ms);
+
+/* Get total song time in millseconds
+ */
+  extern uint32 mid_song_get_total_time (MidSong * song);
+
+/* Get current song time in millseconds
+ */
+  extern uint32 mid_song_get_time (MidSong * song);
+
+/* Get song meta data. Return NULL if no meta data found
+ */
+  extern char *mid_song_get_meta (MidSong * song, MidSongMetaId what);
+
+/* Destroy song
+ */
+  extern void mid_song_free (MidSong * song);
+
+#ifdef __cplusplus
+}
+#endif
+#endif				/* TIMIDITY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/libtimidity/timidity_internal.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,192 @@
+#ifndef TIMIDITY_INTERNAL_H
+#define TIMIDITY_INTERNAL_H
+
+#include "timidity.h"
+
+#if  defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
+    (defined(__alpha__) || defined(__alpha)) || \
+     defined(__arm__) || \
+    (defined(__mips__) && defined(__MIPSEL__)) || \
+     defined(__SYMBIAN32__) || \
+     defined(__x86_64__) || \
+     defined(__LITTLE_ENDIAN__)
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#endif
+#undef BIG_ENDIAN
+#else
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN
+#endif
+#undef LITTLE_ENDIAN
+#endif
+
+/* Instrument files are little-endian, MIDI files big-endian, so we
+   need to do some conversions. */
+
+#define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#ifdef __i486__
+# define XCHG_LONG(x) \
+     ({ sint32 __value; \
+        asm ("bswap %1; movl %1,%0" : "=g" (__value) : "r" (x)); \
+       __value; })
+#else
+# define XCHG_LONG(x) ((((x)&0xFF)<<24) | \
+		      (((x)&0xFF00)<<8) | \
+		      (((x)&0xFF0000)>>8) | \
+		      (((x)>>24)&0xFF))
+#endif
+
+#ifdef LITTLE_ENDIAN
+#define SWAPLE16(x) x
+#define SWAPLE32(x) x
+#define SWAPBE16(x) XCHG_SHORT(x)
+#define SWAPBE32(x) XCHG_LONG(x)
+#else
+#define SWAPBE16(x) x
+#define SWAPBE32(x) x
+#define SWAPLE16(x) XCHG_SHORT(x)
+#define SWAPLE32(x) XCHG_LONG(x)
+#endif
+
+#ifdef DEBUG
+#define DEBUG_MSG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG_MSG(...)
+#endif
+
+
+#define MID_VIBRATO_SAMPLE_INCREMENTS 32
+
+/* Maximum polyphony. */
+#define MID_MAX_VOICES	48
+
+typedef sint16 sample_t;
+typedef sint32 final_volume_t;
+
+typedef struct _MidSample MidSample;
+struct _MidSample
+{
+  sint32
+    loop_start, loop_end, data_length,
+    sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq;
+  sint32 envelope_rate[6], envelope_offset[6];
+  float volume;
+  sample_t *data;
+    sint32
+    tremolo_sweep_increment, tremolo_phase_increment,
+    vibrato_sweep_increment, vibrato_control_ratio;
+    uint8 tremolo_depth, vibrato_depth, modes;
+    sint8 panning, note_to_use;
+};
+
+typedef struct _MidChannel MidChannel;
+struct _MidChannel
+{
+  int bank, program, volume, sustain, panning, pitchbend, expression;
+  int mono;	/* one note only on this channel -- not implemented yet */
+  int pitchsens;
+  /* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar
+     processor near you */
+  float pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
+};
+
+typedef struct _MidVoice MidVoice;
+struct _MidVoice
+{
+  uint8 status, channel, note, velocity;
+  MidSample *sample;
+  sint32
+    orig_frequency, frequency,
+    sample_offset, sample_increment,
+    envelope_volume, envelope_target, envelope_increment,
+    tremolo_sweep, tremolo_sweep_position,
+    tremolo_phase, tremolo_phase_increment,
+    vibrato_sweep, vibrato_sweep_position;
+
+  final_volume_t left_mix, right_mix;
+
+  float left_amp, right_amp, tremolo_volume;
+    sint32 vibrato_sample_increment[MID_VIBRATO_SAMPLE_INCREMENTS];
+  int
+    vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
+    envelope_stage, control_counter, panning, panned;
+
+};
+
+typedef struct _MidInstrument MidInstrument;
+struct _MidInstrument
+{
+  int samples;
+  MidSample *sample;
+};
+
+typedef struct _MidToneBankElement MidToneBankElement;
+struct _MidToneBankElement
+{
+  char *name;
+  int note, amp, pan, strip_loop, strip_envelope, strip_tail;
+};
+
+typedef struct _MidToneBank MidToneBank;
+struct _MidToneBank
+{
+  MidToneBankElement *tone;
+  MidInstrument *instrument[128];
+};
+
+typedef struct _MidEvent MidEvent;
+struct _MidEvent
+{
+  sint32 time;
+  uint8 channel, type, a, b;
+};
+
+typedef struct _MidEventList MidEventList;
+struct _MidEventList
+{
+  MidEvent event;
+  void *next;
+};
+
+struct _MidSong
+{
+  int playing;
+  sint32 rate;
+  sint32 encoding;
+  int bytes_per_sample;
+  float master_volume;
+  sint32 amplification;
+  MidDLSPatches *patches;
+  MidToneBank *tonebank[128];
+  MidToneBank *drumset[128];
+  MidInstrument *default_instrument;
+  int default_program;
+  void (*write) (void *dp, sint32 * lp, sint32 c);
+  int buffer_size;
+  sample_t *resample_buffer;
+  sint32 *common_buffer;
+  /* These would both fit into 32 bits, but they are often added in
+     large multiples, so it's simpler to have two roomy ints */
+  /* samples per MIDI delta-t */
+  sint32 sample_increment;
+  sint32 sample_correction;
+  MidChannel channel[16];
+  MidVoice voice[MID_MAX_VOICES];
+  int voices;
+  sint32 drumchannels;
+  sint32 control_ratio;
+  sint32 lost_notes;
+  sint32 cut_notes;
+  sint32 samples;
+  MidEvent *events;
+  MidEvent *current_event;
+  MidEventList *evlist;
+  sint32 current_sample;
+  sint32 event_count;
+  sint32 at;
+  sint32 groomed_event_count;
+  char *meta_data[8];
+};
+
+#endif /* TIMIDITY_INTERNAL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/Makefile.am	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,15 @@
+lib_LTLIBRARIES = libtimidity.la
+
+libdir = $(plugindir)/$(INPUT_PLUGIN_DIR)
+
+libtimidity_la_LDFLAGS = $(PLUGIN_LDFLAGS) ../libtimidity/libtimidity.la
+
+libtimidity_la_SOURCES = \
+	callbacks.c \
+	callbacks.h \
+	interface.c \
+	interface.h \
+	xmms-timidity.c \
+	xmms-timidity.h
+
+INCLUDES = $(GTK_CFLAGS) -I$(top_srcdir) -I../libtimidity
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/callbacks.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,11 @@
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "interface.h"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/callbacks.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,2 @@
+#include <gtk/gtk.h>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/interface.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,326 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "interface.h"
+
+GtkWidget*
+create_xmmstimid_conf_wnd (void)
+{
+  GtkWidget *xmmstimid_conf_wnd;
+  GtkWidget *vbox4;
+  GtkWidget *table1;
+  GtkWidget *frame1;
+  GtkWidget *vbox1;
+  GSList *rate_group = NULL;
+  GtkWidget *rate_11000;
+  GtkWidget *rate_22000;
+  GtkWidget *rate_44100;
+  GtkWidget *frame2;
+  GtkWidget *vbox2;
+  GSList *bits_group = NULL;
+  GtkWidget *bits_8;
+  GtkWidget *bits_16;
+  GtkWidget *frame3;
+  GtkWidget *vbox3;
+  GSList *channels_group = NULL;
+  GtkWidget *channels_1;
+  GtkWidget *channels_2;
+  GtkWidget *frame4;
+  GtkWidget *vbox5;
+  GtkWidget *config_file;
+  GtkWidget *hseparator1;
+  GtkWidget *hbuttonbox1;
+  GtkWidget *conf_ok;
+  GtkWidget *button2;
+
+  xmmstimid_conf_wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_object_set_data (GTK_OBJECT (xmmstimid_conf_wnd), "xmmstimid_conf_wnd", xmmstimid_conf_wnd);
+  gtk_window_set_title (GTK_WINDOW (xmmstimid_conf_wnd), "TiMidity Configuration");
+  gtk_window_set_position (GTK_WINDOW (xmmstimid_conf_wnd), GTK_WIN_POS_MOUSE);
+
+  vbox4 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox4);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "vbox4", vbox4,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox4);
+  gtk_container_add (GTK_CONTAINER (xmmstimid_conf_wnd), vbox4);
+
+  table1 = gtk_table_new (3, 2, FALSE);
+  gtk_widget_ref (table1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "table1", table1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (table1);
+  gtk_box_pack_start (GTK_BOX (vbox4), table1, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
+  gtk_table_set_row_spacings (GTK_TABLE (table1), 5);
+  gtk_table_set_col_spacings (GTK_TABLE (table1), 5);
+
+  frame1 = gtk_frame_new ("Sampling Rate");
+  gtk_widget_ref (frame1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "frame1", frame1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (frame1);
+  gtk_table_attach (GTK_TABLE (table1), frame1, 0, 1, 1, 2,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+
+  vbox1 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "vbox1", vbox1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox1);
+  gtk_container_add (GTK_CONTAINER (frame1), vbox1);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5);
+
+  rate_11000 = gtk_radio_button_new_with_label (rate_group, "11000 Hz");
+  rate_group = gtk_radio_button_group (GTK_RADIO_BUTTON (rate_11000));
+  gtk_widget_ref (rate_11000);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "rate_11000", rate_11000,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (rate_11000);
+  gtk_box_pack_start (GTK_BOX (vbox1), rate_11000, FALSE, FALSE, 0);
+
+  rate_22000 = gtk_radio_button_new_with_label (rate_group, "22000 Hz");
+  rate_group = gtk_radio_button_group (GTK_RADIO_BUTTON (rate_22000));
+  gtk_widget_ref (rate_22000);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "rate_22000", rate_22000,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (rate_22000);
+  gtk_box_pack_start (GTK_BOX (vbox1), rate_22000, FALSE, FALSE, 0);
+
+  rate_44100 = gtk_radio_button_new_with_label (rate_group, "44100 Hz");
+  rate_group = gtk_radio_button_group (GTK_RADIO_BUTTON (rate_44100));
+  gtk_widget_ref (rate_44100);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "rate_44100", rate_44100,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (rate_44100);
+  gtk_box_pack_start (GTK_BOX (vbox1), rate_44100, FALSE, FALSE, 0);
+
+  frame2 = gtk_frame_new ("Sample Width");
+  gtk_widget_ref (frame2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "frame2", frame2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (frame2);
+  gtk_table_attach (GTK_TABLE (table1), frame2, 1, 2, 1, 2,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "vbox2", vbox2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox2);
+  gtk_container_add (GTK_CONTAINER (frame2), vbox2);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
+
+  bits_8 = gtk_radio_button_new_with_label (bits_group, "8 bit");
+  bits_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bits_8));
+  gtk_widget_ref (bits_8);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "bits_8", bits_8,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (bits_8);
+  gtk_box_pack_start (GTK_BOX (vbox2), bits_8, FALSE, FALSE, 0);
+
+  bits_16 = gtk_radio_button_new_with_label (bits_group, "16 bit");
+  bits_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bits_16));
+  gtk_widget_ref (bits_16);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "bits_16", bits_16,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (bits_16);
+  gtk_box_pack_start (GTK_BOX (vbox2), bits_16, FALSE, FALSE, 0);
+
+  frame3 = gtk_frame_new ("Channels");
+  gtk_widget_ref (frame3);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "frame3", frame3,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (frame3);
+  gtk_table_attach (GTK_TABLE (table1), frame3, 0, 1, 2, 3,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+
+  vbox3 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox3);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "vbox3", vbox3,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox3);
+  gtk_container_add (GTK_CONTAINER (frame3), vbox3);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox3), 5);
+
+  channels_1 = gtk_radio_button_new_with_label (channels_group, "Mono");
+  channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (channels_1));
+  gtk_widget_ref (channels_1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "channels_1", channels_1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (channels_1);
+  gtk_box_pack_start (GTK_BOX (vbox3), channels_1, FALSE, FALSE, 0);
+
+  channels_2 = gtk_radio_button_new_with_label (channels_group, "Stereo");
+  channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (channels_2));
+  gtk_widget_ref (channels_2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "channels_2", channels_2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (channels_2);
+  gtk_box_pack_start (GTK_BOX (vbox3), channels_2, FALSE, FALSE, 0);
+
+  frame4 = gtk_frame_new ("TiMidity Configuration File");
+  gtk_widget_ref (frame4);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "frame4", frame4,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (frame4);
+  gtk_table_attach (GTK_TABLE (table1), frame4, 0, 2, 0, 1,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+
+  vbox5 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox5);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "vbox5", vbox5,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox5);
+  gtk_container_add (GTK_CONTAINER (frame4), vbox5);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox5), 5);
+
+  config_file = gtk_entry_new ();
+  gtk_widget_ref (config_file);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "config_file", config_file,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (config_file);
+  gtk_box_pack_start (GTK_BOX (vbox5), config_file, TRUE, TRUE, 0);
+
+  hseparator1 = gtk_hseparator_new ();
+  gtk_widget_ref (hseparator1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "hseparator1", hseparator1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (hseparator1);
+  gtk_box_pack_start (GTK_BOX (vbox4), hseparator1, TRUE, TRUE, 0);
+
+  hbuttonbox1 = gtk_hbutton_box_new ();
+  gtk_widget_ref (hbuttonbox1);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "hbuttonbox1", hbuttonbox1,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (hbuttonbox1);
+  gtk_box_pack_start (GTK_BOX (vbox4), hbuttonbox1, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 5);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END);
+  gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox1), 10);
+
+  conf_ok = gtk_button_new_with_label ("Ok");
+  gtk_widget_ref (conf_ok);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "conf_ok", conf_ok,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (conf_ok);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox1), conf_ok);
+  GTK_WIDGET_SET_FLAGS (conf_ok, GTK_CAN_DEFAULT);
+
+  button2 = gtk_button_new_with_label ("Cancel");
+  gtk_widget_ref (button2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_conf_wnd), "button2", button2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (button2);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2);
+  GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);
+
+  gtk_signal_connect_object (GTK_OBJECT (button2), "clicked",
+                             GTK_SIGNAL_FUNC (gtk_widget_hide),
+                             GTK_OBJECT (xmmstimid_conf_wnd));
+
+  gtk_widget_grab_focus (conf_ok);
+  gtk_widget_grab_default (conf_ok);
+  return xmmstimid_conf_wnd;
+}
+
+GtkWidget*
+create_xmmstimid_about_wnd (void)
+{
+  GtkWidget *xmmstimid_about_wnd;
+  GtkWidget *vbox6;
+  GtkWidget *vbox7;
+  GtkWidget *name_version;
+  GtkWidget *label2;
+  GtkWidget *hseparator2;
+  GtkWidget *hbuttonbox2;
+  GtkWidget *button3;
+
+  xmmstimid_about_wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_object_set_data (GTK_OBJECT (xmmstimid_about_wnd), "xmmstimid_about_wnd", xmmstimid_about_wnd);
+  gtk_window_set_title (GTK_WINDOW (xmmstimid_about_wnd), "About TiMidity Plugin");
+  gtk_window_set_position (GTK_WINDOW (xmmstimid_about_wnd), GTK_WIN_POS_MOUSE);
+
+  vbox6 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox6);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "vbox6", vbox6,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox6);
+  gtk_container_add (GTK_CONTAINER (xmmstimid_about_wnd), vbox6);
+
+  vbox7 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (vbox7);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "vbox7", vbox7,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (vbox7);
+  gtk_box_pack_start (GTK_BOX (vbox6), vbox7, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox7), 20);
+
+  name_version = gtk_label_new ("TiMidity Plugin");
+  gtk_widget_ref (name_version);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "name_version", name_version,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (name_version);
+  gtk_box_pack_start (GTK_BOX (vbox7), name_version, TRUE, TRUE, 0);
+  gtk_misc_set_alignment (GTK_MISC (name_version), 0.5, 1);
+
+  label2 = gtk_label_new ("http://libtimidity.sourceforge.net\nby Konstantin Korikov");
+  gtk_widget_ref (label2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "label2", label2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (label2);
+  gtk_box_pack_start (GTK_BOX (vbox7), label2, TRUE, TRUE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label2), 0.5, 7.45058e-09);
+
+  hseparator2 = gtk_hseparator_new ();
+  gtk_widget_ref (hseparator2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "hseparator2", hseparator2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (hseparator2);
+  gtk_box_pack_start (GTK_BOX (vbox6), hseparator2, FALSE, TRUE, 0);
+
+  hbuttonbox2 = gtk_hbutton_box_new ();
+  gtk_widget_ref (hbuttonbox2);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "hbuttonbox2", hbuttonbox2,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (hbuttonbox2);
+  gtk_box_pack_start (GTK_BOX (vbox6), hbuttonbox2, FALSE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox2), 5);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_END);
+
+  button3 = gtk_button_new_with_label ("Ok");
+  gtk_widget_ref (button3);
+  gtk_object_set_data_full (GTK_OBJECT (xmmstimid_about_wnd), "button3", button3,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_show (button3);
+  gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3);
+  GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT);
+
+  gtk_signal_connect_object (GTK_OBJECT (button3), "clicked",
+                             GTK_SIGNAL_FUNC (gtk_widget_hide),
+                             GTK_OBJECT (xmmstimid_about_wnd));
+
+  gtk_widget_grab_focus (button3);
+  gtk_widget_grab_default (button3);
+  return xmmstimid_about_wnd;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/interface.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,6 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_xmmstimid_conf_wnd (void);
+GtkWidget* create_xmmstimid_about_wnd (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/xmms-timidity.c	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,465 @@
+/*
+    xmms-timidity - MIDI Plugin for XMMS
+    Copyright (C) 2004 Konstantin Korikov <lostclus@ua.fm>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <audacious/configfile.h>
+#include <audacious/titlestring.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <timidity.h>
+
+#include "xmms-timidity.h"
+#include "interface.h"
+
+InputPlugin xmmstimid_ip = {
+	NULL,
+	NULL,
+	NULL,
+	xmmstimid_init,
+	xmmstimid_about,
+	xmmstimid_configure,
+	xmmstimid_is_our_file,
+	NULL,
+	xmmstimid_play_file,
+	xmmstimid_stop,
+	xmmstimid_pause,
+	xmmstimid_seek,
+	NULL,
+	xmmstimid_get_time,
+	NULL,
+	NULL,
+	xmmstimid_cleanup,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	xmmstimid_get_song_info,
+	NULL,
+	NULL
+};
+
+static struct {
+	gchar *config_file;
+	gint rate;
+	gint bits;
+	gint channels;
+	gint buffer_size;
+} xmmstimid_cfg;
+
+static gboolean xmmstimid_initialized = FALSE;
+static pthread_t xmmstimid_decode_thread;
+static gboolean xmmstimid_audio_error = FALSE;
+static MidSongOptions xmmstimid_opts;
+static MidSong *xmmstimid_song;
+static gboolean xmmstimid_going;
+static gboolean xmmstimid_eof;
+static gint xmmstimid_seek_to;
+
+static GtkWidget *xmmstimid_conf_wnd = NULL, *xmmstimid_about_wnd = NULL;
+static GtkEntry
+	*xmmstimid_conf_config_file;
+static GtkToggleButton
+	*xmmstimid_conf_rate_11000,
+	*xmmstimid_conf_rate_22000,
+	*xmmstimid_conf_rate_44100;
+static GtkToggleButton
+	*xmmstimid_conf_bits_8,
+	*xmmstimid_conf_bits_16;
+static GtkToggleButton
+	*xmmstimid_conf_channels_1,
+	*xmmstimid_conf_channels_2;
+
+InputPlugin *get_iplugin_info(void) {
+	xmmstimid_ip.description = g_strdup_printf(
+			"TiMidity Player %s", VERSION);
+	return &xmmstimid_ip;
+}
+
+void xmmstimid_init(void) {
+	ConfigFile *cf;
+
+	xmmstimid_cfg.config_file = NULL;
+	xmmstimid_cfg.rate = 44100;
+	xmmstimid_cfg.bits = 16;
+	xmmstimid_cfg.channels = 2;
+	xmmstimid_cfg.buffer_size = 512;
+
+	cf = xmms_cfg_open_default_file();
+	if (cf != NULL) {
+		xmms_cfg_read_string(cf, "TIMIDITY", "config_file",
+				&xmmstimid_cfg.config_file);
+		xmms_cfg_read_int(cf, "TIMIDITY", "rate",
+				&xmmstimid_cfg.rate);
+		xmms_cfg_read_int(cf, "TIMIDITY", "bits",
+				&xmmstimid_cfg.bits);
+		xmms_cfg_read_int(cf, "TIMIDITY", "channels",
+				&xmmstimid_cfg.channels);
+		xmms_cfg_free(cf);
+	}
+
+	if (xmmstimid_cfg.config_file == NULL)
+		xmmstimid_cfg.config_file = g_strdup("/etc/timidity/timidity.cfg");
+
+	if (mid_init(xmmstimid_cfg.config_file) != 0) {
+		xmmstimid_initialized = FALSE;
+		return;
+	}
+	xmmstimid_initialized = TRUE;
+}
+
+void xmmstimid_about(void) {
+	if (xmmstimid_about_wnd == NULL) {
+		gchar *name_version;
+		xmmstimid_about_wnd = create_xmmstimid_about_wnd();
+		name_version = g_strdup_printf(
+				"TiMidity Plugin %s", VERSION);
+		gtk_label_set_text(
+				GTK_LABEL(gtk_object_get_data(
+				GTK_OBJECT(xmmstimid_about_wnd),
+				 "name_version")), name_version);
+		g_free(name_version);
+	}
+
+	gtk_widget_show(xmmstimid_about_wnd);
+	gdk_window_raise(xmmstimid_about_wnd->window);
+}
+
+void xmmstimid_conf_ok(GtkButton *button, gpointer user_data);
+
+void xmmstimid_configure(void) {
+	GtkToggleButton *tb;
+	if (xmmstimid_conf_wnd == NULL) {
+		xmmstimid_conf_wnd = create_xmmstimid_conf_wnd();
+
+#define get_conf_wnd_item(type, name) \
+	type (gtk_object_get_data(GTK_OBJECT(xmmstimid_conf_wnd), name))
+	
+		xmmstimid_conf_config_file = get_conf_wnd_item(
+				GTK_ENTRY, "config_file");
+		xmmstimid_conf_rate_11000 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "rate_11000");
+		xmmstimid_conf_rate_22000 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "rate_22000");
+		xmmstimid_conf_rate_44100 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "rate_44100");
+		xmmstimid_conf_bits_8 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "bits_8");
+		xmmstimid_conf_bits_16 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "bits_16");
+		xmmstimid_conf_channels_1 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "channels_1");
+		xmmstimid_conf_channels_2 = get_conf_wnd_item(
+				GTK_TOGGLE_BUTTON, "channels_2");
+
+		gtk_signal_connect_object(
+				get_conf_wnd_item(GTK_OBJECT, "conf_ok"),
+				"clicked", GTK_SIGNAL_FUNC(xmmstimid_conf_ok),
+				NULL);
+	}
+
+	gtk_entry_set_text(xmmstimid_conf_config_file,
+			xmmstimid_cfg.config_file);
+	switch (xmmstimid_cfg.rate) {
+		case 11000: tb = xmmstimid_conf_rate_11000; break;
+		case 22000: tb = xmmstimid_conf_rate_22000; break;
+		case 44100: tb = xmmstimid_conf_rate_44100; break;
+		default: tb = NULL;
+	}
+	if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE);
+	switch (xmmstimid_cfg.bits) {
+		case 8: tb = xmmstimid_conf_bits_8; break;
+		case 16: tb = xmmstimid_conf_bits_16; break;
+		default: tb = NULL;
+	}
+	if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE);
+	switch (xmmstimid_cfg.channels) {
+		case 1: tb = xmmstimid_conf_channels_1; break;
+		case 2: tb = xmmstimid_conf_channels_2; break;
+		default: tb = NULL;
+	}
+	if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE);
+
+	gtk_widget_show(xmmstimid_conf_wnd);
+	gdk_window_raise(xmmstimid_conf_wnd->window);
+}
+
+void xmmstimid_conf_ok(GtkButton *button, gpointer user_data) {
+	gchar *config_file, *filename;
+	ConfigFile *cf;
+
+	g_free(xmmstimid_cfg.config_file);
+	xmmstimid_cfg.config_file = g_strdup(
+			gtk_entry_get_text(xmmstimid_conf_config_file));
+
+	if (gtk_toggle_button_get_active(xmmstimid_conf_rate_11000))
+		xmmstimid_cfg.rate = 11000;
+	else if (gtk_toggle_button_get_active(xmmstimid_conf_rate_22000))
+		xmmstimid_cfg.rate = 22000;
+	else if (gtk_toggle_button_get_active(xmmstimid_conf_rate_44100))
+		xmmstimid_cfg.rate = 44100;
+	if (gtk_toggle_button_get_active(xmmstimid_conf_bits_8))
+		xmmstimid_cfg.bits = 8;
+	else if (gtk_toggle_button_get_active(xmmstimid_conf_bits_16))
+		xmmstimid_cfg.bits = 16;
+	if (gtk_toggle_button_get_active(xmmstimid_conf_channels_1))
+		xmmstimid_cfg.channels = 1;
+	else if (gtk_toggle_button_get_active(xmmstimid_conf_channels_2))
+		xmmstimid_cfg.channels = 2;
+
+	filename = g_strconcat(g_get_home_dir(), "/.audacious/config", NULL);
+	cf = xmms_cfg_open_file(filename);
+	if (cf == NULL) cf = xmms_cfg_new();
+
+	xmms_cfg_write_string(cf, "TIMIDITY", "config_file",
+			xmmstimid_cfg.config_file);
+	xmms_cfg_write_int(cf, "TIMIDITY", "rate",
+			xmmstimid_cfg.rate);
+	xmms_cfg_write_int(cf, "TIMIDITY", "bits",
+			xmmstimid_cfg.bits);
+	xmms_cfg_write_int(cf, "TIMIDITY", "channels",
+			xmmstimid_cfg.channels);
+
+	xmms_cfg_write_file(cf, filename);
+	xmms_cfg_free(cf);
+	g_free(filename);
+
+	gtk_widget_hide(xmmstimid_conf_wnd);
+}
+
+int xmmstimid_is_our_file(char *filename) {
+	gchar *ext;
+
+	ext = strrchr(filename, '.');
+	if (ext && !(
+	    strcasecmp(ext, ".mid") &&
+	    strcasecmp(ext, ".midi"))) return 1;
+
+	return 0;
+}
+
+static void *xmmstimid_play_loop(void *arg) {
+	size_t buffer_size;
+	void *buffer;
+	size_t bytes_read;
+	AFormat fmt;
+
+	buffer_size = ((xmmstimid_opts.format == MID_AUDIO_S16LSB) ? 16 : 8) * 
+			xmmstimid_opts.channels / 8 *
+			xmmstimid_opts.buffer_size;
+
+	buffer = g_malloc(buffer_size);
+	if (buffer == NULL) pthread_exit(NULL);
+
+	fmt = (xmmstimid_opts.format == MID_AUDIO_S16LSB) ? FMT_S16_LE : FMT_S8;
+
+	while (xmmstimid_going) {
+		bytes_read = mid_song_read_wave(xmmstimid_song,
+				buffer, buffer_size);
+
+		if (bytes_read != 0)
+			xmmstimid_ip.add_vis_pcm(
+					mid_song_get_time(xmmstimid_song),
+					fmt, xmmstimid_opts.channels,
+					bytes_read, buffer);
+		else xmmstimid_eof = TRUE;
+
+		while (xmmstimid_going && xmmstimid_seek_to == -1 &&
+				(bytes_read == 0 ||
+				 xmmstimid_ip.output->buffer_free() < bytes_read))
+			xmms_usleep(10000);
+
+		if (xmmstimid_seek_to != -1) {
+			mid_song_seek(xmmstimid_song, xmmstimid_seek_to * 1000);
+			xmmstimid_ip.output->flush(xmmstimid_seek_to * 1000);
+			xmmstimid_seek_to = -1;
+			bytes_read = 0;
+		}
+		
+		if (xmmstimid_going && bytes_read != 0)
+			xmmstimid_ip.output->write_audio(buffer, bytes_read);
+	}
+
+	g_free(buffer);
+
+	pthread_exit(NULL);
+}
+
+static gchar *xmmstimid_get_title(gchar *filename) {
+	TitleInput *input;
+	gchar *temp, *ext, *title, *path, *temp2;
+
+	input = bmp_title_input_new();
+
+	path = g_strdup(filename);
+	temp = g_strdup(filename);
+	ext = strrchr(temp, '.');
+	if (ext)
+		*ext = '\0';
+	temp2 = strrchr(path, '/');
+	if (temp2)
+		*temp2 = '\0';
+
+	input->file_name = g_basename(filename);
+	input->file_ext = ext ? ext+1 : NULL;
+	input->file_path = g_strdup_printf("%s/", path);
+
+	title = xmms_get_titlestring(xmms_get_gentitle_format(), input);
+	if (title == NULL)
+		title = g_strdup(input->file_name);
+
+	g_free(temp);
+	g_free(path);
+	g_free(input);
+
+	return title;
+}
+
+void xmmstimid_play_file(char *filename) {
+	MidIStream *stream;
+	gchar *title;
+
+	if (!xmmstimid_initialized) {
+		xmmstimid_init();
+		if (!xmmstimid_initialized) return;
+	}
+
+	if (xmmstimid_song != NULL) {
+		mid_song_free(xmmstimid_song);
+		xmmstimid_song = NULL;
+	}
+
+	stream = mid_istream_open_file(filename);
+	if (stream == NULL) return;
+
+	xmmstimid_audio_error = FALSE;
+
+	xmmstimid_opts.rate = xmmstimid_cfg.rate;
+	xmmstimid_opts.format = (xmmstimid_cfg.bits == 16) ?
+		MID_AUDIO_S16LSB : MID_AUDIO_S8;
+	xmmstimid_opts.channels = xmmstimid_cfg.channels;
+	xmmstimid_opts.buffer_size = xmmstimid_cfg.buffer_size;
+
+	xmmstimid_song = mid_song_load(stream, &xmmstimid_opts);
+	mid_istream_close(stream);
+
+	if (xmmstimid_song == NULL) {
+		xmmstimid_ip.set_info_text("Couldn't load MIDI file");
+		return;
+	}
+
+	if (xmmstimid_ip.output->open_audio(
+				(xmmstimid_opts.format == MID_AUDIO_S16LSB) ?
+				FMT_S16_LE : FMT_S8,
+				xmmstimid_opts.rate, xmmstimid_opts.channels) == 0) {
+		xmmstimid_audio_error = TRUE;
+		mid_song_free(xmmstimid_song);
+		xmmstimid_song = NULL;
+		return;
+	}
+
+	title = xmmstimid_get_title(filename);
+	xmmstimid_ip.set_info(title,
+			mid_song_get_total_time(xmmstimid_song),
+			0, xmmstimid_opts.rate, xmmstimid_opts.channels);
+	g_free(title);
+
+	mid_song_start(xmmstimid_song);
+	xmmstimid_going = TRUE;
+	xmmstimid_eof = FALSE;
+	xmmstimid_seek_to = -1;
+
+	if (pthread_create(&xmmstimid_decode_thread,
+				NULL, xmmstimid_play_loop, NULL) != 0) {
+		mid_song_free(xmmstimid_song);
+		xmmstimid_stop();
+	}
+}
+
+void xmmstimid_stop(void) {
+	if (xmmstimid_song != NULL && xmmstimid_going) {
+		xmmstimid_going = FALSE;
+		pthread_join(xmmstimid_decode_thread, NULL);
+		xmmstimid_ip.output->close_audio();
+		mid_song_free(xmmstimid_song);
+		xmmstimid_song = NULL;
+	}
+}
+
+void xmmstimid_pause(short p) {
+	xmmstimid_ip.output->pause(p);
+}
+
+void xmmstimid_seek(int time) {
+	xmmstimid_seek_to = time;
+	xmmstimid_eof = FALSE;
+
+	while (xmmstimid_seek_to != -1)
+		xmms_usleep(10000);
+}
+
+int xmmstimid_get_time(void) {
+	if (xmmstimid_audio_error)
+		return -2;
+	if (xmmstimid_song == NULL)
+		return -1;
+	if (!xmmstimid_going || (xmmstimid_eof &&
+				xmmstimid_ip.output->buffer_playing()))
+		return -1;
+
+	return mid_song_get_time(xmmstimid_song);
+}
+
+void xmmstimid_cleanup(void) {
+	if (xmmstimid_initialized)
+		mid_exit();
+}
+
+void xmmstimid_get_song_info(char *filename, char **title, int *length) {
+	MidIStream *stream;
+	MidSongOptions opts;
+	MidSong *song;
+
+	if (!xmmstimid_initialized) {
+		xmmstimid_init();
+		if (!xmmstimid_initialized) return;
+	}
+
+	stream = mid_istream_open_file(filename);
+	if (stream == NULL) return;
+
+	opts.rate = xmmstimid_cfg.rate;
+	opts.format = (xmmstimid_cfg.bits == 16) ?
+		MID_AUDIO_S16LSB : MID_AUDIO_S8;
+	opts.channels = xmmstimid_cfg.channels;
+	opts.buffer_size = 8;
+
+	song = mid_song_load(stream, &opts);
+	mid_istream_close(stream);
+
+	if (song == NULL) return;
+
+	*length = mid_song_get_total_time(song);
+	*title = xmmstimid_get_title(filename);
+
+	mid_song_free(song);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/timidity/src/xmms-timidity.h	Wed Dec 14 08:51:51 2005 -0800
@@ -0,0 +1,39 @@
+/*
+    xmms-timidity - MIDI Plugin for XMMS
+    Copyright (C) 2004 Konstantin Korikov <lostclus@ua.fm>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef XMMS_TIMIDITY_H
+#define XMMS_TIMIDITY_H
+
+#include <audacious/plugin.h>
+
+extern InputPlugin xmmstimid_ip;
+
+static void xmmstimid_init(void);
+static void xmmstimid_about(void);
+static void xmmstimid_configure(void);
+static int xmmstimid_is_our_file(char *filename);
+static void xmmstimid_play_file(char *filename);
+static void xmmstimid_stop(void);
+static void xmmstimid_pause(short p);
+static void xmmstimid_seek(int time);
+static int xmmstimid_get_time(void);
+static void xmmstimid_cleanup(void);
+static void xmmstimid_get_song_info(char *filename, char **title, int *length);
+
+#endif
--- a/configure.ac	Wed Dec 14 08:35:56 2005 -0800
+++ b/configure.ac	Wed Dec 14 08:51:51 2005 -0800
@@ -417,6 +417,16 @@
 
 AM_CONDITIONAL(ENABLE_WMA, test "$enable_wma" = "yes")
 
+dnl *** TiMidity
+
+AC_ARG_ENABLE(timidity,
+    [  --disable-timidity      disable timidity plugin. [default=enabled] ],
+    [enable_timidity=$enableval],
+    [enable_timidity=yes]
+)
+
+AM_CONDITIONAL(ENABLE_TIMIDITY, test "$enable_timidity" = "yes")
+
 dnl *** Crossfader
 
 AC_ARG_ENABLE(crossfade,
@@ -746,6 +756,9 @@
 	Plugins/Input/console/Makefile
 	Plugins/Input/wma/Makefile
 	Plugins/Input/wma/libffwma/Makefile
+	Plugins/Input/timidity/Makefile
+	Plugins/Input/timidity/libtimidity/Makefile
+	Plugins/Input/timidity/src/Makefile
         Plugins/Visualization/Makefile
         Plugins/Visualization/blur_scope/Makefile
 	Plugins/Visualization/libvisual-proxy/Makefile
@@ -801,6 +814,7 @@
 echo "  MPEG 4 Audio (AAC):                     $enable_aac"
 echo "  Windows Media Audio (wma):              $enable_wma"
 echo "  Module decoder (modplug):               $enable_modplug"
+echo "  MIDI to WAVE converter (timidity):      $enable_timidity"
 echo "  CD Digital Audio (cdda):                yes"
 echo "  Microsoft WAV (wav):                    yes"
 echo "    + sndfile extensions:                 $enable_sndfile"