Add "MikMod for Rockbox 0.1" from 2007-06-29 master
authornorly <ny-git@enpas.org>
Fri, 26 Apr 2019 14:26:03 +0000 (16:26 +0200)
committernorly <ny-git@enpas.org>
Fri, 26 Apr 2019 14:33:30 +0000 (16:33 +0200)
This is an early port of MikMod to Rockbox that I did back in 2007.
It was one of my early exercises in the C language.

Since I didn't upstream it back then, someone else ended up porting it
with a nicer UI.

Fun fact:
This version's PCM buffers are designed to be just about large enough
to allow an iPod Video to render fm-2year/rapido.xm without pausing.

40 files changed:
apps/plugins/mikmod/Makefile [new file with mode: 0644]
apps/plugins/mikmod/cygwin.bat [new file with mode: 0755]
apps/plugins/mikmod/include/mikmod_build.h [new file with mode: 0644]
apps/plugins/mikmod/include/mikmod_internals.h [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_669.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_amf.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_asy.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_dsm.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_far.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_gdm.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_imf.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_it.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_m15.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_med.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_mod.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_mtm.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_okt.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_s3m.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_stm.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_stx.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_ult.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_uni.c [new file with mode: 0644]
apps/plugins/mikmod/loaders/load_xm.c [new file with mode: 0644]
apps/plugins/mikmod/mikmod.c [new file with mode: 0644]
apps/plugins/mikmod/mmio/mmalloc.c [new file with mode: 0644]
apps/plugins/mikmod/mmio/mmerror.c [new file with mode: 0644]
apps/plugins/mikmod/mmio/mmio.c [new file with mode: 0644]
apps/plugins/mikmod/mmio/old_mmalloc.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mdriver.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mloader.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mlreg.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mlutil.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mplayer.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/munitrk.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/mwav.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/npertab.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/sloader.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/virtch.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/virtch2.c [new file with mode: 0644]
apps/plugins/mikmod/playercode/virtch_common.c [new file with mode: 0644]

diff --git a/apps/plugins/mikmod/Makefile b/apps/plugins/mikmod/Makefile
new file mode 100644 (file)
index 0000000..45a44ce
--- /dev/null
@@ -0,0 +1,154 @@
+#             __________               __   ___.\r
+#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___\r
+#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /\r
+#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <\r
+#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \\r
+#                     \/            \/     \/    \/            \/\r
+# $Id: Makefile 13515 2007-05-29 16:33:16Z nls $\r
+#\r
+\r
+INCLUDES = -I$(APPSDIR) \\r
+                       -I.. \\r
+                       -I. $(TARGET_INC) \\r
+                       -I$(FIRMDIR)/include \\r
+                       -I$(FIRMDIR)/export \\r
+                       -I$(FIRMDIR)/common \\r
+                       -I$(FIRMDIR)/drivers \\r
+                       -I$(OUTDIR) \\r
+                       -I$(BUILDDIR) \\r
+                       -I./include\r
+CFLAGS = $(INCLUDES) $(GCCOPTS) -O2 $(TARGET) $(EXTRA_DEFINES) \\r
+ -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN -DHAVE_SNPRINTF\r
+\r
+ifdef APPEXTRA\r
+   INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))\r
+endif\r
+\r
+LINKFILE := $(OBJDIR)/link.lds\r
+DEPFILE = $(OBJDIR)/dep-mikmod\r
+SRC = mikmod.c \\r
+       loaders/load_669.c \\r
+       loaders/load_amf.c \\r
+       loaders/load_asy.c \\r
+       loaders/load_dsm.c \\r
+       loaders/load_far.c \\r
+       loaders/load_gdm.c \\r
+       loaders/load_imf.c \\r
+       loaders/load_it.c \\r
+       loaders/load_m15.c \\r
+       loaders/load_med.c \\r
+       loaders/load_mod.c \\r
+       loaders/load_mtm.c \\r
+       loaders/load_s3m.c \\r
+       loaders/load_stm.c \\r
+       loaders/load_stx.c \\r
+       loaders/load_ult.c \\r
+       loaders/load_uni.c \\r
+       loaders/load_xm.c \\r
+       mmio/mmalloc.c \\r
+       mmio/mmerror.c \\r
+       mmio/mmio.c \\r
+       playercode/mdriver.c \\r
+       playercode/mloader.c \\r
+       playercode/mlreg.c \\r
+       playercode/mlutil.c \\r
+       playercode/mplayer.c \\r
+       playercode/munitrk.c \\r
+       playercode/mwav.c \\r
+       playercode/npertab.c \\r
+       playercode/sloader.c \\r
+       playercode/virtch2.c \\r
+       playercode/virtch.c \\r
+       playercode/virtch_common.c\r
+\r
+SOURCES = $(SRC)\r
+OBJS := $(SRC:%.c=$(OBJDIR)/%.o)\r
+DIRS = .\r
+\r
+ifndef SIMVER\r
+ifneq (,$(strip $(foreach tgt,RECORDER ONDIO,$(findstring $(tgt),$(TARGET)))))\r
+    LDS := archos.lds\r
+    OUTPUT = $(OUTDIR)/mikmod.ovl\r
+else  ## iRiver target\r
+    LDS := ../plugin.lds\r
+    OUTPUT = $(OUTDIR)/mikmod.rock\r
+endif\r
+else  ## simulators\r
+    OUTPUT = $(OUTDIR)/mikmod.rock\r
+endif\r
+\r
+all: $(OUTPUT)\r
+\r
+ifndef SIMVER\r
+$(OBJDIR)/mikmod.elf: $(OBJS) $(LINKFILE) $(BITMAPLIBS)\r
+       $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \\r
+           $(LINKBITMAPS) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/mikmod.map\r
+\r
+$(OUTPUT): $(OBJDIR)/mikmod.elf\r
+       $(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@\r
+else\r
+\r
+ifeq ($(SIMVER), x11)\r
+###################################################\r
+# This is the X11 simulator version\r
+\r
+$(OUTPUT): $(OBJS)\r
+       $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@\r
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)\r
+# 'x' must be kept or you'll have "Win32 error 5"\r
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1\r
+#         #define ERROR_ACCESS_DENIED 5L\r
+else\r
+       @chmod -x $@\r
+endif\r
+\r
+else # end of x11-simulator\r
+ifeq ($(SIMVER), sdl)\r
+###################################################\r
+# This is the SDL simulator version\r
+\r
+$(OUTPUT): $(OBJS)\r
+       $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@\r
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)\r
+# 'x' must be kept or you'll have "Win32 error 5"\r
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1\r
+#         #define ERROR_ACCESS_DENIED 5L\r
+else\r
+       @chmod -x $@\r
+endif\r
+\r
+else # end of sdl-simulator\r
+###################################################\r
+# This is the win32 simulator version\r
+DLLTOOLFLAGS = --export-all\r
+DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin\r
+\r
+$(OUTPUT): $(OBJS)\r
+       $(call PRINTS,DLL $(@F))$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)\r
+       $(SILENT)$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \\r
+                $(BUILDDIR)/libplugin.a $(BITMAPLIBS) -o $@\r
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)\r
+# 'x' must be kept or you'll have "Win32 error 5"\r
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1\r
+#         #define ERROR_ACCESS_DENIED 5L\r
+else\r
+       @chmod -x $@\r
+endif\r
+endif # end of win32-simulator\r
+endif\r
+endif # end of simulator section\r
+\r
+\r
+include $(TOOLSDIR)/make.inc\r
+\r
+# MEMORYSIZE should be passed on to this makefile with the chosen memory size\r
+# given in number of MB\r
+$(LINKFILE): $(LDS)\r
+       $(call PRINTS,build $(@F))cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \\r
+       $(DEFINES) -E -P - >$@\r
+\r
+clean:\r
+       $(call PRINTS,cleaning mikmod)rm -rf $(OBJDIR)/mikmod\r
+       $(SILENT)rm -f $(OBJDIR)/mikmod.* $(DEPFILE)\r
+\r
+-include $(DEPFILE)\r
diff --git a/apps/plugins/mikmod/cygwin.bat b/apps/plugins/mikmod/cygwin.bat
new file mode 100755 (executable)
index 0000000..6c2fe02
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+C:\r
+chdir C:\cygwin\bin\r
+\r
+bash --login -i\r
diff --git a/apps/plugins/mikmod/include/mikmod_build.h b/apps/plugins/mikmod/include/mikmod_build.h
new file mode 100644 (file)
index 0000000..0f80319
--- /dev/null
@@ -0,0 +1,753 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mikmod_build.h,v 1.3 2004/02/19 14:15:22 raph Exp $\r
+\r
+  MikMod sound library include file\r
+\r
+==============================================================================*/\r
+\r
+#ifndef _MIKMOD_H_\r
+#define _MIKMOD_H_\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/*\r
+ * ========== Compiler magic for shared libraries\r
+ */\r
+\r
+#if defined WIN32 && defined _DLL\r
+#ifdef DLL_EXPORTS\r
+#define MIKMODAPI __declspec(dllexport)\r
+#else\r
+#define MIKMODAPI __declspec(dllimport)\r
+#endif\r
+#else\r
+#define MIKMODAPI\r
+#endif\r
+\r
+#define BOOL BOOLTYPE\r
+\r
+#ifdef WIN32\r
+       #undef WIN32\r
+#endif\r
+\r
+/*\r
+ *     ========== Library version\r
+ */\r
+\r
+#define LIBMIKMOD_VERSION_MAJOR 3L\r
+#define LIBMIKMOD_VERSION_MINOR 2L\r
+#define LIBMIKMOD_REVISION      0L\r
+\r
+#define LIBMIKMOD_VERSION \\r
+       ((LIBMIKMOD_VERSION_MAJOR<<16)| \\r
+        (LIBMIKMOD_VERSION_MINOR<< 8)| \\r
+        (LIBMIKMOD_REVISION))\r
+\r
+MIKMODAPI extern long MikMod_GetVersion(void);\r
+\r
+/*\r
+ *     ========== Platform independent-type definitions\r
+ */\r
+\r
+#ifdef WIN32\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#include <io.h>\r
+#include <mmsystem.h>\r
+#endif\r
+\r
+#if defined(__OS2__)||defined(__EMX__)\r
+#define INCL_DOSSEMAPHORES\r
+#include <os2.h>\r
+#else\r
+typedef char CHAR;\r
+#endif\r
+\r
+\r
+\r
+#if defined(__arch64__) || defined(__alpha)\r
+/* 64 bit architectures */\r
+\r
+typedef signed char     SBYTE;      /* 1 byte, signed */\r
+typedef unsigned char   UBYTE;      /* 1 byte, unsigned */\r
+typedef signed short    SWORD;      /* 2 bytes, signed */\r
+typedef unsigned short  UWORD;      /* 2 bytes, unsigned */\r
+typedef signed int      SLONG;      /* 4 bytes, signed */\r
+typedef unsigned int    ULONG;      /* 4 bytes, unsigned */\r
+typedef int             BOOL;       /* 0=false, <>0 true */\r
+\r
+#else\r
+/* 32 bit architectures */\r
+\r
+typedef signed char     SBYTE;      /* 1 byte, signed */\r
+typedef unsigned char   UBYTE;      /* 1 byte, unsigned */\r
+typedef signed short    SWORD;      /* 2 bytes, signed */\r
+typedef unsigned short  UWORD;      /* 2 bytes, unsigned */\r
+typedef signed long     SLONG;      /* 4 bytes, signed */\r
+#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)\r
+typedef unsigned long   ULONG;      /* 4 bytes, unsigned */\r
+typedef int             BOOL;       /* 0=false, <>0 true */\r
+#endif\r
+#endif\r
+\r
+/*\r
+ *     ========== Error codes\r
+ */\r
+\r
+enum {\r
+       MMERR_OPENING_FILE = 1,\r
+       MMERR_OUT_OF_MEMORY,\r
+       MMERR_DYNAMIC_LINKING,\r
+\r
+       MMERR_SAMPLE_TOO_BIG,\r
+       MMERR_OUT_OF_HANDLES,\r
+       MMERR_UNKNOWN_WAVE_TYPE,\r
+\r
+       MMERR_LOADING_PATTERN,\r
+       MMERR_LOADING_TRACK,\r
+       MMERR_LOADING_HEADER,\r
+       MMERR_LOADING_SAMPLEINFO,\r
+       MMERR_NOT_A_MODULE,\r
+       MMERR_NOT_A_STREAM,\r
+       MMERR_MED_SYNTHSAMPLES,\r
+       MMERR_ITPACK_INVALID_DATA,\r
+\r
+       MMERR_DETECTING_DEVICE,\r
+       MMERR_INVALID_DEVICE,\r
+       MMERR_INITIALIZING_MIXER,\r
+       MMERR_OPENING_AUDIO,\r
+       MMERR_8BIT_ONLY,\r
+       MMERR_16BIT_ONLY,\r
+       MMERR_STEREO_ONLY,\r
+       MMERR_ULAW,\r
+       MMERR_NON_BLOCK,\r
+\r
+       MMERR_AF_AUDIO_PORT,\r
+\r
+       MMERR_AIX_CONFIG_INIT,\r
+       MMERR_AIX_CONFIG_CONTROL,\r
+       MMERR_AIX_CONFIG_START,\r
+\r
+       MMERR_GUS_SETTINGS,\r
+       MMERR_GUS_RESET,\r
+       MMERR_GUS_TIMER,\r
+\r
+       MMERR_HP_SETSAMPLESIZE,\r
+       MMERR_HP_SETSPEED,\r
+       MMERR_HP_CHANNELS,\r
+       MMERR_HP_AUDIO_OUTPUT,\r
+       MMERR_HP_AUDIO_DESC,\r
+       MMERR_HP_BUFFERSIZE,\r
+\r
+       MMERR_OSS_SETFRAGMENT,\r
+       MMERR_OSS_SETSAMPLESIZE,\r
+       MMERR_OSS_SETSTEREO,\r
+       MMERR_OSS_SETSPEED,\r
+\r
+       MMERR_SGI_SPEED,\r
+       MMERR_SGI_16BIT,\r
+       MMERR_SGI_8BIT,\r
+       MMERR_SGI_STEREO,\r
+       MMERR_SGI_MONO,\r
+\r
+       MMERR_SUN_INIT,\r
+\r
+       MMERR_OS2_MIXSETUP,\r
+       MMERR_OS2_SEMAPHORE,\r
+       MMERR_OS2_TIMER,\r
+       MMERR_OS2_THREAD,\r
+\r
+       MMERR_DS_PRIORITY,\r
+       MMERR_DS_BUFFER,\r
+       MMERR_DS_FORMAT,\r
+       MMERR_DS_NOTIFY,\r
+       MMERR_DS_EVENT,\r
+       MMERR_DS_THREAD,\r
+       MMERR_DS_UPDATE,\r
+\r
+       MMERR_WINMM_HANDLE,\r
+       MMERR_WINMM_ALLOCATED,\r
+       MMERR_WINMM_DEVICEID,\r
+       MMERR_WINMM_FORMAT,\r
+       MMERR_WINMM_UNKNOWN,\r
+\r
+       MMERR_MAC_SPEED,\r
+       MMERR_MAC_START,\r
+\r
+    MMERR_OSX_UNKNOWN_DEVICE,\r
+    MMERR_OSX_BAD_PROPERTY,\r
+    MMERR_OSX_UNSUPPORTED_FORMAT,\r
+    MMERR_OSX_SET_STEREO,\r
+    MMERR_OSX_BUFFER_ALLOC,\r
+    MMERR_OSX_ADD_IO_PROC,\r
+    MMERR_OSX_DEVICE_START,\r
+       MMERR_OSX_PTHREAD,\r
+\r
+       MMERR_DOSWSS_STARTDMA,\r
+       MMERR_DOSSB_STARTDMA,\r
+       \r
+       MMERR_MAX\r
+};\r
+\r
+/*\r
+ *     ========== Error handling\r
+ */\r
+\r
+typedef void (MikMod_handler)(void);\r
+typedef MikMod_handler *MikMod_handler_t;\r
+\r
+MIKMODAPI extern int  MikMod_errno;\r
+MIKMODAPI extern BOOL MikMod_critical;\r
+MIKMODAPI extern char *MikMod_strerror(int);\r
+\r
+MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);\r
+\r
+/*\r
+ *     ========== Library initialization and core functions\r
+ */\r
+\r
+struct MDRIVER;\r
+\r
+MIKMODAPI extern void   MikMod_RegisterAllDrivers(void);\r
+\r
+MIKMODAPI extern CHAR*  MikMod_InfoDriver(void);\r
+MIKMODAPI extern void   MikMod_RegisterDriver(struct MDRIVER*);\r
+MIKMODAPI extern int    MikMod_DriverFromAlias(CHAR*);\r
+MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);\r
+\r
+MIKMODAPI extern BOOL   MikMod_Init(CHAR*);\r
+MIKMODAPI extern void   MikMod_Exit(void);\r
+MIKMODAPI extern BOOL   MikMod_Reset(CHAR*);\r
+MIKMODAPI extern BOOL   MikMod_SetNumVoices(int,int);\r
+MIKMODAPI extern BOOL   MikMod_Active(void);\r
+MIKMODAPI extern BOOL   MikMod_EnableOutput(void);\r
+MIKMODAPI extern void   MikMod_DisableOutput(void);\r
+MIKMODAPI extern void   MikMod_Update(void);\r
+\r
+MIKMODAPI extern BOOL   MikMod_InitThreads(void);\r
+MIKMODAPI extern void   MikMod_Lock(void);\r
+MIKMODAPI extern void   MikMod_Unlock(void);\r
+\r
+/*\r
+ *     ========== Reader, Writer\r
+ */\r
+\r
+typedef struct MREADER {\r
+       BOOL (*Seek)(struct MREADER*,long,int);\r
+       long (*Tell)(struct MREADER*);\r
+       BOOL (*Read)(struct MREADER*,void*,size_t);\r
+       int  (*Get)(struct MREADER*);\r
+       BOOL (*Eof)(struct MREADER*);\r
+} MREADER;\r
+\r
+typedef struct MWRITER {\r
+       BOOL (*Seek)(struct MWRITER*,long,int);\r
+       long (*Tell)(struct MWRITER*);\r
+       BOOL (*Write)(struct MWRITER*,void*,size_t);\r
+       BOOL (*Put)(struct MWRITER*,int);\r
+} MWRITER;\r
+\r
+/*\r
+ *     ========== Samples\r
+ */\r
+\r
+/* Sample playback should not be interrupted */\r
+#define SFX_CRITICAL 1\r
+\r
+/* Sample format [loading and in-memory] flags: */\r
+#define SF_16BITS       0x0001\r
+#define SF_STEREO       0x0002\r
+#define SF_SIGNED       0x0004\r
+#define SF_BIG_ENDIAN   0x0008\r
+#define SF_DELTA        0x0010\r
+#define SF_ITPACKED            0x0020\r
+\r
+#define        SF_FORMATMASK   0x003F\r
+\r
+/* General Playback flags */\r
+\r
+#define SF_LOOP         0x0100\r
+#define SF_BIDI         0x0200\r
+#define SF_REVERSE      0x0400\r
+#define SF_SUSTAIN      0x0800\r
+\r
+#define SF_PLAYBACKMASK        0x0C00\r
+\r
+/* Module-only Playback Flags */\r
+\r
+#define SF_OWNPAN              0x1000\r
+#define SF_UST_LOOP     0x2000\r
+\r
+#define SF_EXTRAPLAYBACKMASK   0x3000\r
+\r
+/* Panning constants */\r
+#define PAN_LEFT               0\r
+#define PAN_HALFLEFT   64\r
+#define PAN_CENTER             128\r
+#define PAN_HALFRIGHT  192\r
+#define PAN_RIGHT              255\r
+#define PAN_SURROUND   512 /* panning value for Dolby Surround */\r
+\r
+typedef struct SAMPLE {\r
+       SWORD  panning;     /* panning (0-255 or PAN_SURROUND) */\r
+       ULONG  speed;       /* Base playing speed/frequency of note */\r
+       UBYTE  volume;      /* volume 0-64 */\r
+       UWORD  inflags;         /* sample format on disk */\r
+       UWORD  flags;       /* sample format in memory */\r
+       ULONG  length;      /* length of sample (in samples!) */\r
+       ULONG  loopstart;   /* repeat position (relative to start, in samples) */\r
+       ULONG  loopend;     /* repeat end */\r
+       ULONG  susbegin;    /* sustain loop begin (in samples) \  Not Supported */\r
+       ULONG  susend;      /* sustain loop end                /      Yet! */\r
+\r
+       /* Variables used by the module player only! (ignored for sound effects) */\r
+       UBYTE  globvol;     /* global volume */\r
+       UBYTE  vibflags;    /* autovibrato flag stuffs */\r
+       UBYTE  vibtype;     /* Vibratos moved from INSTRUMENT to SAMPLE */\r
+       UBYTE  vibsweep;\r
+       UBYTE  vibdepth;\r
+       UBYTE  vibrate;\r
+       CHAR*  samplename;  /* name of the sample */\r
+\r
+       /* Values used internally only */\r
+       UWORD  avibpos;     /* autovibrato pos [player use] */\r
+       UBYTE  divfactor;   /* for sample scaling, maintains proper period slides */\r
+       ULONG  seekpos;     /* seek position in file */\r
+       SWORD  handle;      /* sample handle used by individual drivers */\r
+} SAMPLE;\r
+\r
+/* Sample functions */\r
+\r
+MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);\r
+MIKMODAPI extern SAMPLE *Sample_LoadFP(int);\r
+MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);\r
+MIKMODAPI extern void   Sample_Free(SAMPLE*);\r
+MIKMODAPI extern SBYTE  Sample_Play(SAMPLE*,ULONG,UBYTE);\r
+\r
+MIKMODAPI extern void   Voice_SetVolume(SBYTE,UWORD);\r
+MIKMODAPI extern UWORD  Voice_GetVolume(SBYTE);\r
+MIKMODAPI extern void   Voice_SetFrequency(SBYTE,ULONG);\r
+MIKMODAPI extern ULONG  Voice_GetFrequency(SBYTE);\r
+MIKMODAPI extern void   Voice_SetPanning(SBYTE,ULONG);\r
+MIKMODAPI extern ULONG  Voice_GetPanning(SBYTE);\r
+MIKMODAPI extern void   Voice_Play(SBYTE,SAMPLE*,ULONG);\r
+MIKMODAPI extern void   Voice_Stop(SBYTE);\r
+MIKMODAPI extern BOOL   Voice_Stopped(SBYTE);\r
+MIKMODAPI extern SLONG  Voice_GetPosition(SBYTE);\r
+MIKMODAPI extern ULONG  Voice_RealVolume(SBYTE);\r
+\r
+/*\r
+ *     ========== Internal module representation (UniMod)\r
+ */\r
+\r
+/*\r
+       Instrument definition - for information only, the only field which may be\r
+       of use in user programs is the name field\r
+*/\r
+\r
+/* Instrument note count */\r
+#define INSTNOTES 120\r
+\r
+/* Envelope point */\r
+typedef struct ENVPT {\r
+       SWORD pos;\r
+       SWORD val;\r
+} ENVPT;\r
+\r
+/* Envelope point count */\r
+#define ENVPOINTS 32\r
+\r
+/* Instrument structure */\r
+typedef struct INSTRUMENT {\r
+       CHAR* insname;\r
+\r
+       UBYTE flags;\r
+       UWORD samplenumber[INSTNOTES];\r
+       UBYTE samplenote[INSTNOTES];\r
+\r
+       UBYTE nnatype;\r
+       UBYTE dca;              /* duplicate check action */\r
+       UBYTE dct;              /* duplicate check type */\r
+       UBYTE globvol;\r
+       UWORD volfade;\r
+       SWORD panning;          /* instrument-based panning var */\r
+\r
+       UBYTE pitpansep;        /* pitch pan separation (0 to 255) */\r
+       UBYTE pitpancenter;     /* pitch pan center (0 to 119) */\r
+       UBYTE rvolvar;          /* random volume varations (0 - 100%) */\r
+       UBYTE rpanvar;          /* random panning varations (0 - 100%) */\r
+\r
+       /* volume envelope */\r
+       UBYTE volflg;           /* bit 0: on 1: sustain 2: loop */\r
+       UBYTE volpts;\r
+       UBYTE volsusbeg;\r
+       UBYTE volsusend;\r
+       UBYTE volbeg;\r
+       UBYTE volend;\r
+       ENVPT volenv[ENVPOINTS];\r
+       /* panning envelope */\r
+       UBYTE panflg;           /* bit 0: on 1: sustain 2: loop */\r
+       UBYTE panpts;\r
+       UBYTE pansusbeg;\r
+       UBYTE pansusend;\r
+       UBYTE panbeg;\r
+       UBYTE panend;\r
+       ENVPT panenv[ENVPOINTS];\r
+       /* pitch envelope */\r
+       UBYTE pitflg;           /* bit 0: on 1: sustain 2: loop */\r
+       UBYTE pitpts;\r
+       UBYTE pitsusbeg;\r
+       UBYTE pitsusend;\r
+       UBYTE pitbeg;\r
+       UBYTE pitend;\r
+       ENVPT pitenv[ENVPOINTS];\r
+} INSTRUMENT;\r
+\r
+struct MP_CONTROL;\r
+struct MP_VOICE;\r
+\r
+/*\r
+       Module definition\r
+*/\r
+\r
+/* maximum master channels supported */\r
+#define UF_MAXCHAN     64\r
+\r
+/* Module flags */\r
+#define UF_XMPERIODS   0x0001 /* XM periods / finetuning */\r
+#define UF_LINEAR              0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */\r
+#define UF_INST                        0x0004 /* Instruments are used */\r
+#define UF_NNA                 0x0008 /* IT: NNA used, set numvoices rather\r
+                                                                 than numchn */\r
+#define UF_S3MSLIDES   0x0010 /* uses old S3M volume slides */\r
+#define UF_BGSLIDES            0x0020 /* continue volume slides in the background */\r
+#define UF_HIGHBPM             0x0040 /* MED: can use >255 bpm */\r
+#define UF_NOWRAP              0x0080 /* XM-type (i.e. illogical) pattern break\r
+                                                                 semantics */\r
+#define UF_ARPMEM              0x0100 /* IT: need arpeggio memory */\r
+#define UF_FT2QUIRKS   0x0200 /* emulate some FT2 replay quirks */\r
+#define UF_PANNING             0x0400 /* module uses panning effects or have\r
+                                                                 non-tracker default initial panning */\r
+\r
+typedef struct MODULE {\r
+       /* general module information */\r
+               CHAR*       songname;    /* name of the song */\r
+               CHAR*       modtype;     /* string type of module loaded */\r
+               CHAR*       comment;     /* module comments */\r
+\r
+               UWORD       flags;       /* See module flags above */\r
+               UBYTE       numchn;      /* number of module channels */\r
+               UBYTE       numvoices;   /* max # voices used for full NNA playback */\r
+               UWORD       numpos;      /* number of positions in this song */\r
+               UWORD       numpat;      /* number of patterns in this song */\r
+               UWORD       numins;      /* number of instruments */\r
+               UWORD       numsmp;      /* number of samples */\r
+struct  INSTRUMENT* instruments; /* all instruments */\r
+struct  SAMPLE*     samples;     /* all samples */\r
+               UBYTE       realchn;     /* real number of channels used */\r
+               UBYTE       totalchn;    /* total number of channels used (incl NNAs) */\r
+\r
+       /* playback settings */\r
+               UWORD       reppos;      /* restart position */\r
+               UBYTE       initspeed;   /* initial song speed */\r
+               UWORD       inittempo;   /* initial song tempo */\r
+               UBYTE       initvolume;  /* initial global volume (0 - 128) */\r
+               UWORD       panning[UF_MAXCHAN]; /* panning positions */\r
+               UBYTE       chanvol[UF_MAXCHAN]; /* channel positions */\r
+               UWORD       bpm;         /* current beats-per-minute speed */\r
+               UWORD       sngspd;      /* current song speed */\r
+               SWORD       volume;      /* song volume (0-128) (or user volume) */\r
+\r
+               BOOL        extspd;      /* extended speed flag (default enabled) */\r
+               BOOL        panflag;     /* panning flag (default enabled) */\r
+               BOOL        wrap;        /* wrap module ? (default disabled) */\r
+               BOOL        loop;                /* allow module to loop ? (default enabled) */\r
+               BOOL        fadeout;     /* volume fade out during last pattern */\r
+\r
+               UWORD       patpos;      /* current row number */\r
+               SWORD       sngpos;      /* current song position */\r
+               ULONG       sngtime;     /* current song time in 2^-10 seconds */\r
+\r
+               SWORD       relspd;      /* relative speed factor */\r
+\r
+       /* internal module representation */\r
+               UWORD       numtrk;      /* number of tracks */\r
+               UBYTE**     tracks;      /* array of numtrk pointers to tracks */\r
+               UWORD*      patterns;    /* array of Patterns */\r
+               UWORD*      pattrows;    /* array of number of rows for each pattern */\r
+               UWORD*      positions;   /* all positions */\r
+\r
+               BOOL        forbid;      /* if true, no player update! */\r
+               UWORD       numrow;      /* number of rows on current pattern */\r
+               UWORD       vbtick;      /* tick counter (counts from 0 to sngspd) */\r
+               UWORD       sngremainder;/* used for song time computation */\r
+\r
+struct MP_CONTROL*  control;     /* Effects Channel info (size pf->numchn) */\r
+struct MP_VOICE*    voice;       /* Audio Voice information (size md_numchn) */\r
+\r
+               UBYTE       globalslide; /* global volume slide rate */\r
+               UBYTE       pat_repcrazy;/* module has just looped to position -1 */\r
+               UWORD       patbrk;      /* position where to start a new pattern */\r
+               UBYTE       patdly;      /* patterndelay counter (command memory) */\r
+               UBYTE       patdly2;     /* patterndelay counter (real one) */\r
+               SWORD       posjmp;      /* flag to indicate a jump is needed... */\r
+               UWORD           bpmlimit;        /* threshold to detect bpm or speed values */\r
+} MODULE;\r
+\r
+\r
+/* This structure is used to query current playing voices status */\r
+typedef struct VOICEINFO {\r
+               INSTRUMENT* i;            /* Current channel instrument */\r
+               SAMPLE*     s;            /* Current channel sample */\r
+               SWORD       panning;      /* panning position */\r
+               SBYTE       volume;       /* channel's "global" volume (0..64) */\r
+               UWORD       period;       /* period to play the sample at */\r
+               UBYTE       kick;         /* if true = sample has been restarted */\r
+} VOICEINFO;\r
+\r
+/*\r
+ *     ========== Module loaders\r
+ */\r
+\r
+struct MLOADER;\r
+\r
+MIKMODAPI extern CHAR*   MikMod_InfoLoader(void);\r
+MIKMODAPI extern void    MikMod_RegisterAllLoaders(void);\r
+MIKMODAPI extern void    MikMod_RegisterLoader(struct MLOADER*);\r
+\r
+MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */\r
+MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */\r
+MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */\r
+MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */\r
+MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */\r
+MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */\r
+MIKMODAPI extern struct MLOADER load_it;  /* Impulse Tracker (by Jeffrey Lim) */\r
+MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */\r
+MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */\r
+MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */\r
+MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */\r
+MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */\r
+MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */\r
+MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */\r
+MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */\r
+MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */\r
+MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */\r
+MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */\r
+MIKMODAPI extern struct MLOADER load_xm;  /* FastTracker 2 (by Triton) */\r
+\r
+/*\r
+ *     ========== Module player\r
+ */\r
+\r
+MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL);\r
+MIKMODAPI extern MODULE* Player_LoadFP(int,int,BOOL);\r
+MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);\r
+MIKMODAPI extern CHAR*   Player_LoadTitle(CHAR*);\r
+MIKMODAPI extern CHAR*   Player_LoadTitleFP(int);\r
+MIKMODAPI extern void    Player_Free(MODULE*);\r
+MIKMODAPI extern void    Player_Start(MODULE*);\r
+MIKMODAPI extern BOOL    Player_Active(void);\r
+MIKMODAPI extern void    Player_Stop(void);\r
+MIKMODAPI extern void    Player_TogglePause(void);\r
+MIKMODAPI extern BOOL    Player_Paused(void);\r
+MIKMODAPI extern void    Player_NextPosition(void);\r
+MIKMODAPI extern void    Player_PrevPosition(void);\r
+MIKMODAPI extern void    Player_SetPosition(UWORD);\r
+MIKMODAPI extern BOOL    Player_Muted(UBYTE);\r
+MIKMODAPI extern void    Player_SetVolume(SWORD);\r
+MIKMODAPI extern MODULE* Player_GetModule(void);\r
+MIKMODAPI extern void    Player_SetSpeed(UWORD);\r
+MIKMODAPI extern void    Player_SetTempo(UWORD);\r
+MIKMODAPI extern void    Player_Unmute(SLONG,...);\r
+MIKMODAPI extern void    Player_Mute(SLONG,...);\r
+MIKMODAPI extern void    Player_ToggleMute(SLONG,...);\r
+MIKMODAPI extern int     Player_GetChannelVoice(UBYTE);\r
+MIKMODAPI extern UWORD   Player_GetChannelPeriod(UBYTE);\r
+MIKMODAPI extern int     Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo); \r
+\r
+typedef void (MikMod_player)(void);\r
+typedef MikMod_player *MikMod_player_t;\r
+\r
+MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t);\r
+\r
+#define MUTE_EXCLUSIVE  32000\r
+#define MUTE_INCLUSIVE  32001\r
+\r
+/*\r
+ *     ========== Drivers\r
+ */\r
+\r
+enum {\r
+       MD_MUSIC = 0,\r
+       MD_SNDFX\r
+};\r
+\r
+enum {\r
+       MD_HARDWARE = 0,\r
+       MD_SOFTWARE\r
+};\r
+\r
+/* Mixing flags */\r
+\r
+/* These ones take effect only after MikMod_Init or MikMod_Reset */\r
+#define DMODE_16BITS     0x0001 /* enable 16 bit output */\r
+#define DMODE_STEREO     0x0002 /* enable stereo output */\r
+#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */\r
+#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */\r
+#define DMODE_HQMIXER    0x0010 /* Use high-quality (slower) software mixer */\r
+#define DMODE_FLOAT      0x0020 /* enable float output */\r
+/* These take effect immediately. */\r
+#define DMODE_SURROUND   0x0100 /* enable surround sound */\r
+#define DMODE_INTERP     0x0200 /* enable interpolation */\r
+#define DMODE_REVERSE    0x0400 /* reverse stereo */\r
+\r
+struct SAMPLOAD;\r
+typedef struct MDRIVER {\r
+struct MDRIVER* next;\r
+       CHAR*       Name;\r
+       CHAR*       Version;\r
+\r
+       UBYTE       HardVoiceLimit; /* Limit of hardware mixer voices */\r
+       UBYTE       SoftVoiceLimit; /* Limit of software mixer voices */\r
+\r
+       CHAR        *Alias;\r
+       CHAR        *CmdLineHelp;\r
+\r
+       void        (*CommandLine)      (CHAR*);\r
+       BOOL        (*IsPresent)        (void);\r
+       SWORD       (*SampleLoad)       (struct SAMPLOAD*,int);\r
+       void        (*SampleUnload)     (SWORD);\r
+       ULONG       (*FreeSampleSpace)  (int);\r
+       ULONG       (*RealSampleLength) (int,struct SAMPLE*);\r
+       BOOL        (*Init)             (void);\r
+       void        (*Exit)             (void);\r
+       BOOL        (*Reset)            (void);\r
+       BOOL        (*SetNumVoices)     (void);\r
+       BOOL        (*PlayStart)        (void);\r
+       void        (*PlayStop)         (void);\r
+       void        (*Update)           (void);\r
+       void            (*Pause)                        (void);\r
+       void        (*VoiceSetVolume)   (UBYTE,UWORD);\r
+       UWORD       (*VoiceGetVolume)   (UBYTE);\r
+       void        (*VoiceSetFrequency)(UBYTE,ULONG);\r
+       ULONG       (*VoiceGetFrequency)(UBYTE);\r
+       void        (*VoiceSetPanning)  (UBYTE,ULONG);\r
+       ULONG       (*VoiceGetPanning)  (UBYTE);\r
+       void        (*VoicePlay)        (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+       void        (*VoiceStop)        (UBYTE);\r
+       BOOL        (*VoiceStopped)     (UBYTE);\r
+       SLONG       (*VoiceGetPosition) (UBYTE);\r
+       ULONG       (*VoiceRealVolume)  (UBYTE);\r
+} MDRIVER;\r
+\r
+/* These variables can be changed at ANY time and results will be immediate */\r
+MIKMODAPI extern UBYTE md_volume;      /* global sound volume (0-128) */\r
+MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */\r
+MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */\r
+MIKMODAPI extern UBYTE md_reverb;      /* 0 = none;  15 = chaos */\r
+MIKMODAPI extern UBYTE md_pansep;      /* 0 = mono;  128 == 100% (full left/right) */\r
+\r
+/* The variables below can be changed at any time, but changes will not be\r
+   implemented until MikMod_Reset is called. A call to MikMod_Reset may result\r
+   in a skip or pop in audio (depending on the soundcard driver and the settings\r
+   changed). */\r
+MIKMODAPI extern UWORD md_device;      /* device */\r
+MIKMODAPI extern UWORD md_mixfreq;     /* mixing frequency */\r
+MIKMODAPI extern UWORD md_mode;        /* mode. See DMODE_? flags above */\r
+\r
+/* The following variable should not be changed! */\r
+MIKMODAPI extern MDRIVER* md_driver;   /* Current driver in use. */\r
+\r
+/* Known drivers list */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_nos;    /* no sound */\r
+MIKMODAPI extern struct MDRIVER drv_pipe;   /* piped output */\r
+MIKMODAPI extern struct MDRIVER drv_raw;    /* raw file disk writer [music.raw] */\r
+MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */\r
+MIKMODAPI extern struct MDRIVER drv_wav;    /* RIFF WAVE file disk writer [music.wav] */\r
+MIKMODAPI extern struct MDRIVER drv_aiff;   /* AIFF file disk writer [music.aiff] */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_ultra;  /* Linux Ultrasound driver */\r
+MIKMODAPI extern struct MDRIVER drv_sam9407;   /* Linux sam9407 driver */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_AF;     /* Dec Alpha AudioFile */\r
+MIKMODAPI extern struct MDRIVER drv_aix;    /* AIX audio device */\r
+MIKMODAPI extern struct MDRIVER drv_alsa;   /* Advanced Linux Sound Architecture (ALSA) */\r
+MIKMODAPI extern struct MDRIVER drv_esd;    /* Enlightened sound daemon (EsounD) */\r
+MIKMODAPI extern struct MDRIVER drv_hp;     /* HP-UX audio device */\r
+MIKMODAPI extern struct MDRIVER drv_oss;    /* OpenSound System (Linux,FreeBSD...) */\r
+MIKMODAPI extern struct MDRIVER drv_sgi;    /* SGI audio library */\r
+MIKMODAPI extern struct MDRIVER drv_sun;    /* Sun/NetBSD/OpenBSD audio device */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_dart;   /* OS/2 Direct Audio RealTime */\r
+MIKMODAPI extern struct MDRIVER drv_os2;    /* OS/2 MMPM/2 */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_ds;     /* Win32 DirectSound driver */\r
+MIKMODAPI extern struct MDRIVER drv_win;    /* Win32 multimedia API driver */\r
+\r
+MIKMODAPI extern struct MDRIVER drv_mac;    /* Macintosh Sound Manager driver */\r
+MIKMODAPI extern struct MDRIVER drv_osx;       /* MacOS X CoreAudio Driver */\r
+\r
+/*========== Virtual channel mixer interface (for user-supplied drivers only) */\r
+\r
+MIKMODAPI extern BOOL  VC_Init(void);\r
+MIKMODAPI extern void  VC_Exit(void);\r
+MIKMODAPI extern BOOL  VC_SetNumVoices(void);\r
+MIKMODAPI extern ULONG VC_SampleSpace(int);\r
+MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);\r
+\r
+MIKMODAPI extern BOOL  VC_PlayStart(void);\r
+MIKMODAPI extern void  VC_PlayStop(void);\r
+\r
+MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);\r
+MIKMODAPI extern void  VC_SampleUnload(SWORD);\r
+\r
+MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);\r
+MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);\r
+\r
+MIKMODAPI extern void  VC_VoiceSetVolume(UBYTE,UWORD);\r
+MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);\r
+MIKMODAPI extern void  VC_VoiceSetFrequency(UBYTE,ULONG);\r
+MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);\r
+MIKMODAPI extern void  VC_VoiceSetPanning(UBYTE,ULONG);\r
+MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);\r
+MIKMODAPI extern void  VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+\r
+MIKMODAPI extern void  VC_VoiceStop(UBYTE);\r
+MIKMODAPI extern BOOL  VC_VoiceStopped(UBYTE);\r
+MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);\r
+MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/include/mikmod_internals.h b/apps/plugins/mikmod/include/mikmod_internals.h
new file mode 100644 (file)
index 0000000..53dd755
--- /dev/null
@@ -0,0 +1,729 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
+\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mikmod_internals.h,v 1.4 2004/02/18 13:29:17 raph Exp $\r
+\r
+  MikMod sound library internal definitions\r
+\r
+==============================================================================*/\r
+\r
+#ifndef _MIKMOD_INTERNALS_H\r
+#define _MIKMOD_INTERNALS_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifdef HAVE_MALLOC_H\r
+#include <malloc.h>\r
+#endif\r
+#include <stdarg.h>\r
+#if defined(__OS2__)||defined(__EMX__)||defined(WIN32)\r
+#define strcasecmp(s,t) stricmp(s,t)\r
+#endif\r
+\r
+\r
+#include "plugin.h"\r
+extern struct plugin_api *rb;\r
+\r
+#include <mikmod_build.h>\r
+\r
+#ifdef WIN32\r
+#pragma warning(disable:4761)\r
+#endif\r
+\r
+/*========== More type definitions */\r
+\r
+/* SLONGLONG: 64bit, signed */\r
+typedef long long      SLONGLONG;\r
+\r
+/*========== Error handling */\r
+\r
+#define _mm_errno MikMod_errno\r
+#define _mm_critical MikMod_critical\r
+extern MikMod_handler_t _mm_errorhandler;\r
+\r
+/*========== Memory allocation */\r
+\r
+extern void* _mm_malloc(size_t);\r
+extern void* _mm_calloc(size_t,size_t);\r
+#define _mm_free(p) do { if (p) free(p); p = NULL; } while(0)\r
+\r
+/*========== MT stuff */\r
+\r
+#ifdef HAVE_PTHREAD\r
+#include <pthread.h>\r
+#define DECLARE_MUTEX(name) \\r
+       extern pthread_mutex_t _mm_mutex_##name\r
+#define MUTEX_LOCK(name)       \\r
+       pthread_mutex_lock(&_mm_mutex_##name)\r
+#define MUTEX_UNLOCK(name)     \\r
+       pthread_mutex_unlock(&_mm_mutex_##name)\r
+#elif defined(__OS2__)||defined(__EMX__)\r
+#define DECLARE_MUTEX(name)    \\r
+       extern HMTX _mm_mutex_##name\r
+#define MUTEX_LOCK(name)       \\r
+       if(_mm_mutex_##name)    \\r
+               DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT)\r
+#define MUTEX_UNLOCK(name)     \\r
+       if(_mm_mutex_##name)    \\r
+               DosReleaseMutexSem(_mm_mutex_##name)\r
+#elif defined(WIN32)\r
+#include <windows.h>\r
+#define DECLARE_MUTEX(name)    \\r
+       extern HANDLE _mm_mutex_##name\r
+#define MUTEX_LOCK(name)       \\r
+       if(_mm_mutex_##name)    \\r
+               WaitForSingleObject(_mm_mutex_##name,INFINITE)\r
+#define MUTEX_UNLOCK(name)     \\r
+       if(_mm_mutex_##name)    \\r
+               ReleaseMutex(_mm_mutex_##name)\r
+#else\r
+#define DECLARE_MUTEX(name)    \\r
+       extern void *_mm_mutex_##name\r
+#define MUTEX_LOCK(name)\r
+#define MUTEX_UNLOCK(name)\r
+#endif\r
+\r
+DECLARE_MUTEX(lists);\r
+DECLARE_MUTEX(vars);\r
+\r
+/*========== Portable file I/O */\r
+\r
+extern MREADER* _mm_new_file_reader(int fp);\r
+extern void _mm_delete_file_reader(MREADER*);\r
+\r
+extern MWRITER* _mm_new_file_writer(int fp);\r
+extern void _mm_delete_file_writer(MWRITER*);\r
+\r
+extern BOOL _mm_FileExists(CHAR *fname);\r
+\r
+#define _mm_write_SBYTE(x,y) y->Put(y,(int)x)\r
+#define _mm_write_UBYTE(x,y) y->Put(y,(int)x)\r
+\r
+#define _mm_read_SBYTE(x) (SBYTE)x->Get(x)\r
+#define _mm_read_UBYTE(x) (UBYTE)x->Get(x)\r
+\r
+#define _mm_write_SBYTES(x,y,z) z->Write(z,(void *)x,y)\r
+#define _mm_write_UBYTES(x,y,z) z->Write(z,(void *)x,y)\r
+#define _mm_read_SBYTES(x,y,z)  z->Read(z,(void *)x,y)\r
+#define _mm_read_UBYTES(x,y,z)  z->Read(z,(void *)x,y)\r
+\r
+#define _mm_fseek(x,y,z) x->Seek(x,y,z)\r
+#define _mm_ftell(x) x->Tell(x)\r
+#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)\r
+\r
+#define _mm_eof(x) x->Eof(x)\r
+\r
+extern void _mm_iobase_setcur(MREADER*);\r
+extern void _mm_iobase_revert(void);\r
+extern int _mm_fopen(CHAR*,int);\r
+extern int     _mm_fclose(int);\r
+extern void _mm_write_string(CHAR*,MWRITER*);\r
+extern int  _mm_read_string (CHAR*,int,MREADER*);\r
+\r
+extern SWORD _mm_read_M_SWORD(MREADER*);\r
+extern SWORD _mm_read_I_SWORD(MREADER*);\r
+extern UWORD _mm_read_M_UWORD(MREADER*);\r
+extern UWORD _mm_read_I_UWORD(MREADER*);\r
+\r
+extern SLONG _mm_read_M_SLONG(MREADER*);\r
+extern SLONG _mm_read_I_SLONG(MREADER*);\r
+extern ULONG _mm_read_M_ULONG(MREADER*);\r
+extern ULONG _mm_read_I_ULONG(MREADER*);\r
+\r
+extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);\r
+extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);\r
+extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);\r
+extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);\r
+\r
+extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);\r
+extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);\r
+extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);\r
+extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);\r
+\r
+extern void _mm_write_M_SWORD(SWORD,MWRITER*);\r
+extern void _mm_write_I_SWORD(SWORD,MWRITER*);\r
+extern void _mm_write_M_UWORD(UWORD,MWRITER*);\r
+extern void _mm_write_I_UWORD(UWORD,MWRITER*);\r
+\r
+extern void _mm_write_M_SLONG(SLONG,MWRITER*);\r
+extern void _mm_write_I_SLONG(SLONG,MWRITER*);\r
+extern void _mm_write_M_ULONG(ULONG,MWRITER*);\r
+extern void _mm_write_I_ULONG(ULONG,MWRITER*);\r
+\r
+extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);\r
+extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);\r
+extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);\r
+extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);\r
+\r
+extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);\r
+extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);\r
+extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);\r
+extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*);\r
+\r
+/*========== Samples */\r
+\r
+/* This is a handle of sorts attached to any sample registered with\r
+   SL_RegisterSample.  Generally, this only need be used or changed by the\r
+   loaders and drivers of mikmod. */\r
+typedef struct SAMPLOAD {\r
+       struct SAMPLOAD *next;\r
+\r
+       ULONG    length;       /* length of sample (in samples!) */\r
+       ULONG    loopstart;    /* repeat position (relative to start, in samples) */\r
+       ULONG    loopend;      /* repeat end */\r
+       UWORD    infmt,outfmt;\r
+       int      scalefactor;\r
+       SAMPLE*  sample;\r
+       MREADER* reader;\r
+} SAMPLOAD;\r
+\r
+/*========== Sample and waves loading interface */\r
+\r
+extern void      SL_HalveSample(SAMPLOAD*,int);\r
+extern void      SL_Sample8to16(SAMPLOAD*);\r
+extern void      SL_Sample16to8(SAMPLOAD*);\r
+extern void      SL_SampleSigned(SAMPLOAD*);\r
+extern void      SL_SampleUnsigned(SAMPLOAD*);\r
+extern BOOL      SL_LoadSamples(void);\r
+extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);\r
+extern BOOL      SL_Load(void*,SAMPLOAD*,ULONG);\r
+extern BOOL      SL_Init(SAMPLOAD*);\r
+extern void      SL_Exit(SAMPLOAD*);\r
+\r
+/*========== Internal module representation (UniMod) interface */\r
+\r
+/* number of notes in an octave */\r
+#define OCTAVE 12\r
+\r
+extern void   UniSetRow(UBYTE*);\r
+extern UBYTE  UniGetByte(void);\r
+extern UWORD  UniGetWord(void);\r
+extern UBYTE* UniFindRow(UBYTE*,UWORD);\r
+extern void   UniSkipOpcode(void);\r
+extern void   UniReset(void);\r
+extern void   UniWriteByte(UBYTE);\r
+extern void   UniWriteWord(UWORD);\r
+extern void   UniNewline(void);\r
+extern UBYTE* UniDup(void);\r
+extern BOOL   UniInit(void);\r
+extern void   UniCleanup(void);\r
+extern void   UniEffect(UWORD,UWORD);\r
+#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x)\r
+#define UniNote(x)       UniEffect(UNI_NOTE,x)\r
+extern void   UniPTEffect(UBYTE,UBYTE);\r
+extern void   UniVolEffect(UWORD,UBYTE);\r
+\r
+/*========== Module Commands */\r
+\r
+enum {\r
+       /* Simple note */\r
+       UNI_NOTE = 1,\r
+       /* Instrument change */\r
+       UNI_INSTRUMENT,\r
+       /* Protracker effects */\r
+       UNI_PTEFFECT0,     /* arpeggio */\r
+       UNI_PTEFFECT1,     /* porta up */\r
+       UNI_PTEFFECT2,     /* porta down */\r
+       UNI_PTEFFECT3,     /* porta to note */\r
+       UNI_PTEFFECT4,     /* vibrato */\r
+       UNI_PTEFFECT5,     /* dual effect 3+A */\r
+       UNI_PTEFFECT6,     /* dual effect 4+A */\r
+       UNI_PTEFFECT7,     /* tremolo */\r
+       UNI_PTEFFECT8,     /* pan */\r
+       UNI_PTEFFECT9,     /* sample offset */\r
+       UNI_PTEFFECTA,     /* volume slide */\r
+       UNI_PTEFFECTB,     /* pattern jump */\r
+       UNI_PTEFFECTC,     /* set volume */\r
+       UNI_PTEFFECTD,     /* pattern break */\r
+       UNI_PTEFFECTE,     /* extended effects */\r
+       UNI_PTEFFECTF,     /* set speed */\r
+       /* Scream Tracker effects */\r
+       UNI_S3MEFFECTA,    /* set speed */\r
+       UNI_S3MEFFECTD,    /* volume slide */\r
+       UNI_S3MEFFECTE,    /* porta down */\r
+       UNI_S3MEFFECTF,    /* porta up */\r
+       UNI_S3MEFFECTI,    /* tremor */\r
+       UNI_S3MEFFECTQ,    /* retrig */\r
+       UNI_S3MEFFECTR,    /* tremolo */\r
+       UNI_S3MEFFECTT,    /* set tempo */\r
+       UNI_S3MEFFECTU,    /* fine vibrato */\r
+       UNI_KEYOFF,        /* note off */\r
+       /* Fast Tracker effects */\r
+       UNI_KEYFADE,       /* note fade */\r
+       UNI_VOLEFFECTS,    /* volume column effects */\r
+       UNI_XMEFFECT4,     /* vibrato */\r
+       UNI_XMEFFECT6,     /* dual effect 4+A */\r
+       UNI_XMEFFECTA,     /* volume slide */\r
+       UNI_XMEFFECTE1,    /* fine porta up */\r
+       UNI_XMEFFECTE2,    /* fine porta down */\r
+       UNI_XMEFFECTEA,    /* fine volume slide up */\r
+       UNI_XMEFFECTEB,    /* fine volume slide down */\r
+       UNI_XMEFFECTG,     /* set global volume */\r
+       UNI_XMEFFECTH,     /* global volume slide */\r
+       UNI_XMEFFECTL,     /* set envelope position */\r
+       UNI_XMEFFECTP,     /* pan slide */\r
+       UNI_XMEFFECTX1,    /* extra fine porta up */\r
+       UNI_XMEFFECTX2,    /* extra fine porta down */\r
+       /* Impulse Tracker effects */\r
+       UNI_ITEFFECTG,     /* porta to note */\r
+       UNI_ITEFFECTH,     /* vibrato */\r
+       UNI_ITEFFECTI,     /* tremor (xy not incremented) */\r
+       UNI_ITEFFECTM,     /* set channel volume */\r
+       UNI_ITEFFECTN,     /* slide / fineslide channel volume */\r
+       UNI_ITEFFECTP,     /* slide / fineslide channel panning */\r
+       UNI_ITEFFECTT,     /* slide tempo */\r
+       UNI_ITEFFECTU,     /* fine vibrato */\r
+       UNI_ITEFFECTW,     /* slide / fineslide global volume */\r
+       UNI_ITEFFECTY,     /* panbrello */\r
+       UNI_ITEFFECTZ,     /* resonant filters */\r
+       UNI_ITEFFECTS0,\r
+       /* UltraTracker effects */\r
+       UNI_ULTEFFECT9,    /* Sample fine offset */\r
+       /* OctaMED effects */\r
+       UNI_MEDSPEED,\r
+       UNI_MEDEFFECTF1,   /* play note twice */\r
+       UNI_MEDEFFECTF2,   /* delay note */\r
+       UNI_MEDEFFECTF3,   /* play note three times */\r
+       /* Oktalyzer effects */\r
+       UNI_OKTARP,                /* arpeggio */\r
+\r
+       UNI_LAST\r
+};\r
+\r
+extern UWORD unioperands[UNI_LAST];\r
+\r
+/* IT / S3M Extended SS effects: */\r
+enum {\r
+       SS_GLISSANDO = 1,\r
+       SS_FINETUNE,\r
+       SS_VIBWAVE,\r
+       SS_TREMWAVE,\r
+       SS_PANWAVE,\r
+       SS_FRAMEDELAY,\r
+       SS_S7EFFECTS,\r
+       SS_PANNING,\r
+       SS_SURROUND,\r
+       SS_HIOFFSET,\r
+       SS_PATLOOP,\r
+       SS_NOTECUT,\r
+       SS_NOTEDELAY,\r
+       SS_PATDELAY\r
+};\r
+\r
+/* IT Volume column effects */\r
+enum {\r
+       VOL_VOLUME = 1,\r
+       VOL_PANNING,\r
+       VOL_VOLSLIDE,\r
+       VOL_PITCHSLIDEDN,\r
+       VOL_PITCHSLIDEUP,\r
+       VOL_PORTAMENTO,\r
+       VOL_VIBRATO\r
+};\r
+\r
+/* IT resonant filter information */\r
+\r
+#define        UF_MAXMACRO             0x10\r
+#define        UF_MAXFILTER    0x100\r
+\r
+#define FILT_CUT               0x80\r
+#define FILT_RESONANT  0x81\r
+\r
+typedef struct FILTER {\r
+    UBYTE filter,inf;\r
+} FILTER;\r
+\r
+/*========== Instruments */\r
+\r
+/* Instrument format flags */\r
+#define IF_OWNPAN       1\r
+#define IF_PITCHPAN     2\r
+\r
+/* Envelope flags: */\r
+#define EF_ON           1\r
+#define EF_SUSTAIN      2\r
+#define EF_LOOP         4\r
+#define EF_VOLENV       8\r
+\r
+/* New Note Action Flags */\r
+#define NNA_CUT         0\r
+#define NNA_CONTINUE    1\r
+#define NNA_OFF         2\r
+#define NNA_FADE        3\r
+\r
+#define NNA_MASK        3\r
+\r
+#define DCT_OFF         0\r
+#define DCT_NOTE        1\r
+#define DCT_SAMPLE      2\r
+#define DCT_INST        3\r
+\r
+#define DCA_CUT         0\r
+#define DCA_OFF         1\r
+#define DCA_FADE        2\r
+\r
+#define KEY_KICK        0\r
+#define KEY_OFF         1\r
+#define KEY_FADE        2\r
+#define KEY_KILL        (KEY_OFF|KEY_FADE)\r
+\r
+#define KICK_ABSENT     0\r
+#define KICK_NOTE       1\r
+#define KICK_KEYOFF     2\r
+#define KICK_ENV        4\r
+\r
+#define AV_IT           1   /* IT vs. XM vibrato info */\r
+\r
+/*========== Playing */\r
+\r
+#define POS_NONE        (-2)   /* no loop position defined */\r
+\r
+#define        LAST_PATTERN    (UWORD)(-1)     /* special ``end of song'' pattern */\r
+\r
+typedef struct ENVPR {\r
+       UBYTE  flg;          /* envelope flag */\r
+       UBYTE  pts;          /* number of envelope points */\r
+       UBYTE  susbeg;       /* envelope sustain index begin */\r
+       UBYTE  susend;       /* envelope sustain index end */\r
+       UBYTE  beg;          /* envelope loop begin */\r
+       UBYTE  end;          /* envelope loop end */\r
+       SWORD  p;            /* current envelope counter */\r
+       UWORD  a;            /* envelope index a */\r
+       UWORD  b;            /* envelope index b */\r
+       ENVPT* env;          /* envelope points */\r
+} ENVPR;\r
+\r
+typedef struct MP_CHANNEL {\r
+       INSTRUMENT* i;\r
+       SAMPLE*     s;\r
+       UBYTE       sample;       /* which sample number */\r
+       UBYTE       note;         /* the audible note as heard, direct rep of period */\r
+       SWORD       outvolume;    /* output volume (vol + sampcol + instvol) */\r
+       SBYTE       chanvol;      /* channel's "global" volume */\r
+       UWORD       fadevol;      /* fading volume rate */\r
+       SWORD       panning;      /* panning position */\r
+       UBYTE       kick;         /* if true = sample has to be restarted */\r
+       UBYTE       kick_flag;    /* kick has been true */\r
+       UWORD       period;       /* period to play the sample at */\r
+       UBYTE       nna;          /* New note action type + master/slave flags */\r
+\r
+       UBYTE       volflg;       /* volume envelope settings */\r
+       UBYTE       panflg;       /* panning envelope settings */\r
+       UBYTE       pitflg;       /* pitch envelope settings */\r
+\r
+       UBYTE       keyoff;       /* if true = fade out and stuff */\r
+       SWORD       handle;       /* which sample-handle */\r
+       UBYTE       notedelay;    /* (used for note delay) */\r
+       SLONG       start;        /* The starting byte index in the sample */\r
+} MP_CHANNEL;\r
+\r
+typedef struct MP_CONTROL {\r
+       struct MP_CHANNEL       main;\r
+\r
+       struct MP_VOICE *slave;   /* Audio Slave of current effects control channel */\r
+\r
+       UBYTE       slavechn;     /* Audio Slave of current effects control channel */\r
+       UBYTE       muted;        /* if set, channel not played */\r
+       UWORD           ultoffset;    /* fine sample offset memory */\r
+       UBYTE       anote;        /* the note that indexes the audible */\r
+       UBYTE           oldnote;\r
+       SWORD       ownper;\r
+       SWORD       ownvol;\r
+       UBYTE       dca;          /* duplicate check action */\r
+       UBYTE       dct;          /* duplicate check type */\r
+       UBYTE*      row;          /* row currently playing on this channel */\r
+       SBYTE       retrig;       /* retrig value (0 means don't retrig) */\r
+       ULONG       speed;        /* what finetune to use */\r
+       SWORD       volume;       /* amiga volume (0 t/m 64) to play the sample at */\r
+\r
+       SWORD       tmpvolume;    /* tmp volume */\r
+       UWORD       tmpperiod;    /* tmp period */\r
+       UWORD       wantedperiod; /* period to slide to (with effect 3 or 5) */\r
+\r
+       UBYTE       arpmem;       /* arpeggio command memory */\r
+       UBYTE       pansspd;      /* panslide speed */\r
+       UWORD       slidespeed;\r
+       UWORD       portspeed;    /* noteslide speed (toneportamento) */\r
+\r
+       UBYTE       s3mtremor;    /* s3m tremor (effect I) counter */\r
+       UBYTE       s3mtronof;    /* s3m tremor ontime/offtime */\r
+       UBYTE       s3mvolslide;  /* last used volslide */\r
+       SBYTE       sliding;\r
+       UBYTE       s3mrtgspeed;  /* last used retrig speed */\r
+       UBYTE       s3mrtgslide;  /* last used retrig slide */\r
+\r
+       UBYTE       glissando;    /* glissando (0 means off) */\r
+       UBYTE       wavecontrol;\r
+\r
+       SBYTE       vibpos;       /* current vibrato position */\r
+       UBYTE       vibspd;       /* "" speed */\r
+       UBYTE       vibdepth;     /* "" depth */\r
+\r
+       SBYTE       trmpos;       /* current tremolo position */\r
+       UBYTE       trmspd;       /* "" speed */\r
+       UBYTE       trmdepth;     /* "" depth */\r
+\r
+       UBYTE       fslideupspd;\r
+       UBYTE       fslidednspd;\r
+       UBYTE       fportupspd;   /* fx E1 (extra fine portamento up) data */\r
+       UBYTE       fportdnspd;   /* fx E2 (extra fine portamento dn) data */\r
+       UBYTE       ffportupspd;  /* fx X1 (extra fine portamento up) data */\r
+       UBYTE       ffportdnspd;  /* fx X2 (extra fine portamento dn) data */\r
+\r
+       ULONG       hioffset;     /* last used high order of sample offset */\r
+       UWORD       soffset;      /* last used low order of sample-offset (effect 9) */\r
+\r
+       UBYTE       sseffect;     /* last used Sxx effect */\r
+       UBYTE       ssdata;       /* last used Sxx data info */\r
+       UBYTE       chanvolslide; /* last used channel volume slide */\r
+\r
+       UBYTE       panbwave;     /* current panbrello waveform */\r
+       UBYTE       panbpos;      /* current panbrello position */\r
+       SBYTE       panbspd;      /* "" speed */\r
+       UBYTE       panbdepth;    /* "" depth */\r
+\r
+       UWORD       newsamp;      /* set to 1 upon a sample / inst change */\r
+       UBYTE       voleffect;    /* Volume Column Effect Memory as used by IT */\r
+       UBYTE       voldata;      /* Volume Column Data Memory */\r
+\r
+       SWORD       pat_reppos;   /* patternloop position */\r
+       UWORD       pat_repcnt;   /* times to loop */\r
+} MP_CONTROL;\r
+\r
+/* Used by NNA only player (audio control.  AUDTMP is used for full effects\r
+   control). */\r
+typedef struct MP_VOICE {\r
+       struct MP_CHANNEL       main;\r
+\r
+       ENVPR       venv;\r
+       ENVPR       penv;\r
+       ENVPR       cenv;\r
+\r
+       UWORD       avibpos;      /* autovibrato pos */\r
+       UWORD       aswppos;      /* autovibrato sweep pos */\r
+\r
+       ULONG       totalvol;     /* total volume of channel (before global mixings) */\r
+\r
+       BOOL        mflag;\r
+       SWORD       masterchn;\r
+       UWORD       masterperiod;\r
+\r
+       MP_CONTROL* master;       /* index of "master" effects channel */\r
+} MP_VOICE;\r
+\r
+/*========== Loaders */\r
+\r
+typedef struct MLOADER {\r
+struct MLOADER* next;\r
+       CHAR*       type;\r
+       CHAR*       version;\r
+       BOOL        (*Init)(void);\r
+       BOOL        (*Test)(void);\r
+       BOOL        (*Load)(BOOL);\r
+       void        (*Cleanup)(void);\r
+       CHAR*       (*LoadTitle)(void);\r
+} MLOADER;\r
+\r
+/* internal loader variables */\r
+extern MREADER* modreader;\r
+extern UWORD   finetune[16];\r
+extern MODULE  of;                  /* static unimod loading space */\r
+extern UWORD   npertab[7*OCTAVE];   /* used by the original MOD loaders */\r
+\r
+extern SBYTE   remap[UF_MAXCHAN];   /* for removing empty channels */\r
+extern UBYTE*  poslookup;           /* lookup table for pattern jumps after\r
+                                      blank pattern removal */\r
+extern UBYTE   poslookupcnt;\r
+extern UWORD*  origpositions;\r
+\r
+extern BOOL    filters;             /* resonant filters in use */\r
+extern UBYTE   activemacro;         /* active midi macro number for Sxx */\r
+extern UBYTE   filtermacros[UF_MAXMACRO];    /* midi macro settings */\r
+extern FILTER  filtersettings[UF_MAXFILTER]; /* computed filter settings */\r
+\r
+extern int*    noteindex;\r
+\r
+/*========== Internal loader interface */\r
+\r
+extern BOOL   ReadComment(UWORD);\r
+extern BOOL   ReadLinedComment(UWORD,UWORD);\r
+extern BOOL   AllocPositions(int);\r
+extern BOOL   AllocPatterns(void);\r
+extern BOOL   AllocTracks(void);\r
+extern BOOL   AllocInstruments(void);\r
+extern BOOL   AllocSamples(void);\r
+extern CHAR*  DupStr(CHAR*,UWORD,BOOL);\r
+\r
+/* loader utility functions */\r
+extern int*   AllocLinear(void);\r
+extern void   FreeLinear(void);\r
+extern int    speed_to_finetune(ULONG,int);\r
+extern void   S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int);\r
+extern void   S3MIT_CreateOrders(BOOL);\r
+\r
+/* flags for S3MIT_ProcessCmd */\r
+#define        S3MIT_OLDSTYLE  1       /* behave as old scream tracker */\r
+#define        S3MIT_IT                2       /* behave as impulse tracker */\r
+#define        S3MIT_SCREAM    4       /* enforce scream tracker specific limits */\r
+\r
+/* used to convert c4spd to linear XM periods (IT and IMF loaders). */\r
+extern UWORD  getlinearperiod(UWORD,ULONG);\r
+extern ULONG  getfrequency(UWORD,ULONG);\r
+\r
+/* loader shared data */\r
+#define STM_NTRACKERS 3\r
+extern CHAR *STM_Signatures[STM_NTRACKERS];\r
+\r
+/*========== Player interface */\r
+\r
+extern BOOL   Player_Init(MODULE*);\r
+extern void   Player_Exit(MODULE*);\r
+extern void   Player_HandleTick(void);\r
+\r
+/*========== Drivers */\r
+\r
+/* max. number of handles a driver has to provide. (not strict) */\r
+#define MAXSAMPLEHANDLES 384\r
+\r
+/* These variables can be changed at ANY time and results will be immediate */\r
+extern UWORD md_bpm;         /* current song / hardware BPM rate */\r
+\r
+/* Variables below can be changed via MD_SetNumVoices at any time. However, a\r
+   call to MD_SetNumVoicess while the driver is active will cause the sound to\r
+   skip slightly. */\r
+extern UBYTE md_numchn;      /* number of song + sound effects voices */\r
+extern UBYTE md_sngchn;      /* number of song voices */\r
+extern UBYTE md_sfxchn;      /* number of sound effects voices */\r
+extern UBYTE md_hardchn;     /* number of hardware mixed voices */\r
+extern UBYTE md_softchn;     /* number of software mixed voices */\r
+\r
+/* This is for use by the hardware drivers only.  It points to the registered\r
+   tickhandler function. */\r
+extern void (*md_player)(void);\r
+\r
+extern SWORD  MD_SampleLoad(SAMPLOAD*,int);\r
+extern void   MD_SampleUnload(SWORD);\r
+extern ULONG  MD_SampleSpace(int);\r
+extern ULONG  MD_SampleLength(int,SAMPLE*);\r
+\r
+/* uLaw conversion */\r
+extern void unsignedtoulaw(char *,int);\r
+\r
+/* Parameter extraction helper */\r
+extern CHAR  *MD_GetAtom(CHAR*,CHAR*,BOOL);\r
+\r
+/* Internal software mixer stuff */\r
+extern void VC_SetupPointers(void);\r
+extern BOOL VC1_Init(void);\r
+extern BOOL VC2_Init(void);\r
+\r
+#if defined(unix) || defined(__APPLE__) && defined(__MACH__)\r
+/* POSIX helper functions */\r
+extern BOOL MD_Access(CHAR *);\r
+extern BOOL MD_DropPrivileges(void);\r
+#endif\r
+\r
+/* Macro to define a missing driver, yet allowing binaries to dynamically link\r
+   with the library without missing symbol errors */\r
+#define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 }\r
+\r
+/*========== Prototypes for non-MT safe versions of some public functions */\r
+\r
+extern void _mm_registerdriver(struct MDRIVER*);\r
+extern void _mm_registerloader(struct MLOADER*);\r
+extern BOOL MikMod_Active_internal(void);\r
+extern void MikMod_DisableOutput_internal(void);\r
+extern BOOL MikMod_EnableOutput_internal(void);\r
+extern void MikMod_Exit_internal(void);\r
+extern BOOL MikMod_SetNumVoices_internal(int,int);\r
+extern void Player_Exit_internal(MODULE*);\r
+extern void Player_Stop_internal(void);\r
+extern BOOL Player_Paused_internal(void);\r
+extern void Sample_Free_internal(SAMPLE*);\r
+extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);\r
+extern void Voice_SetFrequency_internal(SBYTE,ULONG);\r
+extern void Voice_SetPanning_internal(SBYTE,ULONG);\r
+extern void Voice_SetVolume_internal(SBYTE,UWORD);\r
+extern void Voice_Stop_internal(SBYTE);\r
+extern BOOL Voice_Stopped_internal(SBYTE);\r
+\r
+\r
+/*\r
+ * Static memory management + rockboxed function calls\r
+ */\r
+void* mikmod_malloc(size_t size);\r
+void* mikmod_calloc(size_t nmemb, size_t size);\r
+void* mikmod_realloc(void* ptr, size_t size);\r
+void mikmod_free(void* ptr);\r
+int mikmod_abs(int num);\r
+char* mikmod_strdup(const char *srcbuf);\r
+char* mikmod_strncat(char *dest, const char *src, size_t count);\r
+char* mikmod_strstr(char *str, char *search);\r
+int mikmod_toupper(int character);\r
+int mikmod_isalnum(int character);\r
+int mikmod_isdigit(char c);\r
+\r
+//#define malloc(a) mikmod_malloc(a)\r
+//#define calloc(a,b) mikmod_calloc(a,b)\r
+#define free(a) mikmod_free(a)\r
+#define realloc(a,b) mikmod_realloc(a,b)\r
+//#define abs(a) mikmod_abs(a)\r
+#define strdup(a) mikmod_strdup(a)\r
+#define strncat(a, b, c) mikmod_strncat(a, b, c)\r
+#define strstr(a, b) mikmod_strstr(a, b)\r
+#define toupper(a) mikmod_toupper(a)\r
+#define isalnum(a) mikmod_isalnum(a)\r
+#define isdigit(a) mikmod_isdigit(a)\r
+\r
+\r
+#define strcpy(a, b) rb->strcpy(a, b)\r
+#define strncpy(a, b, c) rb->strncpy(a, b, c)\r
+#define strlen(a) rb->strlen(a)\r
+#define strrchr(a, b) rb->strrchr(a, b)\r
+#define strcmp(a, b) rb->strcmp(a, b)\r
+#define strncmp(a, b, c) rb->strncmp(a, b, c)\r
+#define strcasecmp(a, b) rb->strcasecmp(a, b)\r
+#define strncasecmp(a, b, c) rb->strncasecmp(a, b, c)\r
+#define memset(a, b, c) rb->memset(a, b, c)\r
+#define memcpy(a, b, c) rb->memcpy(a, b, c)\r
+#define memmove(a, b, c) rb->memmove(a, b, c)\r
+\r
+#define rand() rb->rand()\r
+#define atoi(a) rb->atoi(a)\r
+#define strchr(a, b) rb->strchr(a, b)\r
+#define strcat(a, b) rb->strcat(a, b)\r
+#define memchr(a, b, c) rb->memchr(a, b, c)\r
+#define memcmp(a, b, c) rb->memcmp(a, b, c)\r
+#define strcasestr(a, b) rb->strcasestr(a, b)\r
+#define strtok_r(a, b, c) rb->strtok_r(a, b, c)\r
+#define snprintf(a, b, c, args...) rb->snprintf(a, b, c, args)\r
+\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_669.c b/apps/plugins/mikmod/loaders/load_669.c
new file mode 100644 (file)
index 0000000..1991e75
--- /dev/null
@@ -0,0 +1,369 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Composer 669 module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct S69HEADER {   \r
+       UBYTE   marker[2];\r
+       CHAR    message[108];\r
+       UBYTE   nos;\r
+       UBYTE   nopa;\r
+       UBYTE   looporder;\r
+       UBYTE   orders[0x80];\r
+       UBYTE   tempos[0x80];\r
+       UBYTE   breaks[0x80];\r
+} S69HEADER;\r
+\r
+/* sample information */\r
+typedef struct S69SAMPLE {\r
+       CHAR    filename[13];\r
+       SLONG   length;\r
+       SLONG   loopbeg;\r
+       SLONG   loopend;\r
+} S69SAMPLE;\r
+\r
+/* encoded note */\r
+typedef struct S69NOTE {\r
+       UBYTE   a,b,c;\r
+} S69NOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+/* current pattern */\r
+static S69NOTE* s69pat=NULL;\r
+/* Module header */\r
+static S69HEADER* mh=NULL;\r
+\r
+/* file type identification */\r
+static CHAR* S69_Version[]={\r
+       "Composer 669",\r
+       "Extended 669"\r
+};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL S69_Test(void)\r
+{\r
+       UBYTE buf[0x80];\r
+\r
+       if(!_mm_read_UBYTES(buf,2,modreader))\r
+               return 0;\r
+       /* look for id */\r
+       if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {\r
+               int i;\r
+\r
+               /* skip song message */\r
+               _mm_fseek(modreader,108,SEEK_CUR);\r
+               /* sanity checks */\r
+               if(_mm_read_UBYTE(modreader) > 64) return 0;\r
+               if(_mm_read_UBYTE(modreader) > 128) return 0;\r
+               if(_mm_read_UBYTE(modreader) > 127) return 0;\r
+               /* check order table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;\r
+               /* check tempos table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if((!buf[i])||(buf[i]>32)) return 0;\r
+               /* check pattern length table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if(buf[i]>0x3f) return 0;\r
+       } else\r
+               return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL S69_Init(void)\r
+{\r
+       if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;\r
+       if(!(mh=(S69HEADER *)_mm_malloc(sizeof(S69HEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void S69_Cleanup(void)\r
+{\r
+       _mm_free(s69pat);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL S69_LoadPatterns(void)\r
+{\r
+       int track,row,channel;\r
+       UBYTE note,inst,vol,effect,lastfx,lastval;\r
+       S69NOTE *cur;\r
+       int tracks=0;\r
+       \r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       for(track=0;track<of.numpat;track++) {\r
+               /* set pattern break locations */\r
+               of.pattrows[track]=mh->breaks[track]+1;\r
+\r
+               /* load the 669 pattern */\r
+               cur=s69pat;\r
+               for(row=0;row<64;row++) {\r
+                       for(channel=0;channel<8;channel++,cur++) {\r
+                               cur->a = _mm_read_UBYTE(modreader);\r
+                               cur->b = _mm_read_UBYTE(modreader);\r
+                               cur->c = _mm_read_UBYTE(modreader);\r
+                       }\r
+               }\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               /* translate the pattern */\r
+               for(channel=0;channel<8;channel++) {\r
+                       UniReset();\r
+                       /* set pattern tempo */\r
+                       UniPTEffect(0xf,78);\r
+                       UniPTEffect(0xf,mh->tempos[track]);\r
+\r
+                       lastfx=0xff,lastval=0;\r
+\r
+                       for(row=0;row<=mh->breaks[track];row++) {\r
+                               int a,b,c;\r
+\r
+                               /* fetch the encoded note */\r
+                               a=s69pat[(row*8)+channel].a;\r
+                               b=s69pat[(row*8)+channel].b;\r
+                               c=s69pat[(row*8)+channel].c;\r
+\r
+                               /* decode it */\r
+                               note=a>>2;\r
+                               inst=((a&0x3)<<4)|((b&0xf0)>>4);\r
+                               vol=b&0xf;\r
+\r
+                               if (a<0xff) {\r
+                                       if (a<0xfe) {\r
+                                               UniInstrument(inst);\r
+                                               UniNote(note+2*OCTAVE);\r
+                                               lastfx=0xff; /* reset background effect memory */\r
+                                       }\r
+                                       UniPTEffect(0xc,vol<<2);\r
+                               }\r
+\r
+                               if ((c!=0xff)||(lastfx!=0xff)) {\r
+                                       if(c==0xff)\r
+                                               c=lastfx,effect=lastval;\r
+                                       else\r
+                                               effect=c&0xf;\r
+\r
+                                       switch(c>>4) {\r
+                                               case 0: /* porta up */\r
+                                                       UniPTEffect(0x1,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 1: /* porta down */\r
+                                                       UniPTEffect(0x2,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 2: /* porta to note */\r
+                                                       UniPTEffect(0x3,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 3: /* frequency adjust */\r
+                                                       /* DMP converts this effect to S3M FF1. Why not ? */\r
+                                                       UniEffect(UNI_S3MEFFECTF,0xf0|effect);\r
+                                                       break;\r
+                                               case 4: /* vibrato */\r
+                                                       UniPTEffect(0x4,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 5: /* set speed */\r
+                                                       if (effect)\r
+                                                               UniPTEffect(0xf,effect);\r
+                                                       else \r
+                                                         if(mh->marker[0]!=0x69) {\r
+#ifdef MIKMOD_DEBUG\r
+                                                               fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",\r
+                                                                      track,row,channel);\r
+#endif\r
+                                                       }\r
+                                                       break;\r
+                                       }\r
+                               }\r
+                               UniNewline();\r
+                       }\r
+                       if(!(of.tracks[tracks++]=UniDup())) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL S69_Load(BOOL curious)\r
+{\r
+       int i;\r
+       SAMPLE *current;\r
+       S69SAMPLE sample;\r
+       (void)curious;\r
+\r
+       /* module header */\r
+       _mm_read_UBYTES(mh->marker,2,modreader);\r
+       _mm_read_UBYTES(mh->message,108,modreader);\r
+       mh->nos=_mm_read_UBYTE(modreader);\r
+       mh->nopa=_mm_read_UBYTE(modreader);\r
+       mh->looporder=_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->orders,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+       _mm_read_UBYTES(mh->tempos,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if ((!mh->tempos[i])||(mh->tempos[i]>32)) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+       _mm_read_UBYTES(mh->breaks,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if (mh->breaks[i]>0x3f) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+\r
+       /* set module variables */\r
+       of.initspeed=4;\r
+       of.inittempo=78;\r
+       of.songname=DupStr(mh->message,36,1);\r
+       of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);\r
+       of.numchn=8;\r
+       of.numpat=mh->nopa;\r
+       of.numins=of.numsmp=mh->nos;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       of.flags=UF_XMPERIODS|UF_LINEAR;\r
+\r
+       for(i=   35;(i>=   0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       if((mh->message[0])||(mh->message[36])||(mh->message[72]))\r
+               if((of.comment=(CHAR*)_mm_malloc(3*(36+1)+1))) {\r
+                       strncpy(of.comment,mh->message,36);\r
+                       strcat(of.comment,"\r");\r
+                       if (mh->message[36]) strncat(of.comment,mh->message+36,36);\r
+                       strcat(of.comment,"\r");\r
+                       if (mh->message[72]) strncat(of.comment,mh->message+72,36);\r
+                       strcat(of.comment,"\r");\r
+                       of.comment[3*(36+1)]=0;\r
+               }\r
+\r
+       if(!AllocPositions(0x80)) return 0;\r
+       for(i=0;i<0x80;i++) {\r
+               if(mh->orders[i]>=mh->nopa) break;\r
+               of.positions[i]=mh->orders[i];\r
+       }\r
+       of.numpos=i;\r
+       of.reppos=mh->looporder<of.numpos?mh->looporder:0;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       current=of.samples;\r
+\r
+       for(i=0;i<of.numins;i++) {\r
+               /* sample information */\r
+               _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);\r
+               sample.length=_mm_read_I_SLONG(modreader);\r
+               sample.loopbeg=_mm_read_I_SLONG(modreader);\r
+               sample.loopend=_mm_read_I_SLONG(modreader);\r
+               if (sample.loopend==0xfffff) sample.loopend=0;\r
+\r
+               if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {\r
+                       _mm_errno = MMERR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               current->samplename=DupStr(sample.filename,13,1);\r
+               current->seekpos=0;\r
+               current->speed=0;\r
+               current->length=sample.length;\r
+               current->loopstart=sample.loopbeg;\r
+               current->loopend=sample.loopend;\r
+               current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;\r
+               current->volume=64;\r
+\r
+               current++;\r
+       }\r
+\r
+       if(!S69_LoadPatterns()) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *S69_LoadTitle(void)\r
+{\r
+       CHAR s[36];\r
+\r
+       _mm_fseek(modreader,2,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,36,modreader)) return NULL;\r
+\r
+       return(DupStr(s,36,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_669={\r
+       NULL,\r
+       "669",\r
+       "669 (Composer 669, Unis 669)",\r
+       S69_Init,\r
+       S69_Test,\r
+       S69_Load,\r
+       S69_Cleanup,\r
+       S69_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_amf.c b/apps/plugins/mikmod/loaders/load_amf.c
new file mode 100644 (file)
index 0000000..f53d2ee
--- /dev/null
@@ -0,0 +1,570 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_amf.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  DMP Advanced Module Format loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct AMFHEADER {\r
+       UBYTE id[3];                    /* AMF file marker */\r
+       UBYTE version;                  /* upper major, lower nibble minor version number */\r
+       CHAR  songname[32];             /* ASCIIZ songname */\r
+       UBYTE numsamples;               /* number of samples saved */\r
+       UBYTE numorders;\r
+       UWORD numtracks;                /* number of tracks saved */\r
+       UBYTE numchannels;              /* number of channels used  */\r
+       SBYTE panpos[32];               /* voice pan positions */\r
+       UBYTE songbpm;\r
+       UBYTE songspd;\r
+} AMFHEADER;\r
+\r
+typedef struct AMFSAMPLE {\r
+       UBYTE type;\r
+       CHAR  samplename[32];\r
+       CHAR  filename[13];\r
+       ULONG offset;\r
+       ULONG length;\r
+       UWORD c2spd;\r
+       UBYTE volume;\r
+       ULONG reppos;\r
+       ULONG repend;\r
+} AMFSAMPLE;\r
+\r
+typedef struct AMFNOTE {\r
+       UBYTE note,instr,volume,fxcnt;\r
+       UBYTE effect[3];\r
+       SBYTE parameter[3];\r
+} AMFNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static AMFHEADER *mh = NULL;\r
+#define AMFTEXTLEN 22\r
+static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0";\r
+static AMFNOTE *track = NULL;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL AMF_Test(void)\r
+{\r
+       UBYTE id[3],ver;\r
+\r
+       if(!_mm_read_UBYTES(id,3,modreader)) return 0;\r
+       if(memcmp(id,"AMF",3)) return 0;\r
+\r
+       ver=_mm_read_UBYTE(modreader);\r
+       if((ver>=10)&&(ver<=14)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL AMF_Init(void)\r
+{\r
+       if(!(mh=(AMFHEADER*)_mm_malloc(sizeof(AMFHEADER)))) return 0;\r
+       if(!(track=(AMFNOTE*)_mm_calloc(64,sizeof(AMFNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void AMF_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(track);\r
+}\r
+\r
+static BOOL AMF_UnpackTrack(MREADER* modreader)\r
+{\r
+       ULONG tracksize;\r
+       UBYTE row,cmd;\r
+       SBYTE arg;\r
+\r
+       /* empty track */\r
+       memset(track,0,64*sizeof(AMFNOTE));\r
+\r
+       /* read packed track */\r
+       if (modreader) {\r
+               tracksize=_mm_read_I_UWORD(modreader);\r
+               tracksize+=((ULONG)_mm_read_UBYTE(modreader))<<16;\r
+               if (tracksize)\r
+                       while(tracksize--) {\r
+                               row=_mm_read_UBYTE(modreader);\r
+                               cmd=_mm_read_UBYTE(modreader);\r
+                               arg=_mm_read_SBYTE(modreader);\r
+                               /* unexpected end of track */\r
+                               if(!tracksize) {\r
+                                       if((row==0xff)&&(cmd==0xff)&&(arg==-1))\r
+                                               break;\r
+                                       /* the last triplet should be FF FF FF, but this is not\r
+                                          always the case... maybe a bug in m2amf ? \r
+                                       else\r
+                                               return 0;\r
+                                       */\r
+\r
+                               }\r
+                               /* invalid row (probably unexpected end of row) */\r
+                               if (row>=64)\r
+                                       return 0;\r
+                               if (cmd<0x7f) {\r
+                                       /* note, vol */\r
+                                       track[row].note=cmd;\r
+                                       track[row].volume=(UBYTE)arg+1;\r
+                               } else\r
+                                 if (cmd==0x7f) {\r
+                                       /* duplicate row */\r
+                                       if ((arg<0)&&(row+arg>=0)) {\r
+                                               memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));\r
+                                       }\r
+                               } else\r
+                                 if (cmd==0x80) {\r
+                                       /* instr */\r
+                                       track[row].instr=arg+1;\r
+                               } else\r
+                                 if (cmd==0x83) {\r
+                                       /* volume without note */\r
+                                       track[row].volume=(UBYTE)arg+1;\r
+                               } else \r
+                                 if (cmd==0xff) {\r
+                                       /* apparently, some M2AMF version fail to estimate the\r
+                                          size of the compressed patterns correctly, and end\r
+                                          up with blanks, i.e. dead triplets. Those are marked\r
+                                          with cmd == 0xff. Let's ignore them. */\r
+                               } else\r
+                                 if(track[row].fxcnt<3) {\r
+                                       /* effect, param */\r
+                                       if(cmd>0x97)\r
+                                               return 0;\r
+                                       track[row].effect[track[row].fxcnt]=cmd&0x7f;\r
+                                       track[row].parameter[track[row].fxcnt]=arg;\r
+                                       track[row].fxcnt++;\r
+                               } else\r
+                                       return 0;\r
+                       }\r
+       }\r
+       return 1;\r
+}\r
+\r
+static UBYTE* AMF_ConvertTrack(void)\r
+{\r
+       int row,fx4memory=0;\r
+\r
+       /* convert track */\r
+       UniReset();\r
+       for (row=0;row<64;row++) {\r
+               if (track[row].instr)  UniInstrument(track[row].instr-1);\r
+               if (track[row].note>OCTAVE) UniNote(track[row].note-OCTAVE);\r
+\r
+               /* AMF effects */\r
+               while(track[row].fxcnt--) {\r
+                       SBYTE inf=track[row].parameter[track[row].fxcnt];\r
+\r
+                       switch(track[row].effect[track[row].fxcnt]) {\r
+                               case 1: /* Set speed */\r
+                                       UniEffect(UNI_S3MEFFECTA,inf);\r
+                                       break;\r
+                               case 2: /* Volume slide */\r
+                                       if(inf) {\r
+                                               UniWriteByte(UNI_S3MEFFECTD);\r
+                                               if (inf>=0)\r
+                                                       UniWriteByte((inf&0xf)<<4);\r
+                                               else\r
+                                                       UniWriteByte((-inf)&0xf);\r
+                                       }\r
+                                       break;\r
+                               /* effect 3, set channel volume, done in UnpackTrack */\r
+                               case 4: /* Porta up/down */\r
+                                       if(inf) {\r
+                                               if(inf>0) {\r
+                                                       UniEffect(UNI_S3MEFFECTE,inf);\r
+                                                       fx4memory=UNI_S3MEFFECTE;\r
+                                               } else {\r
+                                                       UniEffect(UNI_S3MEFFECTF,-inf);\r
+                                                       fx4memory=UNI_S3MEFFECTF;\r
+                                               }\r
+                                       } else if(fx4memory)\r
+                                               UniEffect(fx4memory,0);\r
+                                       break;\r
+                               /* effect 5, "Porta abs", not supported */\r
+                               case 6: /* Porta to note */\r
+                                       UniEffect(UNI_ITEFFECTG,inf);\r
+                                       break;\r
+                               case 7: /* Tremor */\r
+                                       UniEffect(UNI_S3MEFFECTI,inf);\r
+                                       break;\r
+                               case 8: /* Arpeggio */\r
+                                       UniPTEffect(0x0,inf);\r
+                                       break;\r
+                               case 9: /* Vibrato */\r
+                                       UniPTEffect(0x4,inf);\r
+                                       break;\r
+                               case 0xa: /* Porta + Volume slide */\r
+                                       UniPTEffect(0x3,0);\r
+                                       if(inf) {\r
+                                               UniWriteByte(UNI_S3MEFFECTD);\r
+                                               if (inf>=0)\r
+                                                       UniWriteByte((inf&0xf)<<4);\r
+                                               else\r
+                                                       UniWriteByte((-inf)&0xf);\r
+                                       }\r
+                                       break;\r
+                               case 0xb: /* Vibrato + Volume slide */\r
+                                       UniPTEffect(0x4,0);\r
+                                       if(inf) {\r
+                                               UniWriteByte(UNI_S3MEFFECTD);\r
+                                               if (inf>=0)\r
+                                                       UniWriteByte((inf&0xf)<<4);\r
+                                               else\r
+                                                       UniWriteByte((-inf)&0xf);\r
+                                       }\r
+                                       break;\r
+                               case 0xc: /* Pattern break (in hex) */\r
+                                       UniPTEffect(0xd,inf);\r
+                                       break;\r
+                               case 0xd: /* Pattern jump */\r
+                                       UniPTEffect(0xb,inf);\r
+                                       break;\r
+                               /* effect 0xe, "Sync", not supported */\r
+                               case 0xf: /* Retrig */\r
+                                       UniEffect(UNI_S3MEFFECTQ,inf&0xf);\r
+                                       break;\r
+                               case 0x10: /* Sample offset */\r
+                                       UniPTEffect(0x9,inf);\r
+                                       break;\r
+                               case 0x11: /* Fine volume slide */\r
+                                       if(inf) {\r
+                                               UniWriteByte(UNI_S3MEFFECTD);\r
+                                               if (inf>=0)\r
+                                                       UniWriteByte((inf&0xf)<<4|0xf);\r
+                                               else\r
+                                                       UniWriteByte(0xf0|((-inf)&0xf));\r
+                                       }\r
+                                       break;\r
+                               case 0x12: /* Fine portamento */\r
+                                       if(inf) {\r
+                                               if(inf>0) {\r
+                                                       UniEffect(UNI_S3MEFFECTE,0xf0|(inf&0xf));\r
+                                                       fx4memory=UNI_S3MEFFECTE;\r
+                                               } else {\r
+                                                       UniEffect(UNI_S3MEFFECTF,0xf0|((-inf)&0xf));\r
+                                                       fx4memory=UNI_S3MEFFECTF;\r
+                                               }\r
+                                       } else if(fx4memory)\r
+                                               UniEffect(fx4memory,0);\r
+                                       break;\r
+                               case 0x13: /* Delay note */\r
+                                       UniPTEffect(0xe,0xd0|(inf&0xf));\r
+                                       break;\r
+                               case 0x14: /* Note cut */\r
+                                       UniPTEffect(0xc,0);\r
+                                       track[row].volume=0;\r
+                                       break;\r
+                               case 0x15: /* Set tempo */\r
+                                       UniEffect(UNI_S3MEFFECTT,inf);\r
+                                       break;\r
+                               case 0x16: /* Extra fine portamento */\r
+                                       if(inf) {\r
+                                               if(inf>0) {\r
+                                                       UniEffect(UNI_S3MEFFECTE,0xe0|((inf>>2)&0xf));\r
+                                                       fx4memory=UNI_S3MEFFECTE;\r
+                                               } else {\r
+                                                       UniEffect(UNI_S3MEFFECTF,0xe0|(((-inf)>>2)&0xf));\r
+                                                       fx4memory=UNI_S3MEFFECTF;\r
+                                               }\r
+                                       } else if(fx4memory)\r
+                                               UniEffect(fx4memory,0);\r
+                                       break;\r
+                               case 0x17: /* Panning */\r
+                                       if (inf>64)\r
+                                               UniEffect(UNI_ITEFFECTS0,0x91); /* surround */\r
+                                       else\r
+                                               UniPTEffect(0x8,(inf==64)?255:(inf+64)<<1);\r
+                                       of.flags |= UF_PANNING;\r
+                                       break;\r
+                       }\r
+                       \r
+               }\r
+               if (track[row].volume) UniVolEffect(VOL_VOLUME,track[row].volume-1);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL AMF_Load(BOOL curious)\r
+{\r
+       int t,u,realtrackcnt,realsmpcnt,defaultpanning;\r
+       AMFSAMPLE s;\r
+       SAMPLE *q;\r
+       UWORD *track_remap;\r
+       ULONG samplepos;\r
+       int channel_remap[16];\r
+       (void)curious;\r
+\r
+       /* try to read module header  */\r
+       _mm_read_UBYTES(mh->id,3,modreader);\r
+       mh->version     =_mm_read_UBYTE(modreader);\r
+       _mm_read_string(mh->songname,32,modreader);\r
+       mh->numsamples  =_mm_read_UBYTE(modreader);\r
+       mh->numorders   =_mm_read_UBYTE(modreader);\r
+       mh->numtracks   =_mm_read_I_UWORD(modreader);\r
+       mh->numchannels =_mm_read_UBYTE(modreader);\r
+       if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+\r
+       if(mh->version>=11) {\r
+               memset(mh->panpos,0,32);\r
+               _mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);\r
+       } else\r
+               _mm_read_UBYTES(channel_remap,16,modreader);\r
+\r
+       if (mh->version>=13) {\r
+               mh->songbpm=_mm_read_UBYTE(modreader);\r
+               if(mh->songbpm<32) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 0;\r
+               }\r
+               mh->songspd=_mm_read_UBYTE(modreader);\r
+               if(mh->songspd>32) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 0;\r
+               }\r
+       } else {\r
+               mh->songbpm=125;\r
+               mh->songspd=6;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.initspeed = mh->songspd;\r
+       of.inittempo = mh->songbpm;\r
+       AMF_Version[AMFTEXTLEN-3]='0'+(mh->version/10);\r
+       AMF_Version[AMFTEXTLEN-1]='0'+(mh->version%10);\r
+       of.modtype   = strdup(AMF_Version);\r
+       of.numchn    = mh->numchannels;\r
+       of.numtrk    = mh->numorders*mh->numchannels;\r
+       if (mh->numtracks>of.numtrk)\r
+               of.numtrk=mh->numtracks;\r
+       of.numtrk++;    /* add room for extra, empty track */\r
+       of.songname  = DupStr(mh->songname,32,1);\r
+       of.numpos    = mh->numorders;\r
+       of.numpat    = mh->numorders;\r
+       of.reppos    = 0;\r
+       of.flags    |= UF_S3MSLIDES;\r
+       /* XXX whenever possible, we should try to determine the original format.\r
+          Here we assume it was S3M-style wrt bpmlimit... */\r
+       of.bpmlimit = 32;\r
+       \r
+       /*\r
+        * Play with the panning table. Although the AMF format embeds a\r
+        * panning table, if the module was a MOD or an S3M with default\r
+        * panning and didn't use any panning commands, don't flag\r
+        * UF_PANNING, to use our preferred panning table for this case.\r
+        */\r
+       defaultpanning = 1;\r
+       for (t = 0; t < 32; t++) {\r
+               if (mh->panpos[t] > 64) {\r
+                       of.panning[t] = PAN_SURROUND;\r
+                       defaultpanning = 0;\r
+               } else\r
+                       if (mh->panpos[t] == 64)\r
+                               of.panning[t] = PAN_RIGHT;\r
+                       else\r
+                               of.panning[t] = (mh->panpos[t] + 64) << 1;\r
+       }\r
+       if (defaultpanning) {\r
+               for (t = 0; t < of.numchn; t++)\r
+                       if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {\r
+                               defaultpanning = 0;     /* not MOD canonical panning */\r
+                               break;\r
+                       }\r
+       }\r
+       if (defaultpanning)\r
+               of.flags |= UF_PANNING;\r
+\r
+       of.numins=of.numsmp=mh->numsamples;\r
+\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=0;t<of.numpos;t++)\r
+               of.positions[t]=t;\r
+\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       /* read AMF order table */\r
+       for (t=0;t<of.numpat;t++) {\r
+               if (mh->version>=14)\r
+                       /* track size */\r
+                       of.pattrows[t]=_mm_read_I_UWORD(modreader);\r
+               if (mh->version>=10)\r
+                       _mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);\r
+               else\r
+                       for(u=0;u<of.numchn;u++)\r
+                               of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);\r
+       }\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* read sample information */\r
+       if(!AllocSamples()) return 0;\r
+       q=of.samples;\r
+       for(t=0;t<of.numins;t++) {\r
+               /* try to read sample info */\r
+               s.type=_mm_read_UBYTE(modreader);\r
+               _mm_read_string(s.samplename,32,modreader);\r
+               _mm_read_string(s.filename,13,modreader);\r
+               s.offset    =_mm_read_I_ULONG(modreader);\r
+               s.length    =_mm_read_I_ULONG(modreader);\r
+               s.c2spd     =_mm_read_I_UWORD(modreader);\r
+               if(s.c2spd==8368) s.c2spd=8363;\r
+               s.volume    =_mm_read_UBYTE(modreader);\r
+               if(mh->version>=11) {\r
+                       s.reppos    =_mm_read_I_ULONG(modreader);\r
+                       s.repend    =_mm_read_I_ULONG(modreader);\r
+               } else {\r
+                       s.reppos    =_mm_read_I_UWORD(modreader);\r
+                       s.repend    =s.length;\r
+               }\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO; \r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.samplename,32,1);\r
+               q->speed     = s.c2spd;\r
+               q->volume    = s.volume;\r
+               if (s.type) {\r
+                       q->seekpos   = s.offset;\r
+                       q->length    = s.length;\r
+                       q->loopstart = s.reppos;\r
+                       q->loopend   = s.repend;\r
+                       if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;\r
+               }\r
+               q++;\r
+       }\r
+\r
+       /* read track table */\r
+       if(!(track_remap=_mm_calloc(mh->numtracks+1,sizeof(UWORD))))\r
+               return 0;\r
+       _mm_read_I_UWORDS(track_remap+1,mh->numtracks,modreader);\r
+       if(_mm_eof(modreader)) {\r
+               free(track_remap);\r
+               _mm_errno=MMERR_LOADING_TRACK;\r
+               return 0;\r
+       }\r
+\r
+       for(realtrackcnt=t=0;t<=mh->numtracks;t++)\r
+               if (realtrackcnt<track_remap[t])\r
+                       realtrackcnt=track_remap[t];\r
+       for(t=0;t<of.numpat*of.numchn;t++)\r
+               of.patterns[t]=(of.patterns[t]<=mh->numtracks)?\r
+                              track_remap[of.patterns[t]]-1:realtrackcnt;\r
+\r
+       free(track_remap);\r
+\r
+       /* unpack tracks */\r
+       for(t=0;t<realtrackcnt;t++) {\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_TRACK;\r
+                       return 0;\r
+               }\r
+               if (!AMF_UnpackTrack(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_TRACK;\r
+                       return 0;\r
+               }\r
+               if(!(of.tracks[t]=AMF_ConvertTrack()))\r
+                       return 0;\r
+       }\r
+       /* add an extra void track */\r
+       UniReset();\r
+       for(t=0;t<64;t++) UniNewline();\r
+       of.tracks[realtrackcnt++]=UniDup();\r
+       for(t=realtrackcnt;t<of.numtrk;t++) of.tracks[t]=NULL;\r
+\r
+       /* compute sample offsets */\r
+       samplepos=_mm_ftell(modreader);\r
+       for(realsmpcnt=t=0;t<of.numsmp;t++)\r
+               if(realsmpcnt<of.samples[t].seekpos)\r
+                       realsmpcnt=of.samples[t].seekpos;\r
+       for(t=1;t<=realsmpcnt;t++) {\r
+               q=of.samples;\r
+               while(q->seekpos!=t) q++;\r
+               q->seekpos=samplepos;\r
+               samplepos+=q->length;\r
+       }\r
+               \r
+       return 1;\r
+}\r
+\r
+CHAR *AMF_LoadTitle(void)\r
+{\r
+       CHAR s[32];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,32,modreader)) return NULL;\r
+\r
+       return(DupStr(s,32,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_amf={\r
+       NULL,\r
+       "AMF",\r
+       "AMF (DSMI Advanced Module Format)",\r
+       AMF_Init,\r
+       AMF_Test,\r
+       AMF_Load,\r
+       AMF_Cleanup,\r
+       AMF_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_asy.c b/apps/plugins/mikmod/loaders/load_asy.c
new file mode 100644 (file)
index 0000000..6b78e31
--- /dev/null
@@ -0,0 +1,399 @@
+/*     MikMod sound library\r
+       (c) 2004, Raphael Assenat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_asy.c,v 1.3 2004/01/28 01:18:22 raph Exp $\r
+\r
+  ASYLUM Music Format v1.0 (.amf) loader\r
+  adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>,\r
+  with the help of the AMF2MOD utility sourcecode,\r
+  written to convert crusader's amf files into 8\r
+  channels mod file in 1995 by Mr. P / Powersource\r
+  mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca \r
+  \r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+//#include <ctype.h>\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct MSAMPINFO {\r
+       CHAR samplename[24];\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       ULONG length;\r
+       ULONG reppos;\r
+       ULONG replen;\r
+} MSAMPINFO;\r
+\r
+typedef struct MODULEHEADER {\r
+       CHAR songname[21];\r
+       UBYTE num_patterns;     /* number of patterns used */\r
+       UBYTE num_orders;\r
+       UBYTE positions[256];   /* which pattern to play at pos */\r
+       MSAMPINFO samples[64];  /* all sampleinfo */\r
+} MODULEHEADER;\r
+\r
+typedef struct MODTYPE {\r
+       CHAR id[5];\r
+       UBYTE channels;\r
+       CHAR *name;\r
+} MODTYPE;\r
+\r
+typedef struct MODNOTE {\r
+       UBYTE a, b, c, d;\r
+} MODNOTE;\r
+\r
+/* This table is taken from AMF2MOD.C\r
+ * written in 1995 by Mr. P / Powersource\r
+ * mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */ \r
+UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304,\r
+       4064,3840,3628,3424,3232,3048,2880,2712,2560,\r
+       2416,2280,2152,2032,1920,1814,1712,1616,1524,\r
+       1440,1356,1280,1208,1140,1076,1016, 960, 907,\r
+       856, 808, 762, 720, 678, 640, 604, 570, 538,\r
+       508, 480, 453, 428, 404, 381, 360, 339, 320,\r
+       302, 285, 269, 254, 240, 226, 214, 202, 190,\r
+       180, 170, 160, 151, 143, 135, 127, 120, 113,\r
+       107, 101,  95,  90,  85,  80,  75,  71,  67,\r
+       63,  60,  56,  53,  50,  47,  45,  42,  40,\r
+       37,  35,  33,  31,  30,  28};\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR asylum[] = "Asylum 1.0";\r
+\r
+static MODULEHEADER *mh = NULL;\r
+static MODNOTE *patbuf = NULL;\r
+static int modtype = 0;\r
+\r
+/*========== Loader code */\r
+\r
+static BOOL ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)\r
+{\r
+       if (!memcmp(id, "ASYLUM Music Format V1.0", 24))\r
+       {\r
+               *descr = asylum;\r
+               *numchn = 8;\r
+               modtype = 1;\r
+               return 1;\r
+       }\r
+       \r
+       return 0;\r
+}\r
+\r
+static BOOL ASY_Test(void)\r
+{\r
+       UBYTE namestring[24], numchn;\r
+       CHAR *descr;\r
+\r
+       /* Read the magic string */\r
+       _mm_fseek(modreader, 0, SEEK_SET);\r
+       if (!_mm_read_UBYTES(namestring, 24, modreader))\r
+               return 0;\r
+\r
+       /* Test if the string is what we expect */\r
+       if (ASY_CheckType(namestring, &numchn, &descr))\r
+               return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+static BOOL ASY_Init(void)\r
+{\r
+       if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))\r
+               return 0;\r
+       return 1;\r
+}\r
+\r
+static void ASY_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(patbuf);\r
+}\r
+\r
+static void ConvertNote(MODNOTE *n)\r
+{\r
+       UBYTE instrument, effect, effdat, note;\r
+       UWORD period;\r
+       UBYTE lastnote = 0;\r
+       \r
+       instrument = n->b&0x1f;\r
+       effect = n->c;\r
+       effdat = n->d;\r
+\r
+       /* convert amf note to mod period */\r
+       if (n->a) {\r
+               period = periodtable[n->a];\r
+       } else {\r
+               period = 0;\r
+       }\r
+       \r
+       /* Convert the period to a note number */\r
+       note = 0;\r
+       if (period) \r
+       {\r
+               for (note = 0; note < 7 * OCTAVE; note++)\r
+                       if (period >= npertab[note])\r
+                               break;\r
+               if (note == 7 * OCTAVE)\r
+                       note = 0;\r
+               else\r
+                       note++;\r
+       }\r
+\r
+       if (instrument) {\r
+               /* if instrument does not exist, note cut */\r
+               if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {\r
+                       UniPTEffect(0xc, 0);\r
+                       if (effect == 0xc)\r
+                               effect = effdat = 0;\r
+               } else {\r
+                       /* Protracker handling */\r
+                       if (!modtype) {\r
+                               /* if we had a note, then change instrument...*/\r
+                               if (note)\r
+                                       UniInstrument(instrument - 1);\r
+                               /* ...otherwise, only adjust volume... */\r
+                               else {\r
+                                       /* ...unless an effect was specified, \r
+                                        * which forces a new note to be \r
+                                        * played */\r
+                                       if (effect || effdat) {\r
+                                               UniInstrument(instrument - 1);\r
+                                               note = lastnote;\r
+                                       } else\r
+                                               UniPTEffect(0xc,\r
+                                                       mh->samples[instrument -\r
+                                                       1].volume & 0x7f);\r
+                               }\r
+                       } else {\r
+                               /* Fasttracker handling */\r
+                               UniInstrument(instrument - 1);\r
+                               if (!note)\r
+                                       note = lastnote;\r
+                       }\r
+               }\r
+       }\r
+       if (note) {\r
+               UniNote(note + 2 * OCTAVE - 1);\r
+               lastnote = note;\r
+       }\r
+\r
+       /* Convert pattern jump from Dec to Hex */\r
+       if (effect == 0xd)\r
+               effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);\r
+\r
+       /* Volume slide, up has priority */\r
+       if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))\r
+               effdat &= 0xf0;\r
+\r
+       UniPTEffect(effect, effdat);\r
+}\r
+\r
+static UBYTE *ConvertTrack(MODNOTE *n)\r
+{\r
+       int t;\r
+\r
+       UniReset();\r
+       for (t = 0; t < 64; t++) {\r
+               ConvertNote(n);\r
+               UniNewline();\r
+               n += of.numchn;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */\r
+static BOOL ML_LoadPatterns(void)\r
+{\r
+       int t, s, tracks = 0;\r
+\r
+       if (!AllocPatterns()) {\r
+               return 0;\r
+       }\r
+       if (!AllocTracks()) {\r
+               return 0;\r
+       }\r
+       \r
+       /* Allocate temporary buffer for loading and converting the patterns */\r
+       if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))\r
+               return 0;\r
+\r
+\r
+       /* patterns start here */\r
+       _mm_fseek(modreader, 0xA66, SEEK_SET);\r
+       for (t = 0; t < of.numpat; t++) {\r
+               /* Load the pattern into the temp buffer and convert it */\r
+               for (s = 0; s < (64U * of.numchn); s++) {\r
+                       patbuf[s].a = _mm_read_UBYTE(modreader);\r
+                       patbuf[s].b = _mm_read_UBYTE(modreader);\r
+                       patbuf[s].c = _mm_read_UBYTE(modreader);\r
+                       patbuf[s].d = _mm_read_UBYTE(modreader);\r
+               }\r
+               for (s = 0; s < of.numchn; s++) {\r
+                       if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {\r
+                               return 0;\r
+                       }\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL ASY_Load(BOOL curious)\r
+{\r
+       int t;\r
+       SAMPLE *q;\r
+       MSAMPINFO *s;\r
+       CHAR *descr=asylum;\r
+       ULONG seekpos;\r
+       (void)curious;\r
+\r
+       // no title in asylum amf files :(\r
+       strcpy(mh->songname, "");\r
+\r
+       _mm_fseek(modreader, 0x23, SEEK_SET);\r
+       mh->num_patterns = _mm_read_UBYTE(modreader);\r
+       mh->num_orders = _mm_read_UBYTE(modreader);\r
+       \r
+       // skip unknown byte\r
+       _mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->positions, 256, modreader);\r
+       \r
+       /* read samples headers*/\r
+       for (t = 0; t < 64; t++) {\r
+               s = &mh->samples[t];\r
+               \r
+               _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);\r
+               \r
+               _mm_read_string(s->samplename, 22, modreader);\r
+               s->samplename[21] = 0;  /* just in case */\r
+               \r
+               s->finetune = _mm_read_UBYTE(modreader);\r
+               s->volume = _mm_read_UBYTE(modreader);\r
+               _mm_read_UBYTE(modreader); // skip unknown byte\r
+               s->length = _mm_read_I_ULONG(modreader);\r
+               s->reppos = _mm_read_I_ULONG(modreader);\r
+               s->replen = _mm_read_I_ULONG(modreader);\r
+       }\r
+\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       of.numchn = 8;\r
+       modtype = 0;\r
+       of.songname = DupStr(mh->songname, 21, 1);\r
+       of.numpos = mh->num_orders;\r
+       of.reppos = 0;\r
+       of.numpat = mh->num_patterns;\r
+       of.numtrk = of.numpat * of.numchn;\r
+\r
+       \r
+       /* Copy positions (orders) */\r
+       if (!AllocPositions(of.numpos))\r
+               return 0;\r
+       for (t = 0; t < of.numpos; t++) {\r
+               of.positions[t] = mh->positions[t];\r
+       }\r
+\r
+       /* Finally, init the sampleinfo structures  */\r
+       of.numins = 31;\r
+       of.numsmp = 31;\r
+       if (!AllocSamples())\r
+               return 0;\r
+       s = mh->samples;\r
+       q = of.samples;\r
+       seekpos = 2662+(2048*(of.numpat));\r
+       for (t = 0; t < of.numins; t++) {\r
+               /* convert the samplename */\r
+               q->samplename = DupStr(s->samplename, 23, 1);\r
+               \r
+               /* init the sampleinfo variables */\r
+               q->speed = finetune[s->finetune & 0xf];\r
+               q->volume = s->volume & 0x7f;\r
+\r
+               q->loopstart = (ULONG)s->reppos;\r
+               q->loopend = (ULONG)q->loopstart + (s->replen);\r
+               q->length = (ULONG)s->length;\r
+               \r
+               q->flags = SF_SIGNED;\r
+       \r
+               q->seekpos = seekpos;\r
+               seekpos += q->length;\r
+               \r
+               if ((s->replen) > 2) {\r
+                       q->flags |= SF_LOOP;\r
+               }\r
+               \r
+               /* fix replen if repend > length */\r
+               if (q->loopend > q->length)\r
+                       q->loopend = q->length;\r
+\r
+               s++;\r
+               q++;\r
+       }\r
+\r
+       of.modtype = strdup(descr);\r
+\r
+       if (!ML_LoadPatterns())\r
+               return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+static CHAR *ASY_LoadTitle(void)\r
+{\r
+       CHAR *s = ""; // no titles\r
+\r
+       return (DupStr(s, 21, 1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MLOADER load_asy = {\r
+       NULL,\r
+       "AMF",\r
+       "AMF (ASYLUM Music Format V1.0)",\r
+       ASY_Init,\r
+       ASY_Test,\r
+       ASY_Load,\r
+       ASY_Cleanup,\r
+       ASY_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_dsm.c b/apps/plugins/mikmod/loaders/load_dsm.c
new file mode 100644 (file)
index 0000000..0eace5f
--- /dev/null
@@ -0,0 +1,365 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_dsm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  DSIK internal format (DSM) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+#define DSM_MAXCHAN (16)\r
+#define DSM_MAXORDERS (128)\r
+\r
+typedef struct DSMSONG {\r
+       CHAR    songname[28];\r
+       UWORD   version;\r
+       UWORD   flags;\r
+       ULONG   reserved2;\r
+       UWORD   numord;\r
+       UWORD   numsmp;\r
+       UWORD   numpat;\r
+       UWORD   numtrk;\r
+       UBYTE   globalvol;\r
+       UBYTE   mastervol;\r
+       UBYTE   speed;\r
+       UBYTE   bpm;\r
+       UBYTE   panpos[DSM_MAXCHAN];\r
+       UBYTE   orders[DSM_MAXORDERS];\r
+} DSMSONG;\r
+\r
+typedef struct DSMINST {\r
+       CHAR    filename[13];\r
+       UWORD   flags;\r
+       UBYTE   volume;\r
+       ULONG   length;\r
+       ULONG   loopstart;\r
+       ULONG   loopend;\r
+       ULONG   reserved1;\r
+       UWORD   c2spd;\r
+       UWORD   period;\r
+       CHAR    samplename[28];\r
+} DSMINST;\r
+\r
+typedef struct DSMNOTE {\r
+       UBYTE   note,ins,vol,cmd,inf;\r
+} DSMNOTE;\r
+\r
+#define DSM_SURROUND (0xa4)\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR* SONGID="SONG";\r
+static CHAR* INSTID="INST";\r
+static CHAR* PATTID="PATT";\r
+\r
+static UBYTE blockid[4];\r
+static ULONG blockln;\r
+static ULONG blocklp;\r
+static DSMSONG* mh=NULL;\r
+static DSMNOTE* dsmbuf=NULL;\r
+\r
+static CHAR DSM_Version[]="DSIK DSM-format";\r
+\r
+static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL DSM_Test(void)\r
+{\r
+       UBYTE id[12];\r
+\r
+       if(!_mm_read_UBYTES(id,12,modreader)) return 0;\r
+       if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+BOOL DSM_Init(void)\r
+{\r
+       if(!(dsmbuf=(DSMNOTE *)_mm_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0;\r
+       if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;\r
+       return 1;\r
+}\r
+\r
+void DSM_Cleanup(void)\r
+{\r
+       _mm_free(dsmbuf);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL GetBlockHeader(void)\r
+{\r
+       /* make sure we're at the right position for reading the\r
+          next riff block, no matter how many bytes read */\r
+       _mm_fseek(modreader, blocklp+blockln, SEEK_SET);\r
+   \r
+       while(1) {\r
+               _mm_read_UBYTES(blockid,4,modreader);\r
+               blockln=_mm_read_I_ULONG(modreader);\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) &&\r
+                  memcmp(blockid,PATTID,4)) {\r
+#ifdef MIKMOD_DEBUG\r
+                               fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid);\r
+#endif\r
+                               _mm_fseek(modreader, blockln, SEEK_CUR);\r
+               } else\r
+                       break;\r
+       }\r
+\r
+       blocklp = _mm_ftell(modreader);\r
+\r
+       return 1;\r
+}\r
+\r
+static BOOL DSM_ReadPattern(void)\r
+{\r
+       int flag,row=0;\r
+       SWORD length;\r
+       DSMNOTE *n;\r
+\r
+       /* clear pattern data */\r
+       memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));\r
+       length=_mm_read_I_SWORD(modreader);\r
+\r
+       while(row<64) {\r
+               flag=_mm_read_UBYTE(modreader);\r
+               if((_mm_eof(modreader))||(--length<0)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               if(flag) {\r
+                       n=&dsmbuf[((flag&0xf)*64)+row];\r
+                       if(flag&0x80) n->note=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x40) n->ins=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x20) n->vol=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x10) {\r
+                               n->cmd=_mm_read_UBYTE(modreader);\r
+                               n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+               } else\r
+                       row++;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)\r
+{\r
+       int t;\r
+       UBYTE note,ins,vol,cmd,inf;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+               vol=tr[t].vol;\r
+               cmd=tr[t].cmd;\r
+               inf=tr[t].inf;\r
+\r
+               if(ins!=0 && ins!=255) UniInstrument(ins-1);\r
+               if(note!=255) UniNote(note-1); /* normal note */\r
+               if(vol<65) UniPTEffect(0xc,vol);\r
+\r
+               if(cmd!=255) {\r
+                       if(cmd==0x8) {\r
+                               if(inf==DSM_SURROUND)\r
+                                       UniEffect(UNI_ITEFFECTS0,0x91);\r
+                               else\r
+                                 if(inf<=0x80) {\r
+                                       inf=(inf<0x80)?inf<<1:255;\r
+                                       UniPTEffect(cmd,inf);\r
+                               }\r
+                       } else\r
+                         if(cmd==0xb) {\r
+                               if(inf<=0x7f) UniPTEffect(cmd,inf);\r
+                       } else {\r
+                               /* Convert pattern jump from Dec to Hex */\r
+                               if(cmd == 0xd)\r
+                                       inf = (((inf&0xf0)>>4)*10)+(inf&0xf);\r
+                               UniPTEffect(cmd,inf);\r
+                       }\r
+               }\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL DSM_Load(BOOL curious)\r
+{\r
+       int t;\r
+       DSMINST s;\r
+       SAMPLE *q;\r
+       int cursmp=0,curpat=0,track=0;\r
+\r
+       blocklp=0;\r
+       blockln=12;\r
+       (void)curious;\r
+\r
+       if(!GetBlockHeader()) return 0;\r
+       if(memcmp(blockid,SONGID,4)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       _mm_read_UBYTES(mh->songname,28,modreader);\r
+       mh->version=_mm_read_I_UWORD(modreader);\r
+       mh->flags=_mm_read_I_UWORD(modreader);\r
+       mh->reserved2=_mm_read_I_ULONG(modreader);\r
+       mh->numord=_mm_read_I_UWORD(modreader);\r
+       mh->numsmp=_mm_read_I_UWORD(modreader);\r
+       mh->numpat=_mm_read_I_UWORD(modreader);\r
+       mh->numtrk=_mm_read_I_UWORD(modreader);\r
+       mh->globalvol=_mm_read_UBYTE(modreader);\r
+       mh->mastervol=_mm_read_UBYTE(modreader);\r
+       mh->speed=_mm_read_UBYTE(modreader);\r
+       mh->bpm=_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader);\r
+       _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader);\r
+\r
+       /* set module variables */\r
+       of.initspeed=mh->speed;\r
+       of.inittempo=mh->bpm;\r
+       of.modtype=strdup(DSM_Version);\r
+       of.numchn=mh->numtrk;\r
+       of.numpat=mh->numpat;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */\r
+       of.reppos=0;\r
+       of.flags |= UF_PANNING;\r
+       /* XXX whenever possible, we should try to determine the original format.\r
+          Here we assume it was S3M-style wrt bpmlimit... */\r
+       of.bpmlimit = 32;\r
+\r
+       for(t=0;t<DSM_MAXCHAN;t++)\r
+               of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND:\r
+                             mh->panpos[t]<0x80?(mh->panpos[t]<<1):255;\r
+\r
+       if(!AllocPositions(mh->numord)) return 0;\r
+       of.numpos=0;\r
+       for(t=0;t<mh->numord;t++) {\r
+               int order=mh->orders[t];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               if(mh->orders[t]<254) of.numpos++;\r
+       }\r
+\r
+       of.numins=of.numsmp=mh->numsmp;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       while(cursmp<of.numins||curpat<of.numpat) {\r
+               if(!GetBlockHeader()) return 0;\r
+               if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) {\r
+                       q=&of.samples[cursmp];\r
+\r
+                       /* try to read sample info */\r
+                       _mm_read_UBYTES(s.filename,13,modreader);\r
+                       s.flags=_mm_read_I_UWORD(modreader);\r
+                       s.volume=_mm_read_UBYTE(modreader);\r
+                       s.length=_mm_read_I_ULONG(modreader);\r
+                       s.loopstart=_mm_read_I_ULONG(modreader);\r
+                       s.loopend=_mm_read_I_ULONG(modreader);\r
+                       s.reserved1=_mm_read_I_ULONG(modreader);\r
+                       s.c2spd=_mm_read_I_UWORD(modreader);\r
+                       s.period=_mm_read_I_UWORD(modreader);\r
+                       _mm_read_UBYTES(s.samplename,28,modreader);\r
+\r
+                       q->samplename=DupStr(s.samplename,28,1);\r
+                       q->seekpos=_mm_ftell(modreader);\r
+                       q->speed=s.c2spd;\r
+                       q->length=s.length;\r
+                       q->loopstart=s.loopstart;\r
+                       q->loopend=s.loopend;\r
+                       q->volume=s.volume;\r
+\r
+                       if(s.flags&1) q->flags|=SF_LOOP;\r
+                       if(s.flags&2) q->flags|=SF_SIGNED;\r
+                       /* (s.flags&4) means packed sample,\r
+                          but did they really exist in dsm ?*/\r
+                       cursmp++;\r
+               } else\r
+                 if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) {\r
+                       DSM_ReadPattern();\r
+                       for(t=0;t<of.numchn;t++)\r
+                               if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;\r
+                       curpat++;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *DSM_LoadTitle(void)\r
+{\r
+       CHAR s[28];\r
+\r
+       _mm_fseek(modreader,12,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,28,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,28,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_dsm={\r
+       NULL,\r
+       "DSM",\r
+       "DSM (DSIK internal format)",\r
+       DSM_Init,\r
+       DSM_Test,\r
+       DSM_Load,\r
+       DSM_Cleanup,\r
+       DSM_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_far.c b/apps/plugins/mikmod/loaders/load_far.c
new file mode 100644 (file)
index 0000000..a66bf8f
--- /dev/null
@@ -0,0 +1,347 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_far.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Farandole (FAR) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct FARHEADER1 {\r
+       UBYTE id[4];                    /* file magic */\r
+       CHAR  songname[40];             /* songname */\r
+       CHAR  blah[3];                  /* 13,10,26 */\r
+       UWORD headerlen;                /* remaining length of header in bytes */\r
+       UBYTE version;\r
+       UBYTE onoff[16];\r
+       UBYTE edit1[9];\r
+       UBYTE speed;\r
+       UBYTE panning[16];\r
+       UBYTE edit2[4];\r
+       UWORD stlen;\r
+} FARHEADER1;\r
+\r
+typedef struct FARHEADER2 {\r
+       UBYTE orders[256];\r
+       UBYTE numpat;\r
+       UBYTE snglen;\r
+       UBYTE loopto;\r
+       UWORD patsiz[256];\r
+} FARHEADER2;\r
+\r
+typedef struct FARSAMPLE {\r
+       CHAR  samplename[32];\r
+       ULONG length;\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       ULONG reppos;\r
+       ULONG repend;\r
+       UBYTE type;\r
+       UBYTE loop;\r
+} FARSAMPLE;\r
+\r
+typedef struct FARNOTE {\r
+       UBYTE note,ins,vol,eff;\r
+} FARNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR FAR_Version[] = "Farandole";\r
+static FARHEADER1 *mh1 = NULL;\r
+static FARHEADER2 *mh2 = NULL;\r
+static FARNOTE *pat = NULL;\r
+\r
+static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL FAR_Test(void)\r
+{\r
+       UBYTE id[47];\r
+\r
+       if(!_mm_read_UBYTES(id,47,modreader)) return 0;\r
+       if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL FAR_Init(void)\r
+{\r
+       if(!(mh1 = (FARHEADER1*)_mm_malloc(sizeof(FARHEADER1)))) return 0;\r
+       if(!(mh2 = (FARHEADER2*)_mm_malloc(sizeof(FARHEADER2)))) return 0;\r
+       if(!(pat = (FARNOTE*)_mm_malloc(256*16*4*sizeof(FARNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void FAR_Cleanup(void)\r
+{\r
+       _mm_free(mh1);\r
+       _mm_free(mh2);\r
+       _mm_free(pat);\r
+}\r
+\r
+static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)\r
+{\r
+       int t,vibdepth=1;\r
+\r
+       UniReset();\r
+       for(t=0;t<rows;t++) {\r
+               if(n->note) {\r
+                       UniInstrument(n->ins);\r
+                       UniNote(n->note+3*OCTAVE-1);\r
+               }\r
+               if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);\r
+               if (n->eff)\r
+                       switch(n->eff>>4) {\r
+                               case 0x3: /* porta to note */\r
+                                       UniPTEffect(0x3,(n->eff&0xf)<<4);\r
+                                       break;\r
+                               case 0x4: /* retrigger */\r
+                                       UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));\r
+                                       break;\r
+                               case 0x5: /* set vibrato depth */\r
+                                       vibdepth=n->eff&0xf;\r
+                                       break;\r
+                               case 0x6: /* vibrato */\r
+                                       UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);\r
+                                       break;\r
+                               case 0x7: /* volume slide up */\r
+                                       UniPTEffect(0xa,(n->eff&0xf)<<4);\r
+                                       break;\r
+                               case 0x8: /* volume slide down */\r
+                                       UniPTEffect(0xa,n->eff&0xf);\r
+                                       break;\r
+                               case 0xb: /* panning */\r
+                                       UniPTEffect(0xe,0x80|(n->eff&0xf));\r
+                                       break;\r
+                               case 0xf: /* set speed */\r
+                                       UniPTEffect(0xf,n->eff&0xf);\r
+                                       break;\r
+\r
+                               /* others not yet implemented */\r
+                               default:\r
+#ifdef MIKMOD_DEBUG\r
+                                       fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff);\r
+#endif\r
+                                       break;\r
+                       }\r
+\r
+               UniNewline();\r
+               n+=16;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL FAR_Load(BOOL curious)\r
+{\r
+       int t,u,tracks=0;\r
+       SAMPLE *q;\r
+       FARSAMPLE s;\r
+       FARNOTE *crow;\r
+       UBYTE smap[8];\r
+       (void)curious;\r
+\r
+       /* try to read module header (first part) */\r
+       _mm_read_UBYTES(mh1->id,4,modreader);\r
+       _mm_read_SBYTES(mh1->songname,40,modreader);\r
+       _mm_read_SBYTES(mh1->blah,3,modreader);\r
+       mh1->headerlen = _mm_read_I_UWORD (modreader);\r
+       mh1->version   = _mm_read_UBYTE (modreader);\r
+       _mm_read_UBYTES(mh1->onoff,16,modreader);\r
+       _mm_read_UBYTES(mh1->edit1,9,modreader);\r
+       mh1->speed     = _mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh1->panning,16,modreader);\r
+       _mm_read_UBYTES(mh1->edit2,4,modreader);\r
+       mh1->stlen     = _mm_read_I_UWORD (modreader);\r
+\r
+       /* init modfile data */\r
+       of.modtype   = strdup(FAR_Version);\r
+       of.songname  = DupStr(mh1->songname,40,1);\r
+       of.numchn    = 16;\r
+       of.initspeed = mh1->speed;\r
+       of.inittempo = 80;\r
+       of.reppos    = 0;\r
+       of.flags    |= UF_PANNING;\r
+       for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;\r
+\r
+       /* read songtext into comment field */\r
+       if(mh1->stlen)\r
+               if (!ReadLinedComment(mh1->stlen, 66)) return 0;\r
+\r
+       /* try to read module header (second part) */\r
+       _mm_read_UBYTES(mh2->orders,256,modreader);\r
+       mh2->numpat        = _mm_read_UBYTE(modreader);\r
+       mh2->snglen        = _mm_read_UBYTE(modreader);\r
+       mh2->loopto        = _mm_read_UBYTE(modreader);\r
+       _mm_read_I_UWORDS(mh2->patsiz,256,modreader);\r
+\r
+       of.numpos = mh2->snglen;\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=0;t<of.numpos;t++) {\r
+               if(mh2->orders[t]==0xff) break;\r
+               of.positions[t] = mh2->orders[t];\r
+       }\r
+\r
+       /* count number of patterns stored in file */\r
+       of.numpat = 0;\r
+       for(t=0;t<256;t++)\r
+               if(mh2->patsiz[t])\r
+                       if((t+1)>of.numpat) of.numpat=t+1;\r
+       of.numtrk = of.numpat*of.numchn;\r
+\r
+       /* seek across eventual new data */\r
+       _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);\r
+\r
+       /* alloc track and pattern structures */\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               UBYTE rows=0,tempo;\r
+\r
+               memset(pat,0,256*16*4*sizeof(FARNOTE));\r
+               if(mh2->patsiz[t]) {\r
+                       rows  = _mm_read_UBYTE(modreader);\r
+                       tempo = _mm_read_UBYTE(modreader);\r
+\r
+                       crow = pat;\r
+                       /* file often allocates 64 rows even if there are less in pattern */\r
+                       if (mh2->patsiz[t]<2+(rows*16*4)) {\r
+                               _mm_errno = MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+                       for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) {\r
+                               crow->note = _mm_read_UBYTE(modreader);\r
+                               crow->ins  = _mm_read_UBYTE(modreader);\r
+                               crow->vol  = _mm_read_UBYTE(modreader);\r
+                               crow->eff  = _mm_read_UBYTE(modreader);\r
+                       }\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+\r
+                       crow=pat;\r
+                       of.pattrows[t] = rows;\r
+                       for(u=16;u;u--,crow++)\r
+                               if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) {\r
+                                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                                       return 0;\r
+                               }\r
+               } else\r
+                       tracks+=16;\r
+       }\r
+\r
+       /* read sample map */\r
+       if(!_mm_read_UBYTES(smap,8,modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* count number of samples used */\r
+       of.numins = 0;\r
+       for(t=0;t<64;t++)\r
+               if(smap[t>>3]&(1<<(t&7))) of.numins=t+1;\r
+       of.numsmp = of.numins;             \r
+\r
+       /* alloc sample structs */\r
+       if(!AllocSamples()) return 0;\r
+\r
+       q = of.samples;\r
+       for(t=0;t<of.numsmp;t++) {\r
+               q->speed      = 8363;\r
+               q->flags      = SF_SIGNED;\r
+               if(smap[t>>3]&(1<<(t&7))) {\r
+                       _mm_read_SBYTES(s.samplename,32,modreader);\r
+                       s.length   = _mm_read_I_ULONG(modreader);\r
+                       s.finetune = _mm_read_UBYTE(modreader);\r
+                       s.volume   = _mm_read_UBYTE(modreader);\r
+                       s.reppos   = _mm_read_I_ULONG(modreader);\r
+                       s.repend   = _mm_read_I_ULONG(modreader);\r
+                       s.type     = _mm_read_UBYTE(modreader);\r
+                       s.loop     = _mm_read_UBYTE(modreader);\r
+\r
+                       q->samplename = DupStr(s.samplename,32,1);\r
+                       q->length     = s.length;\r
+                       q->loopstart  = s.reppos;\r
+                       q->loopend    = s.repend;\r
+                       q->volume     = s.volume<<2;\r
+\r
+                       if(s.type&1) q->flags|=SF_16BITS;\r
+                       if(s.loop&8) q->flags|=SF_LOOP;\r
+\r
+                       q->seekpos    = _mm_ftell(modreader);\r
+                       _mm_fseek(modreader,q->length,SEEK_CUR);\r
+               } else \r
+                       q->samplename = DupStr(NULL,0,0);\r
+               q++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *FAR_LoadTitle(void)\r
+{\r
+       CHAR s[40];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,40,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,40,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_far={\r
+       NULL,\r
+       "FAR",\r
+       "FAR (Farandole Composer)",\r
+       FAR_Init,\r
+       FAR_Test,\r
+       FAR_Load,\r
+       FAR_Cleanup,\r
+       FAR_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_gdm.c b/apps/plugins/mikmod/loaders/load_gdm.c
new file mode 100644 (file)
index 0000000..d65c2f8
--- /dev/null
@@ -0,0 +1,559 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software;you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation;either version 2 of\r
+       the License,or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY;without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
+\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library;if not,write to the Free Software\r
+       Foundation,Inc.,59 Temple Place - Suite 330,Boston,MA\r
+       02111-1307,USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_gdm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  General DigiMusic (GDM) module loader\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+       Written by Kev Vance<kvance@zeux.org>\r
+       based on the file format description written by 'MenTaLguY'\r
+                                                               <mental@kludge.org>\r
+\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+typedef struct GDMNOTE {\r
+       UBYTE note;\r
+       UBYTE samp;\r
+       struct {\r
+               UBYTE effect;\r
+               UBYTE param;\r
+       } effect[4];\r
+} GDMNOTE;\r
+\r
+typedef GDMNOTE GDMTRACK[64];\r
+\r
+typedef struct GDMHEADER {\r
+       CHAR  id1[4];\r
+       CHAR  songname[32];\r
+       CHAR  author[32];\r
+       CHAR  eofmarker[3];\r
+       CHAR  id2[4];\r
+\r
+       UBYTE majorver;\r
+       UBYTE minorver;\r
+       UWORD trackerid;\r
+       UBYTE t_majorver;\r
+       UBYTE t_minorver;\r
+       UBYTE pantable[32];\r
+       UBYTE mastervol;\r
+       UBYTE mastertempo;\r
+       UBYTE masterbpm;\r
+       UWORD flags;\r
+\r
+       ULONG orderloc;\r
+       UBYTE ordernum;\r
+       ULONG patternloc;\r
+       UBYTE patternnum;\r
+       ULONG samhead;\r
+       ULONG samdata;\r
+       UBYTE samnum;\r
+       ULONG messageloc;\r
+       ULONG messagelen;\r
+       ULONG scrollyloc;\r
+       UWORD scrollylen;\r
+       ULONG graphicloc;\r
+       UWORD graphiclen;\r
+} GDMHEADER;\r
+\r
+typedef struct GDMSAMPLE {\r
+       CHAR  sampname[32];\r
+       CHAR  filename[13];\r
+       UBYTE ems;\r
+       ULONG length;\r
+       ULONG loopbeg;\r
+       ULONG loopend;\r
+       UBYTE flags;\r
+       UWORD c4spd;\r
+       UBYTE vol;\r
+       UBYTE pan;\r
+} GDMSAMPLE;\r
+\r
+static GDMHEADER *mh=NULL;     /* pointer to GDM header */\r
+static GDMNOTE *gdmbuf=NULL;   /* pointer to a complete GDM pattern */\r
+\r
+CHAR GDM_Version[]="General DigiMusic 1.xx";\r
+\r
+BOOL GDM_Test(void)\r
+{\r
+       /* test for gdm magic numbers */\r
+       UBYTE id[4];\r
+\r
+       _mm_fseek(modreader,0x00,SEEK_SET);\r
+       if (!_mm_read_UBYTES(id,4,modreader))\r
+               return 0;\r
+       if (!memcmp(id,"GDM\xfe",4)) {\r
+               _mm_fseek(modreader,71,SEEK_SET);\r
+               if (!_mm_read_UBYTES(id,4,modreader))\r
+                       return 0;\r
+               if (!memcmp(id,"GMFS",4))\r
+                       return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+BOOL GDM_Init(void)\r
+{\r
+       if (!(gdmbuf=(GDMNOTE*)_mm_malloc(32*64*sizeof(GDMNOTE)))) return 0;\r
+       if (!(mh=(GDMHEADER*)_mm_malloc(sizeof(GDMHEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void GDM_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(gdmbuf);\r
+}\r
+\r
+BOOL GDM_ReadPattern(void)\r
+{\r
+       int pos,flag,ch,i,maxch;\r
+       GDMNOTE n;\r
+       UWORD length,x=0;\r
+\r
+       /* get pattern length */\r
+       length=_mm_read_I_UWORD(modreader)-2;\r
+\r
+       /* clear pattern data */\r
+       memset(gdmbuf,255,32*64*sizeof(GDMNOTE));\r
+       pos=0;\r
+       maxch=0;\r
+\r
+       while (x<length) {\r
+               memset(&n,255,sizeof(GDMNOTE));\r
+               flag=_mm_read_UBYTE(modreader);\r
+               x++;\r
+\r
+               if (_mm_eof(modreader)) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               ch=flag&31;\r
+               if (ch>maxch) maxch=ch;\r
+               if (!flag) {\r
+                       pos++;\r
+                       continue;\r
+               }\r
+               if (flag&0x60) {\r
+                       if (flag&0x20) {\r
+                               /* new note */\r
+                               n.note=_mm_read_UBYTE(modreader)&127;\r
+                               n.samp=_mm_read_UBYTE(modreader);\r
+                               x +=2;\r
+                       }\r
+                       if (flag&0x40) {\r
+                               do {\r
+                                       /* effect channel set */\r
+                                       i=_mm_read_UBYTE(modreader);\r
+                                       n.effect[i>>6].effect=i&31;\r
+                                       n.effect[i>>6].param=_mm_read_UBYTE(modreader);\r
+                                       x +=2;\r
+                               } while (i&32);\r
+                       }\r
+                       memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE));\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+UBYTE *GDM_ConvertTrack(GDMNOTE*tr)\r
+{\r
+       int t,i=0;\r
+       UBYTE note,ins,inf;\r
+\r
+       UniReset();\r
+       for (t=0;t<64;t++) {\r
+               note=tr[t].note;\r
+               ins=tr[t].samp;\r
+\r
+               if ((ins)&&(ins!=255))\r
+                       UniInstrument(ins-1);\r
+               if (note!=255) {\r
+                       UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);\r
+               }\r
+               for (i=0;i<4;i++) {\r
+                       inf = tr[t].effect[i].param;\r
+                       switch (tr[t].effect[i].effect) {\r
+                               case 1: /* toneslide up */\r
+                                       UniEffect(UNI_S3MEFFECTF,inf);\r
+                                       break;\r
+                               case 2: /* toneslide down */\r
+                                       UniEffect(UNI_S3MEFFECTE,inf);\r
+                                       break;\r
+                               case 3: /* glissando to note */\r
+                                       UniEffect(UNI_ITEFFECTG,inf);\r
+                                       break;\r
+                               case 4: /* vibrato */\r
+                                       UniEffect(UNI_ITEFFECTH,inf);\r
+                                       break;\r
+                               case 5: /* portamento+volslide */\r
+                                       UniEffect(UNI_ITEFFECTG,0);\r
+                                       UniEffect(UNI_S3MEFFECTD,inf);\r
+                                       break;\r
+                               case 6: /* vibrato+volslide */\r
+                                       UniEffect(UNI_ITEFFECTH,0);\r
+                                       UniEffect(UNI_S3MEFFECTD,inf);\r
+                                       break;\r
+                               case 7: /* tremolo */\r
+                                       UniEffect(UNI_S3MEFFECTR,inf);\r
+                                       break;\r
+                               case 8: /* tremor */\r
+                                       UniEffect(UNI_S3MEFFECTI,inf);\r
+                                       break;\r
+                               case 9: /* offset */\r
+                                       UniPTEffect(0x09,inf);\r
+                                       break;\r
+                               case 0x0a:      /* volslide */\r
+                                       UniEffect(UNI_S3MEFFECTD,inf);\r
+                                       break;\r
+                               case 0x0b:      /* jump to order */\r
+                                       UniPTEffect(0x0b,inf);\r
+                                       break;\r
+                               case 0x0c:      /* volume set */\r
+                                       UniPTEffect(0x0c,inf);\r
+                                       break;\r
+                               case 0x0d:      /* pattern break */\r
+                                       UniPTEffect(0x0d,inf);\r
+                                       break;\r
+                               case 0x0e:      /* extended */\r
+                                       switch (inf&0xf0) {\r
+                                               case 0x10:      /* fine portamento up */\r
+                                                       UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f));\r
+                                                       break;\r
+                                               case 0x20:      /* fine portamento down */\r
+                                                       UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));\r
+                                                       break;\r
+                                               case 0x30:      /* glissando control */\r
+                                                       UniEffect(SS_GLISSANDO, inf&0x0f);\r
+                                                       break;\r
+                                               case 0x40:      /* vibrato waveform */\r
+                                                       UniEffect(SS_VIBWAVE, inf&0x0f);\r
+                                                       break;\r
+                                               case 0x50:      /* set c4spd */\r
+                                                       UniEffect(SS_FINETUNE, inf&0x0f);\r
+                                                       break;\r
+                                               case 0x60:      /* loop fun */\r
+                                                       UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0);\r
+                                                       break;\r
+                                               case 0x70:      /* tremolo waveform */\r
+                                                       UniEffect(SS_TREMWAVE, inf&0x0f);\r
+                                                       break;\r
+                                               case 0x80:      /* extra fine porta up */\r
+                                                       UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f));\r
+                                                       break;\r
+                                               case 0x90:      /* extra fine porta down */\r
+                                                       UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));\r
+                                                       break;\r
+                                               case 0xa0:      /* fine volslide up */\r
+                                                       UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f));\r
+                                                       break;\r
+                                               case 0xb0:      /* fine volslide down */\r
+                                                       UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));\r
+                                                       break;\r
+                                               case 0xc0:      /* note cut */\r
+                                               case 0xd0:      /* note delay */\r
+                                               case 0xe0:      /* extend row */\r
+                                                       UniPTEffect(0xe,inf);\r
+                                                       break;\r
+                                       }\r
+                                       break;\r
+                               case 0x0f:      /* set tempo */\r
+                                       UniEffect(UNI_S3MEFFECTA,inf);\r
+                                       break;\r
+                               case 0x10:      /* arpeggio */\r
+                                       UniPTEffect(0x0,inf);\r
+                                       break;\r
+                               case 0x12:      /* retrigger */\r
+                                       UniEffect(UNI_S3MEFFECTQ,inf);\r
+                                       break;\r
+                               case 0x13:      /* set global volume */\r
+                                       UniEffect(UNI_XMEFFECTG,inf<<1);\r
+                                       break;\r
+                               case 0x14:      /* fine vibrato */\r
+                                       UniEffect(UNI_ITEFFECTU,inf);\r
+                                       break;\r
+                               case 0x1e:      /* special */\r
+                                       switch (inf&0xf0) {\r
+                                               case 8: /* set pan position */\r
+                                                       if (inf >=128)\r
+                                                               UniPTEffect(0x08,255);\r
+                                                       else\r
+                                                               UniPTEffect(0x08,inf<<1);\r
+                                                       break;\r
+                                       }\r
+                                       break;\r
+                               case 0x1f:      /* set bpm */\r
+                                       if (inf >=0x20)\r
+                                               UniEffect(UNI_S3MEFFECTT,inf);\r
+                                       break;\r
+                       }\r
+               }\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL GDM_Load(BOOL curious)\r
+{\r
+       int i,x,u,track;\r
+       SAMPLE *q;\r
+       GDMSAMPLE s;\r
+       ULONG position;\r
+       (void)curious;\r
+\r
+       /* read header */\r
+       _mm_read_string(mh->id1,4,modreader);\r
+       _mm_read_string(mh->songname,32,modreader);\r
+       _mm_read_string(mh->author,32,modreader);\r
+       _mm_read_string(mh->eofmarker,3,modreader);\r
+       _mm_read_string(mh->id2,4,modreader);\r
+\r
+       mh->majorver=_mm_read_UBYTE(modreader);\r
+       mh->minorver=_mm_read_UBYTE(modreader);\r
+       mh->trackerid=_mm_read_I_UWORD(modreader);\r
+       mh->t_majorver=_mm_read_UBYTE(modreader);\r
+       mh->t_minorver=_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->pantable,32,modreader);\r
+       mh->mastervol=_mm_read_UBYTE(modreader);\r
+       mh->mastertempo=_mm_read_UBYTE(modreader);\r
+       mh->masterbpm=_mm_read_UBYTE(modreader);\r
+       mh->flags=_mm_read_I_UWORD(modreader);\r
+\r
+       mh->orderloc=_mm_read_I_ULONG(modreader);\r
+       mh->ordernum=_mm_read_UBYTE(modreader);\r
+       mh->patternloc=_mm_read_I_ULONG(modreader);\r
+       mh->patternnum=_mm_read_UBYTE(modreader);\r
+       mh->samhead=_mm_read_I_ULONG(modreader);\r
+       mh->samdata=_mm_read_I_ULONG(modreader);\r
+       mh->samnum=_mm_read_UBYTE(modreader);\r
+       mh->messageloc=_mm_read_I_ULONG(modreader);\r
+       mh->messagelen=_mm_read_I_ULONG(modreader);\r
+       mh->scrollyloc=_mm_read_I_ULONG(modreader);\r
+       mh->scrollylen=_mm_read_I_UWORD(modreader);\r
+       mh->graphicloc=_mm_read_I_ULONG(modreader);\r
+       mh->graphiclen=_mm_read_I_UWORD(modreader);\r
+\r
+       /* have we ended abruptly? */\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno=MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* any orders? */\r
+       if(mh->ordernum==255) {\r
+               _mm_errno=MMERR_LOADING_PATTERN;\r
+               return 0;\r
+       }\r
+\r
+       /* now we fill */\r
+       of.modtype=strdup(GDM_Version);\r
+       of.modtype[18]=mh->majorver+'0';\r
+       of.modtype[20]=mh->minorver/10+'0';\r
+       of.modtype[21]=mh->minorver%10+'0';\r
+       of.songname=DupStr(mh->songname,32,0);\r
+       of.numpat=mh->patternnum+1;\r
+       of.reppos=0;\r
+       of.numins=of.numsmp=mh->samnum+1;\r
+       of.initspeed=mh->mastertempo;\r
+       of.inittempo=mh->masterbpm;\r
+       of.initvolume=mh->mastervol<<1;\r
+       of.flags|=UF_S3MSLIDES | UF_PANNING;\r
+       /* XXX whenever possible, we should try to determine the original format.\r
+          Here we assume it was S3M-style wrt bpmlimit... */\r
+       of.bpmlimit = 32;\r
+\r
+       /* read the order data */\r
+       if (!AllocPositions(mh->ordernum+1)) {\r
+               _mm_errno=MMERR_OUT_OF_MEMORY;\r
+               return 0;\r
+       }\r
+\r
+       _mm_fseek(modreader,mh->orderloc,SEEK_SET);\r
+       for (i=0;i<mh->ordernum+1;i++)\r
+               of.positions[i]=_mm_read_UBYTE(modreader);\r
+\r
+       of.numpos=0;\r
+       for (i=0;i<mh->ordernum+1;i++) {\r
+               int order=of.positions[i];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               if (of.positions[i]<254) of.numpos++;\r
+       }\r
+\r
+       /* have we ended abruptly yet? */\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno=MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* time to load the samples */\r
+       if (!AllocSamples()) {\r
+               _mm_errno=MMERR_OUT_OF_MEMORY;\r
+               return 0;\r
+       }\r
+\r
+       q=of.samples;\r
+       position=mh->samdata;\r
+\r
+       /* seek to instrument position */\r
+       _mm_fseek(modreader,mh->samhead,SEEK_SET);\r
+\r
+       for (i=0;i<of.numins;i++) {\r
+               /* load sample info */\r
+               _mm_read_UBYTES(s.sampname,32,modreader);\r
+               _mm_read_UBYTES(s.filename,12,modreader);\r
+               s.ems=_mm_read_UBYTE(modreader);\r
+               s.length=_mm_read_I_ULONG(modreader);\r
+               s.loopbeg=_mm_read_I_ULONG(modreader);\r
+               s.loopend=_mm_read_I_ULONG(modreader);\r
+               s.flags=_mm_read_UBYTE(modreader);\r
+               s.c4spd=_mm_read_I_UWORD(modreader);\r
+               s.vol=_mm_read_UBYTE(modreader);\r
+               s.pan=_mm_read_UBYTE(modreader);\r
+\r
+               if (_mm_eof(modreader)) {\r
+                       _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+               q->samplename=DupStr(s.sampname,32,0);\r
+               q->speed=s.c4spd;\r
+               q->length=s.length;\r
+               q->loopstart=s.loopbeg;\r
+               q->loopend=s.loopend;\r
+               q->volume=s.vol;\r
+               q->panning=s.pan;\r
+               q->seekpos=position;\r
+\r
+               position +=s.length;\r
+\r
+               if (s.flags&1)\r
+                       q->flags |=SF_LOOP;\r
+               if (s.flags&2)\r
+                       q->flags |=SF_16BITS;\r
+               if (s.flags&16)\r
+                       q->flags |=SF_STEREO;\r
+               q++;\r
+       }\r
+\r
+       /* set the panning */\r
+       for (i=x=0;i<32;i++) {\r
+               of.panning[i]=mh->pantable[i];\r
+               if (!of.panning[i])\r
+                       of.panning[i]=PAN_LEFT;\r
+               else if (of.panning[i]==8)\r
+                       of.panning[i]=PAN_CENTER;\r
+               else if (of.panning[i]==15)\r
+                       of.panning[i]=PAN_RIGHT;\r
+               else if (of.panning[i]==16)\r
+                       of.panning[i]=PAN_SURROUND;\r
+               else if (of.panning[i]==255)\r
+                       of.panning[i]=128;\r
+               else\r
+                       of.panning[i]<<=3;\r
+               if (mh->pantable[i]!=255)\r
+                       x=i;\r
+       }\r
+\r
+       of.numchn=x+1;\r
+       if (of.numchn<1)\r
+               of.numchn=1;    /* for broken counts */\r
+\r
+       /* load the pattern info */\r
+       of.numtrk=of.numpat*of.numchn;\r
+\r
+       /* jump to patterns */\r
+       _mm_fseek(modreader,mh->patternloc,SEEK_SET);\r
+\r
+       if (!AllocTracks()) {\r
+               _mm_errno=MMERR_OUT_OF_MEMORY;\r
+               return 0;\r
+       }\r
+\r
+       if (!AllocPatterns()) {\r
+               _mm_errno=MMERR_OUT_OF_MEMORY;\r
+               return 0;\r
+       }\r
+\r
+       for (i=track=0;i<of.numpat;i++) {\r
+               if (!GDM_ReadPattern()) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+               for (u=0;u<of.numchn;u++,track++) {\r
+                       of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]);\r
+                       if (!of.tracks[track]) {\r
+                               _mm_errno=MMERR_LOADING_TRACK;\r
+                               return 0;\r
+                       }\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *GDM_LoadTitle(void)\r
+{\r
+       CHAR s[32];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if (!_mm_read_UBYTES(s,32,modreader)) return NULL;\r
+\r
+       return DupStr(s,28,0);\r
+}\r
+\r
+MIKMODAPI MLOADER load_gdm=\r
+{\r
+       NULL,\r
+       "GDM",\r
+       "GDM (General DigiMusic)",\r
+       GDM_Init,\r
+       GDM_Test,\r
+       GDM_Load,\r
+       GDM_Cleanup,\r
+       GDM_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_imf.c b/apps/plugins/mikmod/loaders/load_imf.c
new file mode 100644 (file)
index 0000000..dbc2177
--- /dev/null
@@ -0,0 +1,739 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
+\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_imf.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+  Imago Orpheus (IMF) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* module header */\r
+typedef struct IMFHEADER {\r
+       CHAR  songname[32];\r
+       UWORD ordnum;\r
+       UWORD patnum;\r
+       UWORD insnum;\r
+       UWORD flags;\r
+       UBYTE initspeed;\r
+       UBYTE inittempo;\r
+       UBYTE mastervol;\r
+       UBYTE mastermult;\r
+       UBYTE orders[256];\r
+} IMFHEADER;\r
+\r
+/* channel settings */\r
+typedef struct IMFCHANNEL {\r
+       CHAR  name[12];\r
+       UBYTE chorus;\r
+       UBYTE reverb;\r
+       UBYTE pan;\r
+       UBYTE status;\r
+} IMFCHANNEL;\r
+\r
+/* instrument header */\r
+#define IMFNOTECNT (10*OCTAVE)\r
+#define IMFENVCNT (16*2)\r
+typedef struct IMFINSTHEADER {\r
+       CHAR  name[32];\r
+       UBYTE what[IMFNOTECNT];\r
+       UWORD volenv[IMFENVCNT];\r
+       UWORD panenv[IMFENVCNT];\r
+       UWORD pitenv[IMFENVCNT];\r
+       UBYTE volpts;\r
+       UBYTE volsus;\r
+       UBYTE volbeg;\r
+       UBYTE volend;\r
+       UBYTE volflg;\r
+       UBYTE panpts;\r
+       UBYTE pansus;\r
+       UBYTE panbeg;\r
+       UBYTE panend;\r
+       UBYTE panflg;\r
+       UBYTE pitpts;\r
+       UBYTE pitsus;\r
+       UBYTE pitbeg;\r
+       UBYTE pitend;\r
+       UBYTE pitflg;\r
+       UWORD volfade;\r
+       UWORD numsmp;\r
+       ULONG signature;\r
+} IMFINSTHEADER;\r
+\r
+/* sample header */\r
+typedef struct IMFWAVHEADER {\r
+       CHAR  samplename[13];\r
+       ULONG length;\r
+       ULONG loopstart;\r
+       ULONG loopend;\r
+       ULONG samplerate;\r
+       UBYTE volume;\r
+       UBYTE pan;\r
+       UBYTE flags;\r
+} IMFWAVHEADER;\r
+\r
+typedef struct IMFNOTE {\r
+       UBYTE note,ins,eff1,dat1,eff2,dat2;\r
+} IMFNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR IMF_Version[]="Imago Orpheus";\r
+\r
+static IMFNOTE *imfpat=NULL;\r
+static IMFHEADER *mh=NULL;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL IMF_Test(void)\r
+{\r
+       UBYTE id[4];\r
+\r
+       _mm_fseek(modreader,0x3c,SEEK_SET);\r
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
+       if(!memcmp(id,"IM10",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL IMF_Init(void)\r
+{\r
+       if(!(imfpat=(IMFNOTE*)_mm_malloc(32*256*sizeof(IMFNOTE)))) return 0;\r
+       if(!(mh=(IMFHEADER*)_mm_malloc(sizeof(IMFHEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void IMF_Cleanup(void)\r
+{\r
+       FreeLinear();\r
+\r
+       _mm_free(imfpat);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL IMF_ReadPattern(SLONG size,UWORD rows)\r
+{\r
+       int row=0,flag,ch;\r
+       IMFNOTE *n,dummy;\r
+\r
+       /* clear pattern data */\r
+       memset(imfpat,255,32*256*sizeof(IMFNOTE));\r
+\r
+       while((size>0)&&(row<rows)) {\r
+               flag=_mm_read_UBYTE(modreader);size--;\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               if(flag) {\r
+                       ch=remap[flag&31];\r
+\r
+                       if(ch!=-1)\r
+                               n=&imfpat[256*ch+row];\r
+                       else\r
+                               n=&dummy;\r
+\r
+                       if(flag&32) {\r
+                               n->note=_mm_read_UBYTE(modreader);\r
+                               if(n->note>=0xa0) n->note=0xa0; /* note off */\r
+                               n->ins =_mm_read_UBYTE(modreader);\r
+                               size-=2;\r
+                       }\r
+                       if(flag&64) {\r
+                               size-=2;\r
+                               n->eff2=_mm_read_UBYTE(modreader);\r
+                               n->dat2=_mm_read_UBYTE(modreader);\r
+                       }\r
+                       if(flag&128) {\r
+                               n->eff1=_mm_read_UBYTE(modreader);\r
+                               n->dat1=_mm_read_UBYTE(modreader);\r
+                               size-=2;\r
+                       }\r
+               } else row++;\r
+       }\r
+       if((size)||(row!=rows)) {\r
+               _mm_errno=MMERR_LOADING_PATTERN;\r
+               return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static void IMF_ProcessCmd(UBYTE eff,UBYTE inf)\r
+{\r
+       if((eff)&&(eff!=255))\r
+               switch (eff) {\r
+                       case 0x01:      /* set tempo */\r
+                               UniEffect(UNI_S3MEFFECTA,inf);\r
+                               break;\r
+                       case 0x02:      /* set BPM */\r
+                               if(inf>=0x20) UniEffect(UNI_S3MEFFECTT,inf);\r
+                               break;\r
+                       case 0x03:      /* tone portamento */\r
+                               UniEffect(UNI_ITEFFECTG,inf);\r
+                               break;\r
+                       case 0x04:      /* porta + volslide */\r
+                               UniEffect(UNI_ITEFFECTG,inf);\r
+                               UniEffect(UNI_S3MEFFECTD,0);\r
+                               break;\r
+                       case 0x05:      /* vibrato */\r
+                               UniEffect(UNI_XMEFFECT4,inf);\r
+                               break;\r
+                       case 0x06:      /* vibrato + volslide */\r
+                               UniEffect(UNI_XMEFFECT6,inf);\r
+                               break;\r
+                       case 0x07:      /* fine vibrato */\r
+                               UniEffect(UNI_ITEFFECTU,inf);\r
+                               break;\r
+                       case 0x08:      /* tremolo */\r
+                               UniEffect(UNI_S3MEFFECTR,inf);\r
+                               break;\r
+                       case 0x09:      /* arpeggio */\r
+                               UniPTEffect(0x0,inf);\r
+                               break;\r
+                       case 0x0a:      /* panning */\r
+                               UniPTEffect(0x8,(inf>=128)?255:(inf<<1));\r
+                               break;\r
+                       case 0x0b:      /* pan slide */\r
+                               UniEffect(UNI_XMEFFECTP,inf);\r
+                               break;\r
+                       case 0x0c:      /* set channel volume */\r
+                               if(inf<=64) UniPTEffect(0xc,inf);\r
+                               break;\r
+                       case 0x0d:      /* volume slide */\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0x0e:      /* fine volume slide */\r
+                               if(inf) {\r
+                                       if(inf>>4)\r
+                                               UniEffect(UNI_S3MEFFECTD,0x0f|inf);\r
+                                       else\r
+                                               UniEffect(UNI_S3MEFFECTD,0xf0|inf);\r
+                               } else\r
+                                       UniEffect(UNI_S3MEFFECTD,0);\r
+                               break;\r
+                       case 0x0f:      /* set finetune */\r
+                               UniPTEffect(0xe,0x50|(inf>>4));\r
+                               break;\r
+#ifdef MIKMOD_DEBUG\r
+                       case 0x10:      /* note slide up */\r
+                       case 0x11:      /* not slide down */\r
+                               fprintf(stderr,"\rIMF effect 0x10/0x11 (note slide)"\r
+                                              " not implemented (eff=%2X inf=%2X)\n",eff,inf);\r
+                               break;\r
+#endif\r
+                       case 0x12:      /* slide up */\r
+                               UniEffect(UNI_S3MEFFECTF,inf);\r
+                               break;\r
+                       case 0x13:      /* slide down */\r
+                               UniEffect(UNI_S3MEFFECTE,inf);\r
+                               break;\r
+                       case 0x14:      /* fine slide up */\r
+                               if (inf) {\r
+                                       if (inf<0x40)\r
+                                               UniEffect(UNI_S3MEFFECTF,0xe0|(inf>>2));\r
+                                       else\r
+                                               UniEffect(UNI_S3MEFFECTF,0xf0|(inf>>4));\r
+                               } else\r
+                                       UniEffect(UNI_S3MEFFECTF,0);\r
+                               break;\r
+                       case 0x15:      /* fine slide down */\r
+                               if (inf) {\r
+                                       if (inf<0x40)\r
+                                               UniEffect(UNI_S3MEFFECTE,0xe0|(inf>>2));\r
+                                       else\r
+                                               UniEffect(UNI_S3MEFFECTE,0xf0|(inf>>4));\r
+                               } else\r
+                                       UniEffect(UNI_S3MEFFECTE,0);\r
+                               break;\r
+                       /* 0x16 set filter cutoff (awe32) */\r
+                       /* 0x17 filter side + resonance (awe32) */\r
+                       case 0x18:      /* sample offset */\r
+                               UniPTEffect(0x9,inf);\r
+                               break;\r
+#ifdef MIKMOD_DEBUG\r
+                       case 0x19:      /* set fine sample offset */\r
+                               fprintf(stderr,"\rIMF effect 0x19 (fine sample offset)"\r
+                                              " not implemented (inf=%2X)\n",inf);\r
+                               break;\r
+#endif\r
+                       case 0x1a:      /* keyoff */\r
+                               UniWriteByte(UNI_KEYOFF);\r
+                               break;\r
+                       case 0x1b:      /* retrig */\r
+                               UniEffect(UNI_S3MEFFECTQ,inf);\r
+                               break;\r
+                       case 0x1c:      /* tremor */\r
+                               UniEffect(UNI_S3MEFFECTI,inf);\r
+                               break;\r
+                       case 0x1d:      /* position jump */\r
+                               UniPTEffect(0xb,inf);\r
+                               break;\r
+                       case 0x1e:      /* pattern break */\r
+                               UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));\r
+                               break;\r
+                       case 0x1f:      /* set master volume */\r
+                               if(inf<=64) UniEffect(UNI_XMEFFECTG,inf<<1);\r
+                               break;\r
+                       case 0x20:      /* master volume slide */\r
+                               UniEffect(UNI_XMEFFECTH,inf);\r
+                               break;\r
+                       case 0x21:      /* extended effects */\r
+                               switch(inf>>4) {\r
+                                       case 0x1:       /* set filter */\r
+                                       case 0x5:       /* vibrato waveform */\r
+                                       case 0x8:       /* tremolo waveform */\r
+                                               UniPTEffect(0xe,inf-0x10);\r
+                                               break;\r
+                                       case 0xa:       /* pattern loop */\r
+                                               UniPTEffect(0xe,0x60|(inf&0xf));\r
+                                               break;\r
+                                       case 0xb:       /* pattern delay */\r
+                                               UniPTEffect(0xe,0xe0|(inf&0xf));\r
+                                               break;\r
+                                       case 0x3:       /* glissando */\r
+                                       case 0xc:       /* note cut */\r
+                                       case 0xd:       /* note delay */\r
+                                       case 0xf:       /* invert loop */\r
+                                               UniPTEffect(0xe,inf);\r
+                                               break;\r
+                                       case 0xe:       /* ignore envelope */\r
+                                               UniEffect(UNI_ITEFFECTS0, 0x77);    /* vol */\r
+                                               UniEffect(UNI_ITEFFECTS0, 0x79);    /* pan */\r
+                                               UniEffect(UNI_ITEFFECTS0, 0x7b);    /* pit */\r
+                                               break;\r
+                               }\r
+                               break;\r
+                       /* 0x22 chorus (awe32) */\r
+                       /* 0x23 reverb (awe32) */\r
+               }\r
+}\r
+\r
+static UBYTE* IMF_ConvertTrack(IMFNOTE* tr,UWORD rows)\r
+{\r
+       int t;\r
+       UBYTE note,ins;\r
+\r
+       UniReset();\r
+       for(t=0;t<rows;t++) {\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+\r
+               if((ins)&&(ins!=255)) UniInstrument(ins-1);\r
+               if(note!=255) {\r
+                       if(note==0xa0) {\r
+                               UniPTEffect(0xc,0); /* Note cut */\r
+                               if(tr[t].eff1==0x0c) tr[t].eff1=0;\r
+                               if(tr[t].eff2==0x0c) tr[t].eff2=0;\r
+                       } else\r
+                               UniNote(((note>>4)*OCTAVE)+(note&0xf));\r
+               }\r
+\r
+               IMF_ProcessCmd(tr[t].eff1,tr[t].dat1);\r
+               IMF_ProcessCmd(tr[t].eff2,tr[t].dat2);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL IMF_Load(BOOL curious)\r
+{\r
+#define IMF_SMPINCR 64\r
+       int t,u,track=0,oldnumsmp;\r
+       IMFCHANNEL channels[32];\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       IMFWAVHEADER *wh=NULL,*s=NULL;\r
+       ULONG *nextwav=NULL;\r
+       UWORD wavcnt=0;\r
+       UBYTE id[4];\r
+       (void)curious;\r
+\r
+       /* try to read the module header */\r
+       _mm_read_string(mh->songname,32,modreader);\r
+       mh->ordnum=_mm_read_I_UWORD(modreader);\r
+       mh->patnum=_mm_read_I_UWORD(modreader);\r
+       mh->insnum=_mm_read_I_UWORD(modreader);\r
+       mh->flags =_mm_read_I_UWORD(modreader);\r
+       _mm_fseek(modreader,8,SEEK_CUR);\r
+       mh->initspeed =_mm_read_UBYTE(modreader);\r
+       mh->inittempo =_mm_read_UBYTE(modreader);\r
+       mh->mastervol =_mm_read_UBYTE(modreader);\r
+       mh->mastermult=_mm_read_UBYTE(modreader);\r
+       _mm_fseek(modreader,64,SEEK_SET);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.songname=DupStr(mh->songname,31,1);\r
+       of.modtype=strdup(IMF_Version);\r
+       of.numpat=mh->patnum;\r
+       of.numins=mh->insnum;\r
+       of.reppos=0;\r
+       of.initspeed=mh->initspeed;\r
+       of.inittempo=mh->inittempo;\r
+       of.initvolume=mh->mastervol<<1;\r
+       of.flags |= UF_INST | UF_ARPMEM | UF_PANNING;\r
+       if(mh->flags&1) of.flags |= UF_LINEAR;\r
+       of.bpmlimit=32;\r
+\r
+       /* read channel information */\r
+       of.numchn=0;\r
+       memset(remap,-1,32*sizeof(UBYTE));\r
+       for(t=0;t<32;t++) {\r
+               _mm_read_string(channels[t].name,12,modreader);\r
+               channels[t].chorus=_mm_read_UBYTE(modreader);\r
+               channels[t].reverb=_mm_read_UBYTE(modreader);\r
+               channels[t].pan   =_mm_read_UBYTE(modreader);\r
+               channels[t].status=_mm_read_UBYTE(modreader);\r
+       }\r
+       /* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to\r
+          enable 16 channels */\r
+       if(!channels[0].status) {\r
+               for(t=1;t<16;t++) if(channels[t].status!=1) break;\r
+               if(t==16) for(t=1;t<16;t++) channels[t].status=0;\r
+       }\r
+       for(t=0;t<32;t++) {\r
+               if(channels[t].status!=2)\r
+                       remap[t]=of.numchn++;\r
+               else\r
+                       remap[t]=-1;\r
+       }\r
+       for(t=0;t<32;t++)\r
+               if(remap[t]!=-1) {\r
+                       of.panning[remap[t]]=channels[t].pan;\r
+                       of.chanvol[remap[t]]=channels[t].status?0:64;\r
+               }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* read order list */\r
+       _mm_read_UBYTES(mh->orders,256,modreader);\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       of.numpos=0;\r
+       for(t=0;t<mh->ordnum;t++)\r
+               if(mh->orders[t]!=0xff) of.numpos++;\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=u=0;t<mh->ordnum;t++)\r
+               if(mh->orders[t]!=0xff) of.positions[u++]=mh->orders[t];\r
+\r
+       /* load pattern info */\r
+       of.numtrk=of.numpat*of.numchn;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               SLONG size;\r
+               UWORD rows;\r
+\r
+               size=(SLONG)_mm_read_I_UWORD(modreader);\r
+               rows=_mm_read_I_UWORD(modreader);\r
+               if((rows>256)||(size<4)) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               of.pattrows[t]=rows;\r
+               if(!IMF_ReadPattern(size-4,rows)) return 0;\r
+               for(u=0;u<of.numchn;u++)\r
+                       if(!(of.tracks[track++]=IMF_ConvertTrack(&imfpat[u*256],rows)))\r
+                               return 0;\r
+       }\r
+\r
+       /* load instruments */\r
+       if(!AllocInstruments()) return 0;\r
+       d=of.instruments;\r
+\r
+       for(oldnumsmp=t=0;t<of.numins;t++) {\r
+               IMFINSTHEADER ih;\r
+\r
+               memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
+\r
+               /* read instrument header */\r
+               _mm_read_string(ih.name,32,modreader);\r
+               d->insname=DupStr(ih.name,31,1);\r
+               _mm_read_UBYTES(ih.what,IMFNOTECNT,modreader);\r
+               _mm_fseek(modreader,8,SEEK_CUR);\r
+               _mm_read_I_UWORDS(ih.volenv,IMFENVCNT,modreader);\r
+               _mm_read_I_UWORDS(ih.panenv,IMFENVCNT,modreader);\r
+               _mm_read_I_UWORDS(ih.pitenv,IMFENVCNT,modreader);\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IMF_FinishLoadingEnvelope(name)                                        \\r
+               ih. name##pts=_mm_read_UBYTE(modreader);                \\r
+               ih. name##sus=_mm_read_UBYTE(modreader);                \\r
+               ih. name##beg=_mm_read_UBYTE(modreader);                \\r
+               ih. name##end=_mm_read_UBYTE(modreader);                \\r
+               ih. name##flg=_mm_read_UBYTE(modreader);                \\r
+               _mm_read_UBYTE(modreader);                                              \\r
+               _mm_read_UBYTE(modreader);                                              \\r
+               _mm_read_UBYTE(modreader)\r
+#else\r
+#define IMF_FinishLoadingEnvelope(name)                                \\r
+               ih. name/**/pts=_mm_read_UBYTE(modreader);      \\r
+               ih. name/**/sus=_mm_read_UBYTE(modreader);      \\r
+               ih. name/**/beg=_mm_read_UBYTE(modreader);      \\r
+               ih. name/**/end=_mm_read_UBYTE(modreader);      \\r
+               ih. name/**/flg=_mm_read_UBYTE(modreader);      \\r
+               _mm_read_UBYTE(modreader);                                      \\r
+               _mm_read_UBYTE(modreader);                                      \\r
+               _mm_read_UBYTE(modreader)\r
+#endif\r
+\r
+               IMF_FinishLoadingEnvelope(vol);\r
+               IMF_FinishLoadingEnvelope(pan);\r
+               IMF_FinishLoadingEnvelope(pit);\r
+\r
+               ih.volfade=_mm_read_I_UWORD(modreader);\r
+               ih.numsmp =_mm_read_I_UWORD(modreader);\r
+\r
+               _mm_read_UBYTES(id,4,modreader);\r
+               /* Looks like Imago Orpheus forgets the signature for empty\r
+                  instruments following a multi-sample instrument... */\r
+               if(memcmp(id,"II10",4) && \r
+                  (oldnumsmp && memcmp(id,"\x0\x0\x0\x0",4))) {\r
+                       if(nextwav) free(nextwav);\r
+                       if(wh) free(wh);\r
+                       _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+               oldnumsmp=ih.numsmp;\r
+\r
+               if((ih.numsmp>16)||(ih.volpts>IMFENVCNT/2)||(ih.panpts>IMFENVCNT/2)||\r
+                  (ih.pitpts>IMFENVCNT/2)||(_mm_eof(modreader))) {\r
+                       if(nextwav) free(nextwav);\r
+                       if(wh) free(wh);\r
+                       _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               for(u=0;u<IMFNOTECNT;u++)\r
+                       d->samplenumber[u]=ih.what[u]>ih.numsmp?0xffff:ih.what[u]+of.numsmp;\r
+               d->volfade=ih.volfade;\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IMF_ProcessEnvelope(name)                                                                      \\r
+               for (u = 0; u < (IMFENVCNT >> 1); u++) {                                        \\r
+                       d-> name##env[u].pos = ih. name##env[u << 1];                   \\r
+                       d-> name##env[u].val = ih. name##env[(u << 1)+ 1];              \\r
+               }                                                                                                                       \\r
+               if (ih. name##flg&1) d-> name##flg|=EF_ON;                                      \\r
+               if (ih. name##flg&2) d-> name##flg|=EF_SUSTAIN;                         \\r
+               if (ih. name##flg&4) d-> name##flg|=EF_LOOP;                            \\r
+               d-> name##susbeg=d-> name##susend=ih. name##sus;                        \\r
+               d-> name##beg=ih. name##beg;                                                            \\r
+               d-> name##end=ih. name##end;                                                            \\r
+               d-> name##pts=ih. name##pts;                                                            \\r
+                                                                                                                                       \\r
+               if ((d-> name##flg&EF_ON)&&(d-> name##pts<2))                           \\r
+                       d-> name##flg&=~EF_ON\r
+#else\r
+#define IMF_ProcessEnvelope(name)                                                                      \\r
+               for (u = 0; u < (IMFENVCNT >> 1); u++) {                                        \\r
+                       d-> name/**/env[u].pos = ih. name/**/env[u << 1];               \\r
+                       d-> name/**/env[u].val = ih. name/**/env[(u << 1)+ 1];  \\r
+               }                                                                                                                       \\r
+               if (ih. name/**/flg&1) d-> name/**/flg|=EF_ON;                          \\r
+               if (ih. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN;                     \\r
+               if (ih. name/**/flg&4) d-> name/**/flg|=EF_LOOP;                        \\r
+               d-> name/**/susbeg=d-> name/**/susend=ih. name/**/sus;          \\r
+               d-> name/**/beg=ih. name/**/beg;                                                        \\r
+               d-> name/**/end=ih. name/**/end;                                                        \\r
+               d-> name/**/pts=ih. name/**/pts;                                                        \\r
+                                                                                                                                       \\r
+               if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))                       \\r
+                       d-> name/**/flg&=~EF_ON\r
+#endif\r
+\r
+               IMF_ProcessEnvelope(vol);\r
+               IMF_ProcessEnvelope(pan);\r
+               IMF_ProcessEnvelope(pit);\r
+#undef IMF_ProcessEnvelope\r
+\r
+               if(ih.pitflg&1) {\r
+                       d->pitflg&=~EF_ON;\r
+#ifdef MIKMOD_DEBUG\r
+                       fprintf(stderr, "\rFilter envelopes not supported yet\n");\r
+#endif\r
+               }\r
+\r
+               /* gather sample information */\r
+               for(u=0;u<ih.numsmp;u++,s++) {\r
+                       /* allocate more room for sample information if necessary */\r
+                       if(of.numsmp+u==wavcnt) {\r
+                               wavcnt+=IMF_SMPINCR;\r
+                               if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))) {\r
+                                       if(wh) free(wh);\r
+                                       _mm_errno=MMERR_OUT_OF_MEMORY;\r
+                                       return 0;\r
+                               }\r
+                               if(!(wh=realloc(wh,wavcnt*sizeof(IMFWAVHEADER)))) {\r
+                                       free(nextwav);\r
+                                       _mm_errno=MMERR_OUT_OF_MEMORY;\r
+                                       return 0;\r
+                               }\r
+                               s=wh+(wavcnt-IMF_SMPINCR);\r
+                       }\r
+\r
+                       _mm_read_string(s->samplename,13,modreader);\r
+                       _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);\r
+                       s->length    =_mm_read_I_ULONG(modreader);\r
+                       s->loopstart =_mm_read_I_ULONG(modreader);\r
+                       s->loopend   =_mm_read_I_ULONG(modreader);\r
+                       s->samplerate=_mm_read_I_ULONG(modreader);\r
+                       s->volume    =_mm_read_UBYTE(modreader)&0x7f;\r
+                       s->pan       =_mm_read_UBYTE(modreader);\r
+                       _mm_fseek(modreader,14,SEEK_CUR);\r
+                       s->flags     =_mm_read_UBYTE(modreader);\r
+                       _mm_fseek(modreader,11,SEEK_CUR);\r
+                       _mm_read_UBYTES(id,4,modreader);\r
+                       if(((memcmp(id,"IS10",4))&&(memcmp(id,"IW10",4)))||\r
+                          (_mm_eof(modreader))) {\r
+                               free(nextwav);free(wh);\r
+                               _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+                               return 0;\r
+                       }\r
+                       nextwav[of.numsmp+u]=_mm_ftell(modreader);\r
+                       _mm_fseek(modreader,s->length,SEEK_CUR);\r
+               }\r
+\r
+               of.numsmp+=ih.numsmp;\r
+               d++;\r
+       }\r
+\r
+       /* sanity check */\r
+       if(!of.numsmp) {\r
+               if(nextwav) free(nextwav);\r
+               if(wh) free(wh);\r
+               _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+               return 0;\r
+       }\r
+\r
+       /* load samples */\r
+       if(!AllocSamples()) {\r
+               free(nextwav);free(wh);\r
+               return 0;\r
+       }\r
+       if(!AllocLinear()) {\r
+               free(nextwav);free(wh);\r
+               return 0;\r
+       }\r
+       q=of.samples;\r
+       s=wh;\r
+       for(u=0;u<of.numsmp;u++,s++,q++) {\r
+               q->samplename=DupStr(s->samplename,12,1);\r
+               q->length   =s->length;\r
+               q->loopstart=s->loopstart;\r
+               q->loopend  =s->loopend;\r
+               q->volume   =s->volume;\r
+               q->speed    =s->samplerate;\r
+               if(of.flags&UF_LINEAR)\r
+                       q->speed=speed_to_finetune(s->samplerate<<1,u);\r
+               q->panning  =s->pan;\r
+               q->seekpos  =nextwav[u];\r
+\r
+               q->flags|=SF_SIGNED;\r
+               if(s->flags&0x1) q->flags|=SF_LOOP;\r
+               if(s->flags&0x2) q->flags|=SF_BIDI;\r
+               if(s->flags&0x8) q->flags|=SF_OWNPAN;\r
+               if(s->flags&0x4) {\r
+                       q->flags|=SF_16BITS;\r
+                       q->length   >>=1;\r
+                       q->loopstart>>=1;\r
+                       q->loopend  >>=1;\r
+               }\r
+       }\r
+\r
+       d=of.instruments;\r
+       s=wh;\r
+       for(u=0;u<of.numins;u++,d++) {\r
+               for(t=0;t<IMFNOTECNT;t++) {\r
+                       if(d->samplenumber[t]>=of.numsmp)\r
+                               d->samplenote[t]=255;\r
+                       else if (of.flags&UF_LINEAR) {\r
+                               int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
+                               d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
+                       } else\r
+                               d->samplenote[t]=t;\r
+               }\r
+       }\r
+\r
+       free(wh);free(nextwav);\r
+       return 1;\r
+}\r
+\r
+CHAR *IMF_LoadTitle(void)\r
+{\r
+       CHAR s[31];\r
+\r
+       _mm_fseek(modreader,0,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,31,modreader)) return NULL;\r
+\r
+       return(DupStr(s,31,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_imf={\r
+       NULL,\r
+       "IMF",\r
+       "IMF (Imago Orpheus)",\r
+       IMF_Init,\r
+       IMF_Test,\r
+       IMF_Load,\r
+       IMF_Cleanup,\r
+       IMF_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_it.c b/apps/plugins/mikmod/loaders/load_it.c
new file mode 100644 (file)
index 0000000..d115af5
--- /dev/null
@@ -0,0 +1,1008 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_it.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+  Impulse tracker (IT) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+//#include <ctype.h>\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+extern int toupper(int);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct ITHEADER {\r
+       CHAR    songname[26];\r
+       UBYTE   blank01[2];\r
+       UWORD   ordnum;\r
+       UWORD   insnum;\r
+       UWORD   smpnum;\r
+       UWORD   patnum;\r
+       UWORD   cwt;            /* Created with tracker (y.xx = 0x0yxx) */\r
+       UWORD   cmwt;           /* Compatible with tracker ver > than val. */\r
+       UWORD   flags;\r
+       UWORD   special;        /* bit 0 set = song message attached */\r
+       UBYTE   globvol;\r
+       UBYTE   mixvol;         /* mixing volume [ignored] */\r
+       UBYTE   initspeed;\r
+       UBYTE   inittempo;\r
+       UBYTE   pansep;         /* panning separation between channels */\r
+       UBYTE   zerobyte;       \r
+       UWORD   msglength;\r
+       ULONG   msgoffset;\r
+       UBYTE   blank02[4];\r
+       UBYTE   pantable[64];\r
+       UBYTE   voltable[64];\r
+} ITHEADER;\r
+\r
+/* sample information */\r
+typedef struct ITSAMPLE {\r
+       CHAR    filename[12];\r
+       UBYTE   zerobyte;\r
+       UBYTE   globvol;\r
+       UBYTE   flag;\r
+       UBYTE   volume;\r
+       UBYTE   panning;\r
+       CHAR    sampname[28];\r
+       UWORD   convert;        /* sample conversion flag */\r
+       ULONG   length;\r
+       ULONG   loopbeg;\r
+       ULONG   loopend;\r
+       ULONG   c5spd;\r
+       ULONG   susbegin;\r
+       ULONG   susend;\r
+       ULONG   sampoffset;\r
+       UBYTE   vibspeed;\r
+       UBYTE   vibdepth;\r
+       UBYTE   vibrate;\r
+       UBYTE   vibwave;        /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */\r
+} ITSAMPLE;\r
+\r
+/* instrument information */\r
+\r
+#define ITENVCNT 25\r
+#define ITNOTECNT 120\r
+typedef struct ITINSTHEADER {\r
+       ULONG   size;                   /* (dword) Instrument size */\r
+       CHAR    filename[12];   /* (char) Instrument filename */\r
+       UBYTE   zerobyte;               /* (byte) Instrument type (always 0) */\r
+       UBYTE   volflg;\r
+       UBYTE   volpts;   \r
+       UBYTE   volbeg;                 /* (byte) Volume loop start (node) */\r
+       UBYTE   volend;                 /* (byte) Volume loop end (node) */\r
+       UBYTE   volsusbeg;              /* (byte) Volume sustain begin (node) */\r
+       UBYTE   volsusend;              /* (byte) Volume Sustain end (node) */\r
+       UBYTE   panflg;\r
+       UBYTE   panpts;  \r
+       UBYTE   panbeg;                 /* (byte) channel loop start (node) */\r
+       UBYTE   panend;                 /* (byte) channel loop end (node) */\r
+       UBYTE   pansusbeg;              /* (byte) channel sustain begin (node) */\r
+       UBYTE   pansusend;              /* (byte) channel Sustain end (node) */\r
+       UBYTE   pitflg;\r
+       UBYTE   pitpts;   \r
+       UBYTE   pitbeg;                 /* (byte) pitch loop start (node) */\r
+       UBYTE   pitend;                 /* (byte) pitch loop end (node) */\r
+       UBYTE   pitsusbeg;              /* (byte) pitch sustain begin (node) */\r
+       UBYTE   pitsusend;              /* (byte) pitch Sustain end (node) */\r
+       UWORD   blank;\r
+       UBYTE   globvol;\r
+       UBYTE   chanpan;\r
+       UWORD   fadeout;                /* Envelope end / NNA volume fadeout */\r
+       UBYTE   dnc;                    /* Duplicate note check */\r
+       UBYTE   dca;                    /* Duplicate check action */\r
+       UBYTE   dct;                    /* Duplicate check type */\r
+       UBYTE   nna;                    /* New Note Action [0,1,2,3] */\r
+       UWORD   trkvers;                /* tracker version used to save [files only] */\r
+       UBYTE   ppsep;                  /* Pitch-pan Separation */\r
+       UBYTE   ppcenter;               /* Pitch-pan Center */\r
+       UBYTE   rvolvar;                /* random volume varations */\r
+       UBYTE   rpanvar;                /* random panning varations */\r
+       UWORD   numsmp;                 /* Number of samples in instrument [files only] */\r
+       CHAR    name[26];               /* Instrument name */\r
+       UBYTE   blank01[6];\r
+       UWORD   samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */\r
+       UBYTE   volenv[200];         /* volume envelope (IT 1.x stuff) */\r
+       UBYTE   oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */\r
+       UBYTE   volnode[ITENVCNT];   /* amplitude of volume nodes */\r
+       UWORD   voltick[ITENVCNT];   /* tick value of volume nodes */\r
+       SBYTE   pannode[ITENVCNT];   /* panenv - node points */\r
+       UWORD   pantick[ITENVCNT];   /* tick value of panning nodes */\r
+       SBYTE   pitnode[ITENVCNT];   /* pitchenv - node points */\r
+       UWORD   pittick[ITENVCNT];   /* tick value of pitch nodes */\r
+} ITINSTHEADER;                       \r
+\r
+/* unpacked note */\r
+\r
+typedef struct ITNOTE {\r
+       UBYTE note,ins,volpan,cmd,inf;\r
+} ITNOTE;\r
+\r
+/*========== Loader data */\r
+\r
+static ULONG *paraptr=NULL;    /* parapointer array (see IT docs) */\r
+static ITHEADER *mh=NULL;\r
+static ITNOTE *itpat=NULL;     /* allocate to space for one full pattern */\r
+static UBYTE *mask=NULL;       /* arrays allocated to 64 elements and used for */\r
+static ITNOTE *last=NULL;      /* uncompressing IT's pattern information */\r
+static int numtrk=0;\r
+static unsigned int old_effect;                /* if set, use S3M old-effects stuffs */\r
+   \r
+static CHAR* IT_Version[]={\r
+       "ImpulseTracker  .  ",\r
+       "Compressed ImpulseTracker  .  ",\r
+       "ImpulseTracker 2.14p3",\r
+       "Compressed ImpulseTracker 2.14p3",\r
+       "ImpulseTracker 2.14p4",\r
+       "Compressed ImpulseTracker 2.14p4",\r
+};\r
+\r
+/* table for porta-to-note command within volume/panning column */\r
+static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL IT_Test(void)\r
+{\r
+       UBYTE id[4];\r
+\r
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
+       if(!memcmp(id,"IMPM",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL IT_Init(void)\r
+{\r
+       if(!(mh=(ITHEADER*)_mm_malloc(sizeof(ITHEADER)))) return 0;\r
+       if(!(poslookup=(UBYTE*)_mm_malloc(256*sizeof(UBYTE)))) return 0;\r
+       if(!(itpat=(ITNOTE*)_mm_malloc(200*64*sizeof(ITNOTE)))) return 0;\r
+       if(!(mask=(UBYTE*)_mm_malloc(64*sizeof(UBYTE)))) return 0;\r
+       if(!(last=(ITNOTE*)_mm_malloc(64*sizeof(ITNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void IT_Cleanup(void)\r
+{\r
+       FreeLinear();\r
+\r
+       _mm_free(mh);\r
+       _mm_free(poslookup);\r
+       _mm_free(itpat);\r
+       _mm_free(mask);\r
+       _mm_free(last);\r
+       _mm_free(paraptr);\r
+       _mm_free(origpositions);\r
+}\r
+\r
+/* Because so many IT files have 64 channels as the set number used, but really\r
+   only use far less (usually from 8 to 24 still), I had to make this function,\r
+   which determines the number of channels that are actually USED by a pattern.\r
\r
+   NOTE: You must first seek to the file location of the pattern before calling\r
+         this procedure.\r
+\r
+   Returns 1 on error\r
+*/\r
+static BOOL IT_GetNumChannels(UWORD patrows)\r
+{\r
+       int row=0,flag,ch;\r
+\r
+       do {\r
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 1;\r
+               }\r
+               if(!flag)\r
+                       row++;\r
+               else {\r
+                       ch=(flag-1)&63;\r
+                       remap[ch]=0;\r
+                       if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&1)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&2)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&4)   _mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); }\r
+               }\r
+       } while(row<patrows);\r
+\r
+       return 0;\r
+}\r
+\r
+static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)\r
+{\r
+       int t;\r
+       UBYTE note,ins,volpan;\r
+\r
+       UniReset();\r
+\r
+       for(t=0;t<numrows;t++) {\r
+               note=tr[t*of.numchn].note;\r
+               ins=tr[t*of.numchn].ins;\r
+               volpan=tr[t*of.numchn].volpan;\r
+\r
+               if(note!=255) {\r
+                       if(note==253)\r
+                               UniWriteByte(UNI_KEYOFF);\r
+                       else if(note==254) {\r
+                               UniPTEffect(0xc,-1);    /* note cut command */\r
+                               volpan=255;\r
+                       } else\r
+                               UniNote(note);\r
+               }\r
+\r
+               if((ins)&&(ins<100))\r
+                       UniInstrument(ins-1);\r
+               else if(ins==253)\r
+                       UniWriteByte(UNI_KEYOFF);\r
+               else if(ins!=255) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               }\r
+\r
+               /* process volume / panning column\r
+                  volume / panning effects do NOT all share the same memory address\r
+                  yet. */\r
+               if(volpan<=64) \r
+                       UniVolEffect(VOL_VOLUME,volpan);\r
+               else if(volpan==65) /* fine volume slide up (65-74) - A0 case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0);\r
+               else if(volpan<=74)     { /* fine volume slide up (65-74) - general case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4));\r
+               } else if(volpan==75)   /* fine volume slide down (75-84) - B0 case */\r
+                       UniVolEffect(VOL_VOLSLIDE,0);\r
+               else if(volpan<=84) {   /* fine volume slide down (75-84) - general case*/\r
+                       UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75));\r
+               } else if(volpan<=94)   /* volume slide up (85-94) */\r
+                       UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4));\r
+               else if(volpan<=104)/* volume slide down (95-104) */\r
+                       UniVolEffect(VOL_VOLSLIDE,(volpan-95));\r
+               else if(volpan<=114)/* pitch slide down (105-114) */\r
+                       UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105));\r
+               else if(volpan<=124)/* pitch slide up (115-124) */\r
+                       UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115));\r
+               else if(volpan<=127) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               } else if(volpan<=192)\r
+                       UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2));\r
+               else if(volpan<=202)/* portamento to note */\r
+                       UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]);\r
+               else if(volpan<=212)/* vibrato */\r
+                       UniVolEffect(VOL_VIBRATO,(volpan-203));\r
+               else if((volpan!=239)&&(volpan!=255)) { /* crap */\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return NULL;\r
+               }\r
+\r
+               S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,\r
+                   old_effect|S3MIT_IT);\r
+\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL IT_ReadPattern(UWORD patrows)\r
+{\r
+       int row=0,flag,ch,blah;\r
+       ITNOTE *itt=itpat,dummy,*n,*l;\r
+\r
+       memset(itt,255,200*64*sizeof(ITNOTE));\r
+\r
+       do {\r
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+               if(!flag) {\r
+                       itt=&itt[of.numchn];\r
+                       row++;\r
+               } else {\r
+                       ch=remap[(flag-1)&63];\r
+                       if(ch!=-1) {\r
+                               n=&itt[ch];\r
+                               l=&last[ch];\r
+                       } else \r
+                               n=l=&dummy;\r
+\r
+                       if(flag&128) mask[ch]=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&1)\r
+                               /* convert IT note off to internal note off */\r
+                               if((l->note=n->note=_mm_read_UBYTE(modreader))==255) \r
+                                       l->note=n->note=253;\r
+                       if(mask[ch]&2)\r
+                               l->ins=n->ins=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&4)\r
+                               l->volpan=n->volpan=_mm_read_UBYTE(modreader);\r
+                       if(mask[ch]&8) {\r
+                               l->cmd=n->cmd=_mm_read_UBYTE(modreader);\r
+                               l->inf=n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+                       if(mask[ch]&16)\r
+                               n->note=l->note;\r
+                       if(mask[ch]&32)\r
+                               n->ins=l->ins;\r
+                       if(mask[ch]&64)\r
+                               n->volpan=l->volpan;\r
+                       if(mask[ch]&128) {\r
+                               n->cmd=l->cmd;\r
+                               n->inf=l->inf;\r
+                       }\r
+               }\r
+       } while(row<patrows);\r
+\r
+       for(blah=0;blah<of.numchn;blah++) {\r
+               if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows)))\r
+                       return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static void LoadMidiString(MREADER* modreader,CHAR* dest)\r
+{\r
+       CHAR *cur,*last;\r
+\r
+       _mm_read_UBYTES(dest,32,modreader);\r
+       cur=last=dest;\r
+       /* remove blanks and uppercase all */\r
+       while(*last) {\r
+               if(isalnum((int)*last)) *(cur++)=toupper((int)*last);\r
+               last++;\r
+       }\r
+       *cur=0;\r
+}\r
+\r
+/* Load embedded midi information for resonant filters */\r
+static void IT_LoadMidiConfiguration(MREADER* modreader)\r
+{\r
+       int i;\r
+\r
+       memset(filtermacros,0,sizeof(filtermacros));\r
+       memset(filtersettings,0,sizeof(filtersettings));\r
+\r
+       if (modreader) { /* information is embedded in file */\r
+               UWORD dat;\r
+               CHAR midiline[33];\r
+\r
+               dat=_mm_read_I_UWORD(modreader);\r
+               _mm_fseek(modreader,8*dat+0x120,SEEK_CUR);\r
+\r
+               /* read midi macros */\r
+               for(i=0;i<UF_MAXMACRO;i++) {\r
+                       LoadMidiString(modreader,midiline);\r
+                       if((!strncmp(midiline,"F0F00",5))&&\r
+                          ((midiline[5]=='0')||(midiline[5]=='1')))\r
+                                       filtermacros[i]=(midiline[5]-'0')|0x80;\r
+               }\r
+\r
+               /* read standalone filters */\r
+               for(i=0x80;i<0x100;i++) {\r
+                       LoadMidiString(modreader,midiline);\r
+                       if((!strncmp(midiline,"F0F00",5))&&\r
+                          ((midiline[5]=='0')||(midiline[5]=='1'))) {\r
+                               filtersettings[i].filter=(midiline[5]-'0')|0x80;\r
+                               dat=(midiline[6])?(midiline[6]-'0'):0;\r
+                               if(midiline[7])dat=(dat<<4)|(midiline[7]-'0');\r
+                               filtersettings[i].inf=dat;\r
+                       }\r
+               }\r
+       } else { /* use default information */\r
+               filtermacros[0]=FILT_CUT;\r
+               for(i=0x80;i<0x90;i++) {\r
+                       filtersettings[i].filter=FILT_RESONANT;\r
+                       filtersettings[i].inf=(i&0x7f)<<3;\r
+               }\r
+       }\r
+       activemacro=0;\r
+       for(i=0;i<0x80;i++) {\r
+               filtersettings[i].filter=filtermacros[0];\r
+               filtersettings[i].inf=i;\r
+       }\r
+}\r
+\r
+BOOL IT_Load(BOOL curious)\r
+{\r
+       int t,u,lp;\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       BOOL compressed=0;\r
+\r
+       numtrk=0;\r
+       filters=0;\r
+\r
+       /* try to read module header */\r
+       _mm_read_I_ULONG(modreader);    /* kill the 4 byte header */\r
+       _mm_read_string(mh->songname,26,modreader);\r
+       _mm_read_UBYTES(mh->blank01,2,modreader);\r
+       mh->ordnum      =_mm_read_I_UWORD(modreader);\r
+       mh->insnum      =_mm_read_I_UWORD(modreader);\r
+       mh->smpnum      =_mm_read_I_UWORD(modreader);\r
+       mh->patnum      =_mm_read_I_UWORD(modreader);\r
+       mh->cwt         =_mm_read_I_UWORD(modreader);\r
+       mh->cmwt        =_mm_read_I_UWORD(modreader);\r
+       mh->flags       =_mm_read_I_UWORD(modreader);\r
+       mh->special     =_mm_read_I_UWORD(modreader);\r
+       mh->globvol     =_mm_read_UBYTE(modreader);\r
+       mh->mixvol      =_mm_read_UBYTE(modreader);\r
+       mh->initspeed   =_mm_read_UBYTE(modreader);\r
+       mh->inittempo   =_mm_read_UBYTE(modreader);\r
+       mh->pansep      =_mm_read_UBYTE(modreader);\r
+       mh->zerobyte    =_mm_read_UBYTE(modreader);\r
+       mh->msglength   =_mm_read_I_UWORD(modreader);\r
+       mh->msgoffset   =_mm_read_I_ULONG(modreader);\r
+       _mm_read_UBYTES(mh->blank02,4,modreader);\r
+       _mm_read_UBYTES(mh->pantable,64,modreader);\r
+       _mm_read_UBYTES(mh->voltable,64,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno=MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.songname    = DupStr(mh->songname,26,0); /* make a cstr of songname  */\r
+       of.reppos      = 0;\r
+       of.numpat      = mh->patnum;\r
+       of.numins      = mh->insnum;\r
+       of.numsmp      = mh->smpnum;\r
+       of.initspeed   = mh->initspeed;\r
+       of.inittempo   = mh->inittempo;\r
+       of.initvolume  = mh->globvol;\r
+       of.flags      |= UF_BGSLIDES | UF_ARPMEM;\r
+       if (!(mh->flags & 1))\r
+                       of.flags |= UF_PANNING;\r
+       of.bpmlimit=32;\r
+\r
+       if(mh->songname[25]) {\r
+               of.numvoices=1+mh->songname[25];\r
+#ifdef MIKMOD_DEBUG\r
+               fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices);\r
+#endif\r
+       }\r
+\r
+       /* set the module type */\r
+       /* 2.17 : IT 2.14p4 */\r
+       /* 2.16 : IT 2.14p3 with resonant filters */\r
+       /* 2.15 : IT 2.14p3 (improved compression) */\r
+       if((mh->cwt<=0x219)&&(mh->cwt>=0x217))\r
+               of.modtype=strdup(IT_Version[mh->cmwt<0x214?4:5]);\r
+       else if (mh->cwt>=0x215)\r
+               of.modtype=strdup(IT_Version[mh->cmwt<0x214?2:3]);\r
+       else {\r
+               of.modtype     = strdup(IT_Version[mh->cmwt<0x214?0:1]);\r
+               of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0';\r
+               of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0';\r
+               of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0';\r
+       }\r
+\r
+       if(mh->flags&8)\r
+               of.flags |= UF_XMPERIODS | UF_LINEAR;\r
+\r
+       if((mh->cwt>=0x106)&&(mh->flags&16))\r
+               old_effect=S3MIT_OLDSTYLE;\r
+       else\r
+               old_effect=0;\r
+\r
+       /* set panning positions */\r
+       if (mh->flags & 1)\r
+               for(t=0;t<64;t++) {\r
+                       mh->pantable[t]&=0x7f;\r
+                       if(mh->pantable[t]<64)\r
+                               of.panning[t]=mh->pantable[t]<<2;\r
+                       else if(mh->pantable[t]==64)\r
+                               of.panning[t]=255;\r
+                       else if(mh->pantable[t]==100)\r
+                               of.panning[t]=PAN_SURROUND;\r
+                       else if(mh->pantable[t]==127)\r
+                               of.panning[t]=PAN_CENTER;\r
+                       else {\r
+                               _mm_errno=MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               }\r
+       else\r
+               for(t=0;t<64;t++)\r
+                       of.panning[t]=PAN_CENTER;\r
+\r
+       /* set channel volumes */\r
+       memcpy(of.chanvol,mh->voltable,64);\r
+\r
+       /* read the order data */\r
+       if(!AllocPositions(mh->ordnum)) return 0;\r
+       if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0;\r
+\r
+       for(t=0;t<mh->ordnum;t++) {\r
+               origpositions[t]=_mm_read_UBYTE(modreader);\r
+               if((origpositions[t]>mh->patnum)&&(origpositions[t]<254))\r
+                       origpositions[t]=255;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       poslookupcnt=mh->ordnum;\r
+       S3MIT_CreateOrders(curious);\r
+\r
+       if(!(paraptr=(ULONG*)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)*\r
+                                      sizeof(ULONG)))) return 0;\r
+\r
+       /* read the instrument, sample, and pattern parapointers */\r
+       _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* Check for and load midi information for resonant filters */\r
+       if(mh->cmwt>=0x216) {\r
+               if(mh->special&8) {\r
+                       IT_LoadMidiConfiguration(modreader);\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else\r
+                       IT_LoadMidiConfiguration(NULL);\r
+               filters=1;\r
+       }\r
+\r
+       /* Check for and load song comment */\r
+       if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) {\r
+               _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET);\r
+               if(!ReadComment(mh->msglength)) return 0;\r
+       }\r
+\r
+       if(!(mh->flags&4)) of.numins=of.numsmp;\r
+       if(!AllocSamples()) return 0;\r
+\r
+       if(!AllocLinear()) return 0;\r
+\r
+       /* Load all samples */\r
+       q = of.samples;\r
+       for(t=0;t<mh->smpnum;t++) {\r
+               ITSAMPLE s;\r
+\r
+               /* seek to sample position */\r
+               _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET);\r
+\r
+               /* load sample info */\r
+               _mm_read_string(s.filename,12,modreader);\r
+               s.zerobyte    = _mm_read_UBYTE(modreader);\r
+               s.globvol     = _mm_read_UBYTE(modreader);\r
+               s.flag        = _mm_read_UBYTE(modreader);\r
+               s.volume      = _mm_read_UBYTE(modreader);\r
+               _mm_read_string(s.sampname,26,modreader);\r
+               s.convert     = _mm_read_UBYTE(modreader);\r
+               s.panning     = _mm_read_UBYTE(modreader);\r
+               s.length      = _mm_read_I_ULONG(modreader);\r
+               s.loopbeg     = _mm_read_I_ULONG(modreader);\r
+               s.loopend     = _mm_read_I_ULONG(modreader);\r
+               s.c5spd       = _mm_read_I_ULONG(modreader);\r
+               s.susbegin    = _mm_read_I_ULONG(modreader);\r
+               s.susend      = _mm_read_I_ULONG(modreader);\r
+               s.sampoffset  = _mm_read_I_ULONG(modreader);\r
+               s.vibspeed    = _mm_read_UBYTE(modreader);\r
+               s.vibdepth    = _mm_read_UBYTE(modreader);\r
+               s.vibrate     = _mm_read_UBYTE(modreader);\r
+               s.vibwave     = _mm_read_UBYTE(modreader);\r
+\r
+               /* Generate an error if c5spd is > 512k, or samplelength > 256 megs\r
+                  (nothing would EVER be that high) */\r
+\r
+               if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               /* Reality check for sample loop information */\r
+               if((s.flag&16)&&\r
+                  ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.sampname,26,0);\r
+               q->speed      = s.c5spd / 2;\r
+               q->panning    = ((s.panning&127)==64)?255:(s.panning&127)<<2;\r
+               q->length     = s.length;\r
+               q->loopstart  = s.loopbeg;\r
+               q->loopend    = s.loopend;\r
+               q->volume     = s.volume;\r
+               q->globvol    = s.globvol;\r
+               q->seekpos    = s.sampoffset;\r
+\r
+               /* Convert speed to XM linear finetune */\r
+               if(of.flags&UF_LINEAR)\r
+                       q->speed=speed_to_finetune(s.c5spd,t);\r
+\r
+               if(s.panning&128) q->flags|=SF_OWNPAN;\r
+\r
+               if(s.vibrate) {\r
+                       q->vibflags |= AV_IT;\r
+                       q->vibtype   = s.vibwave;\r
+                       q->vibsweep  = s.vibrate * 2;\r
+                       q->vibdepth  = s.vibdepth;\r
+                       q->vibrate   = s.vibspeed;\r
+               }\r
+\r
+               if(s.flag&2) q->flags|=SF_16BITS;\r
+               if((s.flag&8)&&(mh->cwt>=0x214)) {\r
+                       q->flags|=SF_ITPACKED;\r
+                       compressed=1;\r
+               }\r
+               if(s.flag&16) q->flags|=SF_LOOP;\r
+               if(s.flag&64) q->flags|=SF_BIDI;\r
+\r
+               if(mh->cwt>=0x200) {\r
+                       if(s.convert&1) q->flags|=SF_SIGNED;\r
+                       if(s.convert&4) q->flags|=SF_DELTA;   \r
+               }\r
+               q++;\r
+       }\r
+\r
+       /* Load instruments if instrument mode flag enabled */\r
+       if(mh->flags&4) {\r
+               if(!AllocInstruments()) return 0;\r
+               d=of.instruments;\r
+               of.flags|=UF_NNA|UF_INST;\r
+\r
+               for(t=0;t<mh->insnum;t++) {\r
+                       ITINSTHEADER ih;\r
+\r
+                       /* seek to instrument position */\r
+                       _mm_fseek(modreader,paraptr[t]+4,SEEK_SET);\r
+\r
+                       /* load instrument info */\r
+                       _mm_read_string(ih.filename,12,modreader);\r
+                       ih.zerobyte  = _mm_read_UBYTE(modreader);\r
+                       if(mh->cwt<0x200) {\r
+                               /* load IT 1.xx inst header */\r
+                               ih.volflg    = _mm_read_UBYTE(modreader);\r
+                               ih.volbeg    = _mm_read_UBYTE(modreader);\r
+                               ih.volend    = _mm_read_UBYTE(modreader);\r
+                               ih.volsusbeg = _mm_read_UBYTE(modreader);\r
+                               ih.volsusend = _mm_read_UBYTE(modreader);\r
+                               _mm_read_I_UWORD(modreader);\r
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);\r
+                               ih.nna       = _mm_read_UBYTE(modreader);\r
+                               ih.dnc       = _mm_read_UBYTE(modreader);\r
+                       } else {\r
+                               /* Read IT200+ header */\r
+                               ih.nna       = _mm_read_UBYTE(modreader);\r
+                               ih.dct       = _mm_read_UBYTE(modreader);\r
+                               ih.dca       = _mm_read_UBYTE(modreader);\r
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);\r
+                               ih.ppsep     = _mm_read_UBYTE(modreader);\r
+                               ih.ppcenter  = _mm_read_UBYTE(modreader);\r
+                               ih.globvol   = _mm_read_UBYTE(modreader);\r
+                               ih.chanpan   = _mm_read_UBYTE(modreader);\r
+                               ih.rvolvar   = _mm_read_UBYTE(modreader);\r
+                               ih.rpanvar   = _mm_read_UBYTE(modreader);\r
+                       }\r
+\r
+                       ih.trkvers   = _mm_read_I_UWORD(modreader);\r
+                       ih.numsmp    = _mm_read_UBYTE(modreader);\r
+                       _mm_read_UBYTE(modreader);\r
+                       _mm_read_string(ih.name,26,modreader);\r
+                       _mm_read_UBYTES(ih.blank01,6,modreader);\r
+                       _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader);\r
+                       if(mh->cwt<0x200) {\r
+                               /* load IT 1xx volume envelope */\r
+                               _mm_read_UBYTES(ih.volenv,200,modreader);\r
+                               for(lp=0;lp<ITENVCNT;lp++) {\r
+                                       ih.oldvoltick[lp] = _mm_read_UBYTE(modreader);\r
+                                       ih.volnode[lp]    = _mm_read_UBYTE(modreader);\r
+                               } \r
+                       } else {\r
+                               /* load IT 2xx volume, pan and pitch envelopes */\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IT_LoadEnvelope(name,type)                                                                             \\r
+                               ih. name##flg   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##pts   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##beg   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##end   =_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##susbeg=_mm_read_UBYTE(modreader);                             \\r
+                               ih. name##susend=_mm_read_UBYTE(modreader);                             \\r
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \\r
+                                       ih. name##node[lp]=_mm_read_##type (modreader);         \\r
+                                       ih. name##tick[lp]=_mm_read_I_UWORD(modreader);         \\r
+                               }                                                                                                               \\r
+                               _mm_read_UBYTE(modreader)\r
+#else\r
+#define IT_LoadEnvelope(name,type)                                                                             \\r
+                               ih. name/**/flg   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/pts   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/beg   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/end   =_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/susbeg=_mm_read_UBYTE(modreader);                   \\r
+                               ih. name/**/susend=_mm_read_UBYTE(modreader);                   \\r
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \\r
+                                       ih. name/**/node[lp]=_mm_read_/**/type (modreader);     \\r
+                                       ih. name/**/tick[lp]=_mm_read_I_UWORD(modreader);       \\r
+                               }                                                                                                               \\r
+                               _mm_read_UBYTE(modreader)\r
+#endif\r
+\r
+                               IT_LoadEnvelope(vol,UBYTE);\r
+                               IT_LoadEnvelope(pan,SBYTE);\r
+                               IT_LoadEnvelope(pit,SBYTE);\r
+#undef IT_LoadEnvelope\r
+                       }\r
\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                               return 0;\r
+                       }\r
+\r
+                       d->volflg|=EF_VOLENV;\r
+                       d->insname = DupStr(ih.name,26,0);\r
+                       d->nnatype = ih.nna & NNA_MASK;\r
+\r
+                       if(mh->cwt<0x200) {\r
+                               d->volfade=ih.fadeout<< 6;\r
+                               if(ih.dnc) {\r
+                                       d->dct=DCT_NOTE;\r
+                                       d->dca=DCA_CUT;\r
+                               }\r
+\r
+                               if(ih.volflg&1) d->volflg|=EF_ON;\r
+                               if(ih.volflg&2) d->volflg|=EF_LOOP;\r
+                               if(ih.volflg&4) d->volflg|=EF_SUSTAIN;      \r
+\r
+                               /* XM conversion of IT envelope Array */\r
+                               d->volbeg    = ih.volbeg;   \r
+                               d->volend    = ih.volend;\r
+                               d->volsusbeg = ih.volsusbeg;\r
+                               d->volsusend = ih.volsusend;\r
+\r
+                               if(ih.volflg&1) {\r
+                                       for(u=0;u<ITENVCNT;u++)\r
+                                               if(ih.oldvoltick[d->volpts]!=0xff) {\r
+                                                       d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2);\r
+                                                       d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts];\r
+                                                       d->volpts++;\r
+                                               } else\r
+                                                       break;\r
+                               }  \r
+                       } else {\r
+                               d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2;\r
+                               if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN;\r
+\r
+                               if(!(ih.ppsep & 128)) {\r
+                                       d->pitpansep=ih.ppsep<<2;\r
+                                       d->pitpancenter=ih.ppcenter;\r
+                                       d->flags|=IF_PITCHPAN;\r
+                               }\r
+                               d->globvol=ih.globvol>>1;\r
+                               d->volfade=ih.fadeout<<5;\r
+                               d->dct    =ih.dct;\r
+                               d->dca    =ih.dca;\r
+\r
+                               if(mh->cwt>=0x204) {\r
+                                       d->rvolvar = ih.rvolvar;\r
+                                       d->rpanvar = ih.rpanvar;\r
+                               }\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define IT_ProcessEnvelope(name)                                                                               \\r
+                               if(ih. name##flg&1) d-> name##flg|=EF_ON;                               \\r
+                               if(ih. name##flg&2) d-> name##flg|=EF_LOOP;                             \\r
+                               if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN;                  \\r
+                               d-> name##pts=ih. name##pts;                                                    \\r
+                               d-> name##beg=ih. name##beg;                                                    \\r
+                               d-> name##end=ih. name##end;                                                    \\r
+                               d-> name##susbeg=ih. name##susbeg;                                              \\r
+                               d-> name##susend=ih. name##susend;                                              \\r
+                                                                                                                                               \\r
+                               for(u=0;u<ih. name##pts;u++)                                                    \\r
+                                       d-> name##env[u].pos=ih. name##tick[u];                         \\r
+                                                                                                                                               \\r
+                               if((d-> name##flg&EF_ON)&&(d-> name##pts<2))                    \\r
+                                       d-> name##flg&=~EF_ON\r
+#else\r
+#define IT_ProcessEnvelope(name)                                                                       \\r
+                               if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON;           \\r
+                               if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP;         \\r
+                               if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN;      \\r
+                               d-> name/**/pts=ih. name/**/pts;                                        \\r
+                               d-> name/**/beg=ih. name/**/beg;                                        \\r
+                               d-> name/**/end=ih. name/**/end;                                        \\r
+                               d-> name/**/susbeg=ih. name/**/susbeg;                          \\r
+                               d-> name/**/susend=ih. name/**/susend;                          \\r
+                                                                                                                                       \\r
+                               for(u=0;u<ih. name/**/pts;u++)                                          \\r
+                                       d-> name/**/env[u].pos=ih. name/**/tick[u];             \\r
+                                                                                                                                       \\r
+                               if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))        \\r
+                                       d-> name/**/flg&=~EF_ON\r
+#endif\r
+\r
+                               IT_ProcessEnvelope(vol);\r
+                               for(u=0;u<ih.volpts;u++)\r
+                                       d->volenv[u].val=(ih.volnode[u]<<2);\r
+\r
+                               IT_ProcessEnvelope(pan);\r
+                               for(u=0;u<ih.panpts;u++)\r
+                                       d->panenv[u].val=\r
+                                         ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2;\r
+\r
+                               IT_ProcessEnvelope(pit);\r
+                               for(u=0;u<ih.pitpts;u++)\r
+                                       d->pitenv[u].val=ih.pitnode[u]+32;\r
+#undef IT_ProcessEnvelope\r
+\r
+                               if(ih.pitflg&0x80) {\r
+                                       /* filter envelopes not supported yet */\r
+                                       d->pitflg&=~EF_ON;\r
+                                       ih.pitpts=ih.pitbeg=ih.pitend=0;\r
+#ifdef MIKMOD_DEBUG\r
+                                       {\r
+                                               static int warn=0;\r
+                                               \r
+                                               if(!warn)\r
+                                                       fprintf(stderr, "\rFilter envelopes not supported yet\n");\r
+                                               warn=1;\r
+                                       }\r
+#endif\r
+                               }\r
+                       }\r
+\r
+                       for(u=0;u<ITNOTECNT;u++) {\r
+                               d->samplenote[u]=(ih.samptable[u]&255);\r
+                               d->samplenumber[u]=\r
+                                 (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff;\r
+                               if(d->samplenumber[u]>=of.numsmp)\r
+                                       d->samplenote[u]=255;\r
+                               else if (of.flags&UF_LINEAR) {\r
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
+                               }\r
+                       }\r
+\r
+                       d++;                  \r
+               }\r
+       } else if(of.flags & UF_LINEAR) {\r
+               if(!AllocInstruments()) return 0;\r
+               d=of.instruments;\r
+               of.flags|=UF_INST;\r
+\r
+               for(t=0;t<mh->smpnum;t++,d++)\r
+                       for(u=0;u<ITNOTECNT;u++) {\r
+                               if(d->samplenumber[u]>=of.numsmp)\r
+                                       d->samplenote[u]=255;\r
+                               else {\r
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
+                               }\r
+                       }\r
+       }\r
+\r
+       /* Figure out how many channels this song actually uses */\r
+       of.numchn=0;\r
+       memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE));\r
+       for(t=0;t<of.numpat;t++) {\r
+               UWORD packlen;\r
+\r
+               /* seek to pattern position */\r
+               if(paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */\r
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);\r
+                       _mm_read_I_UWORD(modreader);\r
+                       /* read pattern length (# of rows)\r
+                          Impulse Tracker never creates patterns with less than 32 rows,\r
+                          but some other trackers do, so we only check for more than 256\r
+                          rows */\r
+                       packlen=_mm_read_I_UWORD(modreader);\r
+                       if(packlen>256) {\r
+                               _mm_errno=MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+                       _mm_read_I_ULONG(modreader);\r
+                       if(IT_GetNumChannels(packlen)) return 0;\r
+               }\r
+       }\r
+\r
+       /* give each of them a different number */\r
+       for(t=0;t<UF_MAXCHAN;t++) \r
+               if(!remap[t])\r
+                       remap[t]=of.numchn++;\r
+\r
+       of.numtrk = of.numpat*of.numchn;\r
+       if(of.numvoices)\r
+               if (of.numvoices<of.numchn) of.numvoices=of.numchn;\r
+\r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               UWORD packlen;\r
+\r
+               /* seek to pattern position */\r
+               if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */\r
+                       of.pattrows[t]=64;\r
+                       for(u=0;u<of.numchn;u++) {\r
+                               int k;\r
+\r
+                               UniReset();\r
+                               for(k=0;k<64;k++) UniNewline();\r
+                               of.tracks[numtrk++]=UniDup();\r
+                       }\r
+               } else {\r
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);\r
+                       packlen=_mm_read_I_UWORD(modreader);\r
+                       of.pattrows[t]=_mm_read_I_UWORD(modreader);\r
+                       _mm_read_I_ULONG(modreader);\r
+                       if(!IT_ReadPattern(of.pattrows[t])) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *IT_LoadTitle(void)\r
+{\r
+       CHAR s[26];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,26,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,26,0));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_it={\r
+       NULL,\r
+       "IT",\r
+       "IT (Impulse Tracker)",\r
+       IT_Init,\r
+       IT_Test,\r
+       IT_Load,\r
+       IT_Cleanup,\r
+       IT_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_m15.c b/apps/plugins/mikmod/loaders/load_m15.c
new file mode 100644 (file)
index 0000000..6adae0e
--- /dev/null
@@ -0,0 +1,505 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_m15.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  15 instrument MOD loader\r
+  Also supports Ultimate Sound Tracker (old M15 format)\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+//#include <ctype.h>\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module Structure */\r
+\r
+typedef struct MSAMPINFO {\r
+       CHAR  samplename[23];   /* 22 in module, 23 in memory */\r
+       UWORD length;\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       UWORD reppos;\r
+       UWORD replen;\r
+} MSAMPINFO;\r
+\r
+typedef struct MODULEHEADER {\r
+       CHAR      songname[21];         /* the songname.., 20 in module, 21 in memory */\r
+       MSAMPINFO samples[15];          /* all sampleinfo */\r
+       UBYTE     songlength;           /* number of patterns used */\r
+       UBYTE     magic1;               /* should be 127 */\r
+       UBYTE     positions[128];       /* which pattern to play at pos */\r
+} MODULEHEADER;\r
+\r
+typedef struct MODNOTE {\r
+       UBYTE a,b,c,d;\r
+} MODNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static MODULEHEADER *mh = NULL;\r
+static MODNOTE *patbuf = NULL;\r
+static BOOL ust_loader = 0;            /* if TRUE, load as an ust module. */\r
+\r
+/* known file formats which can confuse the loader */\r
+#define REJECT 2\r
+static char *signatures[REJECT]={\r
+       "CAKEWALK",     /* cakewalk midi files */\r
+       "SZDD"          /* Microsoft compressed files */\r
+};\r
+static int siglen[REJECT]={8,4};\r
+\r
+/*========== Loader code */\r
+\r
+static BOOL LoadModuleHeader(MODULEHEADER *mh)\r
+{\r
+       int t,u;\r
+\r
+       _mm_read_string(mh->songname,20,modreader);\r
+       mh->songname[20]=0;     /* just in case */\r
+\r
+       /* sanity check : title should contain printable characters and a bunch\r
+          of null chars */\r
+       for(t=0;t<20;t++)\r
+               if((mh->songname[t])&&(mh->songname[t]<32)) return 0;\r
+       for(t=0;(mh->songname[t])&&(t<20);t++);\r
+       if(t<20) for(;t<20;t++) if(mh->songname[t]) return 0;\r
+\r
+       for(t=0;t<15;t++) {\r
+               MSAMPINFO *s=&mh->samples[t];\r
+\r
+               _mm_read_string(s->samplename,22,modreader);\r
+               s->samplename[22]=0;    /* just in case */\r
+               s->length   =_mm_read_M_UWORD(modreader);\r
+               s->finetune =_mm_read_UBYTE(modreader);\r
+               s->volume   =_mm_read_UBYTE(modreader);\r
+               s->reppos   =_mm_read_M_UWORD(modreader);\r
+               s->replen   =_mm_read_M_UWORD(modreader);\r
+\r
+               /* sanity check : sample title should contain printable characters and\r
+                  a bunch of null chars */\r
+               for(u=0;u<20;u++)\r
+                       if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0;\r
+               for(u=0;(s->samplename[u])&&(u<20);u++);\r
+               if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0;\r
+\r
+               /* sanity check : finetune values */\r
+               if(s->finetune>>4) return 0;\r
+       }\r
+\r
+       mh->songlength  =_mm_read_UBYTE(modreader);\r
+       mh->magic1      =_mm_read_UBYTE(modreader);     /* should be 127 */\r
+\r
+       /* sanity check : no more than 128 positions, restart position in range */\r
+       if((!mh->songlength)||(mh->songlength>128)) return 0;\r
+       /* values encountered so far are 0x6a and 0x78 */\r
+       if(((mh->magic1&0xf8)!=0x78)&&(mh->magic1!=0x6a)&&(mh->magic1>mh->songlength)) return 0;\r
+\r
+       _mm_read_UBYTES(mh->positions,128,modreader);\r
+\r
+       /* sanity check : pattern range is 0..63 */\r
+       for(t=0;t<128;t++)\r
+               if(mh->positions[t]>63) return 0;\r
+\r
+       return(!_mm_eof(modreader));\r
+}\r
+\r
+/* Checks the patterns in the modfile for UST / 15-inst indications.\r
+   For example, if an effect 3xx is found, it is assumed that the song \r
+   is 15-inst.  If a 1xx effect has dat greater than 0x20, it is UST.   \r
+\r
+   Returns:  0 indecisive; 1 = UST; 2 = 15-inst                               */\r
+static int CheckPatternType(int numpat)\r
+{\r
+       int t;\r
+       UBYTE eff, dat;\r
+\r
+       for(t=0;t<numpat*(64U*4);t++) {\r
+               /* Load the pattern into the temp buffer and scan it */\r
+               _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);\r
+               eff = _mm_read_UBYTE(modreader);\r
+               dat = _mm_read_UBYTE(modreader);\r
+\r
+               switch(eff) {\r
+                       case 1:\r
+                               if(dat>0x1f) return 1;\r
+                               if(dat<0x3)  return 2;\r
+                               break;\r
+                       case 2:\r
+                               if(dat>0x1f) return 1;\r
+                               return 2;\r
+                       case 3:\r
+                               if (dat) return 2;\r
+                               break;\r
+                       default:\r
+                               return 2;\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+static BOOL M15_Test(void)\r
+{\r
+       int t, numpat;\r
+       MODULEHEADER mh;\r
+\r
+       ust_loader = 0;\r
+       if(!LoadModuleHeader(&mh)) return 0;\r
+\r
+       /* reject other file types */\r
+       for(t=0;t<REJECT;t++)\r
+               if(!memcmp(mh.songname,signatures[t],siglen[t])) return 0;\r
+\r
+       if(mh.magic1>127) return 0;\r
+       if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0;\r
+\r
+       for(t=0;t<15;t++) {\r
+               /* all finetunes should be zero */\r
+               if(mh.samples[t].finetune) return 0;\r
+\r
+               /* all volumes should be <= 64 */\r
+               if(mh.samples[t].volume>64) return 0;\r
+\r
+               /* all instrument names should begin with s, st-, or a number */\r
+               if((mh.samples[t].samplename[0]=='s')||\r
+                  (mh.samples[t].samplename[0]=='S')) {\r
+                       if((memcmp(mh.samples[t].samplename,"st-",3)) &&\r
+                          (memcmp(mh.samples[t].samplename,"ST-",3)) &&\r
+                          (*mh.samples[t].samplename))\r
+                               ust_loader = 1;\r
+               } else\r
+                 if(!isdigit((int)mh.samples[t].samplename[0]))\r
+                               ust_loader = 1;\r
+\r
+               if(mh.samples[t].length>4999||mh.samples[t].reppos>9999) {\r
+                       ust_loader = 0;\r
+                       if(mh.samples[t].length>32768) return 0;\r
+               }\r
+\r
+               /* if loop information is incorrect as words, but correct as bytes,\r
+                  this is likely to be an ust-style module */\r
+               if((mh.samples[t].reppos+mh.samples[t].replen>mh.samples[t].length)&&\r
+                  (mh.samples[t].reppos+mh.samples[t].replen<(mh.samples[t].length<<1))){\r
+                       ust_loader = 1;\r
+                       return 1;\r
+               }\r
+\r
+               if(!ust_loader) return 1; \r
+       }\r
+\r
+       for(numpat=0,t=0;t<mh.songlength;t++) \r
+               if(mh.positions[t]>numpat)\r
+                       numpat = mh.positions[t];\r
+       numpat++;\r
+       switch(CheckPatternType(numpat)) {\r
+               case 0:   /* indecisive, so check more clues... */\r
+                       break;\r
+               case 1:\r
+                       ust_loader = 1;\r
+                       break;\r
+               case 2:\r
+                       ust_loader = 0;\r
+                       break;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL M15_Init(void)\r
+{\r
+       if(!(mh=(MODULEHEADER*)_mm_malloc(sizeof(MODULEHEADER)))) return 0;\r
+       return 1;\r
+}\r
+\r
+static void M15_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(patbuf);\r
+}\r
+\r
+/*\r
+Old (amiga) noteinfo:\r
+\r
+ _____byte 1_____   byte2_    _____byte 3_____   byte4_\r
+/                \ /      \  /                \ /      \\r
+0000          0000-00000000  0000          0000-00000000\r
+\r
+Upper four    12 bits for    Lower four    Effect command.\r
+bits of sam-  note period.   bits of sam-\r
+ple number.                  ple number.\r
+*/\r
+\r
+static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect)\r
+{\r
+       UBYTE instrument,effect,effdat,note;\r
+       UWORD period;\r
+       UBYTE lastnote=0;\r
+\r
+       /* decode the 4 bytes that make up a single note */\r
+       instrument = n->c>>4;\r
+       period     = (((UWORD)n->a&0xf)<<8)+n->b;\r
+       effect     = n->c&0xf;\r
+       effdat     = n->d;\r
+\r
+       /* Convert the period to a note number */\r
+       note=0;\r
+       if(period) {\r
+               for(note=0;note<7*OCTAVE;note++)\r
+                       if(period>=npertab[note]) break;\r
+               if(note==7*OCTAVE) note=0;\r
+               else note++;\r
+       }\r
+\r
+       if(instrument) {\r
+               /* if instrument does not exist, note cut */\r
+               if((instrument>15)||(!mh->samples[instrument-1].length)) {\r
+                       UniPTEffect(0xc,0);\r
+                       if(effect==0xc) effect=effdat=0;\r
+               } else {\r
+                       /* if we had a note, then change instrument... */\r
+                       if(note)\r
+                               UniInstrument(instrument-1);\r
+                       /* ...otherwise, only adjust volume... */\r
+                       else {\r
+                               /* ...unless an effect was specified, which forces a new note\r
+                                  to be played */\r
+                               if(effect||effdat) {\r
+                                       UniInstrument(instrument-1);\r
+                                       note=lastnote;\r
+                               } else\r
+                                       UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f);\r
+                       }\r
+               }\r
+       }\r
+       if(note) {\r
+               UniNote(note+2*OCTAVE-1);\r
+               lastnote=note;\r
+       }\r
+\r
+       /* Convert pattern jump from Dec to Hex */\r
+       if(effect == 0xd)\r
+               effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);\r
+\r
+       /* Volume slide, up has priority */\r
+       if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0))\r
+               effdat&=0xf0;\r
+\r
+       /* Handle ``heavy'' volumes correctly */\r
+       if ((effect == 0xc) && (effdat > 0x40))\r
+               effdat = 0x40;\r
+\r
+       if(ust_loader) {\r
+               switch(effect) {\r
+                       case 0:\r
+                       case 3:\r
+                               break;\r
+                       case 1:\r
+                               UniPTEffect(0,effdat);\r
+                               break;\r
+                       case 2:  \r
+                               if(effdat&0xf) UniPTEffect(1,effdat&0xf);\r
+                               else if(effdat>>2)  UniPTEffect(2,effdat>>2);\r
+                               break;\r
+                       default:\r
+                               UniPTEffect(effect,effdat);\r
+                               break;\r
+               }\r
+       } else {\r
+               /* An isolated 100, 200 or 300 effect should be ignored (no\r
+                  "standalone" porta memory in mod files). However, a sequence\r
+                  such as 1XX, 100, 100, 100 is fine. */\r
+               if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&\r
+                       (lasteffect < 0x10) && (effect != lasteffect))\r
+                       effect = 0;\r
+\r
+               UniPTEffect(effect,effdat);\r
+       }\r
+       if (effect == 8)\r
+               of.flags |= UF_PANNING;\r
+       \r
+       return effect;\r
+}\r
+\r
+static UBYTE *M15_ConvertTrack(MODNOTE* n)\r
+{\r
+       int t;\r
+       UBYTE lasteffect = 0x10;        /* non existant effect */\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               lasteffect = M15_ConvertNote(n,lasteffect);\r
+               UniNewline();\r
+               n+=4;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */\r
+static BOOL M15_LoadPatterns(void)\r
+{\r
+       int t,s,tracks=0;\r
+\r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       /* Allocate temporary buffer for loading and converting the patterns */\r
+       if(!(patbuf=(MODNOTE*)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               /* Load the pattern into the temp buffer and convert it */\r
+               for(s=0;s<(64U*4);s++) {\r
+                       patbuf[s].a=_mm_read_UBYTE(modreader);\r
+                       patbuf[s].b=_mm_read_UBYTE(modreader);\r
+                       patbuf[s].c=_mm_read_UBYTE(modreader);\r
+                       patbuf[s].d=_mm_read_UBYTE(modreader);\r
+               }\r
+\r
+               for(s=0;s<4;s++)\r
+                       if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL M15_Load(BOOL curious)\r
+{\r
+       int t,scan;\r
+       SAMPLE *q;\r
+       MSAMPINFO *s;\r
+\r
+       /* try to read module header */\r
+       if(!LoadModuleHeader(mh)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       if(ust_loader)\r
+               of.modtype = strdup("Ultimate Soundtracker");\r
+       else\r
+               of.modtype = strdup("Soundtracker");\r
+\r
+       /* set module variables */\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       of.numchn    = 4;                               \r
+       of.songname  = DupStr(mh->songname,21,1);\r
+       of.numpos    = mh->songlength;\r
+       of.reppos    = 0;\r
+\r
+       /* Count the number of patterns */\r
+       of.numpat = 0;\r
+       for(t=0;t<of.numpos;t++)\r
+               if(mh->positions[t]>of.numpat)\r
+                       of.numpat=mh->positions[t];\r
+       /* since some old modules embed extra patterns, we have to check the\r
+          whole list to get the samples' file offsets right - however we can find\r
+          garbage here, so check carefully */\r
+       scan=1;\r
+       for(t=of.numpos;t<128;t++)\r
+               if(mh->positions[t]>=0x80) scan=0;\r
+       if (scan)\r
+               for(t=of.numpos;t<128;t++) {\r
+                       if(mh->positions[t]>of.numpat)\r
+                               of.numpat=mh->positions[t];\r
+                       if((curious)&&(mh->positions[t])) of.numpos=t+1;\r
+               }\r
+       of.numpat++;\r
+       of.numtrk = of.numpat*of.numchn;\r
+\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=0;t<of.numpos;t++)\r
+               of.positions[t]=mh->positions[t];\r
+\r
+       /* Finally, init the sampleinfo structures */\r
+       of.numins=of.numsmp=15;\r
+       if(!AllocSamples()) return 0;\r
+\r
+       s = mh->samples;\r
+       q = of.samples;\r
+\r
+       for(t=0;t<of.numins;t++) {\r
+               /* convert the samplename */\r
+               q->samplename = DupStr(s->samplename,23,1);\r
+\r
+               /* init the sampleinfo variables and convert the size pointers */\r
+               q->speed     = finetune[s->finetune&0xf];\r
+               q->volume    = s->volume;\r
+               if(ust_loader)\r
+                       q->loopstart = s->reppos;\r
+               else\r
+                       q->loopstart = s->reppos<<1;\r
+               q->loopend   = q->loopstart+(s->replen<<1);\r
+               q->length    = s->length<<1;\r
+\r
+               q->flags = SF_SIGNED;\r
+               if(ust_loader) q->flags |= SF_UST_LOOP;\r
+               if(s->replen>2) q->flags |= SF_LOOP;\r
+\r
+               s++;\r
+               q++;\r
+       }\r
+\r
+       if(!M15_LoadPatterns()) return 0;\r
+       ust_loader = 0;\r
+\r
+       return 1;\r
+}\r
+\r
+static CHAR *M15_LoadTitle(void)\r
+{\r
+       CHAR s[21];\r
+\r
+       _mm_fseek(modreader,0,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
+       s[20]=0;        /* just in case */\r
+       return(DupStr(s,21,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_m15={\r
+       NULL,\r
+       "15-instrument module",\r
+       "MOD (15 instrument)",\r
+       M15_Init,\r
+       M15_Test,\r
+       M15_Load,\r
+       M15_Cleanup,\r
+       M15_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_med.c b/apps/plugins/mikmod/loaders/load_med.c
new file mode 100644 (file)
index 0000000..3078dd2
--- /dev/null
@@ -0,0 +1,719 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_med.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Amiga MED module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module information */\r
+\r
+typedef struct MEDHEADER {\r
+       ULONG id;\r
+       ULONG modlen;\r
+       ULONG MEDSONGP;                         /* struct MEDSONG *song; */\r
+       UWORD psecnum;                          /* for the player routine, MMD2 only */\r
+       UWORD pseq;                                     /*  "   "   "   " */\r
+       ULONG MEDBlockPP;                       /* struct MEDBlock **blockarr; */\r
+       ULONG reserved1;\r
+       ULONG MEDINSTHEADERPP;          /* struct MEDINSTHEADER **smplarr; */\r
+       ULONG reserved2;\r
+       ULONG MEDEXPP;                          /* struct MEDEXP *expdata; */\r
+       ULONG reserved3;\r
+       UWORD pstate;                           /* some data for the player routine */\r
+       UWORD pblock;\r
+       UWORD pline;\r
+       UWORD pseqnum;\r
+       SWORD actplayline;\r
+       UBYTE counter;\r
+       UBYTE extra_songs;                      /* number of songs - 1 */\r
+} MEDHEADER;\r
+\r
+typedef struct MEDSAMPLE {\r
+       UWORD rep, replen;                      /* offs: 0(s), 2(s) */\r
+       UBYTE midich;                           /* offs: 4(s) */\r
+       UBYTE midipreset;                       /* offs: 5(s) */\r
+       UBYTE svol;                                     /* offs: 6(s) */\r
+       SBYTE strans;                           /* offs: 7(s) */\r
+} MEDSAMPLE;\r
+\r
+typedef struct MEDSONG {\r
+       MEDSAMPLE sample[63];           /* 63 * 8 bytes = 504 bytes */\r
+       UWORD numblocks;                        /* offs: 504 */\r
+       UWORD songlen;                          /* offs: 506 */\r
+       UBYTE playseq[256];                     /* offs: 508 */\r
+       UWORD deftempo;                         /* offs: 764 */\r
+       SBYTE playtransp;                       /* offs: 766 */\r
+       UBYTE flags;                            /* offs: 767 */\r
+       UBYTE flags2;                           /* offs: 768 */\r
+       UBYTE tempo2;                           /* offs: 769 */\r
+       UBYTE trkvol[16];                       /* offs: 770 */\r
+       UBYTE mastervol;                        /* offs: 786 */\r
+       UBYTE numsamples;                       /* offs: 787 */\r
+} MEDSONG;\r
+\r
+typedef struct MEDEXP {\r
+       ULONG nextmod;                          /* pointer to next module */\r
+       ULONG exp_smp;                          /* pointer to MEDINSTEXT array */\r
+       UWORD s_ext_entries;\r
+       UWORD s_ext_entrsz;\r
+       ULONG annotxt;                          /* pointer to annotation text */\r
+       ULONG annolen;\r
+       ULONG iinfo;                            /* pointer to MEDINSTINFO array */\r
+       UWORD i_ext_entries;\r
+       UWORD i_ext_entrsz;\r
+       ULONG jumpmask;\r
+       ULONG rgbtable;\r
+       ULONG channelsplit;\r
+       ULONG n_info;\r
+       ULONG songname;                         /* pointer to songname */\r
+       ULONG songnamelen;\r
+       ULONG dumps;\r
+       ULONG reserved2[7];\r
+} MEDEXP;\r
+\r
+typedef struct MMD0NOTE {\r
+       UBYTE a, b, c;\r
+} MMD0NOTE;\r
+\r
+typedef struct MMD1NOTE {\r
+       UBYTE a, b, c, d;\r
+} MMD1NOTE;\r
+\r
+typedef struct MEDINSTHEADER {\r
+       ULONG length;\r
+       SWORD type;\r
+       /* Followed by actual data */\r
+} MEDINSTHEADER;\r
+\r
+typedef struct MEDINSTEXT {\r
+       UBYTE hold;\r
+       UBYTE decay;\r
+       UBYTE suppress_midi_off;\r
+       SBYTE finetune;\r
+} MEDINSTEXT;\r
+\r
+typedef struct MEDINSTINFO {\r
+       UBYTE name[40];\r
+} MEDINSTINFO;\r
+\r
+/*========== Loader variables */\r
+\r
+#define MMD0_string 0x4D4D4430\r
+#define MMD1_string 0x4D4D4431\r
+\r
+static MEDHEADER *mh = NULL;\r
+static MEDSONG *ms = NULL;\r
+static MEDEXP *me = NULL;\r
+static ULONG *ba = NULL;\r
+static MMD0NOTE *mmd0pat = NULL;\r
+static MMD1NOTE *mmd1pat = NULL;\r
+\r
+static BOOL decimalvolumes;\r
+static BOOL bpmtempos;\r
+\r
+#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]\r
+#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]\r
+\r
+static CHAR MED_Version[] = "OctaMED (MMDx)";\r
+\r
+/*========== Loader code */\r
+\r
+BOOL MED_Test(void)\r
+{\r
+       UBYTE id[4];\r
+\r
+       if (!_mm_read_UBYTES(id, 4, modreader))\r
+               return 0;\r
+       if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4)))\r
+               return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL MED_Init(void)\r
+{\r
+       if (!(me = (MEDEXP *)_mm_malloc(sizeof(MEDEXP))))\r
+               return 0;\r
+       if (!(mh = (MEDHEADER *)_mm_malloc(sizeof(MEDHEADER))))\r
+               return 0;\r
+       if (!(ms = (MEDSONG *)_mm_malloc(sizeof(MEDSONG))))\r
+               return 0;\r
+       return 1;\r
+}\r
+\r
+void MED_Cleanup(void)\r
+{\r
+       _mm_free(me);\r
+       _mm_free(mh);\r
+       _mm_free(ms);\r
+       _mm_free(ba);\r
+       _mm_free(mmd0pat);\r
+       _mm_free(mmd1pat);\r
+}\r
+\r
+static void EffectCvt(UBYTE eff, UBYTE dat)\r
+{\r
+       switch (eff) {\r
+               /* 0x0 0x1 0x2 0x3 0x4 PT effects */\r
+         case 0x5:                             /* PT vibrato with speed/depth nibbles swapped */\r
+               UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));\r
+               break;\r
+               /* 0x6 0x7 not used */\r
+         case 0x6:\r
+         case 0x7:\r
+               break;\r
+         case 0x8:                             /* midi hold/decay */\r
+               break;\r
+         case 0x9:\r
+               if (bpmtempos) {\r
+                       if (!dat)\r
+                               dat = of.initspeed;\r
+                       UniEffect(UNI_S3MEFFECTA, dat);\r
+               } else {\r
+                       if (dat <= 0x20) {\r
+                               if (!dat)\r
+                                       dat = of.initspeed;\r
+                               else\r
+                                       dat /= 4;\r
+                               UniPTEffect(0xf, dat);\r
+                       } else\r
+                               UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));\r
+               }\r
+               break;\r
+               /* 0xa 0xb PT effects */\r
+         case 0xc:\r
+               if (decimalvolumes)\r
+                       dat = (dat >> 4) * 10 + (dat & 0xf);\r
+               UniPTEffect(0xc, dat);\r
+               break;\r
+         case 0xd:                             /* same as PT volslide */\r
+               UniPTEffect(0xa, dat);\r
+               break;\r
+         case 0xe:                             /* synth jmp - midi */\r
+               break;\r
+         case 0xf:\r
+               switch (dat) {\r
+                 case 0:                               /* patternbreak */\r
+                       UniPTEffect(0xd, 0);\r
+                       break;\r
+                 case 0xf1:                    /* play note twice */\r
+                       UniWriteByte(UNI_MEDEFFECTF1);\r
+                       break;\r
+                 case 0xf2:                    /* delay note */\r
+                       UniWriteByte(UNI_MEDEFFECTF2);\r
+                       break;\r
+                 case 0xf3:                    /* play note three times */\r
+                       UniWriteByte(UNI_MEDEFFECTF3);\r
+                       break;\r
+                 case 0xfe:                    /* stop playing */\r
+                       UniPTEffect(0xb, of.numpat);\r
+                       break;\r
+                 case 0xff:                    /* note cut */\r
+                       UniPTEffect(0xc, 0);\r
+                       break;\r
+                 default:\r
+                       if (dat <= 10)\r
+                               UniPTEffect(0xf, dat);\r
+                       else if (dat <= 240) {\r
+                               if (bpmtempos)\r
+                                       UniPTEffect(0xf, (dat < 32) ? 32 : dat);\r
+                               else\r
+                                       UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);\r
+                       }\r
+               }\r
+               break;\r
+         default:                                      /* all normal PT effects are handled here */\r
+               UniPTEffect(eff, dat);\r
+               break;\r
+       }\r
+}\r
+\r
+static UBYTE *MED_Convert1(int count, int col)\r
+{\r
+       int t;\r
+       UBYTE inst, note, eff, dat;\r
+       MMD1NOTE *n;\r
+\r
+       UniReset();\r
+       for (t = 0; t < count; t++) {\r
+               n = &d1note(t, col);\r
+\r
+               note = n->a & 0x7f;\r
+               inst = n->b & 0x3f;\r
+               eff = n->c & 0xf;\r
+               dat = n->d;\r
+\r
+               if (inst)\r
+                       UniInstrument(inst - 1);\r
+               if (note)\r
+                       UniNote(note + 3 * OCTAVE - 1);\r
+               EffectCvt(eff, dat);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static UBYTE *MED_Convert0(int count, int col)\r
+{\r
+       int t;\r
+       UBYTE a, b, inst, note, eff, dat;\r
+       MMD0NOTE *n;\r
+\r
+       UniReset();\r
+       for (t = 0; t < count; t++) {\r
+               n = &d0note(t, col);\r
+               a = n->a;\r
+               b = n->b;\r
+\r
+               note = a & 0x3f;\r
+               a >>= 6;\r
+               a = ((a & 1) << 1) | (a >> 1);\r
+               inst = (b >> 4) | (a << 4);\r
+               eff = b & 0xf;\r
+               dat = n->c;\r
+\r
+               if (inst)\r
+                       UniInstrument(inst - 1);\r
+               if (note)\r
+                       UniNote(note + 3 * OCTAVE - 1);\r
+               EffectCvt(eff, dat);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL LoadMEDPatterns(void)\r
+{\r
+       int t, row, col;\r
+       UWORD numtracks, numlines, maxlines = 0, track = 0;\r
+       MMD0NOTE *mmdp;\r
+\r
+       /* first, scan patterns to see how many channels are used */\r
+       for (t = 0; t < of.numpat; t++) {\r
+               _mm_fseek(modreader, ba[t], SEEK_SET);\r
+               numtracks = _mm_read_UBYTE(modreader);\r
+               numlines = _mm_read_UBYTE(modreader);\r
+\r
+               if (numtracks > of.numchn)\r
+                       of.numchn = numtracks;\r
+               if (numlines > maxlines)\r
+                       maxlines = numlines;\r
+       }\r
+\r
+       of.numtrk = of.numpat * of.numchn;\r
+       if (!AllocTracks())\r
+               return 0;\r
+       if (!AllocPatterns())\r
+               return 0;\r
+\r
+       if (!\r
+               (mmd0pat =\r
+                (MMD0NOTE *)_mm_calloc(of.numchn * (maxlines + 1),\r
+                                                               sizeof(MMD0NOTE)))) return 0;\r
+\r
+       /* second read: read and convert patterns */\r
+       for (t = 0; t < of.numpat; t++) {\r
+               _mm_fseek(modreader, ba[t], SEEK_SET);\r
+               numtracks = _mm_read_UBYTE(modreader);\r
+               numlines = _mm_read_UBYTE(modreader);\r
+\r
+               of.pattrows[t] = ++numlines;\r
+               memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE));\r
+               for (row = numlines; row; row--) {\r
+                       for (col = numtracks; col; col--, mmdp++) {\r
+                               mmdp->a = _mm_read_UBYTE(modreader);\r
+                               mmdp->b = _mm_read_UBYTE(modreader);\r
+                               mmdp->c = _mm_read_UBYTE(modreader);\r
+                       }\r
+               }\r
+\r
+               for (col = 0; col < of.numchn; col++)\r
+                       of.tracks[track++] = MED_Convert0(numlines, col);\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL LoadMMD1Patterns(void)\r
+{\r
+       int t, row, col;\r
+       UWORD numtracks, numlines, maxlines = 0, track = 0;\r
+       MMD1NOTE *mmdp;\r
+\r
+       /* first, scan patterns to see how many channels are used */\r
+       for (t = 0; t < of.numpat; t++) {\r
+               _mm_fseek(modreader, ba[t], SEEK_SET);\r
+               numtracks = _mm_read_M_UWORD(modreader);\r
+               numlines = _mm_read_M_UWORD(modreader);\r
+               if (numtracks > of.numchn)\r
+                       of.numchn = numtracks;\r
+               if (numlines > maxlines)\r
+                       maxlines = numlines;\r
+       }\r
+\r
+       of.numtrk = of.numpat * of.numchn;\r
+       if (!AllocTracks())\r
+               return 0;\r
+       if (!AllocPatterns())\r
+               return 0;\r
+\r
+       if (!\r
+               (mmd1pat =\r
+                (MMD1NOTE *)_mm_calloc(of.numchn * (maxlines + 1),\r
+                                                               sizeof(MMD1NOTE)))) return 0;\r
+\r
+       /* second read: really read and convert patterns */\r
+       for (t = 0; t < of.numpat; t++) {\r
+               _mm_fseek(modreader, ba[t], SEEK_SET);\r
+               numtracks = _mm_read_M_UWORD(modreader);\r
+               numlines = _mm_read_M_UWORD(modreader);\r
+\r
+               _mm_fseek(modreader, sizeof(ULONG), SEEK_CUR);\r
+               of.pattrows[t] = ++numlines;\r
+               memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE));\r
+\r
+               for (row = numlines; row; row--) {\r
+                       for (col = numtracks; col; col--, mmdp++) {\r
+                               mmdp->a = _mm_read_UBYTE(modreader);\r
+                               mmdp->b = _mm_read_UBYTE(modreader);\r
+                               mmdp->c = _mm_read_UBYTE(modreader);\r
+                               mmdp->d = _mm_read_UBYTE(modreader);\r
+                       }\r
+               }\r
+\r
+               for (col = 0; col < of.numchn; col++)\r
+                       of.tracks[track++] = MED_Convert1(numlines, col);\r
+       }\r
+       return 1;\r
+}\r
+\r
+BOOL MED_Load(BOOL curious)\r
+{\r
+       int t;\r
+       ULONG sa[64];\r
+       MEDINSTHEADER s;\r
+       SAMPLE *q;\r
+       MEDSAMPLE *mss;\r
+\r
+       /* try to read module header */\r
+       mh->id = _mm_read_M_ULONG(modreader);\r
+       mh->modlen = _mm_read_M_ULONG(modreader);\r
+       mh->MEDSONGP = _mm_read_M_ULONG(modreader);\r
+       mh->psecnum = _mm_read_M_UWORD(modreader);\r
+       mh->pseq = _mm_read_M_UWORD(modreader);\r
+       mh->MEDBlockPP = _mm_read_M_ULONG(modreader);\r
+       mh->reserved1 = _mm_read_M_ULONG(modreader);\r
+       mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader);\r
+       mh->reserved2 = _mm_read_M_ULONG(modreader);\r
+       mh->MEDEXPP = _mm_read_M_ULONG(modreader);\r
+       mh->reserved3 = _mm_read_M_ULONG(modreader);\r
+       mh->pstate = _mm_read_M_UWORD(modreader);\r
+       mh->pblock = _mm_read_M_UWORD(modreader);\r
+       mh->pline = _mm_read_M_UWORD(modreader);\r
+       mh->pseqnum = _mm_read_M_UWORD(modreader);\r
+       mh->actplayline = _mm_read_M_SWORD(modreader);\r
+       mh->counter = _mm_read_UBYTE(modreader);\r
+       mh->extra_songs = _mm_read_UBYTE(modreader);\r
+\r
+       /* Seek to MEDSONG struct */\r
+       _mm_fseek(modreader, mh->MEDSONGP, SEEK_SET);\r
+\r
+       /* Load the MED Song Header */\r
+       mss = ms->sample;                       /* load the sample data first */\r
+       for (t = 63; t; t--, mss++) {\r
+               mss->rep = _mm_read_M_UWORD(modreader);\r
+               mss->replen = _mm_read_M_UWORD(modreader);\r
+               mss->midich = _mm_read_UBYTE(modreader);\r
+               mss->midipreset = _mm_read_UBYTE(modreader);\r
+               mss->svol = _mm_read_UBYTE(modreader);\r
+               mss->strans = _mm_read_SBYTE(modreader);\r
+       }\r
+\r
+       ms->numblocks = _mm_read_M_UWORD(modreader);\r
+       ms->songlen = _mm_read_M_UWORD(modreader);\r
+       _mm_read_UBYTES(ms->playseq, 256, modreader);\r
+       ms->deftempo = _mm_read_M_UWORD(modreader);\r
+       ms->playtransp = _mm_read_SBYTE(modreader);\r
+       ms->flags = _mm_read_UBYTE(modreader);\r
+       ms->flags2 = _mm_read_UBYTE(modreader);\r
+       ms->tempo2 = _mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(ms->trkvol, 16, modreader);\r
+       ms->mastervol = _mm_read_UBYTE(modreader);\r
+       ms->numsamples = _mm_read_UBYTE(modreader);\r
+\r
+       /* check for a bad header */\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* load extension structure */\r
+       if (mh->MEDEXPP) {\r
+               _mm_fseek(modreader, mh->MEDEXPP, SEEK_SET);\r
+               me->nextmod = _mm_read_M_ULONG(modreader);\r
+               me->exp_smp = _mm_read_M_ULONG(modreader);\r
+               me->s_ext_entries = _mm_read_M_UWORD(modreader);\r
+               me->s_ext_entrsz = _mm_read_M_UWORD(modreader);\r
+               me->annotxt = _mm_read_M_ULONG(modreader);\r
+               me->annolen = _mm_read_M_ULONG(modreader);\r
+               me->iinfo = _mm_read_M_ULONG(modreader);\r
+               me->i_ext_entries = _mm_read_M_UWORD(modreader);\r
+               me->i_ext_entrsz = _mm_read_M_UWORD(modreader);\r
+               me->jumpmask = _mm_read_M_ULONG(modreader);\r
+               me->rgbtable = _mm_read_M_ULONG(modreader);\r
+               me->channelsplit = _mm_read_M_ULONG(modreader);\r
+               me->n_info = _mm_read_M_ULONG(modreader);\r
+               me->songname = _mm_read_M_ULONG(modreader);\r
+               me->songnamelen = _mm_read_M_ULONG(modreader);\r
+               me->dumps = _mm_read_M_ULONG(modreader);\r
+       }\r
+\r
+       /* seek to and read the samplepointer array */\r
+       _mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET);\r
+       if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* alloc and read the blockpointer array */\r
+       if (!(ba = (ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG))))\r
+               return 0;\r
+       _mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET);\r
+       if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* copy song positions */\r
+       if (!AllocPositions(ms->songlen))\r
+               return 0;\r
+       for (t = 0; t < ms->songlen; t++)\r
+               of.positions[t] = ms->playseq[t];\r
+\r
+       decimalvolumes = (ms->flags & 0x10) ? 0 : 1;\r
+       bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;\r
+\r
+       if (bpmtempos) {\r
+               int bpmlen = (ms->flags2 & 0x1f) + 1;\r
+               of.initspeed = ms->tempo2;\r
+               of.inittempo = ms->deftempo * bpmlen / 4;\r
+\r
+               if (bpmlen != 4) {\r
+                       /* Let's do some math : compute GCD of BPM beat length and speed */\r
+                       int a, b;\r
+\r
+                       a = bpmlen;\r
+                       b = ms->tempo2;\r
+\r
+                       if (a > b) {\r
+                               t = b;\r
+                               b = a;\r
+                               a = t;\r
+                       }\r
+                       while ((a != b) && (a)) {\r
+                               t = a;\r
+                               a = b - a;\r
+                               b = t;\r
+                               if (a > b) {\r
+                                       t = b;\r
+                                       b = a;\r
+                                       a = t;\r
+                               }\r
+                       }\r
+\r
+                       of.initspeed /= b;\r
+                       of.inittempo = ms->deftempo * bpmlen / (4 * b);\r
+               }\r
+       } else {\r
+               of.initspeed = ms->tempo2;\r
+               of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;\r
+               if ((ms->deftempo <= 10) && (ms->deftempo))\r
+                       of.inittempo = (of.inittempo * 33) / 6;\r
+               of.flags |= UF_HIGHBPM;\r
+       }\r
+       MED_Version[12] = mh->id;\r
+       of.modtype = strdup(MED_Version);\r
+       of.numchn = 0;                          /* will be counted later */\r
+       of.numpat = ms->numblocks;\r
+       of.numpos = ms->songlen;\r
+       of.numins = ms->numsamples;\r
+       of.numsmp = of.numins;\r
+       of.reppos = 0;\r
+       if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) {\r
+               char *name;\r
+\r
+               _mm_fseek(modreader, me->songname, SEEK_SET);\r
+               name = _mm_malloc(me->songnamelen);\r
+               _mm_read_UBYTES(name, me->songnamelen, modreader);\r
+               of.songname = DupStr(name, me->songnamelen, 1);\r
+               free(name);\r
+       } else\r
+               of.songname = DupStr(NULL, 0, 0);\r
+       if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) {\r
+               _mm_fseek(modreader, me->annotxt, SEEK_SET);\r
+               ReadComment(me->annolen);\r
+       }\r
+\r
+       if (!AllocSamples())\r
+               return 0;\r
+       q = of.samples;\r
+       for (t = 0; t < of.numins; t++) {\r
+               q->flags = SF_SIGNED;\r
+               q->volume = 64;\r
+               if (sa[t]) {\r
+                       _mm_fseek(modreader, sa[t], SEEK_SET);\r
+                       s.length = _mm_read_M_ULONG(modreader);\r
+                       s.type = _mm_read_M_SWORD(modreader);\r
+\r
+                       if (s.type) {\r
+#ifdef MIKMOD_DEBUG\r
+                               fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");\r
+#endif\r
+                               if (!curious) {\r
+                                       _mm_errno = MMERR_MED_SYNTHSAMPLES;\r
+                                       return 0;\r
+                               }\r
+                               s.length = 0;\r
+                       }\r
+\r
+                       if (_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                               return 0;\r
+                       }\r
+\r
+                       q->length = s.length;\r
+                       q->seekpos = _mm_ftell(modreader);\r
+                       q->loopstart = ms->sample[t].rep << 1;\r
+                       q->loopend = q->loopstart + (ms->sample[t].replen << 1);\r
+\r
+                       if (ms->sample[t].replen > 1)\r
+                               q->flags |= SF_LOOP;\r
+\r
+                       /* don't load sample if length>='MMD0'...\r
+                          such kluges make libmikmod's code unique !!! */\r
+                       if (q->length >= MMD0_string)\r
+                               q->length = 0;\r
+               } else\r
+                       q->length = 0;\r
+\r
+               if ((mh->MEDEXPP) && (me->exp_smp) &&\r
+                       (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) {\r
+                       MEDINSTEXT ie;\r
+\r
+                       _mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz,\r
+                                         SEEK_SET);\r
+                       ie.hold = _mm_read_UBYTE(modreader);\r
+                       ie.decay = _mm_read_UBYTE(modreader);\r
+                       ie.suppress_midi_off = _mm_read_UBYTE(modreader);\r
+                       ie.finetune = _mm_read_SBYTE(modreader);\r
+\r
+                       q->speed = finetune[ie.finetune & 0xf];\r
+               } else\r
+                       q->speed = 8363;\r
+\r
+               if ((mh->MEDEXPP) && (me->iinfo) &&\r
+                       (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) {\r
+                       MEDINSTINFO ii;\r
+\r
+                       _mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);\r
+                       _mm_read_UBYTES(ii.name, 40, modreader);\r
+                       q->samplename = DupStr((char*)ii.name, 40, 1);\r
+               } else\r
+                       q->samplename = NULL;\r
+\r
+               q++;\r
+       }\r
+\r
+       if (mh->id == MMD0_string) {\r
+               if (!LoadMEDPatterns()) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+       } else if (mh->id == MMD1_string) {\r
+               if (!LoadMMD1Patterns()) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+       } else {\r
+               _mm_errno = MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *MED_LoadTitle(void)\r
+{\r
+       ULONG posit, namelen;\r
+       CHAR *name, *retvalue = NULL;\r
+       \r
+       _mm_fseek(modreader, 0x20, SEEK_SET);\r
+       posit = _mm_read_M_ULONG(modreader);\r
+       \r
+       if (posit) {\r
+               _mm_fseek(modreader, posit + 0x2C, SEEK_SET);\r
+               posit = _mm_read_M_ULONG(modreader);\r
+               namelen = _mm_read_M_ULONG(modreader);\r
+\r
+               _mm_fseek(modreader, posit, SEEK_SET);\r
+               name = _mm_malloc(namelen);\r
+               _mm_read_UBYTES(name, namelen, modreader);\r
+               retvalue = DupStr(name, namelen, 1);\r
+               free(name);\r
+       }\r
+\r
+       return retvalue;\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_med = {\r
+       NULL,\r
+       "MED",\r
+       "MED (OctaMED)",\r
+       MED_Init,\r
+       MED_Test,\r
+       MED_Load,\r
+       MED_Cleanup,\r
+       MED_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_mod.c b/apps/plugins/mikmod/loaders/load_mod.c
new file mode 100644 (file)
index 0000000..5166234
--- /dev/null
@@ -0,0 +1,512 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_mod.c,v 1.2 2004/01/21 13:33:11 raph Exp $\r
+\r
+  Generic MOD loader (Protracker, StarTracker, FastTracker, etc)\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+//#include <ctype.h>\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct MSAMPINFO {\r
+       CHAR samplename[23];            /* 22 in module, 23 in memory */\r
+       UWORD length;\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       UWORD reppos;\r
+       UWORD replen;\r
+} MSAMPINFO;\r
+\r
+typedef struct MODULEHEADER {\r
+       CHAR songname[21];                      /* the songname.. 20 in module, 21 in memory */\r
+       MSAMPINFO samples[31];          /* all sampleinfo */\r
+       UBYTE songlength;                       /* number of patterns used */\r
+       UBYTE magic1;                           /* should be 127 */\r
+       UBYTE positions[128];           /* which pattern to play at pos */\r
+       UBYTE magic2[4];                        /* string "M.K." or "FLT4" or "FLT8" */\r
+} MODULEHEADER;\r
+\r
+typedef struct MODTYPE {\r
+       CHAR id[5];\r
+       UBYTE channels;\r
+       CHAR *name;\r
+} MODTYPE;\r
+\r
+typedef struct MODNOTE {\r
+       UBYTE a, b, c, d;\r
+} MODNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+#define MODULEHEADERSIZE 0x438\r
+\r
+static CHAR protracker[] = "Protracker";\r
+static CHAR startrekker[] = "Startrekker";\r
+static CHAR fasttracker[] = "Fasttracker";\r
+static CHAR oktalyser[] = "Oktalyser";\r
+static CHAR oktalyzer[] = "Oktalyzer";\r
+static CHAR taketracker[] = "TakeTracker";\r
+static CHAR orpheus[] = "Imago Orpheus (MOD format)";\r
+\r
+static MODULEHEADER *mh = NULL;\r
+static MODNOTE *patbuf = NULL;\r
+static int modtype, trekker;\r
+\r
+/*========== Loader code */\r
+\r
+/* given the module ID, determine the number of channels and the tracker\r
+   description ; also alters modtype */\r
+static BOOL MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)\r
+{\r
+       modtype = trekker = 0;\r
+\r
+       /* Protracker and variants */\r
+       if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {\r
+               *descr = protracker;\r
+               modtype = 0;\r
+               *numchn = 4;\r
+               return 1;\r
+       }\r
+       \r
+       /* Star Tracker */\r
+       if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&\r
+               (isdigit(id[3]))) {\r
+               *descr = startrekker;\r
+               modtype = trekker = 1;\r
+               *numchn = id[3] - '0';\r
+               if (*numchn == 4 || *numchn == 8)\r
+                       return 1;\r
+#ifdef MIKMOD_DEBUG\r
+               else\r
+                       fprintf(stderr, "\rUnknown FLT%d module type\n", *numchn);\r
+#endif\r
+               return 0;\r
+       }\r
+\r
+       /* Oktalyzer (Amiga) */\r
+       if (!memcmp(id, "OKTA", 4)) {\r
+               *descr = oktalyzer;\r
+               modtype = 1;\r
+               *numchn = 8;\r
+               return 1;\r
+       }\r
+\r
+       /* Oktalyser (Atari) */\r
+       if (!memcmp(id, "CD81", 4)) {\r
+               *descr = oktalyser;\r
+               modtype = 1;\r
+               *numchn = 8;\r
+               return 1;\r
+       }\r
+\r
+       /* Fasttracker */\r
+       if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {\r
+               *descr = fasttracker;\r
+               modtype = 1;\r
+               *numchn = id[0] - '0';\r
+               return 1;\r
+       }\r
+       /* Fasttracker or Taketracker */\r
+       if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))\r
+               && (isdigit(id[0])) && (isdigit(id[1]))) {\r
+               if (id[3] == 'H') {\r
+                       *descr = fasttracker;\r
+                       modtype = 2;            /* this can also be Imago Orpheus */\r
+               } else {\r
+                       *descr = taketracker;\r
+                       modtype = 1;\r
+               }\r
+               *numchn = (id[0] - '0') * 10 + (id[1] - '0');\r
+               return 1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static BOOL MOD_Test(void)\r
+{\r
+       UBYTE id[4], numchn;\r
+       CHAR *descr;\r
+\r
+       _mm_fseek(modreader, MODULEHEADERSIZE, SEEK_SET);\r
+       if (!_mm_read_UBYTES(id, 4, modreader))\r
+               return 0;\r
+\r
+       if (MOD_CheckType(id, &numchn, &descr))\r
+               return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+static BOOL MOD_Init(void)\r
+{\r
+       if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))\r
+               return 0;\r
+       return 1;\r
+}\r
+\r
+static void MOD_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(patbuf);\r
+}\r
+\r
+/*\r
+Old (amiga) noteinfo:\r
+\r
+_____byte 1_____   byte2_    _____byte 3_____   byte4_\r
+/                \ /      \  /                \ /      \\r
+0000          0000-00000000  0000          0000-00000000\r
+\r
+Upper four    12 bits for    Lower four    Effect command.\r
+bits of sam-  note period.   bits of sam-\r
+ple number.                  ple number.\r
+\r
+*/\r
+\r
+static UBYTE ConvertNote(MODNOTE *n, UBYTE lasteffect)\r
+{\r
+       UBYTE instrument, effect, effdat, note;\r
+       UWORD period;\r
+       UBYTE lastnote = 0;\r
+\r
+       /* extract the various information from the 4 bytes that make up a note */\r
+       instrument = (n->a & 0x10) | (n->c >> 4);\r
+       period = (((UWORD)n->a & 0xf) << 8) + n->b;\r
+       effect = n->c & 0xf;\r
+       effdat = n->d;\r
+\r
+       /* Convert the period to a note number */\r
+       note = 0;\r
+       if (period) {\r
+               for (note = 0; note < 7 * OCTAVE; note++)\r
+                       if (period >= npertab[note])\r
+                               break;\r
+               if (note == 7 * OCTAVE)\r
+                       note = 0;\r
+               else\r
+                       note++;\r
+       }\r
+\r
+       if (instrument) {\r
+               /* if instrument does not exist, note cut */\r
+               if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {\r
+                       UniPTEffect(0xc, 0);\r
+                       if (effect == 0xc)\r
+                               effect = effdat = 0;\r
+               } else {\r
+                       /* Protracker handling */\r
+                       if (!modtype) {\r
+                               /* if we had a note, then change instrument... */\r
+                               if (note)\r
+                                       UniInstrument(instrument - 1);\r
+                               /* ...otherwise, only adjust volume... */\r
+                               else {\r
+                                       /* ...unless an effect was specified, which forces a new\r
+                                          note to be played */\r
+                                       if (effect || effdat) {\r
+                                               UniInstrument(instrument - 1);\r
+                                               note = lastnote;\r
+                                       } else\r
+                                               UniPTEffect(0xc,\r
+                                                                       mh->samples[instrument -\r
+                                                                                               1].volume & 0x7f);\r
+                               }\r
+                       } else {\r
+                               /* Fasttracker handling */\r
+                               UniInstrument(instrument - 1);\r
+                               if (!note)\r
+                                       note = lastnote;\r
+                       }\r
+               }\r
+       }\r
+       if (note) {\r
+               UniNote(note + 2 * OCTAVE - 1);\r
+               lastnote = note;\r
+       }\r
+\r
+       /* Convert pattern jump from Dec to Hex */\r
+       if (effect == 0xd)\r
+               effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);\r
+\r
+       /* Volume slide, up has priority */\r
+       if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))\r
+               effdat &= 0xf0;\r
+\r
+       /* Handle ``heavy'' volumes correctly */\r
+       if ((effect == 0xc) && (effdat > 0x40))\r
+               effdat = 0x40;\r
+       \r
+       /* An isolated 100, 200 or 300 effect should be ignored (no\r
+          "standalone" porta memory in mod files). However, a sequence such\r
+          as 1XX, 100, 100, 100 is fine. */\r
+       if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&\r
+               (lasteffect < 0x10) && (effect != lasteffect))\r
+               effect = 0;\r
+\r
+       UniPTEffect(effect, effdat);\r
+       if (effect == 8)\r
+               of.flags |= UF_PANNING;\r
+       \r
+       return effect;\r
+}\r
+\r
+static UBYTE *ConvertTrack(MODNOTE *n, int numchn)\r
+{\r
+       int t;\r
+       UBYTE lasteffect = 0x10;        /* non existant effect */\r
+\r
+       UniReset();\r
+       for (t = 0; t < 64; t++) {\r
+               lasteffect = ConvertNote(n,lasteffect);\r
+               UniNewline();\r
+               n += numchn;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */\r
+static BOOL ML_LoadPatterns(void)\r
+{\r
+       int t, s, tracks = 0;\r
+\r
+       if (!AllocPatterns())\r
+               return 0;\r
+       if (!AllocTracks())\r
+               return 0;\r
+       \r
+       /* Allocate temporary buffer for loading and converting the patterns */\r
+       if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))\r
+               return 0;\r
+\r
+       if (trekker && of.numchn == 8) {\r
+               /* Startrekker module dual pattern */\r
+               for (t = 0; t < of.numpat; t++) {\r
+                       for (s = 0; s < (64U * 4); s++) {\r
+                               patbuf[s].a = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].b = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].c = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].d = _mm_read_UBYTE(modreader);\r
+                       }\r
+                       for (s = 0; s < 4; s++)\r
+                               if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))\r
+                                       return 0;\r
+                       for (s = 0; s < (64U * 4); s++) {\r
+                               patbuf[s].a = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].b = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].c = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].d = _mm_read_UBYTE(modreader);\r
+                       }\r
+                       for (s = 0; s < 4; s++)\r
+                               if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))\r
+                                       return 0;\r
+               }\r
+       } else {\r
+               /* Generic module pattern */\r
+               for (t = 0; t < of.numpat; t++) {\r
+                       /* Load the pattern into the temp buffer and convert it */\r
+                       for (s = 0; s < (64U * of.numchn); s++) {\r
+                               patbuf[s].a = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].b = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].c = _mm_read_UBYTE(modreader);\r
+                               patbuf[s].d = _mm_read_UBYTE(modreader);\r
+                       }\r
+                       for (s = 0; s < of.numchn; s++)\r
+                               if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, of.numchn)))\r
+                                       return 0;\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL MOD_Load(BOOL curious)\r
+{\r
+       int t, scan;\r
+       SAMPLE *q;\r
+       MSAMPINFO *s;\r
+       CHAR *descr;\r
+\r
+       /* try to read module header */\r
+       _mm_read_string((CHAR *)mh->songname, 20, modreader);\r
+       mh->songname[20] = 0;           /* just in case */\r
+\r
+       for (t = 0; t < 31; t++) {\r
+               s = &mh->samples[t];\r
+               _mm_read_string(s->samplename, 22, modreader);\r
+               s->samplename[22] = 0;  /* just in case */\r
+               s->length = _mm_read_M_UWORD(modreader);\r
+               s->finetune = _mm_read_UBYTE(modreader);\r
+               s->volume = _mm_read_UBYTE(modreader);\r
+               s->reppos = _mm_read_M_UWORD(modreader);\r
+               s->replen = _mm_read_M_UWORD(modreader);\r
+       }\r
+\r
+       mh->songlength = _mm_read_UBYTE(modreader);\r
+\r
+       /* this fixes mods which declare more than 128 positions. \r
+        * eg: beatwave.mod */\r
+       if (mh->songlength > 128) { mh->songlength = 128; }\r
+       \r
+       mh->magic1 = _mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->positions, 128, modreader);\r
+       _mm_read_UBYTES(mh->magic2, 4, modreader);\r
+\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       if (!(MOD_CheckType(mh->magic2, &of.numchn, &descr))) {\r
+               _mm_errno = MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       if (trekker && of.numchn == 8)\r
+               for (t = 0; t < 128; t++)\r
+                       /* if module pretends to be FLT8, yet the order table\r
+                          contains odd numbers, chances are it's a lying FLT4... */\r
+                       if (mh->positions[t] & 1) {\r
+                               of.numchn = 4;\r
+                               break;\r
+                       }\r
+       if (trekker && of.numchn == 8)\r
+               for (t = 0; t < 128; t++)\r
+                       mh->positions[t] >>= 1;\r
+\r
+       of.songname = DupStr(mh->songname, 21, 1);\r
+       of.numpos = mh->songlength;\r
+       of.reppos = 0;\r
+\r
+       /* Count the number of patterns */\r
+       of.numpat = 0;\r
+       for (t = 0; t < of.numpos; t++)\r
+               if (mh->positions[t] > of.numpat)\r
+                       of.numpat = mh->positions[t];\r
+\r
+       /* since some old modules embed extra patterns, we have to check the\r
+          whole list to get the samples' file offsets right - however we can find\r
+          garbage here, so check carefully */\r
+       scan = 1;\r
+       for (t = of.numpos; t < 128; t++)\r
+               if (mh->positions[t] >= 0x80)\r
+                       scan = 0;\r
+       if (scan)\r
+               for (t = of.numpos; t < 128; t++) {\r
+                       if (mh->positions[t] > of.numpat)\r
+                               of.numpat = mh->positions[t];\r
+                       if ((curious) && (mh->positions[t]))\r
+                               of.numpos = t + 1;\r
+               }\r
+       of.numpat++;\r
+       of.numtrk = of.numpat * of.numchn;\r
+\r
+       if (!AllocPositions(of.numpos))\r
+               return 0;\r
+       for (t = 0; t < of.numpos; t++)\r
+               of.positions[t] = mh->positions[t];\r
+\r
+       /* Finally, init the sampleinfo structures  */\r
+       of.numins = of.numsmp = 31;\r
+       if (!AllocSamples())\r
+               return 0;\r
+       s = mh->samples;\r
+       q = of.samples;\r
+       for (t = 0; t < of.numins; t++) {\r
+               /* convert the samplename */\r
+               q->samplename = DupStr(s->samplename, 23, 1);\r
+               /* init the sampleinfo variables and convert the size pointers */\r
+               q->speed = finetune[s->finetune & 0xf];\r
+               q->volume = s->volume & 0x7f;\r
+               q->loopstart = (ULONG)s->reppos << 1;\r
+               q->loopend = q->loopstart + ((ULONG)s->replen << 1);\r
+               q->length = (ULONG)s->length << 1;\r
+               q->flags = SF_SIGNED;\r
+               /* Imago Orpheus creates MODs with 16 bit samples, check */\r
+               if ((modtype == 2) && (s->volume & 0x80)) {\r
+                       q->flags |= SF_16BITS;\r
+                       descr = orpheus;\r
+               }\r
+               if (s->replen > 2)\r
+                       q->flags |= SF_LOOP;\r
+\r
+               s++;\r
+               q++;\r
+       }\r
+\r
+       of.modtype = strdup(descr);\r
+\r
+       if (!ML_LoadPatterns())\r
+               return 0;\r
+       \r
+       return 1;\r
+}\r
+\r
+static CHAR *MOD_LoadTitle(void)\r
+{\r
+       CHAR s[21];\r
+\r
+       _mm_fseek(modreader, 0, SEEK_SET);\r
+       if (!_mm_read_UBYTES(s, 20, modreader))\r
+               return NULL;\r
+       s[20] = 0;                                      /* just in case */\r
+\r
+       return (DupStr(s, 21, 1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_mod = {\r
+       NULL,\r
+       "Standard module",\r
+       "MOD (31 instruments)",\r
+       MOD_Init,\r
+       MOD_Test,\r
+       MOD_Load,\r
+       MOD_Cleanup,\r
+       MOD_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_mtm.c b/apps/plugins/mikmod/loaders/load_mtm.c
new file mode 100644 (file)
index 0000000..3da7b28
--- /dev/null
@@ -0,0 +1,286 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_mtm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  MTM module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct MTMHEADER {\r
+       UBYTE id[3];                    /* MTM file marker */\r
+       UBYTE version;                  /* upper major, lower nibble minor version number */\r
+       CHAR  songname[20];             /* ASCIIZ songname */\r
+       UWORD numtracks;                /* number of tracks saved */\r
+       UBYTE lastpattern;              /* last pattern number saved */\r
+       UBYTE lastorder;                /* last order number to play (songlength-1) */\r
+       UWORD commentsize;              /* length of comment field */\r
+       UBYTE numsamples;               /* number of samples saved  */\r
+       UBYTE attribute;                /* attribute byte (unused) */\r
+       UBYTE beatspertrack;\r
+       UBYTE numchannels;              /* number of channels used  */\r
+       UBYTE panpos[32];               /* voice pan positions */\r
+} MTMHEADER;\r
+\r
+typedef struct MTMSAMPLE {\r
+       CHAR  samplename[22];\r
+       ULONG length;\r
+       ULONG reppos;\r
+       ULONG repend;\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       UBYTE attribute;\r
+} MTMSAMPLE;\r
+\r
+typedef struct MTMNOTE {\r
+       UBYTE a,b,c;\r
+} MTMNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static MTMHEADER *mh = NULL;\r
+static MTMNOTE *mtmtrk = NULL;\r
+static UWORD pat[32];\r
+\r
+static CHAR MTM_Version[] = "MTM";\r
+\r
+/*========== Loader code */\r
+\r
+BOOL MTM_Test(void)\r
+{\r
+       UBYTE id[3];\r
+\r
+       if(!_mm_read_UBYTES(id,3,modreader)) return 0;\r
+       if(!memcmp(id,"MTM",3)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL MTM_Init(void)\r
+{\r
+       if(!(mtmtrk=(MTMNOTE*)_mm_calloc(64,sizeof(MTMNOTE)))) return 0;\r
+       if(!(mh=(MTMHEADER*)_mm_malloc(sizeof(MTMHEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void MTM_Cleanup(void)\r
+{\r
+       _mm_free(mtmtrk);\r
+       _mm_free(mh);\r
+}\r
+\r
+static UBYTE* MTM_Convert(void)\r
+{\r
+       int t;\r
+       UBYTE a,b,inst,note,eff,dat;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               a=mtmtrk[t].a;\r
+               b=mtmtrk[t].b;\r
+               inst=((a&0x3)<<4)|(b>>4);\r
+               note=a>>2;\r
+               eff=b&0xf;\r
+               dat=mtmtrk[t].c;\r
+\r
+               if(inst) UniInstrument(inst-1);\r
+               if(note) UniNote(note+2*OCTAVE);\r
+\r
+               /* MTM bug workaround : when the effect is volslide, slide-up *always*\r
+                  overrides slide-down. */\r
+               if(eff==0xa && (dat&0xf0)) dat&=0xf0;\r
+\r
+               /* Convert pattern jump from Dec to Hex */\r
+               if(eff==0xd)\r
+                       dat=(((dat&0xf0)>>4)*10)+(dat&0xf);\r
+               UniPTEffect(eff,dat);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL MTM_Load(BOOL curious)\r
+{\r
+       int t,u;\r
+       MTMSAMPLE s;\r
+       SAMPLE *q;\r
+       (void)curious;\r
+\r
+       /* try to read module header  */\r
+       _mm_read_UBYTES(mh->id,3,modreader);\r
+       mh->version     =_mm_read_UBYTE(modreader);\r
+       _mm_read_string(mh->songname,20,modreader);\r
+       mh->numtracks   =_mm_read_I_UWORD(modreader);\r
+       mh->lastpattern =_mm_read_UBYTE(modreader);\r
+       mh->lastorder   =_mm_read_UBYTE(modreader);\r
+       mh->commentsize =_mm_read_I_UWORD(modreader);\r
+       mh->numsamples  =_mm_read_UBYTE(modreader);\r
+       mh->attribute   =_mm_read_UBYTE(modreader);\r
+       mh->beatspertrack=_mm_read_UBYTE(modreader);\r
+       mh->numchannels =_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->panpos,32,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       of.modtype   = strdup(MTM_Version);\r
+       of.numchn    = mh->numchannels;\r
+       of.numtrk    = mh->numtracks+1;           /* get number of channels */\r
+       of.songname  = DupStr(mh->songname,20,1); /* make a cstr of songname */\r
+       of.numpos    = mh->lastorder+1;           /* copy the songlength */\r
+       of.numpat    = mh->lastpattern+1;\r
+       of.reppos    = 0;\r
+       of.flags    |= UF_PANNING;\r
+       for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4;\r
+       of.numins=of.numsmp=mh->numsamples;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       q=of.samples;\r
+       for(t=0;t<of.numins;t++) {\r
+               /* try to read sample info */\r
+               _mm_read_string(s.samplename,22,modreader);\r
+               s.length    =_mm_read_I_ULONG(modreader);\r
+               s.reppos    =_mm_read_I_ULONG(modreader);\r
+               s.repend    =_mm_read_I_ULONG(modreader);\r
+               s.finetune  =_mm_read_UBYTE(modreader);\r
+               s.volume    =_mm_read_UBYTE(modreader);\r
+               s.attribute =_mm_read_UBYTE(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO; \r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.samplename,22,1);\r
+               q->seekpos   = 0;\r
+               q->speed     = finetune[s.finetune];\r
+               q->length    = s.length;\r
+               q->loopstart = s.reppos;\r
+               q->loopend   = s.repend;\r
+               q->volume    = s.volume;\r
+               if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;\r
+\r
+               if(s.attribute&1) {\r
+                       /* If the sample is 16-bits, convert the length and replen\r
+                          byte-values into sample-values */\r
+                       q->flags|=SF_16BITS;\r
+                       q->length>>=1;\r
+                       q->loopstart>>=1;\r
+                       q->loopend>>=1;\r
+               }\r
+               q++;\r
+       }\r
+\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=0;t<of.numpos;t++)\r
+               of.positions[t]=_mm_read_UBYTE(modreader);\r
+       for(;t<128;t++) _mm_read_UBYTE(modreader);\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       of.tracks[0]=MTM_Convert();             /* track 0 is empty */\r
+       for(t=1;t<of.numtrk;t++) {\r
+               int s;\r
+\r
+               for(s=0;s<64;s++) {\r
+                       mtmtrk[s].a=_mm_read_UBYTE(modreader);\r
+                       mtmtrk[s].b=_mm_read_UBYTE(modreader);\r
+                       mtmtrk[s].c=_mm_read_UBYTE(modreader);\r
+               }\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_TRACK;\r
+                       return 0;\r
+               }\r
+\r
+               if(!(of.tracks[t]=MTM_Convert())) return 0;\r
+       }\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               _mm_read_I_UWORDS(pat,32,modreader);\r
+               for(u=0;u<of.numchn;u++)\r
+                       of.patterns[((long)t*of.numchn)+u]=pat[u];\r
+       }\r
+\r
+       /* read comment field */\r
+       if(mh->commentsize)\r
+               if(!ReadLinedComment(mh->commentsize, 40)) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *MTM_LoadTitle(void)\r
+{\r
+       CHAR s[20];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
+\r
+       return(DupStr(s,20,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_mtm={\r
+       NULL,\r
+       "MTM",\r
+       "MTM (MultiTracker Module editor)",\r
+       MTM_Init,\r
+       MTM_Test,\r
+       MTM_Load,\r
+       MTM_Cleanup,\r
+       MTM_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_okt.c b/apps/plugins/mikmod/loaders/load_okt.c
new file mode 100644 (file)
index 0000000..e99837d
--- /dev/null
@@ -0,0 +1,461 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
+\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_okt.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Oktalyzer (OKT) module loader\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+       Written by UFO <ufo303@poczta.onet.pl>\r
+       based on the file description compiled by Harald Zappe\r
+                                                             <zappe@gaea.sietec.de>\r
+\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module blocks */\r
+\r
+/* sample information */\r
+typedef struct OKTSAMPLE {\r
+       CHAR sampname[20];\r
+       ULONG len;\r
+       UWORD loopbeg;\r
+       UWORD looplen;\r
+       UBYTE volume;\r
+} OKTSAMPLE;\r
+\r
+typedef struct OKTNOTE {\r
+       UBYTE note, ins, eff, dat;\r
+} OKTNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static OKTNOTE *okttrk = NULL;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL OKT_Test(void)\r
+{\r
+       CHAR id[8];\r
+\r
+       if (!_mm_read_UBYTES(id, 8, modreader))\r
+               return 0;\r
+       if (!memcmp(id, "OKTASONG", 8))\r
+               return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+/*     Pattern analysis routine.\r
+       Effects not implemented (yet) : (in decimal)\r
+       11 Arpeggio 4: Change note every 50Hz tick between N,H,N,L\r
+       12 Arpeggio 5: Change note every 50Hz tick between H,H,N\r
+                   N = normal note being played in this channel (1-36)\r
+                   L = normal note number minus upper four bits of 'data'.\r
+                   H = normal note number plus  lower four bits of 'data'.\r
+    13 Decrease note number by 'data' once per tick.\r
+    17 Increase note number by 'data' once per tick.\r
+    21 Decrease note number by 'data' once per line.\r
+    30 Increase note number by 'data' once per line.\r
+*/\r
+static UBYTE *OKT_ConvertTrack(UBYTE patrows)\r
+{\r
+       int t;\r
+       UBYTE ins, note, eff, dat;\r
+\r
+       UniReset();\r
+       for (t = 0; t < patrows; t++) {\r
+               note = okttrk[t].note;\r
+               ins = okttrk[t].ins;\r
+               eff = okttrk[t].eff;\r
+               dat = okttrk[t].dat;\r
+\r
+               if (note) {\r
+                       UniNote(note + 3 * OCTAVE - 1);\r
+                       UniInstrument(ins);\r
+               }\r
+\r
+               if (eff)\r
+                       switch (eff) {\r
+                       case 1:                         /* Porta Up */\r
+                               UniPTEffect(0x1, dat);\r
+                               break;\r
+                       case 2:                         /* Portamento Down */\r
+                               UniPTEffect(0x2, dat);\r
+                               break;\r
+                       /* case 9: what is this? */\r
+                       case 10:                        /* Arpeggio 3 */\r
+                       case 11:                        /* Arpeggio 4 */\r
+                       case 12:                        /* Arpeggio 5 */\r
+                               UniWriteByte(UNI_OKTARP);\r
+                               UniWriteByte(eff + 3 - 10);\r
+                               UniWriteByte(dat);\r
+                               break;\r
+                       case 15:                        /* Amiga filter toggle, ignored */\r
+                               break;\r
+                       case 25:                        /* Pattern Jump */\r
+                               dat = (dat >> 4) * 10 + (dat & 0x0f);\r
+                               UniPTEffect(0xb, dat);\r
+                               break;\r
+                       case 27:                        /* Release - similar to Keyoff */\r
+                               UniWriteByte(UNI_KEYOFF);\r
+                               break;\r
+                       case 28:                        /* Set Tempo */\r
+                               UniPTEffect(0xf, dat & 0x0f);\r
+                               break;\r
+                       case 31:                        /* volume Control */\r
+                               if (dat <= 0x40)\r
+                                       UniPTEffect(0xc, dat);\r
+                               else if (dat <= 0x50)\r
+                                       UniEffect(UNI_XMEFFECTA, (dat - 0x40)); /* fast fade out */\r
+                               else if (dat <= 0x60)\r
+                                       UniEffect(UNI_XMEFFECTA, (dat - 0x50) << 4);    /* fast fade in */\r
+                               else if (dat <= 0x70)\r
+                                       UniEffect(UNI_XMEFFECTEB, (dat - 0x60));        /* slow fade out */\r
+                               else if (dat <= 0x80)\r
+                                       UniEffect(UNI_XMEFFECTEA, (dat - 0x70));        /* slow fade in */\r
+                               break;\r
+#ifdef MIKMOD_DEBUG\r
+                       default:\r
+                               fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n",\r
+                                               eff, dat);\r
+#endif\r
+                       }\r
+\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+/* Read "channel modes" i.e. channel number and panning information */\r
+static void OKT_doCMOD(void)\r
+{\r
+       /* amiga channel panning table */\r
+       UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 };\r
+       int t;\r
+\r
+       of.numchn = 0;\r
+       of.flags |= UF_PANNING;\r
+\r
+       for (t = 0; t < 4; t++)\r
+               if (_mm_read_M_UWORD(modreader)) {\r
+                       /* two channels tied to the same Amiga hardware voice */\r
+                       of.panning[of.numchn++] = amigapan[t];\r
+                       of.panning[of.numchn++] = amigapan[t];\r
+               } else\r
+                       /* one channel tied to the Amiga hardware voice */\r
+                       of.panning[of.numchn++] = amigapan[t];\r
+}\r
+\r
+/* Read sample information */\r
+static BOOL OKT_doSAMP(int len)\r
+{\r
+       int t;\r
+       SAMPLE *q;\r
+       OKTSAMPLE s;\r
+\r
+       of.numins = of.numsmp = (len / 0x20);\r
+       if (!AllocSamples())\r
+               return 0;\r
+\r
+       for (t = 0, q = of.samples; t < of.numins; t++, q++) {\r
+               _mm_read_UBYTES(s.sampname, 20, modreader);\r
+               s.len = _mm_read_M_ULONG(modreader);\r
+               s.loopbeg = _mm_read_M_UWORD(modreader) * 2;\r
+               s.looplen = _mm_read_M_UWORD(modreader) * 2;\r
+               _mm_read_UBYTE(modreader);\r
+               s.volume = _mm_read_UBYTE(modreader);\r
+               _mm_read_M_UWORD(modreader);\r
+\r
+               if (_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               if (!s.len)\r
+                       q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0;\r
+               else {\r
+                       s.len--;\r
+                       /* sanity checks */\r
+                       if (s.loopbeg > s.len)\r
+                               s.loopbeg = s.len;\r
+                       if (s.loopbeg + s.looplen > s.len)\r
+                               s.looplen = s.len - s.loopbeg;\r
+                       if (s.looplen < 2)\r
+                               s.looplen = 0;\r
+\r
+                       q->length = s.len;\r
+                       q->loopstart = s.loopbeg;\r
+                       q->loopend = s.looplen + q->loopstart;\r
+                       q->volume = s.volume;\r
+                       q->flags = SF_SIGNED;\r
+\r
+                       if (s.looplen)\r
+                               q->flags |= SF_LOOP;\r
+               }\r
+               q->samplename = DupStr(s.sampname, 20, 1);\r
+               q->speed = 8287;\r
+       }\r
+       return 1;\r
+}\r
+\r
+/* Read speed information */\r
+static void OKT_doSPEE(void)\r
+{\r
+       int tempo = _mm_read_M_UWORD(modreader);\r
+\r
+       of.initspeed = tempo;\r
+}\r
+\r
+/* Read song length information */\r
+static void OKT_doSLEN(void)\r
+{\r
+       of.numpat = _mm_read_M_UWORD(modreader);\r
+}\r
+\r
+/* Read pattern length information */\r
+static void OKT_doPLEN(void)\r
+{\r
+       of.numpos = _mm_read_M_UWORD(modreader);\r
+}\r
+\r
+/* Read order table */\r
+static BOOL OKT_doPATT(void)\r
+{\r
+       int t;\r
+\r
+       if (!of.numpos || !AllocPositions(of.numpos))\r
+               return 0;\r
+\r
+       for (t = 0; t < 128; t++)\r
+               if (t < of.numpos)\r
+                       of.positions[t] = _mm_read_UBYTE(modreader);\r
+               else\r
+                       break;\r
+\r
+       return 1;\r
+}\r
+\r
+static BOOL OKT_doPBOD(int patnum)\r
+{\r
+       char *patbuf;\r
+       int rows, i;\r
+       int u;\r
+\r
+       if (!patnum) {\r
+               of.numtrk = of.numpat * of.numchn;\r
+\r
+               if (!AllocTracks() || !AllocPatterns())\r
+                       return 0;\r
+       }\r
+\r
+       /* Read pattern */\r
+       of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader);\r
+\r
+       if (!(okttrk = (OKTNOTE *) _mm_calloc(rows, sizeof(OKTNOTE))) ||\r
+           !(patbuf = (char *)_mm_calloc(rows * of.numchn, sizeof(OKTNOTE))))\r
+               return 0;\r
+       _mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader);\r
+       if (_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_PATTERN;\r
+               return 0;\r
+       }\r
+\r
+       for (i = 0; i < of.numchn; i++) {\r
+               for (u = 0; u < rows; u++) {\r
+                       okttrk[u].note = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE)];\r
+                       okttrk[u].ins = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 1];\r
+                       okttrk[u].eff = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 2];\r
+                       okttrk[u].dat = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 3];\r
+               }\r
+\r
+               if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows)))\r
+                       return 0;\r
+       }\r
+       _mm_free(patbuf);\r
+       _mm_free(okttrk);\r
+       return 1;\r
+}\r
+\r
+static void OKT_doSBOD(int insnum)\r
+{\r
+       of.samples[insnum].seekpos = _mm_ftell(modreader);\r
+}\r
+\r
+BOOL OKT_Load(BOOL curious)\r
+{\r
+       UBYTE id[4];\r
+       ULONG len;\r
+       ULONG fp;\r
+       BOOL seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt\r
+                       = 0, seen_spee = 0;\r
+       int patnum = 0, insnum = 0;\r
+       (void)curious;\r
+\r
+       /* skip OKTALYZER header */\r
+       _mm_fseek(modreader, 8, SEEK_SET);\r
+       of.songname = strdup("");\r
+\r
+       of.modtype = strdup("Amiga Oktalyzer");\r
+       of.numpos = of.reppos = 0;\r
+       \r
+       /* default values */\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+\r
+       while (1) {\r
+               /* read block header */\r
+               _mm_read_UBYTES(id, 4, modreader);\r
+               len = _mm_read_M_ULONG(modreader);\r
+               \r
+               if (_mm_eof(modreader))\r
+                       break;\r
+               fp = _mm_ftell(modreader);\r
+               \r
+               if (!memcmp(id, "CMOD", 4)) {\r
+                       /*if (!seen_cmod) {\r
+                               OKT_doCMOD();  // gcc for ipod stucks here, saying it is a call to memcpy...\r
+                               seen_cmod = 1;\r
+                       } else {*/\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       /* } */\r
+               } else if (!memcmp(id, "SAMP", 4)) {\r
+                       if (!seen_samp && OKT_doSAMP(len))\r
+                               seen_samp = 1;\r
+                       else {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id, "SPEE", 4)) {\r
+                       if (!seen_spee) {\r
+                               OKT_doSPEE();\r
+                               seen_spee = 1;\r
+                       } else {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id, "SLEN", 4)) {\r
+                       if (!seen_slen) {\r
+                               OKT_doSLEN();\r
+                               seen_slen = 1;\r
+                       } else {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id, "PLEN", 4)) {\r
+                       if (!seen_plen) {\r
+                               OKT_doPLEN();\r
+                               seen_plen = 1;\r
+                       } else {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id, "PATT", 4)) {\r
+                       if (!seen_plen) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+                       if (!seen_patt && OKT_doPATT())\r
+                               seen_patt = 1;\r
+                       else {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id,"PBOD", 4)) {\r
+                       /* need to know numpat and numchn */\r
+                       if (!seen_slen || !seen_cmod || (patnum >= of.numpat)) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+                       if (!OKT_doPBOD(patnum++)) {\r
+                               _mm_errno = MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+               } else if (!memcmp(id,"SBOD",4)) {\r
+                       /* need to know numsmp */\r
+                       if (!seen_samp) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+                       while ((insnum < of.numins) && !of.samples[insnum].length)\r
+                               insnum++;\r
+                       if (insnum >= of.numins) {\r
+                               _mm_errno = MMERR_LOADING_HEADER;\r
+                               return 0;\r
+                       }\r
+                       OKT_doSBOD(insnum++);\r
+               }\r
+\r
+               /* goto next block start position */\r
+               _mm_fseek(modreader, fp + len, SEEK_SET);\r
+       }\r
+\r
+       if (!seen_cmod || !seen_samp || !seen_patt ||\r
+               !seen_slen || !seen_plen || (patnum != of.numpat)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *OKT_LoadTitle(void)\r
+{\r
+       return strdup("");\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_okt = {\r
+       NULL,\r
+       "OKT",\r
+       "OKT (Amiga Oktalyzer)",\r
+       NULL,\r
+       OKT_Test,\r
+       OKT_Load,\r
+       NULL,\r
+       OKT_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_s3m.c b/apps/plugins/mikmod/loaders/load_s3m.c
new file mode 100644 (file)
index 0000000..11f691b
--- /dev/null
@@ -0,0 +1,470 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_s3m.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Screamtracker (S3M) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct S3MHEADER {\r
+       CHAR  songname[28];\r
+       UBYTE t1a;\r
+       UBYTE type;\r
+       UBYTE unused1[2];\r
+       UWORD ordnum;\r
+       UWORD insnum;\r
+       UWORD patnum;\r
+       UWORD flags;\r
+       UWORD tracker;\r
+       UWORD fileformat;\r
+       CHAR  scrm[4];\r
+       UBYTE mastervol;\r
+       UBYTE initspeed;\r
+       UBYTE inittempo;\r
+       UBYTE mastermult;\r
+       UBYTE ultraclick;\r
+       UBYTE pantable;\r
+       UBYTE unused2[8];\r
+       UWORD special;\r
+       UBYTE channels[32];\r
+} S3MHEADER;\r
+\r
+/* sample information */\r
+typedef struct S3MSAMPLE {\r
+       UBYTE type;\r
+       CHAR  filename[12];\r
+       UBYTE memsegh;\r
+       UWORD memsegl;\r
+       ULONG length;\r
+       ULONG loopbeg;\r
+       ULONG loopend;\r
+       UBYTE volume;\r
+       UBYTE dsk;\r
+       UBYTE pack;\r
+       UBYTE flags;\r
+       ULONG c2spd;\r
+       UBYTE unused[12];\r
+       CHAR  sampname[28];\r
+       CHAR  scrs[4];\r
+} S3MSAMPLE;\r
+\r
+typedef struct S3MNOTE {\r
+       UBYTE note,ins,vol,cmd,inf;\r
+} S3MNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static S3MNOTE   *s3mbuf  = NULL; /* pointer to a complete S3M pattern */\r
+static S3MHEADER *mh      = NULL;\r
+static UWORD     *paraptr = NULL; /* parapointer array (see S3M docs) */\r
+static unsigned int tracker;   /* tracker id */\r
+\r
+/* tracker identifiers */\r
+#define NUMTRACKERS 4\r
+static CHAR* S3M_Version[] = {\r
+       "Screamtracker x.xx",\r
+       "Imago Orpheus x.xx (S3M format)",\r
+       "Impulse Tracker x.xx (S3M format)",\r
+       "Unknown tracker x.xx (S3M format)",\r
+       "Impulse Tracker 2.14p3 (S3M format)",\r
+       "Impulse Tracker 2.14p4 (S3M format)"\r
+};\r
+/* version number position in above array */\r
+static int numeric[NUMTRACKERS]={14,14,16,16};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL S3M_Test(void)\r
+{\r
+       UBYTE id[4];\r
+\r
+       _mm_fseek(modreader,0x2c,SEEK_SET);\r
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
+       if(!memcmp(id,"SCRM",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL S3M_Init(void)\r
+{\r
+       if(!(s3mbuf=(S3MNOTE*)_mm_malloc(32*64*sizeof(S3MNOTE)))) return 0;\r
+       if(!(mh=(S3MHEADER*)_mm_malloc(sizeof(S3MHEADER)))) return 0;\r
+       if(!(poslookup=(UBYTE*)_mm_malloc(sizeof(UBYTE)*256))) return 0;\r
+       memset(poslookup,-1,256);\r
+\r
+       return 1;\r
+}\r
+\r
+void S3M_Cleanup(void)\r
+{\r
+       _mm_free(s3mbuf);\r
+       _mm_free(paraptr);\r
+       _mm_free(poslookup);\r
+       _mm_free(mh);\r
+       _mm_free(origpositions);\r
+}\r
+\r
+/* Because so many s3m files have 16 channels as the set number used, but really\r
+   only use far less (usually 8 to 12 still), I had to make this function, which\r
+   determines the number of channels that are actually USED by a pattern.\r
+\r
+   For every channel that's used, it sets the appropriate array entry of the\r
+   global variable 'remap'\r
+\r
+   NOTE: You must first seek to the file location of the pattern before calling\r
+         this procedure.\r
+\r
+   Returns 1 on fail.                                                         */\r
+static BOOL S3M_GetNumChannels(void)\r
+{\r
+       int row=0,flag,ch;\r
+\r
+       while(row<64) {\r
+               flag=_mm_read_UBYTE(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 1;\r
+               }\r
+\r
+               if(flag) {\r
+                       ch=flag&31;\r
+                       if(mh->channels[ch]<32) remap[ch] = 0;\r
+                       if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}\r
+                       if(flag&64) _mm_read_UBYTE(modreader);\r
+                       if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}\r
+               } else row++;\r
+       }\r
+       return 0;\r
+}    \r
+\r
+static BOOL S3M_ReadPattern(void)\r
+{\r
+       int row=0,flag,ch;\r
+       S3MNOTE *n,dummy;\r
+\r
+       /* clear pattern data */\r
+       memset(s3mbuf,255,32*64*sizeof(S3MNOTE));\r
+\r
+       while(row<64) {\r
+               flag=_mm_read_UBYTE(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               if(flag) {\r
+                       ch=remap[flag&31];\r
+\r
+                       if(ch!=-1)\r
+                               n=&s3mbuf[(64U*ch)+row];\r
+                       else\r
+                               n=&dummy;\r
+\r
+                       if(flag&32) {\r
+                               n->note=_mm_read_UBYTE(modreader);\r
+                               n->ins=_mm_read_UBYTE(modreader);\r
+                       }\r
+                       if(flag&64) {\r
+                               n->vol=_mm_read_UBYTE(modreader);\r
+                               if (n->vol>64) n->vol=64;\r
+                       }\r
+                       if(flag&128) {\r
+                               n->cmd=_mm_read_UBYTE(modreader);\r
+                               n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+               } else row++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static UBYTE* S3M_ConvertTrack(S3MNOTE* tr)\r
+{\r
+       int t;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               UBYTE note,ins,vol;\r
+\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+               vol=tr[t].vol;\r
+\r
+               if((ins)&&(ins!=255)) UniInstrument(ins-1);\r
+               if(note!=255) {\r
+                       if(note==254) {\r
+                               UniPTEffect(0xc,0);     /* note cut command */\r
+                               vol=255;\r
+                       } else\r
+                               UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */\r
+               }\r
+               if(vol<255) UniPTEffect(0xc,vol);\r
+\r
+               S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,\r
+                       tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE);\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL S3M_Load(BOOL curious)\r
+{\r
+       int t,u,track = 0;\r
+       SAMPLE *q;\r
+       UBYTE pan[32];\r
+\r
+       /* try to read module header */\r
+       _mm_read_string(mh->songname,28,modreader);\r
+       mh->t1a         =_mm_read_UBYTE(modreader);\r
+       mh->type        =_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->unused1,2,modreader);\r
+       mh->ordnum      =_mm_read_I_UWORD(modreader);\r
+       mh->insnum      =_mm_read_I_UWORD(modreader);\r
+       mh->patnum      =_mm_read_I_UWORD(modreader);\r
+       mh->flags       =_mm_read_I_UWORD(modreader);\r
+       mh->tracker     =_mm_read_I_UWORD(modreader);\r
+       mh->fileformat  =_mm_read_I_UWORD(modreader);\r
+       _mm_read_string(mh->scrm,4,modreader);\r
+       mh->mastervol   =_mm_read_UBYTE(modreader);\r
+       mh->initspeed   =_mm_read_UBYTE(modreader);\r
+       mh->inittempo   =_mm_read_UBYTE(modreader);\r
+       mh->mastermult  =_mm_read_UBYTE(modreader);\r
+       mh->ultraclick  =_mm_read_UBYTE(modreader);\r
+       mh->pantable    =_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->unused2,8,modreader);\r
+       mh->special     =_mm_read_I_UWORD(modreader);\r
+       _mm_read_UBYTES(mh->channels,32,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* then we can decide the module type */\r
+       tracker=mh->tracker>>12;\r
+       if((!tracker)||(tracker>=NUMTRACKERS))\r
+               tracker=NUMTRACKERS-1; /* unknown tracker */\r
+       else {\r
+               if(mh->tracker>=0x3217)\r
+                       tracker=NUMTRACKERS+1; /* IT 2.14p4 */\r
+               else if(mh->tracker>=0x3216)\r
+                       tracker=NUMTRACKERS; /* IT 2.14p3 */\r
+               else tracker--;\r
+       }\r
+       of.modtype = strdup(S3M_Version[tracker]);\r
+       if(tracker<NUMTRACKERS) {\r
+               of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0';\r
+               of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0';\r
+               of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0';\r
+       }\r
+       /* set module variables */\r
+       of.songname    = DupStr(mh->songname,28,0);\r
+       of.numpat      = mh->patnum;\r
+       of.reppos      = 0;\r
+       of.numins      = of.numsmp = mh->insnum;\r
+       of.initspeed   = mh->initspeed;\r
+       of.inittempo   = mh->inittempo;\r
+       of.initvolume  = mh->mastervol<<1;\r
+       of.flags      |= UF_ARPMEM | UF_PANNING;\r
+       if((mh->tracker==0x1300)||(mh->flags&64))\r
+               of.flags|=UF_S3MSLIDES;\r
+       of.bpmlimit    = 32;\r
+\r
+       /* read the order data */\r
+       if(!AllocPositions(mh->ordnum)) return 0;\r
+       if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0;\r
+\r
+       for(t=0;t<mh->ordnum;t++) {\r
+               origpositions[t]=_mm_read_UBYTE(modreader);\r
+               if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254))\r
+                       origpositions[t]=255/*mh->patnum-1*/;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       poslookupcnt=mh->ordnum;\r
+       S3MIT_CreateOrders(curious);\r
+\r
+       if(!(paraptr=(UWORD*)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD))))\r
+               return 0;\r
+\r
+       /* read the instrument+pattern parapointers */\r
+       _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader);\r
+\r
+       if(mh->pantable==252) {\r
+               /* read the panning table (ST 3.2 addition.  See below for further\r
+                  portions of channel panning [past reampper]). */\r
+               _mm_read_UBYTES(pan,32,modreader);\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* load samples */\r
+       if(!AllocSamples()) return 0;\r
+       q = of.samples;\r
+       for(t=0;t<of.numins;t++) {\r
+               S3MSAMPLE s;\r
+\r
+               /* seek to instrument position */\r
+               _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);\r
+               /* and load sample info */\r
+               s.type      =_mm_read_UBYTE(modreader);\r
+               _mm_read_string(s.filename,12,modreader);\r
+               s.memsegh   =_mm_read_UBYTE(modreader);\r
+               s.memsegl   =_mm_read_I_UWORD(modreader);\r
+               s.length    =_mm_read_I_ULONG(modreader);\r
+               s.loopbeg   =_mm_read_I_ULONG(modreader);\r
+               s.loopend   =_mm_read_I_ULONG(modreader);\r
+               s.volume    =_mm_read_UBYTE(modreader);\r
+               s.dsk       =_mm_read_UBYTE(modreader);\r
+               s.pack      =_mm_read_UBYTE(modreader);\r
+               s.flags     =_mm_read_UBYTE(modreader);\r
+               s.c2spd     =_mm_read_I_ULONG(modreader);\r
+               _mm_read_UBYTES(s.unused,12,modreader);\r
+               _mm_read_string(s.sampname,28,modreader);\r
+               _mm_read_string(s.scrs,4,modreader);\r
+\r
+               /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */\r
+               if (s.length > 64000)\r
+                       s.length = 64000;\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.sampname,28,0);\r
+               q->speed      = s.c2spd;\r
+               q->length     = s.length;\r
+               q->loopstart  = s.loopbeg;\r
+               q->loopend    = s.loopend;\r
+               q->volume     = s.volume;\r
+               q->seekpos    = (((long)s.memsegh)<<16|s.memsegl)<<4;\r
+\r
+               if(s.flags&1) q->flags |= SF_LOOP;\r
+               if(s.flags&4) q->flags |= SF_16BITS;\r
+               if(mh->fileformat==1) q->flags |= SF_SIGNED;\r
+\r
+               /* don't load sample if it doesn't have the SCRS tag */\r
+               if(memcmp(s.scrs,"SCRS",4)) q->length = 0;\r
+\r
+               q++;\r
+       }\r
+\r
+       /* determine the number of channels actually used. */\r
+       of.numchn = 0;\r
+       memset(remap,-1,32*sizeof(UBYTE));\r
+       for(t=0;t<of.numpat;t++) {\r
+               /* seek to pattern position (+2 skip pattern length) */\r
+               _mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET);\r
+               if(S3M_GetNumChannels()) return 0;\r
+       }\r
+\r
+       /* build the remap array  */\r
+       for(t=0;t<32;t++)\r
+               if(!remap[t]) \r
+                       remap[t]=of.numchn++;\r
+\r
+       /* set panning positions after building remap chart! */\r
+       for(t=0;t<32;t++) \r
+               if((mh->channels[t]<32)&&(remap[t]!=-1)) {\r
+                       if(mh->channels[t]<8)\r
+                               of.panning[remap[t]]=0x30;\r
+                       else\r
+                               of.panning[remap[t]]=0xc0;\r
+               }\r
+       if(mh->pantable==252)\r
+               /* set panning positions according to panning table (new for st3.2) */\r
+               for(t=0;t<32;t++)\r
+                       if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1))\r
+                               of.panning[remap[t]]=(pan[t]&0xf)<<4;\r
+\r
+       /* load pattern info */\r
+       of.numtrk=of.numpat*of.numchn;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               /* seek to pattern position (+2 skip pattern length) */\r
+               _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);\r
+               if(!S3M_ReadPattern()) return 0;\r
+               for(u=0;u<of.numchn;u++)\r
+                       if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *S3M_LoadTitle(void)\r
+{\r
+       CHAR s[28];\r
+\r
+       _mm_fseek(modreader,0,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,28,modreader)) return NULL;\r
+\r
+       return(DupStr(s,28,0));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_s3m={\r
+       NULL,\r
+       "S3M",\r
+       "S3M (Scream Tracker 3)",\r
+       S3M_Init,\r
+       S3M_Test,\r
+       S3M_Load,\r
+       S3M_Cleanup,\r
+       S3M_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_stm.c b/apps/plugins/mikmod/loaders/load_stm.c
new file mode 100644 (file)
index 0000000..6a60af0
--- /dev/null
@@ -0,0 +1,375 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_stm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Screamtracker 2 (STM) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* sample information */\r
+typedef struct STMSAMPLE {\r
+       CHAR  filename[12];\r
+       UBYTE unused;       /* 0x00 */\r
+       UBYTE instdisk;     /* Instrument disk */\r
+       UWORD reserved;\r
+       UWORD length;       /* Sample length */\r
+       UWORD loopbeg;      /* Loop start point */\r
+       UWORD loopend;      /* Loop end point */\r
+       UBYTE volume;       /* Volume */\r
+       UBYTE reserved2;\r
+       UWORD c2spd;        /* Good old c2spd */\r
+       ULONG reserved3;\r
+       UWORD isa;\r
+} STMSAMPLE;\r
+\r
+/* header */\r
+typedef struct STMHEADER {\r
+       CHAR  songname[20];\r
+       CHAR  trackername[8]; /* !Scream! for ST 2.xx  */\r
+       UBYTE unused;         /* 0x1A  */\r
+       UBYTE filetype;       /* 1=song, 2=module */\r
+       UBYTE ver_major;\r
+       UBYTE ver_minor;\r
+       UBYTE inittempo;      /* initspeed= stm inittempo>>4  */\r
+       UBYTE numpat;         /* number of patterns  */\r
+       UBYTE globalvol;     \r
+       UBYTE reserved[13];\r
+       STMSAMPLE sample[31]; /* STM sample data */\r
+       UBYTE patorder[128];  /* Docs say 64 - actually 128 */\r
+} STMHEADER;\r
+\r
+typedef struct STMNOTE {\r
+       UBYTE note,insvol,volcmd,cmdinf;\r
+} STMNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static STMNOTE *stmbuf = NULL;\r
+static STMHEADER *mh = NULL;\r
+\r
+/* tracker identifiers */\r
+static CHAR* STM_Version[STM_NTRACKERS] = {\r
+       "Screamtracker 2",\r
+       "Converted by MOD2STM (STM format)",\r
+       "Wuzamod (STM format)"\r
+};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL STM_Test(void)\r
+{\r
+       UBYTE str[44];\r
+       int t;\r
+\r
+       _mm_fseek(modreader,20,SEEK_SET);\r
+       _mm_read_UBYTES(str,44,modreader);\r
+       if(str[9]!=2) return 0; /* STM Module = filetype 2 */\r
+\r
+       /* Prevent false positives for S3M files */\r
+       if(!memcmp(str+40,"SCRM",4))\r
+               return 0;\r
+       \r
+       for (t=0;t<STM_NTRACKERS;t++)\r
+               if(!memcmp(str,STM_Signatures[t],8))\r
+                       return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+BOOL STM_Init(void)\r
+{\r
+       if(!(mh=(STMHEADER*)_mm_malloc(sizeof(STMHEADER)))) return 0;\r
+       if(!(stmbuf=(STMNOTE*)_mm_calloc(64U*4,sizeof(STMNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+static void STM_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+       _mm_free(stmbuf);\r
+}\r
+\r
+static void STM_ConvertNote(STMNOTE *n)\r
+{\r
+       UBYTE note,ins,vol,cmd,inf;\r
+\r
+       /* extract the various information from the 4 bytes that make up a note */\r
+       note = n->note;\r
+       ins  = n->insvol>>3;\r
+       vol  = (n->insvol&7)+((n->volcmd&0x70)>>1);\r
+       cmd  = n->volcmd&15;\r
+       inf  = n->cmdinf;\r
+\r
+       if((ins)&&(ins<32)) UniInstrument(ins-1);\r
+\r
+       /* special values of [SBYTE0] are handled here \r
+          we have no idea if these strange values will ever be encountered.\r
+          but it appears as those stms sound correct. */\r
+       if((note==254)||(note==252)) {\r
+               UniPTEffect(0xc,0); /* note cut */\r
+               n->volcmd|=0x80;\r
+       } else\r
+               /* if note < 251, then all three bytes are stored in the file */\r
+         if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf));\r
+\r
+       if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol);\r
+       if(cmd!=255)\r
+               switch(cmd) {\r
+                       case 1: /* Axx set speed to xx */\r
+                               UniPTEffect(0xf,inf>>4);\r
+                               break;\r
+                       case 2: /* Bxx position jump */\r
+                               UniPTEffect(0xb,inf);\r
+                               break;\r
+                       case 3: /* Cxx patternbreak to row xx */\r
+                               UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));\r
+                               break;\r
+                       case 4: /* Dxy volumeslide */\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 5: /* Exy toneslide down */\r
+                               UniEffect(UNI_S3MEFFECTE,inf);\r
+                               break;\r
+                       case 6: /* Fxy toneslide up */\r
+                               UniEffect(UNI_S3MEFFECTF,inf);\r
+                               break;\r
+                       case 7: /* Gxx Tone portamento,speed xx */\r
+                               UniPTEffect(0x3,inf);\r
+                               break;\r
+                       case 8: /* Hxy vibrato */\r
+                               UniPTEffect(0x4,inf);\r
+                               break;\r
+                       case 9: /* Ixy tremor, ontime x, offtime y */\r
+                               UniEffect(UNI_S3MEFFECTI,inf);\r
+                       break;\r
+                       case 0:         /* protracker arpeggio */\r
+                               if(!inf) break;\r
+                               /* fall through */\r
+                       case 0xa:       /* Jxy arpeggio */\r
+                               UniPTEffect(0x0,inf);\r
+                               break;\r
+                       case 0xb:       /* Kxy Dual command H00 & Dxy */\r
+                               UniPTEffect(0x4,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xc:       /* Lxy Dual command G00 & Dxy */\r
+                               UniPTEffect(0x3,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       /* Support all these above, since ST2 can LOAD these values but can\r
+                          actually only play up to J - and J is only half-way implemented\r
+                          in ST2 */\r
+                       case 0x18:      /* Xxx amiga panning command 8xx */\r
+                               UniPTEffect(0x8,inf);\r
+                               of.flags |= UF_PANNING;\r
+                               break;\r
+               }\r
+}\r
+\r
+static UBYTE *STM_ConvertTrack(STMNOTE *n)\r
+{\r
+       int t;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               STM_ConvertNote(n);\r
+               UniNewline();\r
+               n+=of.numchn;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL STM_LoadPatterns(void)\r
+{\r
+       int t,s,tracks=0;\r
+\r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       /* Allocate temporary buffer for loading and converting the patterns */\r
+       for(t=0;t<of.numpat;t++) {\r
+               for(s=0;s<(64U*of.numchn);s++) {\r
+                       stmbuf[s].note   = _mm_read_UBYTE(modreader);\r
+                       stmbuf[s].insvol = _mm_read_UBYTE(modreader);\r
+                       stmbuf[s].volcmd = _mm_read_UBYTE(modreader);\r
+                       stmbuf[s].cmdinf = _mm_read_UBYTE(modreader);\r
+               }\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               for(s=0;s<of.numchn;s++)\r
+                       if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+BOOL STM_Load(BOOL curious)\r
+{\r
+       int t; \r
+       ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */\r
+       SAMPLE *q;\r
+       (void)curious;\r
+\r
+       /* try to read stm header */\r
+       _mm_read_string(mh->songname,20,modreader);\r
+       _mm_read_string(mh->trackername,8,modreader);\r
+       mh->unused      =_mm_read_UBYTE(modreader);\r
+       mh->filetype    =_mm_read_UBYTE(modreader);\r
+       mh->ver_major   =_mm_read_UBYTE(modreader);\r
+       mh->ver_minor   =_mm_read_UBYTE(modreader);\r
+       mh->inittempo   =_mm_read_UBYTE(modreader);\r
+       if(!mh->inittempo) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       mh->numpat      =_mm_read_UBYTE(modreader);\r
+       mh->globalvol   =_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->reserved,13,modreader);\r
+\r
+       for(t=0;t<31;t++) {\r
+               STMSAMPLE *s=&mh->sample[t];    /* STM sample data */\r
+\r
+               _mm_read_string(s->filename,12,modreader);\r
+               s->unused   =_mm_read_UBYTE(modreader);\r
+               s->instdisk =_mm_read_UBYTE(modreader);\r
+               s->reserved =_mm_read_I_UWORD(modreader);\r
+               s->length   =_mm_read_I_UWORD(modreader);\r
+               s->loopbeg  =_mm_read_I_UWORD(modreader);\r
+               s->loopend  =_mm_read_I_UWORD(modreader);\r
+               s->volume   =_mm_read_UBYTE(modreader);\r
+               s->reserved2=_mm_read_UBYTE(modreader);\r
+               s->c2spd    =_mm_read_I_UWORD(modreader);\r
+               s->reserved3=_mm_read_I_ULONG(modreader);\r
+               s->isa      =_mm_read_I_UWORD(modreader);\r
+       }\r
+       _mm_read_UBYTES(mh->patorder,128,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       for(t=0;t<STM_NTRACKERS;t++)\r
+               if(!memcmp(mh->trackername,STM_Signatures[t],8)) break;\r
+       of.modtype   = strdup(STM_Version[t]);\r
+       of.songname  = DupStr(mh->songname,20,1); /* make a cstr of songname */\r
+       of.numpat    = mh->numpat;\r
+       of.inittempo = 125;                     /* mh->inittempo+0x1c; */\r
+       of.initspeed = mh->inittempo>>4;\r
+       of.numchn    = 4;                       /* get number of channels */\r
+       of.reppos    = 0;\r
+       of.flags    |= UF_S3MSLIDES;\r
+       of.bpmlimit  = 32;\r
+\r
+       t=0;\r
+       if(!AllocPositions(0x80)) return 0;\r
+       /* 99 terminates the patorder list */\r
+       while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) {\r
+               of.positions[t]=mh->patorder[t];\r
+               t++;\r
+       }\r
+       if(mh->patorder[t]<=99) t++;\r
+       of.numpos=t;\r
+       of.numtrk=of.numpat*of.numchn;\r
+       of.numins=of.numsmp=31;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       if(!STM_LoadPatterns()) return 0;\r
+       MikMod_ISA=_mm_ftell(modreader);\r
+       MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;  /* normalize */\r
+\r
+       for(q=of.samples,t=0;t<of.numsmp;t++,q++) {\r
+               /* load sample info */\r
+               q->samplename = DupStr(mh->sample[t].filename,12,1);\r
+               q->speed      = (mh->sample[t].c2spd * 8363) / 8448;\r
+               q->volume     = mh->sample[t].volume;\r
+               q->length     = mh->sample[t].length;\r
+               if (/*(!mh->sample[t].volume)||*/(q->length==1)) q->length=0;\r
+               q->loopstart  = mh->sample[t].loopbeg;\r
+               q->loopend    = mh->sample[t].loopend;\r
+               q->seekpos    = MikMod_ISA;\r
+\r
+               MikMod_ISA+=q->length;\r
+               MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;  /* normalize */\r
+\r
+               /* contrary to the STM specs, sample data is signed */\r
+               q->flags = SF_SIGNED;\r
+\r
+               if(q->loopend && q->loopend != 0xffff)\r
+                               q->flags|=SF_LOOP;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *STM_LoadTitle(void)\r
+{\r
+       CHAR s[20];\r
+\r
+       _mm_fseek(modreader,0,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
+\r
+       return(DupStr(s,20,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_stm={\r
+       NULL,\r
+       "STM",\r
+       "STM (Scream Tracker)",\r
+       STM_Init,\r
+       STM_Test,\r
+       STM_Load,\r
+       STM_Cleanup,\r
+       STM_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_stx.c b/apps/plugins/mikmod/loaders/load_stx.c
new file mode 100644 (file)
index 0000000..66e67f0
--- /dev/null
@@ -0,0 +1,439 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_stx.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  STMIK 0.2 (STX) module loader\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+       Written by Claudio Matsuoka <claudio@helllabs.org>\r
+\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct STXHEADER {\r
+       CHAR  songname[20];\r
+       CHAR  trackername[8];\r
+       UWORD patsize;\r
+       UWORD unknown1;\r
+       UWORD patptr;\r
+       UWORD insptr;\r
+       UWORD chnptr;   /* not sure */\r
+       UWORD unknown2;\r
+       UWORD unknown3;\r
+       UBYTE mastermult;\r
+       UBYTE initspeed;\r
+       UWORD unknown4;\r
+       UWORD unknown5;\r
+       UWORD patnum;\r
+       UWORD insnum;\r
+       UWORD ordnum;\r
+       UWORD unknown6;\r
+       UWORD unknown7;\r
+       UWORD unknown8;\r
+       CHAR  scrm[4];\r
+} STXHEADER;\r
+\r
+/* sample information */\r
+typedef struct STXSAMPLE {\r
+       UBYTE type;\r
+       CHAR  filename[12];\r
+       UBYTE memsegh;\r
+       UWORD memsegl;\r
+       ULONG length;\r
+       ULONG loopbeg;\r
+       ULONG loopend;\r
+       UBYTE volume;\r
+       UBYTE dsk;\r
+       UBYTE pack;\r
+       UBYTE flags;\r
+       ULONG c2spd;\r
+       UBYTE unused[12];\r
+       CHAR  sampname[28];\r
+       CHAR  scrs[4];\r
+} STXSAMPLE;\r
+\r
+typedef struct STXNOTE {\r
+       UBYTE note,ins,vol,cmd,inf;\r
+} STXNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static STXNOTE   *stxbuf  = NULL; /* pointer to a complete STX pattern */\r
+static STXHEADER *mh      = NULL;\r
+static UWORD     *paraptr = NULL; /* parapointer array (see STX docs) */\r
+\r
+/*========== Loader code */\r
+\r
+static BOOL STX_Test(void)\r
+{\r
+       UBYTE id[8];\r
+       int t;\r
+\r
+       _mm_fseek(modreader,0x3C,SEEK_SET);\r
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
+       if(memcmp(id,"SCRM",4)) return 0;\r
+\r
+       _mm_fseek(modreader,0x14,SEEK_SET);\r
+       if(!_mm_read_UBYTES(id,8,modreader)) return 0;\r
+       \r
+       for(t=0;t<STM_NTRACKERS;t++)\r
+               if(!memcmp(id,STM_Signatures[t],8)) return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+static BOOL STX_Init(void)\r
+{\r
+       if(!(stxbuf=(STXNOTE*)_mm_malloc(4*64*sizeof(STXNOTE)))) return 0;\r
+       if(!(mh=(STXHEADER*)_mm_malloc(sizeof(STXHEADER)))) return 0;\r
+       if(!(poslookup=(UBYTE*)_mm_malloc(sizeof(UBYTE)*256))) return 0;\r
+       memset(poslookup,-1,256);\r
+\r
+       return 1;\r
+}\r
+\r
+static void STX_Cleanup(void)\r
+{\r
+       _mm_free(stxbuf);\r
+       _mm_free(paraptr);\r
+       _mm_free(poslookup);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL STX_ReadPattern(void)\r
+{\r
+       int row=0,flag,ch;\r
+       STXNOTE *n,dummy;\r
+\r
+       /* clear pattern data */\r
+       memset(stxbuf,255,4*64*sizeof(STXNOTE));\r
+\r
+       while(row<64) {\r
+               flag=_mm_read_UBYTE(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               if(flag) {\r
+                       ch=flag&31;\r
+\r
+                       if((ch>=0)&&(ch<4))\r
+                               n=&stxbuf[(64U*ch)+row];\r
+                       else\r
+                               n=&dummy;\r
+\r
+                       if(flag&32) {\r
+                               n->note=_mm_read_UBYTE(modreader);\r
+                               n->ins=_mm_read_UBYTE(modreader);\r
+                       }\r
+                       if(flag&64) {\r
+                               n->vol=_mm_read_UBYTE(modreader);\r
+                               if(n->vol>64) n->vol=64;\r
+                       }\r
+                       if(flag&128) {\r
+                               n->cmd=_mm_read_UBYTE(modreader);\r
+                               n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+               } else row++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static UBYTE* STX_ConvertTrack(STXNOTE* tr)\r
+{\r
+       int t;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               UBYTE note,ins,vol,cmd,inf;\r
+\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+               vol=tr[t].vol;\r
+               cmd=tr[t].cmd;\r
+               inf=tr[t].inf;\r
+\r
+               if((ins)&&(ins!=255)) UniInstrument(ins-1);\r
+               if((note)&&(note!=255)) {\r
+                       if(note==254) {\r
+                               UniPTEffect(0xc,0);     /* note cut command */\r
+                               vol=255;\r
+                       } else UniNote(24+((note>>4)*OCTAVE)+(note&0xf)); /* normal note */\r
+               }\r
+\r
+               if(vol<255) UniPTEffect(0xc,vol);\r
+\r
+               if(cmd<255) switch(cmd) {\r
+                       case 1: /* Axx set speed to xx */\r
+                               UniPTEffect(0xf,inf>>4);\r
+                               break;\r
+                       case 2: /* Bxx position jump */\r
+                               UniPTEffect(0xb,inf);\r
+                               break;\r
+                       case 3: /* Cxx patternbreak to row xx */\r
+                               UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));\r
+                               break;\r
+                       case 4: /* Dxy volumeslide */\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 5: /* Exy toneslide down */\r
+                               UniEffect(UNI_S3MEFFECTE,inf);\r
+                               break;\r
+                       case 6: /* Fxy toneslide up */\r
+                               UniEffect(UNI_S3MEFFECTF,inf);\r
+                               break;\r
+                       case 7: /* Gxx Tone portamento,speed xx */\r
+                               UniPTEffect(0x3,inf);\r
+                               break;\r
+                       case 8: /* Hxy vibrato */\r
+                               UniPTEffect(0x4,inf);\r
+                               break;\r
+                       case 9: /* Ixy tremor, ontime x, offtime y */\r
+                               UniEffect(UNI_S3MEFFECTI,inf);\r
+                       break;\r
+                       case 0:         /* protracker arpeggio */\r
+                               if(!inf) break;\r
+                               /* fall through */\r
+                       case 0xa:       /* Jxy arpeggio */\r
+                               UniPTEffect(0x0,inf);\r
+                               break;\r
+                       case 0xb:       /* Kxy Dual command H00 & Dxy */\r
+                               UniPTEffect(0x4,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xc:       /* Lxy Dual command G00 & Dxy */\r
+                               UniPTEffect(0x3,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       /* Support all these above, since ST2 can LOAD these values but can\r
+                          actually only play up to J - and J is only half-way implemented\r
+                          in ST2 */\r
+                       case 0x18:      /* Xxx amiga panning command 8xx */\r
+                               UniPTEffect(0x8,inf);\r
+                               of.flags |= UF_PANNING;\r
+                               break;\r
+               }\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL STX_Load(BOOL curious)\r
+{\r
+       int t,u,track = 0;\r
+       int version = 0;\r
+       SAMPLE *q;\r
+\r
+       /* try to read module header */\r
+       _mm_read_string(mh->songname,20,modreader);\r
+       _mm_read_string(mh->trackername,8,modreader);\r
+       mh->patsize     =_mm_read_I_UWORD(modreader);\r
+       mh->unknown1    =_mm_read_I_UWORD(modreader);\r
+       mh->patptr      =_mm_read_I_UWORD(modreader);\r
+       mh->insptr      =_mm_read_I_UWORD(modreader);\r
+       mh->chnptr      =_mm_read_I_UWORD(modreader);\r
+       mh->unknown2    =_mm_read_I_UWORD(modreader);\r
+       mh->unknown3    =_mm_read_I_UWORD(modreader);\r
+       mh->mastermult  =_mm_read_UBYTE(modreader);\r
+       mh->initspeed   =_mm_read_UBYTE(modreader)>>4;\r
+       mh->unknown4    =_mm_read_I_UWORD(modreader);\r
+       mh->unknown5    =_mm_read_I_UWORD(modreader);\r
+       mh->patnum      =_mm_read_I_UWORD(modreader);\r
+       mh->insnum      =_mm_read_I_UWORD(modreader);\r
+       mh->ordnum      =_mm_read_I_UWORD(modreader);\r
+       mh->unknown6    =_mm_read_I_UWORD(modreader);\r
+       mh->unknown7    =_mm_read_I_UWORD(modreader);\r
+       mh->unknown8    =_mm_read_I_UWORD(modreader);\r
+       _mm_read_string(mh->scrm,4,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.songname    = DupStr(mh->songname,20,1);\r
+       of.numpat      = mh->patnum;\r
+       of.reppos      = 0;\r
+       of.numins      = of.numsmp = mh->insnum;\r
+       of.initspeed   = mh->initspeed;\r
+       of.inittempo   = 125;\r
+       of.numchn      = 4;\r
+       of.flags      |= UF_S3MSLIDES;\r
+       of.bpmlimit    = 32;\r
+\r
+       if(!(paraptr=(UWORD*)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD))))\r
+               return 0;\r
+\r
+       /* read the instrument+pattern parapointers */\r
+       _mm_fseek(modreader,mh->insptr<<4,SEEK_SET);\r
+       _mm_read_I_UWORDS(paraptr,of.numins,modreader);\r
+       _mm_fseek(modreader,mh->patptr<<4,SEEK_SET);\r
+       _mm_read_I_UWORDS(paraptr+of.numins,of.numpat,modreader);\r
+\r
+       /* check module version */\r
+       _mm_fseek(modreader,paraptr[of.numins]<<4,SEEK_SET);\r
+       version=_mm_read_I_UWORD(modreader);\r
+       if(version==mh->patsize) {\r
+               version    = 0x10;\r
+               of.modtype = strdup("STMIK 0.2 (STM2STX 1.0)");\r
+       } else {\r
+               version    = 0x11;\r
+               of.modtype = strdup("STMIK 0.2 (STM2STX 1.1)");\r
+       }\r
+\r
+       /* read the order data */\r
+       _mm_fseek(modreader,(mh->chnptr<<4)+32,SEEK_SET);\r
+       if(!AllocPositions(mh->ordnum)) return 0;\r
+       for(t=0;t<mh->ordnum;t++) {\r
+               of.positions[t]=_mm_read_UBYTE(modreader);\r
+               _mm_fseek(modreader,4,SEEK_CUR);\r
+       }\r
+\r
+       of.numpos=0;poslookupcnt=mh->ordnum;\r
+       for(t=0;t<mh->ordnum;t++) {\r
+               int order=of.positions[t];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               poslookup[t]=of.numpos; /* bug fix for freaky S3Ms */\r
+               if(of.positions[t]<254) of.numpos++;        \r
+               else\r
+                 /* special end of song pattern */\r
+                 if((order==LAST_PATTERN)&&(!curious)) break;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* load samples */\r
+       if(!AllocSamples()) return 0;\r
+       for(q=of.samples,t=0;t<of.numins;t++,q++) {\r
+               STXSAMPLE s;\r
+\r
+               /* seek to instrument position */\r
+               _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);\r
+               /* and load sample info */\r
+               s.type      =_mm_read_UBYTE(modreader);\r
+               _mm_read_string(s.filename,12,modreader);\r
+               s.memsegh   =_mm_read_UBYTE(modreader);\r
+               s.memsegl   =_mm_read_I_UWORD(modreader);\r
+               s.length    =_mm_read_I_ULONG(modreader);\r
+               s.loopbeg   =_mm_read_I_ULONG(modreader);\r
+               s.loopend   =_mm_read_I_ULONG(modreader);\r
+               s.volume    =_mm_read_UBYTE(modreader);\r
+               s.dsk       =_mm_read_UBYTE(modreader);\r
+               s.pack      =_mm_read_UBYTE(modreader);\r
+               s.flags     =_mm_read_UBYTE(modreader);\r
+               s.c2spd     =_mm_read_I_ULONG(modreader);\r
+               _mm_read_UBYTES(s.unused,12,modreader);\r
+               _mm_read_string(s.sampname,28,modreader);\r
+               _mm_read_string(s.scrs,4,modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename = DupStr(s.sampname,28,1);\r
+               q->speed      = (s.c2spd * 8363) / 8448;\r
+               q->length     = s.length;\r
+               q->loopstart  = s.loopbeg;\r
+               q->loopend    = s.loopend;\r
+               q->volume     = s.volume;\r
+               q->seekpos    = (((long)s.memsegh)<<16|s.memsegl)<<4;\r
+               q->flags     |= SF_SIGNED;\r
+\r
+               if(s.flags&1) q->flags |= SF_LOOP;\r
+               if(s.flags&4) q->flags |= SF_16BITS;\r
+       }\r
+\r
+       /* load pattern info */\r
+       of.numtrk=of.numpat*of.numchn;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               /* seek to pattern position (+2 skip pattern length) */\r
+               _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+\r
+                       (version==0x10?2:0),SEEK_SET);\r
+               if(!STX_ReadPattern()) return 0;\r
+               for(u=0;u<of.numchn;u++)\r
+                       if(!(of.tracks[track++]=STX_ConvertTrack(&stxbuf[u*64]))) return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static CHAR *STX_LoadTitle(void)\r
+{\r
+       CHAR s[28];\r
+\r
+       _mm_fseek(modreader,0,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
+\r
+       return(DupStr(s,28,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_stx={\r
+       NULL,\r
+       "STX",\r
+       "STX (Scream Tracker Music Interface Kit)",\r
+       STX_Init,\r
+       STX_Test,\r
+       STX_Load,\r
+       STX_Cleanup,\r
+       STX_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_ult.c b/apps/plugins/mikmod/loaders/load_ult.c
new file mode 100644 (file)
index 0000000..5d8c76d
--- /dev/null
@@ -0,0 +1,336 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_ult.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Ultratracker (ULT) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+/* header */\r
+typedef struct ULTHEADER {\r
+       CHAR  id[16];\r
+       CHAR  songtitle[32];\r
+       UBYTE reserved;\r
+} ULTHEADER;\r
+\r
+/* sample information */\r
+typedef struct ULTSAMPLE {\r
+       CHAR  samplename[32];\r
+       CHAR  dosname[12];\r
+       SLONG loopstart;\r
+       SLONG loopend;\r
+       SLONG sizestart;\r
+       SLONG sizeend;\r
+       UBYTE volume;\r
+       UBYTE flags;\r
+       UWORD speed;\r
+       SWORD finetune;\r
+} ULTSAMPLE;\r
+\r
+typedef struct ULTEVENT {\r
+       UBYTE note,sample,eff,dat1,dat2;\r
+} ULTEVENT;\r
+\r
+/*========== Loader variables */\r
+\r
+#define ULTS_16BITS     4\r
+#define ULTS_LOOP       8\r
+#define ULTS_REVERSE    16\r
+\r
+#define ULT_VERSION_LEN 18\r
+static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x";\r
+\r
+static ULTEVENT ev;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL ULT_Test(void)\r
+{\r
+       CHAR id[16];\r
+\r
+       if(!_mm_read_string(id,15,modreader)) return 0;\r
+       if(strncmp(id,"MAS_UTrack_V00",14)) return 0;\r
+       if((id[14]<'1')||(id[14]>'4')) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL ULT_Init(void)\r
+{\r
+       return 1;\r
+}\r
+\r
+void ULT_Cleanup(void)\r
+{\r
+}\r
+\r
+static UBYTE ReadUltEvent(ULTEVENT* event)\r
+{\r
+       UBYTE flag,rep=1;\r
+\r
+       flag = _mm_read_UBYTE(modreader);\r
+       if(flag==0xfc) {\r
+               rep = _mm_read_UBYTE(modreader);\r
+               event->note =_mm_read_UBYTE(modreader);\r
+       } else\r
+               event->note = flag;\r
+\r
+       event->sample   =_mm_read_UBYTE(modreader);\r
+       event->eff      =_mm_read_UBYTE(modreader);\r
+       event->dat1     =_mm_read_UBYTE(modreader);\r
+       event->dat2     =_mm_read_UBYTE(modreader);\r
+\r
+       return rep;\r
+}\r
+\r
+BOOL ULT_Load(BOOL curious)\r
+{\r
+       int t,u,tracks=0;\r
+       SAMPLE *q;\r
+       ULTSAMPLE s;\r
+       ULTHEADER mh;\r
+       UBYTE nos,noc,nopa;\r
+       (void)curious;\r
+\r
+       /* try to read module header */\r
+       _mm_read_string(mh.id,15,modreader);\r
+       _mm_read_string(mh.songtitle,32,modreader);\r
+       mh.reserved=_mm_read_UBYTE(modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       ULT_Version[ULT_VERSION_LEN-1]='3'+(mh.id[14]-'1');\r
+       of.modtype   = DupStr(ULT_Version,ULT_VERSION_LEN,1);\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       of.reppos    = 0;\r
+\r
+       /* read songtext */\r
+       if ((mh.id[14]>'1')&&(mh.reserved))\r
+               if(!ReadLinedComment(mh.reserved * 32, 32)) return 0;\r
+\r
+       nos=_mm_read_UBYTE(modreader);\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       of.songname=DupStr(mh.songtitle,32,1);\r
+       of.numins=of.numsmp=nos;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       q = of.samples;\r
+       for(t=0;t<nos;t++) {\r
+               /* try to read sample info */\r
+               _mm_read_string(s.samplename,32,modreader);\r
+               _mm_read_string(s.dosname,12,modreader);\r
+               s.loopstart     =_mm_read_I_ULONG(modreader);\r
+               s.loopend       =_mm_read_I_ULONG(modreader);\r
+               s.sizestart     =_mm_read_I_ULONG(modreader);\r
+               s.sizeend       =_mm_read_I_ULONG(modreader);\r
+               s.volume        =_mm_read_UBYTE(modreader);\r
+               s.flags         =_mm_read_UBYTE(modreader);\r
+               s.speed         =(mh.id[14]>='4')?_mm_read_I_UWORD(modreader):8363;\r
+               s.finetune      =_mm_read_I_SWORD(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename=DupStr(s.samplename,32,1);\r
+               /* The correct formula for the coefficient would be\r
+                  pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point\r
+                  here, we'll use a first order approximation here.\r
+                  1/567290 == Ln(2)/OCTAVE/32768 */\r
+               q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290);\r
+               q->length    = s.sizeend-s.sizestart;\r
+               q->volume    = s.volume>>2;\r
+               q->loopstart = s.loopstart;\r
+               q->loopend   = s.loopend;\r
+               q->flags = SF_SIGNED;\r
+               if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;\r
+               if(s.flags&ULTS_16BITS) {\r
+                       s.sizeend+=(s.sizeend-s.sizestart);\r
+                       s.sizestart<<=1;\r
+                       q->flags|=SF_16BITS;\r
+                       q->loopstart>>=1;\r
+                       q->loopend>>=1;\r
+               }\r
+               q++;\r
+       }\r
+\r
+       if(!AllocPositions(256)) return 0;\r
+       for(t=0;t<256;t++)\r
+               of.positions[t]=_mm_read_UBYTE(modreader);\r
+       for(t=0;t<256;t++)\r
+               if(of.positions[t]==255) {\r
+                       of.positions[t]=LAST_PATTERN;\r
+                       break;\r
+               }\r
+       of.numpos=t;\r
+\r
+       noc=_mm_read_UBYTE(modreader);\r
+       nopa=_mm_read_UBYTE(modreader);\r
+\r
+       of.numchn=++noc;\r
+       of.numpat=++nopa;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+       for(u=0;u<of.numchn;u++)\r
+               for(t=0;t<of.numpat;t++)\r
+                       of.patterns[(t*of.numchn)+u]=tracks++;\r
+\r
+       /* read pan position table for v1.5 and higher */\r
+       if(mh.id[14]>='3') {\r
+               for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modreader)<<4;\r
+               of.flags |= UF_PANNING;\r
+       }\r
+\r
+       for(t=0;t<of.numtrk;t++) {\r
+               int rep,row=0;\r
+\r
+               UniReset();\r
+               while(row<64) {\r
+                       rep=ReadUltEvent(&ev);\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_TRACK;\r
+                               return 0;\r
+                       }\r
+\r
+                       while(rep--) {\r
+                               UBYTE eff;\r
+                               int offset;\r
+\r
+                               if(ev.sample) UniInstrument(ev.sample-1);\r
+                               if(ev.note)   UniNote(ev.note+2*OCTAVE-1);\r
+\r
+                               /* first effect - various fixes by Alexander Kerkhove and\r
+                                                 Thomas Neumann */\r
+                               eff = ev.eff>>4;\r
+                               switch(eff) {\r
+                                       case 0x3: /* tone portamento */\r
+                                               UniEffect(UNI_ITEFFECTG,ev.dat2);\r
+                                               break;\r
+                                       case 0x5:\r
+                                               break;\r
+                                       case 0x9: /* sample offset */\r
+                                               offset=(ev.dat2<<8)|((ev.eff&0xf)==9?ev.dat1:0);\r
+                                               UniEffect(UNI_ULTEFFECT9,offset);\r
+                                               break;\r
+                                       case 0xb: /* panning */\r
+                                               UniPTEffect(8,ev.dat2*0xf);\r
+                                               of.flags |= UF_PANNING;\r
+                                               break;\r
+                                       case 0xc: /* volume */\r
+                                               UniPTEffect(eff,ev.dat2>>2);\r
+                                               break;\r
+                                       default:\r
+                                               UniPTEffect(eff,ev.dat2);\r
+                                               break;\r
+                               }\r
+\r
+                               /* second effect */\r
+                               eff=ev.eff&0xf;\r
+                               switch(eff) {\r
+                                       case 0x3: /* tone portamento */\r
+                                               UniEffect(UNI_ITEFFECTG,ev.dat1);\r
+                                               break;\r
+                                       case 0x5:\r
+                                               break;\r
+                                       case 0x9: /* sample offset */\r
+                                               if((ev.eff>>4)!=9)\r
+                                                       UniEffect(UNI_ULTEFFECT9,((UWORD)ev.dat1)<<8);\r
+                                               break;\r
+                                       case 0xb: /* panning */\r
+                                               UniPTEffect(8,ev.dat1*0xf);\r
+                                               of.flags |= UF_PANNING;\r
+                                               break;\r
+                                       case 0xc: /* volume */\r
+                                               UniPTEffect(eff,ev.dat1>>2);\r
+                                               break;\r
+                                       default:\r
+                                               UniPTEffect(eff,ev.dat1);\r
+                                               break;\r
+                               }\r
+\r
+                               UniNewline();\r
+                               row++;\r
+                       }\r
+               }\r
+               if(!(of.tracks[t]=UniDup())) return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *ULT_LoadTitle(void)\r
+{\r
+       CHAR s[32];\r
+\r
+       _mm_fseek(modreader,15,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,32,modreader)) return NULL;\r
+\r
+       return(DupStr(s,32,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_ult={\r
+       NULL,\r
+       "ULT",\r
+       "ULT (UltraTracker)",\r
+       ULT_Init,\r
+       ULT_Test,\r
+       ULT_Load,\r
+       ULT_Cleanup,\r
+       ULT_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_uni.c b/apps/plugins/mikmod/loaders/load_uni.c
new file mode 100644 (file)
index 0000000..ae33671
--- /dev/null
@@ -0,0 +1,718 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_uni.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+  UNIMOD (libmikmod's and APlayer's internal module format) loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct UNIHEADER {\r
+       CHAR  id[4];\r
+       UBYTE numchn;\r
+       UWORD numpos;\r
+       UWORD reppos;\r
+       UWORD numpat;\r
+       UWORD numtrk;\r
+       UWORD numins;\r
+       UWORD numsmp;\r
+       UBYTE initspeed;\r
+       UBYTE inittempo;\r
+       UBYTE initvolume;\r
+       UWORD flags;\r
+       UBYTE numvoices;\r
+       UWORD bpmlimit;\r
+\r
+       UBYTE positions[256];\r
+       UBYTE panning[32];\r
+} UNIHEADER;\r
+\r
+typedef struct UNISMP05 {\r
+       UWORD c2spd;\r
+       UWORD transpose;\r
+       UBYTE volume;\r
+       UBYTE panning;\r
+       ULONG length;\r
+       ULONG loopstart;\r
+       ULONG loopend;\r
+       UWORD flags;\r
+       CHAR* samplename;\r
+       UBYTE vibtype;\r
+       UBYTE vibsweep;\r
+       UBYTE vibdepth;\r
+       UBYTE vibrate;\r
+} UNISMP05;\r
+\r
+/*========== Loader variables */\r
+\r
+static UWORD universion;\r
+static UNIHEADER mh;\r
+\r
+#define UNI_SMPINCR 64\r
+static UNISMP05 *wh=NULL,*s=NULL;\r
+\r
+/*========== Loader code */\r
+\r
+static char* readstring(void)\r
+{\r
+       char *s=NULL;\r
+       UWORD len;\r
+       \r
+       len=_mm_read_I_UWORD(modreader);\r
+       if(len) {\r
+               s=_mm_malloc(len+1);\r
+               _mm_read_UBYTES(s,len,modreader);\r
+               s[len]=0;\r
+       }\r
+       return s;\r
+}\r
+\r
+BOOL UNI_Test(void)\r
+{\r
+       char id[6];\r
+\r
+       if(!_mm_read_UBYTES(id,6,modreader)) return 0;\r
+\r
+       /* UNIMod created by MikCvt */\r
+       if(!(memcmp(id,"UN0",3))) {\r
+               if((id[3]>='4')&&(id[3]<='6')) return 1;\r
+       }\r
+       /* UNIMod created by APlayer */\r
+       if(!(memcmp(id,"APUN\01",5))) {\r
+               if((id[5]>=1)&&(id[5]<=6)) return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+BOOL UNI_Init(void)\r
+{\r
+       return 1;\r
+}\r
+\r
+void UNI_Cleanup(void)\r
+{\r
+       _mm_free(wh);\r
+       s=NULL;\r
+}\r
+\r
+static UBYTE* readtrack(void)\r
+{\r
+       UBYTE *t;\r
+       UWORD len;\r
+       int cur=0,chunk;\r
+\r
+       if(universion>=6)\r
+               len=_mm_read_M_UWORD(modreader);\r
+       else\r
+               len=_mm_read_I_UWORD(modreader);\r
+\r
+       if(!len) return NULL;\r
+       if(!(t=_mm_malloc(len))) return NULL;\r
+       _mm_read_UBYTES(t,len,modreader);\r
+\r
+       /* Check if the track is correct */\r
+       while(1) {\r
+               chunk=t[cur++];\r
+               if(!chunk) break;\r
+               chunk=(chunk&0x1f)-1;\r
+               while(chunk>0) {\r
+                       int opcode,oplen;\r
+\r
+                       if(cur>=len) {\r
+                               free(t);\r
+                               return NULL;\r
+                       }\r
+                       opcode=t[cur];\r
+\r
+                       /* Remap opcodes */\r
+                       if (universion <= 5) {\r
+                               if (opcode > 29) {\r
+                                       free(t);\r
+                                       return NULL;\r
+                               }\r
+                               switch (opcode) {\r
+                                       /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */\r
+                                       case 25:\r
+                                               opcode = UNI_S3MEFFECTT;\r
+                                               break;\r
+                                       case 26:\r
+                                               opcode = UNI_XMEFFECTA;\r
+                                               break;\r
+                                       case 27:\r
+                                               opcode = UNI_XMEFFECTG;\r
+                                               break;\r
+                                       case 28:\r
+                                               opcode = UNI_XMEFFECTH;\r
+                                               break;\r
+                                       case 29:\r
+                                               opcode = UNI_XMEFFECTP;\r
+                                               break;\r
+                               }\r
+                       } else {\r
+                               /* APlayer < 1.05 does not have XMEFFECT6 */\r
+                               if (opcode >= UNI_XMEFFECT6 && universion < 0x105)\r
+                                       opcode++;\r
+                               /* APlayer < 1.03 does not have ITEFFECTT */\r
+                               if (opcode >= UNI_ITEFFECTT && universion < 0x103)\r
+                                       opcode++;\r
+                               /* APlayer < 1.02 does not have ITEFFECTZ */\r
+                               if (opcode >= UNI_ITEFFECTZ && universion < 0x102)\r
+                                       opcode++;\r
+                       }\r
+\r
+                       if((!opcode)||(opcode>=UNI_LAST)) {\r
+                               free(t);\r
+                               return NULL;\r
+                       }\r
+                       t[cur]=opcode;\r
+                       oplen=unioperands[opcode]+1;\r
+                       cur+=oplen;\r
+                       chunk-=oplen;\r
+               }\r
+               if((chunk<0)||(cur>=len)) {\r
+                       free(t);\r
+                       return NULL;\r
+               }\r
+       }\r
+       return t;\r
+}\r
+\r
+static BOOL loadsmp6(void)\r
+{\r
+       int t;\r
+       SAMPLE *s;\r
+\r
+       s=of.samples;\r
+       for(t=0;t<of.numsmp;t++,s++) {\r
+               int flags;\r
+\r
+               flags         = _mm_read_M_UWORD(modreader);\r
+               s->flags=0;\r
+               if(flags&0x0004) s->flags|=SF_STEREO;\r
+               if(flags&0x0002) s->flags|=SF_SIGNED;\r
+               if(flags&0x0001) s->flags|=SF_16BITS;\r
+               /* convert flags */\r
+               if(universion>=0x104) {\r
+                       if(flags&0x2000) s->flags|=SF_UST_LOOP;\r
+                       if(flags&0x1000) s->flags|=SF_OWNPAN;\r
+                       if(flags&0x0800) s->flags|=SF_SUSTAIN;\r
+                       if(flags&0x0400) s->flags|=SF_REVERSE;\r
+                       if(flags&0x0200) s->flags|=SF_BIDI;\r
+                       if(flags&0x0100) s->flags|=SF_LOOP;\r
+                       if(flags&0x0020) s->flags|=SF_ITPACKED;\r
+                       if(flags&0x0010) s->flags|=SF_DELTA;\r
+                       if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
+               } else if(universion>=0x102) {\r
+                       if(flags&0x0800) s->flags|=SF_UST_LOOP;\r
+                       if(flags&0x0400) s->flags|=SF_OWNPAN;\r
+                       if(flags&0x0200) s->flags|=SF_SUSTAIN;\r
+                       if(flags&0x0100) s->flags|=SF_REVERSE;\r
+                       if(flags&0x0080) s->flags|=SF_BIDI;\r
+                       if(flags&0x0040) s->flags|=SF_LOOP;\r
+                       if(flags&0x0020) s->flags|=SF_ITPACKED;\r
+                       if(flags&0x0010) s->flags|=SF_DELTA;\r
+                       if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
+               } else {\r
+                       if(flags&0x400) s->flags|=SF_UST_LOOP;\r
+                       if(flags&0x200) s->flags|=SF_OWNPAN;\r
+                       if(flags&0x100) s->flags|=SF_REVERSE;\r
+                       if(flags&0x080) s->flags|=SF_SUSTAIN;\r
+                       if(flags&0x040) s->flags|=SF_BIDI;\r
+                       if(flags&0x020) s->flags|=SF_LOOP;\r
+                       if(flags&0x010) s->flags|=SF_BIG_ENDIAN;\r
+                       if(flags&0x008) s->flags|=SF_DELTA;\r
+               }\r
+\r
+               s->speed      = _mm_read_M_ULONG(modreader);\r
+               s->volume     = _mm_read_UBYTE(modreader);\r
+               s->panning    = _mm_read_M_UWORD(modreader);\r
+               s->length     = _mm_read_M_ULONG(modreader);\r
+               s->loopstart  = _mm_read_M_ULONG(modreader);\r
+               s->loopend    = _mm_read_M_ULONG(modreader);\r
+               s->susbegin   = _mm_read_M_ULONG(modreader);\r
+               s->susend     = _mm_read_M_ULONG(modreader);\r
+               s->globvol    = _mm_read_UBYTE(modreader);\r
+               s->vibflags   = _mm_read_UBYTE(modreader);\r
+               s->vibtype    = _mm_read_UBYTE(modreader);\r
+               s->vibsweep   = _mm_read_UBYTE(modreader);\r
+               s->vibdepth   = _mm_read_UBYTE(modreader);\r
+               s->vibrate    = _mm_read_UBYTE(modreader);\r
+\r
+               s->samplename=readstring();\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL loadinstr6(void)\r
+{\r
+       int t,w;\r
+       INSTRUMENT *i;\r
+\r
+       i=of.instruments;\r
+       for(t=0;t<of.numins;t++,i++) {\r
+               i->flags        = _mm_read_UBYTE(modreader);\r
+               i->nnatype      = _mm_read_UBYTE(modreader);\r
+               i->dca          = _mm_read_UBYTE(modreader);\r
+               i->dct          = _mm_read_UBYTE(modreader);\r
+               i->globvol      = _mm_read_UBYTE(modreader);\r
+               i->panning      = _mm_read_M_UWORD(modreader);\r
+               i->pitpansep    = _mm_read_UBYTE(modreader);\r
+               i->pitpancenter = _mm_read_UBYTE(modreader);\r
+               i->rvolvar      = _mm_read_UBYTE(modreader);\r
+               i->rpanvar      = _mm_read_UBYTE(modreader);\r
+               i->volfade      = _mm_read_M_UWORD(modreader);\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define UNI_LoadEnvelope6(name)                                                                                \\r
+               i-> name##flg=_mm_read_UBYTE(modreader);                                                \\r
+               i-> name##pts=_mm_read_UBYTE(modreader);                                                \\r
+               i-> name##susbeg=_mm_read_UBYTE(modreader);                                             \\r
+               i-> name##susend=_mm_read_UBYTE(modreader);                                             \\r
+               i-> name##beg=_mm_read_UBYTE(modreader);                                                \\r
+               i-> name##end=_mm_read_UBYTE(modreader);                                                \\r
+               for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) {                   \\r
+                       i-> name##env[w].pos=_mm_read_M_SWORD(modreader);                       \\r
+                       i-> name##env[w].val=_mm_read_M_SWORD(modreader);                       \\r
+               }\r
+#else\r
+#define UNI_LoadEnvelope6(name)                                                                                \\r
+               i-> name/**/flg=_mm_read_UBYTE(modreader);                                              \\r
+               i-> name/**/pts=_mm_read_UBYTE(modreader);                                              \\r
+               i-> name/**/susbeg=_mm_read_UBYTE(modreader);                                   \\r
+               i-> name/**/susend=_mm_read_UBYTE(modreader);                                   \\r
+               i-> name/**/beg=_mm_read_UBYTE(modreader);                                              \\r
+               i-> name/**/end=_mm_read_UBYTE(modreader);                                              \\r
+               for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) {                \\r
+                       i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader);                     \\r
+                       i-> name/**/env[w].val=_mm_read_M_SWORD(modreader);                     \\r
+               }\r
+#endif\r
+\r
+               UNI_LoadEnvelope6(vol);\r
+               UNI_LoadEnvelope6(pan);\r
+               UNI_LoadEnvelope6(pit);\r
+#undef UNI_LoadEnvelope6\r
+\r
+               if(universion>=0x103)\r
+                       _mm_read_M_UWORDS(i->samplenumber,120,modreader);\r
+               else\r
+                       for(w=0;w<120;w++)\r
+                               i->samplenumber[w]=_mm_read_UBYTE(modreader);\r
+               _mm_read_UBYTES(i->samplenote,120,modreader);\r
+\r
+               i->insname=readstring();\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL loadinstr5(void)\r
+{\r
+       INSTRUMENT *i;\r
+       int t;\r
+       UWORD wavcnt=0;\r
+       UBYTE vibtype,vibsweep,vibdepth,vibrate;\r
+\r
+       i=of.instruments;\r
+       for(of.numsmp=t=0;t<of.numins;t++,i++) {\r
+               int u,numsmp;\r
+\r
+               numsmp=_mm_read_UBYTE(modreader);\r
+\r
+               memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
+               for(u=0;u<96;u++)\r
+                       i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader);\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define UNI_LoadEnvelope5(name)                                                                        \\r
+               i-> name##flg=_mm_read_UBYTE(modreader);                                        \\r
+               i-> name##pts=_mm_read_UBYTE(modreader);                                        \\r
+               i-> name##susbeg=_mm_read_UBYTE(modreader);                                     \\r
+               i-> name##susend=i-> name##susbeg;                                                      \\r
+               i-> name##beg=_mm_read_UBYTE(modreader);                                        \\r
+               i-> name##end=_mm_read_UBYTE(modreader);                                        \\r
+               for(u=0;u<12;u++) {                                                                                     \\r
+                       i-> name##env[u].pos=_mm_read_I_SWORD(modreader);               \\r
+                       i-> name##env[u].val=_mm_read_I_SWORD(modreader);               \\r
+               }\r
+#else\r
+#define UNI_LoadEnvelope5(name)                                                                        \\r
+               i-> name/**/flg=_mm_read_UBYTE(modreader);                                      \\r
+               i-> name/**/pts=_mm_read_UBYTE(modreader);                                      \\r
+               i-> name/**/susbeg=_mm_read_UBYTE(modreader);                           \\r
+               i-> name/**/susend=i-> name/**/susbeg;                                          \\r
+               i-> name/**/beg=_mm_read_UBYTE(modreader);                                      \\r
+               i-> name/**/end=_mm_read_UBYTE(modreader);                                      \\r
+               for(u=0;u<12;u++) {                                                                                     \\r
+                       i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader);             \\r
+                       i-> name/**/env[u].val=_mm_read_I_SWORD(modreader);             \\r
+               }\r
+#endif\r
+\r
+               UNI_LoadEnvelope5(vol);\r
+               UNI_LoadEnvelope5(pan);\r
+#undef UNI_LoadEnvelope5\r
+\r
+               vibtype      =_mm_read_UBYTE(modreader);\r
+               vibsweep     =_mm_read_UBYTE(modreader);\r
+               vibdepth     =_mm_read_UBYTE(modreader);\r
+               vibrate      =_mm_read_UBYTE(modreader);\r
+\r
+               i->volfade=_mm_read_I_UWORD(modreader);\r
+               i->insname=readstring();\r
+\r
+               for(u=0;u<numsmp;u++,s++,of.numsmp++) {\r
+                       /* Allocate more room for sample information if necessary */\r
+                       if(of.numsmp+u==wavcnt) {\r
+                               wavcnt+=UNI_SMPINCR;\r
+                               if(!(wh=realloc(wh,wavcnt*sizeof(UNISMP05)))) {\r
+                                       _mm_errno=MMERR_OUT_OF_MEMORY;\r
+                                       return 0;\r
+                               }\r
+                               s=wh+(wavcnt-UNI_SMPINCR);\r
+                       }\r
+\r
+                       s->c2spd    =_mm_read_I_UWORD(modreader);\r
+                       s->transpose=_mm_read_SBYTE(modreader);\r
+                       s->volume   =_mm_read_UBYTE(modreader);\r
+                       s->panning  =_mm_read_UBYTE(modreader);\r
+                       s->length   =_mm_read_I_ULONG(modreader);\r
+                       s->loopstart=_mm_read_I_ULONG(modreader);\r
+                       s->loopend  =_mm_read_I_ULONG(modreader);\r
+                       s->flags    =_mm_read_I_UWORD(modreader);\r
+                       s->samplename=readstring();\r
+\r
+                       s->vibtype =vibtype;\r
+                       s->vibsweep=vibsweep;\r
+                       s->vibdepth=vibdepth;\r
+                       s->vibrate =vibrate;\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               free(wh);wh=NULL;\r
+                               _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+                               return 0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* sanity check */\r
+       if(!of.numsmp) {\r
+               if(wh) { free(wh);wh=NULL; }\r
+               _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+               return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL loadsmp5(void)\r
+{\r
+       int t,u;\r
+       SAMPLE *q;\r
+       INSTRUMENT *d;\r
+\r
+       q=of.samples;s=wh;\r
+       for(u=0;u<of.numsmp;u++,q++,s++) {\r
+               q->samplename=s->samplename;\r
+\r
+               q->length   =s->length;\r
+               q->loopstart=s->loopstart;\r
+               q->loopend  =s->loopend;\r
+               q->volume   =s->volume;\r
+               q->speed    =s->c2spd;\r
+               q->panning  =s->panning;\r
+               q->vibtype  =s->vibtype;\r
+               q->vibsweep =s->vibsweep;\r
+               q->vibdepth =s->vibdepth;\r
+               q->vibrate  =s->vibrate;\r
+\r
+               /* convert flags */\r
+               q->flags=0;\r
+               if(s->flags&128) q->flags|=SF_REVERSE;\r
+               if(s->flags& 64) q->flags|=SF_SUSTAIN;\r
+               if(s->flags& 32) q->flags|=SF_BIDI;\r
+               if(s->flags& 16) q->flags|=SF_LOOP;\r
+               if(s->flags&  8) q->flags|=SF_BIG_ENDIAN;\r
+               if(s->flags&  4) q->flags|=SF_DELTA;\r
+               if(s->flags&  2) q->flags|=SF_SIGNED;\r
+               if(s->flags&  1) q->flags|=SF_16BITS;\r
+       }\r
+\r
+       d=of.instruments;s=wh;\r
+       for(u=0;u<of.numins;u++,d++)\r
+               for(t=0;t<INSTNOTES;t++)\r
+                       d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)?\r
+                         255:(t+s[d->samplenumber[t]].transpose);\r
+\r
+       free(wh);wh=NULL;\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL UNI_Load(BOOL curious)\r
+{\r
+       int t;\r
+       char *modtype,*oldtype=NULL;\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       (void)curious;\r
+       \r
+       /* read module header */\r
+       _mm_read_UBYTES(mh.id,4,modreader);\r
+       if(mh.id[3]!='N')\r
+               universion=mh.id[3]-'0';\r
+       else\r
+               universion=0x100;\r
+\r
+       if(universion>=6) {\r
+               if (universion==6)\r
+                       _mm_read_UBYTE(modreader);\r
+               else\r
+                       universion=_mm_read_M_UWORD(modreader);\r
+\r
+               mh.flags     =_mm_read_M_UWORD(modreader);\r
+               mh.numchn    =_mm_read_UBYTE(modreader);\r
+               mh.numvoices =_mm_read_UBYTE(modreader);\r
+               mh.numpos    =_mm_read_M_UWORD(modreader);\r
+               mh.numpat    =_mm_read_M_UWORD(modreader);\r
+               mh.numtrk    =_mm_read_M_UWORD(modreader);\r
+               mh.numins    =_mm_read_M_UWORD(modreader);\r
+               mh.numsmp    =_mm_read_M_UWORD(modreader);\r
+               mh.reppos    =_mm_read_M_UWORD(modreader);\r
+               mh.initspeed =_mm_read_UBYTE(modreader);\r
+               mh.inittempo =_mm_read_UBYTE(modreader);\r
+               mh.initvolume=_mm_read_UBYTE(modreader);\r
+               /* I expect this to show up soon in APlayer 1.06 format */\r
+               if (universion >= 0x106)\r
+                       mh.bpmlimit=_mm_read_M_UWORD(modreader);\r
+               else\r
+                       mh.bpmlimit=32;\r
+\r
+               mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA;\r
+               mh.flags |= UF_PANNING;\r
+       } else {\r
+               mh.numchn    =_mm_read_UBYTE(modreader);\r
+               mh.numpos    =_mm_read_I_UWORD(modreader);\r
+               mh.reppos    =(universion==5)?_mm_read_I_UWORD(modreader):0;\r
+               mh.numpat    =_mm_read_I_UWORD(modreader);\r
+               mh.numtrk    =_mm_read_I_UWORD(modreader);\r
+               mh.numins    =_mm_read_I_UWORD(modreader);\r
+               mh.initspeed =_mm_read_UBYTE(modreader);\r
+               mh.inittempo =_mm_read_UBYTE(modreader);\r
+               _mm_read_UBYTES(mh.positions,256,modreader);\r
+               _mm_read_UBYTES(mh.panning,32,modreader);\r
+               mh.flags     =_mm_read_UBYTE(modreader);\r
+               mh.bpmlimit  =32;\r
+\r
+               mh.flags &= UF_XMPERIODS | UF_LINEAR;\r
+               mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING;\r
+       }\r
+       \r
+       /* set module parameters */\r
+       of.flags     =mh.flags;\r
+       of.numchn    =mh.numchn;\r
+       of.numpos    =mh.numpos;\r
+       of.numpat    =mh.numpat;\r
+       of.numtrk    =mh.numtrk;\r
+       of.numins    =mh.numins;\r
+       of.reppos    =mh.reppos;\r
+       of.initspeed =mh.initspeed;\r
+       of.inittempo =mh.inittempo;\r
+       if(mh.bpmlimit)\r
+               of.bpmlimit=mh.bpmlimit;\r
+       else\r
+               /* be bug-compatible with older releases */\r
+               of.bpmlimit=32;\r
+\r
+       of.songname=readstring();\r
+       if(universion<0x102)\r
+               oldtype=readstring();\r
+       if(oldtype) {\r
+               int len=strlen(oldtype)+20;\r
+               if(!(modtype=_mm_malloc(len))) return 0;\r
+#ifdef HAVE_SNPRINTF\r
+               snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
+#else\r
+               sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
+#endif\r
+       } else {\r
+               if(!(modtype=_mm_malloc(10))) return 0;\r
+#ifdef HAVE_SNPRINTF\r
+               snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
+#else\r
+               sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
+#endif\r
+       }\r
+       of.modtype=strdup(modtype);\r
+       free(modtype);free(oldtype);\r
+       of.comment=readstring();\r
+\r
+       if(universion>=6) {\r
+               of.numvoices=mh.numvoices;\r
+               of.initvolume=mh.initvolume;\r
+       }\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno=MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* positions */\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       if(universion>=6) {\r
+               if(universion>=0x100)\r
+                       _mm_read_M_UWORDS(of.positions,of.numpos,modreader);\r
+               else\r
+                       for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader);\r
+               _mm_read_M_UWORDS(of.panning,of.numchn,modreader);\r
+               _mm_read_UBYTES(of.chanvol,of.numchn,modreader);\r
+       } else {\r
+               if((mh.numpos>256)||(mh.numchn>32)) {\r
+                       _mm_errno=MMERR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+               for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t];\r
+               for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t];\r
+       }\r
+       /* convert the ``end of song'' pattern code if necessary */\r
+       if(universion<0x106)\r
+               for(t=0;t<of.numpos;t++)\r
+                       if(of.positions[t]==255) of.positions[t]=LAST_PATTERN;\r
+\r
+       /* instruments and samples */\r
+       if(universion>=6) {\r
+               of.numsmp=mh.numsmp;\r
+               if(!AllocSamples()) return 0;\r
+               if(!loadsmp6()) return 0;\r
+\r
+               if(of.flags&UF_INST) {\r
+                       if(!AllocInstruments()) return 0;\r
+                       if(!loadinstr6()) return 0;\r
+               }\r
+       } else {\r
+               if(!AllocInstruments()) return 0;\r
+               if(!loadinstr5()) return 0;\r
+               if(!AllocSamples()) {\r
+                       if(wh) { free(wh);wh=NULL; }\r
+                       return 0;\r
+               }\r
+               if(!loadsmp5()) return 0;\r
+\r
+               /* check if the original file had no instruments */\r
+               if(of.numsmp==of.numins) {\r
+                       for(t=0,d=of.instruments;t<of.numins;t++,d++) {\r
+                               int u;\r
+\r
+                               if((d->volpts)||(d->panpts)||(d->globvol!=64)) break;\r
+                               for(u=0;u<96;u++)\r
+                                       if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break;\r
+                               if(u!=96) break;\r
+                       }\r
+                       if(t==of.numins) {\r
+                               of.flags&=~UF_INST;\r
+                               of.flags&=~UF_NOWRAP;\r
+                               for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) {\r
+                                       q->samplename=d->insname;\r
+                                       d->insname=NULL;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* patterns */\r
+       if(!AllocPatterns()) return 0;\r
+       if(universion>=6) {\r
+               _mm_read_M_UWORDS(of.pattrows,of.numpat,modreader);\r
+               _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
+       } else {\r
+               _mm_read_I_UWORDS(of.pattrows,of.numpat,modreader);\r
+               _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
+       }\r
+\r
+       /* tracks */\r
+       if(!AllocTracks()) return 0;\r
+       for(t=0;t<of.numtrk;t++)\r
+               if(!(of.tracks[t]=readtrack())) {\r
+                       _mm_errno=MMERR_LOADING_TRACK;\r
+                       return 0;\r
+               }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *UNI_LoadTitle(void)\r
+{\r
+       UBYTE ver;\r
+       int posit[3]={304,306,26};\r
+\r
+       _mm_fseek(modreader,3,SEEK_SET);\r
+       ver=_mm_read_UBYTE(modreader);\r
+       if(ver=='N') ver='6';\r
+\r
+       _mm_fseek(modreader,posit[ver-'4'],SEEK_SET);\r
+       return readstring();\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_uni={\r
+       NULL,\r
+       "UNI",\r
+       "APUN (APlayer) and UNI (MikMod)",\r
+       UNI_Init,\r
+       UNI_Test,\r
+       UNI_Load,\r
+       UNI_Cleanup,\r
+       UNI_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/loaders/load_xm.c b/apps/plugins/mikmod/loaders/load_xm.c
new file mode 100644 (file)
index 0000000..fcf958d
--- /dev/null
@@ -0,0 +1,816 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: load_xm.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+  Fasttracker (XM) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct XMHEADER {\r
+       CHAR  id[17];          /* ID text: 'Extended module: ' */\r
+       CHAR  songname[21];    /* Module name */\r
+       CHAR  trackername[20]; /* Tracker name */\r
+       UWORD version;         /* Version number */\r
+       ULONG headersize;      /* Header size */\r
+       UWORD songlength;      /* Song length (in patten order table) */\r
+       UWORD restart;         /* Restart position */\r
+       UWORD numchn;          /* Number of channels (2,4,6,8,10,...,32) */\r
+       UWORD numpat;          /* Number of patterns (max 256) */\r
+       UWORD numins;          /* Number of instruments (max 128) */\r
+       UWORD flags;       \r
+       UWORD tempo;           /* Default tempo */\r
+       UWORD bpm;             /* Default BPM */\r
+       UBYTE orders[256];     /* Pattern order table  */\r
+} XMHEADER;\r
+\r
+typedef struct XMINSTHEADER {\r
+       ULONG size;     /* Instrument size */\r
+       CHAR  name[22]; /* Instrument name */\r
+       UBYTE type;     /* Instrument type (always 0) */\r
+       UWORD numsmp;   /* Number of samples in instrument */\r
+       ULONG ssize;\r
+} XMINSTHEADER;\r
+\r
+#define XMENVCNT (12*2)\r
+#define XMNOTECNT (8*OCTAVE)\r
+typedef struct XMPATCHHEADER {\r
+       UBYTE what[XMNOTECNT];  /*  Sample number for all notes */\r
+       UWORD volenv[XMENVCNT]; /*  Points for volume envelope */\r
+       UWORD panenv[XMENVCNT]; /*  Points for panning envelope */\r
+       UBYTE volpts;      /*  Number of volume points */\r
+       UBYTE panpts;      /*  Number of panning points */\r
+       UBYTE volsus;      /*  Volume sustain point */\r
+       UBYTE volbeg;      /*  Volume loop start point */\r
+       UBYTE volend;      /*  Volume loop end point */\r
+       UBYTE pansus;      /*  Panning sustain point */\r
+       UBYTE panbeg;      /*  Panning loop start point */\r
+       UBYTE panend;      /*  Panning loop end point */\r
+       UBYTE volflg;      /*  Volume type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE panflg;      /*  Panning type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE vibflg;      /*  Vibrato type */\r
+       UBYTE vibsweep;    /*  Vibrato sweep */\r
+       UBYTE vibdepth;    /*  Vibrato depth */\r
+       UBYTE vibrate;     /*  Vibrato rate */\r
+       UWORD volfade;     /*  Volume fadeout */\r
+} XMPATCHHEADER;\r
+\r
+typedef struct XMWAVHEADER {\r
+       ULONG length;         /* Sample length */\r
+       ULONG loopstart;      /* Sample loop start */\r
+       ULONG looplength;     /* Sample loop length */\r
+       UBYTE volume;         /* Volume  */\r
+       SBYTE finetune;       /* Finetune (signed byte -128..+127) */\r
+       UBYTE type;           /* Loop type */\r
+       UBYTE panning;        /* Panning (0-255) */\r
+       SBYTE relnote;        /* Relative note number (signed byte) */\r
+       UBYTE reserved;\r
+       CHAR  samplename[22]; /* Sample name */\r
+       UBYTE vibtype;        /* Vibrato type */\r
+       UBYTE vibsweep;       /* Vibrato sweep */\r
+       UBYTE vibdepth;       /* Vibrato depth */\r
+       UBYTE vibrate;        /* Vibrato rate */\r
+} XMWAVHEADER;\r
+\r
+typedef struct XMPATHEADER {\r
+       ULONG size;     /* Pattern header length  */\r
+       UBYTE packing;  /* Packing type (always 0) */\r
+       UWORD numrows;  /* Number of rows in pattern (1..256) */\r
+       SWORD packsize; /* Packed patterndata size */\r
+} XMPATHEADER;\r
+\r
+typedef struct XMNOTE {\r
+       UBYTE note,ins,vol,eff,dat;\r
+} XMNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static XMNOTE *xmpat=NULL;\r
+static XMHEADER *mh=NULL;\r
+\r
+/* increment unit for sample array reallocation */\r
+#define XM_SMPINCR 64\r
+static ULONG *nextwav=NULL;\r
+static XMWAVHEADER *wh=NULL,*s=NULL;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL XM_Test(void)\r
+{\r
+       UBYTE id[38];\r
+\r
+       if(!_mm_read_UBYTES(id,38,modreader)) return 0;\r
+       if(memcmp(id,"Extended Module: ",17)) return 0;\r
+       if(id[37]==0x1a) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL XM_Init(void)\r
+{\r
+       if(!(mh=(XMHEADER *)_mm_malloc(sizeof(XMHEADER)))) return 0;\r
+       return 1;\r
+}\r
+\r
+void XM_Cleanup(void)\r
+{\r
+       _mm_free(mh);\r
+}\r
+\r
+static int XM_ReadNote(XMNOTE* n)\r
+{\r
+       UBYTE cmp,result=1;\r
+\r
+       memset(n,0,sizeof(XMNOTE));\r
+       cmp=_mm_read_UBYTE(modreader);\r
+\r
+       if(cmp&0x80) {\r
+               if(cmp&1)  { result++;n->note = _mm_read_UBYTE(modreader); }\r
+               if(cmp&2)  { result++;n->ins  = _mm_read_UBYTE(modreader); }\r
+               if(cmp&4)  { result++;n->vol  = _mm_read_UBYTE(modreader); }\r
+               if(cmp&8)  { result++;n->eff  = _mm_read_UBYTE(modreader); }\r
+               if(cmp&16) { result++;n->dat  = _mm_read_UBYTE(modreader); }\r
+       } else {\r
+               n->note = cmp;\r
+               n->ins  = _mm_read_UBYTE(modreader);\r
+               n->vol  = _mm_read_UBYTE(modreader);\r
+               n->eff  = _mm_read_UBYTE(modreader);\r
+               n->dat  = _mm_read_UBYTE(modreader);\r
+               result += 4;\r
+       }\r
+       return result;\r
+}\r
+\r
+static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows)\r
+{\r
+       int t;\r
+       UBYTE note,ins,vol,eff,dat;\r
+\r
+       UniReset();\r
+       for(t=0;t<rows;t++) {\r
+               note = xmtrack->note;\r
+               ins  = xmtrack->ins;\r
+               vol  = xmtrack->vol;\r
+               eff  = xmtrack->eff;\r
+               dat  = xmtrack->dat;\r
+\r
+               if(note) {\r
+                       if(note>XMNOTECNT)\r
+                               UniEffect(UNI_KEYFADE,0);\r
+                       else\r
+                               UniNote(note-1);\r
+               }\r
+               if(ins) UniInstrument(ins-1);\r
+\r
+               switch(vol>>4) {\r
+                       case 0x6: /* volslide down */\r
+                               if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf);\r
+                               break;\r
+                       case 0x7: /* volslide up */\r
+                               if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4);\r
+                               break;\r
+\r
+                               /* volume-row fine volume slide is compatible with protracker\r
+                                  EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as\r
+                                  opposed to 'take the last sliding value'. */\r
+                       case 0x8: /* finevol down */\r
+                               UniPTEffect(0xe,0xb0|(vol&0xf));\r
+                               break;\r
+                       case 0x9: /* finevol up */\r
+                               UniPTEffect(0xe,0xa0|(vol&0xf));\r
+                               break;\r
+                       case 0xa: /* set vibrato speed */\r
+                               UniEffect(UNI_XMEFFECT4,vol<<4);\r
+                               break;\r
+                       case 0xb: /* vibrato */\r
+                               UniEffect(UNI_XMEFFECT4,vol&0xf);\r
+                               break;\r
+                       case 0xc: /* set panning */\r
+                               UniPTEffect(0x8,vol<<4);\r
+                               break;\r
+                       case 0xd: /* panning slide left (only slide when data not zero) */\r
+                               if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf);\r
+                               break;\r
+                       case 0xe: /* panning slide right (only slide when data not zero) */\r
+                               if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4);\r
+                               break;\r
+                       case 0xf: /* tone porta */\r
+                               UniPTEffect(0x3,vol<<4);\r
+                               break;\r
+                       default:\r
+                               if((vol>=0x10)&&(vol<=0x50))\r
+                                       UniPTEffect(0xc,vol-0x10);\r
+               }\r
+\r
+               switch(eff) {\r
+                       case 0x4:\r
+                               UniEffect(UNI_XMEFFECT4,dat);\r
+                               break;\r
+                       case 0x6:\r
+                               UniEffect(UNI_XMEFFECT6,dat);\r
+                               break;\r
+                       case 0xa:\r
+                               UniEffect(UNI_XMEFFECTA,dat);\r
+                               break;\r
+                       case 0xe: /* Extended effects */\r
+                               switch(dat>>4) {\r
+                                       case 0x1: /* XM fine porta up */\r
+                                               UniEffect(UNI_XMEFFECTE1,dat&0xf);\r
+                                               break;\r
+                                       case 0x2: /* XM fine porta down */\r
+                                               UniEffect(UNI_XMEFFECTE2,dat&0xf);\r
+                                               break;\r
+                                       case 0xa: /* XM fine volume up */\r
+                                               UniEffect(UNI_XMEFFECTEA,dat&0xf);\r
+                                               break;\r
+                                       case 0xb: /* XM fine volume down */\r
+                                               UniEffect(UNI_XMEFFECTEB,dat&0xf);\r
+                                               break;\r
+                                       default:\r
+                                               UniPTEffect(eff,dat);\r
+                               }\r
+                               break;\r
+                       case 'G'-55: /* G - set global volume */\r
+                               UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1);\r
+                               break;\r
+                       case 'H'-55: /* H - global volume slide */\r
+                               UniEffect(UNI_XMEFFECTH,dat);\r
+                               break;\r
+                       case 'K'-55: /* K - keyOff and KeyFade */\r
+                               UniEffect(UNI_KEYFADE,dat);\r
+                               break;\r
+                       case 'L'-55: /* L - set envelope position */\r
+                               UniEffect(UNI_XMEFFECTL,dat);\r
+                               break;\r
+                       case 'P'-55: /* P - panning slide */\r
+                               UniEffect(UNI_XMEFFECTP,dat);\r
+                               break;\r
+                       case 'R'-55: /* R - multi retrig note */\r
+                               UniEffect(UNI_S3MEFFECTQ,dat);\r
+                               break;\r
+                       case 'T'-55: /* T - Tremor */\r
+                               UniEffect(UNI_S3MEFFECTI,dat);\r
+                               break;\r
+                       case 'X'-55:\r
+                               switch(dat>>4) {\r
+                                       case 1: /* X1 - Extra Fine Porta up */\r
+                                               UniEffect(UNI_XMEFFECTX1,dat&0xf);\r
+                                               break;\r
+                                       case 2: /* X2 - Extra Fine Porta down */\r
+                                               UniEffect(UNI_XMEFFECTX2,dat&0xf);\r
+                                               break;\r
+                               }\r
+                               break;\r
+                       default:\r
+                               if(eff<=0xf) {\r
+                                       /* the pattern jump destination is written in decimal,\r
+                                          but it seems some poor tracker software writes them\r
+                                          in hexadecimal... (sigh) */\r
+                                       if (eff==0xd)\r
+                                               /* don't change anything if we're sure it's in hexa */\r
+                                               if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9))\r
+                                                       /* otherwise, convert from dec to hex */\r
+                                                       dat=(((dat&0xf0)>>4)*10)+(dat&0xf);\r
+                                       UniPTEffect(eff,dat);\r
+                               }\r
+                               break;\r
+               }\r
+               UniNewline();\r
+               xmtrack++;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+static BOOL LoadPatterns(BOOL dummypat)\r
+{\r
+       int t,u,v,numtrk;\r
+\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       numtrk=0;\r
+       for(t=0;t<mh->numpat;t++) {\r
+               XMPATHEADER ph;\r
+\r
+               ph.size     =_mm_read_I_ULONG(modreader);\r
+               if (ph.size<(mh->version==0x0102?8:9)) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+               ph.packing  =_mm_read_UBYTE(modreader);\r
+               if(ph.packing) {\r
+                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+               if(mh->version==0x0102)\r
+                       ph.numrows  =_mm_read_UBYTE(modreader)+1;\r
+               else\r
+                       ph.numrows  =_mm_read_I_UWORD(modreader);\r
+               ph.packsize =_mm_read_I_UWORD(modreader);\r
+\r
+               ph.size-=(mh->version==0x0102?8:9);\r
+               if(ph.size)\r
+                       _mm_fseek(modreader,ph.size,SEEK_CUR);\r
+\r
+               of.pattrows[t]=ph.numrows;\r
+\r
+               if(ph.numrows) {\r
+                       if(!(xmpat=(XMNOTE*)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE))))\r
+                               return 0;\r
+\r
+                       /* when packsize is 0, don't try to load a pattern.. it's empty. */\r
+                       if(ph.packsize) \r
+                               for(u=0;u<ph.numrows;u++) \r
+                                       for(v=0;v<of.numchn;v++) {\r
+                                               if(!ph.packsize) break;\r
+\r
+                                               ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]);\r
+                                               if(ph.packsize<0) {\r
+                                                       free(xmpat);xmpat=NULL;\r
+                                                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                                                       return 0;\r
+                                               }\r
+                                       }\r
+\r
+                       if(ph.packsize) {\r
+                               _mm_fseek(modreader,ph.packsize,SEEK_CUR);\r
+                       }\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               free(xmpat);xmpat=NULL;\r
+                               _mm_errno=MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+\r
+                       for(v=0;v<of.numchn;v++)\r
+                               of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);\r
+\r
+                       free(xmpat);xmpat=NULL;\r
+               } else {\r
+                       for(v=0;v<of.numchn;v++)\r
+                               of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows);\r
+               }\r
+       }\r
+\r
+       if(dummypat) {\r
+               of.pattrows[t]=64;\r
+               if(!(xmpat=(XMNOTE*)_mm_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0;\r
+               for(v=0;v<of.numchn;v++)\r
+                       of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64);\r
+               free(xmpat);xmpat=NULL;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static void FixEnvelope(ENVPT *cur, int pts)\r
+{\r
+               int u, old, tmp;\r
+               ENVPT *prev;\r
+\r
+               /* Some broken XM editing program will only save the low byte\r
+                  of the position value. Try to compensate by adding the\r
+                  missing high byte. */\r
+\r
+               prev = cur++;\r
+               old = prev->pos;\r
+\r
+               for (u = 1; u < pts; u++, prev++, cur++) {\r
+                       if (cur->pos < prev->pos) {\r
+                               if (cur->pos < 0x100) {\r
+                                       if (cur->pos > old)     /* same hex century */\r
+                                                       tmp = cur->pos + (prev->pos - old);\r
+                                       else\r
+                                                       tmp = cur->pos | ((prev->pos + 0x100) & 0xff00);\r
+                                       old = cur->pos;\r
+                                       cur->pos = tmp;\r
+#ifdef MIKMOD_DEBUG\r
+                                       fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n",\r
+                                           u, pts, prev->pos, old, cur->pos);\r
+#endif\r
+                               } else {\r
+#ifdef MIKMOD_DEBUG\r
+                                       /* different brokenness style... fix unknown */\r
+                                       fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n",\r
+                                           u, pts, old, cur->pos);\r
+#endif\r
+                                       old = cur->pos;\r
+                               }\r
+                       } else\r
+                               old = cur->pos;\r
+               }\r
+}\r
+\r
+static BOOL LoadInstruments(void)\r
+{\r
+       int t,u;\r
+       INSTRUMENT *d;\r
+       ULONG next=0;\r
+       UWORD wavcnt=0;\r
+\r
+       if(!AllocInstruments()) return 0;\r
+       d=of.instruments;\r
+       for(t=0;t<of.numins;t++,d++) {\r
+               XMINSTHEADER ih;\r
+               long headend;\r
+\r
+               memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
+\r
+               /* read instrument header */\r
+               headend     = _mm_ftell(modreader);\r
+               ih.size     = _mm_read_I_ULONG(modreader);\r
+               headend    += ih.size;\r
+               _mm_read_string(ih.name, 22, modreader);\r
+               ih.type     = _mm_read_UBYTE(modreader);\r
+               ih.numsmp   = _mm_read_I_UWORD(modreader);\r
+\r
+               d->insname  = DupStr(ih.name,22,1);\r
+\r
+               if((SWORD)ih.size>29) {\r
+                       ih.ssize    = _mm_read_I_ULONG(modreader);\r
+                       if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) {\r
+                               XMPATCHHEADER pth;\r
+                               int p;\r
+\r
+                               _mm_read_UBYTES (pth.what,XMNOTECNT,modreader);\r
+                               _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader);\r
+                               _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader);\r
+                               pth.volpts      =  _mm_read_UBYTE(modreader);\r
+                               pth.panpts      =  _mm_read_UBYTE(modreader);\r
+                               pth.volsus      =  _mm_read_UBYTE(modreader);\r
+                               pth.volbeg      =  _mm_read_UBYTE(modreader);\r
+                               pth.volend      =  _mm_read_UBYTE(modreader);\r
+                               pth.pansus      =  _mm_read_UBYTE(modreader);\r
+                               pth.panbeg      =  _mm_read_UBYTE(modreader);\r
+                               pth.panend      =  _mm_read_UBYTE(modreader);\r
+                               pth.volflg      =  _mm_read_UBYTE(modreader);\r
+                               pth.panflg      =  _mm_read_UBYTE(modreader);\r
+                               pth.vibflg      =  _mm_read_UBYTE(modreader);\r
+                               pth.vibsweep    =  _mm_read_UBYTE(modreader);\r
+                               pth.vibdepth    =  _mm_read_UBYTE(modreader);\r
+                               pth.vibrate     =  _mm_read_UBYTE(modreader);\r
+                               pth.volfade     =  _mm_read_I_UWORD(modreader);\r
+\r
+                               /* read the remainder of the header\r
+                                  (2 bytes for 1.03, 22 for 1.04) */\r
+                               for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);\r
+\r
+                               /* we can't trust the envelope point count here, as some\r
+                                  modules have incorrect values (K_OSPACE.XM reports 32 volume\r
+                                  points, for example). */\r
+                               if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2;\r
+                               if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;\r
+\r
+                               if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {\r
+                                       if(nextwav) { free(nextwav);nextwav=NULL; }\r
+                                       if(wh) { free(wh);wh=NULL; }\r
+                                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                                       return 0;\r
+                               }\r
+\r
+                               for(u=0;u<XMNOTECNT;u++)\r
+                                       d->samplenumber[u]=pth.what[u]+of.numsmp;\r
+                               d->volfade = pth.volfade;\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define XM_ProcessEnvelope(name)                                                                               \\r
+                               for (u = 0; u < (XMENVCNT >> 1); u++) {                                 \\r
+                                       d-> name##env[u].pos = pth. name##env[u << 1];          \\r
+                                       d-> name##env[u].val = pth. name##env[(u << 1)+ 1];     \\r
+                               }                                                                                                               \\r
+                               if (pth. name##flg&1) d-> name##flg|=EF_ON;                             \\r
+                               if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN;                \\r
+                               if (pth. name##flg&4) d-> name##flg|=EF_LOOP;                   \\r
+                               d-> name##susbeg=d-> name##susend=pth. name##sus;               \\r
+                               d-> name##beg=pth. name##beg;                                                   \\r
+                               d-> name##end=pth. name##end;                                                   \\r
+                               d-> name##pts=pth. name##pts;                                                   \\r
+                                                                                                                                               \\r
+                               /* scale envelope */                                                                    \\r
+                               for (p=0;p<XMENVCNT/2;p++)                                                              \\r
+                                       d-> name##env[p].val<<=2;                                                       \\r
+                                                                                                                                               \\r
+                               if ((d-> name##flg&EF_ON)&&(d-> name##pts<2))                   \\r
+                                       d-> name##flg&=~EF_ON\r
+#else\r
+#define XM_ProcessEnvelope(name)                                                                                       \\r
+                               for (u = 0; u < (XMENVCNT >> 1); u++) {                                         \\r
+                                       d-> name/**/env[u].pos = pth. name/**/env[u << 1];              \\r
+                                       d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \\r
+                               }                                                                                                                       \\r
+                               if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON;                         \\r
+                               if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN;            \\r
+                               if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP;                       \\r
+                               d-> name/**/susbeg=d-> name/**/susend=                                          \\r
+                                                     pth. name/**/sus;                                         \\r
+                               d-> name/**/beg=pth. name/**/beg;                                                       \\r
+                               d-> name/**/end=pth. name/**/end;                                                       \\r
+                               d-> name/**/pts=pth. name/**/pts;                                                       \\r
+                                                                                                                                                       \\r
+                               /* scale envelope */                                                                            \\r
+                               for (p=0;p<XMENVCNT/2;p++)                                                                      \\r
+                                       d-> name/**/env[p].val<<=2;                                                             \\r
+                                                                                                                                                       \\r
+                               if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))                       \\r
+                                       d-> name/**/flg&=~EF_ON\r
+#endif                 \r
+\r
+                               XM_ProcessEnvelope(vol);\r
+                               XM_ProcessEnvelope(pan);\r
+#undef XM_ProcessEnvelope\r
+\r
+                               if (d->volflg & EF_ON)\r
+                                       FixEnvelope(d->volenv, d->volpts);\r
+                               if (d->panflg & EF_ON)\r
+                                       FixEnvelope(d->panenv, d->panpts);\r
+\r
+                               /* Samples are stored outside the instrument struct now, so we\r
+                                  have to load them all into a temp area, count the of.numsmp\r
+                                  along the way and then do an AllocSamples() and move\r
+                                  everything over */\r
+                               if(mh->version>0x0103) next = 0;\r
+                               for(u=0;u<ih.numsmp;u++,s++) {\r
+                                       /* Allocate more room for sample information if necessary */\r
+                                       if(of.numsmp+u==wavcnt) {\r
+                                               wavcnt+=XM_SMPINCR;\r
+                                               if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))){\r
+                                                       if(wh) { free(wh);wh=NULL; }\r
+                                                       _mm_errno = MMERR_OUT_OF_MEMORY;\r
+                                                       return 0;\r
+                                               }\r
+                                               if(!(wh=realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {\r
+                                                       free(nextwav);nextwav=NULL;\r
+                                                       _mm_errno = MMERR_OUT_OF_MEMORY;\r
+                                                       return 0;\r
+                                               }\r
+                                               s=wh+(wavcnt-XM_SMPINCR);\r
+                                       }\r
+\r
+                                       s->length       =_mm_read_I_ULONG (modreader);\r
+                                       s->loopstart    =_mm_read_I_ULONG (modreader);\r
+                                       s->looplength   =_mm_read_I_ULONG (modreader);\r
+                                       s->volume       =_mm_read_UBYTE (modreader);\r
+                                       s->finetune     =_mm_read_SBYTE (modreader);\r
+                                       s->type         =_mm_read_UBYTE (modreader);\r
+                                       s->panning      =_mm_read_UBYTE (modreader);\r
+                                       s->relnote      =_mm_read_SBYTE (modreader);\r
+                                       s->vibtype      = pth.vibflg;\r
+                                       s->vibsweep     = pth.vibsweep;\r
+                                       s->vibdepth     = pth.vibdepth*4;\r
+                                       s->vibrate      = pth.vibrate;\r
+                                       s->reserved     =_mm_read_UBYTE (modreader);\r
+                                       _mm_read_string(s->samplename, 22, modreader);\r
+\r
+                                       nextwav[of.numsmp+u]=next;\r
+                                       next+=s->length;\r
+\r
+                                       if(_mm_eof(modreader)) {\r
+                                               free(nextwav);free(wh);\r
+                                               nextwav=NULL;wh=NULL;\r
+                                               _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                                               return 0;\r
+                                       }\r
+                               }\r
+\r
+                               if(mh->version>0x0103) {\r
+                                       for(u=0;u<ih.numsmp;u++)\r
+                                               nextwav[of.numsmp++]+=_mm_ftell(modreader);\r
+                                       _mm_fseek(modreader,next,SEEK_CUR);\r
+                               } else\r
+                                       of.numsmp+=ih.numsmp;\r
+                       } else {\r
+                               /* read the remainder of the header */\r
+                               for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);\r
+\r
+                               if(_mm_eof(modreader)) {\r
+                                       free(nextwav);free(wh);\r
+                                       nextwav=NULL;wh=NULL;\r
+                                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                                       return 0;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* sanity check */\r
+       if(!of.numsmp) {\r
+               if(nextwav) { free(nextwav);nextwav=NULL; }\r
+               if(wh) { free(wh);wh=NULL; }\r
+               _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+               return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL XM_Load(BOOL curious)\r
+{\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       int t,u;\r
+       BOOL dummypat=0;\r
+       char tracker[21],modtype[60];\r
+       (void)curious;\r
+\r
+       /* try to read module header */\r
+       _mm_read_string(mh->id,17,modreader);\r
+       _mm_read_string(mh->songname,21,modreader);\r
+       _mm_read_string(mh->trackername,20,modreader);\r
+       mh->version     =_mm_read_I_UWORD(modreader);\r
+       if((mh->version<0x102)||(mh->version>0x104)) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       mh->headersize  =_mm_read_I_ULONG(modreader);\r
+       mh->songlength  =_mm_read_I_UWORD(modreader);\r
+       mh->restart     =_mm_read_I_UWORD(modreader);\r
+       mh->numchn      =_mm_read_I_UWORD(modreader);\r
+       mh->numpat      =_mm_read_I_UWORD(modreader);\r
+       mh->numins      =_mm_read_I_UWORD(modreader);\r
+       mh->flags       =_mm_read_I_UWORD(modreader);\r
+       mh->tempo       =_mm_read_I_UWORD(modreader);\r
+       mh->bpm         =_mm_read_I_UWORD(modreader);\r
+       if(!mh->bpm) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       _mm_read_UBYTES(mh->orders,256,modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+       of.initspeed = mh->tempo;         \r
+       of.inittempo = mh->bpm;\r
+       strncpy(tracker,mh->trackername,20);tracker[20]=0;\r
+       for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0;\r
+       \r
+       /* some modules have the tracker name empty */\r
+       if (!tracker[0])\r
+               strcpy(tracker,"Unknown tracker");\r
+\r
+#ifdef HAVE_SNPRINTF\r
+       snprintf(modtype,60,"%s (XM format %d.%02d)",\r
+                           tracker,mh->version>>8,mh->version&0xff);\r
+#else\r
+       sprintf(modtype,"%s (XM format %d.%02d)",\r
+                       tracker,mh->version>>8,mh->version&0xff);\r
+#endif\r
+       of.modtype   = strdup(modtype);\r
+       of.numchn    = mh->numchn;\r
+       of.numpat    = mh->numpat;\r
+       of.numtrk    = (UWORD)of.numpat*of.numchn;   /* get number of channels */\r
+       of.songname  = DupStr(mh->songname,20,1);\r
+       of.numpos    = mh->songlength;               /* copy the songlength */\r
+       of.reppos    = mh->restart<mh->songlength?mh->restart:0;\r
+       of.numins    = mh->numins;\r
+       of.flags    |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS |\r
+                                  UF_PANNING;\r
+       if(mh->flags&1) of.flags |= UF_LINEAR;\r
+       of.bpmlimit  = 32;\r
+\r
+       memset(of.chanvol,64,of.numchn);             /* store channel volumes */\r
+\r
+       if(!AllocPositions(of.numpos+1)) return 0;\r
+       for(t=0;t<of.numpos;t++)\r
+               of.positions[t]=mh->orders[t];\r
+\r
+       /* We have to check for any pattern numbers in the order list greater than\r
+          the number of patterns total. If one or more is found, we set it equal to\r
+          the pattern total and make a dummy pattern to workaround the problem */\r
+       for(t=0;t<of.numpos;t++) {\r
+               if(of.positions[t]>=of.numpat) {\r
+                       of.positions[t]=of.numpat;\r
+                       dummypat=1;\r
+               }\r
+       }\r
+       if(dummypat) {\r
+               of.numpat++;of.numtrk+=of.numchn;\r
+       }\r
+\r
+       if(mh->version<0x0104) {\r
+               if(!LoadInstruments()) return 0;\r
+               if(!LoadPatterns(dummypat)) return 0;\r
+               for(t=0;t<of.numsmp;t++)\r
+                       nextwav[t]+=_mm_ftell(modreader);\r
+       } else {\r
+               if(!LoadPatterns(dummypat)) return 0;\r
+               if(!LoadInstruments()) return 0;\r
+       }\r
+\r
+       if(!AllocSamples()) {\r
+               free(nextwav);free(wh);\r
+               nextwav=NULL;wh=NULL;\r
+               return 0;\r
+       }\r
+       q = of.samples;\r
+       s = wh;\r
+       for(u=0;u<of.numsmp;u++,q++,s++) {\r
+               q->samplename   = DupStr(s->samplename,22,1);\r
+               q->length       = s->length;\r
+               q->loopstart    = s->loopstart;\r
+               q->loopend      = s->loopstart+s->looplength;\r
+               q->volume       = s->volume;\r
+               q->speed        = s->finetune+128;\r
+               q->panning      = s->panning;\r
+               q->seekpos      = nextwav[u];\r
+               q->vibtype      = s->vibtype;\r
+               q->vibsweep     = s->vibsweep;\r
+               q->vibdepth     = s->vibdepth;\r
+               q->vibrate      = s->vibrate;\r
+\r
+               if(s->type & 0x10) {\r
+                       q->length    >>= 1;\r
+                       q->loopstart >>= 1;\r
+                       q->loopend   >>= 1;\r
+               }\r
+\r
+               q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED;\r
+               if(s->type&0x3) q->flags|=SF_LOOP;\r
+               if(s->type&0x2) q->flags|=SF_BIDI;\r
+               if(s->type&0x10) q->flags|=SF_16BITS;\r
+       }\r
+\r
+       d=of.instruments;\r
+       s=wh;\r
+       for(u=0;u<of.numins;u++,d++)\r
+               for(t=0;t<XMNOTECNT;t++) {\r
+                       if (d->samplenumber[t]>=of.numsmp)\r
+                               d->samplenote[t]=255;\r
+                       else {\r
+                               int note=t+s[d->samplenumber[t]].relnote;\r
+                               d->samplenote[t]=(note<0)?0:note;\r
+                       }\r
+               }\r
+\r
+       free(wh);free(nextwav);\r
+       wh=NULL;nextwav=NULL;\r
+       return 1;\r
+}\r
+\r
+CHAR *XM_LoadTitle(void)\r
+{\r
+       CHAR s[21];\r
+\r
+       _mm_fseek(modreader,17,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,21,modreader)) return NULL;\r
+\r
+       return(DupStr(s,21,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_xm={\r
+       NULL,\r
+       "XM",\r
+       "XM (FastTracker 2)",\r
+       XM_Init,\r
+       XM_Test,\r
+       XM_Load,\r
+       XM_Cleanup,\r
+       XM_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
new file mode 100644 (file)
index 0000000..3ec91bd
--- /dev/null
@@ -0,0 +1,348 @@
+/***************************************************************************\r
+ *             __________               __   ___.\r
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___\r
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /\r
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <\r
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \\r
+ *                     \/            \/     \/    \/            \/\r
+ *\r
+ *\r
+ * All files in this archive are subject to the GNU General Public License.\r
+ * See the file COPYING in the source tree root for full license agreement.\r
+ *\r
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY\r
+ * KIND, either express or implied.\r
+ *\r
+ ****************************************************************************/\r
+#include "plugin.h"\r
+#include "mikmod_build.h"\r
+\r
+PLUGIN_HEADER\r
+\r
+struct plugin_api *rb;\r
+\r
+MODULE *module;\r
+\r
+#define MAXPCMBUFFERS 16 // Do NOT set this to a value lower than 2 or playback will break\r
+#define PCMBUFFERSIZE 65536\r
+\r
+char *pcmbufs[MAXPCMBUFFERS];\r
+int bufferlen[MAXPCMBUFFERS];\r
+int buffercount = 0;\r
+\r
+int curbuff = 0;\r
+int lastbuff = 0;\r
+\r
+size_t buffrendered = 0;\r
+size_t buffplayed = 0;\r
+size_t buff_last = ~0;\r
+\r
+int vol, minvol, maxvol;\r
+int lastpower = 0, lastvol = 0;\r
+int lastbutton = 0;\r
+\r
+char sbuf[32];\r
+\r
+int mallocbufsize;\r
+char *mbuf;\r
+\r
+\r
+void mikmod_prepare_malloc(char *buff, int bufsize);\r
+long mikmod_get_malloc_usage(void);\r
+void* mikmod_malloc(size_t size);\r
+\r
+\r
+\r
+int FindLastOccurrenceChar(char *string, char chr)\r
+{\r
+       int i = 0;\r
+       //int LastOcc = -1;\r
+       int LastOcc = 0;\r
+\r
+       while (string[i] != 0)\r
+       {\r
+               if (string[i] == chr)\r
+               {\r
+                       LastOcc = i;\r
+               }\r
+\r
+               i++;\r
+       }\r
+\r
+       return LastOcc;\r
+}\r
+\r
+\r
+void get_more(unsigned char **start, size_t *size)\r
+       {\r
+               if (curbuff >= (buffercount - 1))\r
+               {\r
+                       curbuff = 0;\r
+               }\r
+               else\r
+               {\r
+                       curbuff++;\r
+               }\r
+               *start = pcmbufs[curbuff];\r
+               *size  = bufferlen[curbuff];\r
+               buffplayed++;\r
+       }\r
+\r
+\r
+void checkbutton(void)\r
+{\r
+       lastbutton = rb->button_get(false);\r
+       if (lastbutton & BUTTON_MENU)\r
+       {\r
+               return;\r
+       }\r
+\r
+       switch (lastbutton)\r
+       {\r
+               case BUTTON_SCROLL_FWD:\r
+               case (BUTTON_SCROLL_FWD | BUTTON_REPEAT):\r
+                       vol = rb->global_settings->volume;\r
+\r
+                       if (vol < maxvol)\r
+                       {\r
+                               vol++;\r
+                               rb->sound_set(SOUND_VOLUME, vol);\r
+                               rb->global_settings->volume = vol;\r
+                       }\r
+                       break;\r
+\r
+               case BUTTON_SCROLL_BACK:\r
+               case (BUTTON_SCROLL_BACK | BUTTON_REPEAT):\r
+                       vol = rb->global_settings->volume;\r
+\r
+                       if (vol > minvol)\r
+                       {\r
+                               vol--;\r
+                               rb->sound_set(SOUND_VOLUME, vol);\r
+                               rb->global_settings->volume = vol;\r
+                       }\r
+                       break;\r
+\r
+               case (BUTTON_PLAY | BUTTON_REL):\r
+\r
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+       rb->cpu_boost(false); // Just in case we got called from inside the render loop\r
+#endif\r
+                       rb->pcm_play_pause(false);\r
+                       do /* code from mpegplayer, *very* simple unpause loop */\r
+                       {\r
+                               lastbutton = rb->button_get(true);\r
+                               if (lastbutton == BUTTON_MENU)\r
+                               {\r
+                                       return;\r
+                               }\r
+                       } while (lastbutton != (BUTTON_PLAY | BUTTON_REL));\r
+                       rb->pcm_play_pause(true);\r
+                       break;\r
+\r
+               default:\r
+                       if(rb->default_event_handler(lastbutton) == SYS_USB_CONNECTED)\r
+                       {\r
+                               return;\r
+                       }\r
+       } /* switch(button) */\r
+\r
+       if ((rb->global_settings->volume != lastvol) || (rb->battery_level() != lastpower))\r
+       {\r
+               lastpower = rb->battery_level();\r
+               lastvol = rb->global_settings->volume;\r
+               \r
+               rb->snprintf(sbuf, sizeof(sbuf) - 1, "%d dB   ", rb->global_settings->volume);\r
+               rb->lcd_puts(5, 3, sbuf);\r
+               rb->snprintf(sbuf, sizeof(sbuf) - 1, "%d %%   ", rb->battery_level());\r
+               rb->lcd_puts(5, 4, sbuf);\r
+\r
+               rb->lcd_update();\r
+       }\r
+       lastbutton = 0;\r
+}\r
+\r
+\r
+void mainloop(void)\r
+{\r
+       int i;\r
+\r
+       minvol = rb->sound_min(SOUND_VOLUME);\r
+       maxvol = rb->sound_max(SOUND_VOLUME);\r
+\r
+       while (buffplayed <= buff_last && !lastbutton)\r
+       {\r
+               while (curbuff != lastbuff && !lastbutton) // Render loop, fills up all buffers except the one being played\r
+               {\r
+\r
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+       rb->cpu_boost(true);\r
+#endif\r
+\r
+                       checkbutton();\r
+\r
+                       if (Player_Active())\r
+                       {\r
+                               bufferlen[lastbuff] = VC_WriteBytes(pcmbufs[lastbuff], PCMBUFFERSIZE);\r
+                               buffrendered++;\r
+                       }\r
+                       else\r
+                       {\r
+                               // No more data to render (songend) - clear the next buffer so get_more() can return it a last time\r
+                               for (i = 0; i < PCMBUFFERSIZE; i++)\r
+                                       (pcmbufs[lastbuff])[i] = 0;\r
+                               bufferlen[lastbuff] = PCMBUFFERSIZE;\r
+                               buff_last = buffrendered;\r
+                       }\r
+\r
+                       if (lastbuff >= (buffercount - 1))\r
+                               lastbuff = 0;\r
+                       else\r
+                               lastbuff++;\r
+\r
+                       checkbutton();\r
+                       rb->reset_poweroff_timer();\r
+\r
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+       rb->cpu_boost(false);\r
+#endif\r
+\r
+               }\r
+\r
+               checkbutton();\r
+\r
+               rb->yield();\r
+\r
+       } /* while */\r
+\r
+} /* mainloop */\r
+\r
+\r
+\r
+\r
+enum plugin_status plugin_start(struct plugin_api *api, void *parameter)\r
+{\r
+       bool talk_menu;\r
+       int i;\r
+\r
+       rb = api;\r
+\r
+       /* Have to shut up voice menus or it will mess up our waveform playback */\r
+       talk_menu = rb->global_settings->talk_menu;\r
+       rb->global_settings->talk_menu = false;\r
+\r
+       rb->audio_stop();\r
+       rb->pcm_play_stop();\r
+       rb->pcm_set_frequency(44100);\r
+\r
+       // Initialize internal semi-dynamic memory\r
+       mbuf = rb->plugin_get_audio_buffer(&mallocbufsize);\r
+       mikmod_prepare_malloc(mbuf, mallocbufsize);\r
+\r
+\r
+       // Allocate PCM output buffers\r
+       for (i = 0; i < MAXPCMBUFFERS; i++)\r
+       {\r
+               if ((pcmbufs[i] = mikmod_malloc(PCMBUFFERSIZE)) == NULL)\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+       buffercount = i;\r
+       //lastbuff = buffercount - 1;\r
+       // Prefill buffers !\r
+\r
+\r
+       // General output...\r
+       rb->lcd_clear_display();\r
+       rb->lcd_puts(0, 0, " MikMod for Rockbox 0.1");\r
+       rb->lcd_puts(0, 1, "========================");\r
+\r
+       rb->lcd_puts(0, 3, "Vol: -");\r
+       rb->lcd_puts(0, 4, "Pwr: -");\r
+       rb->lcd_puts(0, 5, "---------");\r
+       rb->lcd_puts(0, 6, "File:");\r
+       rb->lcd_puts(7, 6, &((char*)parameter)[FindLastOccurrenceChar(parameter, '/') + 1]);\r
+\r
+       rb->lcd_update();\r
+\r
+       //initialize the library\r
+       MikMod_RegisterAllLoaders();\r
+       md_mode = DMODE_SOFT_MUSIC | DMODE_16BITS | DMODE_STEREO | DMODE_INTERP | DMODE_SOFT_SNDFX;\r
+\r
+       if (!MikMod_Init(""))\r
+       {\r
+               #ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+                       rb->cpu_boost(true);\r
+               #endif\r
+               //load module\r
+               module = Player_Load(parameter, 32, 1);\r
+\r
+               #ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+                       rb->cpu_boost(false);\r
+               #endif\r
+\r
+               if (module)\r
+               {\r
+                       Player_Start(module);\r
+#ifndef SIMULATOR\r
+                       rb->ata_sleep();\r
+#endif\r
+\r
+                       rb->snprintf(sbuf, sizeof(sbuf) - 1, "Memory: %d / %d", (int)(mikmod_get_malloc_usage() - (buffercount * PCMBUFFERSIZE)), mallocbufsize);\r
+                       rb->lcd_puts(0, 16, sbuf);\r
+\r
+                       rb->lcd_puts(0, 7, "Type:");\r
+                       rb->lcd_puts(7, 7, module->modtype);\r
+\r
+                       rb->lcd_puts(0, 9, "Title:");\r
+                       rb->lcd_puts_scroll(7, 9, module->songname);\r
+\r
+                       rb->lcd_update();\r
+\r
+                       // Only prefill the first buffer so we get a quick start...\r
+                       bufferlen[0] = VC_WriteBytes(pcmbufs[0], PCMBUFFERSIZE);\r
+\r
+                       curbuff = buffercount - 1;\r
+                       lastbuff = 1; // Fixes skip during first buffers played\r
+\r
+                       rb->pcm_play_data(get_more, NULL, 0);\r
+\r
+                       mainloop();\r
+\r
+               }\r
+               else /* module */\r
+               {\r
+                       rb->splash(HZ*2, "Could not load module, reason:");\r
+                       rb->splash(HZ*2, MikMod_strerror(MikMod_errno));\r
+               }\r
+       }\r
+       else /* MikMod_Init */\r
+       {\r
+               rb->splash(HZ*2, "Could not initialize sound, reason:");\r
+               rb->splash(HZ*2, MikMod_strerror(MikMod_errno));\r
+       }\r
+\r
+\r
+       #ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+               rb->cpu_boost(false);\r
+       #endif\r
+\r
+       rb->pcm_play_stop();\r
+\r
+       Player_Stop();\r
+       Player_Free(module);\r
+       MikMod_Exit();\r
+\r
+\r
+       //restore default - user of apis is responsible for restoring\r
+       //   default state - normally playback at 44100Hz\r
+       rb->pcm_set_frequency(HW_SAMPR_DEFAULT);\r
+       rb->global_settings->talk_menu = talk_menu;\r
+\r
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ\r
+       rb->cpu_boost(false);\r
+#endif\r
+\r
+       return PLUGIN_OK;\r
+}\r
diff --git a/apps/plugins/mikmod/mmio/mmalloc.c b/apps/plugins/mikmod/mmio/mmalloc.c
new file mode 100644 (file)
index 0000000..7f7fdbf
--- /dev/null
@@ -0,0 +1,259 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mmalloc.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Dynamic memory routines\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+\r
+size_t mem_offset = 0;\r
+char *mallocbuf = NULL;\r
+size_t mallocbuflen = 0;\r
+\r
+\r
+size_t mikmod_get_mbuffsize(size_t *buff)\r
+{\r
+       return buff[-1];\r
+}\r
+\r
+\r
+void mikmod_prepare_malloc(char *buff, int bufsize)\r
+{\r
+       mallocbuf = buff;\r
+       mallocbuflen = bufsize;\r
+       mem_offset = 0;\r
+}\r
+\r
+long mikmod_get_malloc_usage(void)\r
+{\r
+       return mem_offset;\r
+}\r
+\r
+int mikmod_abs(int num)\r
+{\r
+       if (num < 0)\r
+               return (num * -1);\r
+       else\r
+               return (num);\r
+}\r
+\r
+void* mikmod_memset(char *buf, int val, size_t count)\r
+{\r
+       size_t i;\r
+\r
+       for (i = 0; i < count; i++)\r
+       {\r
+               buf[i] = val;\r
+       }\r
+       return buf;\r
+}\r
+\r
+/* 'Poor man's malloc' taken from rockbox codeclib.c */\r
+void* mikmod_malloc(size_t size)\r
+{\r
+    void* x;\r
+\r
+       if (!mallocbuf)\r
+               return NULL;\r
+    if (mem_offset + (long)size + 4 > mallocbuflen)\r
+        return NULL;\r
+\r
+       mem_offset += 4;\r
+\r
+    x = &mallocbuf[mem_offset];\r
+       ((size_t*)x)[-1] = size;\r
+\r
+       mem_offset += (size + 3) & ~3; /* Keep memory 32-bit aligned */\r
+\r
+\r
+       memset(x, 0, size);\r
+\r
+    return(x);\r
+}\r
+\r
+void* mikmod_calloc(size_t nmemb, size_t size)\r
+{\r
+    void *x;\r
+    x = mikmod_malloc(nmemb * size);\r
+    if (x == NULL)\r
+        return NULL;\r
+    //memset(x, 0, nmemb*size); /* already done in mikmod_malloc() */\r
+    return(x);\r
+}\r
+\r
+void mikmod_free(void* ptr) {\r
+    (void)ptr;\r
+}\r
+\r
+void* mikmod_realloc(void* ptr, size_t size)\r
+{\r
+    void* x;\r
+    //(void)ptr;\r
+    x = mikmod_malloc(size);\r
+       if (ptr != NULL)\r
+       {\r
+               if (mikmod_get_mbuffsize(ptr) < size)\r
+               {\r
+                       memcpy(x, ptr, mikmod_get_mbuffsize(ptr));\r
+               }\r
+               else\r
+               {\r
+                       memcpy(x, ptr, size);\r
+               }\r
+       }\r
+    return(x);\r
+}\r
+\r
+unsigned int mikmod_strlen(const char *string)\r
+{\r
+       unsigned int i;\r
+       for (i = 0; string[i] != 0; i++);\r
+       return i;\r
+}\r
+\r
+char* mikmod_strdup(const char *srcbuf)\r
+{\r
+       char *newbuf;\r
+       unsigned int i, len;\r
+\r
+       len = mikmod_strlen(srcbuf);\r
+       newbuf = mikmod_malloc(len + 1);\r
+       \r
+       if (newbuf)\r
+       {\r
+               for (i = 0; i <= len; i++)\r
+                       newbuf[i] = srcbuf[i];\r
+       }\r
+       return newbuf;\r
+}\r
+\r
+char* mikmod_strncat(char *dest, const char *src, size_t count)\r
+{\r
+       size_t i, j;\r
+       j = mikmod_strlen(dest);\r
+\r
+       for(i = 0; i < count; i++)\r
+       {\r
+               if (src[i] == 0)\r
+                       break;\r
+               dest[i + j] = src[i];\r
+       }\r
+       return dest;\r
+}\r
+\r
+int mikmod_memcmp(const char *buf1, const char *buf2, size_t count)\r
+{\r
+       size_t i;\r
+\r
+       for(i = 0; i < count; i++)\r
+       {\r
+               if (buf1[i] > buf2[i])\r
+                       return 1;\r
+               if (buf1[i] < buf2[i])\r
+                       return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+char* mikmod_strstr(char *str, char *search)\r
+{\r
+       size_t i, j, k;\r
+\r
+       if (!mikmod_strlen(search))\r
+               return str;\r
+\r
+       j = mikmod_strlen(str);\r
+       k = mikmod_strlen(search);\r
+\r
+       for (i = 0; i < (j - k); i++)\r
+       {\r
+               if (!mikmod_memcmp(str, search, k))\r
+                       return &str[i];\r
+       }\r
+       return NULL;\r
+}\r
+\r
+int mikmod_toupper(int character)\r
+{\r
+       if ((character > 96) && (character < 123))\r
+               return (character - 32);\r
+       else\r
+               return character;\r
+}\r
+\r
+int mikmod_isalnum(int character)\r
+{\r
+       if ((character > 96) && (character < 123))\r
+               return character;\r
+       if ((character > 64) && (character < 91))\r
+               return character;\r
+       if ((character > 47) && (character < 58))\r
+               return character;\r
+       return 0;\r
+}\r
+\r
+int mikmod_isdigit(char c)\r
+{\r
+    return (c >= '0') && (c <= '9');\r
+}\r
+\r
+\r
+/****************************************************\r
+ * 'Original' MikMod code goes here\r
+ *\r
+ ****************************************************/\r
+\r
+/* Same as malloc, but sets error variable _mm_error when fails */\r
+void* _mm_malloc(size_t size)\r
+{\r
+       void *d;\r
+\r
+       //if(!(d=mikmod_malloc(size))) {\r
+       if(!(d=mikmod_malloc(size))) {\r
+               _mm_errno = MMERR_OUT_OF_MEMORY;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+       }\r
+       memset(d, 0, size);\r
+       return d;\r
+}\r
+\r
+/* Same as calloc, but sets error variable _mm_error when fails */\r
+void* _mm_calloc(size_t nitems,size_t size)\r
+{\r
+       void *d;\r
+   \r
+       if(!(d=mikmod_calloc(nitems,size))) {\r
+               _mm_errno = MMERR_OUT_OF_MEMORY;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+       }\r
+       return d;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/mmio/mmerror.c b/apps/plugins/mikmod/mmio/mmerror.c
new file mode 100644 (file)
index 0000000..94d0122
--- /dev/null
@@ -0,0 +1,197 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mmerror.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Error handling functions.\r
+  Register an error handler with _mm_RegisterErrorHandler() and you're all set.\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+       The global variables _mm_errno, and _mm_critical are set before the error\r
+       handler in called.  See below for the values of these variables.\r
+\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+CHAR *_mm_errmsg[MMERR_MAX+1] =\r
+{\r
+/* No error */\r
+\r
+       "No error",\r
+\r
+/* Generic errors */\r
+\r
+       "Could not open requested file",\r
+       "Out of memory",\r
+       "Dynamic linking failed",\r
+\r
+/* Sample errors */\r
+\r
+       "Out of memory to load sample",\r
+       "Out of sample handles to load sample",\r
+       "Sample format not recognized",\r
+\r
+/* Module errors */\r
+\r
+       "Failure loading module pattern",\r
+       "Failure loading module track",\r
+       "Failure loading module header",\r
+       "Failure loading sampleinfo",\r
+       "Module format not recognized",\r
+       "Module sample format not recognized",\r
+       "Synthsounds not supported in MED files",\r
+       "Compressed sample is invalid",\r
+\r
+/* Driver errors: */\r
+\r
+       "Sound device not detected",\r
+       "Device number out of range",\r
+       "Software mixer failure",\r
+       "Could not open sound device",\r
+       "This driver supports 8 bit linear output only",\r
+       "This driver supports 16 bit linear output only",\r
+       "This driver supports stereo output only",\r
+       "This driver supports uLaw output (8 bit mono, 8 kHz) only",\r
+       "Unable to set non-blocking mode for audio device",\r
+\r
+/* AudioFile driver errors  */\r
+\r
+       "Cannot find suitable AudioFile audio port",\r
+\r
+/* AIX driver errors */\r
+\r
+       "Configuration (init step) of audio device failed",\r
+       "Configuration (control step) of audio device failed",\r
+       "Configuration (start step) of audio device failed",\r
+\r
+/* ALSA driver errors */\r
+\r
+/* EsounD driver errors */\r
+\r
+/* Ultrasound driver errors */\r
+\r
+       "Ultrasound driver only works in 16 bit stereo 44 KHz",\r
+       "Ultrasound card could not be reset",\r
+       "Could not start Ultrasound timer",\r
+\r
+/* HP driver errors  */\r
+\r
+       "Unable to select 16bit-linear sample format",\r
+       "Could not select requested sample-rate",\r
+       "Could not select requested number of channels",\r
+       "Unable to select audio output",\r
+       "Unable to get audio description",\r
+       "Could not set transmission buffer size",\r
+\r
+/* Open Sound System driver errors */\r
+\r
+       "Could not set fragment size",\r
+       "Could not set sample size",\r
+       "Could not set mono/stereo setting",\r
+       "Could not set sample rate",\r
+\r
+/* SGI driver errors */\r
+\r
+       "Unsupported sample rate",\r
+       "Hardware does not support 16 bit sound",\r
+       "Hardware does not support 8 bit sound",\r
+       "Hardware does not support stereo sound",\r
+       "Hardware does not support mono sound",\r
+\r
+/* Sun driver errors */\r
+\r
+       "Sound device initialization failed",\r
+\r
+/* OS/2 drivers errors */\r
+\r
+       "Could not set mixing parameters",\r
+       "Could not create playback semaphores",\r
+       "Could not create playback timer",\r
+       "Could not create playback thread",\r
+\r
+/* DirectSound driver errors */\r
+\r
+       "Could not set playback priority",\r
+       "Could not create playback buffers",\r
+       "Could not set playback format",\r
+       "Could not register callback",\r
+       "Could not register event",\r
+       "Could not create playback thread",\r
+       "Could not initialize playback thread",\r
+\r
+/* Windows Multimedia API driver errors */\r
+\r
+       "Invalid device handle",\r
+       "The resource is already allocated",\r
+       "Invalid device identifier",\r
+       "Unsupported output format",\r
+       "Unknown error",\r
+\r
+/* Macintosh driver errors */\r
+\r
+       "Unsupported sample rate",\r
+       "Could not start playback",\r
+\r
+/* Invalid error */\r
+\r
+       "Invalid error code"\r
+};\r
+\r
+MIKMODAPI char *MikMod_strerror(int code)\r
+{\r
+       if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1;\r
+       return _mm_errmsg[code];\r
+}\r
+\r
+/* User installed error callback */\r
+MikMod_handler_t _mm_errorhandler = NULL;\r
+MIKMODAPI int  _mm_errno = 0;\r
+MIKMODAPI BOOL _mm_critical = 0;\r
+\r
+MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc)\r
+{\r
+       MikMod_handler_t oldproc=_mm_errorhandler;\r
+\r
+       _mm_errorhandler = proc;\r
+       return oldproc;\r
+}\r
+\r
+MIKMODAPI MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc)\r
+{\r
+       MikMod_handler_t result;\r
+\r
+       MUTEX_LOCK(vars);\r
+               result=_mm_registererrorhandler(proc);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/mmio/mmio.c b/apps/plugins/mikmod/mmio/mmio.c
new file mode 100644 (file)
index 0000000..50269fb
--- /dev/null
@@ -0,0 +1,427 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mmio.c,v 1.2 2004/02/06 19:29:05 raph Exp $\r
+\r
+  Portable file I/O routines\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+       The way this module works:\r
+\r
+       - _mm_fopen will call the errorhandler [see mmerror.c] in addition to\r
+         setting _mm_errno on exit.\r
+       - _mm_iobase is for internal use.  It is used by Player_LoadFP to\r
+         ensure that it works properly with wad files.\r
+       - _mm_read_I_* and _mm_read_M_* differ : the first is for reading data\r
+         written by a little endian (intel) machine, and the second is for reading\r
+         big endian (Mac, RISC, Alpha) machine data.\r
+       - _mm_write functions work the same as the _mm_read functions.\r
+       - _mm_read_string is for reading binary strings.  It is basically the same\r
+         as an fread of bytes.\r
+\r
+*/\r
+\r
+/* FIXME\r
+       the _mm_iobase variable ought to be MREADER-specific. It will eventually\r
+       become a private field of the MREADER structure, but this will require a\r
+       soname version bump.\r
+\r
+       In the meantime, the drawback is that if you use the xxx_LoadFP functions,\r
+       you can't have several MREADER objects with different iobase values.\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#define COPY_BUFSIZE  1024\r
+\r
+static long _mm_iobase=0,temp_iobase=0;\r
+\r
+\r
+int _mm_fopen(CHAR* fname,int attrib)\r
+{\r
+       int fp;\r
+\r
+       fp=rb->open(fname,attrib);\r
+       if(fp == -1) {\r
+               fp = 0;\r
+               _mm_errno = MMERR_OPENING_FILE;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+       }\r
+       return fp;\r
+}\r
+\r
+BOOL _mm_FileExists(CHAR* fname)\r
+{\r
+       int fp;\r
+\r
+       if(!(fp=rb->open(fname, O_RDONLY))) return 0;\r
+       rb->close(fp);\r
+\r
+       return 1;\r
+}\r
+\r
+int _mm_fclose(int fp)\r
+{\r
+       return rb->close(fp);\r
+}\r
+\r
+/* Sets the current file-position as the new _mm_iobase */\r
+void _mm_iobase_setcur(MREADER* reader)\r
+{\r
+       temp_iobase=_mm_iobase;  /* store old value in case of revert */\r
+       _mm_iobase=reader->Tell(reader);\r
+}\r
+\r
+/* Reverts to the last known _mm_iobase value. */\r
+void _mm_iobase_revert(void)\r
+{\r
+       _mm_iobase=temp_iobase;\r
+}\r
+\r
+/*========== File Reader */\r
+\r
+typedef struct MFILEREADER {\r
+       MREADER core;\r
+       int   file;\r
+       int   waseof;\r
+} MFILEREADER;\r
+\r
+static BOOL _mm_FileReader_Eof(MREADER* reader)\r
+{\r
+       /*\r
+       if ((lseek(((MFILEREADER*)reader)->file, 0, SEEK_CUR)-_mm_iobase) < filesize(((MFILEREADER*)reader)->file))\r
+               return 0;\r
+       else\r
+               return 1;\r
+       */\r
+       return ((MFILEREADER*)reader)->waseof;\r
+}\r
+\r
+static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size)\r
+{\r
+       int tempb;\r
+       tempb = rb->read(((MFILEREADER*)reader)->file, ptr, size);\r
+       //printf("(**) READ: %i\n", tempb);\r
+       /*\r
+       if (tempb != size)\r
+       {\r
+               printf("Read: count: %i  newpos: %i  return: %i\n", size, lseek(((MFILEREADER*)reader)->file-_mm_iobase, 0, SEEK_CUR), tempb);\r
+       }\r
+       */\r
+       if ((tempb < 1) && size > 0)\r
+       {\r
+               tempb = 0;\r
+               ((MFILEREADER*)reader)->waseof = 1;\r
+       }\r
+       else\r
+       {\r
+               ((MFILEREADER*)reader)->waseof = 0;\r
+       }\r
+       return tempb;\r
+}\r
+\r
+static int _mm_FileReader_Get(MREADER* reader)\r
+{\r
+       char buf;\r
+       if ((rb->read(((MFILEREADER*)reader)->file, &buf, 1) > 0) == 1)\r
+       {\r
+               ((MFILEREADER*)reader)->waseof = 0;\r
+               //printf("Get: newpos: %i  _mm_iobase: %i\n", lseek(((MFILEREADER*)reader)->file-_mm_iobase, 0, SEEK_CUR), _mm_iobase);\r
+               return buf;\r
+       }\r
+       else\r
+       {\r
+               ((MFILEREADER*)reader)->waseof = 1;\r
+               //printf("Get: newpos: %i  _mm_iobase: %i\n", lseek(((MFILEREADER*)reader)->file-_mm_iobase, 0, SEEK_CUR), _mm_iobase);\r
+               return EOF;\r
+       }\r
+}\r
+\r
+static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence)\r
+{\r
+       long tempb;\r
+\r
+       tempb = rb->lseek(((MFILEREADER*)reader)->file,\r
+                                (whence==SEEK_SET)?offset+_mm_iobase:offset,whence);\r
+       ((MFILEREADER*)reader)->waseof = 0;\r
+       //printf("(**) SEEK: %i\n", tempb);\r
+       if (tempb < 0)\r
+       {\r
+               //printf("Seek: count: %i  newpos: %i  return: %i\n", offset, lseek(((MFILEREADER*)reader)->file-_mm_iobase, 0, SEEK_CUR), tempb);\r
+               return 1;\r
+       }\r
+       else\r
+       {\r
+               return 0;\r
+       }\r
+}\r
+\r
+static long _mm_FileReader_Tell(MREADER* reader)\r
+{\r
+       return rb->lseek(((MFILEREADER*)reader)->file, 0, SEEK_CUR)-_mm_iobase;\r
+}\r
+\r
+MREADER *_mm_new_file_reader(int fp)\r
+{\r
+       MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER));\r
+       if (reader) {\r
+               reader->core.Eof =&_mm_FileReader_Eof;\r
+               reader->core.Read=&_mm_FileReader_Read;\r
+               reader->core.Get =&_mm_FileReader_Get;\r
+               reader->core.Seek=&_mm_FileReader_Seek;\r
+               reader->core.Tell=&_mm_FileReader_Tell;\r
+               reader->file=fp;\r
+               reader->waseof = 0;\r
+       }\r
+       return (MREADER*)reader;\r
+}\r
+\r
+void _mm_delete_file_reader (MREADER* reader)\r
+{\r
+       if(reader) free(reader);\r
+}\r
+\r
+/*========== File Writer */\r
+\r
+typedef struct MFILEWRITER {\r
+       MWRITER core;\r
+       int   file;\r
+} MFILEWRITER;\r
+\r
+static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence)\r
+{\r
+       return rb->lseek(((MFILEWRITER*)writer)->file,offset,whence);\r
+}\r
+\r
+static long _mm_FileWriter_Tell(MWRITER* writer)\r
+{\r
+       return rb->lseek(((MFILEREADER*)writer)->file, 0, SEEK_CUR);\r
+}\r
+\r
+static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size)\r
+{\r
+       return (rb->write(((MFILEWRITER*)writer)->file, ptr, size)==size);\r
+}\r
+\r
+static BOOL _mm_FileWriter_Put(MWRITER* writer,int value)\r
+{\r
+       char buf = value;\r
+       if (rb->write(((MFILEWRITER*)writer)->file, &buf, 1))\r
+               return 0;\r
+       else\r
+               return -1;\r
+}\r
+\r
+MWRITER *_mm_new_file_writer(int fp)\r
+{\r
+       MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER));\r
+       if (writer) {\r
+               writer->core.Seek =&_mm_FileWriter_Seek;\r
+               writer->core.Tell =&_mm_FileWriter_Tell;\r
+               writer->core.Write=&_mm_FileWriter_Write;\r
+               writer->core.Put  =&_mm_FileWriter_Put;\r
+               writer->file=fp;\r
+       }\r
+       return (MWRITER*) writer;\r
+}\r
+\r
+void _mm_delete_file_writer (MWRITER* writer)\r
+{\r
+       if(writer) free (writer);\r
+}\r
+\r
+/*========== Write functions */\r
+\r
+void _mm_write_string(CHAR* data,MWRITER* writer)\r
+{\r
+       if(data)\r
+               _mm_write_UBYTES(data,strlen(data),writer);\r
+}\r
+\r
+void _mm_write_M_UWORD(UWORD data,MWRITER* writer)\r
+{\r
+       _mm_write_UBYTE(data>>8,writer);\r
+       _mm_write_UBYTE(data&0xff,writer);\r
+}\r
+\r
+void _mm_write_I_UWORD(UWORD data,MWRITER* writer)\r
+{\r
+       _mm_write_UBYTE(data&0xff,writer);\r
+       _mm_write_UBYTE(data>>8,writer);\r
+}\r
+\r
+void _mm_write_M_ULONG(ULONG data,MWRITER* writer)\r
+{\r
+       _mm_write_M_UWORD((UWORD)(data>>16),writer);\r
+       _mm_write_M_UWORD((UWORD)(data&0xffff),writer);\r
+}\r
+\r
+void _mm_write_I_ULONG(ULONG data,MWRITER* writer)\r
+{\r
+       _mm_write_I_UWORD((UWORD)(data&0xffff),writer);\r
+       _mm_write_I_UWORD((UWORD)(data>>16),writer);\r
+}\r
+\r
+void _mm_write_M_SWORD(SWORD data,MWRITER* writer)\r
+{\r
+       _mm_write_M_UWORD((UWORD)data,writer);\r
+}\r
+\r
+void _mm_write_I_SWORD(SWORD data,MWRITER* writer)\r
+{\r
+       _mm_write_I_UWORD((UWORD)data,writer);\r
+}\r
+\r
+void _mm_write_M_SLONG(SLONG data,MWRITER* writer)\r
+{\r
+       _mm_write_M_ULONG((ULONG)data,writer);\r
+}\r
+\r
+void _mm_write_I_SLONG(SLONG data,MWRITER* writer)\r
+{\r
+       _mm_write_I_ULONG((ULONG)data,writer);\r
+}\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type)                                         \\r
+void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer)                \\r
+{                                                                                                                                                      \\r
+       while(number-->0)                                                                                                               \\r
+               _mm_write_##type_name(*(buffer++),writer);                                                      \\r
+}\r
+#else\r
+#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type)                                         \\r
+void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer)    \\r
+{                                                                                                                                                      \\r
+       while(number-->0)                                                                                                               \\r
+               _mm_write_/**/type_name(*(buffer++),writer);                                            \\r
+}\r
+#endif\r
+\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD)\r
+\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG)\r
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG)\r
+\r
+/*========== Read functions */\r
+\r
+int _mm_read_string(CHAR* buffer,int number,MREADER* reader)\r
+{\r
+       return reader->Read(reader,buffer,number);\r
+}\r
+\r
+UWORD _mm_read_M_UWORD(MREADER* reader)\r
+{\r
+       UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8;\r
+       result|=_mm_read_UBYTE(reader);\r
+       return result;\r
+}\r
+\r
+UWORD _mm_read_I_UWORD(MREADER* reader)\r
+{\r
+       UWORD result=_mm_read_UBYTE(reader);\r
+       result|=((UWORD)_mm_read_UBYTE(reader))<<8;\r
+       return result;\r
+}\r
+\r
+ULONG _mm_read_M_ULONG(MREADER* reader)\r
+{\r
+       ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16;\r
+       result|=_mm_read_M_UWORD(reader);\r
+       return result;\r
+}\r
+\r
+ULONG _mm_read_I_ULONG(MREADER* reader)\r
+{\r
+       ULONG result=_mm_read_I_UWORD(reader);\r
+       result|=((ULONG)_mm_read_I_UWORD(reader))<<16;\r
+       return result;\r
+}\r
+\r
+SWORD _mm_read_M_SWORD(MREADER* reader)\r
+{\r
+       return((SWORD)_mm_read_M_UWORD(reader));\r
+}\r
+\r
+SWORD _mm_read_I_SWORD(MREADER* reader)\r
+{\r
+       return((SWORD)_mm_read_I_UWORD(reader));\r
+}\r
+\r
+SLONG _mm_read_M_SLONG(MREADER* reader)\r
+{\r
+       return((SLONG)_mm_read_M_ULONG(reader));\r
+}\r
+\r
+SLONG _mm_read_I_SLONG(MREADER* reader)\r
+{\r
+       return((SLONG)_mm_read_I_ULONG(reader));\r
+}\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type)                                          \\r
+int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader)          \\r
+{                                                                                                                                                      \\r
+       while(number-->0)                                                                                                               \\r
+               *(buffer++)=_mm_read_##type_name(reader);                                                       \\r
+       return !reader->Eof(reader);                                                                                    \\r
+}\r
+#else\r
+#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type)                                          \\r
+int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader)      \\r
+{                                                                                                                                                      \\r
+       while(number-->0)                                                                                                               \\r
+               *(buffer++)=_mm_read_/**/type_name(reader);                                                     \\r
+       return !reader->Eof(reader);                                                                                    \\r
+}\r
+#endif\r
+\r
+DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD)\r
+DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD)\r
+DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD)\r
+DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD)\r
+\r
+DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG)\r
+DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG)\r
+DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG)\r
+DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG)\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/mmio/old_mmalloc.c b/apps/plugins/mikmod/mmio/old_mmalloc.c
new file mode 100644 (file)
index 0000000..ea9924e
--- /dev/null
@@ -0,0 +1,290 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mmalloc.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Dynamic memory routines\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+\r
+size_t mem_offset = 0;\r
+char *mallocbuf = NULL;\r
+size_t mallocbuflen = 0;\r
+\r
+#define OTMAX 8192\r
+size_t offsettable[OTMAX];\r
+int otcounter = 0;\r
+\r
+size_t mikmod_get_mbuffsize(void *buff)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; i < otcounter; i++)\r
+       {\r
+               if (offsettable[i] == (size_t)buff - (size_t)mallocbuf)\r
+               {\r
+                       if (i < (otcounter - 1))\r
+                       {\r
+                               return (size_t)(offsettable[i + 1] - offsettable[i]);\r
+                       }\r
+                       else // i == (otcounter - 1)\r
+                       {\r
+                               return mem_offset - offsettable[i];\r
+                       }\r
+               }\r
+       }\r
+\r
+       return 0; // i >= otcounter\r
+}\r
+\r
+\r
+void mikmod_prepare_malloc(char *buff, int bufsize)\r
+{\r
+       mallocbuf = buff;\r
+       mallocbuflen = bufsize;\r
+       mem_offset = 0;\r
+       otcounter = 0;\r
+}\r
+\r
+long mikmod_get_malloc_usage(void)\r
+{\r
+       return mem_offset;\r
+}\r
+\r
+int mikmod_abs(int num)\r
+{\r
+       if (num < 0)\r
+               return (num * -1);\r
+       else\r
+               return (num);\r
+}\r
+\r
+void* mikmod_memset(char *buf, int val, size_t count)\r
+{\r
+       size_t i;\r
+\r
+       for (i = 0; i < count; i++)\r
+       {\r
+               buf[i] = val;\r
+       }\r
+       return buf;\r
+}\r
+\r
+/* 'Poor man's malloc' taken from rockbox codeclib.c */\r
+void* mikmod_malloc(size_t size)\r
+{\r
+    void* x;\r
+\r
+       if (!mallocbuf)\r
+               return NULL;\r
+    if (mem_offset + (long)size > mallocbuflen)\r
+        return NULL;\r
+    \r
+    x = &mallocbuf[mem_offset];\r
+\r
+\r
+       if (otcounter < OTMAX)\r
+       {\r
+               offsettable[otcounter] = mem_offset;\r
+               otcounter++;\r
+       }\r
+       else\r
+       {\r
+               if (otcounter == OTMAX)\r
+               {\r
+                       rb->splash(HZ * 2, "Offset Table FULL !\n");\r
+               }\r
+       }\r
+       mem_offset += (size + 3) & ~3; /* Keep memory 32-bit aligned */\r
+\r
+\r
+       memset(x, 0, size);\r
+\r
+    return(x);\r
+}\r
+\r
+void* mikmod_calloc(size_t nmemb, size_t size)\r
+{\r
+    void *x;\r
+    x = mikmod_malloc(nmemb * size);\r
+    if (x == NULL)\r
+        return NULL;\r
+    //memset(x, 0, nmemb*size);\r
+    return(x);\r
+}\r
+\r
+void mikmod_free(void* ptr) {\r
+    (void)ptr;\r
+}\r
+\r
+void* mikmod_realloc(void* ptr, size_t size)\r
+{\r
+    void* x;\r
+    //(void)ptr;\r
+    x = mikmod_malloc(size);\r
+       if (ptr != NULL)\r
+       {\r
+               if (mikmod_get_mbuffsize(ptr))\r
+               {\r
+                       memcpy(x, ptr, mikmod_get_mbuffsize(ptr));\r
+               }\r
+               else\r
+               {\r
+                       memcpy(x, ptr, size); //FIXME: size has to be the size of the original buffer.....\r
+               }\r
+       }\r
+    return(x);\r
+}\r
+\r
+unsigned int mikmod_strlen(const char *string)\r
+{\r
+       unsigned int i;\r
+       for (i = 0; string[i] != 0; i++);\r
+       return i;\r
+}\r
+\r
+char* mikmod_strdup(const char *srcbuf)\r
+{\r
+       char *newbuf;\r
+       unsigned int i, len;\r
+\r
+       len = mikmod_strlen(srcbuf);\r
+       newbuf = mikmod_malloc(len + 1);\r
+       \r
+       if (newbuf)\r
+       {\r
+               for (i = 0; i <= len; i++)\r
+                       newbuf[i] = srcbuf[i];\r
+       }\r
+       return newbuf;\r
+}\r
+\r
+char* mikmod_strncat(char *dest, const char *src, size_t count)\r
+{\r
+       size_t i, j;\r
+       j = mikmod_strlen(dest);\r
+\r
+       for(i = 0; i < count; i++)\r
+       {\r
+               if (src[i] == 0)\r
+                       break;\r
+               dest[i + j] = src[i];\r
+       }\r
+       return dest;\r
+}\r
+\r
+int mikmod_memcmp(const char *buf1, const char *buf2, size_t count)\r
+{\r
+       size_t i;\r
+\r
+       for(i = 0; i < count; i++)\r
+       {\r
+               if (buf1[i] > buf2[i])\r
+                       return 1;\r
+               if (buf1[i] < buf2[i])\r
+                       return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+char* mikmod_strstr(char *str, char *search)\r
+{\r
+       size_t i, j, k;\r
+\r
+       if (!mikmod_strlen(search))\r
+               return str;\r
+\r
+       j = mikmod_strlen(str);\r
+       k = mikmod_strlen(search);\r
+\r
+       for (i = 0; i < (j - k); i++)\r
+       {\r
+               if (!mikmod_memcmp(str, search, k))\r
+                       return &str[i];\r
+       }\r
+       return NULL;\r
+}\r
+\r
+int mikmod_toupper(int character)\r
+{\r
+       if ((character > 96) && (character < 123))\r
+               return (character - 32);\r
+       else\r
+               return character;\r
+}\r
+\r
+int mikmod_isalnum(int character)\r
+{\r
+       if ((character > 96) && (character < 123))\r
+               return character;\r
+       if ((character > 64) && (character < 91))\r
+               return character;\r
+       if ((character > 47) && (character < 58))\r
+               return character;\r
+       return 0;\r
+}\r
+\r
+int mikmod_isdigit(char c)\r
+{\r
+    return (c >= '0') && (c <= '9');\r
+}\r
+\r
+\r
+/****************************************************\r
+ * 'Original' MikMod code goes here\r
+ *\r
+ ****************************************************/\r
+\r
+/* Same as malloc, but sets error variable _mm_error when fails */\r
+void* _mm_malloc(size_t size)\r
+{\r
+       void *d;\r
+\r
+       //if(!(d=mikmod_malloc(size))) {\r
+       if(!(d=mikmod_malloc(size))) {\r
+               _mm_errno = MMERR_OUT_OF_MEMORY;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+       }\r
+       memset(d, 0, size);\r
+       return d;\r
+}\r
+\r
+/* Same as calloc, but sets error variable _mm_error when fails */\r
+void* _mm_calloc(size_t nitems,size_t size)\r
+{\r
+       void *d;\r
+   \r
+       if(!(d=mikmod_calloc(nitems,size))) {\r
+               _mm_errno = MMERR_OUT_OF_MEMORY;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+       }\r
+       return d;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mdriver.c b/apps/plugins/mikmod/playercode/mdriver.c
new file mode 100644 (file)
index 0000000..247423a
--- /dev/null
@@ -0,0 +1,961 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mdriver.c,v 1.3 2004/02/18 13:29:19 raph Exp $\r
+\r
+  These routines are used to access the available soundcard drivers.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#if defined unix || (defined __APPLE__ && defined __MACH__)\r
+#include <pwd.h>\r
+#include <sys/stat.h>\r
+#endif\r
+\r
+#include <string.h>\r
+#ifdef HAVE_STRINGS_H\r
+#include <strings.h>\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+static MDRIVER *firstdriver=NULL;\r
+\r
+extern MODULE *pf; /* modfile being played */\r
+\r
+/* Initial global settings */\r
+MIKMODAPI      UWORD md_device         = 0;    /* autodetect */\r
+MIKMODAPI      UWORD md_mixfreq        = 44100;\r
+MIKMODAPI      UWORD md_mode           = DMODE_STEREO | DMODE_16BITS |\r
+                                                                         DMODE_SURROUND |DMODE_SOFT_MUSIC |\r
+                                                                         DMODE_SOFT_SNDFX;\r
+MIKMODAPI      UBYTE md_pansep         = 128;  /* 128 == 100% (full left/right) */\r
+MIKMODAPI      UBYTE md_reverb         = 0;    /* no reverb */\r
+MIKMODAPI      UBYTE md_volume         = 128;  /* global sound volume (0-128) */\r
+MIKMODAPI      UBYTE md_musicvolume    = 128;  /* volume of song */\r
+MIKMODAPI      UBYTE md_sndfxvolume    = 128;  /* volume of sound effects */\r
+                       UWORD md_bpm            = 125;  /* tempo */\r
+\r
+/* Do not modify the numchn variables yourself!  use MD_SetVoices() */\r
+                       UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;\r
+                       UBYTE md_hardchn=0,md_softchn=0;\r
+\r
+                       void (*md_player)(void) = Player_HandleTick;\r
+static         BOOL  isplaying=0, initialized = 0;\r
+static         UBYTE *sfxinfo;\r
+static         int sfxpool;\r
+\r
+static         SAMPLE **md_sample = NULL;\r
+\r
+/* Previous driver in use *\r
+static         SWORD olddevice = -1;\r
+*/\r
+/* Limits the number of hardware voices to the specified amount.\r
+   This function should only be used by the low-level drivers. */\r
+static void LimitHardVoices(int limit)\r
+{\r
+       int t=0;\r
+\r
+       if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;\r
+       if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;\r
+\r
+       if (!(md_mode & DMODE_SOFT_SNDFX))\r
+               md_hardchn=md_sfxchn;\r
+       else\r
+               md_hardchn=0;\r
+\r
+       if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;\r
+\r
+       while (md_hardchn>limit) {\r
+               if (++t & 1) {\r
+                       if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;\r
+               } else {\r
+                       if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;\r
+               }\r
+\r
+               if (!(md_mode & DMODE_SOFT_SNDFX))\r
+                       md_hardchn=md_sfxchn;\r
+               else\r
+                       md_hardchn=0;\r
+\r
+               if (!(md_mode & DMODE_SOFT_MUSIC))\r
+                       md_hardchn+=md_sngchn;\r
+       }\r
+       md_numchn=md_hardchn+md_softchn;\r
+}\r
+\r
+/* Limits the number of hardware voices to the specified amount.\r
+   This function should only be used by the low-level drivers. */\r
+static void LimitSoftVoices(int limit)\r
+{\r
+       int t=0;\r
+\r
+       if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;\r
+       if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;\r
+\r
+       if (md_mode & DMODE_SOFT_SNDFX)\r
+               md_softchn=md_sfxchn;\r
+       else\r
+               md_softchn=0;\r
+\r
+       if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;\r
+\r
+       while (md_softchn>limit) {\r
+               if (++t & 1) {\r
+                       if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;\r
+               } else {\r
+                       if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;\r
+               }\r
+\r
+               if (!(md_mode & DMODE_SOFT_SNDFX))\r
+                       md_softchn=md_sfxchn;\r
+               else\r
+                       md_softchn=0;\r
+\r
+               if (!(md_mode & DMODE_SOFT_MUSIC))\r
+                       md_softchn+=md_sngchn;\r
+       }\r
+       md_numchn=md_hardchn+md_softchn;\r
+}\r
+\r
+/* Note: 'type' indicates whether the returned value should be for music or for\r
+   sound effects. */\r
+ULONG MD_SampleSpace(int type)\r
+{\r
+       if(type==MD_MUSIC)\r
+               type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+       else if(type==MD_SNDFX)\r
+               type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+       return VC_SampleSpace(type);\r
+}\r
+\r
+ULONG MD_SampleLength(int type,SAMPLE* s)\r
+{\r
+       if(type==MD_MUSIC)\r
+               type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+       else\r
+         if(type==MD_SNDFX)\r
+               type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+       return VC_SampleLength(type,s);\r
+}\r
+/*\r
+MIKMODAPI CHAR* MikMod_InfoDriver(void)\r
+{\r
+       int t,len=0;\r
+       MDRIVER *l;\r
+       CHAR *list=NULL;\r
+\r
+       MUTEX_LOCK(lists);\r
+       /* compute size of buffer *\r
+       for(l=firstdriver;l;l=l->next)\r
+               len+=4+(l->next?1:0)+strlen(l->Version);\r
+\r
+       if(len)\r
+               if((list=_mm_malloc(len*sizeof(CHAR)))) {\r
+                       list[0]=0;\r
+                       /* list all registered device drivers : *\r
+                       for(t=1,l=firstdriver;l;l=l->next,t++)\r
+                               sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",\r
+                                   list,t,l->Version);\r
+               }\r
+       MUTEX_UNLOCK(lists);\r
+       return list;\r
+}\r
+*/\r
+void _mm_registerdriver(struct MDRIVER* drv)\r
+{\r
+       MDRIVER *cruise = firstdriver;\r
+\r
+       /* don't register a MISSING() driver */\r
+       if ((drv->Name) && (drv->Version)) {\r
+               if (cruise) {\r
+                       while (cruise->next) cruise = cruise->next;\r
+                       cruise->next = drv;\r
+               } else\r
+                       firstdriver = drv; \r
+       }\r
+}\r
+\r
+MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)\r
+{\r
+       /* if we try to register an invalid driver, or an already registered driver,\r
+          ignore this attempt */\r
+       if ((!drv)||(drv->next)||(!drv->Name))\r
+               return;\r
+\r
+       MUTEX_LOCK(lists);\r
+       _mm_registerdriver(drv);\r
+       MUTEX_UNLOCK(lists);\r
+}\r
+\r
+MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)\r
+{\r
+       int rank=1;\r
+       MDRIVER *cruise;\r
+\r
+       MUTEX_LOCK(lists);\r
+       cruise=firstdriver;\r
+       while(cruise) {\r
+               if (cruise->Alias) {\r
+                       if (!(strcasecmp(alias,cruise->Alias))) break;\r
+                       rank++;\r
+               }\r
+               cruise=cruise->next;\r
+       }\r
+       if(!cruise) rank=0;\r
+       MUTEX_UNLOCK(lists);\r
+\r
+       return rank;\r
+}\r
+\r
+MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)\r
+{\r
+        MDRIVER *cruise;\r
+\r
+        /* Allow only driver ordinals > 0 */\r
+        if (!ordinal)\r
+                return 0;\r
+\r
+        MUTEX_LOCK(lists);\r
+        cruise = firstdriver;\r
+        while (cruise && --ordinal)\r
+                cruise = cruise->next;\r
+        MUTEX_UNLOCK(lists);\r
+        return cruise;\r
+}\r
+\r
+SWORD MD_SampleLoad(SAMPLOAD* s, int type)\r
+{\r
+       SWORD result;\r
+\r
+       if(type==MD_MUSIC)\r
+               type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+       else if(type==MD_SNDFX)\r
+               type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+       SL_Init(s);\r
+       result=VC_SampleLoad(s,type);\r
+       SL_Exit(s);\r
+\r
+       return result;\r
+}\r
+\r
+void MD_SampleUnload(SWORD handle)\r
+{\r
+       VC_SampleUnload(handle);\r
+}\r
+\r
+MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)\r
+{\r
+       MikMod_player_t result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=md_player;\r
+       md_player=player;\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI void MikMod_Update(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       /* FIXME - if I'm broken...\r
+       if(isplaying)\r
+       {\r
+               if((!pf)||(!pf->forbid))\r
+               {\r
+                       md_driver->Update();\r
+               }\r
+               else\r
+               {\r
+                       if (md_driver->Pause)\r
+                               md_driver->Pause();\r
+               }\r
+       }\r
+       */\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+void Voice_SetVolume_internal(SBYTE voice,UWORD vol)\r
+{\r
+       ULONG  tmp;\r
+\r
+       if((voice<0)||(voice>=md_numchn)) return;\r
+\r
+       /* range checks */\r
+       if(md_musicvolume>128) md_musicvolume=128;\r
+       if(md_sndfxvolume>128) md_sndfxvolume=128;\r
+       if(md_volume>128) md_volume=128;\r
+\r
+       tmp=(ULONG)vol*(ULONG)md_volume*\r
+            ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);\r
+       VC_VoiceSetVolume(voice,tmp/16384UL);\r
+}\r
+\r
+MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Voice_SetVolume_internal(voice,vol);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)\r
+{\r
+       UWORD result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if((voice>=0)&&(voice<md_numchn))\r
+               result=VC_VoiceGetVolume(voice);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)\r
+{\r
+       if((voice<0)||(voice>=md_numchn)) return;\r
+       if((md_sample[voice])&&(md_sample[voice]->divfactor))\r
+               frq/=md_sample[voice]->divfactor;\r
+       VC_VoiceSetFrequency(voice,frq);\r
+}\r
+\r
+MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Voice_SetFrequency_internal(voice,frq);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)\r
+{\r
+       ULONG result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if((voice>=0)&&(voice<md_numchn))\r
+               result=VC_VoiceGetFrequency(voice);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+void Voice_SetPanning_internal(SBYTE voice,ULONG pan)\r
+{\r
+       if((voice<0)||(voice>=md_numchn)) return;\r
+       if(pan!=PAN_SURROUND) {\r
+               if(md_pansep>128) md_pansep=128;\r
+               if(md_mode & DMODE_REVERSE) pan=255-pan;\r
+               pan = (((SWORD)(pan-128)*md_pansep)/128)+128;\r
+       }\r
+       VC_VoiceSetPanning(voice, pan);\r
+}\r
+\r
+MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)\r
+{\r
+#ifdef MIKMOD_DEBUG\r
+       if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))\r
+               fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);\r
+#endif\r
+\r
+       MUTEX_LOCK(vars);\r
+       Voice_SetPanning_internal(voice,pan);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)\r
+{\r
+       ULONG result=PAN_CENTER;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if((voice>=0)&&(voice<md_numchn))\r
+               result=VC_VoiceGetPanning(voice);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)\r
+{\r
+       ULONG  repend;\r
+\r
+       if((voice<0)||(voice>=md_numchn)) return;\r
+\r
+       md_sample[voice]=s;\r
+       repend=s->loopend;\r
+\r
+       if(s->flags&SF_LOOP)\r
+               /* repend can't be bigger than size */\r
+               if(repend>s->length) repend=s->length;\r
+\r
+       VC_VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);\r
+}\r
+\r
+MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)\r
+{\r
+       if(start>s->length) return;\r
+\r
+       MUTEX_LOCK(vars);\r
+       Voice_Play_internal(voice,s,start);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+void Voice_Stop_internal(SBYTE voice)\r
+{\r
+       if((voice<0)||(voice>=md_numchn)) return;\r
+       if(voice>=md_sngchn)\r
+               /* It is a sound effects channel, so flag the voice as non-critical! */\r
+               sfxinfo[voice-md_sngchn]=0;\r
+       VC_VoiceStop(voice);\r
+}\r
+\r
+MIKMODAPI void Voice_Stop(SBYTE voice)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Voice_Stop_internal(voice);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+BOOL Voice_Stopped_internal(SBYTE voice)\r
+{\r
+       if((voice<0)||(voice>=md_numchn)) return 0;\r
+       return(VC_VoiceStopped(voice));\r
+}\r
+\r
+MIKMODAPI BOOL Voice_Stopped(SBYTE voice)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=Voice_Stopped_internal(voice);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)\r
+{\r
+       SLONG result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if((voice>=0)&&(voice<md_numchn)) {\r
+               /*if (VC_VoiceGetPosition)*/\r
+                       result=(VC_VoiceGetPosition(voice));\r
+               /*else\r
+                       result=-1;*/\r
+       }\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)\r
+{\r
+       ULONG result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if((voice>=0)&&(voice<md_numchn)/*&& VC_VoiceRealVolume*/)\r
+               result=(VC_VoiceRealVolume(voice));\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+static BOOL _mm_init(CHAR *cmdline)\r
+{\r
+       /* UWORD t; */\r
+       (void)cmdline;\r
+\r
+       _mm_critical = 1;\r
+/*\r
+       /* if md_device==0, try to find a device number *\r
+       if(!md_device) {\r
+               cmdline=NULL;\r
+\r
+               for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)\r
+                       if(md_driver->IsPresent()) break;\r
+\r
+               if(!md_driver) {\r
+                       _mm_errno = MMERR_DETECTING_DEVICE;\r
+                       if(_mm_errorhandler) _mm_errorhandler();\r
+                       md_driver = &drv_nos;\r
+                       return 1;\r
+               }\r
+\r
+               md_device = t;\r
+       } else {\r
+               /* if n>0, use that driver *\r
+               for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)\r
+                       t++;\r
+\r
+               if(!md_driver) {\r
+                       _mm_errno = MMERR_INVALID_DEVICE;\r
+                       if(_mm_errorhandler) _mm_errorhandler();\r
+                       md_driver = &drv_nos;\r
+                       return 1;\r
+               }\r
+\r
+               /* arguments here might be necessary for the presence check to succeed *\r
+               if(cmdline&&(md_driver->CommandLine))\r
+                       md_driver->CommandLine(cmdline);\r
+\r
+               if(!md_driver->IsPresent()) {\r
+                       _mm_errno = MMERR_DETECTING_DEVICE;\r
+                       if(_mm_errorhandler) _mm_errorhandler();\r
+                       md_driver = &drv_nos;\r
+                       return 1;\r
+               }\r
+       }\r
+\r
+       olddevice = md_device;\r
+*/\r
+       md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;\r
+\r
+       if(VC_Init()) {\r
+               MikMod_Exit_internal();\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               return 1;\r
+       }\r
+\r
+       initialized=1;\r
+       _mm_critical=0;\r
+\r
+       return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Init(CHAR *cmdline)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       MUTEX_LOCK(lists);\r
+       result=_mm_init(cmdline);\r
+       MUTEX_UNLOCK(lists);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+void MikMod_Exit_internal(void)\r
+{\r
+       MikMod_DisableOutput_internal();\r
+       VC_Exit();\r
+       md_numchn = md_sfxchn = md_sngchn = 0;\r
+       //md_driver = &drv_nos;\r
+\r
+       if(sfxinfo) free(sfxinfo);\r
+       if(md_sample) free(md_sample);\r
+       md_sample  = NULL;\r
+       sfxinfo    = NULL;\r
+\r
+       initialized = 0;\r
+}\r
+\r
+MIKMODAPI void MikMod_Exit(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       MUTEX_LOCK(lists);\r
+       MikMod_Exit_internal();\r
+       MUTEX_UNLOCK(lists);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+/* Reset the driver using the new global variable settings. \r
+   If the driver has not been initialized, it will be now. */\r
+static BOOL _mm_reset(CHAR *cmdline)\r
+{\r
+       BOOL wasplaying = 0;\r
+\r
+       if(!initialized) return _mm_init(cmdline);\r
+       \r
+       if (isplaying) {\r
+               wasplaying = 1;\r
+               VC_PlayStop();\r
+       }\r
+/*\r
+       if((!md_driver->Reset)||(md_device != olddevice)) {\r
+               /* md_driver->Reset was NULL, or md_device was changed, so do a full\r
+                  reset of the driver. *\r
+               md_driver->Exit();\r
+               if(_mm_init(cmdline)) {\r
+                       MikMod_Exit_internal();\r
+                       if(_mm_errno)\r
+                               if(_mm_errorhandler) _mm_errorhandler();\r
+                       return 1;\r
+               }\r
+       } else {\r
+               if(md_driver->Reset()) {\r
+                       MikMod_Exit_internal();\r
+                       if(_mm_errno)\r
+                               if(_mm_errorhandler) _mm_errorhandler();\r
+                       return 1;\r
+               }\r
+       }\r
+*/\r
+       if (wasplaying) VC_PlayStart();\r
+       return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Reset(CHAR *cmdline)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       MUTEX_LOCK(lists);\r
+       result=_mm_reset(cmdline);\r
+       MUTEX_UNLOCK(lists);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+/* If either parameter is -1, the current set value will be retained. */\r
+BOOL MikMod_SetNumVoices_internal(int music, int sfx)\r
+{\r
+       BOOL resume = 0;\r
+       int t, oldchn = 0;\r
+\r
+       if((!music)&&(!sfx)) return 1;\r
+       _mm_critical = 1;\r
+       if(isplaying) {\r
+               MikMod_DisableOutput_internal();\r
+               oldchn = md_numchn;\r
+               resume = 1;\r
+       }\r
+\r
+       if(sfxinfo) free(sfxinfo);\r
+       if(md_sample) free(md_sample);\r
+       md_sample  = NULL;\r
+       sfxinfo    = NULL;\r
+\r
+       if(music!=-1) md_sngchn = music;\r
+       if(sfx!=-1)   md_sfxchn = sfx;\r
+       md_numchn = md_sngchn + md_sfxchn;\r
+/*\r
+       LimitHardVoices(md_driver->HardVoiceLimit);\r
+       LimitSoftVoices(md_driver->SoftVoiceLimit);\r
+*/\r
+       LimitHardVoices(0);\r
+       LimitSoftVoices(255);\r
+\r
+       if(VC_SetNumVoices()) {\r
+               MikMod_Exit_internal();\r
+               if(_mm_errno)\r
+                       if(_mm_errorhandler!=NULL) _mm_errorhandler();\r
+               md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;\r
+               return 1;\r
+       }\r
+\r
+       if(md_sngchn+md_sfxchn)\r
+               md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));\r
+       if(md_sfxchn)\r
+               sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));\r
+\r
+       /* make sure the player doesn't start with garbage */\r
+       for(t=oldchn;t<md_numchn;t++)  Voice_Stop_internal(t);\r
+\r
+       sfxpool = 0;\r
+       if(resume) MikMod_EnableOutput_internal();\r
+       _mm_critical = 0;\r
+\r
+       return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_SetNumVoices(int music, int sfx)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=MikMod_SetNumVoices_internal(music,sfx);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+BOOL MikMod_EnableOutput_internal(void)\r
+{\r
+       _mm_critical = 1;\r
+       if(!isplaying) {\r
+               if(VC_PlayStart()) return 1;\r
+               isplaying = 1;\r
+       }\r
+       _mm_critical = 0;\r
+       return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_EnableOutput(void)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=MikMod_EnableOutput_internal();\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+void MikMod_DisableOutput_internal(void)\r
+{\r
+       if(isplaying/* && md_driver*/) {\r
+               isplaying = 0;\r
+               VC_PlayStop();\r
+       }\r
+}\r
+\r
+MIKMODAPI void MikMod_DisableOutput(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       MikMod_DisableOutput_internal();\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+BOOL MikMod_Active_internal(void)\r
+{\r
+       return isplaying;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Active(void)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=MikMod_Active_internal();\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+/* Plays a sound effects sample.  Picks a voice from the number of voices\r
+   allocated for use as sound effects (loops through voices, skipping all active\r
+   criticals).\r
+\r
+   Returns the voice that the sound is being played on.                       */\r
+SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)\r
+{\r
+       int orig=sfxpool;/* for cases where all channels are critical */\r
+       int c;\r
+\r
+       if(!md_sfxchn) return -1;\r
+       if(s->volume>64) s->volume = 64;\r
+\r
+       /* check the first location after sfxpool */\r
+       do {\r
+               if(sfxinfo[sfxpool]&SFX_CRITICAL) {\r
+                       if(VC_VoiceStopped(c=sfxpool+md_sngchn)) {\r
+                               sfxinfo[sfxpool]=flags;\r
+                               Voice_Play_internal(c,s,start);\r
+                               VC_VoiceSetVolume(c,s->volume<<2);\r
+                               Voice_SetPanning_internal(c,s->panning);\r
+                               VC_VoiceSetFrequency(c,s->speed);\r
+                               sfxpool++;\r
+                               if(sfxpool>=md_sfxchn) sfxpool=0;\r
+                               return c;\r
+                       }\r
+               } else {\r
+                       sfxinfo[sfxpool]=flags;\r
+                       Voice_Play_internal(c=sfxpool+md_sngchn,s,start);\r
+                       VC_VoiceSetVolume(c,s->volume<<2);\r
+                       Voice_SetPanning_internal(c,s->panning);\r
+                       VC_VoiceSetFrequency(c,s->speed);\r
+                       sfxpool++;\r
+                       if(sfxpool>=md_sfxchn) sfxpool=0;\r
+                       return c;\r
+               }\r
+\r
+               sfxpool++;\r
+               if(sfxpool>=md_sfxchn) sfxpool = 0;\r
+       } while(sfxpool!=orig);\r
+\r
+       return -1;\r
+}\r
+\r
+MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)\r
+{\r
+       SBYTE result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=Sample_Play_internal(s,start,flags);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI long MikMod_GetVersion(void)\r
+{\r
+       return LIBMIKMOD_VERSION;\r
+}\r
+\r
+/*========== MT-safe stuff */\r
+\r
+#ifdef HAVE_PTHREAD\r
+#define INIT_MUTEX(name) \\r
+       pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER\r
+#elif defined(__OS2__)||defined(__EMX__)\r
+#define INIT_MUTEX(name) \\r
+       HMTX _mm_mutex_##name\r
+#elif defined(WIN32)\r
+#define INIT_MUTEX(name) \\r
+       HANDLE _mm_mutex_##name\r
+#else\r
+#define INIT_MUTEX(name) \\r
+       void *_mm_mutex_##name = NULL\r
+#endif\r
+\r
+INIT_MUTEX(vars);\r
+INIT_MUTEX(lists);\r
+\r
+MIKMODAPI BOOL MikMod_InitThreads(void)\r
+{\r
+       static int firstcall=1;\r
+       static int result=0;\r
+       \r
+       if (firstcall) {\r
+               firstcall=0;\r
+#ifdef HAVE_PTHREAD\r
+               result=1;\r
+#elif defined(__OS2__)||defined(__EMX__)\r
+               if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||\r
+                  DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {\r
+                       _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;\r
+                       result=0;\r
+               } else\r
+                       result=1;\r
+#elif defined(WIN32)\r
+               if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||\r
+                  (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))\r
+                       result=0;\r
+               else\r
+                       result=1;\r
+#endif\r
+       }\r
+       return result;\r
+}\r
+\r
+MIKMODAPI void MikMod_Unlock(void)\r
+{\r
+       MUTEX_UNLOCK(lists);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void MikMod_Lock(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       MUTEX_LOCK(lists);\r
+}\r
+\r
+/*========== Parameter extraction helper */\r
+\r
+CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit)\r
+{\r
+       CHAR *ret=NULL;\r
+\r
+       if(cmdline) {\r
+               CHAR *buf=strstr(cmdline,atomname);\r
+\r
+               if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {\r
+                       CHAR *ptr=buf+strlen(atomname);\r
+\r
+                       if(*ptr=='=') {\r
+                               for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);\r
+                               ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));\r
+                               if(ret)\r
+                                       strncpy(ret,buf,ptr-buf);\r
+                       } else if((*ptr==',')||(!*ptr)) {\r
+                               if(implicit) {\r
+                                       ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));\r
+                                       if(ret)\r
+                                               strncpy(ret,buf,ptr-buf);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+#if defined unix || (defined __APPLE__ && defined __MACH__)\r
+\r
+/*========== Posix helper functions */\r
+\r
+/* Check if the file is a regular or nonexistant file (or a link to a such a\r
+   file), and that, should the calling program be setuid, the access rights are\r
+   reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.\r
+   The goal is to prevent a setuid root libmikmod application from overriding\r
+   files like /etc/passwd with digital sound... */\r
+BOOL MD_Access(CHAR *filename)\r
+{\r
+       struct stat buf;\r
+\r
+       if(!stat(filename,&buf)) {\r
+               /* not a regular file ? */\r
+               if(!S_ISREG(buf.st_mode)) return 0;\r
+               /* more than one hard link to the file ? */\r
+               if(buf.st_nlink>1) return 0;\r
+               /* check access rights with the real user and group id */\r
+               if(getuid()==buf.st_uid) {\r
+                       if(!(buf.st_mode&S_IWUSR)) return 0;\r
+               } else if(getgid()==buf.st_gid) {\r
+                       if(!(buf.st_mode&S_IWGRP)) return 0;\r
+               } else\r
+                       if(!(buf.st_mode&S_IWOTH)) return 0;\r
+       }\r
+       \r
+       return 1;\r
+}\r
+\r
+/* Drop all root privileges we might have */\r
+BOOL MD_DropPrivileges(void)\r
+{\r
+       if(!geteuid()) {\r
+               if(getuid()) {\r
+                       /* we are setuid root -> drop setuid to become the real user */\r
+                       if(setuid(getuid())) return 1;\r
+               } else {\r
+                       /* we are run as root -> drop all and become user 'nobody' */\r
+                       struct passwd *nobody;\r
+                       int uid;\r
+\r
+                       if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */\r
+                       uid=nobody->pw_uid;\r
+                       if (!uid) /* user 'nobody' has root privileges ? weird... */\r
+                               return 1;\r
+                       if (setuid(uid)) return 1;\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mloader.c b/apps/plugins/mikmod/playercode/mloader.c
new file mode 100644 (file)
index 0000000..75504eb
--- /dev/null
@@ -0,0 +1,564 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  These routines are used to access the available module loaders\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+               MREADER *modreader;\r
+               MODULE of;\r
+\r
+static MLOADER *firstloader=NULL;\r
+\r
+UWORD finetune[16]={\r
+       8363,8413,8463,8529,8581,8651,8723,8757,\r
+       7895,7941,7985,8046,8107,8169,8232,8280\r
+};\r
+/*\r
+MIKMODAPI CHAR* MikMod_InfoLoader(void)\r
+{\r
+       int len=0;\r
+       MLOADER *l;\r
+       CHAR *list=NULL;\r
+\r
+       MUTEX_LOCK(lists);\r
+       /* compute size of buffer *\r
+       for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);\r
+\r
+       if(len)\r
+               if((list=_mm_malloc(len*sizeof(CHAR)))) {\r
+                       list[0]=0;\r
+                       /* list all registered module loders *\r
+                       for(l=firstloader;l;l=l->next)\r
+                               sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version);\r
+               }*\r
+       MUTEX_UNLOCK(lists);\r
+       return list;\r
+}\r
+*/\r
+void _mm_registerloader(MLOADER* ldr)\r
+{\r
+       MLOADER *cruise=firstloader;\r
+\r
+       if(cruise) {\r
+               while(cruise->next) cruise = cruise->next;\r
+               cruise->next=ldr;\r
+       } else\r
+               firstloader=ldr; \r
+}\r
+\r
+MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)\r
+{\r
+       /* if we try to register an invalid loader, or an already registered loader,\r
+          ignore this attempt */\r
+       if ((!ldr)||(ldr->next))\r
+               return;\r
+\r
+       MUTEX_LOCK(lists);\r
+       _mm_registerloader(ldr);\r
+       MUTEX_UNLOCK(lists);\r
+}\r
+\r
+BOOL ReadComment(UWORD len)\r
+{\r
+       if(len) {\r
+               int i;\r
+\r
+               if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0;\r
+               _mm_read_UBYTES(of.comment,len,modreader);\r
+               \r
+               /* translate IT linefeeds */\r
+               for(i=0;i<len;i++)\r
+                       if(of.comment[i]=='\r') of.comment[i]='\n';\r
+\r
+               of.comment[len]=0;      /* just in case */\r
+       }\r
+       if(!of.comment[0]) {\r
+               free(of.comment);\r
+               of.comment=NULL;\r
+       }\r
+       return 1;\r
+}\r
+\r
+BOOL ReadLinedComment(UWORD len,UWORD linelen)\r
+{\r
+       CHAR *tempcomment,*line,*storage;\r
+       UWORD total=0,t,lines;\r
+       int i;\r
+\r
+       lines = (len + linelen - 1) / linelen;\r
+       if (len) {\r
+               if(!(tempcomment=(CHAR*)_mm_malloc(len+1))) return 0;\r
+               if(!(storage=(CHAR*)_mm_malloc(linelen+1))) {\r
+                       free(tempcomment);\r
+                       return 0;\r
+               }\r
+               memset(tempcomment, ' ', len);\r
+               _mm_read_UBYTES(tempcomment,len,modreader);\r
+\r
+               /* compute message length */\r
+               for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {\r
+                       for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;\r
+                       for(i=0;i<linelen;i++) if (!line[i]) break;\r
+                       total+=1+i;\r
+               }\r
+\r
+               if(total>lines) {\r
+                       if(!(of.comment=(CHAR*)_mm_malloc(total+1))) {\r
+                               free(storage);\r
+                               free(tempcomment);\r
+                               return 0;\r
+                       }\r
+\r
+                       /* convert message */\r
+                       for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {\r
+                               for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;\r
+                               storage[i]=0; /* if (i==linelen) */\r
+                               strcat(of.comment,storage);strcat(of.comment,"\r");\r
+                       }\r
+                       free(storage);\r
+                       free(tempcomment);\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+BOOL AllocPositions(int total)\r
+{\r
+       if(!total) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       if(!(of.positions=_mm_calloc(total,sizeof(UWORD)))) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL AllocPatterns(void)\r
+{\r
+       int s,t,tracks = 0;\r
+\r
+       if((!of.numpat)||(!of.numchn)) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       /* Allocate track sequencing array */\r
+       if(!(of.patterns=(UWORD*)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;\r
+       if(!(of.pattrows=(UWORD*)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0;\r
+\r
+       for(t=0;t<=of.numpat;t++) {\r
+               of.pattrows[t]=64;\r
+               for(s=0;s<of.numchn;s++)\r
+               of.patterns[(t*of.numchn)+s]=tracks++;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL AllocTracks(void)\r
+{\r
+       if(!of.numtrk) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL AllocInstruments(void)\r
+{\r
+       int t,n;\r
+       \r
+       if(!of.numins) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       if(!(of.instruments=(INSTRUMENT*)_mm_calloc(of.numins,sizeof(INSTRUMENT))))\r
+               return 0;\r
+\r
+       for(t=0;t<of.numins;t++) {\r
+               for(n=0;n<INSTNOTES;n++) { \r
+                       /* Init note / sample lookup table */\r
+                       of.instruments[t].samplenote[n]   = n;\r
+                       of.instruments[t].samplenumber[n] = t;\r
+               }   \r
+               of.instruments[t].globvol = 64;\r
+       }\r
+       return 1;\r
+}\r
+\r
+BOOL AllocSamples(void)\r
+{\r
+       UWORD u;\r
+\r
+       if(!of.numsmp) {\r
+               _mm_errno=MMERR_NOT_A_MODULE;\r
+               return 0;\r
+       }\r
+       if(!(of.samples=(SAMPLE*)_mm_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;\r
+\r
+       for(u=0;u<of.numsmp;u++) {\r
+               of.samples[u].panning = 128; /* center */\r
+               of.samples[u].handle  = -1;\r
+               of.samples[u].globvol = 64;\r
+               of.samples[u].volume  = 64;\r
+       }\r
+       return 1;\r
+}\r
+\r
+static BOOL ML_LoadSamples(void)\r
+{\r
+       SAMPLE *s;\r
+       int u;\r
+\r
+       for(u=of.numsmp,s=of.samples;u;u--,s++)\r
+               if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);\r
+\r
+       return 1;\r
+}\r
+\r
+/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any\r
+   terminating non-printing characters like 0, spaces etc.                    */\r
+CHAR *DupStr(CHAR* s,UWORD len,BOOL strict)\r
+{\r
+       UWORD t;\r
+       CHAR *d=NULL;\r
+\r
+       /* Scan for last printing char in buffer [includes high ascii up to 254] */\r
+       while(len) {\r
+               if(s[len-1]>0x20) break;\r
+               len--;\r
+       }\r
+\r
+       /* Scan forward for possible NULL character */\r
+       if(strict) {\r
+               for(t=0;t<len;t++) if (!s[t]) break;\r
+               if (t<len) len=t;\r
+       }\r
+\r
+       /* When the buffer wasn't completely empty, allocate a cstring and copy the\r
+          buffer into that string, except for any control-chars */\r
+       if((d=(CHAR*)_mm_malloc(sizeof(CHAR)*(len+1)))) {\r
+               for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];\r
+               d[len]=0;\r
+       }\r
+       return d;\r
+}\r
+\r
+static void ML_XFreeSample(SAMPLE *s)\r
+{\r
+       if(s->handle>=0)\r
+               MD_SampleUnload(s->handle);\r
+       if(s->samplename) free(s->samplename);\r
+}\r
+\r
+static void ML_XFreeInstrument(INSTRUMENT *i)\r
+{\r
+       if(i->insname) free(i->insname);\r
+}\r
+\r
+static void ML_FreeEx(MODULE *mf)\r
+{\r
+       UWORD t;\r
+\r
+       if(mf->songname) free(mf->songname);\r
+       if(mf->comment)  free(mf->comment);\r
+\r
+       if(mf->modtype)   free(mf->modtype);\r
+       if(mf->positions) free(mf->positions);\r
+       if(mf->patterns)  free(mf->patterns);\r
+       if(mf->pattrows)  free(mf->pattrows);\r
+\r
+       if(mf->tracks) {\r
+               for(t=0;t<mf->numtrk;t++)\r
+                       if(mf->tracks[t]) free(mf->tracks[t]);\r
+               free(mf->tracks);\r
+       }\r
+       if(mf->instruments) {\r
+               for(t=0;t<mf->numins;t++)\r
+                       ML_XFreeInstrument(&mf->instruments[t]);\r
+               free(mf->instruments);\r
+       }\r
+       if(mf->samples) {\r
+               for(t=0;t<mf->numsmp;t++)\r
+                       if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);\r
+               free(mf->samples);\r
+       }\r
+       memset(mf,0,sizeof(MODULE));\r
+       if(mf!=&of) free(mf);\r
+}\r
+\r
+static MODULE *ML_AllocUniMod(void)\r
+{\r
+       MODULE *mf;\r
+\r
+       return (mf=_mm_malloc(sizeof(MODULE)));\r
+}\r
+\r
+void Player_Free_internal(MODULE *mf)\r
+{\r
+       if(mf) {\r
+               Player_Exit_internal(mf);\r
+               ML_FreeEx(mf);\r
+       }\r
+}\r
+\r
+MIKMODAPI void Player_Free(MODULE *mf)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Player_Free_internal(mf);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+static CHAR* Player_LoadTitle_internal(MREADER *reader)\r
+{\r
+       MLOADER *l;\r
+\r
+       modreader=reader;\r
+       _mm_errno = 0;\r
+       _mm_critical = 0;\r
+       _mm_iobase_setcur(modreader);\r
+\r
+       /* Try to find a loader that recognizes the module */\r
+       for(l=firstloader;l;l=l->next) {\r
+               _mm_rewind(modreader);\r
+               if(l->Test()) break;\r
+       }\r
+\r
+       if(!l) {\r
+               _mm_errno = MMERR_NOT_A_MODULE;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               return NULL;\r
+       }\r
+\r
+       return l->LoadTitle();\r
+}\r
+\r
+MIKMODAPI CHAR* Player_LoadTitleFP(int fp)\r
+{\r
+       CHAR* result=NULL;\r
+       MREADER* reader;\r
+\r
+       if(fp && (reader=_mm_new_file_reader(fp))) {\r
+               MUTEX_LOCK(lists);\r
+               result=Player_LoadTitle_internal(reader);\r
+               MUTEX_UNLOCK(lists);\r
+               _mm_delete_file_reader(reader);\r
+       }\r
+       return result;\r
+}\r
+\r
+MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename)\r
+{\r
+       CHAR* result=NULL;\r
+       int fp;\r
+       MREADER* reader;\r
+\r
+       if((fp=_mm_fopen(filename,O_RDONLY))) {\r
+               if((reader=_mm_new_file_reader(fp))) {\r
+                       MUTEX_LOCK(lists);\r
+                       result=Player_LoadTitle_internal(reader);\r
+                       MUTEX_UNLOCK(lists);\r
+                       _mm_delete_file_reader(reader);\r
+               }\r
+               _mm_fclose(fp);\r
+       }\r
+       return result;\r
+}\r
+\r
+/* Loads a module given an reader */\r
+MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)\r
+{\r
+       int t;\r
+       MLOADER *l;\r
+       BOOL ok;\r
+       MODULE *mf;\r
+\r
+       modreader = reader;\r
+       _mm_errno = 0;\r
+       _mm_critical = 0;\r
+       _mm_iobase_setcur(modreader);\r
+\r
+       /* Try to find a loader that recognizes the module */\r
+       for(l=firstloader;l;l=l->next) {\r
+               _mm_rewind(modreader);\r
+               if(l->Test()) break;\r
+       }\r
+\r
+       if(!l) {\r
+               _mm_errno = MMERR_NOT_A_MODULE;\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               _mm_rewind(modreader);_mm_iobase_revert();\r
+               return NULL;\r
+       }\r
+\r
+       /* init unitrk routines */\r
+       if(!UniInit()) {\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               _mm_rewind(modreader);_mm_iobase_revert();\r
+               return NULL;\r
+       }\r
+\r
+       /* init the module structure with vanilla settings */\r
+       memset(&of,0,sizeof(MODULE));\r
+       of.bpmlimit = 33;\r
+       of.initvolume = 128;\r
+       for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;\r
+       for (t = 0; t < UF_MAXCHAN; t++)\r
+               of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;\r
+\r
+       /* init module loader and load the header / patterns */\r
+       if (!l->Init || l->Init()) {\r
+               _mm_rewind(modreader);\r
+               ok = l->Load(curious);\r
+               /* propagate inflags=flags for in-module samples */\r
+               for (t = 0; t < of.numsmp; t++)\r
+                       if (of.samples[t].inflags == 0)\r
+                               of.samples[t].inflags = of.samples[t].flags;\r
+       } else\r
+               ok = 0;\r
+\r
+       /* free loader and unitrk allocations */\r
+       if (l->Cleanup) l->Cleanup();\r
+       UniCleanup();\r
+\r
+       if(!ok) {\r
+               ML_FreeEx(&of);\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               _mm_rewind(modreader);_mm_iobase_revert();\r
+               return NULL;\r
+       }\r
+\r
+       if(!ML_LoadSamples()) {\r
+               ML_FreeEx(&of);\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               _mm_rewind(modreader);_mm_iobase_revert();\r
+               return NULL;\r
+       }\r
+\r
+       if(!(mf=ML_AllocUniMod())) {\r
+               ML_FreeEx(&of);\r
+               _mm_rewind(modreader);_mm_iobase_revert();\r
+               if(_mm_errorhandler) _mm_errorhandler();\r
+               return NULL;\r
+       }\r
+       \r
+       /* If the module doesn't have any specific panning, create a\r
+          MOD-like panning, with the channels half-separated. */\r
+       if (!(of.flags & UF_PANNING))\r
+               for (t = 0; t < of.numchn; t++)\r
+                       of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;\r
+\r
+       /* Copy the static MODULE contents into the dynamic MODULE struct. */\r
+       memcpy(mf,&of,sizeof(MODULE));\r
+\r
+       if(maxchan>0) {\r
+               if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))\r
+                       maxchan = mf->numchn;\r
+               else\r
+                 if((mf->numvoices)&&(mf->numvoices<maxchan))\r
+                       maxchan = mf->numvoices;\r
+\r
+               if(maxchan<mf->numchn) mf->flags |= UF_NNA;\r
+\r
+               if(MikMod_SetNumVoices_internal(maxchan,-1)) {\r
+                       _mm_iobase_revert();\r
+                       Player_Free(mf);\r
+                       return NULL;\r
+               }\r
+       }\r
+       if(SL_LoadSamples()) {\r
+               _mm_iobase_revert();\r
+               Player_Free_internal(mf);\r
+               return NULL;\r
+       }\r
+       if(Player_Init(mf)) {\r
+               _mm_iobase_revert();\r
+               Player_Free_internal(mf);\r
+               mf=NULL;\r
+       }\r
+       _mm_iobase_revert();\r
+       return mf;\r
+}\r
+\r
+MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)\r
+{\r
+       MODULE* result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       MUTEX_LOCK(lists);\r
+               result=Player_LoadGeneric_internal(reader,maxchan,curious);\r
+       MUTEX_UNLOCK(lists);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+/* Loads a module given a file pointer.\r
+   File is loaded from the current file seek position. */\r
+MIKMODAPI MODULE* Player_LoadFP(int fp,int maxchan,BOOL curious)\r
+{\r
+       MODULE* result=NULL;\r
+       struct MREADER* reader=_mm_new_file_reader (fp);\r
+\r
+       if (reader) {\r
+               result=Player_LoadGeneric(reader,maxchan,curious);\r
+               _mm_delete_file_reader(reader);\r
+       }\r
+       return result;\r
+}\r
+\r
+/* Open a module via its filename.  The loader will initialize the specified\r
+   song-player 'player'. */\r
+MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)\r
+{\r
+       int fp;\r
+       MODULE *mf=NULL;\r
+\r
+       if((fp=_mm_fopen(filename,O_RDONLY))) {\r
+               mf=Player_LoadFP(fp,maxchan,curious);\r
+               _mm_fclose(fp);\r
+       }\r
+       return mf;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mlreg.c b/apps/plugins/mikmod/playercode/mlreg.c
new file mode 100644 (file)
index 0000000..575f17b
--- /dev/null
@@ -0,0 +1,65 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mlreg.c,v 1.2 2004/01/28 00:49:56 raph Exp $\r
+\r
+  Routine for registering all loaders in libmikmod for the current platform.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+void MikMod_RegisterAllLoaders_internal(void)\r
+{\r
+       _mm_registerloader(&load_669);\r
+       _mm_registerloader(&load_amf);\r
+       _mm_registerloader(&load_asy);\r
+       _mm_registerloader(&load_dsm);\r
+       _mm_registerloader(&load_far);\r
+       _mm_registerloader(&load_gdm);\r
+       _mm_registerloader(&load_it);\r
+       _mm_registerloader(&load_imf);\r
+       _mm_registerloader(&load_mod);\r
+       _mm_registerloader(&load_med);\r
+       _mm_registerloader(&load_mtm);\r
+/*     _mm_registerloader(&load_okt); */\r
+       _mm_registerloader(&load_s3m);\r
+       _mm_registerloader(&load_stm);\r
+       _mm_registerloader(&load_stx);\r
+       _mm_registerloader(&load_ult);\r
+       _mm_registerloader(&load_uni);\r
+       _mm_registerloader(&load_xm);\r
+\r
+       _mm_registerloader(&load_m15);\r
+}\r
+\r
+void MikMod_RegisterAllLoaders(void)\r
+{\r
+       MUTEX_LOCK(lists);\r
+       MikMod_RegisterAllLoaders_internal();\r
+       MUTEX_UNLOCK(lists);\r
+}\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mlutil.c b/apps/plugins/mikmod/playercode/mlutil.c
new file mode 100644 (file)
index 0000000..0746a13
--- /dev/null
@@ -0,0 +1,336 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mlutil.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Utility functions for the module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Shared tracker identifiers */\r
+\r
+CHAR *STM_Signatures[STM_NTRACKERS] = {\r
+       "!Scream!",\r
+       "BMOD2STM",\r
+       "WUZAMOD!"\r
+};\r
+\r
+CHAR *STM_Version[STM_NTRACKERS] = {\r
+       "Screamtracker 2",\r
+       "Converted by MOD2STM (STM format)",\r
+       "Wuzamod (STM format)"\r
+};\r
+\r
+/*========== Shared loader variables */\r
+\r
+SBYTE  remap[UF_MAXCHAN];   /* for removing empty channels */\r
+UBYTE* poslookup=NULL;      /* lookup table for pattern jumps after blank\r
+                               pattern removal */\r
+UBYTE  poslookupcnt;\r
+UWORD* origpositions=NULL;\r
+\r
+BOOL   filters;             /* resonant filters in use */\r
+UBYTE  activemacro;         /* active midi macro number for Sxx,xx<80h */\r
+UBYTE  filtermacros[UF_MAXMACRO];    /* midi macro settings */\r
+FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */\r
+\r
+/*========== Linear periods stuff */\r
+\r
+int*   noteindex=NULL;      /* remap value for linear period modules */\r
+static int noteindexcount=0;\r
+\r
+int *AllocLinear(void)\r
+{\r
+       if(of.numsmp>noteindexcount) {\r
+               noteindexcount=of.numsmp;\r
+               noteindex=realloc(noteindex,noteindexcount*sizeof(int));\r
+       }\r
+       return noteindex;\r
+}\r
+\r
+void FreeLinear(void)\r
+{\r
+       if(noteindex) {\r
+               free(noteindex);\r
+               noteindex=NULL;\r
+       }\r
+       noteindexcount=0;\r
+}\r
+\r
+int speed_to_finetune(ULONG speed,int sample)\r
+{\r
+    int ctmp=0,tmp,note=1,finetune=0;\r
+\r
+    speed>>=1;\r
+    while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {\r
+        ctmp=tmp;\r
+        note++;\r
+    }\r
+\r
+    if(tmp!=speed) {\r
+        if((tmp-speed)<(speed-ctmp))\r
+            while(tmp>speed)\r
+                tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));\r
+        else {\r
+            note--;\r
+            while(ctmp<speed)\r
+                ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));\r
+        }\r
+    }\r
+\r
+    noteindex[sample]=note-4*OCTAVE;\r
+    return finetune;\r
+}\r
+\r
+/*========== Order stuff */\r
+\r
+/* handles S3M and IT orders */\r
+void S3MIT_CreateOrders(BOOL curious)\r
+{\r
+       int t;\r
+\r
+       of.numpos = 0;\r
+       memset(of.positions,0,poslookupcnt*sizeof(UWORD));\r
+       memset(poslookup,-1,256);\r
+       for(t=0;t<poslookupcnt;t++) {\r
+               int order=origpositions[t];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */\r
+               if(origpositions[t]<254) of.numpos++;\r
+               else\r
+                       /* end of song special order */\r
+                       if((order==LAST_PATTERN)&&(!(curious--))) break;\r
+       }\r
+}\r
+\r
+/*========== Effect stuff */\r
+\r
+/* handles S3M and IT effects */\r
+void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       /* process S3M / IT specific command structure */\r
+\r
+       if(cmd!=255) {\r
+               switch(cmd) {\r
+                       case 1: /* Axx set speed to xx */\r
+                               UniEffect(UNI_S3MEFFECTA,inf);\r
+                               break;\r
+                       case 2: /* Bxx position jump */\r
+                               if (inf<poslookupcnt) {\r
+                                       /* switch to curious mode if necessary, for example\r
+                                          sympex.it, deep joy.it */\r
+                                       if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))\r
+                                               S3MIT_CreateOrders(1);\r
+\r
+                                       if(!((SBYTE)poslookup[inf]<0))\r
+                                               UniPTEffect(0xb,poslookup[inf]);\r
+                               }\r
+                               break;\r
+                       case 3: /* Cxx patternbreak to row xx */\r
+                               if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT))\r
+                                       UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));\r
+                               else\r
+                                       UniPTEffect(0xd,inf);\r
+                               break;\r
+                       case 4: /* Dxy volumeslide */\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 5: /* Exy toneslide down */\r
+                               UniEffect(UNI_S3MEFFECTE,inf);\r
+                               break;\r
+                       case 6: /* Fxy toneslide up */\r
+                               UniEffect(UNI_S3MEFFECTF,inf);\r
+                               break;\r
+                       case 7: /* Gxx Tone portamento, speed xx */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x3,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTG,inf);\r
+                               break;\r
+                       case 8: /* Hxy vibrato */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x4,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTH,inf);\r
+                               break;\r
+                       case 9: /* Ixy tremor, ontime x, offtime y */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniEffect(UNI_S3MEFFECTI,inf);\r
+                               else                     \r
+                                       UniEffect(UNI_ITEFFECTI,inf);\r
+                               break;\r
+                       case 0xa: /* Jxy arpeggio */\r
+                               UniPTEffect(0x0,inf);\r
+                               break;\r
+                       case 0xb: /* Kxy Dual command H00 & Dxy */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x4,0);    \r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTH,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xc: /* Lxy Dual command G00 & Dxy */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x3,0);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTG,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xd: /* Mxx Set Channel Volume */\r
+                               UniEffect(UNI_ITEFFECTM,inf);\r
+                               break;       \r
+                       case 0xe: /* Nxy Slide Channel Volume */\r
+                               UniEffect(UNI_ITEFFECTN,inf);\r
+                               break;\r
+                       case 0xf: /* Oxx set sampleoffset xx00h */\r
+                               UniPTEffect(0x9,inf);\r
+                               break;\r
+                       case 0x10: /* Pxy Slide Panning Commands */\r
+                               UniEffect(UNI_ITEFFECTP,inf);\r
+                               break;\r
+                       case 0x11: /* Qxy Retrig (+volumeslide) */\r
+                               UniWriteByte(UNI_S3MEFFECTQ);\r
+                               if(inf && !lo && !(flags & S3MIT_OLDSTYLE))\r
+                                       UniWriteByte(1);\r
+                               else\r
+                                       UniWriteByte(inf); \r
+                               break;\r
+                       case 0x12: /* Rxy tremolo speed x, depth y */\r
+                               UniEffect(UNI_S3MEFFECTR,inf);\r
+                               break;\r
+                       case 0x13: /* Sxx special commands */\r
+                               if (inf>=0xf0) {\r
+                                       /* change resonant filter settings if necessary */\r
+                                       if((filters)&&((inf&0xf)!=activemacro)) {\r
+                                               activemacro=inf&0xf;\r
+                                               for(inf=0;inf<0x80;inf++)\r
+                                                       filtersettings[inf].filter=filtermacros[activemacro];\r
+                                       }\r
+                               } else {\r
+                                       /* Scream Tracker does not have samples larger than\r
+                                          64 Kb, thus doesn't need the SAx effect */\r
+                                       if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0))\r
+                                               break;\r
+\r
+                                       UniEffect(UNI_ITEFFECTS0,inf);\r
+                               }\r
+                               break;\r
+                       case 0x14: /* Txx tempo */\r
+                               if(inf>=0x20)\r
+                                       UniEffect(UNI_S3MEFFECTT,inf);\r
+                               else {\r
+                                       if(!(flags & S3MIT_OLDSTYLE))\r
+                                               /* IT Tempo slide */\r
+                                               UniEffect(UNI_ITEFFECTT,inf);\r
+                               }\r
+                               break;\r
+                       case 0x15: /* Uxy Fine Vibrato speed x, depth y */\r
+                               if(flags & S3MIT_OLDSTYLE)\r
+                                       UniEffect(UNI_S3MEFFECTU,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTU,inf);\r
+                               break;\r
+                       case 0x16: /* Vxx Set Global Volume */\r
+                               UniEffect(UNI_XMEFFECTG,inf);\r
+                               break;\r
+                       case 0x17: /* Wxy Global Volume Slide */\r
+                               UniEffect(UNI_ITEFFECTW,inf);\r
+                               break;\r
+                       case 0x18: /* Xxx amiga command 8xx */\r
+                               if(flags & S3MIT_OLDSTYLE) {\r
+                                       if(inf>128)\r
+                                               UniEffect(UNI_ITEFFECTS0,0x91); /* surround */\r
+                                       else\r
+                                               UniPTEffect(0x8,(inf==128)?255:(inf<<1));\r
+                               } else\r
+                                       UniPTEffect(0x8,inf);\r
+                               break;\r
+                       case 0x19: /* Yxy Panbrello  speed x, depth y */\r
+                               UniEffect(UNI_ITEFFECTY,inf);\r
+                               break;\r
+                       case 0x1a: /* Zxx midi/resonant filters */\r
+                               if(filtersettings[inf].filter) {\r
+                                       UniWriteByte(UNI_ITEFFECTZ);\r
+                                       UniWriteByte(filtersettings[inf].filter);\r
+                                       UniWriteByte(filtersettings[inf].inf);\r
+                               }\r
+                               break;\r
+               }\r
+       }\r
+}\r
+\r
+/*========== Unitrk stuff */\r
+\r
+/* Generic effect writing routine */\r
+void UniEffect(UWORD eff,UWORD dat)\r
+{\r
+       if((!eff)||(eff>=UNI_LAST)) return;\r
+\r
+       UniWriteByte(eff);\r
+       if(unioperands[eff]==2)\r
+               UniWriteWord(dat);\r
+       else\r
+               UniWriteByte(dat);\r
+}\r
+\r
+/*  Appends UNI_PTEFFECTX opcode to the unitrk stream. */\r
+void UniPTEffect(UBYTE eff, UBYTE dat)\r
+{\r
+#ifdef MIKMOD_DEBUG\r
+       if (eff>=0x10)\r
+               fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);\r
+       else\r
+#endif\r
+       if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);\r
+}\r
+\r
+/* Appends UNI_VOLEFFECT + effect/dat to unistream. */\r
+void UniVolEffect(UWORD eff,UBYTE dat)\r
+{\r
+       if((eff)||(dat)) { /* don't write empty effect */\r
+               UniWriteByte(UNI_VOLEFFECTS);\r
+               UniWriteByte(eff);UniWriteByte(dat);\r
+       }\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mplayer.c b/apps/plugins/mikmod/playercode/mplayer.c
new file mode 100644 (file)
index 0000000..fa38a80
--- /dev/null
@@ -0,0 +1,3546 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mplayer.c,v 1.5 2004/01/31 22:40:22 raph Exp $\r
+\r
+  The Protracker Player Driver\r
+\r
+  The protracker driver supports all base Protracker 3.x commands and features.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#ifdef SRANDOM_IN_MATH_H\r
+#include <math.h>\r
+#else\r
+#include <stdlib.h>\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+extern long int random(void);\r
+#endif\r
+\r
+/* The currently playing module */\r
+/* This variable should better be static, but it would break the ABI, so this\r
+   will wait */\r
+/*static*/ MODULE *pf = NULL;\r
+\r
+#define        HIGH_OCTAVE             2       /* number of above-range octaves */\r
+\r
+static UWORD oldperiods[OCTAVE*2]={\r
+       0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80,\r
+       0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0,\r
+       0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160,\r
+       0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700\r
+};\r
+\r
+static UBYTE VibratoTable[32]={\r
+         0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253,\r
+       255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24\r
+};\r
+\r
+static UBYTE avibtab[128]={\r
+        0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,\r
+       24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44,\r
+       45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58,\r
+       59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63,\r
+       64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59,\r
+       59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46,\r
+       45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25,\r
+       24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1\r
+};\r
+\r
+/* Triton's linear periods to frequency translation table (for XM modules) */\r
+static ULONG lintab[768]={\r
+       535232,534749,534266,533784,533303,532822,532341,531861,\r
+       531381,530902,530423,529944,529466,528988,528511,528034,\r
+       527558,527082,526607,526131,525657,525183,524709,524236,\r
+       523763,523290,522818,522346,521875,521404,520934,520464,\r
+       519994,519525,519057,518588,518121,517653,517186,516720,\r
+       516253,515788,515322,514858,514393,513929,513465,513002,\r
+       512539,512077,511615,511154,510692,510232,509771,509312,\r
+       508852,508393,507934,507476,507018,506561,506104,505647,\r
+       505191,504735,504280,503825,503371,502917,502463,502010,\r
+       501557,501104,500652,500201,499749,499298,498848,498398,\r
+       497948,497499,497050,496602,496154,495706,495259,494812,\r
+       494366,493920,493474,493029,492585,492140,491696,491253,\r
+       490809,490367,489924,489482,489041,488600,488159,487718,\r
+       487278,486839,486400,485961,485522,485084,484647,484210,\r
+       483773,483336,482900,482465,482029,481595,481160,480726,\r
+       480292,479859,479426,478994,478562,478130,477699,477268,\r
+       476837,476407,475977,475548,475119,474690,474262,473834,\r
+       473407,472979,472553,472126,471701,471275,470850,470425,\r
+       470001,469577,469153,468730,468307,467884,467462,467041,\r
+       466619,466198,465778,465358,464938,464518,464099,463681,\r
+       463262,462844,462427,462010,461593,461177,460760,460345,\r
+       459930,459515,459100,458686,458272,457859,457446,457033,\r
+       456621,456209,455797,455386,454975,454565,454155,453745,\r
+       453336,452927,452518,452110,451702,451294,450887,450481,\r
+       450074,449668,449262,448857,448452,448048,447644,447240,\r
+       446836,446433,446030,445628,445226,444824,444423,444022,\r
+       443622,443221,442821,442422,442023,441624,441226,440828,\r
+       440430,440033,439636,439239,438843,438447,438051,437656,\r
+       437261,436867,436473,436079,435686,435293,434900,434508,\r
+       434116,433724,433333,432942,432551,432161,431771,431382,\r
+       430992,430604,430215,429827,429439,429052,428665,428278,\r
+       427892,427506,427120,426735,426350,425965,425581,425197,\r
+       424813,424430,424047,423665,423283,422901,422519,422138,\r
+       421757,421377,420997,420617,420237,419858,419479,419101,\r
+       418723,418345,417968,417591,417214,416838,416462,416086,\r
+       415711,415336,414961,414586,414212,413839,413465,413092,\r
+       412720,412347,411975,411604,411232,410862,410491,410121,\r
+       409751,409381,409012,408643,408274,407906,407538,407170,\r
+       406803,406436,406069,405703,405337,404971,404606,404241,\r
+       403876,403512,403148,402784,402421,402058,401695,401333,\r
+       400970,400609,400247,399886,399525,399165,398805,398445,\r
+       398086,397727,397368,397009,396651,396293,395936,395579,\r
+       395222,394865,394509,394153,393798,393442,393087,392733,\r
+       392378,392024,391671,391317,390964,390612,390259,389907,\r
+       389556,389204,388853,388502,388152,387802,387452,387102,\r
+       386753,386404,386056,385707,385359,385012,384664,384317,\r
+       383971,383624,383278,382932,382587,382242,381897,381552,\r
+       381208,380864,380521,380177,379834,379492,379149,378807,\r
+       378466,378124,377783,377442,377102,376762,376422,376082,\r
+       375743,375404,375065,374727,374389,374051,373714,373377,\r
+       373040,372703,372367,372031,371695,371360,371025,370690,\r
+       370356,370022,369688,369355,369021,368688,368356,368023,\r
+       367691,367360,367028,366697,366366,366036,365706,365376,\r
+       365046,364717,364388,364059,363731,363403,363075,362747,\r
+       362420,362093,361766,361440,361114,360788,360463,360137,\r
+       359813,359488,359164,358840,358516,358193,357869,357547,\r
+       357224,356902,356580,356258,355937,355616,355295,354974,\r
+       354654,354334,354014,353695,353376,353057,352739,352420,\r
+       352103,351785,351468,351150,350834,350517,350201,349885,\r
+       349569,349254,348939,348624,348310,347995,347682,347368,\r
+       347055,346741,346429,346116,345804,345492,345180,344869,\r
+       344558,344247,343936,343626,343316,343006,342697,342388,\r
+       342079,341770,341462,341154,340846,340539,340231,339924,\r
+       339618,339311,339005,338700,338394,338089,337784,337479,\r
+       337175,336870,336566,336263,335959,335656,335354,335051,\r
+       334749,334447,334145,333844,333542,333242,332941,332641,\r
+       332341,332041,331741,331442,331143,330844,330546,330247,\r
+       329950,329652,329355,329057,328761,328464,328168,327872,\r
+       327576,327280,326985,326690,326395,326101,325807,325513,\r
+       325219,324926,324633,324340,324047,323755,323463,323171,\r
+       322879,322588,322297,322006,321716,321426,321136,320846,\r
+       320557,320267,319978,319690,319401,319113,318825,318538,\r
+       318250,317963,317676,317390,317103,316817,316532,316246,\r
+       315961,315676,315391,315106,314822,314538,314254,313971,\r
+       313688,313405,313122,312839,312557,312275,311994,311712,\r
+       311431,311150,310869,310589,310309,310029,309749,309470,\r
+       309190,308911,308633,308354,308076,307798,307521,307243,\r
+       306966,306689,306412,306136,305860,305584,305308,305033,\r
+       304758,304483,304208,303934,303659,303385,303112,302838,\r
+       302565,302292,302019,301747,301475,301203,300931,300660,\r
+       300388,300117,299847,299576,299306,299036,298766,298497,\r
+       298227,297958,297689,297421,297153,296884,296617,296349,\r
+       296082,295815,295548,295281,295015,294749,294483,294217,\r
+       293952,293686,293421,293157,292892,292628,292364,292100,\r
+       291837,291574,291311,291048,290785,290523,290261,289999,\r
+       289737,289476,289215,288954,288693,288433,288173,287913,\r
+       287653,287393,287134,286875,286616,286358,286099,285841,\r
+       285583,285326,285068,284811,284554,284298,284041,283785,\r
+       283529,283273,283017,282762,282507,282252,281998,281743,\r
+       281489,281235,280981,280728,280475,280222,279969,279716,\r
+       279464,279212,278960,278708,278457,278206,277955,277704,\r
+       277453,277203,276953,276703,276453,276204,275955,275706,\r
+       275457,275209,274960,274712,274465,274217,273970,273722,\r
+       273476,273229,272982,272736,272490,272244,271999,271753,\r
+       271508,271263,271018,270774,270530,270286,270042,269798,\r
+       269555,269312,269069,268826,268583,268341,268099,267857\r
+};\r
+\r
+#define LOGFAC 2*16\r
+static UWORD logtab[104]={\r
+       LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,\r
+       LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,\r
+       LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,\r
+       LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,\r
+       LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,\r
+       LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,\r
+       LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,\r
+       LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,\r
+       LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,\r
+       LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,\r
+       LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,\r
+       LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,\r
+       LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,\r
+       LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,\r
+       LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,\r
+       LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,\r
+       LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,\r
+       LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,\r
+       LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,\r
+       LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,\r
+       LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,\r
+       LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,\r
+       LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,\r
+       LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,\r
+       LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,\r
+       LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431\r
+};\r
+\r
+static SBYTE PanbrelloTable[256]={\r
+         0,  2,  3,  5,  6,  8,  9, 11, 12, 14, 16, 17, 19, 20, 22, 23,\r
+        24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,\r
+        45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,\r
+        59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,\r
+        64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,\r
+        59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,\r
+        45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,\r
+        24, 23, 22, 20, 19, 17, 16, 14, 12, 11,  9,  8,  6,  5,  3,  2,\r
+         0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23,\r
+       -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,\r
+       -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,\r
+       -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,\r
+       -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,\r
+       -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,\r
+       -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,\r
+       -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2\r
+};\r
+\r
+/* returns a random value between 0 and ceil-1, ceil must be a power of two */\r
+static int getrandom(int ceil)\r
+{\r
+#ifdef HAVE_SRANDOM\r
+       return random()&(ceil-1);\r
+#else\r
+       return (rand()*ceil)/(RAND_MAX+1.0);\r
+       //return ceil - 1;\r
+#endif\r
+}\r
+\r
+/*     New Note Action Scoring System :\r
+       --------------------------------\r
+       1)      total-volume (fadevol, chanvol, volume) is the main scorer.\r
+       2)      a looping sample is a bonus x2\r
+       3)      a foreground channel is a bonus x4\r
+       4)      an active envelope with keyoff is a handicap -x2\r
+*/\r
+static int MP_FindEmptyChannel(MODULE *mod)\r
+{\r
+       MP_VOICE *a;\r
+       ULONG t,k,tvol,pp;\r
+\r
+       for (t=0;t<md_sngchn;t++)\r
+               if (((mod->voice[t].main.kick==KICK_ABSENT)||\r
+                        (mod->voice[t].main.kick==KICK_ENV))&&\r
+                  Voice_Stopped_internal(t))\r
+                       return t;\r
+\r
+       tvol=0xffffffUL;t=-1;a=mod->voice;\r
+       for (k=0;k<md_sngchn;k++,a++) {\r
+               /* allow us to take over a nonexisting sample */\r
+               if (!a->main.s)\r
+                       return k;\r
+\r
+               if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) {\r
+                       pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0);\r
+                       if ((a->master)&&(a==a->master->slave))\r
+                               pp<<=2;\r
+\r
+                       if (pp<tvol) {\r
+                               tvol=pp;\r
+                               t=k;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (tvol>8000*7) return -1;\r
+       return t;\r
+}\r
+\r
+static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)\r
+{\r
+       if ((p1==p2)||(p==p1)) return v1;\r
+       return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1));\r
+}\r
+\r
+UWORD getlinearperiod(UWORD note,ULONG fine)\r
+{\r
+       UWORD t;\r
+\r
+       t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1);\r
+       return t;\r
+}\r
+\r
+static UWORD getlogperiod(UWORD note,ULONG fine)\r
+{\r
+       UWORD n,o;\r
+       UWORD p1,p2;\r
+       ULONG i;\r
+\r
+       n=note%(2*OCTAVE);\r
+       o=note/(2*OCTAVE);\r
+       i=(n<<2)+(fine>>4); /* n*8 + fine/16 */\r
+\r
+       p1=logtab[i];\r
+       p2=logtab[i+1];\r
+\r
+       return (Interpolate(fine>>4,0,15,p1,p2)>>o);\r
+}\r
+\r
+static UWORD getoldperiod(UWORD note,ULONG speed)\r
+{\r
+       UWORD n,o;\r
+\r
+       /* This happens sometimes on badly converted AMF, and old MOD */\r
+       if (!speed) {\r
+#ifdef MIKMOD_DEBUG\r
+               fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note);\r
+#endif\r
+               return 4242; /* <- prevent divide overflow.. (42 hehe) */\r
+       }\r
+\r
+       n=note%(2*OCTAVE);\r
+       o=note/(2*OCTAVE);\r
+       return ((8363L*(ULONG)oldperiods[n])>>o)/speed;\r
+}\r
+\r
+static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed)\r
+{\r
+       if (flags & UF_XMPERIODS) {\r
+               if (flags & UF_LINEAR)\r
+                               return getlinearperiod(note, speed);\r
+               else\r
+                               return getlogperiod(note, speed);\r
+       } else\r
+               return getoldperiod(note, speed);\r
+}\r
+\r
+static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)\r
+{\r
+       return (Interpolate(p,a->pos,b->pos,a->val,b->val));\r
+}\r
+\r
+static SWORD DoPan(SWORD envpan,SWORD pan)\r
+{\r
+       int newpan;\r
+\r
+       newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128);\r
+\r
+       return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan);\r
+}\r
+\r
+static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff)\r
+{\r
+       t->flg=flg;\r
+       t->pts=pts;\r
+       t->susbeg=susbeg;\r
+       t->susend=susend;\r
+       t->beg=beg;\r
+       t->end=end;\r
+       t->env=p;\r
+       t->p=0;\r
+       t->a=0;\r
+       t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1;\r
+\r
+       /* Imago Orpheus sometimes stores an extra initial point in the envelope */\r
+       if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) {\r
+               t->a++;t->b++;\r
+       }\r
+\r
+       /* Fit in the envelope, still */\r
+       if (t->a >= t->pts)\r
+               t->a = t->pts - 1;\r
+       if (t->b >= t->pts)\r
+               t->b = t->pts-1;\r
+\r
+       return t->env[t->a].val;\r
+}\r
+\r
+/* This procedure processes all envelope types, include volume, pitch, and\r
+   panning.  Envelopes are defined by a set of points, each with a magnitude\r
+   [relating either to volume, panning position, or pitch modifier] and a tick\r
+   position.\r
+\r
+   Envelopes work in the following manner:\r
+\r
+   (a) Each tick the envelope is moved a point further in its progression. For\r
+       an accurate progression, magnitudes between two envelope points are\r
+       interpolated.\r
+\r
+   (b) When progression reaches a defined point on the envelope, values are\r
+       shifted to interpolate between this point and the next, and checks for\r
+       loops or envelope end are done.\r
+\r
+   Misc:\r
+     Sustain loops are loops that are only active as long as the keyoff flag is\r
+     clear.  When a volume envelope terminates, so does the current fadeout.\r
+*/\r
+static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v)\r
+{\r
+       if (t->flg & EF_ON) {\r
+               UBYTE a, b;             /* actual points in the envelope */\r
+               UWORD p;                /* the 'tick counter' - real point being played */\r
+\r
+               a = t->a;\r
+               b = t->b;\r
+               p = t->p;\r
+\r
+               /*\r
+                * Sustain loop on one point (XM type).\r
+                * Not processed if KEYOFF.\r
+                * Don't move and don't interpolate when the point is reached\r
+                */\r
+               if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend &&\r
+                  (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) {\r
+                       v = t->env[t->susbeg].val;\r
+               } else {\r
+                       /*\r
+                        * All following situations will require interpolation between\r
+                        * two envelope points.\r
+                        */\r
+\r
+                       /*\r
+                        * Sustain loop between two points (IT type).\r
+                        * Not processed if KEYOFF.\r
+                        */\r
+                       /* if we were on a loop point, loop now */\r
+                       if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) &&\r
+                          a >= t->susend) {\r
+                               a = t->susbeg;\r
+                               b = (t->susbeg==t->susend)?a:a+1;\r
+                               p = t->env[a].pos;\r
+                               v = t->env[a].val;\r
+                       } else\r
+                       /*\r
+                        * Regular loop.\r
+                        * Be sure to correctly handle single point loops.\r
+                        */\r
+                       if ((t->flg & EF_LOOP) && a >= t->end) {\r
+                               a = t->beg;\r
+                               b = t->beg == t->end ? a : a + 1;\r
+                               p = t->env[a].pos;\r
+                               v = t->env[a].val;\r
+                       } else\r
+                       /*\r
+                        * Non looping situations.\r
+                        */\r
+                       if (a != b)\r
+                               v = InterpolateEnv(p, &t->env[a], &t->env[b]);\r
+                       else\r
+                               v = t->env[a].val;\r
+\r
+                       /*\r
+                        * Start to fade if the volume envelope is finished.\r
+                        */\r
+                       if (p >= t->env[t->pts - 1].pos) {\r
+                               if (t->flg & EF_VOLENV) {\r
+                                       aout->main.keyoff |= KEY_FADE;\r
+                                       if (!v)\r
+                                               aout->main.fadevol = 0;\r
+                               }\r
+                       } else {\r
+                               p++;\r
+                               /* did pointer reach point b? */\r
+                               if (p >= t->env[b].pos)\r
+                                       a = b++; /* shift points a and b */\r
+                       }\r
+                       t->a = a;\r
+                       t->b = b;\r
+                       t->p = p;\r
+               }\r
+       }\r
+       return v;\r
+}\r
+\r
+/* XM linear period to frequency conversion */\r
+ULONG getfrequency(UWORD flags,ULONG period)\r
+{\r
+       if (flags & UF_LINEAR) {\r
+               SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE;\r
+\r
+               if (shift >= 0)\r
+                       return lintab[period % 768] >> shift;\r
+               else\r
+                       return lintab[period % 768] << (-shift);\r
+       } else\r
+               return (8363L*1712L)/(period?period:1);\r
+}\r
+\r
+/*========== Protracker effects */\r
+\r
+static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style)\r
+{\r
+       UBYTE note=a->main.note;\r
+\r
+       if (a->arpmem) {\r
+               switch (style) {\r
+               case 0:         /* mod style: N, N+x, N+y */\r
+                       switch (tick % 3) {\r
+                       /* case 0: unchanged */\r
+                       case 1:\r
+                               note += (a->arpmem >> 4);\r
+                               break;\r
+                       case 2:\r
+                               note += (a->arpmem & 0xf);\r
+                               break;\r
+                       }\r
+                       break;\r
+               case 3:         /* okt arpeggio 3: N-x, N, N+y */\r
+                       switch (tick % 3) {\r
+                       case 0:\r
+                               note -= (a->arpmem >> 4);\r
+                               break;\r
+                       /* case 1: unchanged */\r
+                       case 2:\r
+                               note += (a->arpmem & 0xf);\r
+                               break;\r
+                       }\r
+                       break;\r
+               case 4:         /* okt arpeggio 4: N, N+y, N, N-x */\r
+                       switch (tick % 4) {\r
+                       /* case 0, case 2: unchanged */\r
+                       case 1:\r
+                               note += (a->arpmem & 0xf);\r
+                               break;\r
+                       case 3:\r
+                               note -= (a->arpmem >> 4);\r
+                               break;\r
+                       }\r
+                       break;\r
+               case 5:         /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */\r
+                       if (!tick)\r
+                               break;\r
+                       switch (tick % 3) {\r
+                       /* case 0: unchanged */\r
+                       case 1:\r
+                               note -= (a->arpmem >> 4);\r
+                               break;\r
+                       case 2:\r
+                               note += (a->arpmem & 0xf);\r
+                               break;\r
+                       }\r
+                       break;\r
+               }\r
+               a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed);\r
+               a->ownper = 1;\r
+       }\r
+}\r
+\r
+static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick) {\r
+               if (!dat && (flags & UF_ARPMEM))\r
+                       dat=a->arpmem;\r
+               else\r
+                       a->arpmem=dat;\r
+       }\r
+       if (a->main.period)\r
+               DoArpeggio(tick, flags, a, 0);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick && dat)\r
+               a->slidespeed = (UWORD)dat << 2;\r
+       if (a->main.period)\r
+               if (tick)\r
+                       a->tmpperiod -= a->slidespeed;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick && dat)\r
+               a->slidespeed = (UWORD)dat << 2;\r
+       if (a->main.period)\r
+               if (tick)\r
+                       a->tmpperiod += a->slidespeed;\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoToneSlide(UWORD tick, MP_CONTROL *a)\r
+{\r
+       if (!a->main.fadevol)\r
+               a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;\r
+       else\r
+               a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;\r
+\r
+       if (tick != 0) {\r
+               int dist;\r
+\r
+               /* We have to slide a->main.period towards a->wantedperiod, so compute\r
+                  the difference between those two values */\r
+               dist=a->main.period-a->wantedperiod;\r
+\r
+               /* if they are equal or if portamentospeed is too big ...*/\r
+               if (dist == 0 || a->portspeed > abs(dist))\r
+                       /* ...make tmpperiod equal tperiod */\r
+                       a->tmpperiod=a->main.period=a->wantedperiod;\r
+               else if (dist>0) {\r
+                       a->tmpperiod-=a->portspeed;     \r
+                       a->main.period-=a->portspeed; /* dist>0, slide up */\r
+               } else {\r
+                       a->tmpperiod+=a->portspeed;     \r
+                       a->main.period+=a->portspeed; /* dist<0, slide down */\r
+               }\r
+       } else\r
+               a->tmpperiod=a->main.period;\r
+       a->ownper = 1;\r
+}\r
+\r
+static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;\r
+       if (a->main.period)\r
+               DoToneSlide(tick, a);\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoVibrato(UWORD tick, MP_CONTROL *a)\r
+{\r
+       UBYTE q;\r
+       UWORD temp = 0; /* silence warning */\r
+\r
+       if (!tick)\r
+               return;\r
+\r
+       q=(a->vibpos>>2)&0x1f;\r
+\r
+       switch (a->wavecontrol&3) {\r
+       case 0: /* sine */\r
+               temp=VibratoTable[q];\r
+               break;\r
+       case 1: /* ramp down */\r
+               q<<=3;\r
+               if (a->vibpos<0) q=255-q;\r
+               temp=q;\r
+               break;\r
+       case 2: /* square wave */\r
+               temp=255;\r
+               break;\r
+       case 3: /* random wave */\r
+               temp=getrandom(256);\r
+               break;\r
+       }\r
+\r
+       temp*=a->vibdepth;\r
+       temp>>=7;temp<<=2;\r
+\r
+       if (a->vibpos>=0)\r
+               a->main.period=a->tmpperiod+temp;\r
+       else\r
+               a->main.period=a->tmpperiod-temp;\r
+       a->ownper = 1;\r
+\r
+       if (tick != 0)\r
+               a->vibpos+=a->vibspd;\r
+}\r
+\r
+static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->vibdepth=dat&0xf;\r
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+       }\r
+       if (a->main.period)\r
+               DoVibrato(tick, a);\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoVolSlide(MP_CONTROL *a, UBYTE dat)\r
+{\r
+       if (dat&0xf) {\r
+               a->tmpvolume-=(dat&0x0f);\r
+               if (a->tmpvolume<0)\r
+                       a->tmpvolume=0;\r
+       } else {\r
+               a->tmpvolume+=(dat>>4);\r
+               if (a->tmpvolume>64)\r
+                       a->tmpvolume=64;\r
+       }\r
+}\r
+\r
+static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (a->main.period)\r
+               DoToneSlide(tick, a);\r
+\r
+       if (tick)\r
+               DoVolSlide(a, dat);\r
+\r
+       return 0;\r
+}\r
+\r
+/* DoPTEffect6 after DoPTEffectA */\r
+\r
+static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       UBYTE q;\r
+       UWORD temp = 0; /* silence warning */\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->trmdepth=dat&0xf;\r
+               if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;\r
+       }\r
+       if (a->main.period) {\r
+               q=(a->trmpos>>2)&0x1f;\r
+\r
+               switch ((a->wavecontrol>>4)&3) {\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+               case 1: /* ramp down */\r
+                       q<<=3;\r
+                       if (a->trmpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+               case 2: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+               case 3: /* random wave */\r
+                       temp=getrandom(256);\r
+                       break;\r
+               }\r
+               temp*=a->trmdepth;\r
+               temp>>=6;\r
+\r
+               if (a->trmpos>=0) {\r
+                       a->volume=a->tmpvolume+temp;\r
+                       if (a->volume>64) a->volume=64;\r
+               } else {\r
+                       a->volume=a->tmpvolume-temp;\r
+                       if (a->volume<0) a->volume=0;\r
+               }\r
+               a->ownvol = 1;\r
+\r
+               if (tick)\r
+                       a->trmpos+=a->trmspd;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)tick;\r
+\r
+       dat = UniGetByte();\r
+       if (mod->panflag)\r
+               a->main.panning = mod->panning[channel] = dat;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat) a->soffset=(UWORD)dat<<8;\r
+               a->main.start=a->hioffset|a->soffset;\r
+\r
+               if ((a->main.s)&&(a->main.start>a->main.s->length))\r
+                       a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?\r
+                           a->main.s->loopstart:a->main.s->length;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (tick)\r
+               DoVolSlide(a, dat);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       if (a->main.period)\r
+               DoVibrato(tick, a);\r
+       DoPTEffectA(tick, flags, a, mod, channel);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+\r
+       if (tick || mod->patdly2)\r
+               return 0;\r
+\r
+       /* Vincent Voois uses a nasty trick in "Universal Bolero" */\r
+       if (dat == mod->sngpos && mod->patbrk == mod->patpos)\r
+               return 0;\r
+\r
+       if (!mod->loop && !mod->patbrk &&\r
+           (dat < mod->sngpos ||\r
+                (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||\r
+            (dat == mod->sngpos && (flags & UF_NOWRAP))\r
+               )) {\r
+               /* if we don't loop, better not to skip the end of the\r
+                  pattern, after all... so:\r
+               mod->patbrk=0; */\r
+               mod->posjmp=3;\r
+       } else {\r
+               /* if we were fading, adjust... */\r
+               if (mod->sngpos == (mod->numpos-1))\r
+                       mod->volume=mod->initvolume>128?128:mod->initvolume;\r
+               mod->sngpos=dat;\r
+               mod->posjmp=2;\r
+               mod->patpos=0;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+                       dat=UniGetByte();\r
+                       if (tick) return 0;\r
+                       if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */\r
+                       else if (dat>64) dat=64;\r
+                       a->tmpvolume=dat;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+                       dat=UniGetByte();\r
+                       if ((tick)||(mod->patdly2)) return 0;\r
+                       if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&\r
+                          (dat>mod->pattrows[mod->positions[mod->sngpos]]))\r
+                               dat=mod->pattrows[mod->positions[mod->sngpos]];\r
+                       mod->patbrk=dat;\r
+                       if (!mod->posjmp) {\r
+                               /* don't ask me to explain this code - it makes\r
+                                  backwards.s3m and children.xm (heretic's version) play\r
+                                  correctly, among others. Take that for granted, or write\r
+                                  the page of comments yourself... you might need some\r
+                                  aspirin - Miod */\r
+                               if ((mod->sngpos==mod->numpos-1)&&(dat)&&((mod->loop)||\r
+                                              (mod->positions[mod->sngpos]==(mod->numpat-1)\r
+                                                               && !(flags&UF_NOWRAP)))) {\r
+                                       mod->sngpos=0;\r
+                                       mod->posjmp=2;\r
+                               } else\r
+                                       mod->posjmp=3;\r
+                       }\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,\r
+       SWORD channel, UBYTE dat)\r
+{\r
+       UBYTE nib = dat & 0xf;\r
+\r
+       switch (dat>>4) {\r
+       case 0x0: /* hardware filter toggle, not supported */\r
+               break;\r
+       case 0x1: /* fineslide up */\r
+               if (a->main.period)\r
+                       if (!tick)\r
+                               a->tmpperiod-=(nib<<2);\r
+               break;\r
+       case 0x2: /* fineslide dn */\r
+               if (a->main.period)\r
+                       if (!tick)\r
+                               a->tmpperiod+=(nib<<2);\r
+               break;\r
+       case 0x3: /* glissando ctrl */\r
+               a->glissando=nib;\r
+               break;\r
+       case 0x4: /* set vibrato waveform */\r
+               a->wavecontrol&=0xf0;\r
+               a->wavecontrol|=nib;\r
+               break;\r
+       case 0x5: /* set finetune */\r
+               if (a->main.period) {\r
+                       if (flags&UF_XMPERIODS)\r
+                               a->speed=nib+128;\r
+                       else\r
+                               a->speed=finetune[nib];\r
+                       a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);\r
+               }\r
+               break;\r
+       case 0x6: /* set patternloop */\r
+               if (tick)\r
+                       break;\r
+               if (nib) { /* set reppos or repcnt ? */\r
+                       /* set repcnt, so check if repcnt already is set, which means we\r
+                          are already looping */\r
+                       if (a->pat_repcnt)\r
+                               a->pat_repcnt--; /* already looping, decrease counter */\r
+                       else {\r
+#if 0\r
+                               /* this would make walker.xm, shipped with Xsoundtracker,\r
+                                  play correctly, but it's better to remain compatible\r
+                                  with FT2 */\r
+                               if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))\r
+#endif\r
+                                       a->pat_repcnt=nib; /* not yet looping, so set repcnt */\r
+                       }\r
+\r
+                       if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */\r
+                               if (a->pat_reppos==POS_NONE)\r
+                                       a->pat_reppos=mod->patpos-1;\r
+                               if (a->pat_reppos==-1) {\r
+                                       mod->pat_repcrazy=1;\r
+                                       mod->patpos=0;\r
+                               } else\r
+                                       mod->patpos=a->pat_reppos;\r
+                       } else a->pat_reppos=POS_NONE;\r
+               } else\r
+                       a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */\r
+               break;\r
+       case 0x7: /* set tremolo waveform */\r
+               a->wavecontrol&=0x0f;\r
+               a->wavecontrol|=nib<<4;\r
+               break;\r
+       case 0x8: /* set panning */\r
+               if (mod->panflag) {\r
+                       if (nib<=8) nib<<=4;\r
+                       else nib*=17;\r
+                       a->main.panning=mod->panning[channel]=nib;\r
+               }\r
+               break;\r
+       case 0x9: /* retrig note */\r
+               /* do not retrigger on tick 0, until we are emulating FT2 and effect\r
+                  data is zero */\r
+               if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))\r
+                       break;\r
+               /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */\r
+               if (nib || !tick) {\r
+                       if (!a->retrig) {\r
+                               /* when retrig counter reaches 0, reset counter and restart\r
+                                  the sample */\r
+                               if (a->main.period) a->main.kick=KICK_NOTE;\r
+                               a->retrig=nib;\r
+                       }\r
+                       a->retrig--; /* countdown */\r
+               }\r
+               break;\r
+       case 0xa: /* fine volume slide up */\r
+               if (tick)\r
+                       break;\r
+               a->tmpvolume+=nib;\r
+               if (a->tmpvolume>64) a->tmpvolume=64;\r
+               break;\r
+       case 0xb: /* fine volume slide dn  */\r
+               if (tick)\r
+                       break;\r
+               a->tmpvolume-=nib;\r
+               if (a->tmpvolume<0)a->tmpvolume=0;\r
+               break;\r
+       case 0xc: /* cut note */\r
+               /* When tick reaches the cut-note value, turn the volume to\r
+                  zero (just like on the amiga) */\r
+               if (tick>=nib)\r
+                       a->tmpvolume=0; /* just turn the volume down */\r
+               break;\r
+       case 0xd: /* note delay */\r
+               /* delay the start of the sample until tick==nib */\r
+               if (!tick)\r
+                       a->main.notedelay=nib;\r
+               else if (a->main.notedelay)\r
+                       a->main.notedelay--;\r
+               break;\r
+       case 0xe: /* pattern delay */\r
+               if (!tick)\r
+                       if (!mod->patdly2)\r
+                               mod->patdly=nib+1; /* only once, when tick=0 */\r
+               break;\r
+       case 0xf: /* invert loop, not supported  */\r
+               break;\r
+       }\r
+}\r
+\r
+static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       DoEEffects(tick, flags, a, mod, channel, UniGetByte());\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (tick||mod->patdly2) return 0;\r
+       if (mod->extspd&&(dat>=mod->bpmlimit))\r
+               mod->bpm=dat;\r
+       else \r
+         if (dat) {\r
+               mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;\r
+               mod->vbtick=0;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Scream Tracker effects */\r
+\r
+static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE speed;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       speed = UniGetByte();\r
+\r
+       if (tick || mod->patdly2)\r
+               return 0;\r
+\r
+       if (speed > 128)\r
+               speed -= 128;\r
+       if (speed) {\r
+               mod->sngspd = speed;\r
+               mod->vbtick = 0;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)\r
+{\r
+       UBYTE lo, hi;\r
+\r
+       if (inf)\r
+               a->s3mvolslide=inf;\r
+       else\r
+               inf=a->s3mvolslide;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if (!lo) {\r
+               if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;\r
+       } else\r
+         if (!hi) {\r
+               if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;\r
+       } else\r
+         if (lo==0xf) {\r
+               if (!tick) a->tmpvolume+=(hi?hi:0xf);\r
+       } else\r
+         if (hi==0xf) {\r
+               if (!tick) a->tmpvolume-=(lo?lo:0xf);\r
+       } else\r
+         return;\r
+\r
+       if (a->tmpvolume<0)\r
+               a->tmpvolume=0;\r
+       else if (a->tmpvolume>64)\r
+               a->tmpvolume=64;\r
+}\r
+\r
+static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       DoS3MVolSlide(tick, flags, a, UniGetByte());\r
+\r
+       return 1;\r
+}\r
+\r
+static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if (inf)\r
+               a->slidespeed=inf;\r
+       else\r
+               inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if (hi==0xf) {\r
+               if (!tick) a->tmpperiod+=(UWORD)lo<<2;\r
+       } else\r
+         if (hi==0xe) {\r
+               if (!tick) a->tmpperiod+=lo;\r
+       } else {\r
+               if (tick) a->tmpperiod+=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (a->main.period)\r
+               DoS3MSlideDn(tick, a,dat);\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if (inf) a->slidespeed=inf;\r
+       else inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if (hi==0xf) {\r
+               if (!tick) a->tmpperiod-=(UWORD)lo<<2;\r
+       } else\r
+         if (hi==0xe) {\r
+               if (!tick) a->tmpperiod-=lo;\r
+       } else {\r
+               if (tick) a->tmpperiod-=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (a->main.period)\r
+               DoS3MSlideUp(tick, a,dat);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, on, off;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (inf)\r
+               a->s3mtronof = inf;\r
+       else {\r
+               inf = a->s3mtronof;\r
+               if (!inf)\r
+                       return 0;\r
+       }\r
+\r
+       if (!tick)\r
+               return 0;\r
+\r
+       on=(inf>>4)+1;\r
+       off=(inf&0xf)+1;\r
+       a->s3mtremor%=(on+off);\r
+       a->volume=(a->s3mtremor<on)?a->tmpvolume:0;\r
+       a->ownvol=1;\r
+       a->s3mtremor++;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (a->main.period) {\r
+               if (inf) {\r
+                       a->s3mrtgslide=inf>>4;\r
+                       a->s3mrtgspeed=inf&0xf;\r
+               }\r
+\r
+               /* only retrigger if low nibble > 0 */\r
+               if (a->s3mrtgspeed>0) {\r
+                       if (!a->retrig) {\r
+                               /* when retrig counter reaches 0, reset counter and restart the\r
+                                  sample */\r
+                               if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;\r
+                               a->retrig=a->s3mrtgspeed;\r
+\r
+                               if ((tick)||(flags&UF_S3MSLIDES)) {\r
+                                       switch (a->s3mrtgslide) {\r
+                                       case 1:\r
+                                       case 2:\r
+                                       case 3:\r
+                                       case 4:\r
+                                       case 5:\r
+                                               a->tmpvolume-=(1<<(a->s3mrtgslide-1));\r
+                                               break;\r
+                                       case 6:\r
+                                               a->tmpvolume=(2*a->tmpvolume)/3;\r
+                                               break;\r
+                                       case 7:\r
+                                               a->tmpvolume>>=1;\r
+                                               break;\r
+                                       case 9:\r
+                                       case 0xa:\r
+                                       case 0xb:\r
+                                       case 0xc:\r
+                                       case 0xd:\r
+                                               a->tmpvolume+=(1<<(a->s3mrtgslide-9));\r
+                                               break;\r
+                                       case 0xe:\r
+                                               a->tmpvolume=(3*a->tmpvolume)>>1;\r
+                                               break;\r
+                                       case 0xf:\r
+                                               a->tmpvolume=a->tmpvolume<<1;\r
+                                               break;\r
+                                       }\r
+                                       if (a->tmpvolume<0)\r
+                                               a->tmpvolume=0;\r
+                                       else if (a->tmpvolume>64)\r
+                                               a->tmpvolume=64;\r
+                               }\r
+                       }\r
+                       a->retrig--; /* countdown  */\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, q;\r
+       UWORD temp=0;   /* silence warning */\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->trmdepth=dat&0xf;\r
+               if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;\r
+       }\r
+\r
+       q=(a->trmpos>>2)&0x1f;\r
+\r
+       switch ((a->wavecontrol>>4)&3) {\r
+       case 0: /* sine */\r
+               temp=VibratoTable[q];\r
+               break;\r
+       case 1: /* ramp down */\r
+               q<<=3;\r
+               if (a->trmpos<0) q=255-q;\r
+               temp=q;\r
+               break;\r
+       case 2: /* square wave */\r
+               temp=255;\r
+               break;\r
+       case 3: /* random */\r
+               temp=getrandom(256);\r
+               break;\r
+       }\r
+\r
+       temp*=a->trmdepth;\r
+       temp>>=7;\r
+\r
+       if (a->trmpos>=0) {\r
+               a->volume=a->tmpvolume+temp;\r
+               if (a->volume>64) a->volume=64;\r
+       } else {\r
+               a->volume=a->tmpvolume-temp;\r
+               if (a->volume<0) a->volume=0;\r
+       }\r
+       a->ownvol = 1;\r
+\r
+       if (tick)\r
+               a->trmpos+=a->trmspd;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE tempo;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       tempo = UniGetByte();\r
+\r
+       if (tick || mod->patdly2)\r
+               return 0;\r
+\r
+       mod->bpm = (tempo < 32) ? 32 : tempo;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, q;\r
+       UWORD temp = 0; /* silence warning */\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->vibdepth=dat&0xf;\r
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+       } else\r
+               if (a->main.period) {\r
+                       q=(a->vibpos>>2)&0x1f;\r
+\r
+                       switch (a->wavecontrol&3) {\r
+                       case 0: /* sine */\r
+                               temp=VibratoTable[q];\r
+                               break;\r
+                       case 1: /* ramp down */\r
+                               q<<=3;\r
+                               if (a->vibpos<0) q=255-q;\r
+                               temp=q;\r
+                               break;\r
+                       case 2: /* square wave */\r
+                               temp=255;\r
+                               break;\r
+                       case 3: /* random */\r
+                               temp=getrandom(256);\r
+                               break;\r
+                       }\r
+\r
+                       temp*=a->vibdepth;\r
+                       temp>>=8;\r
+\r
+                       if (a->vibpos>=0)\r
+                               a->main.period=a->tmpperiod+temp;\r
+                       else\r
+                               a->main.period=a->tmpperiod-temp;\r
+                       a->ownper = 1;\r
+\r
+                       a->vibpos+=a->vibspd;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Envelope helpers */\r
+\r
+static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       a->main.keyoff|=KEY_OFF;\r
+       if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))\r
+               a->main.keyoff=KEY_KILL;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if ((tick>=dat)||(tick==mod->sngspd-1)) {\r
+               a->main.keyoff=KEY_KILL;\r
+               if (!(a->main.volflg&EF_ON))\r
+                       a->main.fadevol=0;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Fast Tracker effects */\r
+\r
+/* DoXMEffect6 after DoXMEffectA */\r
+\r
+static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, lo, hi;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (inf)\r
+               a->s3mvolslide = inf;\r
+       else\r
+               inf = a->s3mvolslide;\r
+       \r
+       if (tick) {\r
+               lo=inf&0xf;\r
+               hi=inf>>4;\r
+\r
+               if (!hi) {\r
+                       a->tmpvolume-=lo;\r
+                       if (a->tmpvolume<0) a->tmpvolume=0;\r
+               } else {\r
+                       a->tmpvolume+=hi;\r
+                       if (a->tmpvolume>64) a->tmpvolume=64;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       if (a->main.period)\r
+               DoVibrato(tick, a);\r
+\r
+       return DoXMEffectA(tick, flags, a, mod, channel);\r
+}\r
+\r
+static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat) a->fportupspd=dat;\r
+               if (a->main.period)\r
+                       a->tmpperiod-=(a->fportupspd<<2);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat) a->fportdnspd=dat;\r
+               if (a->main.period)\r
+                       a->tmpperiod+=(a->fportdnspd<<2);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick)\r
+               if (dat) a->fslideupspd=dat;\r
+       a->tmpvolume+=a->fslideupspd;\r
+       if (a->tmpvolume>64) a->tmpvolume=64;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if (!tick)\r
+               if (dat) a->fslidednspd=dat;\r
+       a->tmpvolume-=a->fslidednspd;\r
+       if (a->tmpvolume<0) a->tmpvolume=0;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       mod->volume=UniGetByte()<<1;\r
+       if (mod->volume>128) mod->volume=128;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+\r
+       if (tick) {\r
+               if (inf) mod->globalslide=inf;\r
+               else inf=mod->globalslide;\r
+               if (inf & 0xf0) inf&=0xf0;\r
+               mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;\r
+\r
+               if (mod->volume<0)\r
+                       mod->volume=0;\r
+               else if (mod->volume>128)\r
+                       mod->volume=128;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat=UniGetByte();\r
+       if ((!tick)&&(a->main.i)) {\r
+               UWORD points;\r
+               INSTRUMENT *i=a->main.i;\r
+               MP_VOICE *aout;\r
+\r
+               if ((aout=a->slave)) {\r
+                       if (aout->venv.env) {\r
+                               points=i->volenv[i->volpts-1].pos;\r
+                               aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;\r
+                       }\r
+                       if (aout->penv.env) {\r
+                               points=i->panenv[i->panpts-1].pos;\r
+                               aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, lo, hi;\r
+       SWORD pan;\r
+       (void)flags;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (!mod->panflag)\r
+               return 0;\r
+\r
+       if (inf)\r
+               a->pansspd = inf;\r
+       else\r
+               inf =a->pansspd;\r
+\r
+       if (tick) {\r
+               lo=inf&0xf;\r
+               hi=inf>>4;\r
+\r
+               /* slide right has absolute priority */\r
+               if (hi)\r
+                       lo = 0;\r
+\r
+               pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;\r
+               a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (dat)\r
+               a->ffportupspd = dat;\r
+       else\r
+               dat = a->ffportupspd;\r
+\r
+       if (a->main.period)\r
+               if (!tick) {\r
+                       a->main.period-=dat;\r
+                       a->tmpperiod-=dat;\r
+                       a->ownper = 1;\r
+               }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (dat)\r
+               a->ffportdnspd=dat;\r
+       else\r
+               dat = a->ffportdnspd;\r
+\r
+       if (a->main.period)\r
+               if (!tick) {\r
+                       a->main.period+=dat;\r
+                       a->tmpperiod+=dat;\r
+                       a->ownper = 1;\r
+               }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Impulse Tracker effects */\r
+\r
+static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)\r
+{\r
+       if (dat)\r
+               a->portspeed = dat;\r
+\r
+       /* if we don't come from another note, ignore the slide and play the note\r
+          as is */\r
+       if (!a->oldnote || !a->main.period)\r
+                       return;\r
+\r
+       if ((!tick)&&(a->newsamp)){\r
+               a->main.kick=KICK_NOTE;\r
+               a->main.start=-1;\r
+       } else\r
+               a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;\r
+\r
+       if (tick) {\r
+               int dist;\r
+\r
+               /* We have to slide a->main.period towards a->wantedperiod, compute the\r
+                  difference between those two values */\r
+               dist=a->main.period-a->wantedperiod;\r
+\r
+           /* if they are equal or if portamentospeed is too big... */\r
+               if ((!dist)||((a->portspeed<<2)>abs(dist)))\r
+                       /* ... make tmpperiod equal tperiod */\r
+                       a->tmpperiod=a->main.period=a->wantedperiod;\r
+               else\r
+                 if (dist>0) { \r
+                       a->tmpperiod-=a->portspeed<<2;\r
+                       a->main.period-=a->portspeed<<2; /* dist>0 slide up */\r
+               } else {                                \r
+                       a->tmpperiod+=a->portspeed<<2;\r
+                       a->main.period+=a->portspeed<<2; /* dist<0 slide down */\r
+               }\r
+       } else\r
+               a->tmpperiod=a->main.period;\r
+       a->ownper=1;\r
+}\r
+\r
+static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       DoITToneSlide(tick, a, UniGetByte());\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)\r
+{\r
+       UBYTE q;\r
+       UWORD temp=0;\r
+\r
+       if (!tick) {\r
+               if (dat&0x0f) a->vibdepth=dat&0xf;\r
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+       }\r
+       if (!a->main.period)\r
+                       return;\r
+\r
+       q=(a->vibpos>>2)&0x1f;\r
+\r
+       switch (a->wavecontrol&3) {\r
+       case 0: /* sine */\r
+               temp=VibratoTable[q];\r
+               break;\r
+       case 1: /* square wave */\r
+               temp=255;\r
+               break;\r
+       case 2: /* ramp down */\r
+               q<<=3;\r
+               if (a->vibpos<0) q=255-q;\r
+               temp=q;\r
+               break;\r
+       case 3: /* random */\r
+               temp=getrandom(256);\r
+               break;\r
+       }\r
+\r
+       temp*=a->vibdepth;\r
+       temp>>=8;\r
+       temp<<=2;\r
+\r
+       if (a->vibpos>=0)\r
+               a->main.period=a->tmpperiod+temp;\r
+       else\r
+               a->main.period=a->tmpperiod-temp;\r
+       a->ownper=1;\r
+\r
+       a->vibpos+=a->vibspd;\r
+}\r
+\r
+static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       DoITVibrato(tick, a, UniGetByte());\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, on, off;\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (inf)\r
+               a->s3mtronof = inf;\r
+       else {\r
+               inf = a->s3mtronof;\r
+               if (!inf)\r
+                       return 0;\r
+       }\r
+\r
+       on=(inf>>4);\r
+       off=(inf&0xf);\r
+\r
+       a->s3mtremor%=(on+off);\r
+       a->volume=(a->s3mtremor<on)?a->tmpvolume:0;\r
+       a->ownvol = 1;\r
+       a->s3mtremor++;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       a->main.chanvol=UniGetByte();\r
+       if (a->main.chanvol>64)\r
+               a->main.chanvol=64;\r
+       else if (a->main.chanvol<0)\r
+               a->main.chanvol=0;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, lo, hi;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+\r
+       if (inf)\r
+               a->chanvolslide = inf;\r
+       else\r
+               inf = a->chanvolslide;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if (!hi) \r
+               a->main.chanvol-=lo;\r
+       else\r
+         if (!lo) {\r
+               a->main.chanvol+=hi;\r
+       } else\r
+         if (hi==0xf) {\r
+               if (!tick) a->main.chanvol-=lo;\r
+       } else\r
+         if (lo==0xf) {\r
+               if (!tick) a->main.chanvol+=hi;\r
+       }\r
+\r
+       if (a->main.chanvol<0)\r
+               a->main.chanvol=0;\r
+       else if (a->main.chanvol>64)\r
+               a->main.chanvol=64;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, lo, hi;\r
+       SWORD pan;\r
+       (void)flags;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+       if (inf)\r
+               a->pansspd = inf;\r
+       else\r
+               inf = a->pansspd;\r
+\r
+       if (!mod->panflag)\r
+               return 0;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;\r
+\r
+       if (!hi)\r
+               pan+=lo<<2;\r
+       else\r
+         if (!lo) {\r
+               pan-=hi<<2;\r
+       } else\r
+         if (hi==0xf) {\r
+               if (!tick) pan+=lo<<2;\r
+       } else\r
+         if (lo==0xf) {\r
+               if (!tick) pan-=hi<<2;\r
+       }\r
+       a->main.panning=\r
+         (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE tempo;\r
+       SWORD temp;\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       tempo = UniGetByte();\r
+\r
+       if (mod->patdly2)\r
+               return 0;\r
+\r
+       temp = mod->bpm;\r
+       if (tempo & 0x10)\r
+               temp += (tempo & 0x0f);\r
+       else\r
+               temp -= tempo;\r
+\r
+       mod->bpm=(temp>255)?255:(temp<1?1:temp);\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, q;\r
+       UWORD temp = 0; /* silence warning */\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat = UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->vibdepth=dat&0xf;\r
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+       }\r
+       if (a->main.period) {\r
+               q=(a->vibpos>>2)&0x1f;\r
+\r
+               switch (a->wavecontrol&3) {\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+               case 1: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+               case 2: /* ramp down */\r
+                       q<<=3;\r
+                       if (a->vibpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+               case 3: /* random */\r
+                       temp=getrandom(256);\r
+                       break;\r
+               }\r
+\r
+               temp*=a->vibdepth;\r
+               temp>>=8;\r
+\r
+               if (a->vibpos>=0)\r
+                       a->main.period=a->tmpperiod+temp;\r
+               else\r
+                       a->main.period=a->tmpperiod-temp;\r
+               a->ownper = 1;\r
+\r
+               a->vibpos+=a->vibspd;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE inf, lo, hi;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       inf = UniGetByte();\r
+\r
+       if (inf)\r
+               mod->globalslide = inf;\r
+       else\r
+               inf = mod->globalslide;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if (!lo) {\r
+               if (tick) mod->volume+=hi;\r
+       } else\r
+         if (!hi) {\r
+               if (tick) mod->volume-=lo;\r
+       } else\r
+         if (lo==0xf) {\r
+               if (!tick) mod->volume+=hi;\r
+       } else\r
+         if (hi==0xf) {\r
+               if (!tick) mod->volume-=lo;\r
+       }\r
+\r
+       if (mod->volume<0)\r
+               mod->volume=0;\r
+       else if (mod->volume>128)\r
+               mod->volume=128;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, q;\r
+       SLONG temp = 0; /* silence warning */\r
+       (void)flags;\r
+\r
+\r
+       dat=UniGetByte();\r
+       if (!tick) {\r
+               if (dat&0x0f) a->panbdepth=(dat&0xf);\r
+               if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;\r
+       }\r
+       if (mod->panflag) {\r
+               q=a->panbpos;\r
+\r
+               switch (a->panbwave) {\r
+               case 0: /* sine */\r
+                       temp=PanbrelloTable[q];\r
+                       break;\r
+               case 1: /* square wave */\r
+                       temp=(q<0x80)?64:0;\r
+                       break;\r
+               case 2: /* ramp down */\r
+                       q<<=3;\r
+                       temp=q;\r
+                       break;\r
+               case 3: /* random */\r
+                       temp=getrandom(256);\r
+                       break;\r
+               }\r
+\r
+               temp*=a->panbdepth;\r
+               temp=(temp/8)+mod->panning[channel];\r
+\r
+               a->main.panning=\r
+                       (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);\r
+               a->panbpos+=a->panbspd;\r
+\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);\r
+\r
+/* Impulse/Scream Tracker Sxx effects.\r
+   All Sxx effects share the same memory space. */\r
+static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, inf, c;\r
+\r
+       dat = UniGetByte();\r
+       inf=dat&0xf;\r
+       c=dat>>4;\r
+\r
+       if (!dat) {\r
+               c=a->sseffect;\r
+               inf=a->ssdata;\r
+       } else {\r
+               a->sseffect=c;\r
+               a->ssdata=inf;\r
+       }\r
+\r
+       switch (c) {\r
+       case SS_GLISSANDO: /* S1x set glissando voice */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x30|inf);\r
+               break;              \r
+       case SS_FINETUNE: /* S2x set finetune */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x50|inf);\r
+               break;\r
+       case SS_VIBWAVE: /* S3x set vibrato waveform */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x40|inf);\r
+               break;   \r
+       case SS_TREMWAVE: /* S4x set tremolo waveform */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x70|inf);\r
+               break;\r
+       case SS_PANWAVE: /* S5x panbrello */\r
+               a->panbwave=inf;\r
+               break;\r
+       case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */\r
+               DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);\r
+               break;\r
+       case SS_S7EFFECTS: /* S7x instrument / NNA commands */\r
+               DoNNAEffects(mod, a, inf);\r
+               break;\r
+       case SS_PANNING: /* S8x set panning position */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);\r
+               break;\r
+       case SS_SURROUND: /* S9x set surround sound */\r
+               if (mod->panflag)\r
+                       a->main.panning = mod->panning[channel] = PAN_SURROUND;\r
+               break;    \r
+       case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */\r
+               if (!tick) {\r
+                       a->hioffset=inf<<16;\r
+                       a->main.start=a->hioffset|a->soffset;\r
+\r
+                       if ((a->main.s)&&(a->main.start>a->main.s->length))\r
+                               a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?\r
+                                   a->main.s->loopstart:a->main.s->length;\r
+               }\r
+               break;\r
+       case SS_PATLOOP: /* SBx pattern loop */\r
+               DoEEffects(tick, flags, a, mod, channel, 0x60|inf);\r
+               break;\r
+       case SS_NOTECUT: /* SCx notecut */\r
+               if (!inf) inf = 1;\r
+               DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);\r
+               break;\r
+       case SS_NOTEDELAY: /* SDx notedelay */\r
+               DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);\r
+               break;\r
+       case SS_PATDELAY: /* SEx patterndelay */\r
+               DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Impulse Tracker Volume/Pan Column effects */\r
+\r
+/*\r
+ * All volume/pan column effects share the same memory space.\r
+ */\r
+\r
+static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE c, inf;\r
+       (void)channel;\r
+       \r
+       c = UniGetByte(); \r
+       inf = UniGetByte(); \r
+\r
+       if ((!c)&&(!inf)) {\r
+               c=a->voleffect;\r
+               inf=a->voldata;\r
+       } else {\r
+               a->voleffect=c;\r
+               a->voldata=inf;\r
+       }\r
+\r
+       if (c)\r
+               switch (c) {\r
+               case VOL_VOLUME:\r
+                       if (tick) break;\r
+                       if (inf>64) inf=64;\r
+                       a->tmpvolume=inf;\r
+                       break;\r
+               case VOL_PANNING:\r
+                       if (mod->panflag)\r
+                               a->main.panning=inf;\r
+                       break;\r
+               case VOL_VOLSLIDE:\r
+                       DoS3MVolSlide(tick, flags, a, inf);\r
+                       return 1;\r
+               case VOL_PITCHSLIDEDN:\r
+                       if (a->main.period)\r
+                               DoS3MSlideDn(tick, a, inf);\r
+                       break;\r
+               case VOL_PITCHSLIDEUP:\r
+                       if (a->main.period)\r
+                               DoS3MSlideUp(tick, a, inf);\r
+                       break;\r
+               case VOL_PORTAMENTO:\r
+                       DoITToneSlide(tick, a, inf);\r
+                       break;\r
+               case VOL_VIBRATO:\r
+                       DoITVibrato(tick, a, inf);\r
+                       break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== UltraTracker effects */\r
+\r
+static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UWORD offset=UniGetWord();\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       if (offset)\r
+               a->ultoffset=offset;\r
+\r
+       a->main.start=a->ultoffset<<2;\r
+       if ((a->main.s)&&(a->main.start>a->main.s->length))\r
+               a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?\r
+                   a->main.s->loopstart:a->main.s->length;\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== OctaMED effects */\r
+\r
+static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UWORD speed=UniGetWord();\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)channel;\r
+\r
+       mod->bpm=speed;\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));\r
+\r
+       return 0;\r
+}\r
+\r
+static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== Oktalyzer effects */\r
+\r
+static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UBYTE dat, dat2;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       dat2 = UniGetByte();    /* arpeggio style */\r
+       dat = UniGetByte();\r
+       if (!tick) {\r
+               if (!dat && (flags & UF_ARPMEM))\r
+                       dat=a->arpmem;\r
+               else\r
+                       a->arpmem=dat;\r
+       }\r
+       if (a->main.period)\r
+               DoArpeggio(tick, flags, a, dat2);\r
+\r
+       return 0;\r
+}\r
+\r
+/*========== General player functions */\r
+\r
+static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)\r
+{\r
+       UniSkipOpcode();\r
+       (void)tick;\r
+       (void)flags;\r
+       (void)a;\r
+       (void)mod;\r
+       (void)channel;\r
+\r
+       return 0;\r
+}\r
+\r
+typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);\r
+\r
+static effect_func effects[UNI_LAST] = {\r
+               DoNothing,              /* 0 */\r
+               DoNothing,              /* UNI_NOTE */\r
+               DoNothing,              /* UNI_INSTRUMENT */\r
+               DoPTEffect0,    /* UNI_PTEFFECT0 */\r
+               DoPTEffect1,    /* UNI_PTEFFECT1 */\r
+               DoPTEffect2,    /* UNI_PTEFFECT2 */\r
+               DoPTEffect3,    /* UNI_PTEFFECT3 */\r
+               DoPTEffect4,    /* UNI_PTEFFECT4 */\r
+               DoPTEffect5,    /* UNI_PTEFFECT5 */\r
+               DoPTEffect6,    /* UNI_PTEFFECT6 */\r
+               DoPTEffect7,    /* UNI_PTEFFECT7 */\r
+               DoPTEffect8,    /* UNI_PTEFFECT8 */\r
+               DoPTEffect9,    /* UNI_PTEFFECT9 */\r
+               DoPTEffectA,    /* UNI_PTEFFECTA */\r
+               DoPTEffectB,    /* UNI_PTEFFECTB */\r
+               DoPTEffectC,    /* UNI_PTEFFECTC */\r
+               DoPTEffectD,    /* UNI_PTEFFECTD */\r
+               DoPTEffectE,    /* UNI_PTEFFECTE */\r
+               DoPTEffectF,    /* UNI_PTEFFECTF */\r
+               DoS3MEffectA,   /* UNI_S3MEFFECTA */\r
+               DoS3MEffectD,   /* UNI_S3MEFFECTD */\r
+               DoS3MEffectE,   /* UNI_S3MEFFECTE */\r
+               DoS3MEffectF,   /* UNI_S3MEFFECTF */\r
+               DoS3MEffectI,   /* UNI_S3MEFFECTI */\r
+               DoS3MEffectQ,   /* UNI_S3MEFFECTQ */\r
+               DoS3MEffectR,   /* UNI_S3MEFFECTR */\r
+               DoS3MEffectT,   /* UNI_S3MEFFECTT */\r
+               DoS3MEffectU,   /* UNI_S3MEFFECTU */\r
+               DoKeyOff,               /* UNI_KEYOFF */\r
+               DoKeyFade,              /* UNI_KEYFADE */\r
+               DoVolEffects,   /* UNI_VOLEFFECTS */\r
+               DoPTEffect4,    /* UNI_XMEFFECT4 */\r
+               DoXMEffect6,    /* UNI_XMEFFECT6 */\r
+               DoXMEffectA,    /* UNI_XMEFFECTA */\r
+               DoXMEffectE1,   /* UNI_XMEFFECTE1 */\r
+               DoXMEffectE2,   /* UNI_XMEFFECTE2 */\r
+               DoXMEffectEA,   /* UNI_XMEFFECTEA */\r
+               DoXMEffectEB,   /* UNI_XMEFFECTEB */\r
+               DoXMEffectG,    /* UNI_XMEFFECTG */\r
+               DoXMEffectH,    /* UNI_XMEFFECTH */\r
+               DoXMEffectL,    /* UNI_XMEFFECTL */\r
+               DoXMEffectP,    /* UNI_XMEFFECTP */\r
+               DoXMEffectX1,   /* UNI_XMEFFECTX1 */\r
+               DoXMEffectX2,   /* UNI_XMEFFECTX2 */\r
+               DoITEffectG,    /* UNI_ITEFFECTG */\r
+               DoITEffectH,    /* UNI_ITEFFECTH */\r
+               DoITEffectI,    /* UNI_ITEFFECTI */\r
+               DoITEffectM,    /* UNI_ITEFFECTM */\r
+               DoITEffectN,    /* UNI_ITEFFECTN */\r
+               DoITEffectP,    /* UNI_ITEFFECTP */\r
+               DoITEffectT,    /* UNI_ITEFFECTT */\r
+               DoITEffectU,    /* UNI_ITEFFECTU */\r
+               DoITEffectW,    /* UNI_ITEFFECTW */\r
+               DoITEffectY,    /* UNI_ITEFFECTY */\r
+               DoNothing,              /* UNI_ITEFFECTZ */\r
+               DoITEffectS0,   /* UNI_ITEFFECTS0 */\r
+               DoULTEffect9,   /* UNI_ULTEFFECT9 */\r
+               DoMEDSpeed,             /* UNI_MEDSPEED */\r
+               DoMEDEffectF1,  /* UNI_MEDEFFECTF1 */\r
+               DoMEDEffectF2,  /* UNI_MEDEFFECTF2 */\r
+               DoMEDEffectF3,  /* UNI_MEDEFFECTF3 */\r
+               DoOktArp,               /* UNI_OKTARP */\r
+};\r
+\r
+static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)\r
+{\r
+       UWORD tick = mod->vbtick;\r
+       UWORD flags = mod->flags;\r
+       UBYTE c;\r
+       int explicitslides = 0;\r
+       effect_func f;\r
+\r
+       while((c=UniGetByte())) {\r
+               f = effects[c];\r
+               if (f != DoNothing)\r
+                               a->sliding = 0;\r
+               explicitslides |= f(tick, flags, a, mod, channel);\r
+       }\r
+       return explicitslides;\r
+}\r
+\r
+static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)\r
+{\r
+       int t;\r
+       MP_VOICE *aout;\r
+\r
+       dat&=0xf; \r
+       aout=(a->slave)?a->slave:NULL;\r
+\r
+       switch (dat) {\r
+       case 0x0: /* past note cut */\r
+               for (t=0;t<md_sngchn;t++)\r
+                       if (mod->voice[t].master==a)\r
+                               mod->voice[t].main.fadevol=0;\r
+               break;\r
+       case 0x1: /* past note off */\r
+               for (t=0;t<md_sngchn;t++)\r
+                       if (mod->voice[t].master==a) {\r
+                               mod->voice[t].main.keyoff|=KEY_OFF;\r
+                               if ((!(mod->voice[t].venv.flg & EF_ON))||\r
+                                  (mod->voice[t].venv.flg & EF_LOOP))\r
+                                       mod->voice[t].main.keyoff=KEY_KILL;\r
+                       }\r
+               break;\r
+       case 0x2: /* past note fade */\r
+               for (t=0;t<md_sngchn;t++)\r
+                       if (mod->voice[t].master==a)\r
+                               mod->voice[t].main.keyoff|=KEY_FADE;\r
+               break;\r
+       case 0x3: /* set NNA note cut */\r
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;\r
+               break;\r
+       case 0x4: /* set NNA note continue */\r
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;\r
+               break;\r
+       case 0x5: /* set NNA note off */\r
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;\r
+               break;   \r
+       case 0x6: /* set NNA note fade */\r
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;\r
+               break;\r
+       case 0x7: /* disable volume envelope */\r
+               if (aout)\r
+                       aout->main.volflg&=~EF_ON;\r
+               break;\r
+       case 0x8: /* enable volume envelope  */\r
+               if (aout)\r
+                       aout->main.volflg|=EF_ON;\r
+               break;\r
+       case 0x9: /* disable panning envelope */\r
+               if (aout)\r
+                       aout->main.panflg&=~EF_ON;\r
+               break;    \r
+       case 0xa: /* enable panning envelope */\r
+               if (aout)\r
+                       aout->main.panflg|=EF_ON;\r
+               break;\r
+       case 0xb: /* disable pitch envelope */\r
+               if (aout)\r
+                       aout->main.pitflg&=~EF_ON;\r
+               break;\r
+       case 0xc: /* enable pitch envelope */\r
+               if (aout)\r
+                       aout->main.pitflg|=EF_ON;\r
+               break;\r
+       }\r
+}\r
+\r
+void pt_UpdateVoices(MODULE *mod, int max_volume)\r
+{\r
+       SWORD envpan,envvol,envpit,channel;\r
+       UWORD playperiod;\r
+       SLONG vibval,vibdpt;\r
+       ULONG tmpvol;\r
+\r
+       MP_VOICE *aout;\r
+       INSTRUMENT *i;\r
+       SAMPLE *s;\r
+\r
+       mod->totalchn=mod->realchn=0;\r
+       for (channel=0;channel<md_sngchn;channel++) {\r
+               aout=&mod->voice[channel];\r
+               i=aout->main.i;\r
+               s=aout->main.s;\r
+\r
+               if (!s || !s->length) continue;\r
+\r
+               if (aout->main.period<40)\r
+                       aout->main.period=40;\r
+               else if (aout->main.period>50000)\r
+                       aout->main.period=50000;\r
+\r
+               if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {\r
+                       Voice_Play_internal(channel,s,(aout->main.start==-1)?\r
+                           ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start);\r
+                       aout->main.fadevol=32768;\r
+                       aout->aswppos=0;\r
+               }\r
+\r
+               envvol = 256;\r
+               envpan = PAN_CENTER;\r
+               envpit = 32;\r
+               if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {\r
+                       if (aout->main.volflg & EF_ON)\r
+                               envvol = StartEnvelope(&aout->venv,aout->main.volflg,\r
+                                 i->volpts,i->volsusbeg,i->volsusend,\r
+                                 i->volbeg,i->volend,i->volenv,aout->main.keyoff);\r
+                       if (aout->main.panflg & EF_ON)\r
+                               envpan = StartEnvelope(&aout->penv,aout->main.panflg,\r
+                                 i->panpts,i->pansusbeg,i->pansusend,\r
+                                 i->panbeg,i->panend,i->panenv,aout->main.keyoff);\r
+                       if (aout->main.pitflg & EF_ON)\r
+                               envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,\r
+                                 i->pitpts,i->pitsusbeg,i->pitsusend,\r
+                                 i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);\r
+\r
+                       if (aout->cenv.flg & EF_ON)\r
+                               aout->masterperiod=GetPeriod(mod->flags,\r
+                                 (UWORD)aout->main.note<<1, aout->master->speed);\r
+               } else {\r
+                       if (aout->main.volflg & EF_ON)\r
+                               envvol = ProcessEnvelope(aout,&aout->venv,256);\r
+                       if (aout->main.panflg & EF_ON)\r
+                               envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);\r
+                       if (aout->main.pitflg & EF_ON)\r
+                               envpit = ProcessEnvelope(aout,&aout->cenv,32);\r
+               }\r
+               if (aout->main.kick == KICK_NOTE) {\r
+                       aout->main.kick_flag = 1;\r
+               }\r
+               aout->main.kick=KICK_ABSENT;\r
+\r
+               tmpvol = aout->main.fadevol;    /* max 32768 */\r
+               tmpvol *= aout->main.chanvol;   /* * max 64 */\r
+               tmpvol *= aout->main.outvolume; /* * max 256 */\r
+               tmpvol /= (256 * 64);                   /* tmpvol is max 32768 again */\r
+               aout->totalvol = tmpvol >> 2;   /* used to determine samplevolume */\r
+               tmpvol *= envvol;                               /* * max 256 */\r
+               tmpvol *= mod->volume;                  /* * max 128 */\r
+               tmpvol /= (128 * 256 * 128);\r
+\r
+               /* fade out */\r
+               if (mod->sngpos>=mod->numpos)\r
+                       tmpvol=0;\r
+               else\r
+                       tmpvol=(tmpvol*max_volume)/128;\r
+\r
+               if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)\r
+                       Voice_SetVolume_internal(channel,0);\r
+               else {\r
+                       Voice_SetVolume_internal(channel,tmpvol);\r
+                       if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))\r
+                               mod->realchn++;\r
+                       mod->totalchn++;\r
+               }\r
+\r
+               if (aout->main.panning==PAN_SURROUND)\r
+                       Voice_SetPanning_internal(channel,PAN_SURROUND);\r
+               else\r
+                       if ((mod->panflag)&&(aout->penv.flg & EF_ON))\r
+                               Voice_SetPanning_internal(channel,\r
+                                   DoPan(envpan,aout->main.panning));\r
+                       else\r
+                               Voice_SetPanning_internal(channel,aout->main.panning);\r
+\r
+               if (aout->main.period && s->vibdepth)\r
+                       switch (s->vibtype) {\r
+                       case 0:\r
+                               vibval=avibtab[s->avibpos&127];\r
+                               if (aout->avibpos & 0x80) vibval=-vibval;\r
+                               break;\r
+                       case 1:\r
+                               vibval=64;\r
+                               if (aout->avibpos & 0x80) vibval=-vibval;\r
+                               break;\r
+                       case 2:\r
+                               vibval=63-(((aout->avibpos+128)&255)>>1);\r
+                               break;\r
+                       default:\r
+                               vibval=(((aout->avibpos+128)&255)>>1)-64;\r
+                               break;\r
+                       }\r
+               else\r
+                       vibval=0;\r
+\r
+               if (s->vibflags & AV_IT) {\r
+                       if ((aout->aswppos>>8)<s->vibdepth) {\r
+                               aout->aswppos += s->vibsweep;\r
+                               vibdpt=aout->aswppos;\r
+                       } else\r
+                               vibdpt=s->vibdepth<<8;\r
+                       vibval=(vibval*vibdpt)>>16;\r
+                       if (aout->mflag) {\r
+                               if (!(mod->flags&UF_LINEAR)) vibval>>=1;\r
+                               aout->main.period-=vibval;\r
+                       }\r
+               } else {\r
+                       /* do XM style auto-vibrato */\r
+                       if (!(aout->main.keyoff & KEY_OFF)) {\r
+                               if (aout->aswppos<s->vibsweep) {\r
+                                       vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;\r
+                                       aout->aswppos++;\r
+                               } else\r
+                                       vibdpt=s->vibdepth;\r
+                       } else {\r
+                               /* keyoff -> depth becomes 0 if final depth wasn't reached or\r
+                                  stays at final level if depth WAS reached */\r
+                               if (aout->aswppos>=s->vibsweep)\r
+                                       vibdpt=s->vibdepth;\r
+                               else\r
+                                       vibdpt=0;\r
+                       }\r
+                       vibval=(vibval*vibdpt)>>8;\r
+                       aout->main.period-=vibval;\r
+               }\r
+\r
+               /* update vibrato position */\r
+               aout->avibpos=(aout->avibpos+s->vibrate)&0xff;\r
+\r
+               /* process pitch envelope */\r
+               playperiod=aout->main.period;\r
+\r
+               if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {\r
+                       long p1;\r
+\r
+                       envpit-=32;\r
+                       if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);\r
+\r
+                       p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,\r
+                           aout->master->speed)-aout->masterperiod;\r
+                       if (p1>0) {\r
+                               if ((UWORD)(playperiod+p1)<=playperiod) {\r
+                                       p1=0;\r
+                                       aout->main.keyoff|=KEY_OFF;\r
+                               }\r
+                       } else if (p1<0) {\r
+                               if ((UWORD)(playperiod+p1)>=playperiod) {\r
+                                       p1=0;\r
+                                       aout->main.keyoff|=KEY_OFF;\r
+                               }\r
+                       }\r
+                       playperiod+=p1;\r
+               }\r
+\r
+               if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */\r
+                       Voice_Stop_internal(channel);\r
+                       mod->totalchn--;\r
+                       if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))\r
+                               mod->realchn--;\r
+               } else {\r
+                       Voice_SetFrequency_internal(channel,\r
+                                                   getfrequency(mod->flags,playperiod));\r
+\r
+                       /* if keyfade, start substracting fadeoutspeed from fadevol: */\r
+                       if ((i)&&(aout->main.keyoff&KEY_FADE)) {\r
+                               if (aout->main.fadevol>=i->volfade)\r
+                                       aout->main.fadevol-=i->volfade;\r
+                               else\r
+                                       aout->main.fadevol=0;\r
+                       }\r
+               }\r
+\r
+               md_bpm=mod->bpm+mod->relspd;\r
+               if (md_bpm<32)\r
+                       md_bpm=32;\r
+               else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)\r
+                       md_bpm=255;\r
+       }\r
+}\r
+\r
+/* Handles new notes or instruments */\r
+void pt_Notes(MODULE *mod)\r
+{\r
+       SWORD channel;\r
+       MP_CONTROL *a;\r
+       UBYTE c,inst;\r
+       int tr,funky; /* funky is set to indicate note or instrument change */\r
+\r
+       for (channel=0;channel<mod->numchn;channel++) {\r
+               a=&mod->control[channel];\r
+\r
+               if (mod->sngpos>=mod->numpos) {\r
+                       tr=mod->numtrk;\r
+                       mod->numrow=0;\r
+               } else {\r
+                       tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];\r
+                       mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];\r
+               }\r
+\r
+               a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;\r
+               a->newsamp=0;\r
+               if (!mod->vbtick) a->main.notedelay=0;\r
+\r
+               if (!a->row) continue;\r
+               UniSetRow(a->row);\r
+               funky=0;\r
+\r
+               while((c=UniGetByte()))\r
+                       switch (c) {\r
+                       case UNI_NOTE:\r
+                               funky|=1;\r
+                               a->oldnote=a->anote,a->anote=UniGetByte();\r
+                               a->main.kick =KICK_NOTE;\r
+                               a->main.start=-1;\r
+                               a->sliding=0;\r
+\r
+                               /* retrig tremolo and vibrato waves ? */\r
+                               if (!(a->wavecontrol & 0x80)) a->trmpos=0;\r
+                               if (!(a->wavecontrol & 0x08)) a->vibpos=0;\r
+                               if (!a->panbwave) a->panbpos=0;\r
+                               break;\r
+                       case UNI_INSTRUMENT:\r
+                               inst=UniGetByte();\r
+                               if (inst>=mod->numins) break; /* safety valve */\r
+                               funky|=2;\r
+                               a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;\r
+                               a->retrig=0;\r
+                               a->s3mtremor=0;\r
+                               a->ultoffset=0;\r
+                               a->main.sample=inst;\r
+                               break;\r
+                       default:\r
+                               UniSkipOpcode();\r
+                               break;\r
+                       }\r
+\r
+               if (funky) {\r
+                       INSTRUMENT *i;\r
+                       SAMPLE *s;\r
+\r
+                       if ((i=a->main.i)) {\r
+                               if (i->samplenumber[a->anote] >= mod->numsmp) continue;\r
+                               s=&mod->samples[i->samplenumber[a->anote]];\r
+                               a->main.note=i->samplenote[a->anote];\r
+                       } else {\r
+                               a->main.note=a->anote;\r
+                               s=&mod->samples[a->main.sample];\r
+                       }\r
+\r
+                       if (a->main.s!=s) {\r
+                               a->main.s=s;\r
+                               a->newsamp=a->main.period;\r
+                       }\r
+\r
+                       /* channel or instrument determined panning ? */\r
+                       a->main.panning=mod->panning[channel];\r
+                       if (s->flags & SF_OWNPAN)\r
+                               a->main.panning=s->panning;\r
+                       else if ((i)&&(i->flags & IF_OWNPAN))\r
+                               a->main.panning=i->panning;\r
+\r
+                       a->main.handle=s->handle;\r
+                       a->speed=s->speed;\r
+\r
+                       if (i) {\r
+                               if ((mod->panflag)&&(i->flags & IF_PITCHPAN)\r
+                                  &&(a->main.panning!=PAN_SURROUND)){\r
+                                       a->main.panning+=\r
+                                           ((a->anote-i->pitpancenter)*i->pitpansep)/8;\r
+                                       if (a->main.panning<PAN_LEFT)\r
+                                               a->main.panning=PAN_LEFT;\r
+                                       else if (a->main.panning>PAN_RIGHT)\r
+                                               a->main.panning=PAN_RIGHT;\r
+                               }\r
+                               a->main.pitflg=i->pitflg;\r
+                               a->main.volflg=i->volflg;\r
+                               a->main.panflg=i->panflg;\r
+                               a->main.nna=i->nnatype;\r
+                               a->dca=i->dca;\r
+                               a->dct=i->dct;\r
+                       } else {\r
+                               a->main.pitflg=a->main.volflg=a->main.panflg=0;\r
+                               a->main.nna=a->dca=0;\r
+                               a->dct=DCT_OFF;\r
+                       }\r
+\r
+                       if (funky&2) /* instrument change */ {\r
+                               /* IT random volume variations: 0:8 bit fixed, and one bit for\r
+                                  sign. */\r
+                               a->volume=a->tmpvolume=s->volume;\r
+                               if ((s)&&(i)) {\r
+                                       if (i->rvolvar) {\r
+                                               a->volume=a->tmpvolume=s->volume+\r
+                                                 ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)\r
+                                                 ))/25600);\r
+                                               if (a->volume<0)\r
+                                                       a->volume=a->tmpvolume=0;\r
+                                               else if (a->volume>64)\r
+                                                       a->volume=a->tmpvolume=64;\r
+                                       }\r
+                                       if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {\r
+                                               a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*\r
+                                                 (SLONG)getrandom(512)))/25600);\r
+                                               if (a->main.panning<PAN_LEFT)\r
+                                                       a->main.panning=PAN_LEFT;\r
+                                               else if (a->main.panning>PAN_RIGHT)\r
+                                                       a->main.panning=PAN_RIGHT;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       a->wantedperiod=a->tmpperiod=\r
+                           GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);\r
+                       a->main.keyoff=KEY_KICK;\r
+               }\r
+       }\r
+}\r
+\r
+/* Handles effects */\r
+void pt_EffectsPass1(MODULE *mod)\r
+{\r
+       SWORD channel;\r
+       MP_CONTROL *a;\r
+       MP_VOICE *aout;\r
+       int explicitslides;\r
+\r
+       for (channel=0;channel<mod->numchn;channel++) {\r
+               a=&mod->control[channel];\r
+\r
+               if ((aout=a->slave)) {\r
+                       a->main.fadevol=aout->main.fadevol;\r
+                       a->main.period=aout->main.period;\r
+                       if (a->main.kick==KICK_KEYOFF)\r
+                               a->main.keyoff=aout->main.keyoff;\r
+               }\r
+\r
+               if (!a->row) continue;\r
+               UniSetRow(a->row);\r
+\r
+               a->ownper=a->ownvol=0;\r
+               explicitslides = pt_playeffects(mod, channel, a);\r
+\r
+               /* continue volume slide if necessary for XM and IT */\r
+               if (mod->flags&UF_BGSLIDES) {\r
+                       if (!explicitslides && a->sliding)\r
+                               DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);\r
+                       else if (a->tmpvolume)\r
+                               a->sliding = explicitslides;\r
+               }\r
+\r
+               if (!a->ownper)\r
+                       a->main.period=a->tmpperiod;\r
+               if (!a->ownvol)\r
+                       a->volume=a->tmpvolume;\r
+\r
+               if (a->main.s) {\r
+                       if (a->main.i)\r
+                               a->main.outvolume=\r
+                                   (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;\r
+                       else\r
+                               a->main.outvolume=(a->volume*a->main.s->globvol)>>4;\r
+                       if (a->main.outvolume>256)\r
+                               a->main.outvolume=256;\r
+                       else if (a->main.outvolume<0)\r
+                               a->main.outvolume=0;\r
+               }\r
+       }\r
+}\r
+\r
+/* NNA management */\r
+void pt_NNA(MODULE *mod)\r
+{\r
+       SWORD channel;\r
+       MP_CONTROL *a;\r
+\r
+       for (channel=0;channel<mod->numchn;channel++) {\r
+               a=&mod->control[channel];\r
+\r
+               if (a->main.kick==KICK_NOTE) {\r
+                       BOOL kill=0;\r
+\r
+                       if (a->slave) {\r
+                               MP_VOICE *aout;\r
+\r
+                               aout=a->slave;\r
+                               if (aout->main.nna & NNA_MASK) {\r
+                                       /* Make sure the old MP_VOICE channel knows it has no\r
+                                          master now ! */\r
+                                       a->slave=NULL;\r
+                                       /* assume the channel is taken by NNA */\r
+                                       aout->mflag=0;\r
+\r
+                                       switch (aout->main.nna) {\r
+                                       case NNA_CONTINUE: /* continue note, do nothing */\r
+                                               break;\r
+                                       case NNA_OFF: /* note off */\r
+                                               aout->main.keyoff|=KEY_OFF;\r
+                                               if ((!(aout->main.volflg & EF_ON))||\r
+                                                         (aout->main.volflg & EF_LOOP))\r
+                                                       aout->main.keyoff=KEY_KILL;\r
+                                               break;\r
+                                       case NNA_FADE:\r
+                                               aout->main.keyoff |= KEY_FADE;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (a->dct!=DCT_OFF) {\r
+                               int t;\r
+\r
+                               for (t=0;t<md_sngchn;t++)\r
+                                       if ((!Voice_Stopped_internal(t))&&\r
+                                          (mod->voice[t].masterchn==channel)&&\r
+                                          (a->main.sample==mod->voice[t].main.sample)) {\r
+                                               kill=0;\r
+                                               switch (a->dct) {\r
+                                               case DCT_NOTE:\r
+                                                       if (a->main.note==mod->voice[t].main.note)\r
+                                                               kill=1;\r
+                                                       break;\r
+                                               case DCT_SAMPLE:\r
+                                                       if (a->main.handle==mod->voice[t].main.handle)\r
+                                                               kill=1;\r
+                                                       break;\r
+                                               case DCT_INST:\r
+                                                       kill=1;\r
+                                                       break;\r
+                                               }\r
+                                               if (kill)\r
+                                                       switch (a->dca) {\r
+                                                       case DCA_CUT:\r
+                                                               mod->voice[t].main.fadevol=0;\r
+                                                               break;\r
+                                                       case DCA_OFF:\r
+                                                               mod->voice[t].main.keyoff|=KEY_OFF;\r
+                                                               if ((!(mod->voice[t].main.volflg&EF_ON))||\r
+                                                                   (mod->voice[t].main.volflg&EF_LOOP))\r
+                                                                       mod->voice[t].main.keyoff=KEY_KILL;\r
+                                                               break;\r
+                                                       case DCA_FADE:\r
+                                                               mod->voice[t].main.keyoff|=KEY_FADE;\r
+                                                               break;\r
+                                                       }\r
+                                       }\r
+                       }\r
+               } /* if (a->main.kick==KICK_NOTE) */\r
+       }\r
+}\r
+\r
+/* Setup module and NNA voices */\r
+void pt_SetupVoices(MODULE *mod)\r
+{\r
+       SWORD channel;\r
+       MP_CONTROL *a;\r
+       MP_VOICE *aout;\r
+\r
+       for (channel=0;channel<mod->numchn;channel++) {\r
+               a=&mod->control[channel];\r
+\r
+               if (a->main.notedelay) continue;\r
+               if (a->main.kick==KICK_NOTE) {\r
+                       /* if no channel was cut above, find an empty or quiet channel\r
+                          here */\r
+                       if (mod->flags&UF_NNA) {\r
+                               if (!a->slave) {\r
+                                       int newchn;\r
+\r
+                                       if ((newchn=MP_FindEmptyChannel(mod))!=-1)\r
+                                               a->slave=&mod->voice[a->slavechn=newchn];\r
+                               }\r
+                       } else \r
+                               a->slave=&mod->voice[a->slavechn=channel];\r
+\r
+                       /* assign parts of MP_VOICE only done for a KICK_NOTE */\r
+                       if ((aout=a->slave)) {\r
+                               if (aout->mflag && aout->master) aout->master->slave=NULL;\r
+                               aout->master=a;\r
+                               a->slave=aout;\r
+                               aout->masterchn=channel;\r
+                               aout->mflag=1;\r
+                       }\r
+               } else\r
+                       aout=a->slave;\r
+\r
+               if (aout)\r
+                       aout->main=a->main;\r
+               a->main.kick=KICK_ABSENT;\r
+       }\r
+}\r
+\r
+/* second effect pass */\r
+void pt_EffectsPass2(MODULE *mod)\r
+{\r
+       SWORD channel;\r
+       MP_CONTROL *a;\r
+       UBYTE c;\r
+\r
+       for (channel=0;channel<mod->numchn;channel++) {\r
+               a=&mod->control[channel];\r
+\r
+               if (!a->row) continue;\r
+               UniSetRow(a->row);\r
+\r
+               while((c=UniGetByte()))\r
+                       if (c==UNI_ITEFFECTS0) {\r
+                               c=UniGetByte();\r
+                               if ((c>>4)==SS_S7EFFECTS)\r
+                                       DoNNAEffects(mod, a, c&0xf);\r
+                       } else\r
+                               UniSkipOpcode();\r
+       }\r
+}\r
+\r
+void Player_HandleTick(void)\r
+{\r
+       SWORD channel;\r
+       int max_volume;\r
+\r
+#if 0\r
+       /* don't handle the very first ticks, this allows the other hardware to\r
+          settle down so we don't loose any starting notes */\r
+       if (isfirst) {\r
+               isfirst--;\r
+               return;\r
+       }\r
+#endif\r
+\r
+       if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;\r
+\r
+       /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */\r
+       pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */\r
+       pf->sngtime+=pf->sngremainder/pf->bpm;\r
+       pf->sngremainder%=pf->bpm;\r
+\r
+       if (++pf->vbtick>=pf->sngspd) {\r
+               if (pf->pat_repcrazy) \r
+                       pf->pat_repcrazy=0; /* play 2 times row 0 */\r
+               else\r
+                       pf->patpos++;\r
+               pf->vbtick=0;\r
+\r
+               /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is\r
+                  the command memory. */\r
+               if (pf->patdly)\r
+                       pf->patdly2=pf->patdly,pf->patdly=0;\r
+               if (pf->patdly2) {\r
+                       /* patterndelay active */\r
+                       if (--pf->patdly2)\r
+                               /* so turn back pf->patpos by 1 */\r
+                               if (pf->patpos) pf->patpos--;\r
+               }\r
+\r
+               /* do we have to get a new patternpointer ? (when pf->patpos reaches the\r
+                  pattern size, or when a patternbreak is active) */\r
+               if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))\r
+                       pf->posjmp=3;\r
+\r
+               if (pf->posjmp) {\r
+                       pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;\r
+                       pf->pat_repcrazy=0;\r
+                       pf->sngpos+=(pf->posjmp-2);\r
+                       for (channel=0;channel<pf->numchn;channel++)\r
+                               pf->control[channel].pat_reppos=-1;\r
+\r
+                       pf->patbrk=pf->posjmp=0;\r
+                       /* handle the "---" (end of song) pattern since it can occur\r
+                          *inside* the module in some formats */\r
+                       if ((pf->sngpos>=pf->numpos)||\r
+                               (pf->positions[pf->sngpos]==LAST_PATTERN)) {\r
+                               if (!pf->wrap) return;\r
+                               if (!(pf->sngpos=pf->reppos)) {\r
+                                   pf->volume=pf->initvolume>128?128:pf->initvolume;\r
+                                       if(pf->initspeed!=0)\r
+                                               pf->sngspd=pf->initspeed<32?pf->initspeed:32;\r
+                                       else\r
+                                               pf->sngspd=6;\r
+                                       pf->bpm=pf->inittempo<32?32:pf->inittempo;\r
+                               }\r
+                       }\r
+                       if (pf->sngpos<0) pf->sngpos=pf->numpos-1;\r
+               }\r
+\r
+               if (!pf->patdly2)\r
+                       pt_Notes(pf);\r
+       }\r
+\r
+       /* Fade global volume if enabled and we're playing the last pattern */\r
+       if (((pf->sngpos==pf->numpos-1)||\r
+                (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&\r
+           (pf->fadeout))\r
+               max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;\r
+       else\r
+               max_volume=128;\r
+\r
+       pt_EffectsPass1(pf);\r
+       if (pf->flags&UF_NNA)\r
+               pt_NNA(pf);\r
+       pt_SetupVoices(pf);\r
+       pt_EffectsPass2(pf);\r
+\r
+       /* now set up the actual hardware channel playback information */\r
+       pt_UpdateVoices(pf, max_volume);\r
+}\r
+\r
+static void Player_Init_internal(MODULE* mod)\r
+{\r
+       int t;\r
+\r
+       for (t=0;t<mod->numchn;t++) {\r
+               mod->control[t].main.chanvol=mod->chanvol[t];\r
+               mod->control[t].main.panning=mod->panning[t];\r
+       }\r
+       \r
+       mod->sngtime=0;\r
+       mod->sngremainder=0;\r
+\r
+       mod->pat_repcrazy=0;\r
+       mod->sngpos=0;\r
+       if(mod->initspeed!=0)\r
+               mod->sngspd=mod->initspeed<32?mod->initspeed:32;\r
+       else\r
+               mod->sngspd=6;\r
+       mod->volume=mod->initvolume>128?128:mod->initvolume;\r
+\r
+       mod->vbtick=mod->sngspd;\r
+       mod->patdly=0;\r
+       mod->patdly2=0;\r
+       mod->bpm=mod->inittempo<32?32:mod->inittempo;\r
+       mod->realchn=0;\r
+\r
+       mod->patpos=0;\r
+       mod->posjmp=2; /* make sure the player fetches the first note */\r
+       mod->numrow=-1;\r
+       mod->patbrk=0;\r
+}\r
+\r
+BOOL Player_Init(MODULE* mod)\r
+{\r
+       mod->extspd=1;\r
+       mod->panflag=1;\r
+       mod->wrap=0;\r
+       mod->loop=1;\r
+       mod->fadeout=0;\r
+\r
+       mod->relspd=0;\r
+\r
+       /* make sure the player doesn't start with garbage */\r
+       if (!(mod->control=(MP_CONTROL*)_mm_calloc(mod->numchn,sizeof(MP_CONTROL))))\r
+               return 1;\r
+       if (!(mod->voice=(MP_VOICE*)_mm_calloc(md_sngchn,sizeof(MP_VOICE))))\r
+               return 1;\r
+\r
+       Player_Init_internal(mod);\r
+       return 0;\r
+}\r
+\r
+void Player_Exit_internal(MODULE* mod)\r
+{\r
+       if (!mod)\r
+               return;\r
+\r
+       /* Stop playback if necessary */\r
+       if (mod==pf) {\r
+               Player_Stop_internal();\r
+               pf=NULL;\r
+       }\r
+\r
+       if (mod->control)\r
+               free(mod->control);\r
+       if (mod->voice)\r
+               free(mod->voice);\r
+       mod->control=NULL;\r
+       mod->voice=NULL;\r
+}\r
+\r
+void Player_Exit(MODULE* mod)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Player_Exit_internal(mod);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void Player_SetVolume(SWORD volume)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               pf->volume=(volume<0)?0:(volume>128)?128:volume;\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI MODULE* Player_GetModule(void)\r
+{\r
+       MODULE* result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=pf;\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI void Player_Start(MODULE *mod)\r
+{\r
+       int t;\r
+\r
+       if (!mod)\r
+               return;\r
+\r
+       if (!MikMod_Active())\r
+               MikMod_EnableOutput();\r
+\r
+       mod->forbid=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if (pf!=mod) {\r
+               /* new song is being started, so completely stop out the old one. */\r
+               if (pf) pf->forbid=1;\r
+               for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);\r
+       }\r
+       pf=mod;\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+void Player_Stop_internal(void)\r
+{\r
+       if (!md_sfxchn) MikMod_DisableOutput_internal();\r
+       if (pf) pf->forbid=1;\r
+       pf=NULL;\r
+}\r
+\r
+MIKMODAPI void Player_Stop(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+               Player_Stop_internal();\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI BOOL Player_Active(void)\r
+{\r
+       BOOL result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               result=(!(pf->sngpos>=pf->numpos));\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI void Player_NextPosition(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf) {\r
+               int t;\r
+\r
+               pf->forbid=1;\r
+               pf->posjmp=3;\r
+               pf->patbrk=0;\r
+               pf->vbtick=pf->sngspd;\r
+\r
+               for (t=0;t<md_sngchn;t++) {\r
+                       Voice_Stop_internal(t);\r
+                       pf->voice[t].main.i=NULL;\r
+                       pf->voice[t].main.s=NULL;\r
+               }\r
+               for (t=0;t<pf->numchn;t++) {\r
+                       pf->control[t].main.i=NULL;\r
+                       pf->control[t].main.s=NULL;\r
+               }\r
+               pf->forbid=0;\r
+       }\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void Player_PrevPosition(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf) {\r
+               int t;\r
+\r
+               pf->forbid=1;\r
+               pf->posjmp=1;\r
+               pf->patbrk=0;\r
+               pf->vbtick=pf->sngspd;\r
+\r
+               for (t=0;t<md_sngchn;t++) {\r
+                       Voice_Stop_internal(t);\r
+                       pf->voice[t].main.i=NULL;\r
+                       pf->voice[t].main.s=NULL;\r
+               }\r
+               for (t=0;t<pf->numchn;t++) {\r
+                       pf->control[t].main.i=NULL;\r
+                       pf->control[t].main.s=NULL;\r
+               }\r
+               pf->forbid=0;\r
+       }\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void Player_SetPosition(UWORD pos)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf) {\r
+               int t;\r
+\r
+               pf->forbid=1;\r
+               if (pos>=pf->numpos) pos=pf->numpos;\r
+               pf->posjmp=2;\r
+               pf->patbrk=0;\r
+               pf->sngpos=pos;\r
+               pf->vbtick=pf->sngspd;\r
+\r
+               for (t=0;t<md_sngchn;t++) {\r
+                       Voice_Stop_internal(t);\r
+                       pf->voice[t].main.i=NULL;\r
+                       pf->voice[t].main.s=NULL;\r
+               }\r
+               for (t=0;t<pf->numchn;t++) {\r
+                       pf->control[t].main.i=NULL;\r
+                       pf->control[t].main.s=NULL;\r
+               }\r
+               pf->forbid=0;\r
+               \r
+               if (!pos)\r
+                       Player_Init_internal(pf);\r
+       }\r
+       MUTEX_UNLOCK(vars);\r
+}    \r
+\r
+static void Player_Unmute_internal(SLONG arg1,va_list ap)\r
+{\r
+       SLONG t,arg2,arg3=0;\r
+\r
+       if (pf) {\r
+               switch (arg1) {\r
+               case MUTE_INCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                          (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)\r
+                               pf->control[arg2].muted=0;\r
+                       break;\r
+               case MUTE_EXCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                          (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (t=0;t<pf->numchn;t++) {\r
+                               if ((t>=arg2) && (t<=arg3))\r
+                                       continue;\r
+                               pf->control[t].muted=0;\r
+                       }\r
+                       break;\r
+               default:\r
+                       if (arg1<pf->numchn) pf->control[arg1].muted=0;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+MIKMODAPI void Player_Unmute(SLONG arg1, ...)\r
+{\r
+       va_list args;\r
+\r
+       va_start(args,arg1);\r
+       MUTEX_LOCK(vars);\r
+       Player_Unmute_internal(arg1,args);\r
+       MUTEX_UNLOCK(vars);\r
+       va_end(args);\r
+}\r
+\r
+static void Player_Mute_internal(SLONG arg1,va_list ap)\r
+{\r
+       SLONG t,arg2,arg3=0;\r
+\r
+       if (pf) {\r
+               switch (arg1) {\r
+               case MUTE_INCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                           (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)\r
+                               pf->control[arg2].muted=1;\r
+                       break;\r
+               case MUTE_EXCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                           (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (t=0;t<pf->numchn;t++) {\r
+                               if ((t>=arg2) && (t<=arg3))\r
+                                       continue;\r
+                               pf->control[t].muted=1;\r
+                       }\r
+                       break;\r
+               default:\r
+                       if (arg1<pf->numchn)\r
+                               pf->control[arg1].muted=1;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+MIKMODAPI void Player_Mute(SLONG arg1,...)\r
+{\r
+       va_list args;\r
+\r
+       va_start(args,arg1);\r
+       MUTEX_LOCK(vars);\r
+       Player_Mute_internal(arg1,args);\r
+       MUTEX_UNLOCK(vars);\r
+       va_end(args);\r
+}\r
+\r
+static void Player_ToggleMute_internal(SLONG arg1,va_list ap)\r
+{\r
+       SLONG arg2,arg3=0;\r
+       ULONG t;\r
+\r
+       if (pf) {\r
+               switch (arg1) {\r
+               case MUTE_INCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                           (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)\r
+                               pf->control[arg2].muted=1-pf->control[arg2].muted;\r
+                       break;\r
+               case MUTE_EXCLUSIVE:\r
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||\r
+                           (arg2>arg3)||(arg3>=pf->numchn))\r
+                               return;\r
+                       for (t=0;t<pf->numchn;t++) {\r
+                               if ((t>=arg2) && (t<=arg3))\r
+                                       continue;\r
+                               pf->control[t].muted=1-pf->control[t].muted;\r
+                       }\r
+                       break;\r
+               default:\r
+                       if (arg1<pf->numchn) \r
+                               pf->control[arg1].muted=1-pf->control[arg1].muted;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+MIKMODAPI void Player_ToggleMute(SLONG arg1,...)\r
+{\r
+       va_list args;\r
+\r
+       va_start(args,arg1);\r
+       MUTEX_LOCK(vars);\r
+       Player_ToggleMute_internal(arg1,args);\r
+       MUTEX_UNLOCK(vars);\r
+       va_end(args);\r
+}\r
+\r
+MIKMODAPI BOOL Player_Muted(UBYTE chan)\r
+{\r
+       BOOL result=1;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               result=(chan<pf->numchn)?pf->control[chan].muted:1;\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI int Player_GetChannelVoice(UBYTE chan)\r
+{\r
+       int result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)\r
+{\r
+       UWORD result=0;\r
+\r
+       MUTEX_LOCK(vars);\r
+    if (pf)\r
+           result=(chan<pf->numchn)?pf->control[chan].main.period:0;\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+BOOL Player_Paused_internal(void)\r
+{\r
+       return pf?pf->forbid:1;\r
+}\r
+\r
+MIKMODAPI BOOL Player_Paused(void)\r
+{\r
+       BOOL result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=Player_Paused_internal();\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI void Player_TogglePause(void)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               pf->forbid=1-pf->forbid;\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void Player_SetSpeed(UWORD speed)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       if (pf) \r
+               pf->sngspd=speed?(speed<32?speed:32):1;\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void Player_SetTempo(UWORD tempo)\r
+{\r
+       if (tempo<32) tempo=32;\r
+       MUTEX_LOCK(vars);\r
+       if (pf) {\r
+               if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;\r
+               pf->bpm=tempo;\r
+       }\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)\r
+{\r
+       int i;\r
+\r
+       if (numvoices > md_sngchn)\r
+               numvoices = md_sngchn;\r
+\r
+       MUTEX_LOCK(vars);\r
+       if (pf)\r
+               for (i = 0; i < md_sngchn; i++) {\r
+                       vinfo [i].i = pf->voice[i].main.i;\r
+                       vinfo [i].s = pf->voice[i].main.s;\r
+                       vinfo [i].panning = pf->voice [i].main.panning;\r
+                       vinfo [i].volume = pf->voice [i].main.chanvol;\r
+                       vinfo [i].period = pf->voice [i].main.period;\r
+                       vinfo [i].kick = pf->voice [i].main.kick_flag;\r
+                       pf->voice [i].main.kick_flag = 0;\r
+               }\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return numvoices;\r
+}\r
+\r
+\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/munitrk.c b/apps/plugins/mikmod/playercode/munitrk.c
new file mode 100644 (file)
index 0000000..e8c3a44
--- /dev/null
@@ -0,0 +1,303 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: munitrk.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  All routines dealing with the manipulation of UNITRK streams\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+/* Unibuffer chunk size */\r
+#define BUFPAGE  128\r
+\r
+UWORD unioperands[UNI_LAST]={\r
+       0, /* not used */\r
+       1, /* UNI_NOTE */\r
+       1, /* UNI_INSTRUMENT */\r
+       1, /* UNI_PTEFFECT0 */\r
+       1, /* UNI_PTEFFECT1 */\r
+       1, /* UNI_PTEFFECT2 */\r
+       1, /* UNI_PTEFFECT3 */\r
+       1, /* UNI_PTEFFECT4 */\r
+       1, /* UNI_PTEFFECT5 */\r
+       1, /* UNI_PTEFFECT6 */\r
+       1, /* UNI_PTEFFECT7 */\r
+       1, /* UNI_PTEFFECT8 */\r
+       1, /* UNI_PTEFFECT9 */\r
+       1, /* UNI_PTEFFECTA */\r
+       1, /* UNI_PTEFFECTB */\r
+       1, /* UNI_PTEFFECTC */\r
+       1, /* UNI_PTEFFECTD */\r
+       1, /* UNI_PTEFFECTE */\r
+       1, /* UNI_PTEFFECTF */\r
+       1, /* UNI_S3MEFFECTA */\r
+       1, /* UNI_S3MEFFECTD */\r
+       1, /* UNI_S3MEFFECTE */\r
+       1, /* UNI_S3MEFFECTF */\r
+       1, /* UNI_S3MEFFECTI */\r
+       1, /* UNI_S3MEFFECTQ */\r
+       1, /* UNI_S3MEFFECTR */\r
+       1, /* UNI_S3MEFFECTT */\r
+       1, /* UNI_S3MEFFECTU */\r
+       0, /* UNI_KEYOFF */\r
+       1, /* UNI_KEYFADE */\r
+       2, /* UNI_VOLEFFECTS */\r
+       1, /* UNI_XMEFFECT4 */\r
+       1, /* UNI_XMEFFECT6 */\r
+       1, /* UNI_XMEFFECTA */\r
+       1, /* UNI_XMEFFECTE1 */\r
+       1, /* UNI_XMEFFECTE2 */\r
+       1, /* UNI_XMEFFECTEA */\r
+       1, /* UNI_XMEFFECTEB */\r
+       1, /* UNI_XMEFFECTG */\r
+       1, /* UNI_XMEFFECTH */\r
+       1, /* UNI_XMEFFECTL */\r
+       1, /* UNI_XMEFFECTP */\r
+       1, /* UNI_XMEFFECTX1 */\r
+       1, /* UNI_XMEFFECTX2 */\r
+       1, /* UNI_ITEFFECTG */\r
+       1, /* UNI_ITEFFECTH */\r
+       1, /* UNI_ITEFFECTI */\r
+       1, /* UNI_ITEFFECTM */\r
+       1, /* UNI_ITEFFECTN */\r
+       1, /* UNI_ITEFFECTP */\r
+       1, /* UNI_ITEFFECTT */\r
+       1, /* UNI_ITEFFECTU */\r
+       1, /* UNI_ITEFFECTW */\r
+       1, /* UNI_ITEFFECTY */\r
+       2, /* UNI_ITEFFECTZ */\r
+       1, /* UNI_ITEFFECTS0 */\r
+       2, /* UNI_ULTEFFECT9 */\r
+       2, /* UNI_MEDSPEED */\r
+       0, /* UNI_MEDEFFECTF1 */\r
+       0, /* UNI_MEDEFFECTF2 */\r
+       0, /* UNI_MEDEFFECTF3 */\r
+       2, /* UNI_OKTARP */\r
+};\r
+\r
+/* Sparse description of the internal module format\r
+   ------------------------------------------------\r
+\r
+  A UNITRK stream is an array of bytes representing a single track of a pattern.\r
+It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly\r
+language):\r
+\r
+rrrlllll\r
+[REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..\r
+^                                         ^ ^\r
+|-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...\r
+\r
+  The rep/len byte contains the number of bytes in the current row, _including_\r
+the length byte itself (So the LENGTH byte of row 0 in the previous example\r
+would have a value of 5). This makes it easy to search through a stream for a\r
+particular row. A track is concluded by a 0-value length byte.\r
+\r
+  The upper 3 bits of the rep/len byte contain the number of times -1 this row\r
+is repeated for this track. (so a value of 7 means this row is repeated 8 times)\r
+\r
+  Opcodes can range from 1 to 255 but currently only opcodes 1 to 62 are being\r
+used. Each opcode can have a different number of operands. You can find the\r
+number of operands to a particular opcode by using the opcode as an index into\r
+the 'unioperands' table.\r
+\r
+*/\r
+\r
+/*========== Reading routines */\r
+\r
+static UBYTE *rowstart; /* startadress of a row */\r
+static UBYTE *rowend;   /* endaddress of a row (exclusive) */\r
+static UBYTE *rowpc;    /* current unimod(tm) programcounter */\r
+\r
+static UBYTE lastbyte;  /* for UniSkipOpcode() */\r
+\r
+void UniSetRow(UBYTE* t)\r
+{\r
+       rowstart = t;\r
+       rowpc    = rowstart;\r
+       rowend   = t?rowstart+(*(rowpc++)&0x1f):t;\r
+}\r
+\r
+UBYTE UniGetByte(void)\r
+{\r
+       return lastbyte = (rowpc<rowend)?*(rowpc++):0;\r
+}\r
+\r
+UWORD UniGetWord(void)\r
+{\r
+       return ((UWORD)UniGetByte()<<8)|UniGetByte();\r
+}\r
+\r
+void UniSkipOpcode(void)\r
+{\r
+       if (lastbyte < UNI_LAST) {\r
+               UWORD t = unioperands[lastbyte];\r
+\r
+               while (t--)\r
+                       UniGetByte();\r
+       }\r
+}\r
+\r
+/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns\r
+   NULL if the row can't be found. */\r
+UBYTE *UniFindRow(UBYTE* t,UWORD row)\r
+{\r
+       UBYTE c,l;\r
+\r
+       if(t)\r
+               while(1) {\r
+                       c = *t;             /* get rep/len byte */\r
+                       if(!c) return NULL; /* zero ? -> end of track.. */\r
+                       l = (c>>5)+1;       /* extract repeat value */\r
+                       if(l>row) break;    /* reached wanted row? -> return pointer */\r
+                       row -= l;           /* haven't reached row yet.. update row */\r
+                       t += c&0x1f;        /* point t to the next row */\r
+               }\r
+       return t;\r
+}\r
+\r
+/*========== Writing routines */\r
+\r
+static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */\r
+static UWORD unimax;  /* buffer size */\r
+\r
+static UWORD unipc;   /* buffer cursor */\r
+static UWORD unitt;   /* current row index */\r
+static UWORD lastp;   /* previous row index */\r
+\r
+/* Resets index-pointers to create a new track. */\r
+void UniReset(void)\r
+{\r
+       unitt     = 0;   /* reset index to rep/len byte */\r
+       unipc     = 1;   /* first opcode will be written to index 1 */\r
+       lastp     = 0;   /* no previous row yet */\r
+       unibuf[0] = 0;   /* clear rep/len byte */\r
+}\r
+\r
+/* Expands the buffer */\r
+static BOOL UniExpand(int wanted)\r
+{\r
+       if ((unipc+wanted)>=unimax) {\r
+               UBYTE *newbuf;\r
+\r
+               /* Expand the buffer by BUFPAGE bytes */\r
+               newbuf=(UBYTE*)realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));\r
+\r
+               /* Check if realloc succeeded */\r
+               if(newbuf) {\r
+                       unibuf = newbuf;\r
+                       unimax+=BUFPAGE;\r
+                       return 1;\r
+               } else \r
+                       return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+/* Appends one byte of data to the current row of a track. */\r
+void UniWriteByte(UBYTE data)\r
+{\r
+       if (UniExpand(1))\r
+               /* write byte to current position and update */\r
+               unibuf[unipc++]=data;\r
+}\r
+\r
+void UniWriteWord(UWORD data)\r
+{\r
+       if (UniExpand(2)) {\r
+               unibuf[unipc++]=data>>8;\r
+               unibuf[unipc++]=data&0xff;\r
+       }\r
+}\r
+\r
+static BOOL MyCmp(UBYTE* a,UBYTE* b,UWORD l)\r
+{\r
+       UWORD t;\r
+\r
+       for(t=0;t<l;t++)\r
+               if(*(a++)!=*(b++)) return 0;\r
+       return 1;\r
+}\r
+\r
+/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets\r
+   pointers to start a new row. */\r
+void UniNewline(void)\r
+{\r
+       UWORD n,l,len;\r
+\r
+       n = (unibuf[lastp]>>5)+1;     /* repeat of previous row */\r
+       l = (unibuf[lastp]&0x1f);     /* length of previous row */\r
+\r
+       len = unipc-unitt;            /* length of current row */\r
+\r
+       /* Now, check if the previous and the current row are identical.. when they\r
+          are, just increase the repeat field of the previous row */\r
+       if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) {\r
+               unibuf[lastp]+=0x20;\r
+               unipc = unitt+1;\r
+       } else {\r
+               if (UniExpand(unitt-unipc)) {\r
+                       /* current and previous row aren't equal... update the pointers */\r
+                       unibuf[unitt] = len;\r
+                       lastp = unitt;\r
+                       unitt = unipc++;\r
+               }\r
+       }\r
+}\r
+\r
+/* Terminates the current unitrk stream and returns a pointer to a copy of the\r
+   stream. */\r
+UBYTE* UniDup(void)\r
+{\r
+       UBYTE *d;\r
+\r
+       if (!UniExpand(unitt-unipc)) return NULL;\r
+       unibuf[unitt] = 0;\r
+\r
+       if(!(d=(UBYTE *)_mm_malloc(unipc))) return NULL;\r
+       memcpy(d,unibuf,unipc);\r
+\r
+       return d;\r
+}\r
+\r
+BOOL UniInit(void)\r
+{\r
+       unimax = BUFPAGE;\r
+\r
+       if(!(unibuf=(UBYTE*)_mm_malloc(unimax*sizeof(UBYTE)))) return 0;\r
+       return 1;\r
+}\r
+\r
+void UniCleanup(void)\r
+{\r
+       if(unibuf) free(unibuf);\r
+       unibuf = NULL;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/mwav.c b/apps/plugins/mikmod/playercode/mwav.c
new file mode 100644 (file)
index 0000000..f054208
--- /dev/null
@@ -0,0 +1,198 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: mwav.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  WAV sample loader\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+   FIXME: Stereo .WAV files are not yet supported as samples.\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+typedef struct WAV {\r
+       CHAR  rID[4];\r
+       ULONG rLen;\r
+       CHAR  wID[4];\r
+       CHAR  fID[4];\r
+       ULONG fLen;\r
+       UWORD wFormatTag;\r
+       UWORD nChannels;\r
+       ULONG nSamplesPerSec;\r
+       ULONG nAvgBytesPerSec;\r
+       UWORD nBlockAlign;\r
+       UWORD nFormatSpecific;\r
+} WAV;\r
+\r
+SAMPLE* Sample_LoadGeneric_internal(MREADER* reader)\r
+{\r
+       SAMPLE *si=NULL;\r
+       WAV wh;\r
+       BOOL have_fmt=0;\r
+\r
+       /* read wav header */\r
+       _mm_read_string(wh.rID,4,reader);\r
+       wh.rLen = _mm_read_I_ULONG(reader);\r
+       _mm_read_string(wh.wID,4,reader);\r
+\r
+       /* check for correct header */\r
+       if(_mm_eof(reader)|| memcmp(wh.rID,"RIFF",4) || memcmp(wh.wID,"WAVE",4)) {\r
+               _mm_errno = MMERR_UNKNOWN_WAVE_TYPE;\r
+               return NULL;\r
+       }\r
+\r
+       /* scan all RIFF blocks until we find the sample data */\r
+       for(;;) {\r
+               CHAR dID[4];\r
+               ULONG len,start;\r
+\r
+               _mm_read_string(dID,4,reader);\r
+               len = _mm_read_I_ULONG(reader);\r
+               /* truncated file ? */\r
+               if (_mm_eof(reader)) {\r
+                       _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
+                       return NULL;\r
+               }\r
+               start = _mm_ftell(reader);\r
+\r
+               /* sample format block\r
+                  should be present only once and before a data block */\r
+               if(!memcmp(dID,"fmt ",4)) {\r
+                       wh.wFormatTag      = _mm_read_I_UWORD(reader);\r
+                       wh.nChannels       = _mm_read_I_UWORD(reader);\r
+                       wh.nSamplesPerSec  = _mm_read_I_ULONG(reader);\r
+                       wh.nAvgBytesPerSec = _mm_read_I_ULONG(reader);\r
+                       wh.nBlockAlign     = _mm_read_I_UWORD(reader);\r
+                       wh.nFormatSpecific = _mm_read_I_UWORD(reader);\r
+\r
+#ifdef MIKMOD_DEBUG\r
+                       fprintf(stderr,"\rwavloader : wFormatTag=%04x blockalign=%04x nFormatSpc=%04x\n",\r
+                               wh.wFormatTag,wh.nBlockAlign,wh.nFormatSpecific);\r
+#endif\r
+\r
+                       if((have_fmt)||(wh.nChannels>1)) {\r
+                               _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
+                               return NULL;\r
+                       }\r
+                       have_fmt=1;\r
+               } else\r
+               /* sample data block\r
+                  should be present only once and after a format block */\r
+                 if(!memcmp(dID,"data",4)) {\r
+                       if(!have_fmt) {\r
+                               _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
+                               return NULL;\r
+                       }\r
+                       if(!(si=(SAMPLE*)_mm_malloc(sizeof(SAMPLE)))) return NULL;\r
+                       si->speed  = wh.nSamplesPerSec/wh.nChannels;\r
+                       si->volume = 64;\r
+                       si->length = len;\r
+                       if(wh.nBlockAlign == 2) {\r
+                               si->flags    = SF_16BITS | SF_SIGNED;\r
+                               si->length >>= 1;\r
+                       }\r
+                       si->inflags = si->flags;\r
+                       SL_RegisterSample(si,MD_SNDFX,reader);\r
+                       SL_LoadSamples();\r
+                       \r
+                       /* skip any other remaining blocks - so in case of repeated sample\r
+                          fragments, we'll return the first anyway instead of an error */\r
+                       break;\r
+               }\r
+               /* onto next block */\r
+               _mm_fseek(reader,start+len,SEEK_SET);\r
+               if (_mm_eof(reader))\r
+                       break;\r
+       }\r
+\r
+       return si;\r
+}\r
+\r
+MIKMODAPI SAMPLE* Sample_LoadGeneric(MREADER* reader)\r
+{\r
+       SAMPLE* result;\r
+\r
+       MUTEX_LOCK(vars);\r
+       result=Sample_LoadGeneric_internal(reader);\r
+       MUTEX_UNLOCK(vars);\r
+\r
+       return result;\r
+}\r
+\r
+MIKMODAPI SAMPLE* Sample_LoadFP(int fp)\r
+{\r
+       SAMPLE* result=NULL;\r
+       MREADER* reader;\r
+\r
+       if((reader=_mm_new_file_reader(fp))) {\r
+               result=Sample_LoadGeneric(reader);\r
+               _mm_delete_file_reader(reader);\r
+       }\r
+       return result;\r
+}\r
+\r
+MIKMODAPI SAMPLE* Sample_Load(CHAR* filename)\r
+{\r
+       int fp;\r
+       SAMPLE *si=NULL;\r
+\r
+       if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;\r
+       if((fp=_mm_fopen(filename,O_RDONLY))) {\r
+               si = Sample_LoadFP(fp);\r
+               _mm_fclose(fp);\r
+       }\r
+       return si;\r
+}\r
+\r
+MIKMODAPI void Sample_Free(SAMPLE* si)\r
+{\r
+       if(si) {\r
+               MD_SampleUnload(si->handle);\r
+               free(si);\r
+       }\r
+}\r
+\r
+void Sample_Free_internal(SAMPLE *si)\r
+{\r
+       MUTEX_LOCK(vars);\r
+       Sample_Free(si);\r
+       MUTEX_UNLOCK(vars);\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/npertab.c b/apps/plugins/mikmod/playercode/npertab.c
new file mode 100644 (file)
index 0000000..ca02611
--- /dev/null
@@ -0,0 +1,48 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: npertab.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  MOD format period table.  Used by both the MOD and M15 (15-inst mod) Loaders.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+UWORD npertab[7 * OCTAVE] = {\r
+       /* Octaves 6 -> 0 */\r
+       /* C    C#     D    D#     E     F    F#     G    G#     A    A#     B */\r
+       0x6b0,0x650,0x5f4,0x5a0,0x54c,0x500,0x4b8,0x474,0x434,0x3f8,0x3c0,0x38a,\r
+       0x358,0x328,0x2fa,0x2d0,0x2a6,0x280,0x25c,0x23a,0x21a,0x1fc,0x1e0,0x1c5,\r
+       0x1ac,0x194,0x17d,0x168,0x153,0x140,0x12e,0x11d,0x10d,0x0fe,0x0f0,0x0e2,\r
+       0x0d6,0x0ca,0x0be,0x0b4,0x0aa,0x0a0,0x097,0x08f,0x087,0x07f,0x078,0x071,\r
+       0x06b,0x065,0x05f,0x05a,0x055,0x050,0x04b,0x047,0x043,0x03f,0x03c,0x038,\r
+       0x035,0x032,0x02f,0x02d,0x02a,0x028,0x025,0x023,0x021,0x01f,0x01e,0x01c,\r
+       0x01b,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,0x00f,0x00e\r
+};\r
+\r
+/* ex:set ts=4: */\r
+\r
diff --git a/apps/plugins/mikmod/playercode/sloader.c b/apps/plugins/mikmod/playercode/sloader.c
new file mode 100644 (file)
index 0000000..390e94e
--- /dev/null
@@ -0,0 +1,519 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: sloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Routines for loading samples. The sample loader utilizes the routines\r
+  provided by the "registered" sample loader.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+static int sl_rlength;\r
+static SWORD sl_old;\r
+static SWORD *sl_buffer=NULL;\r
+static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;\r
+\r
+/* size of the loader buffer in words */\r
+#define SLBUFSIZE 2048\r
+\r
+/* IT-Compressed status structure */\r
+typedef struct ITPACK {\r
+       UWORD bits;    /* current number of bits */\r
+       UWORD bufbits; /* bits in buffer */\r
+       SWORD last;    /* last output */\r
+       UBYTE buf;     /* bit buffer */\r
+} ITPACK;\r
+\r
+BOOL SL_Init(SAMPLOAD* s)\r
+{\r
+       if(!sl_buffer)\r
+               if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;\r
+\r
+       sl_rlength = s->length;\r
+       if(s->infmt & SF_16BITS) sl_rlength>>=1;\r
+       sl_old = 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void SL_Exit(SAMPLOAD *s)\r
+{\r
+       if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);\r
+       if(sl_buffer) {\r
+               free(sl_buffer);\r
+               sl_buffer=NULL;\r
+       }\r
+}\r
+\r
+/* unpack a 8bit IT packed sample */\r
+static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
+{\r
+       SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
+       UWORD x,y,needbits,havebits,new_count=0;\r
+       UWORD bits = status->bits;\r
+       UWORD bufbits = status->bufbits;\r
+       SBYTE last = status->last;\r
+       UBYTE buf = status->buf;\r
+\r
+       while (dest<end) {\r
+               needbits=new_count?3:bits;\r
+               x=havebits=0;\r
+               while (needbits) {\r
+                       /* feed buffer */\r
+                       if (!bufbits) {\r
+                               if((*incnt)--)\r
+                                       buf=_mm_read_UBYTE(reader);\r
+                               else\r
+                                       buf=0;\r
+                               bufbits=8;\r
+                       }\r
+                       /* get as many bits as necessary */\r
+                       y = needbits<bufbits?needbits:bufbits;\r
+                       x|= (buf & ((1<<y)- 1))<<havebits;\r
+                       buf>>=y;\r
+                       bufbits-=y;\r
+                       needbits-=y;\r
+                       havebits+=y;\r
+               }\r
+               if (new_count) {\r
+                       new_count = 0;\r
+                       if (++x >= bits)\r
+                               x++;\r
+                       bits = x;\r
+                       continue;\r
+               }\r
+               if (bits<7) {\r
+                       if (x==(1<<(bits-1))) {\r
+                               new_count = 1;\r
+                               continue;\r
+                       }\r
+               }\r
+               else if (bits<9) {\r
+                       y = (0xff >> (9-bits)) - 4;\r
+                       if ((x>y)&&(x<=y+8)) {\r
+                               if ((x-=y)>=bits)\r
+                                       x++;\r
+                               bits = x;\r
+                               continue;\r
+                       }\r
+               }\r
+               else if (bits<10) {\r
+                       if (x>=0x100) {\r
+                               bits=x-0x100+1;\r
+                               continue;\r
+                       }\r
+               } else {\r
+                       /* error in compressed data... */\r
+                       _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+                       return 0;\r
+               }\r
+\r
+               if (bits<8) /* extend sign */\r
+                       x = ((SBYTE)(x <<(8-bits))) >> (8-bits);\r
+               *(dest++)= (last+=x) << 8; /* convert to 16 bit */\r
+       }\r
+       status->bits = bits;\r
+       status->bufbits = bufbits;\r
+       status->last = last;\r
+       status->buf = buf;\r
+       return dest-sl_buffer;\r
+}\r
+\r
+/* unpack a 16bit IT packed sample */\r
+static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
+{\r
+       SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
+       SLONG x,y,needbits,havebits,new_count=0;\r
+       UWORD bits = status->bits;\r
+       UWORD bufbits = status->bufbits;\r
+       SWORD last = status->last;\r
+       UBYTE buf = status->buf;\r
+\r
+       while (dest<end) {\r
+               needbits=new_count?4:bits;\r
+               x=havebits=0;\r
+               while (needbits) {\r
+                       /* feed buffer */\r
+                       if (!bufbits) {\r
+                               if((*incnt)--)\r
+                                       buf=_mm_read_UBYTE(reader);\r
+                               else\r
+                                       buf=0;\r
+                               bufbits=8;\r
+                       }\r
+                       /* get as many bits as necessary */\r
+                       y=needbits<bufbits?needbits:bufbits;\r
+                       x|=(buf &((1<<y)-1))<<havebits;\r
+                       buf>>=y;\r
+                       bufbits-=y;\r
+                       needbits-=y;\r
+                       havebits+=y;\r
+               }\r
+               if (new_count) {\r
+                       new_count = 0;\r
+                       if (++x >= bits)\r
+                               x++;\r
+                       bits = x;\r
+                       continue;\r
+               }\r
+               if (bits<7) {\r
+                       if (x==(1<<(bits-1))) {\r
+                               new_count=1;\r
+                               continue;\r
+                       }\r
+               }\r
+               else if (bits<17) {\r
+                       y=(0xffff>>(17-bits))-8;\r
+                       if ((x>y)&&(x<=y+16)) {\r
+                               if ((x-=y)>=bits)\r
+                                       x++;\r
+                               bits = x;\r
+                               continue;\r
+                       }\r
+               }\r
+               else if (bits<18) {\r
+                       if (x>=0x10000) {\r
+                               bits=x-0x10000+1;\r
+                               continue;\r
+                       }\r
+               } else {\r
+                        /* error in compressed data... */\r
+                       _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+                       return 0;\r
+               }\r
+\r
+               if (bits<16) /* extend sign */\r
+                       x = ((SWORD)(x<<(16-bits)))>>(16-bits);\r
+               *(dest++)=(last+=x);\r
+       }\r
+       status->bits = bits;\r
+       status->bufbits = bufbits;\r
+       status->last = last;\r
+       status->buf = buf;\r
+       return dest-sl_buffer;\r
+}\r
+\r
+static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)\r
+{\r
+       SBYTE *bptr = (SBYTE*)buffer;\r
+       SWORD *wptr = (SWORD*)buffer;\r
+       int stodo,t,u;\r
+\r
+       int result,c_block=0;   /* compression bytes until next block */\r
+       ITPACK status;\r
+       UWORD incnt;\r
+\r
+       while(length) {\r
+               stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;\r
+\r
+               if(infmt&SF_ITPACKED) {\r
+                       sl_rlength=0;\r
+                       if (!c_block) {\r
+                               status.bits = (infmt & SF_16BITS) ? 17 : 9;\r
+                               status.last = status.bufbits = 0;\r
+                               incnt=_mm_read_I_UWORD(reader);\r
+                               c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;\r
+                               if(infmt&SF_DELTA) sl_old=0;\r
+                       }\r
+                       if (infmt & SF_16BITS) {\r
+                               if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))\r
+                                       return 1;\r
+                       } else {\r
+                               if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))\r
+                                       return 1;\r
+                       }\r
+                       if(result!=stodo) {\r
+                               _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+                               return 1;\r
+                       }\r
+                       c_block -= stodo;\r
+               } else {\r
+                       if(infmt&SF_16BITS) {\r
+                               if(infmt&SF_BIG_ENDIAN)\r
+                                       _mm_read_M_SWORDS(sl_buffer,stodo,reader);\r
+                               else\r
+                                       _mm_read_I_SWORDS(sl_buffer,stodo,reader);\r
+                       } else {\r
+                               SBYTE *src;\r
+                               SWORD *dest;\r
+\r
+                               reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);\r
+                               src = (SBYTE*)sl_buffer;\r
+                               dest  = sl_buffer;\r
+                               src += stodo;dest += stodo;\r
+\r
+                               for(t=0;t<stodo;t++) {\r
+                                       src--;dest--;\r
+                                       *dest = (*src)<<8;\r
+                               }\r
+                       }\r
+                       sl_rlength-=stodo;\r
+               }\r
+\r
+               if(infmt & SF_DELTA)\r
+                       for(t=0;t<stodo;t++) {\r
+                               sl_buffer[t] += sl_old;\r
+                               sl_old = sl_buffer[t];\r
+                       }\r
+\r
+               if((infmt^outfmt) & SF_SIGNED) \r
+                       for(t=0;t<stodo;t++)\r
+                               sl_buffer[t]^= 0x8000;\r
+\r
+               if(scalefactor) {\r
+                       int idx = 0;\r
+                       SLONG scaleval;\r
+\r
+                       /* Sample Scaling... average values for better results. */\r
+                       t= 0;\r
+                       while(t<stodo && length) {\r
+                               scaleval = 0;\r
+                               for(u=scalefactor;u && t<stodo;u--,t++)\r
+                                       scaleval+=sl_buffer[t];\r
+                               sl_buffer[idx++]=scaleval/(scalefactor-u);\r
+                               length--;\r
+                       }\r
+                       stodo = idx;\r
+               } else\r
+                       length -= stodo;\r
+\r
+               if (dither) {\r
+                       if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {\r
+                               /* dither stereo to mono, average together every two samples */\r
+                               SLONG avgval;\r
+                               int idx = 0;\r
+\r
+                               t=0;\r
+                               while(t<stodo && length) {\r
+                                       avgval=sl_buffer[t++];\r
+                                       avgval+=sl_buffer[t++];\r
+                                       sl_buffer[idx++]=avgval>>1;\r
+                                       length-=2;\r
+                               }\r
+                               stodo = idx;\r
+                       }\r
+               }\r
+\r
+               if(outfmt & SF_16BITS) {\r
+                       for(t=0;t<stodo;t++)\r
+                               *(wptr++)=sl_buffer[t];\r
+               } else {\r
+                       for(t=0;t<stodo;t++)\r
+                               *(bptr++)=sl_buffer[t]>>8;\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)\r
+{\r
+       return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,\r
+                              length,smp->reader,0);\r
+}\r
+\r
+/* Registers a sample for loading when SL_LoadSamples() is called. */\r
+SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)\r
+{\r
+       SAMPLOAD *news,**samplist,*cruise;\r
+\r
+       if(type==MD_MUSIC) {\r
+               samplist = &musiclist;\r
+               cruise = musiclist;\r
+       } else\r
+         if (type==MD_SNDFX) {\r
+               samplist = &sndfxlist;\r
+               cruise = sndfxlist;\r
+       } else\r
+               return NULL;\r
+       \r
+       /* Allocate and add structure to the END of the list */\r
+       if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;\r
+\r
+       if(cruise) {\r
+               while(cruise->next) cruise=cruise->next;\r
+               cruise->next = news;\r
+       } else\r
+               *samplist = news;\r
+\r
+       news->infmt     = s->flags & SF_FORMATMASK;\r
+       news->outfmt    = news->infmt;\r
+       news->reader    = reader;\r
+       news->sample    = s;\r
+       news->length    = s->length;\r
+       news->loopstart = s->loopstart;\r
+       news->loopend   = s->loopend;\r
+\r
+       return news;\r
+}\r
+\r
+static void FreeSampleList(SAMPLOAD* s)\r
+{\r
+       SAMPLOAD *old;\r
+\r
+       while(s) {\r
+               old = s;\r
+               s = s->next;\r
+               free(old);\r
+       }\r
+}\r
+\r
+/* Returns the total amount of memory required by the samplelist queue. */\r
+static ULONG SampleTotal(SAMPLOAD* samplist,int type)\r
+{\r
+       int total = 0;\r
+\r
+       while(samplist) {\r
+               samplist->sample->flags=\r
+                 (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;\r
+               total += MD_SampleLength(type,samplist->sample);\r
+               samplist=samplist->next;\r
+       }\r
+\r
+       return total;\r
+}\r
+\r
+static ULONG RealSpeed(SAMPLOAD *s)\r
+{\r
+       return(s->sample->speed/(s->scalefactor?s->scalefactor:1));\r
+}    \r
+\r
+static BOOL DitherSamples(SAMPLOAD* samplist,int type)\r
+{\r
+       SAMPLOAD *c2smp=NULL;\r
+       ULONG maxsize, speed;\r
+       SAMPLOAD *s;\r
+\r
+       if(!samplist) return 0;\r
+\r
+       if((maxsize=MD_SampleSpace(type)*1024)) \r
+               while(SampleTotal(samplist,type)>maxsize) {\r
+                       /* First Pass - check for any 16 bit samples */\r
+                       s = samplist;\r
+                       while(s) {\r
+                               if(s->outfmt & SF_16BITS) {\r
+                                       SL_Sample16to8(s);\r
+                                       break;\r
+                               }\r
+                               s=s->next;\r
+                       }\r
+                       /* Second pass (if no 16bits found above) is to take the sample with\r
+                          the highest speed and dither it by half. */\r
+                       if(!s) {\r
+                               s = samplist;\r
+                               speed = 0;\r
+                               while(s) {\r
+                                       if((s->sample->length) && (RealSpeed(s)>speed)) {\r
+                                               speed=RealSpeed(s);\r
+                                               c2smp=s;\r
+                                       }\r
+                                       s=s->next;\r
+                               }\r
+                               if (c2smp)\r
+                                       SL_HalveSample(c2smp,2);\r
+                       }\r
+               }\r
+\r
+       /* Samples dithered, now load them ! */\r
+       s = samplist;\r
+       while(s) {\r
+               /* sample has to be loaded ? -> increase number of samples, allocate\r
+                  memory and load sample. */\r
+               if(s->sample->length) {\r
+                       if(s->sample->seekpos)\r
+                               _mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);\r
+\r
+                       /* Call the sample load routine of the driver module. It has to\r
+                          return a 'handle' (>=0) that identifies the sample. */\r
+                       s->sample->handle = MD_SampleLoad(s, type);\r
+                       s->sample->flags  = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;\r
+                       if(s->sample->handle<0) {\r
+                               FreeSampleList(samplist);\r
+                               if(_mm_errorhandler) _mm_errorhandler();\r
+                               return 1;\r
+                       }\r
+               }\r
+               s = s->next;\r
+       }\r
+\r
+       FreeSampleList(samplist);\r
+       return 0;\r
+}\r
+\r
+BOOL SL_LoadSamples(void)\r
+{\r
+       BOOL ok;\r
+\r
+       _mm_critical = 0;\r
+\r
+       if((!musiclist)&&(!sndfxlist)) return 0;\r
+       ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);\r
+       musiclist=sndfxlist=NULL;\r
+\r
+       return ok;\r
+}\r
+\r
+void SL_Sample16to8(SAMPLOAD* s)\r
+{\r
+       s->outfmt &= ~SF_16BITS;\r
+       s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_Sample8to16(SAMPLOAD* s)\r
+{\r
+       s->outfmt |= SF_16BITS;\r
+       s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_SampleSigned(SAMPLOAD* s)\r
+{\r
+       s->outfmt |= SF_SIGNED;\r
+       s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_SampleUnsigned(SAMPLOAD* s)\r
+{\r
+       s->outfmt &= ~SF_SIGNED;\r
+       s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_HalveSample(SAMPLOAD* s,int factor)\r
+{\r
+       s->scalefactor=factor>0?factor:2;\r
+\r
+       s->sample->divfactor = s->scalefactor;\r
+       s->sample->length    = s->length / s->scalefactor;\r
+       s->sample->loopstart = s->loopstart / s->scalefactor;\r
+       s->sample->loopend   = s->loopend / s->scalefactor;\r
+}\r
+\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/virtch.c b/apps/plugins/mikmod/playercode/virtch.c
new file mode 100644 (file)
index 0000000..a7b49d8
--- /dev/null
@@ -0,0 +1,968 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+       AUTHORS for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: virtch.c,v 1.2 2004/02/13 13:31:54 raph Exp $\r
+\r
+  Sample mixing routines, using a 32 bits mixing buffer.\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+  Optional features include:\r
+    (a) 4-step reverb (for 16 bit output only)\r
+    (b) Interpolation of sample data during mixing\r
+    (c) Dolby Surround Sound\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include <stddef.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+/*\r
+   Constant definitions\r
+   ====================\r
+\r
+       BITSHIFT\r
+               Controls the maximum volume of the sound output.  All data is shifted\r
+               right by BITSHIFT after being mixed. Higher values result in quieter\r
+               sound and less chance of distortion.\r
+\r
+       REVERBERATION\r
+               Controls the duration of the reverb. Larger values represent a shorter\r
+               reverb loop. Smaller values extend the reverb but can result in more of\r
+               an echo-ish sound.\r
+\r
+*/\r
+\r
+#define BITSHIFT               9\r
+#define REVERBERATION  110000L\r
+\r
+#define FRACBITS 11\r
+#define FRACMASK ((1L<<FRACBITS)-1L)\r
+\r
+#define TICKLSIZE 8192\r
+#define TICKWSIZE (TICKLSIZE<<1)\r
+#define TICKBSIZE (TICKWSIZE<<1)\r
+\r
+#define CLICK_SHIFT  6\r
+#define CLICK_BUFFER (1L<<CLICK_SHIFT)\r
+\r
+#ifndef MIN\r
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))\r
+#endif\r
+\r
+typedef struct VINFO {\r
+       UBYTE     kick;              /* =1 -> sample has to be restarted */\r
+       UBYTE     active;            /* =1 -> sample is playing */\r
+       UWORD     flags;             /* 16/8 bits looping/one-shot */\r
+       SWORD     handle;            /* identifies the sample */\r
+       ULONG     start;             /* start index */\r
+       ULONG     size;              /* samplesize */\r
+       ULONG     reppos;            /* loop start */\r
+       ULONG     repend;            /* loop end */\r
+       ULONG     frq;               /* current frequency */\r
+       int       vol;               /* current volume */\r
+       int       pan;               /* current panning position */\r
+\r
+       int       rampvol;\r
+       int       lvolsel,rvolsel;   /* Volume factor in range 0-255 */\r
+       int       oldlvol,oldrvol;\r
+\r
+       SLONGLONG current;           /* current index in the sample */\r
+       SLONGLONG increment;         /* increment value */\r
+} VINFO;\r
+\r
+static SWORD **Samples;\r
+static VINFO *vinf=NULL,*vnf;\r
+static long tickleft,samplesthatfit,vc_memory=0;\r
+static int vc_softchn;\r
+static SLONGLONG idxsize,idxlpos,idxlend;\r
+static SLONG *vc_tickbuf=NULL;\r
+static UWORD vc_mode;\r
+\r
+/* Reverb control variables */\r
+\r
+static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;\r
+static ULONG RVRindex;\r
+\r
+/* For Mono or Left Channel */\r
+static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,\r
+                     *RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;\r
+\r
+/* For Stereo only (Right Channel) */\r
+static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,\r
+                     *RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;\r
+\r
+#ifdef NATIVE_64BIT_INT\r
+#define NATIVE SLONGLONG\r
+#else\r
+#define NATIVE SLONG\r
+#endif\r
+\r
+/*========== 32 bit sample mixers - only for 32 bit platforms */\r
+#ifndef NATIVE_64BIT_INT\r
+\r
+static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+\r
+       while(todo--) {\r
+               sample = srce[index >> FRACBITS];\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+\r
+       while(todo--) {\r
+               sample=srce[index >> FRACBITS];\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+               *dest++ += rvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32SurroundNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+\r
+       if (lvolsel>=rvolsel) {\r
+               while(todo--) {\r
+                       sample = srce[index >> FRACBITS];\r
+                       index += increment;\r
+\r
+                       *dest++ += lvolsel*sample;\r
+                       *dest++ -= lvolsel*sample;\r
+               }\r
+       } else {\r
+               while(todo--) {\r
+                       sample = srce[index >> FRACBITS];\r
+                       index += increment;\r
+\r
+                       *dest++ -= rvolsel*sample;\r
+                       *dest++ += rvolsel*sample;\r
+               }\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32MonoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+\r
+       if (rampvol) {\r
+               SLONG oldlvol = vnf->oldlvol - lvolsel;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)\r
+                                  * sample >> CLICK_SHIFT;\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32StereoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+\r
+       if (rampvol) {\r
+               SLONG oldlvol = vnf->oldlvol - lvolsel;\r
+               SLONG oldrvol = vnf->oldrvol - rvolsel;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)\r
+                                  * sample >> CLICK_SHIFT;\r
+                       *dest++ += ((rvolsel << CLICK_SHIFT) + oldrvol * rampvol)\r
+                                          * sample >> CLICK_SHIFT;\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+               *dest++ += rvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32SurroundInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+       SLONG oldvol, vol;\r
+\r
+       if (lvolsel >= rvolsel) {\r
+               vol = lvolsel;\r
+               oldvol = vnf->oldlvol;\r
+       } else {\r
+               vol = rvolsel;\r
+               oldvol = vnf->oldrvol;\r
+       }\r
+\r
+       if (rampvol) {\r
+               oldvol -= vol;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       sample=((vol << CLICK_SHIFT) + oldvol * rampvol)\r
+                                  * sample >> CLICK_SHIFT;\r
+                       *dest++ += sample;\r
+                       *dest++ -= sample;\r
+\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += vol*sample;\r
+               *dest++ -= vol*sample;\r
+       }\r
+       return index;\r
+}\r
+#endif\r
+\r
+/*========== 64 bit sample mixers - all platforms */\r
+\r
+static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+\r
+       while(todo--) {\r
+               sample = srce[index >> FRACBITS];\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+\r
+       while(todo--) {\r
+               sample=srce[index >> FRACBITS];\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+               *dest++ += rvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixSurroundNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SWORD sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+\r
+       if(vnf->lvolsel>=vnf->rvolsel) {\r
+               while(todo--) {\r
+                       sample = srce[index >> FRACBITS];\r
+                       index += increment;\r
+\r
+                       *dest++ += lvolsel*sample;\r
+                       *dest++ -= lvolsel*sample;\r
+               }\r
+       } else {\r
+               while(todo--) {\r
+                       sample = srce[index >> FRACBITS];\r
+                       index += increment;\r
+\r
+                       *dest++ -= rvolsel*sample;\r
+                       *dest++ += rvolsel*sample;\r
+               }\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixMonoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+\r
+       if (rampvol) {\r
+               SLONG oldlvol = vnf->oldlvol - lvolsel;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)\r
+                                          * sample >> CLICK_SHIFT;\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixStereoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+\r
+       if (rampvol) {\r
+               SLONG oldlvol = vnf->oldlvol - lvolsel;\r
+               SLONG oldrvol = vnf->oldrvol - rvolsel;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       *dest++ +=((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)\r
+                                          * sample >> CLICK_SHIFT;\r
+                       *dest++ +=((rvolsel << CLICK_SHIFT) + oldrvol * rampvol)\r
+                                          * sample >> CLICK_SHIFT;\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += lvolsel * sample;\r
+               *dest++ += rvolsel * sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixSurroundInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SLONG sample;\r
+       SLONG lvolsel = vnf->lvolsel;\r
+       SLONG rvolsel = vnf->rvolsel;\r
+       SLONG rampvol = vnf->rampvol;\r
+       SLONG oldvol, vol;\r
+\r
+       if (lvolsel >= rvolsel) {\r
+               vol = lvolsel;\r
+               oldvol = vnf->oldlvol;\r
+       } else {\r
+               vol = rvolsel;\r
+               oldvol = vnf->oldrvol;\r
+       }\r
+\r
+       if (rampvol) {\r
+               oldvol -= vol;\r
+               while(todo--) {\r
+                       sample=(SLONG)srce[index>>FRACBITS]+\r
+                              ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                               *(index&FRACMASK)>>FRACBITS);\r
+                       index += increment;\r
+\r
+                       sample=((vol << CLICK_SHIFT) + oldvol * rampvol)\r
+                                  * sample >> CLICK_SHIFT;\r
+                       *dest++ += sample;\r
+                       *dest++ -= sample;\r
+                       if (!--rampvol)\r
+                               break;\r
+               }\r
+               vnf->rampvol = rampvol;\r
+               if (todo < 0)\r
+                       return index;\r
+       }\r
+\r
+       while(todo--) {\r
+               sample=(SLONG)srce[index>>FRACBITS]+\r
+                      ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])\r
+                       *(index&FRACMASK)>>FRACBITS);\r
+               index += increment;\r
+\r
+               *dest++ += vol*sample;\r
+               *dest++ -= vol*sample;\r
+       }\r
+       return index;\r
+}\r
+\r
+static void (*MixReverb)(SLONG* srce,NATIVE count);\r
+\r
+/* Reverb macros */\r
+#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n\r
+#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)\r
+#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)\r
+\r
+static void MixReverb_Normal(SLONG* srce,NATIVE count)\r
+{\r
+       unsigned int speedup;\r
+       int ReverbPct;\r
+       unsigned int loc1,loc2,loc3,loc4;\r
+       unsigned int loc5,loc6,loc7,loc8;\r
+\r
+       ReverbPct=58+(md_reverb<<2);\r
+\r
+       COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+       COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+       while(count--) {\r
+               /* Compute the left channel echo buffers */\r
+               speedup = *srce >> 3;\r
+\r
+               COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
+               COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
+\r
+               /* Prepare to compute actual finalized data */\r
+               RVRindex++;\r
+\r
+               COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+               COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+               /* left channel */\r
+               *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+\r
+                         RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
+       }\r
+}\r
+\r
+static void MixReverb_Stereo(SLONG* srce,NATIVE count)\r
+{\r
+       unsigned int speedup;\r
+       int          ReverbPct;\r
+       unsigned int loc1, loc2, loc3, loc4;\r
+       unsigned int loc5, loc6, loc7, loc8;\r
+\r
+       ReverbPct = 92+(md_reverb<<1);\r
+\r
+       COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+       COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+       while(count--) {\r
+               /* Compute the left channel echo buffers */\r
+               speedup = *srce >> 3;\r
+\r
+               COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
+               COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
+\r
+               /* Compute the right channel echo buffers */\r
+               speedup = srce[1] >> 3;\r
+\r
+               COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);\r
+               COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);\r
+\r
+               /* Prepare to compute actual finalized data */\r
+               RVRindex++;\r
+\r
+               COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+               COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+               /* left channel then right channel */\r
+               *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+\r
+                         RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
+\r
+               *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+\r
+                         RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];\r
+       }\r
+}\r
+\r
+/* Mixing macros */\r
+#define EXTRACT_SAMPLE_FP(var,size) var=(*srce++>>(BITSHIFT-size)) * ((1.0f / 32768.0f) / (1 << size))\r
+#define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var\r
+#define PUT_SAMPLE_FP(var) *dste++=var\r
+\r
+static void Mix32ToFP(float* dste,SLONG* srce,NATIVE count)\r
+{\r
+       float x1,x2,x3,x4;\r
+       int     remain;\r
+\r
+       #define FP_SHIFT        4\r
+       \r
+       remain=count&3;\r
+       for(count>>=2;count;count--) {\r
+               EXTRACT_SAMPLE_FP(x1,FP_SHIFT); EXTRACT_SAMPLE_FP(x2,FP_SHIFT);\r
+               EXTRACT_SAMPLE_FP(x3,FP_SHIFT); EXTRACT_SAMPLE_FP(x4,FP_SHIFT);\r
+\r
+               CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);\r
+               CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f);\r
+\r
+               PUT_SAMPLE_FP(x1); PUT_SAMPLE_FP(x2);\r
+               PUT_SAMPLE_FP(x3); PUT_SAMPLE_FP(x4);\r
+       }\r
+       while(remain--) {\r
+               EXTRACT_SAMPLE_FP(x1,FP_SHIFT);\r
+               CHECK_SAMPLE_FP(x1,1.0f);\r
+               PUT_SAMPLE_FP(x1);\r
+       }\r
+}\r
+\r
+\r
+/* Mixing macros */\r
+#define EXTRACT_SAMPLE(var,size) var=*srce++>>(BITSHIFT+16-size)\r
+#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var\r
+#define PUT_SAMPLE(var) *dste++=var\r
+\r
+static void Mix32To16(SWORD* dste,SLONG* srce,NATIVE count)\r
+{\r
+       SLONG x1,x2,x3,x4;\r
+       int     remain;\r
+\r
+       remain=count&3;\r
+       for(count>>=2;count;count--) {\r
+               EXTRACT_SAMPLE(x1,16); EXTRACT_SAMPLE(x2,16);\r
+               EXTRACT_SAMPLE(x3,16); EXTRACT_SAMPLE(x4,16);\r
+\r
+               CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);\r
+               CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);\r
+\r
+               PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4);\r
+       }\r
+       while(remain--) {\r
+               EXTRACT_SAMPLE(x1,16);\r
+               CHECK_SAMPLE(x1,32768);\r
+               PUT_SAMPLE(x1);\r
+       }\r
+}\r
+\r
+static void Mix32To8(SBYTE* dste,SLONG* srce,NATIVE count)\r
+{\r
+       SWORD x1,x2,x3,x4;\r
+       int     remain;\r
+\r
+       remain=count&3;\r
+       for(count>>=2;count;count--) {\r
+               EXTRACT_SAMPLE(x1,8); EXTRACT_SAMPLE(x2,8);\r
+               EXTRACT_SAMPLE(x3,8); EXTRACT_SAMPLE(x4,8);\r
+\r
+               CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);\r
+               CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);\r
+\r
+               PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128);\r
+               PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128);\r
+       }\r
+       while(remain--) {\r
+               EXTRACT_SAMPLE(x1,8);\r
+               CHECK_SAMPLE(x1,128);\r
+               PUT_SAMPLE(x1+128);\r
+       }\r
+}\r
+\r
+static void AddChannel(SLONG* ptr,NATIVE todo)\r
+{\r
+       SLONGLONG end,done;\r
+       SWORD *s;\r
+\r
+       if(!(s=Samples[vnf->handle])) {\r
+               vnf->current = vnf->active  = 0;\r
+               return;\r
+       }\r
+\r
+       /* update the 'current' index so the sample loops, or stops playing if it\r
+          reached the end of the sample */\r
+       while(todo>0) {\r
+               SLONGLONG endpos;\r
+\r
+               if(vnf->flags & SF_REVERSE) {\r
+                       /* The sample is playing in reverse */\r
+                       if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {\r
+                               /* the sample is looping and has reached the loopstart index */\r
+                               if(vnf->flags & SF_BIDI) {\r
+                                       /* sample is doing bidirectional loops, so 'bounce' the\r
+                                          current index against the idxlpos */\r
+                                       vnf->current = idxlpos+(idxlpos-vnf->current);\r
+                                       vnf->flags &= ~SF_REVERSE;\r
+                                       vnf->increment = -vnf->increment;\r
+                               } else\r
+                                       /* normal backwards looping, so set the current position to\r
+                                          loopend index */\r
+                                       vnf->current=idxlend-(idxlpos-vnf->current);\r
+                       } else {\r
+                               /* the sample is not looping, so check if it reached index 0 */\r
+                               if(vnf->current < 0) {\r
+                                       /* playing index reached 0, so stop playing this sample */\r
+                                       vnf->current = vnf->active  = 0;\r
+                                       break;\r
+                               }\r
+                       }\r
+               } else {\r
+                       /* The sample is playing forward */\r
+                       if((vnf->flags & SF_LOOP) &&\r
+                          (vnf->current >= idxlend)) {\r
+                               /* the sample is looping, check the loopend index */\r
+                               if(vnf->flags & SF_BIDI) {\r
+                                       /* sample is doing bidirectional loops, so 'bounce' the\r
+                                          current index against the idxlend */\r
+                                       vnf->flags |= SF_REVERSE;\r
+                                       vnf->increment = -vnf->increment;\r
+                                       vnf->current = idxlend-(vnf->current-idxlend);\r
+                               } else\r
+                                       /* normal backwards looping, so set the current position\r
+                                          to loopend index */\r
+                                       vnf->current=idxlpos+(vnf->current-idxlend);\r
+                       } else {\r
+                               /* sample is not looping, so check if it reached the last\r
+                                  position */\r
+                               if(vnf->current >= idxsize) {\r
+                                       /* yes, so stop playing this sample */\r
+                                       vnf->current = vnf->active  = 0;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:\r
+                    (vnf->flags&SF_LOOP)?idxlend:idxsize;\r
+\r
+               /* if the sample is not blocked... */\r
+               if((end==vnf->current)||(!vnf->increment))\r
+                       done=0;\r
+               else {\r
+                       done=MIN((end-vnf->current)/vnf->increment+1,todo);\r
+                       if(done<0) done=0;\r
+               }\r
+\r
+               if(!done) {\r
+                       vnf->active = 0;\r
+                       break;\r
+               }\r
+\r
+               endpos=vnf->current+done*vnf->increment;\r
+\r
+               if(vnf->vol) {\r
+#ifndef NATIVE_64BIT_INT\r
+                       /* use the 32 bit mixers as often as we can (they're much faster) */\r
+                       if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {\r
+                               if((md_mode & DMODE_INTERP)) {\r
+                                       if(vc_mode & DMODE_STEREO) {\r
+                                               if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))\r
+                                                       vnf->current=Mix32SurroundInterp\r
+                                                                  (s,ptr,vnf->current,vnf->increment,done);\r
+                                               else\r
+                                                       vnf->current=Mix32StereoInterp\r
+                                                                  (s,ptr,vnf->current,vnf->increment,done);\r
+                                       } else\r
+                                               vnf->current=Mix32MonoInterp\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else if(vc_mode & DMODE_STEREO) {\r
+                                       if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))\r
+                                               vnf->current=Mix32SurroundNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                                       else\r
+                                               vnf->current=Mix32StereoNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else\r
+                                       vnf->current=Mix32MonoNormal\r
+                                                          (s,ptr,vnf->current,vnf->increment,done);\r
+                       } else\r
+#endif\r
+                              {\r
+                               if((md_mode & DMODE_INTERP)) {\r
+                                       if(vc_mode & DMODE_STEREO) {\r
+                                               if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))\r
+                                                       vnf->current=MixSurroundInterp\r
+                                                                  (s,ptr,vnf->current,vnf->increment,done);\r
+                                               else\r
+                                                       vnf->current=MixStereoInterp\r
+                                                                  (s,ptr,vnf->current,vnf->increment,done);\r
+                                       } else\r
+                                               vnf->current=MixMonoInterp\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else if(vc_mode & DMODE_STEREO) {\r
+                                       if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))\r
+                                               vnf->current=MixSurroundNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                                       else\r
+                                               vnf->current=MixStereoNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else\r
+                                       vnf->current=MixMonoNormal\r
+                                                          (s,ptr,vnf->current,vnf->increment,done);\r
+                       }\r
+               } else\r
+                       /* update sample position */\r
+                       vnf->current=endpos;\r
+\r
+               todo-=done;\r
+               ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;\r
+       }\r
+}\r
+\r
+#define _IN_VIRTCH_\r
+#include "virtch_common.c"\r
+#undef _IN_VIRTCH_\r
+\r
+void VC1_WriteSamples(SBYTE* buf,ULONG todo)\r
+{\r
+       int left,portion=0,count;\r
+       SBYTE  *buffer;\r
+       int t, pan, vol;\r
+\r
+       while(todo) {\r
+               if(!tickleft) {\r
+                       if(vc_mode & DMODE_SOFT_MUSIC) md_player();\r
+                       tickleft=(md_mixfreq*125L)/(md_bpm*50L);\r
+               }\r
+               left = MIN(tickleft, todo);\r
+               buffer    = buf;\r
+               tickleft -= left;\r
+               todo     -= left;\r
+               buf += samples2bytes(left);\r
+\r
+               while(left) {\r
+                       portion = MIN(left, samplesthatfit);\r
+                       count   = (vc_mode & DMODE_STEREO)?(portion<<1):portion;\r
+                       memset(vc_tickbuf, 0, count<<2);\r
+                       for(t=0;t<vc_softchn;t++) {\r
+                               vnf = &vinf[t];\r
+\r
+                               if(vnf->kick) {\r
+                                       vnf->current=((SLONGLONG)vnf->start)<<FRACBITS;\r
+                                       vnf->kick   =0;\r
+                                       vnf->active =1;\r
+                               }\r
+\r
+                               if(!vnf->frq) vnf->active = 0;\r
+\r
+                               if(vnf->active) {\r
+                                       vnf->increment=((SLONGLONG)(vnf->frq<<FRACBITS))/md_mixfreq;\r
+                                       if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;\r
+                                       vol = vnf->vol;  pan = vnf->pan;\r
+\r
+                                       vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;\r
+                                       if(vc_mode & DMODE_STEREO) {\r
+                                               if(pan != PAN_SURROUND) {\r
+                                                       vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;\r
+                                                       vnf->rvolsel=(vol*pan)>>8;\r
+                                               } else\r
+                                                       vnf->lvolsel=vnf->rvolsel=vol/2;\r
+                                       } else\r
+                                               vnf->lvolsel=vol;\r
+\r
+                                       idxsize = (vnf->size)? ((SLONGLONG)vnf->size << FRACBITS)-1 : 0;\r
+                                       idxlend = (vnf->repend)? ((SLONGLONG)vnf->repend << FRACBITS)-1 : 0;\r
+                                       idxlpos = (SLONGLONG)vnf->reppos << FRACBITS;\r
+                                       AddChannel(vc_tickbuf, portion);\r
+                               }\r
+                       }\r
+\r
+                       if(md_reverb) {\r
+                               if(md_reverb>15) md_reverb=15;\r
+                               MixReverb(vc_tickbuf, portion);\r
+                       }\r
+\r
+                       if(vc_mode & DMODE_FLOAT)\r
+                               Mix32ToFP((float*) buffer, vc_tickbuf, count);\r
+                       else if(vc_mode & DMODE_16BITS)\r
+                               Mix32To16((SWORD*) buffer, vc_tickbuf, count);\r
+                       else\r
+                               Mix32To8((SBYTE*) buffer, vc_tickbuf, count);\r
+\r
+                       buffer += samples2bytes(portion);\r
+                       left   -= portion;\r
+               }\r
+       }\r
+}\r
+\r
+BOOL VC1_Init(void)\r
+{\r
+       VC_SetupPointers();\r
+       \r
+       if (md_mode&DMODE_HQMIXER)\r
+               return VC2_Init();\r
+\r
+       if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {\r
+               _mm_errno = MMERR_INITIALIZING_MIXER;\r
+               return 1;\r
+       }\r
+       if(!vc_tickbuf)\r
+               if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {\r
+                       _mm_errno = MMERR_INITIALIZING_MIXER;\r
+                       return 1;\r
+               }\r
+\r
+       MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal;\r
+       vc_mode = md_mode;\r
+       return 0;\r
+}\r
+\r
+BOOL VC1_PlayStart(void)\r
+{\r
+       samplesthatfit=TICKLSIZE;\r
+       if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;\r
+       tickleft = 0;\r
+\r
+       RVc1 = (5000L * md_mixfreq) / REVERBERATION;\r
+       RVc2 = (5078L * md_mixfreq) / REVERBERATION;\r
+       RVc3 = (5313L * md_mixfreq) / REVERBERATION;\r
+       RVc4 = (5703L * md_mixfreq) / REVERBERATION;\r
+       RVc5 = (6250L * md_mixfreq) / REVERBERATION;\r
+       RVc6 = (6953L * md_mixfreq) / REVERBERATION;\r
+       RVc7 = (7813L * md_mixfreq) / REVERBERATION;\r
+       RVc8 = (8828L * md_mixfreq) / REVERBERATION;\r
+\r
+       if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
+\r
+       if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
+\r
+       RVRindex = 0;\r
+       return 0;\r
+}\r
+\r
+void VC1_PlayStop(void)\r
+{\r
+       if(RVbufL1) free(RVbufL1);\r
+       if(RVbufL2) free(RVbufL2);\r
+       if(RVbufL3) free(RVbufL3);\r
+       if(RVbufL4) free(RVbufL4);\r
+       if(RVbufL5) free(RVbufL5);\r
+       if(RVbufL6) free(RVbufL6);\r
+       if(RVbufL7) free(RVbufL7);\r
+       if(RVbufL8) free(RVbufL8);\r
+       RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;\r
+       if(RVbufR1) free(RVbufR1);\r
+       if(RVbufR2) free(RVbufR2);\r
+       if(RVbufR3) free(RVbufR3);\r
+       if(RVbufR4) free(RVbufR4);\r
+       if(RVbufR5) free(RVbufR5);\r
+       if(RVbufR6) free(RVbufR6);\r
+       if(RVbufR7) free(RVbufR7);\r
+       if(RVbufR8) free(RVbufR8);\r
+       RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;\r
+}\r
+\r
+BOOL VC1_SetNumVoices(void)\r
+{\r
+       int t;\r
+\r
+       if(!(vc_softchn=md_softchn)) return 0;\r
+\r
+       if(vinf) free(vinf);\r
+       if(!(vinf= _mm_calloc(sizeof(VINFO),vc_softchn))) return 1;\r
+\r
+       for(t=0;t<vc_softchn;t++) {\r
+               vinf[t].frq=10000;\r
+               vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/virtch2.c b/apps/plugins/mikmod/playercode/virtch2.c
new file mode 100644 (file)
index 0000000..4a11dc7
--- /dev/null
@@ -0,0 +1,938 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for\r
+       complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: virtch2.c,v 1.2 2004/02/13 13:31:54 raph Exp $\r
+\r
+  High-quality sample mixing routines, using a 32 bits mixing buffer,\r
+  interpolation, and sample smoothing to improve sound quality and remove\r
+  clicks.\r
+\r
+==============================================================================*/\r
+\r
+/*\r
+\r
+  Future Additions:\r
+       Low-Pass filter to remove annoying staticy buzz.\r
+\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+  \r
+/*\r
+   Constant Definitions\r
+   ====================\r
+\r
+       MAXVOL_FACTOR (was BITSHIFT in virtch.c)\r
+               Controls the maximum volume of the output data. All mixed data is\r
+               divided by this number after mixing, so larger numbers result in\r
+               quieter mixing.  Smaller numbers will increase the likeliness of\r
+               distortion on loud modules.\r
+\r
+       REVERBERATION\r
+               Larger numbers result in shorter reverb duration. Longer reverb\r
+               durations can cause unwanted static and make the reverb sound more\r
+               like a crappy echo.\r
+\r
+       SAMPLING_SHIFT\r
+               Specified the shift multiplier which controls by how much the mixing\r
+               rate is multiplied while mixing.  Higher values can improve quality by\r
+               smoothing the sound and reducing pops and clicks. Note, this is a shift\r
+               value, so a value of 2 becomes a mixing-rate multiplier of 4, and a\r
+               value of 3 = 8, etc.\r
+\r
+       FRACBITS\r
+               The number of bits per integer devoted to the fractional part of the\r
+               number. Generally, this number should not be changed for any reason.\r
+\r
+       !!! IMPORTANT !!! All values below MUST ALWAYS be greater than 0\r
+\r
+*/\r
+\r
+#define MAXVOL_FACTOR (1<<9)\r
+#define        REVERBERATION 11000L\r
+\r
+#define SAMPLING_SHIFT 2\r
+#define SAMPLING_FACTOR (1UL<<SAMPLING_SHIFT)\r
+\r
+#define        FRACBITS 28\r
+#define FRACMASK ((1UL<<FRACBITS)-1UL)\r
+\r
+#define TICKLSIZE 8192\r
+#define TICKWSIZE (TICKLSIZE * 2)\r
+#define TICKBSIZE (TICKWSIZE * 2)\r
+\r
+#define CLICK_SHIFT_BASE 6\r
+#define CLICK_SHIFT (CLICK_SHIFT_BASE + SAMPLING_SHIFT)\r
+#define CLICK_BUFFER (1L << CLICK_SHIFT)\r
+\r
+#ifndef MIN\r
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))\r
+#endif\r
+\r
+typedef struct VINFO {\r
+       UBYTE     kick;              /* =1 -> sample has to be restarted */\r
+       UBYTE     active;            /* =1 -> sample is playing */\r
+       UWORD     flags;             /* 16/8 bits looping/one-shot */\r
+       SWORD     handle;            /* identifies the sample */\r
+       ULONG     start;             /* start index */\r
+       ULONG     size;              /* samplesize */\r
+       ULONG     reppos;            /* loop start */\r
+       ULONG     repend;            /* loop end */\r
+       ULONG     frq;               /* current frequency */\r
+       int       vol;               /* current volume */\r
+       int       pan;               /* current panning position */\r
+\r
+       int       click;\r
+       int       rampvol;\r
+       SLONG     lastvalL,lastvalR;\r
+       int       lvolsel,rvolsel;   /* Volume factor in range 0-255 */\r
+       int       oldlvol,oldrvol;\r
+\r
+       SLONGLONG current;           /* current index in the sample */\r
+       SLONGLONG increment;         /* increment value */\r
+} VINFO;\r
+\r
+static SWORD **Samples;\r
+static VINFO *vinf=NULL,*vnf;\r
+static long tickleft,samplesthatfit,vc_memory=0;\r
+static int vc_softchn;\r
+static SLONGLONG idxsize,idxlpos,idxlend;\r
+static SLONG *vc_tickbuf=NULL;\r
+static UWORD vc_mode;\r
+\r
+/* Reverb control variables */\r
+\r
+static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;\r
+static ULONG RVRindex;\r
+\r
+/* For Mono or Left Channel */\r
+static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,\r
+                     *RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;\r
+\r
+/* For Stereo only (Right Channel) */\r
+static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,\r
+                     *RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;\r
+\r
+#ifdef NATIVE_64BIT_INT\r
+#define NATIVE SLONGLONG\r
+#else\r
+#define NATIVE SLONG\r
+#endif\r
+\r
+/*========== 32 bit sample mixers - only for 32 bit platforms */\r
+#ifndef NATIVE_64BIT_INT\r
+\r
+static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
+{\r
+       SWORD sample=0;\r
+       SLONG i,f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=(((SLONG)(srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONG)srce[i+1]*f)) >> FRACBITS);\r
+               index+=increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       *dest++ += (long)(\r
+                         ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
+                           (SLONG)sample ) >> CLICK_SHIFT );\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONG)sample ) +\r
+                           (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );\r
+                       vnf->click--;\r
+               } else\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel * sample;\r
+\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)\r
+{\r
+       SWORD sample=0;\r
+       SLONG i,f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONG)srce[i+1] * f)) >> FRACBITS);\r
+               index += increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONG)vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))\r
+                           ) * (SLONG)sample ) >> CLICK_SHIFT );\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONG)vnf->oldrvol*vnf->rampvol) +\r
+                             (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))\r
+                           ) * (SLONG)sample ) >> CLICK_SHIFT );\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       *dest++ += (long)(\r
+                         ( ( (SLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONG)sample ) + (vnf->lastvalL * vnf->click) )\r
+                           >> CLICK_SHIFT );\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONG)sample ) + (vnf->lastvalR * vnf->click) )\r
+                           >> CLICK_SHIFT );\r
+                       vnf->click--;\r
+               } else {\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+                       *dest++ +=vnf->rvolsel*sample;\r
+               }\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel*sample;\r
+       vnf->lastvalR=vnf->rvolsel*sample;\r
+\r
+       return index;\r
+}\r
+\r
+static SLONG Mix32StereoSurround(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)\r
+{\r
+       SWORD sample=0;\r
+       long whoop;\r
+       SLONG i, f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONG)srce[i+1]*f)) >> FRACBITS);\r
+               index+=increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       whoop=(long)(\r
+                         ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
+                           (SLONG)sample) >> CLICK_SHIFT );\r
+                       *dest++ +=whoop;\r
+                       *dest++ -=whoop;\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       whoop = (long)(\r
+                         ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONG)sample) +\r
+                           (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );\r
+                       *dest++ +=whoop;\r
+                       *dest++ -=whoop;\r
+                       vnf->click--;\r
+               } else {\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+                       *dest++ -=vnf->lvolsel*sample;\r
+               }\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel*sample;\r
+       vnf->lastvalR=vnf->lvolsel*sample;\r
+\r
+       return index;\r
+}\r
+#endif\r
+\r
+/*========== 64 bit mixers */\r
+\r
+static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
+{\r
+       SWORD sample=0;\r
+       SLONGLONG i,f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=(((SLONGLONG)(srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONGLONG)srce[i+1]*f)) >> FRACBITS);\r
+               index+=increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       *dest++ += (long)(\r
+                         ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
+                           (SLONGLONG)sample ) >> CLICK_SHIFT );\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONGLONG)sample ) +\r
+                           (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );\r
+                       vnf->click--;\r
+               } else\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel * sample;\r
+\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)\r
+{\r
+       SWORD sample=0;\r
+       SLONGLONG i,f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONGLONG)srce[i+1] * f)) >> FRACBITS);\r
+               index += increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONGLONG)vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))\r
+                           ) * (SLONGLONG)sample ) >> CLICK_SHIFT );\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONGLONG)vnf->oldrvol*vnf->rampvol) +\r
+                             (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))\r
+                           ) * (SLONGLONG)sample ) >> CLICK_SHIFT );\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       *dest++ += (long)(\r
+                         ( ( (SLONGLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONGLONG)sample ) + (vnf->lastvalL * vnf->click) )\r
+                           >> CLICK_SHIFT );\r
+                       *dest++ += (long)(\r
+                         ( ( ((SLONGLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONGLONG)sample ) + (vnf->lastvalR * vnf->click) )\r
+                           >> CLICK_SHIFT );\r
+                       vnf->click--;\r
+               } else {\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+                       *dest++ +=vnf->rvolsel*sample;\r
+               }\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel*sample;\r
+       vnf->lastvalR=vnf->rvolsel*sample;\r
+\r
+       return index;\r
+}\r
+\r
+static SLONGLONG MixStereoSurround(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)\r
+{\r
+       SWORD sample=0;\r
+       long whoop;\r
+       SLONGLONG i, f;\r
+\r
+       while(todo--) {\r
+               i=index>>FRACBITS,f=index&FRACMASK;\r
+               sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +\r
+                       ((SLONGLONG)srce[i+1]*f)) >> FRACBITS);\r
+               index+=increment;\r
+\r
+               if(vnf->rampvol) {\r
+                       whoop=(long)(\r
+                         ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +\r
+                             (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
+                           (SLONGLONG)sample) >> CLICK_SHIFT );\r
+                       *dest++ +=whoop;\r
+                       *dest++ -=whoop;\r
+                       vnf->rampvol--;\r
+               } else\r
+                 if(vnf->click) {\r
+                       whoop = (long)(\r
+                         ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
+                             (SLONGLONG)sample) +\r
+                           (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );\r
+                       *dest++ +=whoop;\r
+                       *dest++ -=whoop;\r
+                       vnf->click--;\r
+               } else {\r
+                       *dest++ +=vnf->lvolsel*sample;\r
+                       *dest++ -=vnf->lvolsel*sample;\r
+               }\r
+       }\r
+       vnf->lastvalL=vnf->lvolsel*sample;\r
+       vnf->lastvalR=vnf->lvolsel*sample;\r
+\r
+       return index;\r
+}\r
+\r
+static void(*Mix32toFP)(float* dste,SLONG* srce,NATIVE count);\r
+static void(*Mix32to16)(SWORD* dste,SLONG* srce,NATIVE count);\r
+static void(*Mix32to8)(SBYTE* dste,SLONG* srce,NATIVE count);\r
+static void(*MixReverb)(SLONG* srce,NATIVE count);\r
+\r
+/* Reverb macros */\r
+#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n\r
+#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)\r
+#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)\r
+\r
+static void MixReverb_Normal(SLONG* srce,NATIVE count)\r
+{\r
+       NATIVE speedup;\r
+       int ReverbPct;\r
+       unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;\r
+\r
+       ReverbPct=58+(md_reverb*4);\r
+\r
+       COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+       COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+       while(count--) {\r
+               /* Compute the left channel echo buffers */\r
+               speedup = *srce >> 3;\r
+\r
+               COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
+               COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
+\r
+               /* Prepare to compute actual finalized data */\r
+               RVRindex++;\r
+\r
+               COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+               COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+               /* left channel */\r
+               *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+\r
+                         RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
+       }\r
+}\r
+\r
+static void MixReverb_Stereo(SLONG *srce,NATIVE count)\r
+{\r
+       NATIVE speedup;\r
+       int ReverbPct;\r
+       unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;\r
+\r
+       ReverbPct=58+(md_reverb*4);\r
+\r
+       COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+       COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+       while(count--) {\r
+               /* Compute the left channel echo buffers */\r
+               speedup = *srce >> 3;\r
+\r
+               COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
+               COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
+\r
+               /* Compute the right channel echo buffers */\r
+               speedup = srce[1] >> 3;\r
+\r
+               COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);\r
+               COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);\r
+\r
+               /* Prepare to compute actual finalized data */\r
+               RVRindex++;\r
+\r
+               COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
+               COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
+\r
+               /* left channel */\r
+               *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ \r
+                         RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
+\r
+               /* right channel */\r
+               *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+\r
+                         RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];\r
+       }\r
+}\r
+\r
+/* Mixing macros */\r
+#define EXTRACT_SAMPLE_FP(var,attenuation) var=*srce++*((1.0f / 32768.0f) / (MAXVOL_FACTOR*attenuation))\r
+#define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var\r
+\r
+static void Mix32ToFP_Normal(float* dste,SLONG* srce,NATIVE count)\r
+{\r
+       float x1,x2,tmpx;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx=0.0f;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);\r
+\r
+                       CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);\r
+\r
+                       tmpx+=x1+x2;\r
+               }\r
+               *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);\r
+       }\r
+}\r
+\r
+static void Mix32ToFP_Stereo(float* dste,SLONG* srce,NATIVE count)\r
+{\r
+       float x1,x2,x3,x4,tmpx,tmpy;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx=tmpy=0.0f;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);\r
+                       EXTRACT_SAMPLE_FP(x3,1.0f); EXTRACT_SAMPLE_FP(x4,1.0f);\r
+\r
+                       CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);\r
+                       CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f);\r
+\r
+                       tmpx+=x1+x3;\r
+                       tmpy+=x2+x4;\r
+               }\r
+               *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);\r
+               *dste++ =tmpy*(1.0f/SAMPLING_FACTOR);\r
+       }\r
+}\r
+\r
+/* Mixing macros */\r
+#define EXTRACT_SAMPLE(var,attenuation) var=*srce++/(MAXVOL_FACTOR*attenuation)\r
+#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var\r
+\r
+static void Mix32To16_Normal(SWORD* dste,SLONG* srce,NATIVE count)\r
+{\r
+       NATIVE x1,x2,tmpx;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx=0;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);\r
+\r
+                       CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);\r
+\r
+                       tmpx+=x1+x2;\r
+               }\r
+               *dste++ =tmpx/SAMPLING_FACTOR;\r
+       }\r
+}\r
+\r
+static void Mix32To16_Stereo(SWORD* dste,SLONG* srce,NATIVE count)\r
+{\r
+       NATIVE x1,x2,x3,x4,tmpx,tmpy;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx=tmpy=0;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);\r
+                       EXTRACT_SAMPLE(x3,1); EXTRACT_SAMPLE(x4,1);\r
+\r
+                       CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);\r
+                       CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);\r
+\r
+                       tmpx+=x1+x3;\r
+                       tmpy+=x2+x4;\r
+               }\r
+               *dste++ =tmpx/SAMPLING_FACTOR;\r
+               *dste++ =tmpy/SAMPLING_FACTOR;\r
+       }\r
+}\r
+\r
+static void Mix32To8_Normal(SBYTE* dste,SLONG* srce,NATIVE count)\r
+{\r
+       NATIVE x1,x2,tmpx;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx = 0;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);\r
+\r
+                       CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);\r
+\r
+                       tmpx+=x1+x2;\r
+               }\r
+               *dste++ =(tmpx/SAMPLING_FACTOR)+128;\r
+       }\r
+}\r
+\r
+static void Mix32To8_Stereo(SBYTE* dste,SLONG* srce,NATIVE count)\r
+{\r
+       NATIVE x1,x2,x3,x4,tmpx,tmpy;\r
+       int i;\r
+\r
+       for(count/=SAMPLING_FACTOR;count;count--) {\r
+               tmpx=tmpy=0;\r
+\r
+               for(i=SAMPLING_FACTOR/2;i;i--) {\r
+                       EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);\r
+                       EXTRACT_SAMPLE(x3,256); EXTRACT_SAMPLE(x4,256);\r
+\r
+                       CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);\r
+                       CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);\r
+\r
+                       tmpx+=x1+x3;\r
+                       tmpy+=x2+x4;\r
+               }\r
+               *dste++ =(tmpx/SAMPLING_FACTOR)+128;        \r
+               *dste++ =(tmpy/SAMPLING_FACTOR)+128;        \r
+       }\r
+}\r
+\r
+static void AddChannel(SLONG* ptr,NATIVE todo)\r
+{\r
+       SLONGLONG end,done;\r
+       SWORD *s;\r
+\r
+       if(!(s=Samples[vnf->handle])) {\r
+               vnf->current = vnf->active  = 0;\r
+               vnf->lastvalL = vnf->lastvalR = 0;\r
+               return;\r
+       }\r
+\r
+       /* update the 'current' index so the sample loops, or stops playing if it\r
+          reached the end of the sample */\r
+       while(todo>0) {\r
+               SLONGLONG endpos;\r
+\r
+               if(vnf->flags & SF_REVERSE) {\r
+                       /* The sample is playing in reverse */\r
+                       if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {\r
+                               /* the sample is looping and has reached the loopstart index */\r
+                               if(vnf->flags & SF_BIDI) {\r
+                                       /* sample is doing bidirectional loops, so 'bounce' the\r
+                                          current index against the idxlpos */\r
+                                       vnf->current = idxlpos+(idxlpos-vnf->current);\r
+                                       vnf->flags &= ~SF_REVERSE;\r
+                                       vnf->increment = -vnf->increment;\r
+                               } else\r
+                                       /* normal backwards looping, so set the current position to\r
+                                          loopend index */\r
+                                       vnf->current=idxlend-(idxlpos-vnf->current);\r
+                       } else {\r
+                               /* the sample is not looping, so check if it reached index 0 */\r
+                               if(vnf->current < 0) {\r
+                                       /* playing index reached 0, so stop playing this sample */\r
+                                       vnf->current = vnf->active  = 0;\r
+                                       break;\r
+                               }\r
+                       }\r
+               } else {\r
+                       /* The sample is playing forward */\r
+                       if((vnf->flags & SF_LOOP) &&\r
+                          (vnf->current >= idxlend)) {\r
+                               /* the sample is looping, check the loopend index */\r
+                               if(vnf->flags & SF_BIDI) {\r
+                                       /* sample is doing bidirectional loops, so 'bounce' the\r
+                                          current index against the idxlend */\r
+                                       vnf->flags |= SF_REVERSE;\r
+                                       vnf->increment = -vnf->increment;\r
+                                       vnf->current = idxlend-(vnf->current-idxlend);\r
+                               } else\r
+                                       /* normal backwards looping, so set the current position\r
+                                          to loopend index */\r
+                                       vnf->current=idxlpos+(vnf->current-idxlend);\r
+                       } else {\r
+                               /* sample is not looping, so check if it reached the last\r
+                                  position */\r
+                               if(vnf->current >= idxsize) {\r
+                                       /* yes, so stop playing this sample */\r
+                                       vnf->current = vnf->active  = 0;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:\r
+                    (vnf->flags&SF_LOOP)?idxlend:idxsize;\r
+\r
+               /* if the sample is not blocked... */\r
+               if((end==vnf->current)||(!vnf->increment))\r
+                       done=0;\r
+               else {\r
+                       done=MIN((end-vnf->current)/vnf->increment+1,todo);\r
+                       if(done<0) done=0;\r
+               }\r
+\r
+               if(!done) {\r
+                       vnf->active = 0;\r
+                       break;\r
+               }\r
+\r
+               endpos=vnf->current+done*vnf->increment;\r
+\r
+               if(vnf->vol || vnf->rampvol) {\r
+#ifndef NATIVE_64BIT_INT\r
+                       /* use the 32 bit mixers as often as we can (they're much faster) */\r
+                       if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {\r
+                               if(vc_mode & DMODE_STEREO) {\r
+                                       if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))\r
+                                               vnf->current=Mix32StereoSurround\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                                       else\r
+                                               vnf->current=Mix32StereoNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else\r
+                                       vnf->current=Mix32MonoNormal\r
+                                                          (s,ptr,vnf->current,vnf->increment,done);\r
+                       } else\r
+#endif\r
+                              {\r
+                               if(vc_mode & DMODE_STEREO) {\r
+                                       if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))\r
+                                               vnf->current=MixStereoSurround\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                                       else\r
+                                               vnf->current=MixStereoNormal\r
+                                                              (s,ptr,vnf->current,vnf->increment,done);\r
+                               } else\r
+                                       vnf->current=MixMonoNormal\r
+                                                          (s,ptr,vnf->current,vnf->increment,done);\r
+                       }\r
+               } else  {\r
+                       vnf->lastvalL = vnf->lastvalR = 0;\r
+                       /* update sample position */\r
+                       vnf->current=endpos;\r
+               }\r
+\r
+               todo -= done;\r
+               ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;\r
+       }\r
+}\r
+\r
+#define _IN_VIRTCH_\r
+\r
+#define VC1_SilenceBytes      VC2_SilenceBytes\r
+#define VC1_WriteSamples      VC2_WriteSamples\r
+#define VC1_WriteBytes        VC2_WriteBytes\r
+#define VC1_Exit              VC2_Exit\r
+#define VC1_VoiceSetVolume    VC2_VoiceSetVolume\r
+#define VC1_VoiceGetVolume    VC2_VoiceGetVolume\r
+#define VC1_VoiceSetPanning   VC2_VoiceSetPanning\r
+#define VC1_VoiceGetPanning   VC2_VoiceGetPanning\r
+#define VC1_VoiceSetFrequency VC2_VoiceSetFrequency\r
+#define VC1_VoiceGetFrequency VC2_VoiceGetFrequency\r
+#define VC1_VoicePlay         VC2_VoicePlay\r
+#define VC1_VoiceStop         VC2_VoiceStop\r
+#define VC1_VoiceStopped      VC2_VoiceStopped\r
+#define VC1_VoiceGetPosition  VC2_VoiceGetPosition\r
+#define VC1_SampleUnload      VC2_SampleUnload\r
+#define VC1_SampleLoad        VC2_SampleLoad\r
+#define VC1_SampleSpace       VC2_SampleSpace\r
+#define VC1_SampleLength      VC2_SampleLength\r
+#define VC1_VoiceRealVolume   VC2_VoiceRealVolume\r
+\r
+#include "virtch_common.c"\r
+#undef _IN_VIRTCH_\r
+\r
+void VC2_WriteSamples(SBYTE* buf,ULONG todo)\r
+{\r
+       int left,portion=0;\r
+       SBYTE *buffer;\r
+       int t,pan,vol;\r
+\r
+       todo*=SAMPLING_FACTOR;\r
+\r
+       while(todo) {\r
+               if(!tickleft) {\r
+                       if(vc_mode & DMODE_SOFT_MUSIC) md_player();\r
+                       tickleft=(md_mixfreq*125L*SAMPLING_FACTOR)/(md_bpm*50L);\r
+                       tickleft&=~(SAMPLING_FACTOR-1);\r
+               }\r
+               left = MIN(tickleft, todo);\r
+               buffer    = buf;\r
+               tickleft -= left;\r
+               todo     -= left;\r
+               buf += samples2bytes(left)/SAMPLING_FACTOR;\r
+\r
+               while(left) {\r
+                       portion = MIN(left, samplesthatfit);\r
+                       memset(vc_tickbuf,0,portion<<((vc_mode&DMODE_STEREO)?3:2));\r
+                       for(t=0;t<vc_softchn;t++) {\r
+                               vnf = &vinf[t];\r
+\r
+                               if(vnf->kick) {\r
+                                       vnf->current=((SLONGLONG)(vnf->start))<<FRACBITS;\r
+                                       vnf->kick    = 0;\r
+                                       vnf->active  = 1;\r
+                                       vnf->click   = CLICK_BUFFER;\r
+                                       vnf->rampvol = 0;\r
+                               }\r
+\r
+                               if(!vnf->frq) vnf->active = 0;\r
+\r
+                               if(vnf->active) {\r
+                                       vnf->increment=((SLONGLONG)(vnf->frq)<<(FRACBITS-SAMPLING_SHIFT))\r
+                                                      /md_mixfreq;\r
+                                       if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;\r
+                                       vol = vnf->vol;  pan = vnf->pan;\r
+\r
+                                       vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;\r
+                                       if(vc_mode & DMODE_STEREO) {\r
+                                               if(pan!=PAN_SURROUND) {\r
+                                                       vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;\r
+                                                       vnf->rvolsel=(vol*pan)>>8;\r
+                                               } else {\r
+                                                       vnf->lvolsel=vnf->rvolsel=(vol * 256L) / 480;\r
+                                               }\r
+                                       } else\r
+                                               vnf->lvolsel=vol;\r
+\r
+                                       idxsize=(vnf->size)?((SLONGLONG)(vnf->size)<<FRACBITS)-1:0;\r
+                                       idxlend=(vnf->repend)?((SLONGLONG)(vnf->repend)<<FRACBITS)-1:0;\r
+                                       idxlpos=(SLONGLONG)(vnf->reppos)<<FRACBITS;\r
+                                       AddChannel(vc_tickbuf,portion);\r
+                               }\r
+                       }\r
+\r
+                       if(md_reverb) {\r
+                               if(md_reverb>15) md_reverb=15;\r
+                               MixReverb(vc_tickbuf,portion);\r
+                       }\r
+\r
+                       if(vc_mode & DMODE_FLOAT)\r
+                               Mix32toFP((float*)buffer,vc_tickbuf,portion);\r
+                       else if(vc_mode & DMODE_16BITS)\r
+                               Mix32to16((SWORD*)buffer,vc_tickbuf,portion);\r
+                       else\r
+                               Mix32to8((SBYTE*)buffer,vc_tickbuf,portion);\r
+\r
+                       buffer += samples2bytes(portion) / SAMPLING_FACTOR;\r
+                       left   -= portion;\r
+               }\r
+       }\r
+}\r
+\r
+BOOL VC2_Init(void)\r
+{\r
+       VC_SetupPointers();\r
+       \r
+       if (!(md_mode&DMODE_HQMIXER))\r
+               return VC1_Init();\r
+       \r
+       if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {\r
+               _mm_errno = MMERR_INITIALIZING_MIXER;\r
+               return 1;\r
+       }\r
+       if(!vc_tickbuf)\r
+               if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {\r
+                       _mm_errno = MMERR_INITIALIZING_MIXER;\r
+                       return 1;\r
+               }\r
+\r
+       if(md_mode & DMODE_STEREO) {\r
+               Mix32toFP  = Mix32ToFP_Stereo;\r
+               Mix32to16  = Mix32To16_Stereo;\r
+               Mix32to8   = Mix32To8_Stereo;\r
+               MixReverb  = MixReverb_Stereo;\r
+       } else {\r
+               Mix32toFP  = Mix32ToFP_Normal;\r
+               Mix32to16  = Mix32To16_Normal;\r
+               Mix32to8   = Mix32To8_Normal;\r
+               MixReverb  = MixReverb_Normal;\r
+       }\r
+       md_mode |= DMODE_INTERP;\r
+       vc_mode = md_mode;\r
+       return 0;\r
+}\r
+\r
+BOOL VC2_PlayStart(void)\r
+{\r
+       md_mode|=DMODE_INTERP;\r
+\r
+       samplesthatfit = TICKLSIZE;\r
+       if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;\r
+       tickleft = 0;\r
+\r
+       RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc2 = (5078L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc3 = (5313L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc4 = (5703L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc5 = (6250L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc6 = (6953L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc7 = (7813L * md_mixfreq) / (REVERBERATION * 10);\r
+       RVc8 = (8828L * md_mixfreq) / (REVERBERATION * 10);\r
+\r
+       if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
+\r
+       if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
+       if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
+\r
+       RVRindex = 0;\r
+       return 0;\r
+}\r
+\r
+void VC2_PlayStop(void)\r
+{\r
+       if(RVbufL1) free(RVbufL1);\r
+       if(RVbufL2) free(RVbufL2);\r
+       if(RVbufL3) free(RVbufL3);\r
+       if(RVbufL4) free(RVbufL4);\r
+       if(RVbufL5) free(RVbufL5);\r
+       if(RVbufL6) free(RVbufL6);\r
+       if(RVbufL7) free(RVbufL7);\r
+       if(RVbufL8) free(RVbufL8);\r
+       if(RVbufR1) free(RVbufR1);\r
+       if(RVbufR2) free(RVbufR2);\r
+       if(RVbufR3) free(RVbufR3);\r
+       if(RVbufR4) free(RVbufR4);\r
+       if(RVbufR5) free(RVbufR5);\r
+       if(RVbufR6) free(RVbufR6);\r
+       if(RVbufR7) free(RVbufR7);\r
+       if(RVbufR8) free(RVbufR8);\r
+\r
+       RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;\r
+       RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;\r
+}\r
+\r
+BOOL VC2_SetNumVoices(void)\r
+{\r
+       int t;\r
+\r
+       md_mode|=DMODE_INTERP;\r
+\r
+       if(!(vc_softchn=md_softchn)) return 0;\r
+\r
+       if(vinf) free(vinf);\r
+       if(!(vinf=_mm_calloc(sizeof(VINFO),vc_softchn))) return 1;\r
+\r
+       for(t=0;t<vc_softchn;t++) {\r
+               vinf[t].frq=10000;\r
+               vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+/* ex:set ts=4: */\r
diff --git a/apps/plugins/mikmod/playercode/virtch_common.c b/apps/plugins/mikmod/playercode/virtch_common.c
new file mode 100644 (file)
index 0000000..2483386
--- /dev/null
@@ -0,0 +1,461 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       for complete list.\r
+\r
+       This library is free software; you can redistribute it and/or modify\r
+       it under the terms of the GNU Library General Public License as\r
+       published by the Free Software Foundation; either version 2 of\r
+       the License, or (at your option) any later version.\r
\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU Library General Public License for more details.\r
\r
+       You should have received a copy of the GNU Library General Public\r
+       License along with this library; if not, write to the Free Software\r
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+       02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+  $Id: virtch_common.c,v 1.2 2004/02/13 13:31:54 raph Exp $\r
+\r
+  Common source parts between the two software mixers.\r
+  This file is probably the ugliest part of libmikmod...\r
+\r
+==============================================================================*/\r
+\r
+#ifndef _IN_VIRTCH_\r
+\r
+#include "mikmod_internals.h"\r
+\r
+extern BOOL  VC1_Init(void);\r
+extern BOOL  VC2_Init(void);\r
+static BOOL (*VC_Init_ptr)(void)=VC1_Init;\r
+extern void  VC1_Exit(void);\r
+extern void  VC2_Exit(void);\r
+static void (*VC_Exit_ptr)(void)=VC1_Exit;\r
+extern BOOL  VC1_SetNumVoices(void);\r
+extern BOOL  VC2_SetNumVoices(void);\r
+static BOOL (*VC_SetNumVoices_ptr)(void);\r
+extern ULONG VC1_SampleSpace(int);\r
+extern ULONG VC2_SampleSpace(int);\r
+static ULONG (*VC_SampleSpace_ptr)(int);\r
+extern ULONG VC1_SampleLength(int,SAMPLE*);\r
+extern ULONG VC2_SampleLength(int,SAMPLE*);\r
+static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);\r
+\r
+extern BOOL  VC1_PlayStart(void);\r
+extern BOOL  VC2_PlayStart(void);\r
+static BOOL (*VC_PlayStart_ptr)(void);\r
+extern void  VC1_PlayStop(void);\r
+extern void  VC2_PlayStop(void);\r
+static void (*VC_PlayStop_ptr)(void);\r
+\r
+extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);\r
+extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);\r
+static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);\r
+extern void  VC1_SampleUnload(SWORD);\r
+extern void  VC2_SampleUnload(SWORD);\r
+static void (*VC_SampleUnload_ptr)(SWORD);\r
+\r
+extern ULONG VC1_WriteBytes(SBYTE*,ULONG);\r
+extern ULONG VC2_WriteBytes(SBYTE*,ULONG);\r
+static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);\r
+extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);\r
+extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);\r
+static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);\r
+\r
+extern void  VC1_VoiceSetVolume(UBYTE,UWORD);\r
+extern void  VC2_VoiceSetVolume(UBYTE,UWORD);\r
+static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);\r
+extern UWORD VC1_VoiceGetVolume(UBYTE);\r
+extern UWORD VC2_VoiceGetVolume(UBYTE);\r
+static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);\r
+extern void  VC1_VoiceSetFrequency(UBYTE,ULONG);\r
+extern void  VC2_VoiceSetFrequency(UBYTE,ULONG);\r
+static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);\r
+extern ULONG VC1_VoiceGetFrequency(UBYTE);\r
+extern ULONG VC2_VoiceGetFrequency(UBYTE);\r
+static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);\r
+extern void  VC1_VoiceSetPanning(UBYTE,ULONG);\r
+extern void  VC2_VoiceSetPanning(UBYTE,ULONG);\r
+static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);\r
+extern ULONG VC1_VoiceGetPanning(UBYTE);\r
+extern ULONG VC2_VoiceGetPanning(UBYTE);\r
+static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);\r
+extern void  VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+extern void  VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+\r
+extern void  VC1_VoiceStop(UBYTE);\r
+extern void  VC2_VoiceStop(UBYTE);\r
+static void (*VC_VoiceStop_ptr)(UBYTE);\r
+extern BOOL  VC1_VoiceStopped(UBYTE);\r
+extern BOOL  VC2_VoiceStopped(UBYTE);\r
+static BOOL (*VC_VoiceStopped_ptr)(UBYTE);\r
+extern SLONG VC1_VoiceGetPosition(UBYTE);\r
+extern SLONG VC2_VoiceGetPosition(UBYTE);\r
+static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);\r
+extern ULONG VC1_VoiceRealVolume(UBYTE);\r
+extern ULONG VC2_VoiceRealVolume(UBYTE);\r
+static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);\r
+\r
+#if defined __STDC__ || defined _MSC_VER\r
+#define VC_PROC0(suffix) \\r
+MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }\r
+\r
+#define VC_FUNC0(suffix,ret) \\r
+MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }\r
+\r
+#define VC_PROC1(suffix,typ1) \\r
+MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }\r
+\r
+#define VC_FUNC1(suffix,ret,typ1) \\r
+MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }\r
+\r
+#define VC_PROC2(suffix,typ1,typ2) \\r
+MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }\r
+\r
+#define VC_FUNC2(suffix,ret,typ1,typ2) \\r
+MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }\r
+#else\r
+#define VC_PROC0(suffix) \\r
+MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }\r
+\r
+#define VC_FUNC0(suffix,ret) \\r
+MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }\r
+\r
+#define VC_PROC1(suffix,typ1) \\r
+MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }\r
+\r
+#define VC_FUNC1(suffix,ret,typ1) \\r
+MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }\r
+\r
+#define VC_PROC2(suffix,typ1,typ2) \\r
+MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }\r
+\r
+#define VC_FUNC2(suffix,ret,typ1,typ2) \\r
+MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }\r
+#endif\r
+\r
+VC_FUNC0(Init,BOOL)\r
+VC_PROC0(Exit)\r
+VC_FUNC0(SetNumVoices,BOOL)\r
+VC_FUNC1(SampleSpace,ULONG,int)\r
+VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)\r
+VC_FUNC0(PlayStart,BOOL)\r
+VC_PROC0(PlayStop)\r
+VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)\r
+VC_PROC1(SampleUnload,SWORD)\r
+VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)\r
+VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)\r
+VC_PROC2(VoiceSetVolume,UBYTE,UWORD)\r
+VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)\r
+VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)\r
+VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)\r
+VC_PROC2(VoiceSetPanning,UBYTE,ULONG)\r
+VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)\r
+               \r
+void  VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g)\r
+{ VC_VoicePlay_ptr(a,b,c,d,e,f,g); }\r
+\r
+VC_PROC1(VoiceStop,UBYTE)\r
+VC_FUNC1(VoiceStopped,BOOL,UBYTE)\r
+VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)\r
+VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)\r
+               \r
+void VC_SetupPointers(void)\r
+{\r
+       if (md_mode&DMODE_HQMIXER) {\r
+               VC_Init_ptr=VC2_Init;\r
+               VC_Exit_ptr=VC2_Exit;\r
+               VC_SetNumVoices_ptr=VC2_SetNumVoices;\r
+               VC_SampleSpace_ptr=VC2_SampleSpace;\r
+               VC_SampleLength_ptr=VC2_SampleLength;\r
+               VC_PlayStart_ptr=VC2_PlayStart;\r
+               VC_PlayStop_ptr=VC2_PlayStop;\r
+               VC_SampleLoad_ptr=VC2_SampleLoad;\r
+               VC_SampleUnload_ptr=VC2_SampleUnload;\r
+               VC_WriteBytes_ptr=VC2_WriteBytes;\r
+               VC_SilenceBytes_ptr=VC2_SilenceBytes;\r
+               VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;\r
+               VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;\r
+               VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;\r
+               VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;\r
+               VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;\r
+               VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;\r
+               VC_VoicePlay_ptr=VC2_VoicePlay;\r
+               VC_VoiceStop_ptr=VC2_VoiceStop;\r
+               VC_VoiceStopped_ptr=VC2_VoiceStopped;\r
+               VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;\r
+               VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;\r
+       } else {\r
+               VC_Init_ptr=VC1_Init;\r
+               VC_Exit_ptr=VC1_Exit;\r
+               VC_SetNumVoices_ptr=VC1_SetNumVoices;\r
+               VC_SampleSpace_ptr=VC1_SampleSpace;\r
+               VC_SampleLength_ptr=VC1_SampleLength;\r
+               VC_PlayStart_ptr=VC1_PlayStart;\r
+               VC_PlayStop_ptr=VC1_PlayStop;\r
+               VC_SampleLoad_ptr=VC1_SampleLoad;\r
+               VC_SampleUnload_ptr=VC1_SampleUnload;\r
+               VC_WriteBytes_ptr=VC1_WriteBytes;\r
+               VC_SilenceBytes_ptr=VC1_SilenceBytes;\r
+               VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;\r
+               VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;\r
+               VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;\r
+               VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;\r
+               VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;\r
+               VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;\r
+               VC_VoicePlay_ptr=VC1_VoicePlay;\r
+               VC_VoiceStop_ptr=VC1_VoiceStop;\r
+               VC_VoiceStopped_ptr=VC1_VoiceStopped;\r
+               VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;\r
+               VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;\r
+       }\r
+}\r
+\r
+#else\r
+\r
+#ifndef _VIRTCH_COMMON_\r
+#define _VIRTCH_COMMON_\r
+\r
+static ULONG samples2bytes(ULONG samples)\r
+{\r
+       if(vc_mode & DMODE_FLOAT) samples <<= 2;\r
+       else if(vc_mode & DMODE_16BITS) samples <<= 1;\r
+       if(vc_mode & DMODE_STEREO) samples <<= 1;\r
+       return samples;\r
+}\r
+\r
+static ULONG bytes2samples(ULONG bytes)\r
+{\r
+       if(vc_mode & DMODE_FLOAT) bytes >>= 2;\r
+       else if(vc_mode & DMODE_16BITS) bytes >>= 1;\r
+       if(vc_mode & DMODE_STEREO) bytes >>= 1;\r
+       return bytes;\r
+}\r
+\r
+/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode\r
+   how the buffer is filled) */\r
+ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)\r
+{\r
+       todo=samples2bytes(bytes2samples(todo));\r
+\r
+       /* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */\r
+       if(vc_mode & DMODE_FLOAT)\r
+               memset(buf,0,todo);\r
+       else if(vc_mode & DMODE_16BITS)\r
+               memset(buf,0,todo);\r
+       else\r
+               memset(buf,0x80,todo);\r
+\r
+       return todo;\r
+}\r
+\r
+void VC1_WriteSamples(SBYTE*,ULONG);\r
+\r
+/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES\r
+   actually written to 'buf' (which is rounded to number of samples that fit\r
+   into 'todo' bytes). */\r
+ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)\r
+{\r
+       if(!vc_softchn)\r
+               return VC1_SilenceBytes(buf,todo);\r
+\r
+       todo = bytes2samples(todo);\r
+       VC1_WriteSamples(buf,todo);\r
+\r
+       return samples2bytes(todo);\r
+}\r
+\r
+void VC1_Exit(void)\r
+{\r
+       if(vc_tickbuf) free(vc_tickbuf);\r
+       if(vinf) free(vinf);\r
+       if(Samples) free(Samples);\r
+\r
+       vc_tickbuf = NULL;\r
+       vinf = NULL;\r
+       Samples = NULL;\r
+       \r
+       VC_SetupPointers();\r
+}\r
+\r
+UWORD VC1_VoiceGetVolume(UBYTE voice)\r
+{\r
+       return vinf[voice].vol;\r
+}\r
+\r
+ULONG VC1_VoiceGetPanning(UBYTE voice)\r
+{\r
+       return vinf[voice].pan;\r
+}\r
+\r
+void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)\r
+{\r
+       vinf[voice].frq=frq;\r
+}\r
+\r
+ULONG VC1_VoiceGetFrequency(UBYTE voice)\r
+{\r
+       return vinf[voice].frq;\r
+}\r
+\r
+void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+       vinf[voice].flags    = flags;\r
+       vinf[voice].handle   = handle;\r
+       vinf[voice].start    = start;\r
+       vinf[voice].size     = size;\r
+       vinf[voice].reppos   = reppos;\r
+       vinf[voice].repend   = repend;\r
+       vinf[voice].kick     = 1;\r
+}\r
+\r
+void VC1_VoiceStop(UBYTE voice)\r
+{\r
+       vinf[voice].active = 0;\r
+}  \r
+\r
+BOOL VC1_VoiceStopped(UBYTE voice)\r
+{\r
+       return(vinf[voice].active==0);\r
+}\r
+\r
+SLONG VC1_VoiceGetPosition(UBYTE voice)\r
+{\r
+       return(vinf[voice].current>>FRACBITS);\r
+}\r
+\r
+void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)\r
+{    \r
+       /* protect against clicks if volume variation is too high */\r
+       if(abs((int)vinf[voice].vol-(int)vol)>32)\r
+               vinf[voice].rampvol=CLICK_BUFFER;\r
+       vinf[voice].vol=vol;\r
+}\r
+\r
+void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)\r
+{\r
+       /* protect against clicks if panning variation is too high */\r
+       if(abs((int)vinf[voice].pan-(int)pan)>48)\r
+               vinf[voice].rampvol=CLICK_BUFFER;\r
+       vinf[voice].pan=pan;\r
+}\r
+\r
+/*========== External mixer interface */\r
+\r
+void VC1_SampleUnload(SWORD handle)\r
+{\r
+       if (handle<MAXSAMPLEHANDLES) {\r
+               if (Samples[handle])\r
+                       free(Samples[handle]);\r
+               Samples[handle]=NULL;\r
+       }\r
+}\r
+\r
+SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)\r
+{\r
+       SAMPLE *s = sload->sample;\r
+       int handle;\r
+       ULONG t, length,loopstart,loopend;\r
+\r
+       if(type==MD_HARDWARE) return -1;\r
+\r
+       /* Find empty slot to put sample address in */\r
+       for(handle=0;handle<MAXSAMPLEHANDLES;handle++)\r
+               if(!Samples[handle]) break;\r
+\r
+       if(handle==MAXSAMPLEHANDLES) {\r
+               _mm_errno = MMERR_OUT_OF_HANDLES;\r
+               return -1;\r
+       }\r
+       \r
+       /* Reality check for loop settings */\r
+       if (s->loopend > s->length)\r
+               s->loopend = s->length;\r
+       if (s->loopstart >= s->loopend)\r
+               s->flags &= ~SF_LOOP;\r
+\r
+       length    = s->length;\r
+       loopstart = s->loopstart;\r
+       loopend   = s->loopend;\r
+\r
+       SL_SampleSigned(sload);\r
+       SL_Sample8to16(sload);\r
+\r
+       if(!(Samples[handle]=(SWORD*)_mm_malloc((length+20)<<1))) {\r
+               _mm_errno = MMERR_SAMPLE_TOO_BIG;\r
+               return -1;\r
+       }\r
+\r
+       /* read sample into buffer */\r
+       if (SL_Load(Samples[handle],sload,length))\r
+               return -1;\r
+\r
+       /* Unclick sample */\r
+       if(s->flags & SF_LOOP) {\r
+               if(s->flags & SF_BIDI)\r
+                       for(t=0;t<16;t++)\r
+                               Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];\r
+               else\r
+                       for(t=0;t<16;t++)\r
+                               Samples[handle][loopend+t]=Samples[handle][t+loopstart];\r
+       } else\r
+               for(t=0;t<16;t++)\r
+                       Samples[handle][t+length]=0;\r
+\r
+       return handle;\r
+}\r
+\r
+ULONG VC1_SampleSpace(int type)\r
+{\r
+       (void)type;\r
+       return vc_memory;\r
+}\r
+\r
+ULONG VC1_SampleLength(int type,SAMPLE* s)\r
+{\r
+       (void)type;\r
+       if (!s) return 0;\r
+\r
+       return (s->length*((s->flags&SF_16BITS)?2:1))+16;\r
+}\r
+\r
+ULONG VC1_VoiceRealVolume(UBYTE voice)\r
+{\r
+       ULONG i,s,size;\r
+       int k,j;\r
+       SWORD *smp;\r
+       SLONG t;\r
+\r
+       t = vinf[voice].current>>FRACBITS;\r
+       if(!vinf[voice].active) return 0;\r
+\r
+       s = vinf[voice].handle;\r
+       size = vinf[voice].size;\r
+\r
+       i=64; t-=64; k=0; j=0;\r
+       if(i>size) i = size;\r
+       if(t<0) t = 0;\r
+       if(t+i > size) t = size-i;\r
+\r
+       i &= ~1;  /* make sure it's EVEN. */\r
+\r
+       smp = &Samples[s][t];\r
+       for(;i;i--,smp++) {\r
+               if(k<*smp) k = *smp;\r
+               if(j>*smp) j = *smp;\r
+       }\r
+       return abs(k-j);\r
+}\r
+\r
+#endif\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r