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.
--- /dev/null
+# __________ __ ___.\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
--- /dev/null
+@echo off\r
+\r
+C:\r
+chdir C:\cygwin\bin\r
+\r
+bash --login -i\r
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/***************************************************************************\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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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