added an old version of mikmod for dos
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 19 Sep 2016 23:42:10 +0000 (02:42 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 19 Sep 2016 23:42:10 +0000 (02:42 +0300)
58 files changed:
Makefile
libs/mikmod/Makefile [new file with mode: 0644]
libs/mikmod/drivers/dos/dosdma.c [deleted file]
libs/mikmod/drivers/dos/dosdma.h [deleted file]
libs/mikmod/drivers/dos/dosgus.c [deleted file]
libs/mikmod/drivers/dos/dosgus.h [deleted file]
libs/mikmod/drivers/dos/dosirq.c [deleted file]
libs/mikmod/drivers/dos/dosirq.h [deleted file]
libs/mikmod/drivers/dos/dossb.c [deleted file]
libs/mikmod/drivers/dos/dossb.h [deleted file]
libs/mikmod/drivers/dos/doswss.c [deleted file]
libs/mikmod/drivers/dos/doswss.h [deleted file]
libs/mikmod/drivers/dos/libgus.h [deleted file]
libs/mikmod/drvdos/dosdma.c [new file with mode: 0644]
libs/mikmod/drvdos/dosdma.h [new file with mode: 0644]
libs/mikmod/drvdos/dosgus.c [new file with mode: 0644]
libs/mikmod/drvdos/dosgus.h [new file with mode: 0644]
libs/mikmod/drvdos/dosirq.c [new file with mode: 0644]
libs/mikmod/drvdos/dosirq.h [new file with mode: 0644]
libs/mikmod/drvdos/dossb.c [new file with mode: 0644]
libs/mikmod/drvdos/dossb.h [new file with mode: 0644]
libs/mikmod/drvdos/doswss.c [new file with mode: 0644]
libs/mikmod/drvdos/doswss.h [new file with mode: 0644]
libs/mikmod/drvdos/libgus.h [new file with mode: 0644]
libs/oldmik/Makefile [new file with mode: 0644]
libs/oldmik/credits.txt [new file with mode: 0644]
libs/oldmik/src/drv_gus.c [new file with mode: 0644]
libs/oldmik/src/drv_nos.c [new file with mode: 0644]
libs/oldmik/src/drv_raw.c [new file with mode: 0644]
libs/oldmik/src/drv_sb.c [new file with mode: 0644]
libs/oldmik/src/drv_ss.c [new file with mode: 0644]
libs/oldmik/src/load_m15.c [new file with mode: 0644]
libs/oldmik/src/load_mod.c [new file with mode: 0644]
libs/oldmik/src/load_mtm.c [new file with mode: 0644]
libs/oldmik/src/load_s3m.c [new file with mode: 0644]
libs/oldmik/src/load_stm.c [new file with mode: 0644]
libs/oldmik/src/load_ult.c [new file with mode: 0644]
libs/oldmik/src/load_uni.c [new file with mode: 0644]
libs/oldmik/src/load_xm.c [new file with mode: 0644]
libs/oldmik/src/mdma.c [new file with mode: 0644]
libs/oldmik/src/mdma.h [new file with mode: 0644]
libs/oldmik/src/mdriver.c [new file with mode: 0644]
libs/oldmik/src/mikmod.h [new file with mode: 0644]
libs/oldmik/src/mirq.c [new file with mode: 0644]
libs/oldmik/src/mirq.h [new file with mode: 0644]
libs/oldmik/src/mloader.c [new file with mode: 0644]
libs/oldmik/src/mmio.c [new file with mode: 0644]
libs/oldmik/src/mplayer.c [new file with mode: 0644]
libs/oldmik/src/mtypes.h [new file with mode: 0644]
libs/oldmik/src/munitrk.c [new file with mode: 0644]
libs/oldmik/src/resample.asm [new file with mode: 0644]
libs/oldmik/src/virtch.c [new file with mode: 0644]
mklibs.bat
src/demo.c
src/dos/music.c [new file with mode: 0644]
src/music.c [deleted file]
src/music.h
src/sdl/music.c [new file with mode: 0644]

index 810d2ca..6e73142 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,22 @@
 baseobj = main.obj
-demoobj = demo.obj screen.obj gfxutil.obj 3dgfx.obj polyfill.obj
+demoobj = demo.obj screen.obj music.obj gfxutil.obj 3dgfx.obj polyfill.obj
 scrobj = tunnel.obj fract.obj grise.obj polytest.obj plasma.obj
 sysobj = gfx.obj vbe.obj dpmi.obj timer.obj keyb.obj mouse.obj logger.obj tinyfps.obj
 obj = $(baseobj) $(demoobj) $(sysobj) $(scrobj)
 bin = demo.exe
 
-libs = imago.lib
+libs = imago.lib mikmod.lib
 
 def = -dM_PI=3.141592653589793
 opt = -5 -fp5 -otexan -oh -oi -ei
 dbg = -d1
 
 !ifdef __UNIX__
-incpath = -Isrc -Isrc/dos -Ilibs/imago/src
-libpath = libs/imago
+incpath = -Isrc -Isrc/dos -Ilibs/imago/src -Ilibs/oldmik/src
+libpath = libpath libs/imago libpath libs/oldmik
 !else
-incpath = -Isrc -Isrc\dos -Ilibs\imago\src
-libpath = libs\imago
+incpath = -Isrc -Isrc\dos -Ilibs\imago\src -Ilibs\oldmik\src
+libpath = libpath libs\imago libpath libs\oldmik
 !endif
 
 AS = nasm
@@ -25,12 +25,13 @@ CXX = wpp386
 ASFLAGS = -fobj
 CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)
 CXXFLAGS = $(CFLAGS)
-LDFLAGS = libpath $(libpath) library { $(libs) }
+LDFLAGS = $(libpath) library { $(libs) }
 LD = wlink
 
 $(bin): cflags.occ $(obj) libs/imago/imago.lib
        %write objects.lnk $(obj)
-       $(LD) debug all name $@ system dos4g file { @objects } $(LDFLAGS)
+       %write ldflags.lnk $(LDFLAGS)
+       $(LD) debug all name $@ system dos4g file { @objects } @ldflags
 
 .c: src;src/dos
 .cc: src;src/dos
diff --git a/libs/mikmod/Makefile b/libs/mikmod/Makefile
new file mode 100644 (file)
index 0000000..dd93135
--- /dev/null
@@ -0,0 +1,37 @@
+odrivers = drv_oss.obj drv_wss.obj drv_ultra.obj drv_sb.obj drv_sdl.obj drv_nos.obj &
+dossb.obj dosirq.obj dosgus.obj dosdma.obj doswss.obj
+oloaders = load_s3m.obj load_mod.obj load_it.obj load_xm.obj
+ommio = mmalloc.obj mmerror.obj mmio.obj
+odepackers = mmcmp.obj pp20.obj s404.obj xpk.obj
+oposix = memcmp.obj strcasecmp.obj strstr.obj
+oplayercode = mdreg.obj mlreg.obj mloader.obj virtch_common.obj munitrk.obj mplayer.obj &
+mlutil.obj sloader.obj npertab.obj virtch.obj mdulaw.obj mwav.obj virtch2.obj mdriver.obj
+
+obj = $(odrivers) $(oloaders) $(ommio) $(odepackers) $(oposix) $(oplayercode)
+
+alib = mikmod.lib
+
+opt = -5 -fp5 -otexan -zu
+dbg = -d1
+def = -DHAVE_CONFIG_H -DMIKMOD_BUILD
+
+CC = wcc386
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -I. -Iinclude -Idrvdos
+
+$(alib): cflags.occ $(obj)
+       %write objects.lbc $(obj)
+       wlib -b -n $@ @objects
+
+.c: drivers;drvdos;loaders;mmio;depackers;posix;playercode
+
+cflags.occ: Makefile
+       %write $@ $(CFLAGS)
+
+.c.obj: .autodepend
+       $(CC) -fo=$@ @cflags.occ $[*
+
+clean: .symbolic
+       del *.obj
+       del *.occ
+       del *.lbc
+       del $(alib)
diff --git a/libs/mikmod/drivers/dos/dosdma.c b/libs/mikmod/drivers/dos/dosdma.c
deleted file mode 100644 (file)
index e232c30..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-    Implementation of DMA routines on DOS
-    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "dosdma.h"
-
-#include <go32.h> /* includes sys/version.h (djgpp >= 2.02) */
-#include <dos.h>
-#include <dpmi.h>
-#include <sys/nearptr.h>
-#include <malloc.h>
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-/* BUG WARNING:  there is an error in DJGPP libraries <= 2.01:
- * src/libc/dpmi/api/d0102.s loads the selector and allocsize
- * arguments in the wrong order.  DJGPP >= 2.02 have it fixed. */
-#if (!defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__+0) < 2)
-#warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken!
-#endif
-
-__dma_regs dma[8] = {
-/* *INDENT-OFF* */
-       {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
-        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-       {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
-        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-
-       {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
-        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-       {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
-        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-
-       {DMA_ADDR_4,          0, DMA_SIZE_4,
-        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
-       {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
-        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
-
-       {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
-        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
-       {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
-        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
-/* *INDENT-ON* */
-};
-
-static int __initialized = 0;
-static int __buffer_count = 0;
-static __dpmi_meminfo __locked_data;
-
-int dma_initialize()
-{
-       if (!__djgpp_nearptr_enable())
-               return 0;
-
-       /* Trick: Avoid re-setting DS selector limit on each memory allocation
-          call */
-       __djgpp_selector_limit = 0xffffffff;
-
-       __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
-       __locked_data.size = sizeof(dma);
-       if (__dpmi_lock_linear_region(&__locked_data))
-               return 0;
-
-       return (__initialized = 1);
-}
-
-void dma_finalize()
-{
-       if (!__initialized)
-               return;
-       __dpmi_unlock_linear_region(&__locked_data);
-       __djgpp_nearptr_disable();
-}
-
-dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
-{
-       int parsize = (size + 15) >> 4; /* size in paragraphs */
-       int par = 0;                            /* Real-mode paragraph */
-       int selector = 0;                       /* Protected-mode selector */
-       int mask = channel <= 3 ? 0xfff : 0x1fff;       /* Alignment mask in para. */
-       int allocsize = parsize;        /* Allocated size in paragraphs */
-       int count;                                      /* Try count */
-       int bound = 0;                          /* Nearest bound address */
-       int maxsize;                            /* Maximal possible block size */
-       dma_buffer *buffer = NULL;
-       __dpmi_meminfo buff_info, struct_info;
-
-       if (!dma_initialize())
-               return NULL;
-
-       /* Loop until we'll get a properly aligned memory block */
-       for (count = 8; count; count--) {
-               int resize = (selector != 0);
-
-               /* Try first to resize (possibly previously) allocated block */
-               if (resize) {
-                       maxsize = (bound + parsize) - par;
-                       if (maxsize > parsize * 2)
-                               maxsize = parsize * 2;
-                       if (maxsize == allocsize)
-                               resize = 0;
-                       else {
-                               allocsize = maxsize;
-                               if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) !=
-                                       0) resize = 0;
-                       }
-               }
-
-               if (!resize) {
-                       if (selector)
-                               __dpmi_free_dos_memory(selector), selector = 0;
-                       par = __dpmi_allocate_dos_memory(allocsize, &selector);
-               }
-
-               if ((par == 0) || (par == -1))
-                       goto exit;
-
-               /* If memory block contains a properly aligned portion, quit loop */
-               bound = (par + mask + 1) & ~mask;
-               if (par + parsize <= bound)
-                       break;
-               if (bound + parsize <= par + allocsize) {
-                       par = bound;
-                       break;
-               }
-       }
-       if (!count) {
-               __dpmi_free_dos_memory(selector);
-               goto exit;
-       }
-
-       buffer = (dma_buffer *) MikMod_malloc(sizeof(dma_buffer));
-       buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16);
-       buffer->physical = bound * 16;
-       buffer->size = parsize * 16;
-       buffer->selector = selector;
-       buffer->channel = channel;
-
-       buff_info.address = buffer->physical;
-       buff_info.size = buffer->size;
-       /*
-          Don't pay attention to return code since under plain DOS it often
-          returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
-        */
-       __dpmi_lock_linear_region(&buff_info);
-
-       /* Lock the DMA buffer control structure as well */
-       struct_info.address = __djgpp_base_address + (unsigned long)buffer;
-       struct_info.size = sizeof(dma_buffer);
-       if (__dpmi_lock_linear_region(&struct_info)) {
-               __dpmi_unlock_linear_region(&buff_info);
-               __dpmi_free_dos_memory(selector);
-               MikMod_free(buffer);
-               buffer = NULL;
-               goto exit;
-       }
-
-  exit:
-       if (buffer)
-               __buffer_count++;
-       else if (--__buffer_count == 0)
-               dma_finalize();
-       return buffer;
-}
-
-void dma_free(dma_buffer * buffer)
-{
-       __dpmi_meminfo buff_info;
-
-       if (!buffer)
-               return;
-
-       buff_info.address = buffer->physical;
-       buff_info.size = buffer->size;
-       __dpmi_unlock_linear_region(&buff_info);
-
-       __dpmi_free_dos_memory(buffer->selector);
-       MikMod_free(buffer);
-
-       if (--__buffer_count == 0)
-               dma_finalize();
-}
-
-void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
-{
-       /* Disable interrupts */
-       int old_ints = disable();
-       dma_disable(buffer->channel);
-       dma_set_mode(buffer->channel, mode);
-       dma_clear_ff(buffer->channel);
-       dma_set_addr(buffer->channel, buffer->physical);
-       dma_clear_ff(buffer->channel);
-       dma_set_count(buffer->channel, count);
-       dma_enable(buffer->channel);
-       /* Re-enable interrupts */
-       if (old_ints)
-               enable();
-}
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosdma.h b/libs/mikmod/drivers/dos/dosdma.h
deleted file mode 100644 (file)
index 882c9ac..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-    Interface for DMA routines on DOS
-    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __DOSDMA_H__
-#define __DOSDMA_H__
-
-#include <pc.h>
-
-#define DMA1_BASE              0x00    /* 8 bit slave DMA, channels 0..3 */
-#define DMA2_BASE              0xC0    /* 16 bit master DMA, ch 4(=slave input)..7 */
-
-#define DMA1_CMD_REG           0x08    /* command register (w) */
-#define DMA1_STAT_REG          0x08    /* status register (r) */
-#define DMA1_REQ_REG           0x09    /* request register (w) */
-#define DMA1_MASK_REG          0x0A    /* single-channel mask (w) */
-#define DMA1_MODE_REG          0x0B    /* mode register (w) */
-#define DMA1_CLEAR_FF_REG      0x0C    /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG          0x0D    /* Temporary Register (r) */
-#define DMA1_RESET_REG         0x0D    /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG      0x0E    /* Clear Mask */
-#define DMA1_MASK_ALL_REG      0x0F    /* all-channels mask (w) */
-
-#define DMA2_CMD_REG           0xD0    /* command register (w) */
-#define DMA2_STAT_REG          0xD0    /* status register (r) */
-#define DMA2_REQ_REG           0xD2    /* request register (w) */
-#define DMA2_MASK_REG          0xD4    /* single-channel mask (w) */
-#define DMA2_MODE_REG          0xD6    /* mode register (w) */
-#define DMA2_CLEAR_FF_REG      0xD8    /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG          0xDA    /* Temporary Register (r) */
-#define DMA2_RESET_REG         0xDA    /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG      0xDC    /* Clear Mask */
-#define DMA2_MASK_ALL_REG      0xDE    /* all-channels mask (w) */
-
-#define DMA_ADDR_0      0x00   /* DMA address registers */
-#define DMA_ADDR_1      0x02
-#define DMA_ADDR_2      0x04
-#define DMA_ADDR_3      0x06
-#define DMA_ADDR_4      0xC0
-#define DMA_ADDR_5      0xC4
-#define DMA_ADDR_6      0xC8
-#define DMA_ADDR_7      0xCC
-
-#define DMA_SIZE_0             0x01    /* DMA transfer size registers */
-#define DMA_SIZE_1             0x03
-#define DMA_SIZE_2             0x05
-#define DMA_SIZE_3             0x07
-#define DMA_SIZE_4             0xC2
-#define DMA_SIZE_5             0xC6
-#define DMA_SIZE_6             0xCA
-#define DMA_SIZE_7             0xCE
-
-#define DMA_PAGE_0      0x87   /* DMA page registers */
-#define DMA_PAGE_1      0x83
-#define DMA_PAGE_2      0x81
-#define DMA_PAGE_3      0x82
-#define DMA_PAGE_5      0x8B
-#define DMA_PAGE_6      0x89
-#define DMA_PAGE_7      0x8A
-
-#define DMA_MODE_AUTOINIT      0x10    /* Auto-init mode bit */
-#define DMA_MODE_READ          0x44    /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE         0x48    /* memory to I/O, no autoinit, increment, single mode */
-#define DMA_MODE_CASCADE       0xC0    /* pass thru DREQ->HRQ, DACK<-HLDA only */
-
-/* Indexable specific DMA registers */
-typedef struct __dma_regs_s {
-       unsigned char addr;                     /* DMA transfer address register */
-       unsigned char page;                     /* DMA page register */
-       unsigned char size;                     /* DMA transfer size register */
-       unsigned char mask;                     /* DMA mask/unmask register */
-       unsigned char flip;                     /* DMA flip-flop reset register */
-       unsigned char mode;                     /* DMA mode register */
-} __dma_regs;
-
-extern __dma_regs dma[8];
-
-/* Enable a specific DMA channel */
-static inline void dma_enable(unsigned int channel)
-{
-       outportb(dma[channel].mask, channel & 3);
-}
-
-/* Disable a specific DMA channel */
-static inline void dma_disable(unsigned int channel)
-{
-       outportb(dma[channel].mask, (channel & 3) | 0x04);
-}
-
-/* Clear the 'DMA Flip Flop' flag */
-static inline void dma_clear_ff(unsigned int channel)
-{
-       outportb(dma[channel].flip, 0);
-}
-
-/* Set mode for a specific DMA channel */
-static inline void dma_set_mode(unsigned int channel, char mode)
-{
-       outportb(dma[channel].mode, mode | (channel & 3));
-}
-
-/* Set DMA page register */
-static inline void dma_set_page(unsigned int channel, char page)
-{
-       if (channel > 3)
-               page &= 0xfe;
-       outportb(dma[channel].page, page);
-}
-
-/*
-  Set transfer address & page bits for specific DMA channel.
-  Assumes dma flipflop is clear.
-*/
-static inline void dma_set_addr(unsigned int channel, unsigned int address)
-{
-       unsigned char dma_reg = dma[channel].addr;
-       dma_set_page(channel, address >> 16);
-       if (channel <= 3) {
-               outportb(dma_reg, (address) & 0xff);
-               outportb(dma_reg, (address >> 8) & 0xff);
-       } else {
-               outportb(dma_reg, (address >> 1) & 0xff);
-               outportb(dma_reg, (address >> 9) & 0xff);
-       }
-}
-
-/*
-  Set transfer size for a specific DMA channel.
-  Assumes dma flip-flop is clear.
-*/
-static inline void dma_set_count(unsigned int channel, unsigned int count)
-{
-       unsigned char dma_reg = dma[channel].size;
-       count--;                                        /* number of DMA transfers is bigger by one */
-       if (channel > 3)
-               count >>= 1;
-       outportb(dma_reg, (count) & 0xff);
-       outportb(dma_reg, (count >> 8) & 0xff);
-}
-
-/*
-  Query the number of bytes left to transfer.
-  Assumes DMA flip-flop is clear.
-*/
-static inline int dma_get_count(unsigned int channel)
-{
-       unsigned char dma_reg = dma[channel].size;
-
-       /* using short to get 16-bit wrap around */
-       unsigned short count;
-       count = inportb(dma_reg);
-       count |= inportb(dma_reg) << 8;
-       count++;
-       return (channel <= 3) ? count : (count << 1);
-}
-
-typedef struct dma_buffer_s {
-       unsigned char *linear;          /* Linear address */
-       unsigned long physical;         /* Physical address */
-       unsigned long size;                     /* Buffer size */
-       unsigned short selector;        /* The selector assigned to this memory */
-       unsigned char channel;          /* The DMA channel */
-} dma_buffer;
-
-/* Allocate a block of memory suitable for using as a DMA buffer */
-extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
-/* Deallocate a DMA buffer */
-extern void dma_free(dma_buffer * buffer);
-/* Start DMA transfer to or from given buffer */
-extern void dma_start(dma_buffer * buffer, unsigned long count,
-                                         unsigned char mode);
-
-#endif /* __DOSDMA_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosgus.c b/libs/mikmod/drivers/dos/dosgus.c
deleted file mode 100644 (file)
index 637b526..0000000
+++ /dev/null
@@ -1,1907 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  Driver for GUS cards under DOS
-  Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_ULTRA
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <dos.h>
-#include <dpmi.h>
-#include <sys/farptr.h>
-#include <sys/nearptr.h>
-#include <go32.h>
-#include <string.h>
-
-#include "dosgus.h"
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-/********************************************* Private variables/routines *****/
-
-/* The Gravis Ultrasound state/info */
-__gus_state gus;
-
-/* Try to avoid holes in DRAM less than this size */
-#define DRAM_HOLE_THRESHOLD    8192
-/* If hole is larger than that, create a free block describing it */
-#define DRAM_SPLIT_THRESHOLD   64
-/* The size of DMA buffer used for RAM->DRAM transfers */
-#define GF1_DMA_BUFFER_SIZE    8192
-
-/* Debug macro: useful to change screen locations when some event occurs */
-#ifdef MIKMOD_DEBUG
-#  define DEBUG_PRINT(x) printf x;
-#  define DEBUG_OFS(addr, attr)                        \
-   {                                           \
-     unsigned short x;                         \
-     _dosmemgetw (0xb8780 + addr*2, 1, &x);    \
-     if ((x >> 8) != attr) x = '0';            \
-     x = ((x + 1) & 0xff) | (attr << 8);       \
-     _dosmemputw (&x, 1, 0xb8780 + addr*2);    \
-   }
-#else
-#  define DEBUG_PRINT(x)
-#  define DEBUG_OFS(addr, attr)
-#endif
-
-static unsigned short __gus_volume_table[512] = {
-       0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00,
-       0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, 0xac00, 0xae00,
-       0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700,
-       0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00,
-       0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380,
-       0xc400, 0xc480, 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780,
-       0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
-       0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80,
-       0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, 0xd180, 0xd1c0,
-       0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0,
-       0xd400, 0xd440, 0xd480, 0xd4c0, 0xd500, 0xd540, 0xd580, 0xd5c0,
-       0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0,
-       0xd800, 0xd840, 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0,
-       0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
-       0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0,
-       0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, 0xdf80, 0xdfc0,
-       0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0,
-       0xe100, 0xe120, 0xe140, 0xe160, 0xe180, 0xe1a0, 0xe1c0, 0xe1e0,
-       0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0,
-       0xe300, 0xe320, 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0,
-       0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
-       0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0,
-       0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, 0xe6c0, 0xe6e0,
-       0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0,
-       0xe800, 0xe820, 0xe840, 0xe860, 0xe880, 0xe8a0, 0xe8c0, 0xe8e0,
-       0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0,
-       0xea00, 0xea20, 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0,
-       0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
-       0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0,
-       0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, 0xedc0, 0xede0,
-       0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0,
-       0xef00, 0xef20, 0xef40, 0xef60, 0xef80, 0xefa0, 0xefc0, 0xefe0,
-       0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070,
-       0xf080, 0xf090, 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0,
-       0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
-       0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0,
-       0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, 0xf260, 0xf270,
-       0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0,
-       0xf300, 0xf310, 0xf320, 0xf330, 0xf340, 0xf350, 0xf360, 0xf370,
-       0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0,
-       0xf400, 0xf410, 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470,
-       0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
-       0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570,
-       0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, 0xf5e0, 0xf5f0,
-       0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670,
-       0xf680, 0xf690, 0xf6a0, 0xf6b0, 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0,
-       0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770,
-       0xf780, 0xf790, 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0,
-       0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
-       0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0,
-       0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, 0xf960, 0xf970,
-       0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0,
-       0xfa00, 0xfa10, 0xfa20, 0xfa30, 0xfa40, 0xfa50, 0xfa60, 0xfa70,
-       0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0,
-       0xfb00, 0xfb10, 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70,
-       0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
-       0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70,
-       0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, 0xfce0, 0xfcf0,
-       0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70,
-       0xfd80, 0xfd90, 0xfda0, 0xfdb0, 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0,
-       0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70,
-       0xfe80, 0xfe90, 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0,
-       0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
-       0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0
-};
-
-/* Wait a bit for GUS before doing something
- * Mark function as volatile: don't allow it to be inlined.
- * It *should* be slow, no need to make it work faster :-)
- */
-#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
-# define _func_noinline volatile /* match original code */
-# define _func_noclone
-#else
-/* avoid warnings from newer gcc:
- * "function definition has qualified void return type" and
- * function return types not compatible due to 'volatile' */
-# define _func_noinline __attribute__((__noinline__))
-# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
-#  define _func_noclone
-# else
-#  define _func_noclone __attribute__((__noclone__))
-# endif
-#endif
-_func_noinline
-_func_noclone
- void __gus_delay()
-{
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-       inportb(GF1_MIX_CTRL);
-}
-
-static void __gus_stop_controller(unsigned char gf1reg)
-{
-       register unsigned char value = __gus_inregb(gf1reg);
-       __gus_outregb(gf1reg, (value | GF1VC_STOPPED | GF1VC_STOP) &
-                      ~(GF1VC_IRQ_PENDING | GF1VC_IRQ));
-}
-
-/* Returns 1 if volume is already at given position */
-static boolean __gus_volume_ramp_to(unsigned short volume,
-                                    unsigned char rate,
-                                    unsigned char vol_ctrl)
-{
-       int svol = __gus_inregw(GF1R_VOLUME) & 0xfff0;
-       int evol = volume;
-
-       /* First of all, disable volume ramp */
-       __gus_stop_controller(GF1R_VOLUME_CONTROL);
-
-       /* If voice is stopped, set the volume to zero and return */
-       if (__gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED) {
-               __gus_outregw(GF1R_VOLUME, 0);
-               return 1;
-       }
-
-       /* Avoid clicks when volume ramp goes too high or too low */
-       if (svol < 0x0400)
-               svol = 0x0400;
-       if (svol > 0xfc00)
-               svol = 0xfc00;
-       if (evol < 0x0400)
-               evol = 0x0400;
-       if (evol > 0xfc00)
-               evol = 0xfc00;
-
-       /* Adjust start/end positions */
-       if (svol > evol) {
-               unsigned short tmp = evol;
-               evol = svol;
-               svol = tmp;
-               vol_ctrl |= GF1VL_BACKWARD;
-       }
-
-       /* If we already are (near) the target volume, quit */
-       if (evol - svol < 0x1000) {
-               __gus_outregw(GF1R_VOLUME, volume);
-               return 1;
-       }
-
-       __gus_outregb(GF1R_VOLUME_START, svol >> 8);
-       __gus_outregb(GF1R_VOLUME_END, evol >> 8);
-       __gus_outregb(GF1R_VOLUME_RATE, rate);
-       __gus_outregb_slow(GF1R_VOLUME_CONTROL, vol_ctrl);
-       return 0;
-}
-
-static inline void __gus_stop_voice()
-{
-       __gus_stop_controller(GF1R_VOICE_CONTROL);
-       __gus_outregb_slow(GF1R_VOICE_CONTROL, GF1VC_STOPPED | GF1VC_STOP);
-}
-
-/* The GUS IRQ handler */
-static void gf1_irq()
-{
-       unsigned char irq_source;       /* The contents of GF1_IRQ_STATUS register */
-       boolean timer_cb = 0;           /* Call timer callback function */
-
-       DEBUG_OFS(0, 0xCE)
-       gus.eow_ignore = 0;
-       while ((irq_source = inportb(GF1_IRQ_STATUS))) {
-               DEBUG_OFS(1, 0xCE)
-
-                 if (irq_source & GF1M_IRQ_DMA_COMPLETE) {
-                       DEBUG_OFS(4, 0x9F)
-                         /* reset the IRQ pending bit */
-                         __gus_inregb(GF1R_DMA_CONTROL);
-                       gus.dma_active = 0;
-
-                       if (gus.dma_callback)
-                               gus.dma_callback();
-               }
-
-               if (irq_source & (GF1M_IRQ_WAVETABLE | GF1M_IRQ_ENVELOPE)) {
-                       unsigned char vcirq;
-                       unsigned int done_mask = 0;
-
-                       /* IRQ bits are inverse (i.e. 0 = IRQ pending) */
-                       while ((vcirq = __gus_inregb(GF1R_IRQ_SOURCE) ^
-                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) &
-                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) {
-                               unsigned long voice = (vcirq & 0x1f);
-                               unsigned char voice_ctl, volume_ctl;
-                               unsigned int voice_mask = (1 << voice);
-
-                               /* Don't handle more than one IRQ from same voice */
-                               if (done_mask & voice_mask)
-                                       continue;
-
-                               done_mask |= voice_mask;
-
-                               /* Read voice/volume selection registers */
-                               __gus_select_voice(voice);
-                               voice_ctl = __gus_inregb(GF1R_VOICE_CONTROL);
-                               volume_ctl = __gus_inregb(GF1R_VOLUME_CONTROL);
-
-                               if ((vcirq & GF1IRQ_WAVE) && (gus.wt_callback)
-                                       && !(gus.eow_ignore & voice_mask)) {
-                                       DEBUG_OFS(5, 0xAF)
-                                       gus.wt_callback(voice, voice_ctl, volume_ctl);
-                               }
-
-                               if ((vcirq & GF1IRQ_VOLUME) && (gus.vl_callback)) {
-                                       DEBUG_OFS(6, 0xAF)
-                                       gus.vl_callback(voice, voice_ctl, volume_ctl);
-                               }
-                       }
-               }
-
-               /* Reset timers that sent this IRQ */
-               if (irq_source & (GF1M_IRQ_TIMER1 | GF1M_IRQ_TIMER2)) {
-                       unsigned char timer_ctl = gus.timer_ctl_reg;
-
-                       if (irq_source & GF1M_IRQ_TIMER1)
-                               timer_ctl &= ~GF1M_TIMER1;
-
-                       if (irq_source & GF1M_IRQ_TIMER2)
-                               timer_ctl &= ~GF1M_TIMER2;
-
-                       __gus_outregb_slow(GF1R_TIMER_CONTROL, timer_ctl);
-                       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
-               }
-
-               if (irq_source & GF1M_IRQ_TIMER1)
-                       if (--gus.t1_countdown == 0) {
-                               gus.t1_countdown = gus.t1_multiple;
-                               gus.t1_ticks++;
-
-                               DEBUG_OFS(2, 0xCF)
-
-                               if (gus.t1_callback) {
-                                       timer_cb = 1;
-                                       gus.t1_callback();
-                               }
-                       }
-
-               if (irq_source & GF1M_IRQ_TIMER2)
-                       if (--gus.t2_countdown == 0) {
-                               gus.t2_countdown = gus.t2_multiple;
-                               gus.t2_ticks++;
-
-                               DEBUG_OFS(3, 0xCF)
-
-                               if (gus.t2_callback)
-                                       gus.t2_callback();
-                       }
-#if 0
-               /* The following are not used and implemented yet */
-               if (irq_source & (GF1M_IRQ_MIDI_TX | GF1M_IRQ_MIDI_RX)) {
-               }
-#endif
-       }
-
-       irq_ack(gus.gf1_irq);
-
-       if (timer_cb && gus.timer_callback)
-               gus.timer_callback();
-}
-
-static void gf1_irq_end()
-{
-}
-
-static boolean __gus_detect()
-{
-       /* A relatively relaxed autodetection;
-          We don't count on DRAM: GUS PnP could not have it
-          (although its anyway bad for us)
-        */
-       __gus_select_voice(0);
-       __gus_stop_voice();
-       __gus_outregw(GF1R_FREQUENCY, 0x1234);
-       __gus_outregw(GF1R_VOLUME, 0x5670);
-       return ((__gus_inregw(GF1R_FREQUENCY) & 0xfffe) == 0x1234)
-         && ((__gus_inregw(GF1R_VOLUME) & 0xfff0) == 0x5670);
-}
-
-static void __gus_reset(boolean reset_io_dma)
-{
-       static unsigned char irqctl[16] = { 0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7 };
-       static unsigned char dmactl[8] = { 0, 1, 0, 2, 0, 3, 4, 5 };
-       unsigned char irqtmp, dmatmp;
-
-       /* Disable interrupts while resetting to avoid spurious IRQs */
-       int i, timer, old_ints = disable();
-
-       /* Stop the timer so that GUS IRQ won't clobber registers */
-       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
-       if (timer)
-               gus_timer_stop();
-
-       gus.dma_active = 0;
-
-       __gus_outregb(GF1R_RESET, 0);
-       for (i = 0; i < 10; i++)
-               __gus_delay();
-       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET);
-       for (i = 0; i < 10; i++)
-               __gus_delay();
-
-       outportb(GF1_MIDI_CTRL, GF1M_MIDI_RESET);
-       for (i = 0; i < 10; i++)
-               __gus_delay();
-       outportb(GF1_MIDI_CTRL, 0);
-
-       /* Reset all IRQ sources */
-       __gus_outregb(GF1R_DMA_CONTROL, 0);
-       __gus_outregb(GF1R_TIMER_CONTROL, 0);
-       __gus_outregb(GF1R_SAMPLE_CONTROL, 0);
-
-       /* Reset all voices */
-       gus_reset(gus.voices, gus.dynmask);
-
-       /* Flush any pending IRQs */
-       inportb(GF1_IRQ_STATUS);
-       __gus_inregb(GF1R_DMA_CONTROL);
-       __gus_inregb(GF1R_SAMPLE_CONTROL);
-       __gus_inregb(GF1R_IRQ_SOURCE);
-
-       if (reset_io_dma) {
-               /* Now set up the GUS card to required IRQs and DMAs */
-               if (gus.irq[0] == gus.irq[1])
-                       irqtmp = irqctl[gus.irq[0]] | GF1M_IRQ_EQUAL;
-               else
-                       irqtmp = irqctl[gus.irq[0]] | (irqctl[gus.irq[1]] << 3);
-
-               if (gus.dma[0] == gus.dma[1])
-                       dmatmp = dmactl[gus.dma[0]] | GF1M_DMA_EQUAL;
-               else
-                       dmatmp = dmactl[gus.dma[0]] | (dmactl[gus.dma[1]] << 3);
-
-               /* Reset IRQs if possible */
-               gus.mixer =
-                 GF1M_MIXER_NO_LINE_IN | GF1M_MIXER_NO_OUTPUT | GF1M_MIXER_GF1_IRQ;
-               if (gus.version >= GUS_CARD_VERSION_CLASSIC1) {
-                       outportb(GF1_REG_CTRL, 0x05);
-                       outportb(GF1_MIX_CTRL, gus.mixer);
-                       outportb(GF1_IRQ_CTRL, 0x00);   /* Reset IRQs */
-                       outportb(GF1_REG_CTRL, 0x00);
-               }
-
-               /* Set up DMA channels: NEVER disable MIXER_GF1_IRQ in the future */
-               outportb(GF1_MIX_CTRL, gus.mixer);
-               outportb(GF1_IRQ_CTRL, dmatmp);
-
-               /* Set up IRQ channels */
-               outportb(GF1_MIX_CTRL, gus.mixer | GF1M_CONTROL_SELECT);
-               outportb(GF1_IRQ_CTRL, irqtmp);
-       }
-
-       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET | GF1M_OUTPUT_ENABLE | GF1M_MASTER_IRQ);
-       __gus_delay();
-
-       /* Flush IRQs again */
-       inportb(GF1_IRQ_STATUS);
-       __gus_inregb(GF1R_DMA_CONTROL);
-       __gus_inregb(GF1R_SAMPLE_CONTROL);
-       __gus_inregb(GF1R_IRQ_SOURCE);
-
-       _irq_ack(gus.irq[0]);
-       _irq_ack(gus.irq[1]);
-
-       if (timer)
-               gus_timer_continue();
-
-       if (old_ints)
-               enable();
-
-       /* Enable output */
-       __gus_mixer_output(1);
-}
-
-/* Transfer a block of data from GUS DRAM to main RAM through port I/O */
-static void __gus_transfer_io_in(unsigned long address, unsigned char *source,
-                                 unsigned long size)
-{
-       while (size) {
-               register unsigned int size64k;
-
-               size64k = 0x10000 - (address & 0xffff);
-               if (size64k > size)
-                       size64k = size;
-               size -= size64k;
-
-               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
-               while (size64k--) {
-                       __gus_outregw(GF1R_DRAM_LOW, address++);
-                       *source++ = inportb(GF1_DRAM);
-               }
-       }
-}
-
-/* Transfer a block of data into GUS DRAM through port I/O */
-static void __gus_transfer_io(unsigned long address, unsigned char *source,
-                              unsigned long size, int flags)
-{
-       while (size) {
-               register unsigned int size64k;
-
-               size64k = 0x10000 - (address & 0xffff);
-               if (size64k > size)
-                       size64k = size;
-               size -= size64k;
-
-               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
-               if (flags & GUS_WAVE_INVERT)
-                       if (flags & GUS_WAVE_16BIT)
-                               while (size64k-- && size64k--) {
-                                       __gus_outregw(GF1R_DRAM_LOW, address++);
-                                       outportb(GF1_DRAM, *source++);
-                                       __gus_outregw(GF1R_DRAM_LOW, address++);
-                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
-                       } else
-                               while (size64k--) {
-                                       __gus_outregw(GF1R_DRAM_LOW, address++);
-                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
-               } else
-                       while (size64k--) {
-                               __gus_outregw(GF1R_DRAM_LOW, address++);
-                               outportb(GF1_DRAM, *source++);
-                       }
-       }
-}
-
-/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
-static int __gus_wait_dma()
-{
-       unsigned long timer;
-       _farsetsel(_dos_ds);
-       timer = _farnspeekl(0x46c);
-       while (gus.dma_active)
-               if (_farnspeekl(0x46c) - timer > 8) {
-                       /* Force DMA abort since something went wrong */
-                       __gus_reset(0);
-                       return -1;
-               }
-
-       return 0;
-}
-
-/* Transfer a block of data into GUS DRAM through DMA controller */
-static void __gus_transfer_dma(unsigned long address, unsigned char *source,
-                               unsigned long size, int flags)
-{
-       unsigned char dma_control;
-       unsigned long bytes_left;
-       unsigned long cur_size;
-       unsigned long dest_addr;
-
-       if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
-               size = (size + 1) & ~1;
-
-       bytes_left = size;
-       while (bytes_left) {
-               __gus_wait_dma();
-
-               cur_size = gus.dma_buff->size;
-               if (cur_size > bytes_left)
-                       cur_size = bytes_left;
-               bytes_left -= cur_size;
-               dest_addr = address;
-
-               if (gus.dma_buff->linear != source)
-                       memmove(gus.dma_buff->linear, source, cur_size);
-               source += cur_size;
-               address += cur_size;
-
-               /* Disable GUS -> DMA tie */
-               __gus_outregb(GF1R_DMA_CONTROL, 0);
-               __gus_delay();
-
-               /* Set up the DMA */
-               dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
-               gus.dma_active = 1;
-
-               /* Reset the DMA IRQ pending bit if set */
-               __gus_inregb(GF1R_DMA_CONTROL);
-
-               /* The 16-bit DMA channels needs a slightly different approach */
-               dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
-               if (gus.dma[0] > 3) {
-                       dest_addr = __gus_convert_addr16(dest_addr);
-                       dma_control |= GF1M_DMAR_CHAN16;
-               }
-
-               __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);
-
-               if (flags & GUS_WAVE_16BIT)
-                       dma_control |= GF1M_DMAR_DATA16;
-               if (flags & GUS_WAVE_INVERT)
-                       dma_control |= GF1M_DMAR_TOGGLE_SIGN;
-
-               /* Tell GUS to start transfer */
-               __gus_outregb(GF1R_DMA_CONTROL, dma_control);
-       }
-}
-
-static void __gus_detect_version()
-{
-       unsigned char tmp;
-
-       switch (gus.version = inportb(GF1_REVISION)) {
-         case 5:
-               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
-               gus.ics = 1;
-               gus.ics_flipped = 1;
-               break;
-         case 6:
-         case 7:
-         case 8:
-         case 9:
-               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
-               gus.ics = 1;
-               break;
-         case 10:
-               gus.version = GUS_CARD_VERSION_MAX;
-               gus.codec = 1;
-               break;
-         case 11:
-               gus.version = GUS_CARD_VERSION_MAX1;
-               gus.codec = 1;
-               break;
-         case 0x30:
-               gus.version = GUS_CARD_VERSION_ACE;
-               break;
-         case 0x50:
-               gus.version = GUS_CARD_VERSION_EXTREME;
-               break;
-         case 0xff:
-               /* Pre-3.7 board */
-               outportb(GF1_REG_CTRL, 0x20);
-               tmp = inportb(GF1_REG_CTRL);
-               if ((tmp != 0xff) && (tmp & 0x06))
-                       gus.version = GUS_CARD_VERSION_CLASSIC1;
-               else
-                       gus.version = GUS_CARD_VERSION_CLASSIC;
-               break;
-         default:
-               /* Hmm... unknown revision. Assume a safe Classic model */
-#ifdef MIKMOD_DEBUG
-               fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
-                               gus.version);
-#endif
-               gus.version = GUS_CARD_VERSION_CLASSIC;
-               break;
-       }
-}
-
-static void __gus_detect_transfer()
-{
-       unsigned char *outbuff, *inbuff;
-       unsigned int i, j, seed = 0x13243546;
-       __gus_transfer_func func;
-
-#define TRANSFER_SIZE  0x4000
-
-       outbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
-       inbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
-
-       /* Suppose we have an malfunctioning GUS */
-       gus.transfer = NULL;
-
-       for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
-               switch (i) {
-                 case 0:
-                       gus.dma_rate = GF1M_DMAR_RATE0;
-                       func = __gus_transfer_dma;
-                       break;
-                 case 1:
-                       gus.dma_rate = GF1M_DMAR_RATE1;
-                       func = __gus_transfer_dma;
-                       break;
-                 case 2:
-                       gus.dma_rate = GF1M_DMAR_RATE2;
-                       func = __gus_transfer_dma;
-                       break;
-                 case 3:
-                       gus.dma_rate = GF1M_DMAR_RATE3;
-                       func = __gus_transfer_dma;
-                       break;
-                 case 4:
-                       func = __gus_transfer_io;
-                       break;
-               }
-
-               /* Fill data array each time with pseudo-random values */
-               for (j = 0; j < TRANSFER_SIZE; j++)
-                       outbuff[j] = seed, seed =
-                         ((seed + 358979323) ^ (seed >> 16)) * 314159265;
-
-               /* Transfer the random array to GUS */
-               /* Poke a security fence around dest block */
-               __gus_poke(0x100 - 1, 0xAA);
-               __gus_poke(0x100 - 2, 0x55);
-               __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
-               __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);
-
-               func(0x100, outbuff, TRANSFER_SIZE, 0);
-
-               if (__gus_wait_dma() == 0) {
-                       /* Check if the security fence was not damaged */
-                       if ((__gus_peek(0x100 - 1) != 0xAA)
-                               || (__gus_peek(0x100 - 2) != 0x55)
-                               || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
-                               || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
-                               continue;
-
-                       /* Now check if GUS DRAM really data that we expects to be transferred */
-                       __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
-                       if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
-                               gus.transfer = func;
-                               break;
-                       }
-               }
-       }
-
-#undef TRANSFER_SIZE
-
-       MikMod_free(inbuff);
-       MikMod_free(outbuff);
-}
-
-static void __gus_detect_memory()
-{
-       unsigned int size;
-       for (size = 0; size < 1024; size += 256) {
-               __gus_poke(size * 1024, 0xaa);
-               if (__gus_peek(size * 1024) != 0xaa)
-                       break;
-               __gus_poke(size * 1024, 0x55);
-               if (__gus_peek(size * 1024) != 0x55)
-                       break;
-       }
-       gus.ram = size;
-}
-
-static void __gus_init()
-{
-       char *gusenv = getenv("ULTRASND");
-
-       memset((void *)&gus, 0, sizeof(gus));
-       gus.cmd_voice = -1;
-
-       if (!gusenv)
-               return;
-
-       sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
-                  &gus.irq[0], &gus.irq[1]);
-
-       /* A relaxed sanity check */
-       if ((gus.port < 0x100) || (gus.port > 0x1000)
-               || (gus.irq[0] < 2) || (gus.irq[0] > 15)
-               || (gus.irq[1] < 2) || (gus.irq[1] > 15)
-               || (gus.dma[0] < 0) || (gus.dma[0] > 7)
-               || (gus.dma[1] < 0) || (gus.dma[1] > 7))
-               return;
-
-       gus.voices = 32;
-       gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;
-
-       /* Detect if the card is really there */
-       if (__gus_detect() == 0)
-               return;
-
-       /* Detect the version of Gravis Ultrasound */
-       __gus_detect_version();
-
-       /* Reset the card */
-       __gus_reset(1);
-
-       /* Detect the amount of on-board memory */
-       __gus_detect_memory();
-
-       gus.ok = 1;
-}
-
-static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
-{
-       unsigned char vc;
-
-       vc = GF1VC_IRQ;
-       if (wave->format & GUS_WAVE_16BIT)
-               vc |= GF1VC_DATA16;
-       if (wave->format & GUS_WAVE_BACKWARD)
-               vc |= GF1VC_BACKWARD;
-       if (wave->format & GUS_WAVE_LOOP) {
-               vc |= GF1VC_LOOP_ENABLE;
-               if (wave->format & GUS_WAVE_BIDIR)
-                       vc |= GF1VC_BI_LOOP;
-       }
-       __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
-       if (wave->format & GUS_WAVE_LOOP)
-               __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
-       else
-               __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
-       __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
-       __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
-}
-
-/* Timer 1 callback function (updates voices) */
-static void __gus_timer_update()
-{
-       gus_wave_t *wave;
-       unsigned long wave_offset;
-       unsigned char *src, *top;
-       unsigned int vmask = (1 << gus.cur_voice);
-
-       if (!gus.cmd_pool_ready)
-               return;
-
-       __gus_select_voice(gus.cur_voice);
-       wave_offset = 0;
-       src = gus.cmd_pool;
-       top = gus.cmd_pool + gus.cmd_pool_top;
-
-#define GET_B  *src
-#define GET_W  *((unsigned short *)src)
-#define GET_L  *((unsigned long *)src)
-
-       while (src < top) {
-               __gus_delay();
-               switch (GET_B++) {
-                 case PCMD_VOICE:
-                       __gus_select_voice(gus.cur_voice = GET_B++);
-                       vmask = (1 << gus.cur_voice);
-                       break;
-                 case PCMD_FREQ:
-               /*      __gus_outregw(GF1R_FREQUENCY, GET_W++);*/
-                       __gus_outregw(GF1R_FREQUENCY, *(unsigned short *)src);
-                       src += 2;
-                       break;
-                 case PCMD_PAN:
-                       __gus_outregb(GF1R_BALANCE, GET_B++);
-                       break;
-                 case PCMD_VOLUME:
-                       __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
-                                                       /*       GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);*/
-                                                 *(unsigned short *)src, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
-                                                               src += 2;
-                       break;
-                 case PCMD_VOLUME_PREPARE:
-               /*      gus.cur_vol[gus.cur_voice] = GET_W++;*/
-                       gus.cur_vol[gus.cur_voice] = *(unsigned short *)src;
-                       src += 2;
-                       break;
-                 case PCMD_OFFSET:
-               /*      wave_offset = GET_L++;*/
-                       wave_offset = *(unsigned long *)src;
-                       src += 4;
-                       break;
-                 case PCMD_START:
-               /*      wave = (gus_wave_t *) GET_L++;*/
-                       wave = (gus_wave_t *) *(unsigned long *)src;
-                       src += 4;
-                       gus.cur_wave[gus.cur_voice] = wave;
-                       gus.kick_offs[gus.cur_voice] = wave_offset;
-                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
-                               __gus_kick(wave, wave_offset);
-                               __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
-                                                                        GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
-                       } else
-                               gus.voice_kick[gus.cur_voice] = 1;
-                       wave_offset = 0;
-                       gus.eow_ignore |= vmask;
-                       break;
-                 case PCMD_STOP:
-                       /* If volume is close to nothing, abort immediately instead of
-                          ramping */
-                       gus.cur_vol[gus.cur_voice] = 0;
-                       gus.cur_wave[gus.cur_voice] = NULL;
-                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
-                               __gus_stop_voice();
-                       break;
-                 case PCMD_STOP_LOOP:
-                       __gus_outregb_slow(GF1R_VOICE_CONTROL,
-                                                          (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
-                                                          & ~GF1VC_LOOP_ENABLE);
-                       __gus_outregb_slow(GF1R_VOLUME_CONTROL,
-                                                          __gus_inregb(GF1R_VOLUME_CONTROL) &
-                                                          ~GF1VL_ROLLOVER);
-                       break;
-                 default:
-                       /* Alarm! Break out immediately */
-                       src = top;
-                       break;
-               }
-       }
-
-#undef GET_B
-#undef GET_W
-#undef GET_L
-
-       gus.cmd_pool_ready = 0;
-       gus.cmd_pool_top = 0;
-}
-
-static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
-                                                                  unsigned int volume_ctl)
-{
-       gus_wave_t *wave = gus.cur_wave[voice];
-
-       if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
-               __gus_stop_voice();
-               gus.cur_wave[voice] = NULL;
-               gus.cur_vol[voice] = 0;
-               if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
-                       __gus_stop_voice();
-       }
-}
-
-static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
-                                                               unsigned int volume_ctl)
-{
-       __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
-       if (!gus.cur_wave[voice])
-               __gus_stop_voice();
-       else if (gus.voice_kick[voice])
-               __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
-       gus.voice_kick[voice] = 0;
-}
-
-/***************************************************** GUS memory manager *****/
-
-/* Mark all GUS memory as available */
-static void __gus_mem_clear()
-{
-       __gus_mcb *cur = gus.mcb;
-
-       while (cur) {
-               __gus_mcb *next = cur->next;
-               if (cur != gus.mcb)
-                       MikMod_free(cur);
-               cur = next;
-       }
-
-       if (!gus.mcb)
-               gus.mcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
-
-       gus.mcb->next = gus.mcb->prev = NULL;
-       gus.mcb->addr = 0;
-       gus.mcb->size = gus.ram * 1024;
-       gus.mcb->free = 1;
-}
-
-/* Return amount of free memory */
-static unsigned int __gus_mem_get_free()
-{
-       __gus_mcb *cur = gus.mcb;
-       unsigned int size = 0;
-
-       if (!gus.open)
-               return gus.ram * 1024;
-
-       while (cur) {
-               if (cur->free)
-                       size += cur->size;
-               cur = cur->next;
-       }
-
-       return size;
-}
-
-/* Return largest size for a 8-bit sample */
-static unsigned int __gus_mem_get_free_8()
-{
-       __gus_mcb *cur = gus.mcb;
-       unsigned int size = 0;
-
-       if (!gus.open)
-               return 0;
-
-       while (cur) {
-               if (cur->free && (cur->size > size))
-                       size = cur->size;
-               cur = cur->next;
-       }
-
-       return size;
-}
-
-/* Return largest size for a 16-bit sample */
-static unsigned int __gus_mem_get_free_16()
-{
-       __gus_mcb *cur = gus.mcb;
-       unsigned int size = 0;
-
-       if (!gus.open)
-               return 0;
-
-       while (cur) {
-               if (cur->free) {
-                       unsigned int size16 = cur->size;
-                       unsigned int tmp;
-                       /* 16-bit samples cannot cross 256K boundaries */
-                       tmp = 0x40000 - (cur->addr & 0x3ffff);
-                       if (size16 > tmp)
-                               size16 = tmp;
-                       /* 16-bit samples should be aligned on a 32-byte boundary */
-                       size16 -= (32 - cur->addr) & 0x1f;
-
-                       if (size16 > size)
-                               size = size16;
-
-                       /* Now try vice versa: skip a portion of aligned memory */
-                       size16 =
-                         (cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
-                       if ((size16 < 0x7fffffff) && (size16 > size))
-                               size = size16;
-               }
-               cur = cur->next;
-       }
-
-       return size;
-}
-
-/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
- * The algorithm tries to find the smallest free block that fits requested
- * size; but if found free block is larger by some (large) delta than
- * requested block size, the largest possible block is preffered.
- */
-static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
-{
-       __gus_mcb *cur = gus.mcb;
-       __gus_mcb *best_max = NULL, *best_min = NULL;
-       unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
-       unsigned int best_max_prefix = 0, best_min_prefix = 0;
-       unsigned int memaddr, memsize;
-
-       if (!gus.open || !size || (bits16 && size > 0x40000))
-               return -1;
-
-       /* Round block size up to nearest acceptable DMA bound */
-       if (bits16)
-               size = (size + 0x1f) & ~0x1f;
-       else
-               size = (size + 0x0f) & ~0x0f;
-
-       while (cur) {
-               if (cur->free) {
-                       unsigned char fits = 0;
-
-                       memsize = cur->size;
-                       memaddr = cur->addr;
-
-                       if (bits16) {
-                               /* 16-bit samples cannot cross 256K boundaries */
-                               unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
-                               if (memsize > tmp)
-                                       memsize = tmp;
-                               /* 16-bit samples should be aligned on a 32-byte boundary */
-                               memsize -= (32 - memaddr) & 0x1f;
-                               memaddr = (memaddr + 0x1f) & ~0x1f;
-                       }
-
-                       /* If block fits, analyze it */
-                       if (size <= memsize)
-                               fits = 1;
-                       /* Look if we still can complete the request by creating a free
-                          block */
-                       else if (size <= cur->size) {
-                               /* Align start address to next 256k boundary */
-                               unsigned int endaddr = cur->addr + cur->size;
-                               memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
-                               /* Can we split current block by inserting a free block at the
-                                  beginning? */
-                               if ((memaddr < endaddr) && (memaddr + size <= endaddr))
-                                       fits = 1;
-                       }
-
-                       if (fits) {
-                               unsigned int size_delta = cur->size - size;
-                               unsigned int size_prefix = memaddr - cur->addr;
-                               if (size_delta < best_min_delta)
-                                       best_min = cur, best_min_delta =
-                                         size_delta, best_min_prefix = size_prefix;
-                               if (size_delta > best_max_delta)
-                                       best_max = cur, best_max_delta =
-                                         size_delta, best_max_prefix = size_prefix;
-                       }
-               }
-
-               cur = cur->next;
-       }
-
-       if (!best_min)
-               return -1;
-
-       /* If minimal block that fits is too large, use largest block that fits */
-       /* But if using the maximal block is going to create a small hole, forget
-          it */
-       if ((best_max_prefix == 0)
-               || (best_max_prefix >= DRAM_HOLE_THRESHOLD)
-               || (best_min_prefix != 0))
-               if (
-                       ((best_min_delta < DRAM_HOLE_THRESHOLD) &&
-                        (best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
-                       ((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
-                        && ((best_max_prefix == 0) ||
-                                (best_max_prefix > best_min_prefix))) ||
-                       ((best_min_prefix != 0) && (best_max_prefix == 0))) {
-                       best_min = best_max;
-                       best_min_delta = best_max_delta;
-                       best_min_prefix = best_max_prefix;
-               }
-
-       /* Compute the DRAM address to return */
-       memaddr = best_min->addr + best_min_prefix;
-       if (bits16)
-               memaddr = (memaddr + 0x1f) & ~0x1f;
-       else
-               memaddr = (memaddr + 0x0f) & ~0x0f;
-
-       /* If we have a considerable hole at the beginning of sample,
-          create a free node describing the hole */
-       if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
-               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
-               newmcb->prev = best_min->prev;
-               newmcb->next = best_min;
-               newmcb->addr = best_min->addr;
-               newmcb->size = memaddr - best_min->addr;
-               newmcb->free = 1;
-               best_min->addr = memaddr;
-               best_min->size -= newmcb->size;
-               best_min->prev = newmcb;
-               if (newmcb->prev)
-                       newmcb->prev->next = newmcb;
-       }
-
-       /* Compute the size of hole at the end of block */
-       memsize = (best_min->addr + best_min->size) - (memaddr + size);
-
-       /* Split the block if the block is larger than requested amount */
-       if (memsize > DRAM_SPLIT_THRESHOLD) {
-               /* The next node cannot be free since free blocks are always glued
-                  together */
-               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
-               best_min->size -= memsize;
-               newmcb->prev = best_min;
-               newmcb->next = best_min->next;
-               newmcb->addr = best_min->addr + best_min->size;
-               newmcb->size = memsize;
-               newmcb->free = 1;
-               if (best_min->next)
-                       best_min->next->prev = newmcb;
-               best_min->next = newmcb;
-       }
-       best_min->free = 0;
-
-       return memaddr;
-}
-
-static void __gus_mem_free(unsigned int addr)
-{
-       __gus_mcb *cur = gus.mcb;
-       while (cur) {
-               if (!cur->free && (cur->addr <= addr) &&
-                       (cur->addr + cur->size > addr)) {
-                       cur->free = 1;
-
-                       /* If next block is free as well, link them together */
-                       if (cur->next && cur->next->free) {
-                               __gus_mcb *next = cur->next;
-                               cur->size += next->size;
-                               cur->next = next->next;
-                               if (next->next)
-                                       next->next->prev = cur;
-                               MikMod_free(next);
-                       }
-
-                       /* If previous block is free, link current block with it */
-                       if (cur->prev && cur->prev->free) {
-                               cur->prev->size += cur->size;
-                               cur->prev->next = cur->next;
-                               if (cur->next)
-                                       cur->next->prev = cur->prev;
-                               MikMod_free(cur);
-                       }
-                       return;
-               }
-               cur = cur->next;
-       }
-}
-
-static void __gus_mem_pack()
-{
-}
-
-#ifdef MIKMOD_DEBUG
-
-/* Debug dump of GUS DRAM heap */
-void __gus_mem_dump()
-{
-       __gus_mcb *cur = gus.mcb;
-       fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
-       while (cur) {
-               fprintf(stderr, "|  %08X  | %08X |  %6d  |   %s    |\n",
-                               cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
-                               cur->free ? "yes" : " no");
-               cur = cur->next;
-       }
-       fprintf(stderr, "\\------------+----------+----------+----------/\n");
-}
-
-#endif
-
-/************************************************** Middle-level routines *****/
-
-static int __gus_instrument_free(gus_instrument_t * instrument)
-{
-       gus_instrument_t **cur_instr;
-       gus_layer_t *cur_layer;
-       gus_wave_t *cur_wave, *wave_head;
-
-       /* Remove the instrument from the list of registered instruments */
-       cur_instr = (gus_instrument_t **) & gus.instr;
-       while (*cur_instr) {
-               if (*cur_instr == instrument) {
-                       *cur_instr = instrument->next;
-                       goto instr_loaded;
-               }
-               cur_instr = &(*cur_instr)->next;
-       }
-       return -1;
-
-instr_loaded:
-       wave_head = NULL;
-       for (cur_layer = instrument->info.layer; cur_layer;
-                cur_layer = cur_layer->next)
-               /* Free all waves */
-               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
-                       if (!wave_head)
-                               wave_head = cur_wave;
-                       if (cur_wave->begin.memory != (unsigned int)-1)
-                               __gus_mem_free(cur_wave->begin.memory);
-               }
-       if (wave_head)
-               MikMod_free(wave_head);
-
-       MikMod_free(instrument->info.layer);
-       if (instrument->name)
-               MikMod_free(instrument->name);
-       MikMod_free(instrument);
-       return 0;
-}
-
-static gus_instrument_t *__gus_instrument_get(int program)
-{
-       gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
-       while (cur_instr) {
-               if (cur_instr->number.instrument == program)
-                       return cur_instr;
-               cur_instr = cur_instr->next;
-       }
-       return NULL;
-}
-
-static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
-{
-       gus_instrument_t **cur_instr, *instr;
-       gus_layer_t *cur_layer, *dest_layer;
-       gus_wave_t *cur_wave, *dest_wave;
-       unsigned int waves, layers;
-
-       if (!instrument || !instrument->info.layer || !gus.open)
-               return NULL;
-
-       if (__gus_instrument_get(instrument->number.instrument))
-               return NULL;
-
-       instr = (gus_instrument_t *) MikMod_malloc(sizeof(gus_instrument_t));
-       *instr = *instrument;
-
-       if (instrument->name)
-               instr->name = MikMod_strdup(instrument->name);
-
-       /* Make a copy of all layers at once */
-       for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
-               cur_layer = cur_layer->next;
-
-       if (!(dest_layer = instr->info.layer = (gus_layer_t *) MikMod_malloc(sizeof(gus_layer_t) * layers))) {
-               if (instr->name)
-                       MikMod_free(instr->name);
-               MikMod_free(instr);
-               return NULL;
-       }
-       for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
-                cur_layer = cur_layer->next) {
-               *dest_layer = *cur_layer;
-               dest_layer->wave = NULL;
-               /* Count the total number of waves */
-               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
-                       waves++;
-               if (cur_layer->next)
-                       dest_layer->next = dest_layer + 1;
-               else
-                       dest_layer->next = NULL;
-               dest_layer++;
-       }
-
-       /* Allocate memory for waves */
-       if (!(dest_wave = (gus_wave_t *) MikMod_malloc(sizeof(gus_wave_t) * waves))) {
-               MikMod_free(instr->info.layer);
-               if (instr->name)
-                       MikMod_free(instr->name);
-               MikMod_free(instr);
-               return NULL;
-       }
-       for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
-            cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
-               /* Copy all waves */
-               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
-                       if (!dest_layer->wave)
-                               dest_layer->wave = dest_wave;
-
-                       *dest_wave = *cur_wave;
-                       /* Mark DRAM address as unallocated */
-                       dest_wave->begin.memory = -1;
-
-                       if (cur_wave->next)
-                               dest_wave->next = (dest_wave + 1);
-                       else
-                               dest_wave->next = NULL;
-                       dest_wave++;
-               }
-
-       /* Insert the instrument into list of registered instruments */
-       cur_instr = (gus_instrument_t **) & gus.instr;
-       while (*cur_instr)
-               cur_instr = &(*cur_instr)->next;
-       *cur_instr = instr;
-
-       return instr;
-}
-
-static void __gus_instruments_clear()
-{
-       gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
-       while (cur_instr) {
-               next_instr = cur_instr->next;
-               __gus_instrument_free(cur_instr);
-               cur_instr = next_instr;
-       }
-}
-
-/******************************************************* libGUS interface *****/
-
-/* return value: number of GUS cards installed in system */
-int gus_cards()
-{
-       if (!gus.ok)
-               __gus_init();
-       return gus.ok ? 1 : 0;
-}
-
-int gus_info(gus_info_t * info, int reread)
-{
-       if (!gus.ok)
-               __gus_init();
-       if (!gus.ok)
-               return -1;
-
-       strcpy((char *)info->id, "gus0");
-       info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
-       info->version = gus.version;
-       info->port = gus.port;
-       info->irq = gus.irq[0];
-       info->dma1 = gus.dma[0];
-       info->dma2 = gus.dma[1];
-
-       info->mixing_freq = gus.freq;
-
-       info->memory_size = gus.ram * 1024;
-       info->memory_free = __gus_mem_get_free();
-       info->memory_block_8 = __gus_mem_get_free_8();
-       info->memory_block_16 = __gus_mem_get_free_16();
-       return 0;
-}
-
-int gus_open(int card, size_t queue_buffer_size, int non_block)
-{
-       __dpmi_meminfo struct_info, pool_info;
-
-       if (!gus.ok)
-               __gus_init();
-
-       if (!gus.ok || gus.open || card != 0)
-               return -1;
-
-       /* Now lock the gus structure in memory */
-       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
-       struct_info.size = sizeof(gus);
-       if (__dpmi_lock_linear_region(&struct_info))
-               return -1;
-
-       /* And hook the GF1 interrupt */
-       __irq_stack_count = 4;
-       gus.gf1_irq =
-         irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
-       __irq_stack_count = 1;
-       if (!gus.gf1_irq) {
-               __dpmi_unlock_linear_region(&struct_info);
-               return -1;
-       }
-
-       /* Enable the interrupt */
-       irq_enable(gus.gf1_irq);
-       if (gus.irq[0] > 7)
-               _irq_enable(2);
-
-       /* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
-       if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
-               gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
-       else
-               gus.dma_buff = NULL;
-
-       /* Detect the best available RAM -> DRAM transfer function */
-       if (!gus.transfer) {
-               __gus_detect_transfer();
-               if (gus.transfer != __gus_transfer_dma || !gus.transfer)
-                       dma_free(gus.dma_buff), gus.dma_buff = NULL;
-
-               /* If no transfer function worked, fail */
-               if (!gus.transfer) {
-                       if (gus.dma_buff) {
-                               dma_free(gus.dma_buff);
-                               gus.dma_buff = NULL;
-                       }
-                       __dpmi_unlock_linear_region(&struct_info);
-                       irq_unhook(gus.gf1_irq);
-                       gus.gf1_irq = NULL;
-                       return -1;
-               }
-       }
-
-       /* Allocate and lock command pool buffer */
-       if (queue_buffer_size < 64)
-               queue_buffer_size = 64;
-       if (queue_buffer_size > 16384)
-               queue_buffer_size = 16384;
-       gus.cmd_pool = (unsigned char *) MikMod_malloc(queue_buffer_size);
-       pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
-       pool_info.size = sizeof(queue_buffer_size);
-       if (__dpmi_lock_linear_region(&pool_info)) {
-               if (gus.dma_buff) {
-                       dma_free(gus.dma_buff);
-                       gus.dma_buff = NULL;
-               }
-               __dpmi_unlock_linear_region(&struct_info);
-               irq_unhook(gus.gf1_irq);
-               gus.gf1_irq = NULL;
-               return -1;
-       }
-
-       gus.open++;
-
-       __gus_mem_clear();
-       gus.t1_callback = __gus_timer_update;
-       gus.wt_callback = __gus_wavetable_update;
-       gus.vl_callback = __gus_volume_update;
-       gus_do_tempo(60);                       /* Default is 60 Hz */
-
-       return 0;
-}
-
-int gus_close(int card)
-{
-       __dpmi_meminfo struct_info;
-
-       if (!gus.open || card != 0)
-               return -1;
-
-       /* First reset the card: disable any operation it can currently perform */
-       __gus_reset(0);
-
-       gus.open--;
-
-       /* Stop the timer */
-       gus_timer_stop();
-
-       /* Free DMA buffer if used */
-       if (gus.dma_buff) {
-               dma_free(gus.dma_buff);
-               gus.dma_buff = NULL;
-       }
-
-       /* And unhook the GF1 interrupt */
-       irq_unhook(gus.gf1_irq);
-       gus.gf1_irq = NULL;
-
-       /* Unlock the gus structure */
-       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
-       struct_info.size = sizeof(gus);
-       __dpmi_unlock_linear_region(&struct_info);
-
-       __gus_mem_clear();
-       __gus_instruments_clear();
-
-       return 0;
-}
-
-int gus_select(int card)
-{
-       if (!gus.open || (card != 0))
-               return -1;
-
-       return 0;
-}
-
-/* return value: same as gus_reset function
-   note: this command doesn't change number of active voices and doesn't do
-   hardware reset */
-int gus_reset_engine_only()
-{
-       gus.timer_base = 100;
-       return 0;
-}
-
-int gus_reset(int voices, unsigned int channel_voices)
-{
-       static unsigned short freq_table[32 - 14 + 1] = {
-               44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
-               25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
-       };
-       int voice;
-       int timer;
-
-       /* No support for dynamically allocated voices for now */
-       gus.dynmask = channel_voices;
-
-       if (voices < 14)
-               voices = 14;
-       if (voices > 32)
-               voices = 32;
-
-       /* Stop the timer so that GUS IRQ won't clobber registers */
-       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
-       if (timer)
-               gus_timer_stop();
-
-       /* Stop all voices */
-       for (voice = 0; voice < 32; voice++) {
-               __gus_select_voice(voice);
-               __gus_stop_voice();
-               gus.cur_wave[voice] = NULL;
-               gus.cur_vol[voice] = 0;
-
-               __gus_delay();
-
-               /* Reset voice parameters to reasonable values */
-               __gus_set_current(0, 0);
-               __gus_set_loop_start(0, 0);
-               __gus_set_loop_end(0, 0);
-               __gus_outregw(GF1R_VOLUME, 0);
-               __gus_outregb(GF1R_VOLUME_RATE, 0);
-               __gus_outregb(GF1R_VOLUME_START, 0);
-               __gus_outregb(GF1R_VOLUME_END, 0);
-               __gus_outregb(GF1R_BALANCE, 0x7);
-       }
-
-       voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
-
-       if (voice != voices) {
-               int reset = __gus_inregb(GF1R_RESET);
-               __gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
-               __gus_delay();
-               __gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
-               __gus_delay();
-               __gus_outregb(GF1R_RESET, reset);
-       }
-
-       /* Compute the discretization frequence */
-       gus.voices = voices;
-       if (gus.interwave)
-               gus.freq = 44100;
-       else
-               gus.freq = freq_table[voices - 14];
-
-       gus_reset_engine_only();
-
-       if (timer)
-               gus_timer_continue();
-
-       return gus.voices;
-}
-
-int gus_do_flush()
-{
-       DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
-         gus.cmd_pool_ready = 1;
-       return 0;
-}
-
-/* set new tempo */
-void gus_do_tempo(unsigned int tempo)
-{
-       DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
-         gus_timer_tempo(tempo);
-       gus_timer_start();
-}
-
-/* set voice frequency in Hz */
-void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
-{
-       DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
-         __pool_select_voice(voice);
-       __pool_command_w(PCMD_FREQ,
-                                        (((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
-}
-
-/* set voice pan (0-16384) (full left - full right) */
-void gus_do_voice_pan(unsigned char voice, unsigned short pan)
-{
-       DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
-         pan >>= 10;
-       if (pan > 15)
-               pan = 15;
-       __pool_select_voice(voice);
-       __pool_command_b(PCMD_PAN, pan);
-}
-
-/* set voice volume level 0-16384 (linear) */
-void gus_do_voice_volume(unsigned char voice, unsigned short vol)
-{
-       DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
-         if (vol > 0x3fff)
-               vol = 0x3fff;
-       __pool_select_voice(voice);
-       __pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
-}
-
-/* start voice
- *   voice    : voice #
- *   program  : program # or ~0 = current
- *   freq     : frequency in Hz
- *   volume   : volume level (0-16384) or ~0 = current
- *   pan      : pan level (0-16384) or ~0 = current
- */
-void gus_do_voice_start(unsigned char voice, unsigned int program,
-                                               unsigned int freq, unsigned short volume,
-                                               unsigned short pan)
-{
-       gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
-}
-
-/* start voice
- *   voice    : voice #
- *   program  : program # or ~0 = current
- *   freq     : frequency in Hz
- *   volume   : volume level (0-16384) or ~0 = current
- *   pan      : pan level (0-16384) or ~0 = current
- *   position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
- */
-void gus_do_voice_start_position(unsigned char voice, unsigned int program,
-                                                                unsigned int freq, unsigned short volume,
-                                                                unsigned short pan, unsigned int position)
-{
-       gus_instrument_t *instrument;
-       gus_wave_t *wave;
-
-       DEBUG_PRINT(
-                               ("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
-                                program, position))
-
-         instrument = __gus_instrument_get(program);
-
-       if (!instrument
-               || !instrument->info.layer
-               || !instrument->info.layer->wave
-               || instrument->flags == GUS_INSTR_F_NOT_FOUND
-               || instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
-
-       gus_do_voice_frequency(voice, freq);
-       gus_do_voice_pan(voice, pan);
-
-       /* We have to set volume different way, to avoid unneeded work in handler */
-       if (volume > 0x3fff)
-               volume = 0x3fff;
-       __pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
-
-       switch (instrument->mode) {
-         case GUS_INSTR_SIMPLE:
-               wave = instrument->info.layer->wave;
-               if (position)
-                       __pool_command_l(PCMD_OFFSET, position);
-               __pool_command_l(PCMD_START, (unsigned long)wave);
-               break;
-       }
-}
-
-/* stop voice
- *   mode = 0 : stop voice now
- *   mode = 1 : disable wave loop and finish it
- */
-void gus_do_voice_stop(unsigned char voice, unsigned char mode)
-{
-       __pool_select_voice(voice);
-       if (mode)
-               __pool_command(PCMD_STOP_LOOP);
-       else
-               __pool_command(PCMD_STOP);
-}
-
-/* wait x ticks - this command is block separator
-   all commands between blocks are interpreted in the begining of one tick */
-void gus_do_wait(unsigned int ticks)
-{
-       DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
-
-         ticks += gus.t1_ticks;
-       while ((int)(ticks - gus.t1_ticks) > 0);
-}
-
-int gus_get_voice_status(int voice)
-{
-       __gus_select_voice(voice);
-       return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
-}
-
-/* return value: file handle (descriptor) for /dev/gus */
-int gus_get_handle()
-{
-       /* Return stdout handle so that select() will "work" with it */
-       return 0;
-}
-
-/* return value: zero if instrument was successfully allocated */
-int gus_memory_alloc(gus_instrument_t * instrument)
-{
-       gus_instrument_t *instr = __gus_instrument_copy(instrument);
-       gus_layer_t *cur_layer;
-       gus_wave_t *cur_wave;
-
-       DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
-
-         if (!instr)
-               return -1;
-
-       for (cur_layer = instr->info.layer; cur_layer;
-                cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
-                                                                                  cur_wave;
-                                                                                  cur_wave = cur_wave->next) {
-                       if (cur_layer->mode == GUS_INSTR_SIMPLE) {
-                               cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
-                                                                                                                cur_wave->format &
-                                                                                                                GUS_WAVE_16BIT);
-                               if (cur_wave->begin.memory == (unsigned int)-1) {
-                                       __gus_instrument_free(instr);
-                                       return -1;
-                               }
-                               gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
-                                                        cur_wave->size, cur_wave->format);
-                       } else if (cur_layer->mode == GUS_INSTR_PATCH)
-                               /* not supported yet */ ;
-               }
-
-       return 0;
-}
-
-/* return value: zero if instrument was successfully removed */
-int gus_memory_free(gus_instrument_t * instrument)
-{
-       gus_instrument_t *cur_instr = gus.instr;
-
-       DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
-
-         for (; cur_instr; cur_instr = cur_instr->next)
-               if (cur_instr->number.instrument == instrument->number.instrument)
-                       return __gus_instrument_free(cur_instr);
-
-       return -1;
-}
-
-/* return value: unused gus memory in bytes */
-int gus_memory_free_size()
-{
-       return __gus_mem_get_free();
-}
-
-/* return value: zero if success */
-int gus_memory_pack()
-{
-       __gus_mem_pack();
-       return 0;
-}
-
-/* return value: gus memory size in bytes */
-int gus_memory_size()
-{
-       return gus.ram * 1024;
-}
-
-/* return value: current largest free block for 8-bit or 16-bit wave */
-int gus_memory_free_block(int w_16bit)
-{
-       return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
-}
-
-/* input value:        see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
-   return value: zero if samples & instruments was successfully removed        from
-   GF1 memory manager */
-int gus_memory_reset(int mode)
-{
-       __gus_mem_clear();
-       __gus_instruments_clear();
-       return 0;
-}
-
-/* return value: zero if command queue was successfully flushed */
-int gus_queue_flush()
-{
-       return 0;
-}
-
-/* input value: echo buffer size in items (if 0 - erase echo buffer) */
-int gus_queue_read_set_size(int items)
-{
-       return 0;
-}
-
-/* input value: write queue size in items (each item have 8 bytes) */
-int gus_queue_write_set_size(int items)
-{
-       return 0;
-}
-
-/* return value: zero if successfull */
-int gus_timer_start()
-{
-       gus.timer_ctl_reg |= GF1M_TIMER1;
-       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
-
-       gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
-       outportb(GF1_TIMER_CTRL, 0x04);
-       outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
-       return 0;
-}
-
-/* return value: zero if timer was stoped */
-int gus_timer_stop()
-{
-       gus.timer_ctl_reg &= ~GF1M_TIMER1;
-       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
-
-       gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
-       outportb(GF1_TIMER_CTRL, 0x04);
-       outportb(GF1_TIMER_DATA, gus.timer_ctl);
-       return 0;
-}
-
-/* return value: zero if setup was success */
-int gus_timer_tempo(int ticks)
-{
-       unsigned int counter;
-
-       /* Limit ticks per second to 1..1000 range */
-       if (ticks < 1)
-               ticks = 1;
-       if (ticks > 1000)
-               ticks = 1000;
-
-       /* GF1 timer1 period is 80 usecs, 12500 times per second */
-       counter = 1250000 / (ticks * gus.timer_base);
-       gus.t1_multiple = 1;
-       while (counter > 255) {
-               counter >>= 1;
-               gus.t1_multiple <<= 1;
-       }
-       gus.t1_countdown = gus.t1_multiple;
-       __gus_outregb(GF1R_TIMER1, 256 - counter);
-       return 0;
-}
-
-/* return value: zero if timer will be continue */
-int gus_timer_continue()
-{
-       return gus_timer_start();
-}
-
-/* return value: zero if setup was success (default timebase = 100) */
-int gus_timer_base(int base)
-{
-       gus.timer_base = base;
-       return 0;
-}
-
-void gus_timer_callback(void (*timer_callback) ())
-{
-       gus.timer_callback = timer_callback;
-}
-
-void gus_convert_delta(unsigned int type, unsigned char *dest,
-                                          unsigned char *src, size_t size)
-{
-       if (!(type & GUS_WAVE_DELTA))
-               return;
-
-       /* This doesn't depend much on wave signedness, since addition/subtraction
-          do not depend on operand signedness */
-       if (type & GUS_WAVE_16BIT) {
-               unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
-               while (size--) {
-                       delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
-                       src += sizeof(unsigned short);
-                       dest += sizeof(unsigned short);
-               }
-       } else {
-               unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
-               while (size--) {
-                       delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
-                       src++;
-                       dest++;
-               }
-       }
-}
-
-int gus_dma_usage (int use)
-{
-       if (gus.dma_buff)
-               return -1;
-       gus.transfer = __gus_transfer_io;
-       return 0;
-}
-
-#endif /* DRV_ULTRA */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosgus.h b/libs/mikmod/drivers/dos/dosgus.h
deleted file mode 100644 (file)
index ae3488a..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  $Id$
-
-  libGUS-alike definitions for DOS
-
-==============================================================================*/
-
-#ifndef __DOSGUS_H__
-#define __DOSGUS_H__
-
-#include <pc.h>
-#include "dosdma.h"
-#include "dosirq.h"
-#include "libgus.h"
-
-/* Private header file for a libGUS-alike library for DOS */
-
-#define JOYSTICK_TIMER                 (gus.port+0x201)        /* 201 */
-#define JOYSTICK_DATA                  (gus.port+0x201)        /* 201 */
-
-#define GF1_MIDI_CTRL                  (gus.port+0x100)        /* 3X0 */
-#define GF1_MIDI_DATA                  (gus.port+0x101)        /* 3X1 */
-
-#define GF1_VOICESEL                   (gus.port+0x102)        /* 3X2 */
-#define GF1_REGSEL                     (gus.port+0x103)        /* 3X3 */
-#define GF1_DATA                       (gus.port+0x104)        /* 3X4 */
-#define GF1_DATA_LOW                   (gus.port+0x104)        /* 3X4 */
-#define GF1_DATA_HIGH                  (gus.port+0x105)        /* 3X5 */
-#define GF1_IRQ_STATUS                 (gus.port+0x006)        /* 2X6 */
-#define GF1_DRAM                       (gus.port+0x107)        /* 3X7 */
-
-#define GF1_MIX_CTRL                   (gus.port+0x000)        /* 2X0 */
-#define GF1_TIMER_CTRL                 (gus.port+0x008)        /* 2X8 */
-#define GF1_TIMER_DATA                 (gus.port+0x009)        /* 2X9 */
-#define GF1_IRQ_CTRL                   (gus.port+0x00B)        /* 2XB */
-#define GF1_REG_CTRL                   (gus.port+0x00F)        /* 2XF */
-
-#define GF1_REVISION                   (gus.port+0x506)        /* 7X6 */
-
-/* The GF1 hardware clock rate */
-#define CLOCK_RATE                     9878400L
-
-/* GF1 voice-independent registers */
-#define        GF1R_DMA_CONTROL                0x41
-#define        GF1R_DMA_ADDRESS                0x42
-#define        GF1R_DRAM_LOW                   0x43
-#define        GF1R_DRAM_HIGH                  0x44
-
-#define        GF1R_TIMER_CONTROL              0x45
-#define        GF1R_TIMER1                     0x46
-#define        GF1R_TIMER2                     0x47
-
-#define        GF1R_SAMPLE_RATE                0x48
-#define        GF1R_SAMPLE_CONTROL             0x49
-
-#define        GF1R_JOYSTICK                   0x4B
-#define        GF1R_RESET                      0x4C
-
-/* GF1 voice-specific registers */
-#define        GF1R_VOICE_CONTROL              0x00
-#define        GF1R_FREQUENCY                  0x01
-#define        GF1R_START_HIGH                 0x02
-#define        GF1R_START_LOW                  0x03
-#define        GF1R_END_HIGH                   0x04
-#define        GF1R_END_LOW                    0x05
-#define        GF1R_VOLUME_RATE                0x06
-#define        GF1R_VOLUME_START               0x07
-#define        GF1R_VOLUME_END                 0x08
-#define        GF1R_VOLUME                     0x09
-#define        GF1R_ACC_HIGH                   0x0a
-#define        GF1R_ACC_LOW                    0x0b
-#define        GF1R_BALANCE                    0x0c
-#define        GF1R_VOLUME_CONTROL             0x0d
-#define        GF1R_VOICES                     0x0e
-#define        GF1R_IRQ_SOURCE                 0x0f
-
-/* Add this to above registers for reading */
-#define GF1R_READ_MASK                 0x80
-
-/* MIDI */
-#define        GF1M_MIDI_RESET                 0x03
-#define        GF1M_MIDI_ENABLE_XMIT           0x20
-#define        GF1M_MIDI_ENABLE_RCV            0x80
-
-#define        GF1M_MIDI_RCV_FULL              0x01
-#define        GF1M_MIDI_XMIT_EMPTY            0x02
-#define        GF1M_MIDI_FRAME_ERR             0x10
-#define        GF1M_MIDI_OVERRUN               0x20
-#define        GF1M_MIDI_IRQ_PEND              0x80
-
-/* Joystick */
-#define        GF1M_JOY_POSITION               0x0f
-#define        GF1M_JOY_BUTTONS                0xf0
-
-/* GF1_IRQ_STATUS (port 2X6) */
-#define        GF1M_IRQ_MIDI_TX                0x01    /* pending MIDI xmit IRQ */
-#define        GF1M_IRQ_MIDI_RX                0x02    /* pending MIDI recv IRQ */
-#define        GF1M_IRQ_TIMER1                 0x04    /* general purpose timer */
-#define        GF1M_IRQ_TIMER2                 0x08    /* general purpose timer */
-#define        GF1M_IRQ_WAVETABLE              0x20    /* pending wavetable IRQ */
-#define        GF1M_IRQ_ENVELOPE               0x40    /* pending volume envelope IRQ */
-#define        GF1M_IRQ_DMA_COMPLETE           0x80    /* pending dma transfer complete IRQ */
-
-/* GF1_MIX_CTRL (port 2X0) */
-#define        GF1M_MIXER_NO_LINE_IN           0x01    /* 0: enable */
-#define        GF1M_MIXER_NO_OUTPUT            0x02    /* 0: enable */
-#define        GF1M_MIXER_MIC_IN               0x04    /* 1: enable */
-#define        GF1M_MIXER_GF1_IRQ              0x08    /* 1: enable */
-#define GF1M_GF1_COMBINED_IRQ          0x10    /* 1: IRQ1 == IRQ2 */
-#define        GF1M_MIDI_LOOPBACK              0x20    /* 1: enable loop back */
-#define        GF1M_CONTROL_SELECT             0x40    /* 0: DMA latches; 1: IRQ latches */
-
-/* Timer data register (2X9) */
-#define GF1M_START_TIMER1              0x01
-#define GF1M_START_TIMER2              0x02
-#define GF1M_MASK_TIMER1               0x20
-#define GF1M_MASK_TIMER2               0x40
-#define GF1M_TIMER_CLRIRQ              0x80
-
-/* IRQ/DMA control register (2XB) */
-#define GF1M_IRQ_EQUAL                 0x40
-#define GF1M_DMA_EQUAL                 0x40
-
-/* (0x41) DMA control register bits */
-#define        GF1M_DMAR_ENABLE                0x01    /* 1: go */
-#define        GF1M_DMAR_READ                  0x02    /* 1: read (->RAM), 0: write (->DRAM) */
-#define        GF1M_DMAR_CHAN16                0x04    /* 1: 16 bit, 0: 8 bit DMA channel */
-#define        GF1M_DMAR_RATE                  0x18    /* 00: fast, 11: slow */
-#define        GF1M_DMAR_IRQ_ENABLE            0x20    /* 1: enable */
-#define        GF1M_DMAR_IRQ_PENDING           0x40    /* R: DMA irq pending */
-#define        GF1M_DMAR_DATA16                0x40    /* W: 0: 8 bits; 1: 16 bits per sample */
-#define        GF1M_DMAR_TOGGLE_SIGN           0x80    /* W: 1: invert high bit */
-
-/* DMA transfer rate divisors */
-#define        GF1M_DMAR_RATE0                 0x00    /* Fastest DMA xfer (~650khz) */
-#define        GF1M_DMAR_RATE1                 0x08    /* fastest / 2 */
-#define        GF1M_DMAR_RATE2                 0x10    /* fastest / 4 */
-#define        GF1M_DMAR_RATE3                 0x18    /* Slowest DMA xfer (fastest / 8) */
-
-/* (0x45) Timer Control */
-#define GF1M_TIMER1                    0x04    /* Enable timer 1 IRQ */
-#define GF1M_TIMER2                    0x08    /* Enable timer 2 IRQ */
-
-/* (0x49) Sampling (ADC) control register */
-#define        GF1M_DMAW_ENABLE                0x01    /* 1: Start sampling */
-#define        GF1M_DMAW_MODE                  0x02    /* 0: mono, 1: stereo */
-#define        GF1M_DMAW_CHAN16                0x04    /* 0: 8 bit, 1: 16 bit */
-#define        GF1M_DMAW_IRQ_ENABLE            0x20    /* 1: enable IRQ */
-#define        GF1M_DMAW_IRQ_PENDING           0x40    /* 1: irq pending */
-#define        GF1M_DMAW_TOGGLE_SIGN           0x80    /* 1: invert sign bit */
-
-/* (0x4C) GF1 reset register */
-#define        GF1M_MASTER_RESET               0x01    /* 0: hold in reset */
-#define        GF1M_OUTPUT_ENABLE              0x02    /* 1: enable output */
-#define        GF1M_MASTER_IRQ                 0x04    /* 1: master IRQ enable */
-
-/* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
-#define        GF1VC_STOPPED                   0x01    /* 1: voice has stopped */
-#define        GF1VC_STOP                      0x02    /* 1: stop voice */
-#define        GF1VC_DATA16                    0x04    /* 0: 8 bit, 1: 16 bit */
-#define        GF1VC_LOOP_ENABLE               0x08    /* 1: enable */
-#define        GF1VC_BI_LOOP                   0x10    /* 1: bi directional looping */
-#define        GF1VC_IRQ                       0x20    /* 1: enable voice's wave irq */
-#define        GF1VC_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
-#define        GF1VC_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
-
-/* (0x01,0x81) Frequency control */
-/* Bit 0       - Unused */
-/* Bits        1-9     - Fractional portion */
-/* Bits        10-15   - Integer portion */
-
-/* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
-/* Bits        0-11    - HIGH 12 bits of address */
-/* Bits        12-15   - Unused */
-
-/* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
-/* Bits        0-4     - Unused */
-/* Bits        5-8     - Fractional portion */
-/* Bits        9-15    - Low 7 bits of integer portion */
-
-/* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
-/* Bits        0-11    - HIGH 12 bits of address */
-/* Bits        12-15   - Unused */
-
-/* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
-/* Bits        0-4     - Unused */
-/* Bits        5-8     - Fractional portion */
-/* Bits        9-15    - Low 7 bits of integer portion */
-
-/* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
-#define        GF1VL_RATE_MANTISSA             0x3f
-#define        GF1VL_RATE_RANGE                0xC0
-
-/* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
-#define        GF1VL_START_MANT                0x0F
-#define        GF1VL_START_EXP                 0xF0
-
-/* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
-#define        GF1VL_END_MANT                  0x0F
-#define        GF1VL_END_EXP                   0xF0
-
-/* (0x09,0x89) Current volume register - GF1R_VOLUME */
-/* Bits        0-3     - Unused */
-/* Bits        4-11    - Mantissa of current volume */
-/* Bits        10-15   - Exponent of current volume */
-
-/* (0x0A,0x8A) Accumulator value (high) */
-/* Bits        0-12    - HIGH 12 bits of current position (a19-a7) */
-
-/* (0x0B,0x8B) Accumulator value (low) */
-/* Bits        0-8     - Fractional portion */
-/* Bits        9-15    - Integer portion of low adress (a6-a0) */
-
-/* (0x0C,0x8C) Pan (balance) position */
-/* Bits        0-3     - Balance position 0=full left, 0x0f=full right */
-
-/* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
-#define        GF1VL_STOPPED                   0x01    /* volume has stopped */
-#define        GF1VL_STOP                      0x02    /* stop volume */
-#define        GF1VL_ROLLOVER                  0x04    /* Roll PAST end & gen IRQ */
-#define        GF1VL_LOOP_ENABLE               0x08    /* 1: enable */
-#define        GF1VL_BI_LOOP                   0x10    /* 1: bi directional looping */
-#define        GF1VL_IRQ                       0x20    /* 1: enable voice's volume irq */
-#define        GF1VL_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
-#define        GF1VL_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
-
-/* (0x0E,0x8E) Number of active voices */
-/* Bits        0-5     - Number of active voices - 1 */
-
-/* (0x0F,0x8F) Sources of IRQs */
-/* Bits        0-4     - interrupting voice number */
-/* Bit 5       - Always a 1 */
-#define        GF1IRQ_VOLUME                   0x40    /* individual voice irq bit */
-#define        GF1IRQ_WAVE                     0x80    /* individual waveform irq bit */
-
-/* Commands are pooled and executed ON TIMER (1st timer) interrupt.
- * Currently there is a limit on the number of commands that you can
- * issue between gus_do_flush (...); this should not be an issue however
- * because each voice has a limited (little) set of parameters that
- * you can change (freq, vol, pan... what else?)
- *
- * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
- */
-
-/* Below are definitions for commands placed in GUS command pool */
-#define PCMD_NOP                       0x00    /* Traditionally ... */
-#define PCMD_VOICE                     0x01    /* +B: select voice */
-#define PCMD_START                     0x02    /* +L: start voice */
-#define PCMD_STOP                      0x03    /*     stop voice */
-#define PCMD_FREQ                      0x04    /* +W: set frequence */
-#define PCMD_VOLUME                    0x05    /* +W: set volume */
-#define PCMD_VOLUME_PREPARE            0x06    /* +W: prepare to set volume on (soon to follow) kick */
-#define PCMD_PAN                       0x07    /* +B: set panning */
-#define PCMD_OFFSET                    0x08    /* +L: set DRAM offset */
-#define PCMD_STOP_LOOP                 0x09    /*     stop looping */
-
-#define GUS_VOLCHANGE_RAMP             0x20    /* Volume change ramp speed */
-
-/* Definition for the boolean type */
-typedef unsigned char boolean;
-/* Prototype for functions that do block transfers to GUS DRAM:
-   flags can contain any of the following bits:
-   GUS_WAVE_16BIT    - sample is 16-bit
-   GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
- */
-typedef void (*__gus_transfer_func) (unsigned long address,
-                                     unsigned char *source,
-                                     unsigned long size, int flags);
-typedef void (*__gus_callback) ();
-typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
-
-/* Structure used to keep track of all on-board GUS memory */
-typedef struct __struct_gus_mcb {
-       struct __struct_gus_mcb *next;          /* Next MCB in chain */
-       struct __struct_gus_mcb *prev;          /* Previous MCB in chain */
-       unsigned int addr;                      /* GUS DRAM address */
-       unsigned int size;                      /* Memory block size */
-       int free;                               /* 1: block is free */
-} __gus_mcb;
-
-/* Structure defining overall GUS state/information */
-typedef struct __gus_state_s {
-       unsigned int port;                      /* Base I/O port (0x220, 0x240, ...) */
-       unsigned int irq[2];                    /* GF1 IRQ and MIDI IRQ */
-       unsigned int dma[2];                    /* Play / record DMA */
-       unsigned int ram;                       /* Memory size (K), i.e. 256, 1024 etc */
-       unsigned int version;                   /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
-       unsigned int freq;                      /* Current mixing frequency */
-       unsigned int voices;                    /* Active voices (14-32) */
-       unsigned int dynmask;                   /* Dynamically allocated voices mask */
-       unsigned int timer_base;                /* The relative timer speed in percents (def: 100) */
-       volatile unsigned int t1_ticks;         /* Incremented per each timer1 tick */
-       volatile unsigned int t2_ticks;         /* Incremented per each timer2 tick */
-       volatile unsigned int t1_countdown;     /* t1_callback is called when this reaches zero */
-       volatile unsigned int t2_countdown;     /* t2_callback is called when this reaches zero */
-       unsigned int t1_multiple;               /* Timer1 handler is called once per such many ticks */
-       unsigned int t2_multiple;               /* Timer2 handler is called once per such many ticks */
-       struct irq_handle *gf1_irq;             /* The interrupt handler for GF1 events */
-       dma_buffer *dma_buff;                   /* Pre-allocated DMA buffer */
-       __gus_callback dma_callback;            /* Routine called at end of DMA transfers */
-       __gus_callback t1_callback;             /* Routine called on Timer1 events */
-       __gus_callback t2_callback;             /* Routine called on Timer1 events */
-       __gus_callback timer_callback;          /* Called once per TEMPO ticks */
-       __gus_callback_3 wt_callback;           /* Routine called on WaveTable events */
-       __gus_callback_3 vl_callback;           /* Routine called on Volume ramp events */
-       __gus_mcb *mcb;                         /* Chained list of memory control blocks */
-       __gus_transfer_func transfer;           /* Best working function for DRAM transfer */
-       gus_instrument_t *instr;                /* The list of registered instruments */
-       unsigned short mixer;                   /* Current mixer register state */
-       unsigned char dma_rate;                 /* One of GF1M_DMAR_RATEX constants defined above */
-       unsigned char timer_ctl;                /* Timer control register value (2x8/2x9) */
-       unsigned char timer_ctl_reg;            /* Timer control register value (GF1/0x45) */
-       boolean ok;                             /* Is the information below okay? */
-       boolean open;                           /* 1 if between gus_open() and gus_close() */
-       boolean ics;                            /* Is it equipped with an ICS mixer? */
-       boolean ics_flipped;                    /* rev 5 (3.7) has flipped R/L mixer */
-       boolean codec;                          /* Is it equipped with a GUS MAX codec? */
-       boolean interwave;                      /* GUS InterWave card */
-       volatile boolean dma_active;            /* DMA is transferring data */
-       volatile boolean cmd_pool_ready;        /* Flush cmd_pool during timer interrupt */
-       unsigned char cmd_voice;                /* Pool selection index cache */
-       unsigned int cmd_pool_top;              /* Command pool top */
-       unsigned char *cmd_pool;                /* Async commands pool */
-       /* The following data is for private use only by interrupt routines! */
-       gus_wave_t *cur_wave[32];               /* Currently played waves */
-       boolean voice_kick[32];                 /* Kick wave on next volume ramp IRQ */
-       unsigned int kick_offs[32];             /* Sample start position on kick */
-       unsigned short cur_vol[32];             /* Current voice volumes */
-       unsigned int cur_voice;                 /* Current voice */
-       unsigned int eow_ignore;                /* Temp ignore end-of-wave IRQ for these voices */
-} __gus_state;
-
-extern __gus_state gus;
-extern void __gus_delay();
-
-static unsigned long __gus_convert_addr16(unsigned long address)
-{
-       return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
-}
-
-/* The XXX_slow routines cannot be used outside IRQ handler! */
-static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
-{
-       outportb(GF1_REGSEL, reg);
-       outportb(GF1_DATA_HIGH, value);
-       __gus_delay();
-       outportb(GF1_DATA_HIGH, value);
-}
-
-static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
-{
-       outportb(GF1_REGSEL, reg);
-       outportw(GF1_DATA, value);
-       __gus_delay();
-       outportw(GF1_DATA, value);
-}
-
-static inline void __gus_outregb(unsigned char reg, unsigned char value)
-{
-       outportb(GF1_REGSEL, reg);
-       outportb(GF1_DATA_HIGH, value);
-}
-
-static inline void __gus_outregw(unsigned char reg, unsigned short value)
-{
-       outportb(GF1_REGSEL, reg);
-       outportw(GF1_DATA, value);
-}
-
-static inline unsigned char __gus_inregb(unsigned char reg)
-{
-       if (reg < 0x10)
-               reg |= GF1R_READ_MASK;
-       outportb(GF1_REGSEL, reg);
-       return inportb(GF1_DATA_HIGH);
-}
-
-static inline unsigned short __gus_inregw(unsigned char reg)
-{
-       if (reg < 0x10)
-               reg |= GF1R_READ_MASK;
-       outportb(GF1_REGSEL, reg);
-       return inportw(GF1_DATA);
-}
-
-static inline void __gus_set_dram_address(unsigned int address)
-{
-       __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
-       __gus_outregw(GF1R_DRAM_LOW, address);
-}
-
-static inline unsigned char __gus_peek(unsigned int address)
-{
-       __gus_set_dram_address(address);
-       return inportb(GF1_DRAM);
-}
-
-static inline void __gus_poke(unsigned int address, unsigned char value)
-{
-       __gus_set_dram_address(address);
-       outportb(GF1_DRAM, value);
-}
-
-static inline void __gus_select_voice(unsigned char voice)
-{
-       outportb(GF1_VOICESEL, voice);
-}
-
-static inline void __gus_set_current(unsigned char mode,
-                                     unsigned long address)
-{
-       if (mode & GF1VC_DATA16)
-               address = __gus_convert_addr16(address);
-       __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
-       __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
-}
-
-static inline void __gus_set_loop_start(unsigned char mode,
-                                                                               unsigned long address)
-{
-       if (mode & GF1VC_DATA16)
-               address = __gus_convert_addr16(address);
-       __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
-       __gus_outregw_slow(GF1R_START_LOW, address << 5);
-}
-
-static inline void __gus_set_loop_end(unsigned char mode,
-                                      unsigned long address)
-{
-       address--;
-       if (mode & GF1VC_DATA16)
-               address = __gus_convert_addr16(address);
-       __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
-       __gus_outregw_slow(GF1R_END_LOW, address << 5);
-}
-
-static inline void __gus_mixer_output(boolean state)
-{
-       if (state)
-               gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
-       else
-               gus.mixer |= GF1M_MIXER_NO_OUTPUT;
-       outportb(GF1_MIX_CTRL, gus.mixer);
-       /* Dummy read to avoid touching DMA latches */
-       __gus_inregb(GF1R_BALANCE);
-}
-
-/* Inline routines for working with command pools */
-
-/* WARNING: no bounds checking due to performance reasons */
-#define __POOL_VALUE(type,value)                                                               \
-  *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value;        \
-  gus.cmd_pool_top += sizeof (type);
-
-static inline void __pool_command(unsigned char command)
-{
-       __POOL_VALUE(char, command);
-}
-
-static inline void __pool_command_b(unsigned char command, unsigned char arg)
-{
-       __POOL_VALUE(char, command);
-       __POOL_VALUE(char, arg);
-}
-
-static inline void __pool_command_w(unsigned char command, unsigned short arg)
-{
-       __POOL_VALUE(char, command);
-       __POOL_VALUE(short, arg);
-}
-
-static inline void __pool_command_l(unsigned char command, unsigned long arg)
-{
-       __POOL_VALUE(char, command);
-       __POOL_VALUE(long, arg);
-}
-
-static inline void __pool_select_voice(unsigned char voice)
-{
-       if (gus.cmd_voice != voice)
-               __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
-}
-
-#undef __POOL_VALUE
-
-#ifdef DEBUG
-/* Debug dump of GUS DRAM heap */
-extern void __gus_mem_dump();
-#endif
-
-#endif /* __DOSGUS_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosirq.c b/libs/mikmod/drivers/dos/dosirq.c
deleted file mode 100644 (file)
index 9b0e21f..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
-    Implementation of IRQ routines on DOS
-    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "dosirq.h"
-
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <malloc.h>
-#include <string.h>
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-unsigned int __irq_stack_size = 0x4000;
-unsigned int __irq_stack_count = 1;
-
-static void __int_stub_template (void)
-{
-/* *INDENT-OFF* */
-       asm("   pushal\n"
-               "       pushl   %ds\n"
-               "       pushl   %es\n"
-               "       pushl   %fs\n"
-               "       pushl   %gs\n"
-               "       movw    $0x1234,%ax\n"          /* Get DPMI data selector */
-               "       movw    %ax,%ds\n"                      /* Set DS and ES to data selector */
-               "       movw    %ax,%es\n"
-               "       movl    $0x12345678,%ebx\n"     /* Interrupt stack top */
-               "       movl    (%ebx),%ecx\n"
-               "       movl    %ecx,%edx\n"
-               "       subl    $0x12345678,%ecx\n"     /* Subtract irq_stack_count */
-               "       movl    %ecx,(%ebx)\n"
-               "       movw    %ss,%si\n"                      /* Save old SS:ESP */
-               "       movl    %esp,%edi\n"
-               "       movl    %edx,%esp\n"            /* Set SS:ESP to interrupt stack */
-               "       movw    %ax,%ss\n"
-               "       pushl   %esi\n"
-               "       pushl   %edi\n"
-               "       pushl   %ebx\n"
-               "       pushl   %edx\n"
-               "       call    1f\n"                           /* Call user interrupt handler */
-               "1:     popl    %edx\n"
-               "       popl    %ebx\n"
-               "       movl    %edx,(%ebx)\n"
-               "       popl    %edi\n"
-               "       popl    %esi\n"
-               "       movl    %edi,%esp\n"            /* Restore old SS:ESP */
-               "       movw    %si,%ss\n"
-               "       popl    %gs\n"
-               "       popl    %fs\n"
-               "       popl    %es\n"
-               "       popl    %ds\n"
-               "       popal\n"
-               "       iret\n");
-/* *INDENT-ON* */
-}
-
-#include <stdio.h>
-
-static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
-{
-       unsigned char *irqtpl = (unsigned char *)__int_stub_template;
-       unsigned char *irqend, *irqwrapper, *tmp;
-       __dpmi_meminfo handler_info;
-       unsigned int wrappersize;
-
-       /* First, skip until pushal */
-       while (*irqtpl != 0x60)
-               irqtpl++;
-       /* Now find the iret */
-       irqend = irqtpl;
-       while (*irqend++ != 0xcf);
-
-       wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
-         ((long)irqend - (long)irqtpl);
-       irqwrapper = (unsigned char *) MikMod_malloc(wrappersize);
-       /* Lock the wrapper */
-       handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
-       handler_info.size = wrappersize;
-       if (__dpmi_lock_linear_region(&handler_info)) {
-               MikMod_free(irqwrapper);
-               return -1;
-       }
-
-       /* First comes the interrupt wrapper size */
-       *(unsigned long *)irqwrapper = wrappersize;
-
-       /* Next comes the interrupt stack */
-       tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
-
-       /* The following dword is interrupt stack pointer */
-       *((void **)tmp) = tmp;
-       tmp += 4;
-
-       /* Now comes the interrupt wrapper itself */
-       memcpy(tmp, irqtpl, irqend - irqtpl);
-       *(unsigned short *)(tmp + 9) = _my_ds();
-       *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
-       *(unsigned long *)(tmp + 26) = __irq_stack_size;
-       *(unsigned long *)(tmp + 46) =
-         info->pm_offset - (unsigned long)(tmp + 50);
-
-       info->pm_offset = (unsigned long)tmp;
-       info->pm_selector = _my_cs();
-
-       return 0;
-}
-
-static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
-{
-       __dpmi_meminfo handler_info;
-
-       info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
-
-       handler_info.address = __djgpp_base_address + info->pm_offset;
-       handler_info.size = *(unsigned long *)info->pm_offset;
-       __dpmi_unlock_linear_region(&handler_info);
-
-       MikMod_free((void *)info->pm_offset);
-}
-
-struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size)
-{
-       int interrupt;
-       struct irq_handle *irq;
-       __dpmi_version_ret version;
-       __dpmi_meminfo handler_info, struct_info;
-       _go32_dpmi_seginfo info;
-       unsigned long old_sel, old_ofs;
-
-       __dpmi_get_version(&version);
-       if (irqno < 8)
-               interrupt = version.master_pic + irqno;
-       else
-               interrupt = version.slave_pic + (irqno - 8);
-
-       if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
-               return NULL;
-
-       old_sel = info.pm_selector;
-       old_ofs = info.pm_offset;
-
-       info.pm_offset = (unsigned long)handler;
-       if (_allocate_iret_wrapper(&info))
-               return NULL;
-
-       /* Lock the interrupt handler in memory */
-       handler_info.address = __djgpp_base_address + (unsigned long)handler;
-       handler_info.size = size;
-       if (__dpmi_lock_linear_region(&handler_info)) {
-               _free_iret_wrapper(&info);
-               return NULL;
-       }
-
-       irq = (struct irq_handle *) MikMod_malloc(sizeof(struct irq_handle));
-       irq->c_handler = handler;
-       irq->handler_size = size;
-       irq->handler = info.pm_offset;
-       irq->prev_selector = old_sel;
-       irq->prev_offset = old_ofs;
-       irq->int_num = interrupt;
-       irq->irq_num = irqno;
-       irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
-
-       struct_info.address = __djgpp_base_address + (unsigned long)irq;
-       struct_info.size = sizeof(struct irq_handle);
-       if (__dpmi_lock_linear_region(&struct_info)) {
-               MikMod_free(irq);
-               __dpmi_unlock_linear_region(&handler_info);
-               _free_iret_wrapper(&info);
-               return NULL;
-       }
-
-       _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
-
-       irq->pic_mask = irq_state(irq);
-       return irq;
-}
-
-void irq_unhook(struct irq_handle *irq)
-{
-       _go32_dpmi_seginfo info;
-       __dpmi_meminfo mem_info;
-
-       if (!irq)
-               return;
-
-       /* Restore the interrupt vector */
-       irq_disable(irq);
-       info.pm_offset = irq->prev_offset;
-       info.pm_selector = irq->prev_selector;
-       _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
-
-       /* Unlock the interrupt handler */
-       mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
-       mem_info.size = irq->handler_size;
-       __dpmi_unlock_linear_region(&mem_info);
-
-       /* Unlock the irq_handle structure */
-       mem_info.address = __djgpp_base_address + (unsigned long)irq;
-       mem_info.size = sizeof(struct irq_handle);
-       __dpmi_unlock_linear_region(&mem_info);
-
-       info.pm_offset = irq->handler;
-       _free_iret_wrapper(&info);
-
-       /* If IRQ was enabled before we hooked, restore enabled state */
-       if (irq->pic_mask)
-               irq_enable(irq);
-       else
-               irq_disable(irq);
-
-       MikMod_free(irq);
-}
-
-/*---------------------------------------------- IRQ detection mechanism -----*/
-static struct irq_handle *__irqs[16];
-static int (*__irq_confirm) (int irqno);
-static volatile unsigned int __irq_mask;
-static volatile unsigned int __irq_count[16];
-
-#define DECLARE_IRQ_HANDLER(irqno)                                                     \
-static void __irq##irqno##_handler ()                                          \
-{                                                                                                                      \
-  if (irq_check (__irqs [irqno]) && __irq_confirm (irqno))     \
-  {                                                                                                                    \
-    __irq_count [irqno]++;                                                                     \
-    __irq_mask |= (1 << irqno);                                                                \
-  }                                                                                                                    \
-  irq_ack (__irqs [irqno]);                                                                    \
-}
-
-/* *INDENT-OFF* */
-DECLARE_IRQ_HANDLER(0)
-DECLARE_IRQ_HANDLER(1)
-DECLARE_IRQ_HANDLER(2)
-DECLARE_IRQ_HANDLER(3)
-DECLARE_IRQ_HANDLER(4)
-DECLARE_IRQ_HANDLER(5)
-DECLARE_IRQ_HANDLER(6)
-DECLARE_IRQ_HANDLER(7)
-DECLARE_IRQ_HANDLER(8)
-DECLARE_IRQ_HANDLER(9)
-DECLARE_IRQ_HANDLER(10)
-DECLARE_IRQ_HANDLER(11)
-DECLARE_IRQ_HANDLER(12)
-DECLARE_IRQ_HANDLER(13)
-DECLARE_IRQ_HANDLER(14)
-DECLARE_IRQ_HANDLER(15)
-/* *INDENT-ON* */
-
-static void (*__irq_handlers[16]) () = {
-       __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
-         __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
-         __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
-         __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
-
-void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
-{
-       int i;
-
-       __irq_mask = 0;
-       __irq_confirm = irq_confirm;
-       memset(&__irqs, 0, sizeof(__irqs));
-       memset((void *) &__irq_count, 0, sizeof(__irq_count));
-
-       /* Hook all specified IRQs */
-       for (i = 1; i <= 15; i++)
-               if (irqs & (1 << i)) {
-                       __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
-                       /* Enable the interrupt */
-                       irq_enable(__irqs[i]);
-               }
-       /* Enable IRQ2 if we need at least one IRQ above 7 */
-       if (irqs & 0xff00)
-               _irq_enable(2);
-}
-
-void irq_detect_end()
-{
-       int i;
-       for (i = 15; i >= 1; i--)
-               if (__irqs[i])
-                       irq_unhook(__irqs[i]);
-}
-
-int irq_detect_get(int irqno, unsigned int *irqmask)
-{
-       int oldirq = disable();
-       int count = __irq_count[irqno];
-       *irqmask = __irq_mask;
-       __irq_mask = 0;
-       if (oldirq)
-               enable();
-       return count;
-}
-
-void irq_detect_clear()
-{
-       int oldirq = disable();
-       memset((void *) &__irq_count, 0, sizeof(__irq_count));
-       __irq_mask = 0;
-       if (oldirq)
-               enable();
-}
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosirq.h b/libs/mikmod/drivers/dos/dosirq.h
deleted file mode 100644 (file)
index eaf60a1..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-    Interface for IRQ routines on DOS
-    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __DOSIRQ_H__
-#define __DOSIRQ_H__
-
-#include <pc.h>
-
-#define PIC1_BASE      0x20            /* PIC1 base */
-#define PIC2_BASE      0xA0            /* PIC2 base */
-
-struct irq_handle {
-       void (*c_handler) ();           /* The real interrupt handler */
-       unsigned long handler_size;     /* The size of interrupt handler */
-       unsigned long handler;          /* Interrupt wrapper address */
-       unsigned long prev_selector;    /* Selector of previous handler */
-       unsigned long prev_offset;      /* Offset of previous handler */
-       unsigned char irq_num;          /* IRQ number */
-       unsigned char int_num;          /* Interrupt number */
-       unsigned char pic_base;         /* PIC base (0x20 or 0xA0) */
-       unsigned char pic_mask;         /* Old PIC mask state */
-};
-
-/* Return the enabled state for specific IRQ */
-static inline unsigned char irq_state(struct irq_handle * irq)
-{
-       return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7)));
-}
-
-/* Acknowledge the end of interrupt */
-static inline void _irq_ack(int irqno)
-{
-       outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7));
-       /* For second controller we also should acknowledge first controller */
-       if (irqno > 7)
-               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
-}
-
-/* Acknowledge the end of interrupt */
-static inline void irq_ack(struct irq_handle * irq)
-{
-       outportb(irq->pic_base, 0x60 | (irq->irq_num & 7));
-       /* For second controller we also should acknowledge first controller */
-       if (irq->pic_base != PIC1_BASE)
-               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
-}
-
-/* Mask (disable) the particular IRQ given his ordinal */
-static inline void _irq_disable(int irqno)
-{
-       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
-       outportb(port_no, inportb(port_no) | (1 << (irqno & 7)));
-}
-
-/* Unmask (enable) the particular IRQ given its ordinal */
-static inline void _irq_enable(int irqno)
-{
-       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
-       outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7)));
-}
-
-/* Mask (disable) the particular IRQ given its irq_handle structure */
-static inline void irq_disable(struct irq_handle * irq)
-{
-       outportb(irq->pic_base + 1,
-                 inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7)));
-}
-
-/* Unmask (enable) the particular IRQ given its irq_handle structure */
-static inline void irq_enable(struct irq_handle * irq)
-{
-       outportb(irq->pic_base + 1,
-                 inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7)));
-}
-
-/* Check if a specific IRQ is pending: return 0 is no */
-static inline int irq_check(struct irq_handle * irq)
-{
-       outportb(irq->pic_base, 0x0B);  /* Read IRR vector */
-       return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7)));
-}
-
-/* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */
-extern struct irq_handle *irq_hook(int irqno, void (*handler)(),
-                                   unsigned long size);
-/* Unhook a previously hooked IRQ */
-extern void irq_unhook(struct irq_handle * irq);
-/* Start IRQ detection process (IRQ list is given with irq mask) */
-/* irq_confirm should return "1" if the IRQ really comes from the device */
-extern void irq_detect_start(unsigned int irqs,
-                             int (*irq_confirm) (int irqno));
-/* Finish IRQ detection process */
-extern void irq_detect_end();
-/* Get the count of specific irqno that happened */
-extern int irq_detect_get(int irqno, unsigned int *irqmask);
-/* Clear IRQ counters */
-extern void irq_detect_clear();
-
-/* The size of interrupt stack */
-extern unsigned int __irq_stack_size;
-/* The number of nested interrupts that can be handled */
-extern unsigned int __irq_stack_count;
-
-#endif /* __DOSIRQ_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dossb.c b/libs/mikmod/drivers/dos/dossb.c
deleted file mode 100644 (file)
index 344ac85..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  Sound Blaster I/O routines, common for SB8, SBPro and SB16
-  Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_SB
-
-#include <stdlib.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <sys/farptr.h>
-#include <string.h>
-
-#include "dossb.h"
-
-/********************************************* Private variables/routines *****/
-
-__sb_state sb;
-
-/* Wait for SoundBlaster for some time */
-#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
-# define _func_noinline volatile /* match original code */
-# define _func_noclone
-#else
-/* avoid warnings from newer gcc:
- * "function definition has qualified void return type" and
- * function return types not compatible due to 'volatile' */
-# define _func_noinline __attribute__((__noinline__))
-# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
-#  define _func_noclone
-# else
-#  define _func_noclone __attribute__((__noclone__))
-# endif
-#endif
-_func_noinline
-_func_noclone
- void __sb_wait()
-{
-       inportb(SB_DSP_RESET);
-       inportb(SB_DSP_RESET);
-       inportb(SB_DSP_RESET);
-       inportb(SB_DSP_RESET);
-       inportb(SB_DSP_RESET);
-       inportb(SB_DSP_RESET);
-}
-
-static void sb_irq()
-{
-       /* Make sure its not a spurious IRQ */
-       if (!irq_check(sb.irq_handle))
-               return;
-
-       sb.irqcount++;
-
-       /* Acknowledge DMA transfer is complete */
-       if (sb.mode & SBMODE_16BITS)
-               __sb_dsp_ack_dma16();
-       else
-               __sb_dsp_ack_dma8();
-
-       /* SoundBlaster 1.x cannot do autoinit ... */
-       if (sb.dspver < SBVER_20)
-               __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
-
-       /* Send EOI */
-       irq_ack(sb.irq_handle);
-
-       enable();
-       if (sb.timer_callback)
-               sb.timer_callback();
-}
-
-static void sb_irq_end()
-{
-}
-
-static boolean __sb_reset()
-{
-       /* Disable the output */
-       sb_output(FALSE);
-
-       /* Clear pending ints if any */
-       __sb_dsp_ack_dma8();
-       __sb_dsp_ack_dma16();
-
-       /* Reset the DSP */
-       outportb(SB_DSP_RESET, SBM_DSP_RESET);
-       __sb_wait();
-       __sb_wait();
-       outportb(SB_DSP_RESET, 0);
-
-       /* Now wait for AA coming from datain port */
-       if (__sb_dsp_in() != 0xaa)
-               return FALSE;
-
-       /* Finally, get the DSP version */
-       if ((sb.dspver = __sb_dsp_version()) == 0xffff)
-               return FALSE;
-       /* Check again */
-       if (sb.dspver != __sb_dsp_version())
-               return FALSE;
-
-       return TRUE;
-}
-
-/***************************************************** SB detection stuff *****/
-
-static int __sb_irq_irqdetect(int irqno)
-{
-       __sb_dsp_ack_dma8();
-       return 1;
-}
-
-static void __sb_irq_dmadetect()
-{
-       /* Make sure its not a spurious IRQ */
-       if (!irq_check(sb.irq_handle))
-               return;
-
-       sb.irqcount++;
-
-       /* Acknowledge DMA transfer is complete */
-       if (sb.mode & SBMODE_16BITS)
-               __sb_dsp_ack_dma16();
-       else
-               __sb_dsp_ack_dma8();
-
-       /* Send EOI */
-       irq_ack(sb.irq_handle);
-}
-
-static boolean __sb_detect()
-{
-       /* First find the port number */
-       if (!sb.port) {
-               int i;
-               for (i = 5; i >= 0; i--) {
-                       sb.port = 0x210 + i * 0x10;
-                       if (__sb_reset())
-                               break;
-               }
-               if (i < 0) {
-                       sb.port = 0;
-                       return FALSE;
-               }
-       }
-
-       /* Now detect the IRQ and DMA numbers */
-       if (!sb.irq) {
-               unsigned int irqmask, sbirqmask, sbirqcount;
-               unsigned long timer;
-
-               /* IRQ can be one of 2,3,5,7,10 */
-               irq_detect_start(0x04ac, __sb_irq_irqdetect);
-
-               /* Prepare timeout counter */
-               _farsetsel(_dos_ds);
-               timer = _farnspeekl(0x46c);
-
-               sbirqmask = 0;
-               sbirqcount = 10;                /* Emit 10 SB irqs */
-
-               /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
-               __sb_dsp_out(SBDSP_GEN_IRQ8);
-               __sb_wait();
-               for (;;) {
-                       irq_detect_get(0, &irqmask);
-                       if (irqmask) {
-                               sbirqmask |= irqmask;
-                               if (!--sbirqcount)
-                                       break;
-                               __sb_dsp_out(SBDSP_GEN_IRQ8);
-                       }
-                       if (_farnspeekl(0x46c) - timer >= 9)    /* Wait ~1/2 secs */
-                               break;
-               }
-               if (sbirqmask)
-                       for (sb.irq = 15; sb.irq > 0; sb.irq--)
-                               if (irq_detect_get(sb.irq, &irqmask) == 10)
-                                       break;
-
-               irq_detect_end();
-               if (!sb.irq)
-                       return FALSE;
-       }
-
-       /* Detect the 8-bit and 16-bit DMAs */
-       if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
-               static int __dma8[] = { 0, 1, 3 };
-               static int __dma16[] = { 5, 6, 7 };
-               int *dma;
-
-               sb_output(FALSE);
-               /* Temporary hook SB IRQ */
-               sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
-               irq_enable(sb.irq_handle);
-               if (sb.irq > 7)
-                       _irq_enable(2);
-
-               /* Start a short DMA transfer and check if IRQ happened */
-               for (;;) {
-                       int i;
-                       unsigned int timer, oldcount;
-
-                       if (!sb.dma8)
-                               dma = &sb.dma8;
-                       else if ((sb.dspver >= SBVER_16) && !sb.dma16)
-                               dma = &sb.dma16;
-                       else
-                               break;
-
-                       for (i = 0; i < 3; i++) {
-                               boolean success = 1;
-
-                               *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
-                               oldcount = sb.irqcount;
-
-                               dma_disable(*dma);
-                               dma_set_mode(*dma, DMA_MODE_WRITE);
-                               dma_clear_ff(*dma);
-                               dma_set_count(*dma, 2);
-                               dma_enable(*dma);
-
-                               __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
-                               if (dma == &sb.dma8) {
-                                       sb.mode = 0;
-                                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
-                               } else {
-                                       sb.mode = SBMODE_16BITS;
-                                       __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
-                                       __sb_dsp_out(0);
-                                       __sb_dsp_out(1);
-                               }
-
-                               _farsetsel(_dos_ds);
-                               timer = _farnspeekl(0x46c);
-
-                               while (oldcount == sb.irqcount)
-                                       if (_farnspeekl(0x46c) - timer >= 2) {
-                                               success = 0;
-                                               break;
-                                       }
-                               dma_disable(*dma);
-                               if (success)
-                                       break;
-                               *dma = 0;
-                       }
-                       if (!*dma)
-                               break;
-               }
-
-               irq_unhook(sb.irq_handle);
-               sb.irq_handle = NULL;
-               if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-/*************************************************** High-level interface *****/
-
-/* Detect whenever SoundBlaster is present and fill "sb" structure */
-boolean sb_detect()
-{
-       char *env;
-
-       /* Try to find the port and DMA from environment */
-       env = getenv("BLASTER");
-
-       while (env && *env) {
-               /* Skip whitespace */
-               while ((*env == ' ') || (*env == '\t'))
-                       env++;
-               if (!*env)
-                       break;
-
-               switch (*env++) {
-                 case 'A':
-                 case 'a':
-                       if (!sb.port)
-                               sb.port = strtol(env, &env, 16);
-                       break;
-                 case 'E':
-                 case 'e':
-                       if (!sb.aweport)
-                               sb.aweport = strtol(env, &env, 16);
-                       break;
-                 case 'I':
-                 case 'i':
-                       if (!sb.irq)
-                               sb.irq = strtol(env, &env, 10);
-                       break;
-                 case 'D':
-                 case 'd':
-                       if (!sb.dma8)
-                               sb.dma8 = strtol(env, &env, 10);
-                       break;
-                 case 'H':
-                 case 'h':
-                       if (!sb.dma16)
-                               sb.dma16 = strtol(env, &env, 10);
-                       break;
-                 default:
-                       /* Skip other values (H == MIDI, T == model, any other?) */
-                       while (*env && (*env != ' ') && (*env != '\t'))
-                               env++;
-                       break;
-               }
-       }
-
-       /* Try to detect missing sound card parameters */
-       __sb_detect();
-
-       if (!sb.port || !sb.irq || !sb.dma8)
-               return FALSE;
-
-       if (!__sb_reset())
-               return FALSE;
-
-       if ((sb.dspver >= SBVER_16) && !sb.dma16)
-               return FALSE;
-
-       if (sb.dspver >= SBVER_PRO)
-               sb.caps |= SBMODE_STEREO;
-       if (sb.dspver >= SBVER_16 && sb.dma16)
-               sb.caps |= SBMODE_16BITS;
-       if (sb.dspver < SBVER_20)
-               sb.maxfreq_mono = 22222;
-       else
-               sb.maxfreq_mono = 45454;
-       if (sb.dspver <= SBVER_16)
-               sb.maxfreq_stereo = 22727;
-       else
-               sb.maxfreq_stereo = 45454;
-
-       sb.ok = 1;
-       return TRUE;
-}
-
-/* Reset SoundBlaster */
-void sb_reset()
-{
-       sb_stop_dma();
-       __sb_reset();
-}
-
-/* Start working with SoundBlaster */
-boolean sb_open()
-{
-       __dpmi_meminfo struct_info;
-
-       if (!sb.ok)
-               if (!sb_detect())
-                       return FALSE;
-
-       if (sb.open)
-               return FALSE;
-
-       /* Now lock the sb structure in memory */
-       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
-       struct_info.size = sizeof(sb);
-       if (__dpmi_lock_linear_region(&struct_info))
-               return FALSE;
-
-       /* Hook the SB IRQ */
-       sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
-       if (!sb.irq_handle) {
-               __dpmi_unlock_linear_region(&struct_info);
-               return FALSE;
-       }
-
-       /* Enable the interrupt */
-       irq_enable(sb.irq_handle);
-       if (sb.irq > 7)
-               _irq_enable(2);
-
-       sb.open++;
-
-       return TRUE;
-}
-
-/* Finish working with SoundBlaster */
-boolean sb_close()
-{
-       __dpmi_meminfo struct_info;
-       if (!sb.open)
-               return FALSE;
-
-       sb.open--;
-
-       /* Stop/free DMA buffer */
-       sb_stop_dma();
-
-       /* Unhook IRQ */
-       irq_unhook(sb.irq_handle);
-       sb.irq_handle = NULL;
-
-       /* Unlock the sb structure */
-       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
-       struct_info.size = sizeof(sb);
-       __dpmi_unlock_linear_region(&struct_info);
-
-       return TRUE;
-}
-
-/* Enable/disable stereo DSP mode */
-/* Enable/disable speaker output */
-void sb_output(boolean enable)
-{
-       __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
-}
-
-/* Start playing from DMA buffer */
-boolean sb_start_dma(unsigned char mode, unsigned int freq)
-{
-       int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
-       int dmabuffsize;
-       unsigned int tc = 0;            /* timing constant (<=sbpro only) */
-
-       /* Stop DMA transfer if it is enabled */
-       sb_stop_dma();
-
-       /* Sanity check */
-       if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
-               return FALSE;
-
-       /* Check this SB can perform at requested frequency */
-       if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
-               || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
-               return FALSE;
-
-       /* Check the timing constant here to avoid failing later */
-       if (sb.dspver < SBVER_16) {
-               /* SBpro cannot do signed transfer */
-               if (mode & SBMODE_SIGNED)
-                       return FALSE;
-
-               /* Old SBs have a different way on setting DMA timing constant */
-               tc = freq;
-               if (mode & SBMODE_STEREO)
-                       tc *= 2;
-               tc = 1000000 / tc;
-               if (tc > 255)
-                       return FALSE;
-       }
-
-       sb.mode = mode;
-
-       /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
-       dmabuffsize = freq;
-       if (mode & SBMODE_STEREO)
-               dmabuffsize *= 2;
-       if (mode & SBMODE_16BITS)
-               dmabuffsize *= 2;
-       dmabuffsize >>= 2;
-       if (dmabuffsize < 4096)
-               dmabuffsize = 4096;
-       if (dmabuffsize > 32768)
-               dmabuffsize = 32768;
-       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
-
-       sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
-       if (!sb.dma_buff)
-               return FALSE;
-
-       /* Fill DMA buffer with silence */
-       dmabuffsize = sb.dma_buff->size;
-       if (mode & SBMODE_SIGNED)
-               memset(sb.dma_buff->linear, 0, dmabuffsize);
-       else
-               memset(sb.dma_buff->linear, 0x80, dmabuffsize);
-
-       /* Prime DMA for transfer */
-       dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-
-       /* Tell SoundBlaster to start transfer */
-       if (sb.dspver >= SBVER_16) {    /* SB16 */
-               __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
-
-               /* Start DMA->DAC transfer */
-               __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO |
-                                               ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
-                                                SBDSP_DMA_GENERIC8),
-                                               ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
-                                               ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
-
-               /* Write the length of transfer */
-               dmabuffsize = (dmabuffsize >> 2) - 1;
-               __sb_dsp_out(dmabuffsize);
-               __sb_dsp_out(dmabuffsize >> 8);
-       } else {
-               __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
-               dmabuffsize = (dmabuffsize >> 1) - 1;
-               if (sb.dspver >= SBVER_20) {    /* SB 2.0/Pro */
-                       /* Set stereo mode */
-                       __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
-                       __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
-                       if (sb.dspver >= SBVER_PRO)
-                               __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
-                       else
-                               __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
-               } else {                                /* Original SB */
-                       /* Start DMA->DAC transfer */
-                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
-               }
-       }
-
-       return TRUE;
-}
-
-/* Stop playing from DMA buffer */
-void sb_stop_dma()
-{
-       if (!sb.dma_buff)
-               return;
-
-       if (sb.mode & SBMODE_16BITS)
-               __sb_dsp_out(SBDSP_DMA_HALT16);
-       else
-               __sb_dsp_out(SBDSP_DMA_HALT8);
-
-       dma_disable(sb.dma_buff->channel);
-       dma_free(sb.dma_buff);
-       sb.dma_buff = NULL;
-}
-
-/* Query current position/total size of the DMA buffer */
-void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
-{
-       unsigned int dma_left;
-       *dma_size = sb.dma_buff->size;
-       /* It can happen we try to read DMA count when HI/LO bytes will be
-          inconsistent */
-       for (;;) {
-               unsigned int dma_left_test;
-               dma_clear_ff(sb.dma_buff->channel);
-               dma_left_test = dma_get_count(sb.dma_buff->channel);
-               dma_left = dma_get_count(sb.dma_buff->channel);
-               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
-                       break;
-       }
-       *dma_pos = *dma_size - dma_left;
-}
-
-#endif /* DRV_SB */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dossb.h b/libs/mikmod/drivers/dos/dossb.h
deleted file mode 100644 (file)
index cb8dc70..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  $Id$
-
-  SoundBlaster and compatible soundcards definitions
-
-==============================================================================*/
-
-#ifndef __DOSSB_H__
-#define __DOSSB_H__
-
-#include "dosdma.h"
-#include "dosirq.h"
-
-#define SB_FM_LEFT_STATUS              (sb.port + 0x00)        /* (r) Left FM status */
-#define SB_FM_LEFT_REGSEL              (sb.port + 0x00)        /* (w) Left FM register select */
-#define SB_FM_LEFT_DATA                        (sb.port + 0x01)        /* (w) Left FM data */
-#define SB_FM_RIGHT_STATUS             (sb.port + 0x02)        /* (r) Right FM status */
-#define SB_FM_RIGHT_REGSEL             (sb.port + 0x02)        /* (w) Right FM register select */
-#define SB_FM_RIGHT_DATA               (sb.port + 0x03)        /* (w) Right FM data */
-#define SB_MIXER_REGSEL                        (sb.port + 0x04)        /* (w) Mixer register select */
-#define SB_MIXER_DATA                  (sb.port + 0x05)        /* (rw)Mixer data */
-#define SB_DSP_RESET                   (sb.port + 0x06)        /* (w) DSP reset */
-#define SB_FM_STATUS                   (sb.port + 0x08)        /* (r) FM status */
-#define SB_FM_REGSEL                   (sb.port + 0x08)        /* (w) FM register select */
-#define SB_FM_DATA                     (sb.port + 0x09)        /* (w) FM data */
-#define SB_DSP_DATA_IN                 (sb.port + 0x0a)        /* (r) DSP data input */
-#define SB_DSP_DATA_OUT                        (sb.port + 0x0c)        /* (w) DSP data output */
-#define SB_DSP_DATA_OUT_STATUS         (sb.port + 0x0c)        /* (r) DSP data output status */
-#define SB_DSP_TIMER_IRQ               (sb.port + 0x0d)        /* (r) clear timer IRQ? */
-#define SB_DSP_DATA_IN_STATUS          (sb.port + 0x0e)        /* (r) DSP data input status */
-#define SB_DSP_DMA8_IRQ                        (sb.port + 0x0e)        /* (r) Acknowledge 8-bit DMA transfer */
-#define SB_DSP_DMA16_IRQ               (sb.port + 0x0f)        /* (r) Acknowledge 16-bit DMA transfer */
-
-/* DSP commands */
-#define SBDSP_ASP_STATUS               0x03    /* ASP Status (SB16ASP) */
-#define SBDSP_STATUS_OLD               0x04    /* DSP Status (Obsolete) (SB2.0-Pro2) */
-#define SBDSP_DIRECT_DAC               0x10    /* Direct DAC, 8-bit (SB) */
-#define SBDSP_DMA_PCM8                 0x14    /* DMA DAC, 8-bit (SB) */
-#define SBDSP_DMA_ADPCM2               0x16    /* DMA DAC, 2-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM2R              0x17    /* DMA DAC, 2-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_PCM8_AUTO            0x1C    /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */
-#define SBDSP_DMA_ADPCM2R_AUTO         0x1F    /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DIRECT_ADC               0x20    /* Direct ADC, 8-bit (SB) */
-#define SBDSP_DMA_ADC8                 0x24    /* DMA ADC, 8-bit (SB) */
-#define SBDSP_DIRECT_ADC8_BURST                0x28    /* Direct ADC, 8-bit (Burst) (SB-Pro2) */
-#define SBDSP_DMA_ADC8_AUTO            0x2C    /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */
-#define SBDSP_MIDI_READ_POLL           0x30    /* MIDI Read Poll (SB) */
-#define SBDSP_MIDI_READ_IRQ            0x31    /* MIDI Read Interrupt (SB) */
-#define SBDSP_MIDI_READ_TIME           0x32    /* MIDI Read Timestamp Poll (SB???) */
-#define SBDSP_MIDI_READ_TIME_IRQ       0x33    /* MIDI Read Timestamp Interrupt (SB???) */
-#define SBDSP_MIDI_RW_POLL             0x34    /* MIDI Read Poll + Write Poll (UART) (SB2.0) */
-#define SBDSP_MIDI_RW_IRQ              0x35    /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */
-#define SBDSP_MIDI_RW_TIME_IRQ         0x37    /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */
-#define SBDSP_MIDI_WRITE_POLL          0x38    /* MIDI Write Poll (SB) */
-#define SBDSP_SET_TIMING               0x40    /* Set Time Constant (SB) */
-#define SBDSP_SET_RATE                 0x41    /* Set Sample Rate, Hz (SB16) */
-#define SBDSP_DMA_CONT8_AUTO           0x45    /* Continue Auto-Initialize DMA, 8-bit (SB16) */
-#define SBDSP_DMA_CONT16_AUTO          0x47    /* Continue Auto-Initialize DMA, 16-bit (SB16) */
-#define SBDSP_SET_DMA_BLOCK            0x48    /* Set DMA Block Size (SB2.0) */
-#define SBDSP_DMA_ADPCM4               0x74    /* DMA DAC, 4-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM4_REF           0x75    /* DMA DAC, 4-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_ADPCM26              0x76    /* DMA DAC, 2.6-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM26_REF          0x77    /* DMA DAC, 2.6-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_ADPCM4R_AUTO         0x7D    /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DMA_ADPCM26R_AUTO                0x7F    /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DISABLE_DAC              0x80    /* Silence DAC (SB) */
-#define SBDSP_HS_DMA_DAC8_AUTO         0x90    /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */
-#define SBDSP_HS_DMA_ADC8_AUTO         0x98    /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */
-#define SBDSP_STEREO_ADC_DIS           0xA0    /* Disable Stereo Input Mode (SBPro Only) */
-#define SBDSP_STEREO_ADC_ENA           0xA8    /* Enable Stereo Input Mode (SBPro Only) */
-#define SBDSP_DMA_GENERIC16            0xB0    /* Generic DAC/ADC DMA (16-bit) (SB16) */
-#define SBDSP_DMA_GENERIC8             0xC0    /* Generic DAC/ADC DMA (8-bit) (SB16) */
-#define SBDSP_DMA_HALT8                        0xD0    /* Halt DMA Operation, 8-bit (SB) */
-#define SBDSP_SPEAKER_ENA              0xD1    /* Enable Speaker (SB) */
-#define SBDSP_SPEAKER_DIS              0xD3    /* Disable Speaker (SB) */
-#define SBDSP_DMA_CONT8                        0xD4    /* Continue DMA Operation, 8-bit (SB) */
-#define SBDSP_DMA_HALT16               0xD5    /* Halt DMA Operation, 16-bit (SB16) */
-#define SBDSP_DMA_CONT16               0xD6    /* Continue DMA Operation, 16-bit (SB16) */
-#define SBDSP_SPEAKER_STATUS           0xD8    /* Speaker Status (SB) */
-#define SBDSP_DMA_EXIT16_AUTO          0xD9    /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */
-#define SBDSP_DMA_EXIT8_AUTO           0xDA    /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */
-#define SBDSP_IDENTIFY                 0xE0    /* DSP Identification (SB2.0) */
-#define SBDSP_VERSION                  0xE1    /* DSP Version (SB) */
-#define SBDSP_COPYRIGHT                        0xE3    /* DSP Copyright (SBPro2???) */
-#define SBDSP_WRITE_TEST               0xE4    /* Write Test Register (SB2.0) */
-#define SBDSP_READ_TEST                        0xE8    /* Read Test Register (SB2.0) */
-#define SBDSP_SINE_GEN                 0xF0    /* Sine Generator (SB) */
-#define SBDSP_AUX_STATUS_PRO           0xF1    /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */
-#define SBDSP_GEN_IRQ8                 0xF2    /* IRQ Request, 8-bit (SB) */
-#define SBDSP_GEN_IRQ16                        0xF3    /* IRQ Request, 16-bit (SB16) */
-#define SBDSP_STATUS                   0xFB    /* DSP Status (SB16) */
-#define SBDSP_AUX_STATUS_16            0xFC    /* DSP Auxiliary Status (SB16) */
-#define SBDSP_CMD_STATUS               0xFD    /* DSP Command Status (SB16) */
-
-/* Mixer commands */
-#define SBMIX_RESET                    0x00    /* Reset                        Write       SBPro */
-#define SBMIX_STATUS                   0x01    /* Status                       Read        SBPro */
-#define SBMIX_MASTER_LEVEL1            0x02    /* Master Volume                Read/Write  SBPro Only */
-#define SBMIX_DAC_LEVEL                        0x04    /* DAC Level                    Read/Write  SBPro */
-#define SBMIX_FM_OUTPUT                        0x06    /* FM Output Control            Read/Write  SBPro Only */
-#define SBMIX_MIC_LEVEL                        0x0A    /* Microphone Level             Read/Write  SBPro */
-#define SBMIX_INPUT_SELECT             0x0C    /* Input/Filter Select          Read/Write  SBPro Only */
-#define SBMIX_OUTPUT_SELECT            0x0E    /* Output/Stereo Select         Read/Write  SBPro Only */
-#define SBMIX_FM_LEVEL                 0x22    /* Master Volume                Read/Write  SBPro */
-#define SBMIX_MASTER_LEVEL             0x26    /* FM Level                     Read/Write  SBPro */
-#define SBMIX_CD_LEVEL                 0x28    /* CD Audio Level               Read/Write  SBPro */
-#define SBMIX_LINEIN_LEVEL             0x2E    /* Line In Level                Read/Write  SBPro */
-#define SBMIX_MASTER_LEVEL_L           0x30    /* Master Volume Left           Read/Write  SB16 */
-#define SBMIX_MASTER_LEVEL_R           0x31    /* Master Volume Right          Read/Write  SB16 */
-#define SBMIX_DAC_LEVEL_L              0x32    /* DAC Level Left               Read/Write  SB16 */
-#define SBMIX_DAC_LEVEL_R              0x33    /* DAC Level Right              Read/Write  SB16 */
-#define SBMIX_FM_LEVEL_L               0x34    /* FM Level Left                Read/Write  SB16 */
-#define SBMIX_FM_LEVEL_R               0x35    /* FM Level Right               Read/Write  SB16 */
-#define SBMIX_CD_LEVEL_L               0x36    /* CD Audio Level Left          Read/Write  SB16 */
-#define SBMIX_CD_LEVEL_R               0x37    /* CD Audio Level Right         Read/Write  SB16 */
-#define SBMIX_LINEIN_LEVEL_L           0x38    /* Line In Level Left           Read/Write  SB16 */
-#define SBMIX_LINEIN_LEVEL_R           0x39    /* Line In Level Right          Read/Write  SB16 */
-#define SBMIX_MIC_LEVEL_16             0x3A    /* Microphone Level             Read/Write  SB16 */
-#define SBMIX_PCSPK_LEVEL              0x3B    /* PC Speaker Level             Read/Write  SB16 */
-#define SBMIX_OUTPUT_CONTROL           0x3C    /* Output Control               Read/Write  SB16 */
-#define SBMIX_INPUT_CONTROL_L          0x3D    /* Input Control Left           Read/Write  SB16 */
-#define SBMIX_INPUT_CONTROL_R          0x3E    /* Input Control Right          Read/Write  SB16 */
-#define SBMIX_INPUT_GAIN_L             0x3F    /* Input Gain Control Left      Read/Write  SB16 */
-#define SBMIX_INPUT_GAIN_R             0x40    /* Input Gain Control Right     Read/Write  SB16 */
-#define SBMIX_OUTPUT_GAIN_L            0x41    /* Output Gain Control Left     Read/Write  SB16 */
-#define SBMIX_OUTPUT_GAIN_R            0x42    /* Output Gain Control Right    Read/Write  SB16 */
-#define SBMIX_AGC_CONTROL              0x43    /* Automatic Gain Control (AGC) Read/Write  SB16 */
-#define SBMIX_TREBLE_L                 0x44    /* Treble Left                  Read/Write  SB16 */
-#define SBMIX_TREBLE_R                 0x45    /* Treble Right                 Read/Write  SB16 */
-#define SBMIX_BASS_L                   0x46    /* Bass Left                    Read/Write  SB16 */
-#define SBMIX_BASS_R                   0x47    /* Bass Right                   Read/Write  SB16 */
-#define SBMIX_IRQ_SELECT               0x80    /* IRQ Select                   Read/Write  SB16 */
-#define SBMIX_DMA_SELECT               0x81    /* DMA Select                   Read/Write  SB16 */
-#define SBMIX_IRQ_STATUS               0x82    /* IRQ Status                   Read        SB16 */
-
-/* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */
-#define SBM_DSP_READY                  0x80
-
-/* SB_DSP_RESET / SBMIX_RESET */
-#define SBM_DSP_RESET                  0x01
-
-/* SBMIX_OUTPUT_SELECT */
-#define SBM_MIX_STEREO                 0x02
-#define SBM_MIX_FILTER                 0x20
-
-/* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */
-#define SBM_GENDAC_FIFO                        0x02
-#define SBM_GENDAC_AUTOINIT            0x04
-#define SBM_GENDAC_ADC                 0x08
-/* Second (mode) byte */
-#define SBM_GENDAC_SIGNED              0x10
-#define SBM_GENDAC_STEREO              0x20
-
-/* DSP version masks */
-#define SBVER_10                       0x0100  /* Original SoundBlaster */
-#define SBVER_15                       0x0105  /* SoundBlaster 1.5 */
-#define SBVER_20                       0x0200  /* SoundBlaster 2.0 */
-#define SBVER_PRO                      0x0300  /* SoundBlaster Pro */
-#define SBVER_PRO2                     0x0301  /* SoundBlaster Pro 2 */
-#define SBVER_16                       0x0400  /* SoundBlaster 16 */
-#define SBVER_AWE32                    0x040c  /* SoundBlaster AWE32 */
-
-typedef unsigned char boolean;
-
-#ifndef FALSE
-#define FALSE                          0
-#define TRUE                           1
-#endif
-
-/* Play mode bits */
-#define SBMODE_16BITS                  0x0001
-#define SBMODE_STEREO                  0x0002
-#define SBMODE_SIGNED                  0x0004
-
-/* Mask for capabilities that never change */
-#define SBMODE_MASK                    (SBMODE_16BITS | SBMODE_STEREO)
-
-/* You can fill some members of this struct (i.e. port,irq,dma) before
- * calling sb_detect() or sb_open()... this will ignore environment settings.
- */
-typedef struct __sb_state_s {
-       boolean ok;                     /* Are structure contents valid? */
-       int port, aweport;              /* sb/awe32 base port */
-       int irq;                        /* SoundBlaster IRQ */
-       int dma8, dma16;                /* 8-bit and 16-bit DMAs */
-       int maxfreq_mono;               /* Maximum discretization frequency / mono mode */
-       int maxfreq_stereo;             /* Maximum discretization frequency / stereo mode */
-       unsigned short dspver;          /* DSP version number */
-       struct irq_handle *irq_handle;  /* The interrupt handler */
-       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
-       unsigned char caps;             /* SoundBlaster capabilities (SBMODE_XXX) */
-       unsigned char mode;             /* Current SB mode (SBMODE_XXX) */
-       boolean open;                   /* Whenever the card has been opened */
-       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
-       void (*timer_callback) ();      /* Called TWICE per buffer play */
-} __sb_state;
-
-extern __sb_state sb;
-
-extern void __sb_wait();
-
-static inline boolean __sb_dsp_ready_in()
-{
-       int count;
-       for (count = 10000; count >= 0; count--)
-               if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY)
-                       return TRUE;
-       return FALSE;
-}
-
-static inline boolean __sb_dsp_ready_out()
-{
-       int count;
-       for (count = 10000; count >= 0; count--)
-               if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0)
-                       return TRUE;
-       return FALSE;
-}
-
-static inline void __sb_dsp_out(unsigned char reg)
-{
-       __sb_dsp_ready_out();
-       outportb(SB_DSP_DATA_OUT, reg);
-}
-
-static inline unsigned char __sb_dsp_in()
-{
-       __sb_dsp_ready_in();
-       return inportb(SB_DSP_DATA_IN);
-}
-
-static inline void __sb_dspreg_out(unsigned char reg, unsigned char val)
-{
-       __sb_dsp_out(reg);
-       __sb_dsp_out(val);
-}
-
-static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val)
-{
-       __sb_dsp_out(reg);
-       __sb_dsp_out(val);
-       __sb_dsp_out(val >> 8);
-}
-
-static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val)
-{
-       __sb_dsp_out(reg);
-       __sb_dsp_out(val >> 8);
-       __sb_dsp_out(val);
-}
-
-static inline unsigned char __sb_dspreg_in(unsigned char reg)
-{
-       __sb_dsp_out(reg);
-       return __sb_dsp_in();
-}
-
-static inline void __sb_dsp_ack_dma8()
-{
-       inportb(SB_DSP_DMA8_IRQ);
-}
-
-static inline void __sb_dsp_ack_dma16()
-{
-       inportb(SB_DSP_DMA16_IRQ);
-}
-
-static inline unsigned short __sb_dsp_version()
-{
-       unsigned short ver;
-       __sb_dsp_out(SBDSP_VERSION);
-       __sb_dsp_ready_in();
-       ver = ((unsigned short)__sb_dsp_in()) << 8;
-       ver |= __sb_dsp_in();
-       return ver;
-}
-
-static inline void __sb_mixer_out(unsigned char reg, unsigned char val)
-{
-       outportb(SB_MIXER_REGSEL, reg);
-       outportb(SB_MIXER_DATA, val);
-}
-
-static inline unsigned char __sb_mixer_in(unsigned char reg)
-{
-       outportb(SB_MIXER_REGSEL, reg);
-       return inportb(SB_MIXER_DATA);
-}
-
-/* Enable stereo transfers: sbpro mode only */
-static inline void __sb_stereo(boolean stereo)
-{
-       unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT);
-       if (stereo)
-               val |= SBM_MIX_STEREO;
-       else
-               val &= ~SBM_MIX_STEREO;
-       __sb_mixer_out(SBMIX_OUTPUT_SELECT, val);
-}
-
-/* Detect whenever SoundBlaster is present and fill "sb" structure */
-extern boolean sb_detect();
-/* Reset SoundBlaster */
-extern void sb_reset();
-/* Start working with SoundBlaster */
-extern boolean sb_open();
-/* Finish working with SoundBlaster */
-extern boolean sb_close();
-/* Enable/disable speaker output */
-extern void sb_output(boolean enable);
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-extern boolean sb_start_dma(unsigned char mode, unsigned int freq);
-/* Stop playing from DMA buffer */
-extern void sb_stop_dma();
-/* Query current position/total size of the DMA buffer */
-extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
-
-#endif /* __DOSSB_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/doswss.c b/libs/mikmod/drivers/dos/doswss.c
deleted file mode 100644 (file)
index 41cdf38..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)
-  Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_WSS
-
-#include <stdlib.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <sys/farptr.h>
-#include <string.h>
-
-#include "doswss.h"
-
-/********************************************* Private variables/routines *****/
-
-__wss_state wss;
-
-/* WSS frequency rates... lower bit selects one of two frequency generators */
-static unsigned int wss_rates[14][2] = {
-       {5510, 0x00 | WSSM_XTAL2},
-       {6620, 0x0E | WSSM_XTAL2},
-       {8000, 0x00 | WSSM_XTAL1},
-       {9600, 0x0E | WSSM_XTAL1},
-       {11025, 0x02 | WSSM_XTAL2},
-       {16000, 0x02 | WSSM_XTAL1},
-       {18900, 0x04 | WSSM_XTAL2},
-       {22050, 0x06 | WSSM_XTAL2},
-       {27420, 0x04 | WSSM_XTAL1},
-       {32000, 0x06 | WSSM_XTAL1},
-       {33075, 0x0C | WSSM_XTAL2},
-       {37800, 0x08 | WSSM_XTAL2},
-       {44100, 0x0A | WSSM_XTAL2},
-       {48000, 0x0C | WSSM_XTAL1}
-};
-
-static void wss_irq()
-{
-       /* Make sure its not a spurious IRQ */
-       if (!irq_check(wss.irq_handle))
-               return;
-
-       wss.irqcount++;
-
-       /* Clear IRQ status */
-       outportb(WSS_STATUS, 0);
-
-       /* Write transfer count again */
-       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
-       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
-       irq_ack(wss.irq_handle);
-
-       enable();
-       if (wss.timer_callback)
-               wss.timer_callback();
-}
-
-static void wss_irq_end()
-{
-}
-
-/* WSS accepts some conventional values instead of frequency in Hz... */
-static unsigned char __wss_getrate(unsigned int *freq)
-{
-       int i, best = -1, delta = 0xffff;
-
-       for (i = 0; i < 14; i++) {
-               int newdelta = abs(wss_rates[i][0] - *freq);
-               if (newdelta < delta)
-                       best = i, delta = newdelta;
-       }
-
-       *freq = wss_rates[best][0];
-       return wss_rates[best][1];
-}
-
-/* Check if we really have a WSS compatible card on given address */
-static boolean __wss_ping()
-{
-       /* Disable CODEC operations first */
-       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-       /* Now put some harmless values in registers and check them */
-       __wss_outreg(WSSR_COUNT_LOW, 0xaa);
-       __wss_outreg(WSSR_COUNT_HIGH, 0x55);
-       return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)
-         && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);
-}
-
-static boolean __wss_reset()
-{
-       int count;
-
-       /* Disable output */
-       wss_output(FALSE);
-
-       /* Now select the test/initialization register */
-       count = 10000;
-       while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {
-               outportb(WSS_ADDR, WSSR_TEST_INIT);
-               if (!--count)
-                       return FALSE;
-       }
-
-       count = 10000;
-       while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {
-               outportb(WSS_ADDR, WSSR_TEST_INIT);
-               if (!--count)
-                       return FALSE;
-       }
-
-       /* Enable playback IRQ */
-       __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
-       __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
-
-       /* Clear IRQ status */
-       outportb(WSS_STATUS, 0);
-
-       return TRUE;
-}
-
-static boolean __wss_setformat(unsigned char format)
-{
-       int count;
-
-       outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);
-       outportb(WSS_DATA, format);
-       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
-       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
-
-       /* Wait end of syncronization ... */
-       if (!__wss_wait())
-               return FALSE;
-
-       /* Turn off the ModeChangeEnable bit: do it until it works */
-       count = 10000;
-       while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {
-               outportb(WSS_ADDR, WSSR_PLAY_FORMAT);
-               if (!--count)
-                       return FALSE;
-       }
-
-       return __wss_reset();
-}
-
-/**************************************************** WSS detection stuff *****/
-
-static int __wss_irq_irqdetect(int irqno)
-{
-       unsigned char status = inportb(WSS_STATUS);
-       /* Clear IRQ status */
-       outportb(WSS_STATUS, 0);
-       /* Reset transfer counter */
-       __wss_outreg(WSSR_COUNT_LOW, 0);
-       __wss_outreg(WSSR_COUNT_HIGH, 0);
-       return (status & WSSM_INT);
-}
-
-static boolean __wss_detect()
-{
-       /* First find the port number */
-       if (!wss.port) {
-               static unsigned int wss_ports[] =
-                 { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };
-               int i;
-               for (i = 0; i < 5; i++) {
-                       wss.port = wss_ports[i];
-                       if (__wss_ping())
-                               break;
-               }
-               if (i < 0) {
-                       wss.port = 0;
-                       return FALSE;
-               }
-       }
-
-       /* Now disable output */
-       wss_output(FALSE);
-
-       /* Detect the DMA channel */
-       if (!wss.dma) {
-               static int __dma[] = { 0, 1, 3 };
-               int i;
-
-               /* Enable playback IRQ */
-               __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
-               __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
-
-               /* Start a short DMA transfer and check if DMA count is zero */
-               for (i = 0; i < 3; i++) {
-                       unsigned int timer, status, freq = 44100;
-
-                       wss.dma = __dma[i];
-
-                       dma_disable(wss.dma);
-                       dma_set_mode(wss.dma, DMA_MODE_WRITE);
-                       dma_clear_ff(wss.dma);
-                       dma_set_count(wss.dma, 10);
-                       dma_enable(wss.dma);
-
-                       /* Clear IRQ status */
-                       outportb(WSS_STATUS, 0);
-
-                       __wss_setformat(__wss_getrate(&freq));
-                       __wss_outreg(WSSR_COUNT_LOW, 1);
-                       __wss_outreg(WSSR_COUNT_HIGH, 0);
-                       /* Tell codec to start transfer */
-                       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
-                       _farsetsel(_dos_ds);
-                       timer = _farnspeekl(0x46c);
-
-                       while (_farnspeekl(0x46c) - timer <= 2)
-                               if (dma_get_count(wss.dma) == 0)
-                                       break;
-                       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-                       dma_disable(wss.dma);
-
-                       /* Now check if DMA transfer count is zero and an IRQ is pending */
-                       status = inportb(WSS_STATUS);
-                       outportb(WSS_STATUS, 0);
-                       if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))
-                               break;
-
-                       wss.dma = 0;
-               }
-
-               if (!wss.dma)
-                       return FALSE;
-       }
-
-       /* Now detect the IRQ number */
-       if (!wss.irq) {
-               unsigned int i, irqmask, freq = 5510;
-               unsigned long timer, delta = 0x7fffffff;
-
-               /* IRQ can be one of 2,3,5,7,10 */
-               irq_detect_start(0x04ac, __wss_irq_irqdetect);
-
-               dma_disable(wss.dma);
-               dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-               dma_clear_ff(wss.dma);
-               dma_set_count(wss.dma, 1);
-               dma_enable(wss.dma);
-
-               __wss_setformat(__wss_getrate(&freq));
-
-               /* Clear IRQ status */
-               outportb(WSS_STATUS, 0);
-
-               __wss_outreg(WSSR_COUNT_LOW, 0);
-               __wss_outreg(WSSR_COUNT_HIGH, 0);
-
-               /* Prepare timeout counter */
-               _farsetsel(_dos_ds);
-               timer = _farnspeekl(0x46c);
-               while (timer == _farnspeekl(0x46c));
-               timer = _farnspeekl(0x46c);
-
-               /* Reset all IRQ counters */
-               irq_detect_clear();
-
-               /* Tell codec to start transfer */
-               __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
-               /* Now wait 1/18 seconds */
-               while (timer == _farnspeekl(0x46c));
-               __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-               dma_disable(wss.dma);
-
-               /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval
-                  of 1/18.2 second, we should have received about 302 interrupts */
-               for (i = 2; i <= 10; i++) {
-                       int count = abs(302 - irq_detect_get(i, &irqmask));
-                       if (count < delta)
-                               wss.irq = i, delta = count;
-               }
-               if (delta > 150)
-                       wss.irq = 0;
-
-               irq_detect_end();
-               if (!wss.irq)
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
-/*************************************************** High-level interface *****/
-
-/* Detect whenever WSS is present and fill "wss" structure */
-boolean wss_detect()
-{
-       char *env;
-
-       /* Try to find the port and DMA from environment */
-       env = getenv("WSS");
-
-       while (env && *env) {
-               /* Skip whitespace */
-               while ((*env == ' ') || (*env == '\t'))
-                       env++;
-               if (!*env)
-                       break;
-
-               switch (*env++) {
-                 case 'A':
-                 case 'a':
-                       if (!wss.port)
-                               wss.port = strtol(env, &env, 16);
-                       break;
-                 case 'I':
-                 case 'i':
-                       if (!wss.irq)
-                               wss.irq = strtol(env, &env, 10);
-                       break;
-                 case 'D':
-                 case 'd':
-                       if (!wss.dma)
-                               wss.dma = strtol(env, &env, 10);
-                       break;
-                 default:
-                       /* Skip other values */
-                       while (*env && (*env != ' ') && (*env != '\t'))
-                               env++;
-                       break;
-               }
-       }
-
-       /* Try to fill the gaps in wss hardware parameters */
-       __wss_detect();
-
-       if (!wss.port || !wss.irq || !wss.dma)
-               return FALSE;
-
-       if (!__wss_ping())
-               return FALSE;
-
-       if (!__wss_reset())
-               return FALSE;
-
-       wss.ok = 1;
-       return TRUE;
-}
-
-/* Reset WSS */
-void wss_reset()
-{
-       wss_stop_dma();
-       __wss_reset();
-}
-
-/* Open WSS for usage */
-boolean wss_open()
-{
-       __dpmi_meminfo struct_info;
-
-       if (!wss.ok)
-               if (!wss_detect())
-                       return FALSE;
-
-       if (wss.open)
-               return FALSE;
-
-       /* Now lock the wss structure in memory */
-       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
-       struct_info.size = sizeof(wss);
-       if (__dpmi_lock_linear_region(&struct_info))
-               return FALSE;
-
-       /* Hook the WSS IRQ */
-       wss.irq_handle =
-         irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);
-       if (!wss.irq_handle) {
-               __dpmi_unlock_linear_region(&struct_info);
-               return FALSE;
-       }
-
-       /* Enable the interrupt */
-       irq_enable(wss.irq_handle);
-       if (wss.irq > 7)
-               _irq_enable(2);
-
-       wss.open++;
-
-       return TRUE;
-}
-
-/* Finish working with WSS */
-boolean wss_close()
-{
-       __dpmi_meminfo struct_info;
-       if (!wss.open)
-               return FALSE;
-
-       wss.open--;
-
-       /* Stop/free DMA buffer */
-       wss_stop_dma();
-
-       /* Unhook IRQ */
-       irq_unhook(wss.irq_handle);
-       wss.irq_handle = NULL;
-
-       /* Unlock the wss structure */
-       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
-       struct_info.size = sizeof(wss);
-       __dpmi_unlock_linear_region(&struct_info);
-
-       return TRUE;
-}
-
-/* Adjust frequency rate to nearest WSS available */
-unsigned int wss_adjust_freq(unsigned int freq)
-{
-       __wss_getrate(&freq);
-       return freq;
-}
-
-/* Enable/disable speaker output */
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-boolean wss_start_dma(unsigned char mode, unsigned int freq)
-{
-       int dmabuffsize;
-       unsigned char format;
-
-       /* Stop DMA transfer if it is enabled */
-       wss_stop_dma();
-
-       /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */
-       if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))
-               || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))
-               return FALSE;
-
-       /* Find the nearest frequency divisor (rate) */
-       format = __wss_getrate(&freq);
-       wss.mode = mode;
-
-       /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */
-       dmabuffsize = freq;
-       if (mode & WSSMODE_STEREO)
-               dmabuffsize *= 2;
-       if (mode & WSSMODE_16BITS)
-               dmabuffsize *= 2;
-       dmabuffsize >>= 2;
-       if (dmabuffsize < 4096)
-               dmabuffsize = 4096;
-       if (dmabuffsize > 32768)
-               dmabuffsize = 32768;
-       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
-
-       wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);
-       if (!wss.dma_buff)
-               return FALSE;
-
-       /* Fill DMA buffer with silence */
-       dmabuffsize = wss.dma_buff->size;
-       if (mode & WSSMODE_SIGNED)
-               memset(wss.dma_buff->linear, 0, dmabuffsize);
-       else
-               memset(wss.dma_buff->linear, 0x80, dmabuffsize);
-
-       /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */
-       wss.samples = dmabuffsize;
-       if (mode & WSSMODE_16BITS) {
-               wss.samples >>= 1;
-               format |= WSSM_16BITS;
-       }
-
-       if (mode & WSSMODE_STEREO) {
-               wss.samples >>= 1;
-               format |= WSSM_STEREO;
-       }
-
-       if (!__wss_setformat(format)) {
-               wss_stop_dma();
-               return FALSE;
-       }
-
-       /* Prime DMA for transfer */
-       dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-
-       /* Tell codec how many samples to transfer */
-       wss.samples = (wss.samples >> 1) - 1;
-       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
-       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
-
-       /* Tell codec to start transfer */
-       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
-       return TRUE;
-}
-
-/* Stop playing from DMA buffer */
-void wss_stop_dma()
-{
-       if (!wss.dma_buff)
-               return;
-
-       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-       dma_disable(wss.dma);
-       dma_free(wss.dma_buff);
-       wss.dma_buff = NULL;
-}
-
-/* Query current position/total size of the DMA buffer */
-void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
-{
-       unsigned int dma_left;
-       *dma_size = wss.dma_buff->size;
-       /* It can happen we try to read DMA count when HI/LO bytes will be
-          inconsistent */
-       for (;;) {
-               unsigned int dma_left_test;
-               dma_clear_ff(wss.dma);
-               dma_left_test = dma_get_count(wss.dma);
-               dma_left = dma_get_count(wss.dma);
-               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
-                       break;
-       }
-       *dma_pos = *dma_size - dma_left;
-}
-
-void wss_output(boolean enable)
-{
-       if (enable)
-               wss.curlevel = wss.level;
-       else
-               wss.curlevel = 0x3f;
-
-       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
-       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
-}
-
-void wss_level(int level)
-{
-       if (level < 0)
-               level = 0;
-       if (level > 63)
-               level = 63;
-       wss.curlevel = wss.level = level ^ 63;
-
-       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
-       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
-}
-
-#endif /* DRV_WSS */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/doswss.h b/libs/mikmod/drivers/dos/doswss.h
deleted file mode 100644 (file)
index ae77bb5..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  $Id$
-
-  Windows Sound System and compatible soundcards definitions
-
-==============================================================================*/
-
-#ifndef __DOSWSS_H__
-#define __DOSWSS_H__
-
-#include "dosdma.h"
-#include "dosirq.h"
-
-#define WSS_ADDR                       (wss.port + 0x04)
-#define WSS_DATA                       (wss.port + 0x05)
-#define WSS_STATUS                     (wss.port + 0x06)
-#define WSS_PIO                                (wss.port + 0x07)
-
-/* WSS_ADDR: Bits 0-4 select an internal register to read/write */
-#define WSSR_INPUT_L                   0x00    /* Left input control register */
-#define WSSR_INPUT_R                   0x01    /* RIght input control register */
-#define WSSR_AUX1_L                    0x02    /* Left Aux #1 input control */
-#define WSSR_AUX1_R                    0x03    /* Right Aux #1 input control */
-#define WSSR_CD_L                      0x04    /* Left Aux #2 input control */
-#define WSSR_CD_R                      0x05    /* Right Aux #2 input control */
-#define WSSR_MASTER_L                  0x06    /* Left output control */
-#define WSSR_MASTER_R                  0x07    /* Right output control */
-#define WSSR_PLAY_FORMAT               0x08    /* Clock and data format */
-#define WSSR_IFACE_CTRL                        0x09    /* Interface control */
-#define WSSR_PIN_CTRL                  0x0a    /* Pin control */
-#define WSSR_TEST_INIT                 0x0b    /* Test and initialization */
-#define WSSR_MISC_INFO                 0x0c    /* Miscellaneaous information */
-#define WSSR_LOOPBACK                  0x0d    /* Digital Mix */
-#define WSSR_COUNT_HIGH                        0x0e    /* Playback Upper Base Count */
-#define WSSR_COUNT_LOW                 0x0f    /* Playback Lower Base Count */
-#define WSSR_ALT_FEATURE_1             0x10    /* alternate #1 feature enable */
-#define WSSR_ALT_FEATURE_2             0x11    /* alternate #2 feature enable */
-#define WSSR_LINE_IN_L                 0x12    /* left line input control */
-#define WSSR_LINE_IN_R                 0x13    /* right line input control */
-#define WSSR_TIMER_LOW                 0x14    /* timer low byte */
-#define WSSR_TIMER_HIGH                        0x15    /* timer high byte */
-#define WSSR_IRQ_STATUS                        0x18    /* irq status register */
-#define WSSR_MONO_IO_CTRL              0x1a    /* mono input/output control */
-#define WSSR_REC_FORMAT                        0x1c    /* record format */
-#define WSSR_REC_COUNT_HIGH            0x1e    /* record upper count */
-#define WSSR_REC_COUNT_LOW             0x1f    /* record lower count */
-
-/* WSS_ADDR bits 7-5 definition */
-#define WSSM_INIT                      0x80    /* Codec is initializing */
-#define WSSM_MCE                       0x40    /* Mode change enable */
-#define WSSM_TRD                       0x20    /* Transfer Request Disable */
-/* bits 4-0 are indirect register address (0-15) */
-
-/* WSS_STATUS bit masks */
-#define WSSM_CUL                       0x80    /* Capture data upper/lower byte */
-#define WSSM_CLR                       0x40    /* Capture left/right sample */
-#define WSSM_CRDY                      0x20    /* Capture data read */
-#define WSSM_SOUR                      0x10    /* Playback over/under run error */
-#define WSSM_PUL                       0x08    /* Playback upper/lower byte */
-#define WSSM_PLR                       0x04    /* Playback left/right sample */
-#define WSSM_PRDY                      0x02    /* Playback data register read */
-#define WSSM_INT                       0x01    /* interrupt status */
-
-/* Definitions for output level registers */
-#define WSSM_MUTE                      0x80    /* Mute this output source */
-/* bits 5-0 are left output attenuation select (0-63) */
-/* bits 5-0 are right output attenuation select (0-63) */
-
-/* Definitions for clock and data format register (WSSR_PLAY_FORMAT) */
-#define WSSM_STEREO                    0x10    /* stero mode */
-#define WSSM_ULAW_8                    0x20    /* 8-bit U-law companded */
-#define WSSM_16BITS                    0x40    /* 16 bit twos complement data - little endian */
-#define WSSM_ALAW_8                    0x60    /* 8-bit A-law companded */
-#define WSSM_16BITS_BE                 0xc0    /* 16-bit twos complement data - big endian */
-#define WSSM_ADPCM_16                  0xa0    /* 16-bit ADPCM */
-/* Bits 3-1 define frequency divisor */
-#define WSSM_XTAL1                     0x00    /* 24.576 crystal */
-#define WSSM_XTAL2                     0x01    /* 16.9344 crystal */
-
-/* Definitions for interface control register (WSSR_IFACE_CTRL) */
-#define WSSM_CAPTURE_PIO               0x80    /* Capture PIO enable */
-#define WSSM_PLAYBACK_PIO              0x40    /* Playback PIO enable */
-#define WSSM_AUTOCALIB                 0x08    /* auto calibrate */
-#define WSSM_SINGLE_DMA                        0x04    /* Use single DMA channel */
-#define WSSM_PLAYBACK_ENABLE           0x01    /* playback enable */
-
-/* Definitions for Pin control register (WSSR_PIN_CTRL) */
-#define WSSM_IRQ_ENABLE                        0x02    /* interrupt enable */
-#define WSSM_XCTL1                     0x40    /* external control #1 */
-#define WSSM_XCTL0                     0x80    /* external control #0 */
-
-/* Definitions for WSSR_TEST_INIT register */
-#define WSSM_CALIB_IN_PROGRESS 0x20    /* auto calibrate in progress */
-
-/* Definitions for misc control register (WSR_MISC_INFO) */
-#define WSSM_MODE2                     0x40    /* MODE 2 */
-#define WSSM_MODE3                     0x6c    /* MODE 3 - enhanced mode */
-
-/* Definitions for codec irq status (WSSR_IRQ_STATUS) */
-#define WSSM_PLAYBACK_IRQ              0x10
-#define WSSM_RECORD_IRQ                        0x20
-#define WSSM_TIMER_IRQ                 0x40
-
-typedef unsigned char boolean;
-
-#ifndef FALSE
-#define FALSE                          0
-#define TRUE                           1
-#endif
-
-/* Play mode bits */
-#define WSSMODE_16BITS                 0x0001
-#define WSSMODE_STEREO                 0x0002
-#define WSSMODE_SIGNED                 0x0004
-
-/* You can fill some members of this struct (i.e. port,irq,dma) before
- * calling wss_detect() or wss_open()... this will ignore environment settings.
- */
-typedef struct __wss_state_s {
-       boolean ok;                     /* Set if this structure is properly filled */
-       int port;                       /* Base codec port */
-       int irq;                        /* codec IRQ */
-       int dma;                        /* codec DMA */
-       struct irq_handle *irq_handle;  /* The interrupt handler */
-       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
-       unsigned char mode;             /* Current WSS mode (WSSMODE_XXX) */
-       boolean open;                   /* Whenever the card has been opened */
-       int samples;                    /* Number of samples in DMA buffer */
-       unsigned char level;            /* Output level (63..0): doesn't change when mute */
-       unsigned char curlevel;         /* Current output level (63(min)..0(max)) */
-       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
-       void (*timer_callback) ();      /* Called TWICE per buffer play */
-} __wss_state;
-
-extern __wss_state wss;
-
-/* Wait until codec finishes initialization */
-static inline boolean __wss_wait()
-{
-       int count;
-       for (count = 10000; count >= 0; count--)
-               if (!(inportb(WSS_ADDR) & WSSM_INIT))
-                       return TRUE;
-       return FALSE;
-}
-
-static inline void __wss_outreg(unsigned char reg, unsigned char val)
-{
-       outportb(WSS_ADDR, reg);
-       outportb(WSS_DATA, val);
-}
-
-static inline unsigned char __wss_inreg(unsigned char reg)
-{
-       outportb(WSS_ADDR, reg);
-       return inportb(WSS_DATA);
-}
-
-/* Set some bits in a specific register */
-static inline void __wss_regbit_set(unsigned char reg, unsigned char mask)
-{
-       outportb(WSS_ADDR, reg);
-       outportb(WSS_DATA, inportb(WSS_DATA) | mask);
-}
-
-/* Reset some bits in a specific register */
-static inline void __wss_regbit_reset(unsigned char reg, unsigned char mask)
-{
-       outportb(WSS_ADDR, reg);
-       outportb(WSS_DATA, inportb(WSS_DATA) & ~mask);
-}
-
-/* Detect whenever WSS is present and fill "wss" structure */
-extern boolean wss_detect();
-/* Reset WSS */
-extern void wss_reset();
-/* Open WSS for usage */
-extern boolean wss_open();
-/* Finish working with WSS */
-extern boolean wss_close();
-/* Enable/disable speaker output */
-extern void wss_output(boolean enable);
-/* Adjust frequency rate to nearest WSS available */
-extern unsigned int wss_adjust_freq(unsigned int freq);
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-extern boolean wss_start_dma(unsigned char mode, unsigned int freq);
-/* Stop playing from DMA buffer */
-extern void wss_stop_dma();
-/* Query current position/total size of the DMA buffer */
-extern void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
-/* Set output level (0(min)-63(max)) */
-extern void wss_level(int level);
-
-#endif /* __DOSWSS_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/libgus.h b/libs/mikmod/drivers/dos/libgus.h
deleted file mode 100644 (file)
index 0d66ee9..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*     MikMod sound library
-       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
-       complete list.
-
-       This library is free software; you can redistribute it and/or modify
-       it under the terms of the GNU Library General Public License as
-       published by the Free Software Foundation; either version 2 of
-       the License, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-       GNU Library General Public License for more details.
-
-       You should have received a copy of the GNU Library General Public
-       License along with this library; if not, write to the Free Software
-       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-       02111-1307, USA.
-*/
-
-/*==============================================================================
-
-  $Id$
-
-  Linux libGUS-alike library for DOS, used by drv_ultra.c under DOS.
-
-==============================================================================*/
-
-/*
-       Current limitations:
-       - Only a subset of libgus is supported
-       - Only one GUS card is supported (due to the fact that ULTRASND environment
-         variable is used)
-       - No Interwawe support (if IW works the old way, it's ok).
-*/
-
-#ifndef __LIBGUS_H__
-#define __LIBGUS_H__
-
-#include <stddef.h>
-
-#define __LITTLE_ENDIAN
-
-typedef struct _gus_info_t gus_info_t;
-typedef struct _gus_instrument_t gus_instrument_t;
-typedef struct _gus_wave_t gus_wave_t;
-typedef struct _gus_layer_t gus_layer_t;
-
-#define GUS_CARD_VERSION_CLASSIC       0x0024  /* revision 2.4 */
-#define GUS_CARD_VERSION_CLASSIC1      0x0034  /* revision 3.4? */
-#define GUS_CARD_VERSION_CLASSIC_ICS   0x0037  /* revision 3.7 (ICS mixer) */
-#define GUS_CARD_VERSION_EXTREME       0x0050  /* GUS Extreme */
-#define GUS_CARD_VERSION_ACE           0x0090  /* GUS ACE */
-#define GUS_CARD_VERSION_MAX           0x00a0  /* GUS MAX - revision 10 */
-#define GUS_CARD_VERSION_MAX1          0x00a1  /* GUS MAX - revision 11 */
-#define GUS_CARD_VERSION_PNP           0x0100  /* GUS Plug & Play */
-
-#define GUS_STRU_INFO_F_DB16           0x00000001      /* 16-bit daughter board present */
-#define GUS_STRU_INFO_F_PCM            0x00000004      /* GF1 PCM during SYNTH enabled */
-#define GUS_STRU_INFO_F_ENHANCED       0x00000008      /* InterWave - enhanced mode */
-#define GUS_STRU_INFO_F_DAEMON         0x00000010      /* instrument daemon is present */
-
-struct _gus_info_t {
-       unsigned char id[8];            /* id of this card (warning! maybe unterminated!!!) */
-
-       unsigned int flags;             /* some info flags - see to GUS_STRU_INFO_F_XXXX */
-       unsigned int version;           /* see to GUS_CARD_VERSION_XXXX constants */
-
-       unsigned short port;
-       unsigned short irq;
-       unsigned short dma1;            /* DMA1 - GF1 download & codec record */
-       unsigned short dma2;            /* DMA2 - GF1 record & codec playback */
-
-       unsigned int mixing_freq;       /* mixing frequency in Hz */
-
-       unsigned int memory_size;       /* in bytes */
-       unsigned int memory_free;       /* in bytes */
-       unsigned int memory_block_8;    /* largest free 8-bit block in memory */
-       unsigned int memory_block_16;   /* largest free 16-bit block in memory */
-};
-
-/* struct gus_instrument_t - mode */
-
-#define GUS_INSTR_SIMPLE       0x00    /* simple format - for MOD players */
-#define GUS_INSTR_PATCH                0x01    /* old GF1 patch format */
-#define GUS_INSTR_COUNT                2
-
-#define GUS_INSTR_F_NORMAL     0x0000  /* normal mode */
-#define GUS_INSTR_F_NOT_FOUND  0x0001  /* instrument can't be loaded */
-#define GUS_INSTR_F_ALIAS      0x0002  /* alias */
-#define GUS_INSTR_F_NOT_LOADED 0x00ff  /* instrument not loaded (not found) */
-
-#define GUS_INSTR_E_NONE       0x0000  /* exclusion mode - none */
-#define GUS_INSTR_E_SINGLE     0x0001  /* exclude single - single note from this instrument */
-#define GUS_INSTR_E_MULTIPLE   0x0002  /* exclude multiple - stop only same note from this instrument */
-
-#define GUS_INSTR_L_NONE       0x0000  /* not layered */
-#define GUS_INSTR_L_ON         0x0001  /* layered */
-#define GUS_INSTR_L_VELOCITY   0x0002  /* layered by velocity */
-#define GUS_INSTR_L_FREQUENCY  0x0003  /* layered by frequency */
-
-struct _gus_instrument_t {
-       union {
-               unsigned int instrument;/* instrument number */
-       } number;
-
-       char *name;                     /* name of this instrument or NULL */
-
-       unsigned int mode:8,            /* see to GUS_INSTR_XXXX */
-           flags:8,                    /* see to GUS_INSTR_F_XXXX */
-           exclusion:4,                /* see to GUS_INSTR_E_XXXX */
-           layer:4;                    /* see to GUS_INSTR_L_XXXX */
-       unsigned short exclusion_group; /* 0 - none, 1-65535 */
-
-       struct {
-               unsigned char effect1:4,/* use global effect if available */
-                   effect2:4;          /* use global effect if available */
-               unsigned char effect1_depth;/* 0-127 */
-               unsigned char effect2_depth;/* 0-127 */
-       } patch;
-
-       union {
-               gus_layer_t *layer;     /* first layer */
-               unsigned int alias;     /* pointer to instrument */
-       } info;
-       gus_instrument_t *next;         /* next instrument */
-};
-
-struct _gus_layer_t {
-       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
-
-       gus_wave_t *wave;
-       gus_layer_t *next;
-};
-
-/* bits for format variable in gus_wave_t */
-
-#define GUS_WAVE_16BIT          0x0001 /* 16-bit wave */
-#define GUS_WAVE_UNSIGNED       0x0002 /* unsigned wave */
-#define GUS_WAVE_INVERT         0x0002 /* same as unsigned wave */
-#define GUS_WAVE_BACKWARD       0x0004 /* forward mode */
-#define GUS_WAVE_LOOP           0x0008 /* loop mode */
-#define GUS_WAVE_BIDIR          0x0010 /* bidirectional mode */
-#define GUS_WAVE_ULAW           0x0020 /* uLaw compressed wave */
-#define GUS_WAVE_RAM            0x0040 /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
-#define GUS_WAVE_ROM            0x0080 /* wave is in ROM */
-#define GUS_WAVE_DELTA          0x0100
-
-#define GUS_WAVE_PATCH_ENVELOPE 0x01   /* envelopes on */
-#define GUS_WAVE_PATCH_SUSTAIN  0x02   /* sustain mode */
-
-struct _gus_wave_t {
-       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
-       unsigned char format;           /* see to GUS_WAVE_XXXX constants */
-       unsigned int size;              /* size of waveform in bytes */
-       unsigned int start;             /* start offset in bytes * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_start;        /* bits loop start offset in bytes * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_end;          /* loop start offset in bytes * 16 (lowest 4 bits - fraction) */
-       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
-       struct {
-               unsigned int memory;    /* begin of waveform in GUS's memory */
-               unsigned char *ptr;     /* pointer to waveform in system memory */
-       } begin;
-
-       struct {
-               unsigned char flags;
-               unsigned int sample_rate;
-               unsigned int low_frequency;/* low frequency range for this waveform */
-               unsigned int high_frequency;/* high frequency range for this waveform */
-               unsigned int root_frequency;/* root frequency for this waveform */
-               signed short tune;
-               unsigned char balance;
-               unsigned char envelope_rate[6];
-               unsigned char envelope_offset[6];
-               unsigned char tremolo_sweep;
-               unsigned char tremolo_rate;
-               unsigned char tremolo_depth;
-               unsigned char vibrato_sweep;
-               unsigned char vibrato_rate;
-               unsigned char vibrato_depth;
-               unsigned short scale_frequency;
-               unsigned short scale_factor;/* 0-2048 or 0-2 */
-       } patch;
-
-       gus_wave_t *next;
-};
-
-/* defines for gus_memory_reset () */
-#define GUS_DOWNLOAD_MODE_NORMAL 0x0000
-#define GUS_DOWNLOAD_MODE_TEST  0x0001
-
-/*
-    A subset of libgus functions (used by MikMod Ultrasound driver)
-*/
-int gus_cards(void);
-  /*
-   * return value:      number of GUS cards installed in system or
-   *                    zero if driver isn't installed
-   */
-int gus_close(int card);
-  /*
-   * close file (gus synthesizer) previously opened with gusOpen function
-   * return value:      zero if success
-   */
-int gus_do_flush(void);
-  /*
-   * return value:      zero if command queue was successfully flushed
-   *                    in non block mode - number of written bytes
-   */
-void gus_do_tempo(unsigned int tempo);
-  /*
-   * set new tempo
-   */
-void gus_do_voice_frequency(unsigned char voice, unsigned int freq);
-  /*
-   * set voice frequency in Hz
-   */
-void gus_do_voice_pan(unsigned char voice, unsigned short pan);
-  /*
-   * set voice pan (0-16384) (full left - full right)
-   */
-void gus_do_voice_start(unsigned char voice, unsigned int program,
-                        unsigned int freq, unsigned short volume,
-                        unsigned short pan);
-  /*
-   * start voice
-   *            voice    : voice #
-   *            program  : program # or ~0 = current
-   *            freq     : frequency in Hz
-   *            volume   : volume level (0-16384) or ~0 = current
-   *            pan      : pan level (0-16384) or ~0 = current
-   */
-void gus_do_voice_start_position(unsigned char voice, unsigned int program,
-                                 unsigned int freq, unsigned short volume,
-                                 unsigned short pan, unsigned int position);
-  /*
-   * start voice
-   *            voice    : voice #
-   *            program  : program # or ~0 = current
-   *            freq     : frequency in Hz
-   *            volume   : volume level (0-16384) or ~0 = current
-   *            pan      : pan level (0-16384) or ~0 = current
-   *            position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
-   */
-void gus_do_voice_stop(unsigned char voice, unsigned char mode);
-  /*
-   * stop voice
-   *            mode = 0 : stop voice now
-   *            mode = 1 : disable wave loop and finish it
-   */
-void gus_do_voice_volume(unsigned char voice, unsigned short vol);
-  /*
-   * set voice volume level 0-16384 (linear)
-   */
-void gus_do_wait(unsigned int ticks);
-  /*
-   * wait x ticks - this command is block separator
-   * all commands between blocks are interpreted in the begining of one tick
-   */
-int gus_get_voice_status(int voice);
-  /*
-   * THIS IS NOT A FUNCTION OF ORIGINAL libGUS!
-   * Return voice status: -1 on error, 0 if voice stopped, 1 if playing
-   */
-int gus_get_handle(void);
-  /*
-   * return value:      file handle (descriptor) for /dev/gus
-   */
-int gus_info(gus_info_t * info, int reread);
-  /*
-   * return value:      filled info variable with actual values
-   *                    (look at gus.h header file for more informations)
-   * version field:     0x0024  - GUS revision 2.4
-   *                    0x0035  - GUS revision 3.7 with flipped mixer channels
-   *                    0x0037  - GUS revision 3.7
-   *                    0x0090  - GUS ACE
-   *                    0x00a0  - GUS MAX revision 10
-   *                    0x00a1  - GUS MAX revision 11
-   *                    0x0100  - InterWave (full version)
-   * flags field:       see to GUS_STRU_INFO_F_???? constants (gus.h header file)
-   * port field:        port number (for example 0x220)
-   * irq field:         irq number (for example 11)
-   * dma1 field:        dma1 number (for example 5)
-   * dma2 field:        dma2 number (for example 6)
-   * note:              dma1 and dma2 could be same in case of only one dma channel used
-   */
-int gus_memory_alloc(gus_instrument_t * instrument);
-  /*
-   * input value:       look at gus.h for more details about gus_instrument_t structure
-   * return value:      zero if instrument was successfully allocated
-   */
-int gus_memory_free(gus_instrument_t * instrument);
-  /*
-   * input value:       look at gus.h for more details about gus_instrument_t structure
-   * return value:      zero if instrument was successfully removed
-   */
-int gus_memory_size(void);
-  /*
-   * return value:  gus memory size in bytes
-   */
-int gus_memory_free_size(void);
-  /*
-   * return value:      unused gus memory in bytes
-   * warning:           reset function must be called before
-   */
-int gus_memory_free_block(int w_16bit);
-  /*
-   * return value:  current largest free block for 8-bit or 16-bit wave
-   */
-int gus_memory_pack(void);
-  /*
-   * return value:      zero if success
-   */
-int gus_memory_reset(int mode);
-  /*
-   * input value:   see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
-   * return value:  zero if samples & instruments was successfully removed
-   *            from GF1 memory manager
-   */
-
-int gus_open(int card, size_t queue_buffer_size, int non_block);
-  /*
-   * input values:      card number,
-   *                    size of command queue buffer (512-1MB)
-   *                    buffer is allocated dynamically,
-   *                    non block mode
-   * return value:      zero if success
-   * note 1:            this function must be called as first
-   *                    open file /dev/gus
-   * note 2:            you can open more cards with one process
-   */
-int gus_queue_flush(void);
-  /*
-   * return value:      zero if command queue was successfully flushed
-   */
-int gus_queue_read_set_size(int items);
-  /*
-   * input value:       echo buffer size in items (if 0 - erase echo buffer)
-   */
-int gus_queue_write_set_size(int items);
-  /*
-   * input value:       write queue size in items (each item have 8 bytes)
-   */
-int gus_reset(int voices, unsigned int channel_voices);
-  /*
-   * input values:      active voices and channel voices (for dynamic allocation)
-   * return value:      number of active voices if reset was successfull (GF1 chip active)
-   */
-int gus_reset_engine_only(void);
-  /*
-   * return value:  same as gus_reset function
-   * note:      this command doesn't change number of active
-   *            voices and doesn't do hardware reset
-   */
-int gus_select(int card);
-  /*
-   * select specified card
-   * return value:      zero if success
-   */
-int gus_timer_start(void);
-  /*
-   * return value:      zero if successfull
-   */
-int gus_timer_stop(void);
-  /*
-   * return value:      zero if timer was stoped
-   */
-int gus_timer_continue(void);
-  /*
-   * return value:  zero if timer will be continue
-   */
-int gus_timer_tempo(int ticks);
-  /*
-   * return value:      zero if setup was success
-   */
-int gus_timer_base(int base);
-  /*
-   * return value:  zero if setup was success (default timebase = 100)
-   */
-
-void gus_convert_delta(unsigned int type, unsigned char *dest,
-                       unsigned char *src, size_t size);
-  /*
-   * note: dest and src pointers can be equal
-   */
-
-void gus_timer_callback(void (*timer_callback) ());
-  /*
-   * Set a callback to be called once per tempo tick
-   */
-
-int gus_dma_usage (int use);
-  /*
-   * Tell GUS library to use/to not use DMA for sample transfer.
-   * In some environments/on some hardware platforms you will need
-   * to disable DMA in order to function properly. You should call
-   * this function before opening the card.
-   */
-
-#endif /* __LIBGUS_H__ */
-
-/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosdma.c b/libs/mikmod/drvdos/dosdma.c
new file mode 100644 (file)
index 0000000..e232c30
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+    Implementation of DMA routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosdma.h"
+
+#include <go32.h> /* includes sys/version.h (djgpp >= 2.02) */
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/* BUG WARNING:  there is an error in DJGPP libraries <= 2.01:
+ * src/libc/dpmi/api/d0102.s loads the selector and allocsize
+ * arguments in the wrong order.  DJGPP >= 2.02 have it fixed. */
+#if (!defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__+0) < 2)
+#warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken!
+#endif
+
+__dma_regs dma[8] = {
+/* *INDENT-OFF* */
+       {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+       {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+       {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+       {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+       {DMA_ADDR_4,          0, DMA_SIZE_4,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+       {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+
+       {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+       {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
+/* *INDENT-ON* */
+};
+
+static int __initialized = 0;
+static int __buffer_count = 0;
+static __dpmi_meminfo __locked_data;
+
+int dma_initialize()
+{
+       if (!__djgpp_nearptr_enable())
+               return 0;
+
+       /* Trick: Avoid re-setting DS selector limit on each memory allocation
+          call */
+       __djgpp_selector_limit = 0xffffffff;
+
+       __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
+       __locked_data.size = sizeof(dma);
+       if (__dpmi_lock_linear_region(&__locked_data))
+               return 0;
+
+       return (__initialized = 1);
+}
+
+void dma_finalize()
+{
+       if (!__initialized)
+               return;
+       __dpmi_unlock_linear_region(&__locked_data);
+       __djgpp_nearptr_disable();
+}
+
+dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
+{
+       int parsize = (size + 15) >> 4; /* size in paragraphs */
+       int par = 0;                            /* Real-mode paragraph */
+       int selector = 0;                       /* Protected-mode selector */
+       int mask = channel <= 3 ? 0xfff : 0x1fff;       /* Alignment mask in para. */
+       int allocsize = parsize;        /* Allocated size in paragraphs */
+       int count;                                      /* Try count */
+       int bound = 0;                          /* Nearest bound address */
+       int maxsize;                            /* Maximal possible block size */
+       dma_buffer *buffer = NULL;
+       __dpmi_meminfo buff_info, struct_info;
+
+       if (!dma_initialize())
+               return NULL;
+
+       /* Loop until we'll get a properly aligned memory block */
+       for (count = 8; count; count--) {
+               int resize = (selector != 0);
+
+               /* Try first to resize (possibly previously) allocated block */
+               if (resize) {
+                       maxsize = (bound + parsize) - par;
+                       if (maxsize > parsize * 2)
+                               maxsize = parsize * 2;
+                       if (maxsize == allocsize)
+                               resize = 0;
+                       else {
+                               allocsize = maxsize;
+                               if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) !=
+                                       0) resize = 0;
+                       }
+               }
+
+               if (!resize) {
+                       if (selector)
+                               __dpmi_free_dos_memory(selector), selector = 0;
+                       par = __dpmi_allocate_dos_memory(allocsize, &selector);
+               }
+
+               if ((par == 0) || (par == -1))
+                       goto exit;
+
+               /* If memory block contains a properly aligned portion, quit loop */
+               bound = (par + mask + 1) & ~mask;
+               if (par + parsize <= bound)
+                       break;
+               if (bound + parsize <= par + allocsize) {
+                       par = bound;
+                       break;
+               }
+       }
+       if (!count) {
+               __dpmi_free_dos_memory(selector);
+               goto exit;
+       }
+
+       buffer = (dma_buffer *) MikMod_malloc(sizeof(dma_buffer));
+       buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16);
+       buffer->physical = bound * 16;
+       buffer->size = parsize * 16;
+       buffer->selector = selector;
+       buffer->channel = channel;
+
+       buff_info.address = buffer->physical;
+       buff_info.size = buffer->size;
+       /*
+          Don't pay attention to return code since under plain DOS it often
+          returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
+        */
+       __dpmi_lock_linear_region(&buff_info);
+
+       /* Lock the DMA buffer control structure as well */
+       struct_info.address = __djgpp_base_address + (unsigned long)buffer;
+       struct_info.size = sizeof(dma_buffer);
+       if (__dpmi_lock_linear_region(&struct_info)) {
+               __dpmi_unlock_linear_region(&buff_info);
+               __dpmi_free_dos_memory(selector);
+               MikMod_free(buffer);
+               buffer = NULL;
+               goto exit;
+       }
+
+  exit:
+       if (buffer)
+               __buffer_count++;
+       else if (--__buffer_count == 0)
+               dma_finalize();
+       return buffer;
+}
+
+void dma_free(dma_buffer * buffer)
+{
+       __dpmi_meminfo buff_info;
+
+       if (!buffer)
+               return;
+
+       buff_info.address = buffer->physical;
+       buff_info.size = buffer->size;
+       __dpmi_unlock_linear_region(&buff_info);
+
+       __dpmi_free_dos_memory(buffer->selector);
+       MikMod_free(buffer);
+
+       if (--__buffer_count == 0)
+               dma_finalize();
+}
+
+void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
+{
+       /* Disable interrupts */
+       int old_ints = disable();
+       dma_disable(buffer->channel);
+       dma_set_mode(buffer->channel, mode);
+       dma_clear_ff(buffer->channel);
+       dma_set_addr(buffer->channel, buffer->physical);
+       dma_clear_ff(buffer->channel);
+       dma_set_count(buffer->channel, count);
+       dma_enable(buffer->channel);
+       /* Re-enable interrupts */
+       if (old_ints)
+               enable();
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosdma.h b/libs/mikmod/drvdos/dosdma.h
new file mode 100644 (file)
index 0000000..882c9ac
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+    Interface for DMA routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSDMA_H__
+#define __DOSDMA_H__
+
+#include <pc.h>
+
+#define DMA1_BASE              0x00    /* 8 bit slave DMA, channels 0..3 */
+#define DMA2_BASE              0xC0    /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+#define DMA1_CMD_REG           0x08    /* command register (w) */
+#define DMA1_STAT_REG          0x08    /* status register (r) */
+#define DMA1_REQ_REG           0x09    /* request register (w) */
+#define DMA1_MASK_REG          0x0A    /* single-channel mask (w) */
+#define DMA1_MODE_REG          0x0B    /* mode register (w) */
+#define DMA1_CLEAR_FF_REG      0x0C    /* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG          0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG         0x0D    /* Master Clear (w) */
+#define DMA1_CLR_MASK_REG      0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG      0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG           0xD0    /* command register (w) */
+#define DMA2_STAT_REG          0xD0    /* status register (r) */
+#define DMA2_REQ_REG           0xD2    /* request register (w) */
+#define DMA2_MASK_REG          0xD4    /* single-channel mask (w) */
+#define DMA2_MODE_REG          0xD6    /* mode register (w) */
+#define DMA2_CLEAR_FF_REG      0xD8    /* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG          0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG         0xDA    /* Master Clear (w) */
+#define DMA2_CLR_MASK_REG      0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG      0xDE    /* all-channels mask (w) */
+
+#define DMA_ADDR_0      0x00   /* DMA address registers */
+#define DMA_ADDR_1      0x02
+#define DMA_ADDR_2      0x04
+#define DMA_ADDR_3      0x06
+#define DMA_ADDR_4      0xC0
+#define DMA_ADDR_5      0xC4
+#define DMA_ADDR_6      0xC8
+#define DMA_ADDR_7      0xCC
+
+#define DMA_SIZE_0             0x01    /* DMA transfer size registers */
+#define DMA_SIZE_1             0x03
+#define DMA_SIZE_2             0x05
+#define DMA_SIZE_3             0x07
+#define DMA_SIZE_4             0xC2
+#define DMA_SIZE_5             0xC6
+#define DMA_SIZE_6             0xCA
+#define DMA_SIZE_7             0xCE
+
+#define DMA_PAGE_0      0x87   /* DMA page registers */
+#define DMA_PAGE_1      0x83
+#define DMA_PAGE_2      0x81
+#define DMA_PAGE_3      0x82
+#define DMA_PAGE_5      0x8B
+#define DMA_PAGE_6      0x89
+#define DMA_PAGE_7      0x8A
+
+#define DMA_MODE_AUTOINIT      0x10    /* Auto-init mode bit */
+#define DMA_MODE_READ          0x44    /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE         0x48    /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE       0xC0    /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+/* Indexable specific DMA registers */
+typedef struct __dma_regs_s {
+       unsigned char addr;                     /* DMA transfer address register */
+       unsigned char page;                     /* DMA page register */
+       unsigned char size;                     /* DMA transfer size register */
+       unsigned char mask;                     /* DMA mask/unmask register */
+       unsigned char flip;                     /* DMA flip-flop reset register */
+       unsigned char mode;                     /* DMA mode register */
+} __dma_regs;
+
+extern __dma_regs dma[8];
+
+/* Enable a specific DMA channel */
+static inline void dma_enable(unsigned int channel)
+{
+       outportb(dma[channel].mask, channel & 3);
+}
+
+/* Disable a specific DMA channel */
+static inline void dma_disable(unsigned int channel)
+{
+       outportb(dma[channel].mask, (channel & 3) | 0x04);
+}
+
+/* Clear the 'DMA Flip Flop' flag */
+static inline void dma_clear_ff(unsigned int channel)
+{
+       outportb(dma[channel].flip, 0);
+}
+
+/* Set mode for a specific DMA channel */
+static inline void dma_set_mode(unsigned int channel, char mode)
+{
+       outportb(dma[channel].mode, mode | (channel & 3));
+}
+
+/* Set DMA page register */
+static inline void dma_set_page(unsigned int channel, char page)
+{
+       if (channel > 3)
+               page &= 0xfe;
+       outportb(dma[channel].page, page);
+}
+
+/*
+  Set transfer address & page bits for specific DMA channel.
+  Assumes dma flipflop is clear.
+*/
+static inline void dma_set_addr(unsigned int channel, unsigned int address)
+{
+       unsigned char dma_reg = dma[channel].addr;
+       dma_set_page(channel, address >> 16);
+       if (channel <= 3) {
+               outportb(dma_reg, (address) & 0xff);
+               outportb(dma_reg, (address >> 8) & 0xff);
+       } else {
+               outportb(dma_reg, (address >> 1) & 0xff);
+               outportb(dma_reg, (address >> 9) & 0xff);
+       }
+}
+
+/*
+  Set transfer size for a specific DMA channel.
+  Assumes dma flip-flop is clear.
+*/
+static inline void dma_set_count(unsigned int channel, unsigned int count)
+{
+       unsigned char dma_reg = dma[channel].size;
+       count--;                                        /* number of DMA transfers is bigger by one */
+       if (channel > 3)
+               count >>= 1;
+       outportb(dma_reg, (count) & 0xff);
+       outportb(dma_reg, (count >> 8) & 0xff);
+}
+
+/*
+  Query the number of bytes left to transfer.
+  Assumes DMA flip-flop is clear.
+*/
+static inline int dma_get_count(unsigned int channel)
+{
+       unsigned char dma_reg = dma[channel].size;
+
+       /* using short to get 16-bit wrap around */
+       unsigned short count;
+       count = inportb(dma_reg);
+       count |= inportb(dma_reg) << 8;
+       count++;
+       return (channel <= 3) ? count : (count << 1);
+}
+
+typedef struct dma_buffer_s {
+       unsigned char *linear;          /* Linear address */
+       unsigned long physical;         /* Physical address */
+       unsigned long size;                     /* Buffer size */
+       unsigned short selector;        /* The selector assigned to this memory */
+       unsigned char channel;          /* The DMA channel */
+} dma_buffer;
+
+/* Allocate a block of memory suitable for using as a DMA buffer */
+extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
+/* Deallocate a DMA buffer */
+extern void dma_free(dma_buffer * buffer);
+/* Start DMA transfer to or from given buffer */
+extern void dma_start(dma_buffer * buffer, unsigned long count,
+                                         unsigned char mode);
+
+#endif /* __DOSDMA_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosgus.c b/libs/mikmod/drvdos/dosgus.c
new file mode 100644 (file)
index 0000000..637b526
--- /dev/null
@@ -0,0 +1,1907 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  Driver for GUS cards under DOS
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_ULTRA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/farptr.h>
+#include <sys/nearptr.h>
+#include <go32.h>
+#include <string.h>
+
+#include "dosgus.h"
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/********************************************* Private variables/routines *****/
+
+/* The Gravis Ultrasound state/info */
+__gus_state gus;
+
+/* Try to avoid holes in DRAM less than this size */
+#define DRAM_HOLE_THRESHOLD    8192
+/* If hole is larger than that, create a free block describing it */
+#define DRAM_SPLIT_THRESHOLD   64
+/* The size of DMA buffer used for RAM->DRAM transfers */
+#define GF1_DMA_BUFFER_SIZE    8192
+
+/* Debug macro: useful to change screen locations when some event occurs */
+#ifdef MIKMOD_DEBUG
+#  define DEBUG_PRINT(x) printf x;
+#  define DEBUG_OFS(addr, attr)                        \
+   {                                           \
+     unsigned short x;                         \
+     _dosmemgetw (0xb8780 + addr*2, 1, &x);    \
+     if ((x >> 8) != attr) x = '0';            \
+     x = ((x + 1) & 0xff) | (attr << 8);       \
+     _dosmemputw (&x, 1, 0xb8780 + addr*2);    \
+   }
+#else
+#  define DEBUG_PRINT(x)
+#  define DEBUG_OFS(addr, attr)
+#endif
+
+static unsigned short __gus_volume_table[512] = {
+       0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00,
+       0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, 0xac00, 0xae00,
+       0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700,
+       0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00,
+       0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380,
+       0xc400, 0xc480, 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780,
+       0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
+       0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80,
+       0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, 0xd180, 0xd1c0,
+       0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0,
+       0xd400, 0xd440, 0xd480, 0xd4c0, 0xd500, 0xd540, 0xd580, 0xd5c0,
+       0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0,
+       0xd800, 0xd840, 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0,
+       0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
+       0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0,
+       0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, 0xdf80, 0xdfc0,
+       0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0,
+       0xe100, 0xe120, 0xe140, 0xe160, 0xe180, 0xe1a0, 0xe1c0, 0xe1e0,
+       0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0,
+       0xe300, 0xe320, 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0,
+       0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
+       0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0,
+       0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, 0xe6c0, 0xe6e0,
+       0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0,
+       0xe800, 0xe820, 0xe840, 0xe860, 0xe880, 0xe8a0, 0xe8c0, 0xe8e0,
+       0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0,
+       0xea00, 0xea20, 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0,
+       0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
+       0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0,
+       0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, 0xedc0, 0xede0,
+       0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0,
+       0xef00, 0xef20, 0xef40, 0xef60, 0xef80, 0xefa0, 0xefc0, 0xefe0,
+       0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070,
+       0xf080, 0xf090, 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0,
+       0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
+       0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0,
+       0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, 0xf260, 0xf270,
+       0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0,
+       0xf300, 0xf310, 0xf320, 0xf330, 0xf340, 0xf350, 0xf360, 0xf370,
+       0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0,
+       0xf400, 0xf410, 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470,
+       0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
+       0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570,
+       0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, 0xf5e0, 0xf5f0,
+       0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670,
+       0xf680, 0xf690, 0xf6a0, 0xf6b0, 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0,
+       0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770,
+       0xf780, 0xf790, 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0,
+       0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
+       0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0,
+       0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, 0xf960, 0xf970,
+       0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0,
+       0xfa00, 0xfa10, 0xfa20, 0xfa30, 0xfa40, 0xfa50, 0xfa60, 0xfa70,
+       0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0,
+       0xfb00, 0xfb10, 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70,
+       0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
+       0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70,
+       0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, 0xfce0, 0xfcf0,
+       0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70,
+       0xfd80, 0xfd90, 0xfda0, 0xfdb0, 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0,
+       0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70,
+       0xfe80, 0xfe90, 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0,
+       0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
+       0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0
+};
+
+/* Wait a bit for GUS before doing something
+ * Mark function as volatile: don't allow it to be inlined.
+ * It *should* be slow, no need to make it work faster :-)
+ */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+#  define _func_noclone
+# else
+#  define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __gus_delay()
+{
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+}
+
+static void __gus_stop_controller(unsigned char gf1reg)
+{
+       register unsigned char value = __gus_inregb(gf1reg);
+       __gus_outregb(gf1reg, (value | GF1VC_STOPPED | GF1VC_STOP) &
+                      ~(GF1VC_IRQ_PENDING | GF1VC_IRQ));
+}
+
+/* Returns 1 if volume is already at given position */
+static boolean __gus_volume_ramp_to(unsigned short volume,
+                                    unsigned char rate,
+                                    unsigned char vol_ctrl)
+{
+       int svol = __gus_inregw(GF1R_VOLUME) & 0xfff0;
+       int evol = volume;
+
+       /* First of all, disable volume ramp */
+       __gus_stop_controller(GF1R_VOLUME_CONTROL);
+
+       /* If voice is stopped, set the volume to zero and return */
+       if (__gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED) {
+               __gus_outregw(GF1R_VOLUME, 0);
+               return 1;
+       }
+
+       /* Avoid clicks when volume ramp goes too high or too low */
+       if (svol < 0x0400)
+               svol = 0x0400;
+       if (svol > 0xfc00)
+               svol = 0xfc00;
+       if (evol < 0x0400)
+               evol = 0x0400;
+       if (evol > 0xfc00)
+               evol = 0xfc00;
+
+       /* Adjust start/end positions */
+       if (svol > evol) {
+               unsigned short tmp = evol;
+               evol = svol;
+               svol = tmp;
+               vol_ctrl |= GF1VL_BACKWARD;
+       }
+
+       /* If we already are (near) the target volume, quit */
+       if (evol - svol < 0x1000) {
+               __gus_outregw(GF1R_VOLUME, volume);
+               return 1;
+       }
+
+       __gus_outregb(GF1R_VOLUME_START, svol >> 8);
+       __gus_outregb(GF1R_VOLUME_END, evol >> 8);
+       __gus_outregb(GF1R_VOLUME_RATE, rate);
+       __gus_outregb_slow(GF1R_VOLUME_CONTROL, vol_ctrl);
+       return 0;
+}
+
+static inline void __gus_stop_voice()
+{
+       __gus_stop_controller(GF1R_VOICE_CONTROL);
+       __gus_outregb_slow(GF1R_VOICE_CONTROL, GF1VC_STOPPED | GF1VC_STOP);
+}
+
+/* The GUS IRQ handler */
+static void gf1_irq()
+{
+       unsigned char irq_source;       /* The contents of GF1_IRQ_STATUS register */
+       boolean timer_cb = 0;           /* Call timer callback function */
+
+       DEBUG_OFS(0, 0xCE)
+       gus.eow_ignore = 0;
+       while ((irq_source = inportb(GF1_IRQ_STATUS))) {
+               DEBUG_OFS(1, 0xCE)
+
+                 if (irq_source & GF1M_IRQ_DMA_COMPLETE) {
+                       DEBUG_OFS(4, 0x9F)
+                         /* reset the IRQ pending bit */
+                         __gus_inregb(GF1R_DMA_CONTROL);
+                       gus.dma_active = 0;
+
+                       if (gus.dma_callback)
+                               gus.dma_callback();
+               }
+
+               if (irq_source & (GF1M_IRQ_WAVETABLE | GF1M_IRQ_ENVELOPE)) {
+                       unsigned char vcirq;
+                       unsigned int done_mask = 0;
+
+                       /* IRQ bits are inverse (i.e. 0 = IRQ pending) */
+                       while ((vcirq = __gus_inregb(GF1R_IRQ_SOURCE) ^
+                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) &
+                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) {
+                               unsigned long voice = (vcirq & 0x1f);
+                               unsigned char voice_ctl, volume_ctl;
+                               unsigned int voice_mask = (1 << voice);
+
+                               /* Don't handle more than one IRQ from same voice */
+                               if (done_mask & voice_mask)
+                                       continue;
+
+                               done_mask |= voice_mask;
+
+                               /* Read voice/volume selection registers */
+                               __gus_select_voice(voice);
+                               voice_ctl = __gus_inregb(GF1R_VOICE_CONTROL);
+                               volume_ctl = __gus_inregb(GF1R_VOLUME_CONTROL);
+
+                               if ((vcirq & GF1IRQ_WAVE) && (gus.wt_callback)
+                                       && !(gus.eow_ignore & voice_mask)) {
+                                       DEBUG_OFS(5, 0xAF)
+                                       gus.wt_callback(voice, voice_ctl, volume_ctl);
+                               }
+
+                               if ((vcirq & GF1IRQ_VOLUME) && (gus.vl_callback)) {
+                                       DEBUG_OFS(6, 0xAF)
+                                       gus.vl_callback(voice, voice_ctl, volume_ctl);
+                               }
+                       }
+               }
+
+               /* Reset timers that sent this IRQ */
+               if (irq_source & (GF1M_IRQ_TIMER1 | GF1M_IRQ_TIMER2)) {
+                       unsigned char timer_ctl = gus.timer_ctl_reg;
+
+                       if (irq_source & GF1M_IRQ_TIMER1)
+                               timer_ctl &= ~GF1M_TIMER1;
+
+                       if (irq_source & GF1M_IRQ_TIMER2)
+                               timer_ctl &= ~GF1M_TIMER2;
+
+                       __gus_outregb_slow(GF1R_TIMER_CONTROL, timer_ctl);
+                       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+               }
+
+               if (irq_source & GF1M_IRQ_TIMER1)
+                       if (--gus.t1_countdown == 0) {
+                               gus.t1_countdown = gus.t1_multiple;
+                               gus.t1_ticks++;
+
+                               DEBUG_OFS(2, 0xCF)
+
+                               if (gus.t1_callback) {
+                                       timer_cb = 1;
+                                       gus.t1_callback();
+                               }
+                       }
+
+               if (irq_source & GF1M_IRQ_TIMER2)
+                       if (--gus.t2_countdown == 0) {
+                               gus.t2_countdown = gus.t2_multiple;
+                               gus.t2_ticks++;
+
+                               DEBUG_OFS(3, 0xCF)
+
+                               if (gus.t2_callback)
+                                       gus.t2_callback();
+                       }
+#if 0
+               /* The following are not used and implemented yet */
+               if (irq_source & (GF1M_IRQ_MIDI_TX | GF1M_IRQ_MIDI_RX)) {
+               }
+#endif
+       }
+
+       irq_ack(gus.gf1_irq);
+
+       if (timer_cb && gus.timer_callback)
+               gus.timer_callback();
+}
+
+static void gf1_irq_end()
+{
+}
+
+static boolean __gus_detect()
+{
+       /* A relatively relaxed autodetection;
+          We don't count on DRAM: GUS PnP could not have it
+          (although its anyway bad for us)
+        */
+       __gus_select_voice(0);
+       __gus_stop_voice();
+       __gus_outregw(GF1R_FREQUENCY, 0x1234);
+       __gus_outregw(GF1R_VOLUME, 0x5670);
+       return ((__gus_inregw(GF1R_FREQUENCY) & 0xfffe) == 0x1234)
+         && ((__gus_inregw(GF1R_VOLUME) & 0xfff0) == 0x5670);
+}
+
+static void __gus_reset(boolean reset_io_dma)
+{
+       static unsigned char irqctl[16] = { 0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7 };
+       static unsigned char dmactl[8] = { 0, 1, 0, 2, 0, 3, 4, 5 };
+       unsigned char irqtmp, dmatmp;
+
+       /* Disable interrupts while resetting to avoid spurious IRQs */
+       int i, timer, old_ints = disable();
+
+       /* Stop the timer so that GUS IRQ won't clobber registers */
+       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+       if (timer)
+               gus_timer_stop();
+
+       gus.dma_active = 0;
+
+       __gus_outregb(GF1R_RESET, 0);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+
+       outportb(GF1_MIDI_CTRL, GF1M_MIDI_RESET);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+       outportb(GF1_MIDI_CTRL, 0);
+
+       /* Reset all IRQ sources */
+       __gus_outregb(GF1R_DMA_CONTROL, 0);
+       __gus_outregb(GF1R_TIMER_CONTROL, 0);
+       __gus_outregb(GF1R_SAMPLE_CONTROL, 0);
+
+       /* Reset all voices */
+       gus_reset(gus.voices, gus.dynmask);
+
+       /* Flush any pending IRQs */
+       inportb(GF1_IRQ_STATUS);
+       __gus_inregb(GF1R_DMA_CONTROL);
+       __gus_inregb(GF1R_SAMPLE_CONTROL);
+       __gus_inregb(GF1R_IRQ_SOURCE);
+
+       if (reset_io_dma) {
+               /* Now set up the GUS card to required IRQs and DMAs */
+               if (gus.irq[0] == gus.irq[1])
+                       irqtmp = irqctl[gus.irq[0]] | GF1M_IRQ_EQUAL;
+               else
+                       irqtmp = irqctl[gus.irq[0]] | (irqctl[gus.irq[1]] << 3);
+
+               if (gus.dma[0] == gus.dma[1])
+                       dmatmp = dmactl[gus.dma[0]] | GF1M_DMA_EQUAL;
+               else
+                       dmatmp = dmactl[gus.dma[0]] | (dmactl[gus.dma[1]] << 3);
+
+               /* Reset IRQs if possible */
+               gus.mixer =
+                 GF1M_MIXER_NO_LINE_IN | GF1M_MIXER_NO_OUTPUT | GF1M_MIXER_GF1_IRQ;
+               if (gus.version >= GUS_CARD_VERSION_CLASSIC1) {
+                       outportb(GF1_REG_CTRL, 0x05);
+                       outportb(GF1_MIX_CTRL, gus.mixer);
+                       outportb(GF1_IRQ_CTRL, 0x00);   /* Reset IRQs */
+                       outportb(GF1_REG_CTRL, 0x00);
+               }
+
+               /* Set up DMA channels: NEVER disable MIXER_GF1_IRQ in the future */
+               outportb(GF1_MIX_CTRL, gus.mixer);
+               outportb(GF1_IRQ_CTRL, dmatmp);
+
+               /* Set up IRQ channels */
+               outportb(GF1_MIX_CTRL, gus.mixer | GF1M_CONTROL_SELECT);
+               outportb(GF1_IRQ_CTRL, irqtmp);
+       }
+
+       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET | GF1M_OUTPUT_ENABLE | GF1M_MASTER_IRQ);
+       __gus_delay();
+
+       /* Flush IRQs again */
+       inportb(GF1_IRQ_STATUS);
+       __gus_inregb(GF1R_DMA_CONTROL);
+       __gus_inregb(GF1R_SAMPLE_CONTROL);
+       __gus_inregb(GF1R_IRQ_SOURCE);
+
+       _irq_ack(gus.irq[0]);
+       _irq_ack(gus.irq[1]);
+
+       if (timer)
+               gus_timer_continue();
+
+       if (old_ints)
+               enable();
+
+       /* Enable output */
+       __gus_mixer_output(1);
+}
+
+/* Transfer a block of data from GUS DRAM to main RAM through port I/O */
+static void __gus_transfer_io_in(unsigned long address, unsigned char *source,
+                                 unsigned long size)
+{
+       while (size) {
+               register unsigned int size64k;
+
+               size64k = 0x10000 - (address & 0xffff);
+               if (size64k > size)
+                       size64k = size;
+               size -= size64k;
+
+               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+               while (size64k--) {
+                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                       *source++ = inportb(GF1_DRAM);
+               }
+       }
+}
+
+/* Transfer a block of data into GUS DRAM through port I/O */
+static void __gus_transfer_io(unsigned long address, unsigned char *source,
+                              unsigned long size, int flags)
+{
+       while (size) {
+               register unsigned int size64k;
+
+               size64k = 0x10000 - (address & 0xffff);
+               if (size64k > size)
+                       size64k = size;
+               size -= size64k;
+
+               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+               if (flags & GUS_WAVE_INVERT)
+                       if (flags & GUS_WAVE_16BIT)
+                               while (size64k-- && size64k--) {
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, *source++);
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
+                       } else
+                               while (size64k--) {
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
+               } else
+                       while (size64k--) {
+                               __gus_outregw(GF1R_DRAM_LOW, address++);
+                               outportb(GF1_DRAM, *source++);
+                       }
+       }
+}
+
+/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
+static int __gus_wait_dma()
+{
+       unsigned long timer;
+       _farsetsel(_dos_ds);
+       timer = _farnspeekl(0x46c);
+       while (gus.dma_active)
+               if (_farnspeekl(0x46c) - timer > 8) {
+                       /* Force DMA abort since something went wrong */
+                       __gus_reset(0);
+                       return -1;
+               }
+
+       return 0;
+}
+
+/* Transfer a block of data into GUS DRAM through DMA controller */
+static void __gus_transfer_dma(unsigned long address, unsigned char *source,
+                               unsigned long size, int flags)
+{
+       unsigned char dma_control;
+       unsigned long bytes_left;
+       unsigned long cur_size;
+       unsigned long dest_addr;
+
+       if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
+               size = (size + 1) & ~1;
+
+       bytes_left = size;
+       while (bytes_left) {
+               __gus_wait_dma();
+
+               cur_size = gus.dma_buff->size;
+               if (cur_size > bytes_left)
+                       cur_size = bytes_left;
+               bytes_left -= cur_size;
+               dest_addr = address;
+
+               if (gus.dma_buff->linear != source)
+                       memmove(gus.dma_buff->linear, source, cur_size);
+               source += cur_size;
+               address += cur_size;
+
+               /* Disable GUS -> DMA tie */
+               __gus_outregb(GF1R_DMA_CONTROL, 0);
+               __gus_delay();
+
+               /* Set up the DMA */
+               dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
+               gus.dma_active = 1;
+
+               /* Reset the DMA IRQ pending bit if set */
+               __gus_inregb(GF1R_DMA_CONTROL);
+
+               /* The 16-bit DMA channels needs a slightly different approach */
+               dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
+               if (gus.dma[0] > 3) {
+                       dest_addr = __gus_convert_addr16(dest_addr);
+                       dma_control |= GF1M_DMAR_CHAN16;
+               }
+
+               __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);
+
+               if (flags & GUS_WAVE_16BIT)
+                       dma_control |= GF1M_DMAR_DATA16;
+               if (flags & GUS_WAVE_INVERT)
+                       dma_control |= GF1M_DMAR_TOGGLE_SIGN;
+
+               /* Tell GUS to start transfer */
+               __gus_outregb(GF1R_DMA_CONTROL, dma_control);
+       }
+}
+
+static void __gus_detect_version()
+{
+       unsigned char tmp;
+
+       switch (gus.version = inportb(GF1_REVISION)) {
+         case 5:
+               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+               gus.ics = 1;
+               gus.ics_flipped = 1;
+               break;
+         case 6:
+         case 7:
+         case 8:
+         case 9:
+               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+               gus.ics = 1;
+               break;
+         case 10:
+               gus.version = GUS_CARD_VERSION_MAX;
+               gus.codec = 1;
+               break;
+         case 11:
+               gus.version = GUS_CARD_VERSION_MAX1;
+               gus.codec = 1;
+               break;
+         case 0x30:
+               gus.version = GUS_CARD_VERSION_ACE;
+               break;
+         case 0x50:
+               gus.version = GUS_CARD_VERSION_EXTREME;
+               break;
+         case 0xff:
+               /* Pre-3.7 board */
+               outportb(GF1_REG_CTRL, 0x20);
+               tmp = inportb(GF1_REG_CTRL);
+               if ((tmp != 0xff) && (tmp & 0x06))
+                       gus.version = GUS_CARD_VERSION_CLASSIC1;
+               else
+                       gus.version = GUS_CARD_VERSION_CLASSIC;
+               break;
+         default:
+               /* Hmm... unknown revision. Assume a safe Classic model */
+#ifdef MIKMOD_DEBUG
+               fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
+                               gus.version);
+#endif
+               gus.version = GUS_CARD_VERSION_CLASSIC;
+               break;
+       }
+}
+
+static void __gus_detect_transfer()
+{
+       unsigned char *outbuff, *inbuff;
+       unsigned int i, j, seed = 0x13243546;
+       __gus_transfer_func func;
+
+#define TRANSFER_SIZE  0x4000
+
+       outbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+       inbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+
+       /* Suppose we have an malfunctioning GUS */
+       gus.transfer = NULL;
+
+       for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
+               switch (i) {
+                 case 0:
+                       gus.dma_rate = GF1M_DMAR_RATE0;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 1:
+                       gus.dma_rate = GF1M_DMAR_RATE1;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 2:
+                       gus.dma_rate = GF1M_DMAR_RATE2;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 3:
+                       gus.dma_rate = GF1M_DMAR_RATE3;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 4:
+                       func = __gus_transfer_io;
+                       break;
+               }
+
+               /* Fill data array each time with pseudo-random values */
+               for (j = 0; j < TRANSFER_SIZE; j++)
+                       outbuff[j] = seed, seed =
+                         ((seed + 358979323) ^ (seed >> 16)) * 314159265;
+
+               /* Transfer the random array to GUS */
+               /* Poke a security fence around dest block */
+               __gus_poke(0x100 - 1, 0xAA);
+               __gus_poke(0x100 - 2, 0x55);
+               __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
+               __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);
+
+               func(0x100, outbuff, TRANSFER_SIZE, 0);
+
+               if (__gus_wait_dma() == 0) {
+                       /* Check if the security fence was not damaged */
+                       if ((__gus_peek(0x100 - 1) != 0xAA)
+                               || (__gus_peek(0x100 - 2) != 0x55)
+                               || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
+                               || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
+                               continue;
+
+                       /* Now check if GUS DRAM really data that we expects to be transferred */
+                       __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
+                       if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
+                               gus.transfer = func;
+                               break;
+                       }
+               }
+       }
+
+#undef TRANSFER_SIZE
+
+       MikMod_free(inbuff);
+       MikMod_free(outbuff);
+}
+
+static void __gus_detect_memory()
+{
+       unsigned int size;
+       for (size = 0; size < 1024; size += 256) {
+               __gus_poke(size * 1024, 0xaa);
+               if (__gus_peek(size * 1024) != 0xaa)
+                       break;
+               __gus_poke(size * 1024, 0x55);
+               if (__gus_peek(size * 1024) != 0x55)
+                       break;
+       }
+       gus.ram = size;
+}
+
+static void __gus_init()
+{
+       char *gusenv = getenv("ULTRASND");
+
+       memset((void *)&gus, 0, sizeof(gus));
+       gus.cmd_voice = -1;
+
+       if (!gusenv)
+               return;
+
+       sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
+                  &gus.irq[0], &gus.irq[1]);
+
+       /* A relaxed sanity check */
+       if ((gus.port < 0x100) || (gus.port > 0x1000)
+               || (gus.irq[0] < 2) || (gus.irq[0] > 15)
+               || (gus.irq[1] < 2) || (gus.irq[1] > 15)
+               || (gus.dma[0] < 0) || (gus.dma[0] > 7)
+               || (gus.dma[1] < 0) || (gus.dma[1] > 7))
+               return;
+
+       gus.voices = 32;
+       gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;
+
+       /* Detect if the card is really there */
+       if (__gus_detect() == 0)
+               return;
+
+       /* Detect the version of Gravis Ultrasound */
+       __gus_detect_version();
+
+       /* Reset the card */
+       __gus_reset(1);
+
+       /* Detect the amount of on-board memory */
+       __gus_detect_memory();
+
+       gus.ok = 1;
+}
+
+static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
+{
+       unsigned char vc;
+
+       vc = GF1VC_IRQ;
+       if (wave->format & GUS_WAVE_16BIT)
+               vc |= GF1VC_DATA16;
+       if (wave->format & GUS_WAVE_BACKWARD)
+               vc |= GF1VC_BACKWARD;
+       if (wave->format & GUS_WAVE_LOOP) {
+               vc |= GF1VC_LOOP_ENABLE;
+               if (wave->format & GUS_WAVE_BIDIR)
+                       vc |= GF1VC_BI_LOOP;
+       }
+       __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
+       if (wave->format & GUS_WAVE_LOOP)
+               __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
+       else
+               __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
+       __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
+       __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
+}
+
+/* Timer 1 callback function (updates voices) */
+static void __gus_timer_update()
+{
+       gus_wave_t *wave;
+       unsigned long wave_offset;
+       unsigned char *src, *top;
+       unsigned int vmask = (1 << gus.cur_voice);
+
+       if (!gus.cmd_pool_ready)
+               return;
+
+       __gus_select_voice(gus.cur_voice);
+       wave_offset = 0;
+       src = gus.cmd_pool;
+       top = gus.cmd_pool + gus.cmd_pool_top;
+
+#define GET_B  *src
+#define GET_W  *((unsigned short *)src)
+#define GET_L  *((unsigned long *)src)
+
+       while (src < top) {
+               __gus_delay();
+               switch (GET_B++) {
+                 case PCMD_VOICE:
+                       __gus_select_voice(gus.cur_voice = GET_B++);
+                       vmask = (1 << gus.cur_voice);
+                       break;
+                 case PCMD_FREQ:
+               /*      __gus_outregw(GF1R_FREQUENCY, GET_W++);*/
+                       __gus_outregw(GF1R_FREQUENCY, *(unsigned short *)src);
+                       src += 2;
+                       break;
+                 case PCMD_PAN:
+                       __gus_outregb(GF1R_BALANCE, GET_B++);
+                       break;
+                 case PCMD_VOLUME:
+                       __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
+                                                       /*       GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);*/
+                                                 *(unsigned short *)src, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+                                                               src += 2;
+                       break;
+                 case PCMD_VOLUME_PREPARE:
+               /*      gus.cur_vol[gus.cur_voice] = GET_W++;*/
+                       gus.cur_vol[gus.cur_voice] = *(unsigned short *)src;
+                       src += 2;
+                       break;
+                 case PCMD_OFFSET:
+               /*      wave_offset = GET_L++;*/
+                       wave_offset = *(unsigned long *)src;
+                       src += 4;
+                       break;
+                 case PCMD_START:
+               /*      wave = (gus_wave_t *) GET_L++;*/
+                       wave = (gus_wave_t *) *(unsigned long *)src;
+                       src += 4;
+                       gus.cur_wave[gus.cur_voice] = wave;
+                       gus.kick_offs[gus.cur_voice] = wave_offset;
+                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
+                               __gus_kick(wave, wave_offset);
+                               __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
+                                                                        GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+                       } else
+                               gus.voice_kick[gus.cur_voice] = 1;
+                       wave_offset = 0;
+                       gus.eow_ignore |= vmask;
+                       break;
+                 case PCMD_STOP:
+                       /* If volume is close to nothing, abort immediately instead of
+                          ramping */
+                       gus.cur_vol[gus.cur_voice] = 0;
+                       gus.cur_wave[gus.cur_voice] = NULL;
+                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+                               __gus_stop_voice();
+                       break;
+                 case PCMD_STOP_LOOP:
+                       __gus_outregb_slow(GF1R_VOICE_CONTROL,
+                                                          (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
+                                                          & ~GF1VC_LOOP_ENABLE);
+                       __gus_outregb_slow(GF1R_VOLUME_CONTROL,
+                                                          __gus_inregb(GF1R_VOLUME_CONTROL) &
+                                                          ~GF1VL_ROLLOVER);
+                       break;
+                 default:
+                       /* Alarm! Break out immediately */
+                       src = top;
+                       break;
+               }
+       }
+
+#undef GET_B
+#undef GET_W
+#undef GET_L
+
+       gus.cmd_pool_ready = 0;
+       gus.cmd_pool_top = 0;
+}
+
+static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
+                                                                  unsigned int volume_ctl)
+{
+       gus_wave_t *wave = gus.cur_wave[voice];
+
+       if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
+               __gus_stop_voice();
+               gus.cur_wave[voice] = NULL;
+               gus.cur_vol[voice] = 0;
+               if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+                       __gus_stop_voice();
+       }
+}
+
+static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
+                                                               unsigned int volume_ctl)
+{
+       __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+       if (!gus.cur_wave[voice])
+               __gus_stop_voice();
+       else if (gus.voice_kick[voice])
+               __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
+       gus.voice_kick[voice] = 0;
+}
+
+/***************************************************** GUS memory manager *****/
+
+/* Mark all GUS memory as available */
+static void __gus_mem_clear()
+{
+       __gus_mcb *cur = gus.mcb;
+
+       while (cur) {
+               __gus_mcb *next = cur->next;
+               if (cur != gus.mcb)
+                       MikMod_free(cur);
+               cur = next;
+       }
+
+       if (!gus.mcb)
+               gus.mcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+
+       gus.mcb->next = gus.mcb->prev = NULL;
+       gus.mcb->addr = 0;
+       gus.mcb->size = gus.ram * 1024;
+       gus.mcb->free = 1;
+}
+
+/* Return amount of free memory */
+static unsigned int __gus_mem_get_free()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return gus.ram * 1024;
+
+       while (cur) {
+               if (cur->free)
+                       size += cur->size;
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Return largest size for a 8-bit sample */
+static unsigned int __gus_mem_get_free_8()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return 0;
+
+       while (cur) {
+               if (cur->free && (cur->size > size))
+                       size = cur->size;
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Return largest size for a 16-bit sample */
+static unsigned int __gus_mem_get_free_16()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return 0;
+
+       while (cur) {
+               if (cur->free) {
+                       unsigned int size16 = cur->size;
+                       unsigned int tmp;
+                       /* 16-bit samples cannot cross 256K boundaries */
+                       tmp = 0x40000 - (cur->addr & 0x3ffff);
+                       if (size16 > tmp)
+                               size16 = tmp;
+                       /* 16-bit samples should be aligned on a 32-byte boundary */
+                       size16 -= (32 - cur->addr) & 0x1f;
+
+                       if (size16 > size)
+                               size = size16;
+
+                       /* Now try vice versa: skip a portion of aligned memory */
+                       size16 =
+                         (cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
+                       if ((size16 < 0x7fffffff) && (size16 > size))
+                               size = size16;
+               }
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
+ * The algorithm tries to find the smallest free block that fits requested
+ * size; but if found free block is larger by some (large) delta than
+ * requested block size, the largest possible block is preffered.
+ */
+static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
+{
+       __gus_mcb *cur = gus.mcb;
+       __gus_mcb *best_max = NULL, *best_min = NULL;
+       unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
+       unsigned int best_max_prefix = 0, best_min_prefix = 0;
+       unsigned int memaddr, memsize;
+
+       if (!gus.open || !size || (bits16 && size > 0x40000))
+               return -1;
+
+       /* Round block size up to nearest acceptable DMA bound */
+       if (bits16)
+               size = (size + 0x1f) & ~0x1f;
+       else
+               size = (size + 0x0f) & ~0x0f;
+
+       while (cur) {
+               if (cur->free) {
+                       unsigned char fits = 0;
+
+                       memsize = cur->size;
+                       memaddr = cur->addr;
+
+                       if (bits16) {
+                               /* 16-bit samples cannot cross 256K boundaries */
+                               unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
+                               if (memsize > tmp)
+                                       memsize = tmp;
+                               /* 16-bit samples should be aligned on a 32-byte boundary */
+                               memsize -= (32 - memaddr) & 0x1f;
+                               memaddr = (memaddr + 0x1f) & ~0x1f;
+                       }
+
+                       /* If block fits, analyze it */
+                       if (size <= memsize)
+                               fits = 1;
+                       /* Look if we still can complete the request by creating a free
+                          block */
+                       else if (size <= cur->size) {
+                               /* Align start address to next 256k boundary */
+                               unsigned int endaddr = cur->addr + cur->size;
+                               memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
+                               /* Can we split current block by inserting a free block at the
+                                  beginning? */
+                               if ((memaddr < endaddr) && (memaddr + size <= endaddr))
+                                       fits = 1;
+                       }
+
+                       if (fits) {
+                               unsigned int size_delta = cur->size - size;
+                               unsigned int size_prefix = memaddr - cur->addr;
+                               if (size_delta < best_min_delta)
+                                       best_min = cur, best_min_delta =
+                                         size_delta, best_min_prefix = size_prefix;
+                               if (size_delta > best_max_delta)
+                                       best_max = cur, best_max_delta =
+                                         size_delta, best_max_prefix = size_prefix;
+                       }
+               }
+
+               cur = cur->next;
+       }
+
+       if (!best_min)
+               return -1;
+
+       /* If minimal block that fits is too large, use largest block that fits */
+       /* But if using the maximal block is going to create a small hole, forget
+          it */
+       if ((best_max_prefix == 0)
+               || (best_max_prefix >= DRAM_HOLE_THRESHOLD)
+               || (best_min_prefix != 0))
+               if (
+                       ((best_min_delta < DRAM_HOLE_THRESHOLD) &&
+                        (best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
+                       ((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
+                        && ((best_max_prefix == 0) ||
+                                (best_max_prefix > best_min_prefix))) ||
+                       ((best_min_prefix != 0) && (best_max_prefix == 0))) {
+                       best_min = best_max;
+                       best_min_delta = best_max_delta;
+                       best_min_prefix = best_max_prefix;
+               }
+
+       /* Compute the DRAM address to return */
+       memaddr = best_min->addr + best_min_prefix;
+       if (bits16)
+               memaddr = (memaddr + 0x1f) & ~0x1f;
+       else
+               memaddr = (memaddr + 0x0f) & ~0x0f;
+
+       /* If we have a considerable hole at the beginning of sample,
+          create a free node describing the hole */
+       if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
+               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+               newmcb->prev = best_min->prev;
+               newmcb->next = best_min;
+               newmcb->addr = best_min->addr;
+               newmcb->size = memaddr - best_min->addr;
+               newmcb->free = 1;
+               best_min->addr = memaddr;
+               best_min->size -= newmcb->size;
+               best_min->prev = newmcb;
+               if (newmcb->prev)
+                       newmcb->prev->next = newmcb;
+       }
+
+       /* Compute the size of hole at the end of block */
+       memsize = (best_min->addr + best_min->size) - (memaddr + size);
+
+       /* Split the block if the block is larger than requested amount */
+       if (memsize > DRAM_SPLIT_THRESHOLD) {
+               /* The next node cannot be free since free blocks are always glued
+                  together */
+               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+               best_min->size -= memsize;
+               newmcb->prev = best_min;
+               newmcb->next = best_min->next;
+               newmcb->addr = best_min->addr + best_min->size;
+               newmcb->size = memsize;
+               newmcb->free = 1;
+               if (best_min->next)
+                       best_min->next->prev = newmcb;
+               best_min->next = newmcb;
+       }
+       best_min->free = 0;
+
+       return memaddr;
+}
+
+static void __gus_mem_free(unsigned int addr)
+{
+       __gus_mcb *cur = gus.mcb;
+       while (cur) {
+               if (!cur->free && (cur->addr <= addr) &&
+                       (cur->addr + cur->size > addr)) {
+                       cur->free = 1;
+
+                       /* If next block is free as well, link them together */
+                       if (cur->next && cur->next->free) {
+                               __gus_mcb *next = cur->next;
+                               cur->size += next->size;
+                               cur->next = next->next;
+                               if (next->next)
+                                       next->next->prev = cur;
+                               MikMod_free(next);
+                       }
+
+                       /* If previous block is free, link current block with it */
+                       if (cur->prev && cur->prev->free) {
+                               cur->prev->size += cur->size;
+                               cur->prev->next = cur->next;
+                               if (cur->next)
+                                       cur->next->prev = cur->prev;
+                               MikMod_free(cur);
+                       }
+                       return;
+               }
+               cur = cur->next;
+       }
+}
+
+static void __gus_mem_pack()
+{
+}
+
+#ifdef MIKMOD_DEBUG
+
+/* Debug dump of GUS DRAM heap */
+void __gus_mem_dump()
+{
+       __gus_mcb *cur = gus.mcb;
+       fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
+       while (cur) {
+               fprintf(stderr, "|  %08X  | %08X |  %6d  |   %s    |\n",
+                               cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
+                               cur->free ? "yes" : " no");
+               cur = cur->next;
+       }
+       fprintf(stderr, "\\------------+----------+----------+----------/\n");
+}
+
+#endif
+
+/************************************************** Middle-level routines *****/
+
+static int __gus_instrument_free(gus_instrument_t * instrument)
+{
+       gus_instrument_t **cur_instr;
+       gus_layer_t *cur_layer;
+       gus_wave_t *cur_wave, *wave_head;
+
+       /* Remove the instrument from the list of registered instruments */
+       cur_instr = (gus_instrument_t **) & gus.instr;
+       while (*cur_instr) {
+               if (*cur_instr == instrument) {
+                       *cur_instr = instrument->next;
+                       goto instr_loaded;
+               }
+               cur_instr = &(*cur_instr)->next;
+       }
+       return -1;
+
+instr_loaded:
+       wave_head = NULL;
+       for (cur_layer = instrument->info.layer; cur_layer;
+                cur_layer = cur_layer->next)
+               /* Free all waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+                       if (!wave_head)
+                               wave_head = cur_wave;
+                       if (cur_wave->begin.memory != (unsigned int)-1)
+                               __gus_mem_free(cur_wave->begin.memory);
+               }
+       if (wave_head)
+               MikMod_free(wave_head);
+
+       MikMod_free(instrument->info.layer);
+       if (instrument->name)
+               MikMod_free(instrument->name);
+       MikMod_free(instrument);
+       return 0;
+}
+
+static gus_instrument_t *__gus_instrument_get(int program)
+{
+       gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
+       while (cur_instr) {
+               if (cur_instr->number.instrument == program)
+                       return cur_instr;
+               cur_instr = cur_instr->next;
+       }
+       return NULL;
+}
+
+static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
+{
+       gus_instrument_t **cur_instr, *instr;
+       gus_layer_t *cur_layer, *dest_layer;
+       gus_wave_t *cur_wave, *dest_wave;
+       unsigned int waves, layers;
+
+       if (!instrument || !instrument->info.layer || !gus.open)
+               return NULL;
+
+       if (__gus_instrument_get(instrument->number.instrument))
+               return NULL;
+
+       instr = (gus_instrument_t *) MikMod_malloc(sizeof(gus_instrument_t));
+       *instr = *instrument;
+
+       if (instrument->name)
+               instr->name = MikMod_strdup(instrument->name);
+
+       /* Make a copy of all layers at once */
+       for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
+               cur_layer = cur_layer->next;
+
+       if (!(dest_layer = instr->info.layer = (gus_layer_t *) MikMod_malloc(sizeof(gus_layer_t) * layers))) {
+               if (instr->name)
+                       MikMod_free(instr->name);
+               MikMod_free(instr);
+               return NULL;
+       }
+       for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
+                cur_layer = cur_layer->next) {
+               *dest_layer = *cur_layer;
+               dest_layer->wave = NULL;
+               /* Count the total number of waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
+                       waves++;
+               if (cur_layer->next)
+                       dest_layer->next = dest_layer + 1;
+               else
+                       dest_layer->next = NULL;
+               dest_layer++;
+       }
+
+       /* Allocate memory for waves */
+       if (!(dest_wave = (gus_wave_t *) MikMod_malloc(sizeof(gus_wave_t) * waves))) {
+               MikMod_free(instr->info.layer);
+               if (instr->name)
+                       MikMod_free(instr->name);
+               MikMod_free(instr);
+               return NULL;
+       }
+       for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
+            cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
+               /* Copy all waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+                       if (!dest_layer->wave)
+                               dest_layer->wave = dest_wave;
+
+                       *dest_wave = *cur_wave;
+                       /* Mark DRAM address as unallocated */
+                       dest_wave->begin.memory = -1;
+
+                       if (cur_wave->next)
+                               dest_wave->next = (dest_wave + 1);
+                       else
+                               dest_wave->next = NULL;
+                       dest_wave++;
+               }
+
+       /* Insert the instrument into list of registered instruments */
+       cur_instr = (gus_instrument_t **) & gus.instr;
+       while (*cur_instr)
+               cur_instr = &(*cur_instr)->next;
+       *cur_instr = instr;
+
+       return instr;
+}
+
+static void __gus_instruments_clear()
+{
+       gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
+       while (cur_instr) {
+               next_instr = cur_instr->next;
+               __gus_instrument_free(cur_instr);
+               cur_instr = next_instr;
+       }
+}
+
+/******************************************************* libGUS interface *****/
+
+/* return value: number of GUS cards installed in system */
+int gus_cards()
+{
+       if (!gus.ok)
+               __gus_init();
+       return gus.ok ? 1 : 0;
+}
+
+int gus_info(gus_info_t * info, int reread)
+{
+       if (!gus.ok)
+               __gus_init();
+       if (!gus.ok)
+               return -1;
+
+       strcpy((char *)info->id, "gus0");
+       info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
+       info->version = gus.version;
+       info->port = gus.port;
+       info->irq = gus.irq[0];
+       info->dma1 = gus.dma[0];
+       info->dma2 = gus.dma[1];
+
+       info->mixing_freq = gus.freq;
+
+       info->memory_size = gus.ram * 1024;
+       info->memory_free = __gus_mem_get_free();
+       info->memory_block_8 = __gus_mem_get_free_8();
+       info->memory_block_16 = __gus_mem_get_free_16();
+       return 0;
+}
+
+int gus_open(int card, size_t queue_buffer_size, int non_block)
+{
+       __dpmi_meminfo struct_info, pool_info;
+
+       if (!gus.ok)
+               __gus_init();
+
+       if (!gus.ok || gus.open || card != 0)
+               return -1;
+
+       /* Now lock the gus structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+       struct_info.size = sizeof(gus);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return -1;
+
+       /* And hook the GF1 interrupt */
+       __irq_stack_count = 4;
+       gus.gf1_irq =
+         irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
+       __irq_stack_count = 1;
+       if (!gus.gf1_irq) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return -1;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(gus.gf1_irq);
+       if (gus.irq[0] > 7)
+               _irq_enable(2);
+
+       /* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
+       if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
+               gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
+       else
+               gus.dma_buff = NULL;
+
+       /* Detect the best available RAM -> DRAM transfer function */
+       if (!gus.transfer) {
+               __gus_detect_transfer();
+               if (gus.transfer != __gus_transfer_dma || !gus.transfer)
+                       dma_free(gus.dma_buff), gus.dma_buff = NULL;
+
+               /* If no transfer function worked, fail */
+               if (!gus.transfer) {
+                       if (gus.dma_buff) {
+                               dma_free(gus.dma_buff);
+                               gus.dma_buff = NULL;
+                       }
+                       __dpmi_unlock_linear_region(&struct_info);
+                       irq_unhook(gus.gf1_irq);
+                       gus.gf1_irq = NULL;
+                       return -1;
+               }
+       }
+
+       /* Allocate and lock command pool buffer */
+       if (queue_buffer_size < 64)
+               queue_buffer_size = 64;
+       if (queue_buffer_size > 16384)
+               queue_buffer_size = 16384;
+       gus.cmd_pool = (unsigned char *) MikMod_malloc(queue_buffer_size);
+       pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
+       pool_info.size = sizeof(queue_buffer_size);
+       if (__dpmi_lock_linear_region(&pool_info)) {
+               if (gus.dma_buff) {
+                       dma_free(gus.dma_buff);
+                       gus.dma_buff = NULL;
+               }
+               __dpmi_unlock_linear_region(&struct_info);
+               irq_unhook(gus.gf1_irq);
+               gus.gf1_irq = NULL;
+               return -1;
+       }
+
+       gus.open++;
+
+       __gus_mem_clear();
+       gus.t1_callback = __gus_timer_update;
+       gus.wt_callback = __gus_wavetable_update;
+       gus.vl_callback = __gus_volume_update;
+       gus_do_tempo(60);                       /* Default is 60 Hz */
+
+       return 0;
+}
+
+int gus_close(int card)
+{
+       __dpmi_meminfo struct_info;
+
+       if (!gus.open || card != 0)
+               return -1;
+
+       /* First reset the card: disable any operation it can currently perform */
+       __gus_reset(0);
+
+       gus.open--;
+
+       /* Stop the timer */
+       gus_timer_stop();
+
+       /* Free DMA buffer if used */
+       if (gus.dma_buff) {
+               dma_free(gus.dma_buff);
+               gus.dma_buff = NULL;
+       }
+
+       /* And unhook the GF1 interrupt */
+       irq_unhook(gus.gf1_irq);
+       gus.gf1_irq = NULL;
+
+       /* Unlock the gus structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+       struct_info.size = sizeof(gus);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       __gus_mem_clear();
+       __gus_instruments_clear();
+
+       return 0;
+}
+
+int gus_select(int card)
+{
+       if (!gus.open || (card != 0))
+               return -1;
+
+       return 0;
+}
+
+/* return value: same as gus_reset function
+   note: this command doesn't change number of active voices and doesn't do
+   hardware reset */
+int gus_reset_engine_only()
+{
+       gus.timer_base = 100;
+       return 0;
+}
+
+int gus_reset(int voices, unsigned int channel_voices)
+{
+       static unsigned short freq_table[32 - 14 + 1] = {
+               44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
+               25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
+       };
+       int voice;
+       int timer;
+
+       /* No support for dynamically allocated voices for now */
+       gus.dynmask = channel_voices;
+
+       if (voices < 14)
+               voices = 14;
+       if (voices > 32)
+               voices = 32;
+
+       /* Stop the timer so that GUS IRQ won't clobber registers */
+       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+       if (timer)
+               gus_timer_stop();
+
+       /* Stop all voices */
+       for (voice = 0; voice < 32; voice++) {
+               __gus_select_voice(voice);
+               __gus_stop_voice();
+               gus.cur_wave[voice] = NULL;
+               gus.cur_vol[voice] = 0;
+
+               __gus_delay();
+
+               /* Reset voice parameters to reasonable values */
+               __gus_set_current(0, 0);
+               __gus_set_loop_start(0, 0);
+               __gus_set_loop_end(0, 0);
+               __gus_outregw(GF1R_VOLUME, 0);
+               __gus_outregb(GF1R_VOLUME_RATE, 0);
+               __gus_outregb(GF1R_VOLUME_START, 0);
+               __gus_outregb(GF1R_VOLUME_END, 0);
+               __gus_outregb(GF1R_BALANCE, 0x7);
+       }
+
+       voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
+
+       if (voice != voices) {
+               int reset = __gus_inregb(GF1R_RESET);
+               __gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
+               __gus_delay();
+               __gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
+               __gus_delay();
+               __gus_outregb(GF1R_RESET, reset);
+       }
+
+       /* Compute the discretization frequence */
+       gus.voices = voices;
+       if (gus.interwave)
+               gus.freq = 44100;
+       else
+               gus.freq = freq_table[voices - 14];
+
+       gus_reset_engine_only();
+
+       if (timer)
+               gus_timer_continue();
+
+       return gus.voices;
+}
+
+int gus_do_flush()
+{
+       DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
+         gus.cmd_pool_ready = 1;
+       return 0;
+}
+
+/* set new tempo */
+void gus_do_tempo(unsigned int tempo)
+{
+       DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
+         gus_timer_tempo(tempo);
+       gus_timer_start();
+}
+
+/* set voice frequency in Hz */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
+{
+       DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
+         __pool_select_voice(voice);
+       __pool_command_w(PCMD_FREQ,
+                                        (((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
+}
+
+/* set voice pan (0-16384) (full left - full right) */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan)
+{
+       DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
+         pan >>= 10;
+       if (pan > 15)
+               pan = 15;
+       __pool_select_voice(voice);
+       __pool_command_b(PCMD_PAN, pan);
+}
+
+/* set voice volume level 0-16384 (linear) */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol)
+{
+       DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
+         if (vol > 0x3fff)
+               vol = 0x3fff;
+       __pool_select_voice(voice);
+       __pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
+}
+
+/* start voice
+ *   voice    : voice #
+ *   program  : program # or ~0 = current
+ *   freq     : frequency in Hz
+ *   volume   : volume level (0-16384) or ~0 = current
+ *   pan      : pan level (0-16384) or ~0 = current
+ */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+                                               unsigned int freq, unsigned short volume,
+                                               unsigned short pan)
+{
+       gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
+}
+
+/* start voice
+ *   voice    : voice #
+ *   program  : program # or ~0 = current
+ *   freq     : frequency in Hz
+ *   volume   : volume level (0-16384) or ~0 = current
+ *   pan      : pan level (0-16384) or ~0 = current
+ *   position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+ */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+                                                                unsigned int freq, unsigned short volume,
+                                                                unsigned short pan, unsigned int position)
+{
+       gus_instrument_t *instrument;
+       gus_wave_t *wave;
+
+       DEBUG_PRINT(
+                               ("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
+                                program, position))
+
+         instrument = __gus_instrument_get(program);
+
+       if (!instrument
+               || !instrument->info.layer
+               || !instrument->info.layer->wave
+               || instrument->flags == GUS_INSTR_F_NOT_FOUND
+               || instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
+
+       gus_do_voice_frequency(voice, freq);
+       gus_do_voice_pan(voice, pan);
+
+       /* We have to set volume different way, to avoid unneeded work in handler */
+       if (volume > 0x3fff)
+               volume = 0x3fff;
+       __pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
+
+       switch (instrument->mode) {
+         case GUS_INSTR_SIMPLE:
+               wave = instrument->info.layer->wave;
+               if (position)
+                       __pool_command_l(PCMD_OFFSET, position);
+               __pool_command_l(PCMD_START, (unsigned long)wave);
+               break;
+       }
+}
+
+/* stop voice
+ *   mode = 0 : stop voice now
+ *   mode = 1 : disable wave loop and finish it
+ */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode)
+{
+       __pool_select_voice(voice);
+       if (mode)
+               __pool_command(PCMD_STOP_LOOP);
+       else
+               __pool_command(PCMD_STOP);
+}
+
+/* wait x ticks - this command is block separator
+   all commands between blocks are interpreted in the begining of one tick */
+void gus_do_wait(unsigned int ticks)
+{
+       DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
+
+         ticks += gus.t1_ticks;
+       while ((int)(ticks - gus.t1_ticks) > 0);
+}
+
+int gus_get_voice_status(int voice)
+{
+       __gus_select_voice(voice);
+       return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
+}
+
+/* return value: file handle (descriptor) for /dev/gus */
+int gus_get_handle()
+{
+       /* Return stdout handle so that select() will "work" with it */
+       return 0;
+}
+
+/* return value: zero if instrument was successfully allocated */
+int gus_memory_alloc(gus_instrument_t * instrument)
+{
+       gus_instrument_t *instr = __gus_instrument_copy(instrument);
+       gus_layer_t *cur_layer;
+       gus_wave_t *cur_wave;
+
+       DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
+
+         if (!instr)
+               return -1;
+
+       for (cur_layer = instr->info.layer; cur_layer;
+                cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
+                                                                                  cur_wave;
+                                                                                  cur_wave = cur_wave->next) {
+                       if (cur_layer->mode == GUS_INSTR_SIMPLE) {
+                               cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
+                                                                                                                cur_wave->format &
+                                                                                                                GUS_WAVE_16BIT);
+                               if (cur_wave->begin.memory == (unsigned int)-1) {
+                                       __gus_instrument_free(instr);
+                                       return -1;
+                               }
+                               gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
+                                                        cur_wave->size, cur_wave->format);
+                       } else if (cur_layer->mode == GUS_INSTR_PATCH)
+                               /* not supported yet */ ;
+               }
+
+       return 0;
+}
+
+/* return value: zero if instrument was successfully removed */
+int gus_memory_free(gus_instrument_t * instrument)
+{
+       gus_instrument_t *cur_instr = gus.instr;
+
+       DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
+
+         for (; cur_instr; cur_instr = cur_instr->next)
+               if (cur_instr->number.instrument == instrument->number.instrument)
+                       return __gus_instrument_free(cur_instr);
+
+       return -1;
+}
+
+/* return value: unused gus memory in bytes */
+int gus_memory_free_size()
+{
+       return __gus_mem_get_free();
+}
+
+/* return value: zero if success */
+int gus_memory_pack()
+{
+       __gus_mem_pack();
+       return 0;
+}
+
+/* return value: gus memory size in bytes */
+int gus_memory_size()
+{
+       return gus.ram * 1024;
+}
+
+/* return value: current largest free block for 8-bit or 16-bit wave */
+int gus_memory_free_block(int w_16bit)
+{
+       return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
+}
+
+/* input value:        see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+   return value: zero if samples & instruments was successfully removed        from
+   GF1 memory manager */
+int gus_memory_reset(int mode)
+{
+       __gus_mem_clear();
+       __gus_instruments_clear();
+       return 0;
+}
+
+/* return value: zero if command queue was successfully flushed */
+int gus_queue_flush()
+{
+       return 0;
+}
+
+/* input value: echo buffer size in items (if 0 - erase echo buffer) */
+int gus_queue_read_set_size(int items)
+{
+       return 0;
+}
+
+/* input value: write queue size in items (each item have 8 bytes) */
+int gus_queue_write_set_size(int items)
+{
+       return 0;
+}
+
+/* return value: zero if successfull */
+int gus_timer_start()
+{
+       gus.timer_ctl_reg |= GF1M_TIMER1;
+       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+       gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
+       outportb(GF1_TIMER_CTRL, 0x04);
+       outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
+       return 0;
+}
+
+/* return value: zero if timer was stoped */
+int gus_timer_stop()
+{
+       gus.timer_ctl_reg &= ~GF1M_TIMER1;
+       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+       gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
+       outportb(GF1_TIMER_CTRL, 0x04);
+       outportb(GF1_TIMER_DATA, gus.timer_ctl);
+       return 0;
+}
+
+/* return value: zero if setup was success */
+int gus_timer_tempo(int ticks)
+{
+       unsigned int counter;
+
+       /* Limit ticks per second to 1..1000 range */
+       if (ticks < 1)
+               ticks = 1;
+       if (ticks > 1000)
+               ticks = 1000;
+
+       /* GF1 timer1 period is 80 usecs, 12500 times per second */
+       counter = 1250000 / (ticks * gus.timer_base);
+       gus.t1_multiple = 1;
+       while (counter > 255) {
+               counter >>= 1;
+               gus.t1_multiple <<= 1;
+       }
+       gus.t1_countdown = gus.t1_multiple;
+       __gus_outregb(GF1R_TIMER1, 256 - counter);
+       return 0;
+}
+
+/* return value: zero if timer will be continue */
+int gus_timer_continue()
+{
+       return gus_timer_start();
+}
+
+/* return value: zero if setup was success (default timebase = 100) */
+int gus_timer_base(int base)
+{
+       gus.timer_base = base;
+       return 0;
+}
+
+void gus_timer_callback(void (*timer_callback) ())
+{
+       gus.timer_callback = timer_callback;
+}
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+                                          unsigned char *src, size_t size)
+{
+       if (!(type & GUS_WAVE_DELTA))
+               return;
+
+       /* This doesn't depend much on wave signedness, since addition/subtraction
+          do not depend on operand signedness */
+       if (type & GUS_WAVE_16BIT) {
+               unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
+               while (size--) {
+                       delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
+                       src += sizeof(unsigned short);
+                       dest += sizeof(unsigned short);
+               }
+       } else {
+               unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
+               while (size--) {
+                       delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
+                       src++;
+                       dest++;
+               }
+       }
+}
+
+int gus_dma_usage (int use)
+{
+       if (gus.dma_buff)
+               return -1;
+       gus.transfer = __gus_transfer_io;
+       return 0;
+}
+
+#endif /* DRV_ULTRA */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosgus.h b/libs/mikmod/drvdos/dosgus.h
new file mode 100644 (file)
index 0000000..ae3488a
--- /dev/null
@@ -0,0 +1,514 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  $Id$
+
+  libGUS-alike definitions for DOS
+
+==============================================================================*/
+
+#ifndef __DOSGUS_H__
+#define __DOSGUS_H__
+
+#include <pc.h>
+#include "dosdma.h"
+#include "dosirq.h"
+#include "libgus.h"
+
+/* Private header file for a libGUS-alike library for DOS */
+
+#define JOYSTICK_TIMER                 (gus.port+0x201)        /* 201 */
+#define JOYSTICK_DATA                  (gus.port+0x201)        /* 201 */
+
+#define GF1_MIDI_CTRL                  (gus.port+0x100)        /* 3X0 */
+#define GF1_MIDI_DATA                  (gus.port+0x101)        /* 3X1 */
+
+#define GF1_VOICESEL                   (gus.port+0x102)        /* 3X2 */
+#define GF1_REGSEL                     (gus.port+0x103)        /* 3X3 */
+#define GF1_DATA                       (gus.port+0x104)        /* 3X4 */
+#define GF1_DATA_LOW                   (gus.port+0x104)        /* 3X4 */
+#define GF1_DATA_HIGH                  (gus.port+0x105)        /* 3X5 */
+#define GF1_IRQ_STATUS                 (gus.port+0x006)        /* 2X6 */
+#define GF1_DRAM                       (gus.port+0x107)        /* 3X7 */
+
+#define GF1_MIX_CTRL                   (gus.port+0x000)        /* 2X0 */
+#define GF1_TIMER_CTRL                 (gus.port+0x008)        /* 2X8 */
+#define GF1_TIMER_DATA                 (gus.port+0x009)        /* 2X9 */
+#define GF1_IRQ_CTRL                   (gus.port+0x00B)        /* 2XB */
+#define GF1_REG_CTRL                   (gus.port+0x00F)        /* 2XF */
+
+#define GF1_REVISION                   (gus.port+0x506)        /* 7X6 */
+
+/* The GF1 hardware clock rate */
+#define CLOCK_RATE                     9878400L
+
+/* GF1 voice-independent registers */
+#define        GF1R_DMA_CONTROL                0x41
+#define        GF1R_DMA_ADDRESS                0x42
+#define        GF1R_DRAM_LOW                   0x43
+#define        GF1R_DRAM_HIGH                  0x44
+
+#define        GF1R_TIMER_CONTROL              0x45
+#define        GF1R_TIMER1                     0x46
+#define        GF1R_TIMER2                     0x47
+
+#define        GF1R_SAMPLE_RATE                0x48
+#define        GF1R_SAMPLE_CONTROL             0x49
+
+#define        GF1R_JOYSTICK                   0x4B
+#define        GF1R_RESET                      0x4C
+
+/* GF1 voice-specific registers */
+#define        GF1R_VOICE_CONTROL              0x00
+#define        GF1R_FREQUENCY                  0x01
+#define        GF1R_START_HIGH                 0x02
+#define        GF1R_START_LOW                  0x03
+#define        GF1R_END_HIGH                   0x04
+#define        GF1R_END_LOW                    0x05
+#define        GF1R_VOLUME_RATE                0x06
+#define        GF1R_VOLUME_START               0x07
+#define        GF1R_VOLUME_END                 0x08
+#define        GF1R_VOLUME                     0x09
+#define        GF1R_ACC_HIGH                   0x0a
+#define        GF1R_ACC_LOW                    0x0b
+#define        GF1R_BALANCE                    0x0c
+#define        GF1R_VOLUME_CONTROL             0x0d
+#define        GF1R_VOICES                     0x0e
+#define        GF1R_IRQ_SOURCE                 0x0f
+
+/* Add this to above registers for reading */
+#define GF1R_READ_MASK                 0x80
+
+/* MIDI */
+#define        GF1M_MIDI_RESET                 0x03
+#define        GF1M_MIDI_ENABLE_XMIT           0x20
+#define        GF1M_MIDI_ENABLE_RCV            0x80
+
+#define        GF1M_MIDI_RCV_FULL              0x01
+#define        GF1M_MIDI_XMIT_EMPTY            0x02
+#define        GF1M_MIDI_FRAME_ERR             0x10
+#define        GF1M_MIDI_OVERRUN               0x20
+#define        GF1M_MIDI_IRQ_PEND              0x80
+
+/* Joystick */
+#define        GF1M_JOY_POSITION               0x0f
+#define        GF1M_JOY_BUTTONS                0xf0
+
+/* GF1_IRQ_STATUS (port 2X6) */
+#define        GF1M_IRQ_MIDI_TX                0x01    /* pending MIDI xmit IRQ */
+#define        GF1M_IRQ_MIDI_RX                0x02    /* pending MIDI recv IRQ */
+#define        GF1M_IRQ_TIMER1                 0x04    /* general purpose timer */
+#define        GF1M_IRQ_TIMER2                 0x08    /* general purpose timer */
+#define        GF1M_IRQ_WAVETABLE              0x20    /* pending wavetable IRQ */
+#define        GF1M_IRQ_ENVELOPE               0x40    /* pending volume envelope IRQ */
+#define        GF1M_IRQ_DMA_COMPLETE           0x80    /* pending dma transfer complete IRQ */
+
+/* GF1_MIX_CTRL (port 2X0) */
+#define        GF1M_MIXER_NO_LINE_IN           0x01    /* 0: enable */
+#define        GF1M_MIXER_NO_OUTPUT            0x02    /* 0: enable */
+#define        GF1M_MIXER_MIC_IN               0x04    /* 1: enable */
+#define        GF1M_MIXER_GF1_IRQ              0x08    /* 1: enable */
+#define GF1M_GF1_COMBINED_IRQ          0x10    /* 1: IRQ1 == IRQ2 */
+#define        GF1M_MIDI_LOOPBACK              0x20    /* 1: enable loop back */
+#define        GF1M_CONTROL_SELECT             0x40    /* 0: DMA latches; 1: IRQ latches */
+
+/* Timer data register (2X9) */
+#define GF1M_START_TIMER1              0x01
+#define GF1M_START_TIMER2              0x02
+#define GF1M_MASK_TIMER1               0x20
+#define GF1M_MASK_TIMER2               0x40
+#define GF1M_TIMER_CLRIRQ              0x80
+
+/* IRQ/DMA control register (2XB) */
+#define GF1M_IRQ_EQUAL                 0x40
+#define GF1M_DMA_EQUAL                 0x40
+
+/* (0x41) DMA control register bits */
+#define        GF1M_DMAR_ENABLE                0x01    /* 1: go */
+#define        GF1M_DMAR_READ                  0x02    /* 1: read (->RAM), 0: write (->DRAM) */
+#define        GF1M_DMAR_CHAN16                0x04    /* 1: 16 bit, 0: 8 bit DMA channel */
+#define        GF1M_DMAR_RATE                  0x18    /* 00: fast, 11: slow */
+#define        GF1M_DMAR_IRQ_ENABLE            0x20    /* 1: enable */
+#define        GF1M_DMAR_IRQ_PENDING           0x40    /* R: DMA irq pending */
+#define        GF1M_DMAR_DATA16                0x40    /* W: 0: 8 bits; 1: 16 bits per sample */
+#define        GF1M_DMAR_TOGGLE_SIGN           0x80    /* W: 1: invert high bit */
+
+/* DMA transfer rate divisors */
+#define        GF1M_DMAR_RATE0                 0x00    /* Fastest DMA xfer (~650khz) */
+#define        GF1M_DMAR_RATE1                 0x08    /* fastest / 2 */
+#define        GF1M_DMAR_RATE2                 0x10    /* fastest / 4 */
+#define        GF1M_DMAR_RATE3                 0x18    /* Slowest DMA xfer (fastest / 8) */
+
+/* (0x45) Timer Control */
+#define GF1M_TIMER1                    0x04    /* Enable timer 1 IRQ */
+#define GF1M_TIMER2                    0x08    /* Enable timer 2 IRQ */
+
+/* (0x49) Sampling (ADC) control register */
+#define        GF1M_DMAW_ENABLE                0x01    /* 1: Start sampling */
+#define        GF1M_DMAW_MODE                  0x02    /* 0: mono, 1: stereo */
+#define        GF1M_DMAW_CHAN16                0x04    /* 0: 8 bit, 1: 16 bit */
+#define        GF1M_DMAW_IRQ_ENABLE            0x20    /* 1: enable IRQ */
+#define        GF1M_DMAW_IRQ_PENDING           0x40    /* 1: irq pending */
+#define        GF1M_DMAW_TOGGLE_SIGN           0x80    /* 1: invert sign bit */
+
+/* (0x4C) GF1 reset register */
+#define        GF1M_MASTER_RESET               0x01    /* 0: hold in reset */
+#define        GF1M_OUTPUT_ENABLE              0x02    /* 1: enable output */
+#define        GF1M_MASTER_IRQ                 0x04    /* 1: master IRQ enable */
+
+/* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
+#define        GF1VC_STOPPED                   0x01    /* 1: voice has stopped */
+#define        GF1VC_STOP                      0x02    /* 1: stop voice */
+#define        GF1VC_DATA16                    0x04    /* 0: 8 bit, 1: 16 bit */
+#define        GF1VC_LOOP_ENABLE               0x08    /* 1: enable */
+#define        GF1VC_BI_LOOP                   0x10    /* 1: bi directional looping */
+#define        GF1VC_IRQ                       0x20    /* 1: enable voice's wave irq */
+#define        GF1VC_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
+#define        GF1VC_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
+
+/* (0x01,0x81) Frequency control */
+/* Bit 0       - Unused */
+/* Bits        1-9     - Fractional portion */
+/* Bits        10-15   - Integer portion */
+
+/* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
+/* Bits        0-11    - HIGH 12 bits of address */
+/* Bits        12-15   - Unused */
+
+/* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
+/* Bits        0-4     - Unused */
+/* Bits        5-8     - Fractional portion */
+/* Bits        9-15    - Low 7 bits of integer portion */
+
+/* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
+/* Bits        0-11    - HIGH 12 bits of address */
+/* Bits        12-15   - Unused */
+
+/* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
+/* Bits        0-4     - Unused */
+/* Bits        5-8     - Fractional portion */
+/* Bits        9-15    - Low 7 bits of integer portion */
+
+/* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
+#define        GF1VL_RATE_MANTISSA             0x3f
+#define        GF1VL_RATE_RANGE                0xC0
+
+/* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
+#define        GF1VL_START_MANT                0x0F
+#define        GF1VL_START_EXP                 0xF0
+
+/* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
+#define        GF1VL_END_MANT                  0x0F
+#define        GF1VL_END_EXP                   0xF0
+
+/* (0x09,0x89) Current volume register - GF1R_VOLUME */
+/* Bits        0-3     - Unused */
+/* Bits        4-11    - Mantissa of current volume */
+/* Bits        10-15   - Exponent of current volume */
+
+/* (0x0A,0x8A) Accumulator value (high) */
+/* Bits        0-12    - HIGH 12 bits of current position (a19-a7) */
+
+/* (0x0B,0x8B) Accumulator value (low) */
+/* Bits        0-8     - Fractional portion */
+/* Bits        9-15    - Integer portion of low adress (a6-a0) */
+
+/* (0x0C,0x8C) Pan (balance) position */
+/* Bits        0-3     - Balance position 0=full left, 0x0f=full right */
+
+/* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
+#define        GF1VL_STOPPED                   0x01    /* volume has stopped */
+#define        GF1VL_STOP                      0x02    /* stop volume */
+#define        GF1VL_ROLLOVER                  0x04    /* Roll PAST end & gen IRQ */
+#define        GF1VL_LOOP_ENABLE               0x08    /* 1: enable */
+#define        GF1VL_BI_LOOP                   0x10    /* 1: bi directional looping */
+#define        GF1VL_IRQ                       0x20    /* 1: enable voice's volume irq */
+#define        GF1VL_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
+#define        GF1VL_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
+
+/* (0x0E,0x8E) Number of active voices */
+/* Bits        0-5     - Number of active voices - 1 */
+
+/* (0x0F,0x8F) Sources of IRQs */
+/* Bits        0-4     - interrupting voice number */
+/* Bit 5       - Always a 1 */
+#define        GF1IRQ_VOLUME                   0x40    /* individual voice irq bit */
+#define        GF1IRQ_WAVE                     0x80    /* individual waveform irq bit */
+
+/* Commands are pooled and executed ON TIMER (1st timer) interrupt.
+ * Currently there is a limit on the number of commands that you can
+ * issue between gus_do_flush (...); this should not be an issue however
+ * because each voice has a limited (little) set of parameters that
+ * you can change (freq, vol, pan... what else?)
+ *
+ * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
+ */
+
+/* Below are definitions for commands placed in GUS command pool */
+#define PCMD_NOP                       0x00    /* Traditionally ... */
+#define PCMD_VOICE                     0x01    /* +B: select voice */
+#define PCMD_START                     0x02    /* +L: start voice */
+#define PCMD_STOP                      0x03    /*     stop voice */
+#define PCMD_FREQ                      0x04    /* +W: set frequence */
+#define PCMD_VOLUME                    0x05    /* +W: set volume */
+#define PCMD_VOLUME_PREPARE            0x06    /* +W: prepare to set volume on (soon to follow) kick */
+#define PCMD_PAN                       0x07    /* +B: set panning */
+#define PCMD_OFFSET                    0x08    /* +L: set DRAM offset */
+#define PCMD_STOP_LOOP                 0x09    /*     stop looping */
+
+#define GUS_VOLCHANGE_RAMP             0x20    /* Volume change ramp speed */
+
+/* Definition for the boolean type */
+typedef unsigned char boolean;
+/* Prototype for functions that do block transfers to GUS DRAM:
+   flags can contain any of the following bits:
+   GUS_WAVE_16BIT    - sample is 16-bit
+   GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
+ */
+typedef void (*__gus_transfer_func) (unsigned long address,
+                                     unsigned char *source,
+                                     unsigned long size, int flags);
+typedef void (*__gus_callback) ();
+typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
+
+/* Structure used to keep track of all on-board GUS memory */
+typedef struct __struct_gus_mcb {
+       struct __struct_gus_mcb *next;          /* Next MCB in chain */
+       struct __struct_gus_mcb *prev;          /* Previous MCB in chain */
+       unsigned int addr;                      /* GUS DRAM address */
+       unsigned int size;                      /* Memory block size */
+       int free;                               /* 1: block is free */
+} __gus_mcb;
+
+/* Structure defining overall GUS state/information */
+typedef struct __gus_state_s {
+       unsigned int port;                      /* Base I/O port (0x220, 0x240, ...) */
+       unsigned int irq[2];                    /* GF1 IRQ and MIDI IRQ */
+       unsigned int dma[2];                    /* Play / record DMA */
+       unsigned int ram;                       /* Memory size (K), i.e. 256, 1024 etc */
+       unsigned int version;                   /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
+       unsigned int freq;                      /* Current mixing frequency */
+       unsigned int voices;                    /* Active voices (14-32) */
+       unsigned int dynmask;                   /* Dynamically allocated voices mask */
+       unsigned int timer_base;                /* The relative timer speed in percents (def: 100) */
+       volatile unsigned int t1_ticks;         /* Incremented per each timer1 tick */
+       volatile unsigned int t2_ticks;         /* Incremented per each timer2 tick */
+       volatile unsigned int t1_countdown;     /* t1_callback is called when this reaches zero */
+       volatile unsigned int t2_countdown;     /* t2_callback is called when this reaches zero */
+       unsigned int t1_multiple;               /* Timer1 handler is called once per such many ticks */
+       unsigned int t2_multiple;               /* Timer2 handler is called once per such many ticks */
+       struct irq_handle *gf1_irq;             /* The interrupt handler for GF1 events */
+       dma_buffer *dma_buff;                   /* Pre-allocated DMA buffer */
+       __gus_callback dma_callback;            /* Routine called at end of DMA transfers */
+       __gus_callback t1_callback;             /* Routine called on Timer1 events */
+       __gus_callback t2_callback;             /* Routine called on Timer1 events */
+       __gus_callback timer_callback;          /* Called once per TEMPO ticks */
+       __gus_callback_3 wt_callback;           /* Routine called on WaveTable events */
+       __gus_callback_3 vl_callback;           /* Routine called on Volume ramp events */
+       __gus_mcb *mcb;                         /* Chained list of memory control blocks */
+       __gus_transfer_func transfer;           /* Best working function for DRAM transfer */
+       gus_instrument_t *instr;                /* The list of registered instruments */
+       unsigned short mixer;                   /* Current mixer register state */
+       unsigned char dma_rate;                 /* One of GF1M_DMAR_RATEX constants defined above */
+       unsigned char timer_ctl;                /* Timer control register value (2x8/2x9) */
+       unsigned char timer_ctl_reg;            /* Timer control register value (GF1/0x45) */
+       boolean ok;                             /* Is the information below okay? */
+       boolean open;                           /* 1 if between gus_open() and gus_close() */
+       boolean ics;                            /* Is it equipped with an ICS mixer? */
+       boolean ics_flipped;                    /* rev 5 (3.7) has flipped R/L mixer */
+       boolean codec;                          /* Is it equipped with a GUS MAX codec? */
+       boolean interwave;                      /* GUS InterWave card */
+       volatile boolean dma_active;            /* DMA is transferring data */
+       volatile boolean cmd_pool_ready;        /* Flush cmd_pool during timer interrupt */
+       unsigned char cmd_voice;                /* Pool selection index cache */
+       unsigned int cmd_pool_top;              /* Command pool top */
+       unsigned char *cmd_pool;                /* Async commands pool */
+       /* The following data is for private use only by interrupt routines! */
+       gus_wave_t *cur_wave[32];               /* Currently played waves */
+       boolean voice_kick[32];                 /* Kick wave on next volume ramp IRQ */
+       unsigned int kick_offs[32];             /* Sample start position on kick */
+       unsigned short cur_vol[32];             /* Current voice volumes */
+       unsigned int cur_voice;                 /* Current voice */
+       unsigned int eow_ignore;                /* Temp ignore end-of-wave IRQ for these voices */
+} __gus_state;
+
+extern __gus_state gus;
+extern void __gus_delay();
+
+static unsigned long __gus_convert_addr16(unsigned long address)
+{
+       return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
+}
+
+/* The XXX_slow routines cannot be used outside IRQ handler! */
+static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportb(GF1_DATA_HIGH, value);
+       __gus_delay();
+       outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportw(GF1_DATA, value);
+       __gus_delay();
+       outportw(GF1_DATA, value);
+}
+
+static inline void __gus_outregb(unsigned char reg, unsigned char value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw(unsigned char reg, unsigned short value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportw(GF1_DATA, value);
+}
+
+static inline unsigned char __gus_inregb(unsigned char reg)
+{
+       if (reg < 0x10)
+               reg |= GF1R_READ_MASK;
+       outportb(GF1_REGSEL, reg);
+       return inportb(GF1_DATA_HIGH);
+}
+
+static inline unsigned short __gus_inregw(unsigned char reg)
+{
+       if (reg < 0x10)
+               reg |= GF1R_READ_MASK;
+       outportb(GF1_REGSEL, reg);
+       return inportw(GF1_DATA);
+}
+
+static inline void __gus_set_dram_address(unsigned int address)
+{
+       __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+       __gus_outregw(GF1R_DRAM_LOW, address);
+}
+
+static inline unsigned char __gus_peek(unsigned int address)
+{
+       __gus_set_dram_address(address);
+       return inportb(GF1_DRAM);
+}
+
+static inline void __gus_poke(unsigned int address, unsigned char value)
+{
+       __gus_set_dram_address(address);
+       outportb(GF1_DRAM, value);
+}
+
+static inline void __gus_select_voice(unsigned char voice)
+{
+       outportb(GF1_VOICESEL, voice);
+}
+
+static inline void __gus_set_current(unsigned char mode,
+                                     unsigned long address)
+{
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_start(unsigned char mode,
+                                                                               unsigned long address)
+{
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_START_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_end(unsigned char mode,
+                                      unsigned long address)
+{
+       address--;
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_END_LOW, address << 5);
+}
+
+static inline void __gus_mixer_output(boolean state)
+{
+       if (state)
+               gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
+       else
+               gus.mixer |= GF1M_MIXER_NO_OUTPUT;
+       outportb(GF1_MIX_CTRL, gus.mixer);
+       /* Dummy read to avoid touching DMA latches */
+       __gus_inregb(GF1R_BALANCE);
+}
+
+/* Inline routines for working with command pools */
+
+/* WARNING: no bounds checking due to performance reasons */
+#define __POOL_VALUE(type,value)                                                               \
+  *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value;        \
+  gus.cmd_pool_top += sizeof (type);
+
+static inline void __pool_command(unsigned char command)
+{
+       __POOL_VALUE(char, command);
+}
+
+static inline void __pool_command_b(unsigned char command, unsigned char arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(char, arg);
+}
+
+static inline void __pool_command_w(unsigned char command, unsigned short arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(short, arg);
+}
+
+static inline void __pool_command_l(unsigned char command, unsigned long arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(long, arg);
+}
+
+static inline void __pool_select_voice(unsigned char voice)
+{
+       if (gus.cmd_voice != voice)
+               __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
+}
+
+#undef __POOL_VALUE
+
+#ifdef DEBUG
+/* Debug dump of GUS DRAM heap */
+extern void __gus_mem_dump();
+#endif
+
+#endif /* __DOSGUS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosirq.c b/libs/mikmod/drvdos/dosirq.c
new file mode 100644 (file)
index 0000000..9b0e21f
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+    Implementation of IRQ routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosirq.h"
+
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include <string.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+unsigned int __irq_stack_size = 0x4000;
+unsigned int __irq_stack_count = 1;
+
+static void __int_stub_template (void)
+{
+/* *INDENT-OFF* */
+       asm("   pushal\n"
+               "       pushl   %ds\n"
+               "       pushl   %es\n"
+               "       pushl   %fs\n"
+               "       pushl   %gs\n"
+               "       movw    $0x1234,%ax\n"          /* Get DPMI data selector */
+               "       movw    %ax,%ds\n"                      /* Set DS and ES to data selector */
+               "       movw    %ax,%es\n"
+               "       movl    $0x12345678,%ebx\n"     /* Interrupt stack top */
+               "       movl    (%ebx),%ecx\n"
+               "       movl    %ecx,%edx\n"
+               "       subl    $0x12345678,%ecx\n"     /* Subtract irq_stack_count */
+               "       movl    %ecx,(%ebx)\n"
+               "       movw    %ss,%si\n"                      /* Save old SS:ESP */
+               "       movl    %esp,%edi\n"
+               "       movl    %edx,%esp\n"            /* Set SS:ESP to interrupt stack */
+               "       movw    %ax,%ss\n"
+               "       pushl   %esi\n"
+               "       pushl   %edi\n"
+               "       pushl   %ebx\n"
+               "       pushl   %edx\n"
+               "       call    1f\n"                           /* Call user interrupt handler */
+               "1:     popl    %edx\n"
+               "       popl    %ebx\n"
+               "       movl    %edx,(%ebx)\n"
+               "       popl    %edi\n"
+               "       popl    %esi\n"
+               "       movl    %edi,%esp\n"            /* Restore old SS:ESP */
+               "       movw    %si,%ss\n"
+               "       popl    %gs\n"
+               "       popl    %fs\n"
+               "       popl    %es\n"
+               "       popl    %ds\n"
+               "       popal\n"
+               "       iret\n");
+/* *INDENT-ON* */
+}
+
+#include <stdio.h>
+
+static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+       unsigned char *irqtpl = (unsigned char *)__int_stub_template;
+       unsigned char *irqend, *irqwrapper, *tmp;
+       __dpmi_meminfo handler_info;
+       unsigned int wrappersize;
+
+       /* First, skip until pushal */
+       while (*irqtpl != 0x60)
+               irqtpl++;
+       /* Now find the iret */
+       irqend = irqtpl;
+       while (*irqend++ != 0xcf);
+
+       wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
+         ((long)irqend - (long)irqtpl);
+       irqwrapper = (unsigned char *) MikMod_malloc(wrappersize);
+       /* Lock the wrapper */
+       handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
+       handler_info.size = wrappersize;
+       if (__dpmi_lock_linear_region(&handler_info)) {
+               MikMod_free(irqwrapper);
+               return -1;
+       }
+
+       /* First comes the interrupt wrapper size */
+       *(unsigned long *)irqwrapper = wrappersize;
+
+       /* Next comes the interrupt stack */
+       tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
+
+       /* The following dword is interrupt stack pointer */
+       *((void **)tmp) = tmp;
+       tmp += 4;
+
+       /* Now comes the interrupt wrapper itself */
+       memcpy(tmp, irqtpl, irqend - irqtpl);
+       *(unsigned short *)(tmp + 9) = _my_ds();
+       *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
+       *(unsigned long *)(tmp + 26) = __irq_stack_size;
+       *(unsigned long *)(tmp + 46) =
+         info->pm_offset - (unsigned long)(tmp + 50);
+
+       info->pm_offset = (unsigned long)tmp;
+       info->pm_selector = _my_cs();
+
+       return 0;
+}
+
+static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+       __dpmi_meminfo handler_info;
+
+       info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
+
+       handler_info.address = __djgpp_base_address + info->pm_offset;
+       handler_info.size = *(unsigned long *)info->pm_offset;
+       __dpmi_unlock_linear_region(&handler_info);
+
+       MikMod_free((void *)info->pm_offset);
+}
+
+struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size)
+{
+       int interrupt;
+       struct irq_handle *irq;
+       __dpmi_version_ret version;
+       __dpmi_meminfo handler_info, struct_info;
+       _go32_dpmi_seginfo info;
+       unsigned long old_sel, old_ofs;
+
+       __dpmi_get_version(&version);
+       if (irqno < 8)
+               interrupt = version.master_pic + irqno;
+       else
+               interrupt = version.slave_pic + (irqno - 8);
+
+       if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
+               return NULL;
+
+       old_sel = info.pm_selector;
+       old_ofs = info.pm_offset;
+
+       info.pm_offset = (unsigned long)handler;
+       if (_allocate_iret_wrapper(&info))
+               return NULL;
+
+       /* Lock the interrupt handler in memory */
+       handler_info.address = __djgpp_base_address + (unsigned long)handler;
+       handler_info.size = size;
+       if (__dpmi_lock_linear_region(&handler_info)) {
+               _free_iret_wrapper(&info);
+               return NULL;
+       }
+
+       irq = (struct irq_handle *) MikMod_malloc(sizeof(struct irq_handle));
+       irq->c_handler = handler;
+       irq->handler_size = size;
+       irq->handler = info.pm_offset;
+       irq->prev_selector = old_sel;
+       irq->prev_offset = old_ofs;
+       irq->int_num = interrupt;
+       irq->irq_num = irqno;
+       irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
+
+       struct_info.address = __djgpp_base_address + (unsigned long)irq;
+       struct_info.size = sizeof(struct irq_handle);
+       if (__dpmi_lock_linear_region(&struct_info)) {
+               MikMod_free(irq);
+               __dpmi_unlock_linear_region(&handler_info);
+               _free_iret_wrapper(&info);
+               return NULL;
+       }
+
+       _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
+
+       irq->pic_mask = irq_state(irq);
+       return irq;
+}
+
+void irq_unhook(struct irq_handle *irq)
+{
+       _go32_dpmi_seginfo info;
+       __dpmi_meminfo mem_info;
+
+       if (!irq)
+               return;
+
+       /* Restore the interrupt vector */
+       irq_disable(irq);
+       info.pm_offset = irq->prev_offset;
+       info.pm_selector = irq->prev_selector;
+       _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
+
+       /* Unlock the interrupt handler */
+       mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
+       mem_info.size = irq->handler_size;
+       __dpmi_unlock_linear_region(&mem_info);
+
+       /* Unlock the irq_handle structure */
+       mem_info.address = __djgpp_base_address + (unsigned long)irq;
+       mem_info.size = sizeof(struct irq_handle);
+       __dpmi_unlock_linear_region(&mem_info);
+
+       info.pm_offset = irq->handler;
+       _free_iret_wrapper(&info);
+
+       /* If IRQ was enabled before we hooked, restore enabled state */
+       if (irq->pic_mask)
+               irq_enable(irq);
+       else
+               irq_disable(irq);
+
+       MikMod_free(irq);
+}
+
+/*---------------------------------------------- IRQ detection mechanism -----*/
+static struct irq_handle *__irqs[16];
+static int (*__irq_confirm) (int irqno);
+static volatile unsigned int __irq_mask;
+static volatile unsigned int __irq_count[16];
+
+#define DECLARE_IRQ_HANDLER(irqno)                                                     \
+static void __irq##irqno##_handler ()                                          \
+{                                                                                                                      \
+  if (irq_check (__irqs [irqno]) && __irq_confirm (irqno))     \
+  {                                                                                                                    \
+    __irq_count [irqno]++;                                                                     \
+    __irq_mask |= (1 << irqno);                                                                \
+  }                                                                                                                    \
+  irq_ack (__irqs [irqno]);                                                                    \
+}
+
+/* *INDENT-OFF* */
+DECLARE_IRQ_HANDLER(0)
+DECLARE_IRQ_HANDLER(1)
+DECLARE_IRQ_HANDLER(2)
+DECLARE_IRQ_HANDLER(3)
+DECLARE_IRQ_HANDLER(4)
+DECLARE_IRQ_HANDLER(5)
+DECLARE_IRQ_HANDLER(6)
+DECLARE_IRQ_HANDLER(7)
+DECLARE_IRQ_HANDLER(8)
+DECLARE_IRQ_HANDLER(9)
+DECLARE_IRQ_HANDLER(10)
+DECLARE_IRQ_HANDLER(11)
+DECLARE_IRQ_HANDLER(12)
+DECLARE_IRQ_HANDLER(13)
+DECLARE_IRQ_HANDLER(14)
+DECLARE_IRQ_HANDLER(15)
+/* *INDENT-ON* */
+
+static void (*__irq_handlers[16]) () = {
+       __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
+         __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
+         __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
+         __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
+
+void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
+{
+       int i;
+
+       __irq_mask = 0;
+       __irq_confirm = irq_confirm;
+       memset(&__irqs, 0, sizeof(__irqs));
+       memset((void *) &__irq_count, 0, sizeof(__irq_count));
+
+       /* Hook all specified IRQs */
+       for (i = 1; i <= 15; i++)
+               if (irqs & (1 << i)) {
+                       __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
+                       /* Enable the interrupt */
+                       irq_enable(__irqs[i]);
+               }
+       /* Enable IRQ2 if we need at least one IRQ above 7 */
+       if (irqs & 0xff00)
+               _irq_enable(2);
+}
+
+void irq_detect_end()
+{
+       int i;
+       for (i = 15; i >= 1; i--)
+               if (__irqs[i])
+                       irq_unhook(__irqs[i]);
+}
+
+int irq_detect_get(int irqno, unsigned int *irqmask)
+{
+       int oldirq = disable();
+       int count = __irq_count[irqno];
+       *irqmask = __irq_mask;
+       __irq_mask = 0;
+       if (oldirq)
+               enable();
+       return count;
+}
+
+void irq_detect_clear()
+{
+       int oldirq = disable();
+       memset((void *) &__irq_count, 0, sizeof(__irq_count));
+       __irq_mask = 0;
+       if (oldirq)
+               enable();
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dosirq.h b/libs/mikmod/drvdos/dosirq.h
new file mode 100644 (file)
index 0000000..eaf60a1
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+    Interface for IRQ routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSIRQ_H__
+#define __DOSIRQ_H__
+
+#include <pc.h>
+
+#define PIC1_BASE      0x20            /* PIC1 base */
+#define PIC2_BASE      0xA0            /* PIC2 base */
+
+struct irq_handle {
+       void (*c_handler) ();           /* The real interrupt handler */
+       unsigned long handler_size;     /* The size of interrupt handler */
+       unsigned long handler;          /* Interrupt wrapper address */
+       unsigned long prev_selector;    /* Selector of previous handler */
+       unsigned long prev_offset;      /* Offset of previous handler */
+       unsigned char irq_num;          /* IRQ number */
+       unsigned char int_num;          /* Interrupt number */
+       unsigned char pic_base;         /* PIC base (0x20 or 0xA0) */
+       unsigned char pic_mask;         /* Old PIC mask state */
+};
+
+/* Return the enabled state for specific IRQ */
+static inline unsigned char irq_state(struct irq_handle * irq)
+{
+       return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7)));
+}
+
+/* Acknowledge the end of interrupt */
+static inline void _irq_ack(int irqno)
+{
+       outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7));
+       /* For second controller we also should acknowledge first controller */
+       if (irqno > 7)
+               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
+}
+
+/* Acknowledge the end of interrupt */
+static inline void irq_ack(struct irq_handle * irq)
+{
+       outportb(irq->pic_base, 0x60 | (irq->irq_num & 7));
+       /* For second controller we also should acknowledge first controller */
+       if (irq->pic_base != PIC1_BASE)
+               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
+}
+
+/* Mask (disable) the particular IRQ given his ordinal */
+static inline void _irq_disable(int irqno)
+{
+       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+       outportb(port_no, inportb(port_no) | (1 << (irqno & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its ordinal */
+static inline void _irq_enable(int irqno)
+{
+       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+       outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7)));
+}
+
+/* Mask (disable) the particular IRQ given its irq_handle structure */
+static inline void irq_disable(struct irq_handle * irq)
+{
+       outportb(irq->pic_base + 1,
+                 inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its irq_handle structure */
+static inline void irq_enable(struct irq_handle * irq)
+{
+       outportb(irq->pic_base + 1,
+                 inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7)));
+}
+
+/* Check if a specific IRQ is pending: return 0 is no */
+static inline int irq_check(struct irq_handle * irq)
+{
+       outportb(irq->pic_base, 0x0B);  /* Read IRR vector */
+       return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7)));
+}
+
+/* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */
+extern struct irq_handle *irq_hook(int irqno, void (*handler)(),
+                                   unsigned long size);
+/* Unhook a previously hooked IRQ */
+extern void irq_unhook(struct irq_handle * irq);
+/* Start IRQ detection process (IRQ list is given with irq mask) */
+/* irq_confirm should return "1" if the IRQ really comes from the device */
+extern void irq_detect_start(unsigned int irqs,
+                             int (*irq_confirm) (int irqno));
+/* Finish IRQ detection process */
+extern void irq_detect_end();
+/* Get the count of specific irqno that happened */
+extern int irq_detect_get(int irqno, unsigned int *irqmask);
+/* Clear IRQ counters */
+extern void irq_detect_clear();
+
+/* The size of interrupt stack */
+extern unsigned int __irq_stack_size;
+/* The number of nested interrupts that can be handled */
+extern unsigned int __irq_stack_count;
+
+#endif /* __DOSIRQ_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dossb.c b/libs/mikmod/drvdos/dossb.c
new file mode 100644 (file)
index 0000000..344ac85
--- /dev/null
@@ -0,0 +1,575 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  Sound Blaster I/O routines, common for SB8, SBPro and SB16
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_SB
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "dossb.h"
+
+/********************************************* Private variables/routines *****/
+
+__sb_state sb;
+
+/* Wait for SoundBlaster for some time */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+#  define _func_noclone
+# else
+#  define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __sb_wait()
+{
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+}
+
+static void sb_irq()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(sb.irq_handle))
+               return;
+
+       sb.irqcount++;
+
+       /* Acknowledge DMA transfer is complete */
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_ack_dma16();
+       else
+               __sb_dsp_ack_dma8();
+
+       /* SoundBlaster 1.x cannot do autoinit ... */
+       if (sb.dspver < SBVER_20)
+               __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
+
+       /* Send EOI */
+       irq_ack(sb.irq_handle);
+
+       enable();
+       if (sb.timer_callback)
+               sb.timer_callback();
+}
+
+static void sb_irq_end()
+{
+}
+
+static boolean __sb_reset()
+{
+       /* Disable the output */
+       sb_output(FALSE);
+
+       /* Clear pending ints if any */
+       __sb_dsp_ack_dma8();
+       __sb_dsp_ack_dma16();
+
+       /* Reset the DSP */
+       outportb(SB_DSP_RESET, SBM_DSP_RESET);
+       __sb_wait();
+       __sb_wait();
+       outportb(SB_DSP_RESET, 0);
+
+       /* Now wait for AA coming from datain port */
+       if (__sb_dsp_in() != 0xaa)
+               return FALSE;
+
+       /* Finally, get the DSP version */
+       if ((sb.dspver = __sb_dsp_version()) == 0xffff)
+               return FALSE;
+       /* Check again */
+       if (sb.dspver != __sb_dsp_version())
+               return FALSE;
+
+       return TRUE;
+}
+
+/***************************************************** SB detection stuff *****/
+
+static int __sb_irq_irqdetect(int irqno)
+{
+       __sb_dsp_ack_dma8();
+       return 1;
+}
+
+static void __sb_irq_dmadetect()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(sb.irq_handle))
+               return;
+
+       sb.irqcount++;
+
+       /* Acknowledge DMA transfer is complete */
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_ack_dma16();
+       else
+               __sb_dsp_ack_dma8();
+
+       /* Send EOI */
+       irq_ack(sb.irq_handle);
+}
+
+static boolean __sb_detect()
+{
+       /* First find the port number */
+       if (!sb.port) {
+               int i;
+               for (i = 5; i >= 0; i--) {
+                       sb.port = 0x210 + i * 0x10;
+                       if (__sb_reset())
+                               break;
+               }
+               if (i < 0) {
+                       sb.port = 0;
+                       return FALSE;
+               }
+       }
+
+       /* Now detect the IRQ and DMA numbers */
+       if (!sb.irq) {
+               unsigned int irqmask, sbirqmask, sbirqcount;
+               unsigned long timer;
+
+               /* IRQ can be one of 2,3,5,7,10 */
+               irq_detect_start(0x04ac, __sb_irq_irqdetect);
+
+               /* Prepare timeout counter */
+               _farsetsel(_dos_ds);
+               timer = _farnspeekl(0x46c);
+
+               sbirqmask = 0;
+               sbirqcount = 10;                /* Emit 10 SB irqs */
+
+               /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
+               __sb_dsp_out(SBDSP_GEN_IRQ8);
+               __sb_wait();
+               for (;;) {
+                       irq_detect_get(0, &irqmask);
+                       if (irqmask) {
+                               sbirqmask |= irqmask;
+                               if (!--sbirqcount)
+                                       break;
+                               __sb_dsp_out(SBDSP_GEN_IRQ8);
+                       }
+                       if (_farnspeekl(0x46c) - timer >= 9)    /* Wait ~1/2 secs */
+                               break;
+               }
+               if (sbirqmask)
+                       for (sb.irq = 15; sb.irq > 0; sb.irq--)
+                               if (irq_detect_get(sb.irq, &irqmask) == 10)
+                                       break;
+
+               irq_detect_end();
+               if (!sb.irq)
+                       return FALSE;
+       }
+
+       /* Detect the 8-bit and 16-bit DMAs */
+       if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
+               static int __dma8[] = { 0, 1, 3 };
+               static int __dma16[] = { 5, 6, 7 };
+               int *dma;
+
+               sb_output(FALSE);
+               /* Temporary hook SB IRQ */
+               sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
+               irq_enable(sb.irq_handle);
+               if (sb.irq > 7)
+                       _irq_enable(2);
+
+               /* Start a short DMA transfer and check if IRQ happened */
+               for (;;) {
+                       int i;
+                       unsigned int timer, oldcount;
+
+                       if (!sb.dma8)
+                               dma = &sb.dma8;
+                       else if ((sb.dspver >= SBVER_16) && !sb.dma16)
+                               dma = &sb.dma16;
+                       else
+                               break;
+
+                       for (i = 0; i < 3; i++) {
+                               boolean success = 1;
+
+                               *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
+                               oldcount = sb.irqcount;
+
+                               dma_disable(*dma);
+                               dma_set_mode(*dma, DMA_MODE_WRITE);
+                               dma_clear_ff(*dma);
+                               dma_set_count(*dma, 2);
+                               dma_enable(*dma);
+
+                               __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
+                               if (dma == &sb.dma8) {
+                                       sb.mode = 0;
+                                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
+                               } else {
+                                       sb.mode = SBMODE_16BITS;
+                                       __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
+                                       __sb_dsp_out(0);
+                                       __sb_dsp_out(1);
+                               }
+
+                               _farsetsel(_dos_ds);
+                               timer = _farnspeekl(0x46c);
+
+                               while (oldcount == sb.irqcount)
+                                       if (_farnspeekl(0x46c) - timer >= 2) {
+                                               success = 0;
+                                               break;
+                                       }
+                               dma_disable(*dma);
+                               if (success)
+                                       break;
+                               *dma = 0;
+                       }
+                       if (!*dma)
+                               break;
+               }
+
+               irq_unhook(sb.irq_handle);
+               sb.irq_handle = NULL;
+               if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+boolean sb_detect()
+{
+       char *env;
+
+       /* Try to find the port and DMA from environment */
+       env = getenv("BLASTER");
+
+       while (env && *env) {
+               /* Skip whitespace */
+               while ((*env == ' ') || (*env == '\t'))
+                       env++;
+               if (!*env)
+                       break;
+
+               switch (*env++) {
+                 case 'A':
+                 case 'a':
+                       if (!sb.port)
+                               sb.port = strtol(env, &env, 16);
+                       break;
+                 case 'E':
+                 case 'e':
+                       if (!sb.aweport)
+                               sb.aweport = strtol(env, &env, 16);
+                       break;
+                 case 'I':
+                 case 'i':
+                       if (!sb.irq)
+                               sb.irq = strtol(env, &env, 10);
+                       break;
+                 case 'D':
+                 case 'd':
+                       if (!sb.dma8)
+                               sb.dma8 = strtol(env, &env, 10);
+                       break;
+                 case 'H':
+                 case 'h':
+                       if (!sb.dma16)
+                               sb.dma16 = strtol(env, &env, 10);
+                       break;
+                 default:
+                       /* Skip other values (H == MIDI, T == model, any other?) */
+                       while (*env && (*env != ' ') && (*env != '\t'))
+                               env++;
+                       break;
+               }
+       }
+
+       /* Try to detect missing sound card parameters */
+       __sb_detect();
+
+       if (!sb.port || !sb.irq || !sb.dma8)
+               return FALSE;
+
+       if (!__sb_reset())
+               return FALSE;
+
+       if ((sb.dspver >= SBVER_16) && !sb.dma16)
+               return FALSE;
+
+       if (sb.dspver >= SBVER_PRO)
+               sb.caps |= SBMODE_STEREO;
+       if (sb.dspver >= SBVER_16 && sb.dma16)
+               sb.caps |= SBMODE_16BITS;
+       if (sb.dspver < SBVER_20)
+               sb.maxfreq_mono = 22222;
+       else
+               sb.maxfreq_mono = 45454;
+       if (sb.dspver <= SBVER_16)
+               sb.maxfreq_stereo = 22727;
+       else
+               sb.maxfreq_stereo = 45454;
+
+       sb.ok = 1;
+       return TRUE;
+}
+
+/* Reset SoundBlaster */
+void sb_reset()
+{
+       sb_stop_dma();
+       __sb_reset();
+}
+
+/* Start working with SoundBlaster */
+boolean sb_open()
+{
+       __dpmi_meminfo struct_info;
+
+       if (!sb.ok)
+               if (!sb_detect())
+                       return FALSE;
+
+       if (sb.open)
+               return FALSE;
+
+       /* Now lock the sb structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+       struct_info.size = sizeof(sb);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return FALSE;
+
+       /* Hook the SB IRQ */
+       sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
+       if (!sb.irq_handle) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return FALSE;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(sb.irq_handle);
+       if (sb.irq > 7)
+               _irq_enable(2);
+
+       sb.open++;
+
+       return TRUE;
+}
+
+/* Finish working with SoundBlaster */
+boolean sb_close()
+{
+       __dpmi_meminfo struct_info;
+       if (!sb.open)
+               return FALSE;
+
+       sb.open--;
+
+       /* Stop/free DMA buffer */
+       sb_stop_dma();
+
+       /* Unhook IRQ */
+       irq_unhook(sb.irq_handle);
+       sb.irq_handle = NULL;
+
+       /* Unlock the sb structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+       struct_info.size = sizeof(sb);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       return TRUE;
+}
+
+/* Enable/disable stereo DSP mode */
+/* Enable/disable speaker output */
+void sb_output(boolean enable)
+{
+       __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
+}
+
+/* Start playing from DMA buffer */
+boolean sb_start_dma(unsigned char mode, unsigned int freq)
+{
+       int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
+       int dmabuffsize;
+       unsigned int tc = 0;            /* timing constant (<=sbpro only) */
+
+       /* Stop DMA transfer if it is enabled */
+       sb_stop_dma();
+
+       /* Sanity check */
+       if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
+               return FALSE;
+
+       /* Check this SB can perform at requested frequency */
+       if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
+               || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
+               return FALSE;
+
+       /* Check the timing constant here to avoid failing later */
+       if (sb.dspver < SBVER_16) {
+               /* SBpro cannot do signed transfer */
+               if (mode & SBMODE_SIGNED)
+                       return FALSE;
+
+               /* Old SBs have a different way on setting DMA timing constant */
+               tc = freq;
+               if (mode & SBMODE_STEREO)
+                       tc *= 2;
+               tc = 1000000 / tc;
+               if (tc > 255)
+                       return FALSE;
+       }
+
+       sb.mode = mode;
+
+       /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
+       dmabuffsize = freq;
+       if (mode & SBMODE_STEREO)
+               dmabuffsize *= 2;
+       if (mode & SBMODE_16BITS)
+               dmabuffsize *= 2;
+       dmabuffsize >>= 2;
+       if (dmabuffsize < 4096)
+               dmabuffsize = 4096;
+       if (dmabuffsize > 32768)
+               dmabuffsize = 32768;
+       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+       sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
+       if (!sb.dma_buff)
+               return FALSE;
+
+       /* Fill DMA buffer with silence */
+       dmabuffsize = sb.dma_buff->size;
+       if (mode & SBMODE_SIGNED)
+               memset(sb.dma_buff->linear, 0, dmabuffsize);
+       else
+               memset(sb.dma_buff->linear, 0x80, dmabuffsize);
+
+       /* Prime DMA for transfer */
+       dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+       /* Tell SoundBlaster to start transfer */
+       if (sb.dspver >= SBVER_16) {    /* SB16 */
+               __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
+
+               /* Start DMA->DAC transfer */
+               __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO |
+                                               ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
+                                                SBDSP_DMA_GENERIC8),
+                                               ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
+                                               ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
+
+               /* Write the length of transfer */
+               dmabuffsize = (dmabuffsize >> 2) - 1;
+               __sb_dsp_out(dmabuffsize);
+               __sb_dsp_out(dmabuffsize >> 8);
+       } else {
+               __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
+               dmabuffsize = (dmabuffsize >> 1) - 1;
+               if (sb.dspver >= SBVER_20) {    /* SB 2.0/Pro */
+                       /* Set stereo mode */
+                       __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
+                       __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
+                       if (sb.dspver >= SBVER_PRO)
+                               __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
+                       else
+                               __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
+               } else {                                /* Original SB */
+                       /* Start DMA->DAC transfer */
+                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
+               }
+       }
+
+       return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void sb_stop_dma()
+{
+       if (!sb.dma_buff)
+               return;
+
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_out(SBDSP_DMA_HALT16);
+       else
+               __sb_dsp_out(SBDSP_DMA_HALT8);
+
+       dma_disable(sb.dma_buff->channel);
+       dma_free(sb.dma_buff);
+       sb.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+       unsigned int dma_left;
+       *dma_size = sb.dma_buff->size;
+       /* It can happen we try to read DMA count when HI/LO bytes will be
+          inconsistent */
+       for (;;) {
+               unsigned int dma_left_test;
+               dma_clear_ff(sb.dma_buff->channel);
+               dma_left_test = dma_get_count(sb.dma_buff->channel);
+               dma_left = dma_get_count(sb.dma_buff->channel);
+               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+                       break;
+       }
+       *dma_pos = *dma_size - dma_left;
+}
+
+#endif /* DRV_SB */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/dossb.h b/libs/mikmod/drvdos/dossb.h
new file mode 100644 (file)
index 0000000..cb8dc70
--- /dev/null
@@ -0,0 +1,341 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  $Id$
+
+  SoundBlaster and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSSB_H__
+#define __DOSSB_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define SB_FM_LEFT_STATUS              (sb.port + 0x00)        /* (r) Left FM status */
+#define SB_FM_LEFT_REGSEL              (sb.port + 0x00)        /* (w) Left FM register select */
+#define SB_FM_LEFT_DATA                        (sb.port + 0x01)        /* (w) Left FM data */
+#define SB_FM_RIGHT_STATUS             (sb.port + 0x02)        /* (r) Right FM status */
+#define SB_FM_RIGHT_REGSEL             (sb.port + 0x02)        /* (w) Right FM register select */
+#define SB_FM_RIGHT_DATA               (sb.port + 0x03)        /* (w) Right FM data */
+#define SB_MIXER_REGSEL                        (sb.port + 0x04)        /* (w) Mixer register select */
+#define SB_MIXER_DATA                  (sb.port + 0x05)        /* (rw)Mixer data */
+#define SB_DSP_RESET                   (sb.port + 0x06)        /* (w) DSP reset */
+#define SB_FM_STATUS                   (sb.port + 0x08)        /* (r) FM status */
+#define SB_FM_REGSEL                   (sb.port + 0x08)        /* (w) FM register select */
+#define SB_FM_DATA                     (sb.port + 0x09)        /* (w) FM data */
+#define SB_DSP_DATA_IN                 (sb.port + 0x0a)        /* (r) DSP data input */
+#define SB_DSP_DATA_OUT                        (sb.port + 0x0c)        /* (w) DSP data output */
+#define SB_DSP_DATA_OUT_STATUS         (sb.port + 0x0c)        /* (r) DSP data output status */
+#define SB_DSP_TIMER_IRQ               (sb.port + 0x0d)        /* (r) clear timer IRQ? */
+#define SB_DSP_DATA_IN_STATUS          (sb.port + 0x0e)        /* (r) DSP data input status */
+#define SB_DSP_DMA8_IRQ                        (sb.port + 0x0e)        /* (r) Acknowledge 8-bit DMA transfer */
+#define SB_DSP_DMA16_IRQ               (sb.port + 0x0f)        /* (r) Acknowledge 16-bit DMA transfer */
+
+/* DSP commands */
+#define SBDSP_ASP_STATUS               0x03    /* ASP Status (SB16ASP) */
+#define SBDSP_STATUS_OLD               0x04    /* DSP Status (Obsolete) (SB2.0-Pro2) */
+#define SBDSP_DIRECT_DAC               0x10    /* Direct DAC, 8-bit (SB) */
+#define SBDSP_DMA_PCM8                 0x14    /* DMA DAC, 8-bit (SB) */
+#define SBDSP_DMA_ADPCM2               0x16    /* DMA DAC, 2-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM2R              0x17    /* DMA DAC, 2-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_PCM8_AUTO            0x1C    /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */
+#define SBDSP_DMA_ADPCM2R_AUTO         0x1F    /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DIRECT_ADC               0x20    /* Direct ADC, 8-bit (SB) */
+#define SBDSP_DMA_ADC8                 0x24    /* DMA ADC, 8-bit (SB) */
+#define SBDSP_DIRECT_ADC8_BURST                0x28    /* Direct ADC, 8-bit (Burst) (SB-Pro2) */
+#define SBDSP_DMA_ADC8_AUTO            0x2C    /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */
+#define SBDSP_MIDI_READ_POLL           0x30    /* MIDI Read Poll (SB) */
+#define SBDSP_MIDI_READ_IRQ            0x31    /* MIDI Read Interrupt (SB) */
+#define SBDSP_MIDI_READ_TIME           0x32    /* MIDI Read Timestamp Poll (SB???) */
+#define SBDSP_MIDI_READ_TIME_IRQ       0x33    /* MIDI Read Timestamp Interrupt (SB???) */
+#define SBDSP_MIDI_RW_POLL             0x34    /* MIDI Read Poll + Write Poll (UART) (SB2.0) */
+#define SBDSP_MIDI_RW_IRQ              0x35    /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_RW_TIME_IRQ         0x37    /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_WRITE_POLL          0x38    /* MIDI Write Poll (SB) */
+#define SBDSP_SET_TIMING               0x40    /* Set Time Constant (SB) */
+#define SBDSP_SET_RATE                 0x41    /* Set Sample Rate, Hz (SB16) */
+#define SBDSP_DMA_CONT8_AUTO           0x45    /* Continue Auto-Initialize DMA, 8-bit (SB16) */
+#define SBDSP_DMA_CONT16_AUTO          0x47    /* Continue Auto-Initialize DMA, 16-bit (SB16) */
+#define SBDSP_SET_DMA_BLOCK            0x48    /* Set DMA Block Size (SB2.0) */
+#define SBDSP_DMA_ADPCM4               0x74    /* DMA DAC, 4-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM4_REF           0x75    /* DMA DAC, 4-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM26              0x76    /* DMA DAC, 2.6-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM26_REF          0x77    /* DMA DAC, 2.6-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM4R_AUTO         0x7D    /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DMA_ADPCM26R_AUTO                0x7F    /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DISABLE_DAC              0x80    /* Silence DAC (SB) */
+#define SBDSP_HS_DMA_DAC8_AUTO         0x90    /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_HS_DMA_ADC8_AUTO         0x98    /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_STEREO_ADC_DIS           0xA0    /* Disable Stereo Input Mode (SBPro Only) */
+#define SBDSP_STEREO_ADC_ENA           0xA8    /* Enable Stereo Input Mode (SBPro Only) */
+#define SBDSP_DMA_GENERIC16            0xB0    /* Generic DAC/ADC DMA (16-bit) (SB16) */
+#define SBDSP_DMA_GENERIC8             0xC0    /* Generic DAC/ADC DMA (8-bit) (SB16) */
+#define SBDSP_DMA_HALT8                        0xD0    /* Halt DMA Operation, 8-bit (SB) */
+#define SBDSP_SPEAKER_ENA              0xD1    /* Enable Speaker (SB) */
+#define SBDSP_SPEAKER_DIS              0xD3    /* Disable Speaker (SB) */
+#define SBDSP_DMA_CONT8                        0xD4    /* Continue DMA Operation, 8-bit (SB) */
+#define SBDSP_DMA_HALT16               0xD5    /* Halt DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_CONT16               0xD6    /* Continue DMA Operation, 16-bit (SB16) */
+#define SBDSP_SPEAKER_STATUS           0xD8    /* Speaker Status (SB) */
+#define SBDSP_DMA_EXIT16_AUTO          0xD9    /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_EXIT8_AUTO           0xDA    /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */
+#define SBDSP_IDENTIFY                 0xE0    /* DSP Identification (SB2.0) */
+#define SBDSP_VERSION                  0xE1    /* DSP Version (SB) */
+#define SBDSP_COPYRIGHT                        0xE3    /* DSP Copyright (SBPro2???) */
+#define SBDSP_WRITE_TEST               0xE4    /* Write Test Register (SB2.0) */
+#define SBDSP_READ_TEST                        0xE8    /* Read Test Register (SB2.0) */
+#define SBDSP_SINE_GEN                 0xF0    /* Sine Generator (SB) */
+#define SBDSP_AUX_STATUS_PRO           0xF1    /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */
+#define SBDSP_GEN_IRQ8                 0xF2    /* IRQ Request, 8-bit (SB) */
+#define SBDSP_GEN_IRQ16                        0xF3    /* IRQ Request, 16-bit (SB16) */
+#define SBDSP_STATUS                   0xFB    /* DSP Status (SB16) */
+#define SBDSP_AUX_STATUS_16            0xFC    /* DSP Auxiliary Status (SB16) */
+#define SBDSP_CMD_STATUS               0xFD    /* DSP Command Status (SB16) */
+
+/* Mixer commands */
+#define SBMIX_RESET                    0x00    /* Reset                        Write       SBPro */
+#define SBMIX_STATUS                   0x01    /* Status                       Read        SBPro */
+#define SBMIX_MASTER_LEVEL1            0x02    /* Master Volume                Read/Write  SBPro Only */
+#define SBMIX_DAC_LEVEL                        0x04    /* DAC Level                    Read/Write  SBPro */
+#define SBMIX_FM_OUTPUT                        0x06    /* FM Output Control            Read/Write  SBPro Only */
+#define SBMIX_MIC_LEVEL                        0x0A    /* Microphone Level             Read/Write  SBPro */
+#define SBMIX_INPUT_SELECT             0x0C    /* Input/Filter Select          Read/Write  SBPro Only */
+#define SBMIX_OUTPUT_SELECT            0x0E    /* Output/Stereo Select         Read/Write  SBPro Only */
+#define SBMIX_FM_LEVEL                 0x22    /* Master Volume                Read/Write  SBPro */
+#define SBMIX_MASTER_LEVEL             0x26    /* FM Level                     Read/Write  SBPro */
+#define SBMIX_CD_LEVEL                 0x28    /* CD Audio Level               Read/Write  SBPro */
+#define SBMIX_LINEIN_LEVEL             0x2E    /* Line In Level                Read/Write  SBPro */
+#define SBMIX_MASTER_LEVEL_L           0x30    /* Master Volume Left           Read/Write  SB16 */
+#define SBMIX_MASTER_LEVEL_R           0x31    /* Master Volume Right          Read/Write  SB16 */
+#define SBMIX_DAC_LEVEL_L              0x32    /* DAC Level Left               Read/Write  SB16 */
+#define SBMIX_DAC_LEVEL_R              0x33    /* DAC Level Right              Read/Write  SB16 */
+#define SBMIX_FM_LEVEL_L               0x34    /* FM Level Left                Read/Write  SB16 */
+#define SBMIX_FM_LEVEL_R               0x35    /* FM Level Right               Read/Write  SB16 */
+#define SBMIX_CD_LEVEL_L               0x36    /* CD Audio Level Left          Read/Write  SB16 */
+#define SBMIX_CD_LEVEL_R               0x37    /* CD Audio Level Right         Read/Write  SB16 */
+#define SBMIX_LINEIN_LEVEL_L           0x38    /* Line In Level Left           Read/Write  SB16 */
+#define SBMIX_LINEIN_LEVEL_R           0x39    /* Line In Level Right          Read/Write  SB16 */
+#define SBMIX_MIC_LEVEL_16             0x3A    /* Microphone Level             Read/Write  SB16 */
+#define SBMIX_PCSPK_LEVEL              0x3B    /* PC Speaker Level             Read/Write  SB16 */
+#define SBMIX_OUTPUT_CONTROL           0x3C    /* Output Control               Read/Write  SB16 */
+#define SBMIX_INPUT_CONTROL_L          0x3D    /* Input Control Left           Read/Write  SB16 */
+#define SBMIX_INPUT_CONTROL_R          0x3E    /* Input Control Right          Read/Write  SB16 */
+#define SBMIX_INPUT_GAIN_L             0x3F    /* Input Gain Control Left      Read/Write  SB16 */
+#define SBMIX_INPUT_GAIN_R             0x40    /* Input Gain Control Right     Read/Write  SB16 */
+#define SBMIX_OUTPUT_GAIN_L            0x41    /* Output Gain Control Left     Read/Write  SB16 */
+#define SBMIX_OUTPUT_GAIN_R            0x42    /* Output Gain Control Right    Read/Write  SB16 */
+#define SBMIX_AGC_CONTROL              0x43    /* Automatic Gain Control (AGC) Read/Write  SB16 */
+#define SBMIX_TREBLE_L                 0x44    /* Treble Left                  Read/Write  SB16 */
+#define SBMIX_TREBLE_R                 0x45    /* Treble Right                 Read/Write  SB16 */
+#define SBMIX_BASS_L                   0x46    /* Bass Left                    Read/Write  SB16 */
+#define SBMIX_BASS_R                   0x47    /* Bass Right                   Read/Write  SB16 */
+#define SBMIX_IRQ_SELECT               0x80    /* IRQ Select                   Read/Write  SB16 */
+#define SBMIX_DMA_SELECT               0x81    /* DMA Select                   Read/Write  SB16 */
+#define SBMIX_IRQ_STATUS               0x82    /* IRQ Status                   Read        SB16 */
+
+/* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */
+#define SBM_DSP_READY                  0x80
+
+/* SB_DSP_RESET / SBMIX_RESET */
+#define SBM_DSP_RESET                  0x01
+
+/* SBMIX_OUTPUT_SELECT */
+#define SBM_MIX_STEREO                 0x02
+#define SBM_MIX_FILTER                 0x20
+
+/* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */
+#define SBM_GENDAC_FIFO                        0x02
+#define SBM_GENDAC_AUTOINIT            0x04
+#define SBM_GENDAC_ADC                 0x08
+/* Second (mode) byte */
+#define SBM_GENDAC_SIGNED              0x10
+#define SBM_GENDAC_STEREO              0x20
+
+/* DSP version masks */
+#define SBVER_10                       0x0100  /* Original SoundBlaster */
+#define SBVER_15                       0x0105  /* SoundBlaster 1.5 */
+#define SBVER_20                       0x0200  /* SoundBlaster 2.0 */
+#define SBVER_PRO                      0x0300  /* SoundBlaster Pro */
+#define SBVER_PRO2                     0x0301  /* SoundBlaster Pro 2 */
+#define SBVER_16                       0x0400  /* SoundBlaster 16 */
+#define SBVER_AWE32                    0x040c  /* SoundBlaster AWE32 */
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE                          0
+#define TRUE                           1
+#endif
+
+/* Play mode bits */
+#define SBMODE_16BITS                  0x0001
+#define SBMODE_STEREO                  0x0002
+#define SBMODE_SIGNED                  0x0004
+
+/* Mask for capabilities that never change */
+#define SBMODE_MASK                    (SBMODE_16BITS | SBMODE_STEREO)
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling sb_detect() or sb_open()... this will ignore environment settings.
+ */
+typedef struct __sb_state_s {
+       boolean ok;                     /* Are structure contents valid? */
+       int port, aweport;              /* sb/awe32 base port */
+       int irq;                        /* SoundBlaster IRQ */
+       int dma8, dma16;                /* 8-bit and 16-bit DMAs */
+       int maxfreq_mono;               /* Maximum discretization frequency / mono mode */
+       int maxfreq_stereo;             /* Maximum discretization frequency / stereo mode */
+       unsigned short dspver;          /* DSP version number */
+       struct irq_handle *irq_handle;  /* The interrupt handler */
+       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
+       unsigned char caps;             /* SoundBlaster capabilities (SBMODE_XXX) */
+       unsigned char mode;             /* Current SB mode (SBMODE_XXX) */
+       boolean open;                   /* Whenever the card has been opened */
+       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
+       void (*timer_callback) ();      /* Called TWICE per buffer play */
+} __sb_state;
+
+extern __sb_state sb;
+
+extern void __sb_wait();
+
+static inline boolean __sb_dsp_ready_in()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY)
+                       return TRUE;
+       return FALSE;
+}
+
+static inline boolean __sb_dsp_ready_out()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0)
+                       return TRUE;
+       return FALSE;
+}
+
+static inline void __sb_dsp_out(unsigned char reg)
+{
+       __sb_dsp_ready_out();
+       outportb(SB_DSP_DATA_OUT, reg);
+}
+
+static inline unsigned char __sb_dsp_in()
+{
+       __sb_dsp_ready_in();
+       return inportb(SB_DSP_DATA_IN);
+}
+
+static inline void __sb_dspreg_out(unsigned char reg, unsigned char val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val);
+}
+
+static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val);
+       __sb_dsp_out(val >> 8);
+}
+
+static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val >> 8);
+       __sb_dsp_out(val);
+}
+
+static inline unsigned char __sb_dspreg_in(unsigned char reg)
+{
+       __sb_dsp_out(reg);
+       return __sb_dsp_in();
+}
+
+static inline void __sb_dsp_ack_dma8()
+{
+       inportb(SB_DSP_DMA8_IRQ);
+}
+
+static inline void __sb_dsp_ack_dma16()
+{
+       inportb(SB_DSP_DMA16_IRQ);
+}
+
+static inline unsigned short __sb_dsp_version()
+{
+       unsigned short ver;
+       __sb_dsp_out(SBDSP_VERSION);
+       __sb_dsp_ready_in();
+       ver = ((unsigned short)__sb_dsp_in()) << 8;
+       ver |= __sb_dsp_in();
+       return ver;
+}
+
+static inline void __sb_mixer_out(unsigned char reg, unsigned char val)
+{
+       outportb(SB_MIXER_REGSEL, reg);
+       outportb(SB_MIXER_DATA, val);
+}
+
+static inline unsigned char __sb_mixer_in(unsigned char reg)
+{
+       outportb(SB_MIXER_REGSEL, reg);
+       return inportb(SB_MIXER_DATA);
+}
+
+/* Enable stereo transfers: sbpro mode only */
+static inline void __sb_stereo(boolean stereo)
+{
+       unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT);
+       if (stereo)
+               val |= SBM_MIX_STEREO;
+       else
+               val &= ~SBM_MIX_STEREO;
+       __sb_mixer_out(SBMIX_OUTPUT_SELECT, val);
+}
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+extern boolean sb_detect();
+/* Reset SoundBlaster */
+extern void sb_reset();
+/* Start working with SoundBlaster */
+extern boolean sb_open();
+/* Finish working with SoundBlaster */
+extern boolean sb_close();
+/* Enable/disable speaker output */
+extern void sb_output(boolean enable);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean sb_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void sb_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+
+#endif /* __DOSSB_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/doswss.c b/libs/mikmod/drvdos/doswss.c
new file mode 100644 (file)
index 0000000..41cdf38
--- /dev/null
@@ -0,0 +1,577 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_WSS
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "doswss.h"
+
+/********************************************* Private variables/routines *****/
+
+__wss_state wss;
+
+/* WSS frequency rates... lower bit selects one of two frequency generators */
+static unsigned int wss_rates[14][2] = {
+       {5510, 0x00 | WSSM_XTAL2},
+       {6620, 0x0E | WSSM_XTAL2},
+       {8000, 0x00 | WSSM_XTAL1},
+       {9600, 0x0E | WSSM_XTAL1},
+       {11025, 0x02 | WSSM_XTAL2},
+       {16000, 0x02 | WSSM_XTAL1},
+       {18900, 0x04 | WSSM_XTAL2},
+       {22050, 0x06 | WSSM_XTAL2},
+       {27420, 0x04 | WSSM_XTAL1},
+       {32000, 0x06 | WSSM_XTAL1},
+       {33075, 0x0C | WSSM_XTAL2},
+       {37800, 0x08 | WSSM_XTAL2},
+       {44100, 0x0A | WSSM_XTAL2},
+       {48000, 0x0C | WSSM_XTAL1}
+};
+
+static void wss_irq()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(wss.irq_handle))
+               return;
+
+       wss.irqcount++;
+
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+
+       /* Write transfer count again */
+       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+       irq_ack(wss.irq_handle);
+
+       enable();
+       if (wss.timer_callback)
+               wss.timer_callback();
+}
+
+static void wss_irq_end()
+{
+}
+
+/* WSS accepts some conventional values instead of frequency in Hz... */
+static unsigned char __wss_getrate(unsigned int *freq)
+{
+       int i, best = -1, delta = 0xffff;
+
+       for (i = 0; i < 14; i++) {
+               int newdelta = abs(wss_rates[i][0] - *freq);
+               if (newdelta < delta)
+                       best = i, delta = newdelta;
+       }
+
+       *freq = wss_rates[best][0];
+       return wss_rates[best][1];
+}
+
+/* Check if we really have a WSS compatible card on given address */
+static boolean __wss_ping()
+{
+       /* Disable CODEC operations first */
+       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+       /* Now put some harmless values in registers and check them */
+       __wss_outreg(WSSR_COUNT_LOW, 0xaa);
+       __wss_outreg(WSSR_COUNT_HIGH, 0x55);
+       return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)
+         && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);
+}
+
+static boolean __wss_reset()
+{
+       int count;
+
+       /* Disable output */
+       wss_output(FALSE);
+
+       /* Now select the test/initialization register */
+       count = 10000;
+       while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {
+               outportb(WSS_ADDR, WSSR_TEST_INIT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       count = 10000;
+       while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {
+               outportb(WSS_ADDR, WSSR_TEST_INIT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       /* Enable playback IRQ */
+       __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+       __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+
+       return TRUE;
+}
+
+static boolean __wss_setformat(unsigned char format)
+{
+       int count;
+
+       outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);
+       outportb(WSS_DATA, format);
+       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
+       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
+
+       /* Wait end of syncronization ... */
+       if (!__wss_wait())
+               return FALSE;
+
+       /* Turn off the ModeChangeEnable bit: do it until it works */
+       count = 10000;
+       while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {
+               outportb(WSS_ADDR, WSSR_PLAY_FORMAT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       return __wss_reset();
+}
+
+/**************************************************** WSS detection stuff *****/
+
+static int __wss_irq_irqdetect(int irqno)
+{
+       unsigned char status = inportb(WSS_STATUS);
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+       /* Reset transfer counter */
+       __wss_outreg(WSSR_COUNT_LOW, 0);
+       __wss_outreg(WSSR_COUNT_HIGH, 0);
+       return (status & WSSM_INT);
+}
+
+static boolean __wss_detect()
+{
+       /* First find the port number */
+       if (!wss.port) {
+               static unsigned int wss_ports[] =
+                 { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };
+               int i;
+               for (i = 0; i < 5; i++) {
+                       wss.port = wss_ports[i];
+                       if (__wss_ping())
+                               break;
+               }
+               if (i < 0) {
+                       wss.port = 0;
+                       return FALSE;
+               }
+       }
+
+       /* Now disable output */
+       wss_output(FALSE);
+
+       /* Detect the DMA channel */
+       if (!wss.dma) {
+               static int __dma[] = { 0, 1, 3 };
+               int i;
+
+               /* Enable playback IRQ */
+               __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+               __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+               /* Start a short DMA transfer and check if DMA count is zero */
+               for (i = 0; i < 3; i++) {
+                       unsigned int timer, status, freq = 44100;
+
+                       wss.dma = __dma[i];
+
+                       dma_disable(wss.dma);
+                       dma_set_mode(wss.dma, DMA_MODE_WRITE);
+                       dma_clear_ff(wss.dma);
+                       dma_set_count(wss.dma, 10);
+                       dma_enable(wss.dma);
+
+                       /* Clear IRQ status */
+                       outportb(WSS_STATUS, 0);
+
+                       __wss_setformat(__wss_getrate(&freq));
+                       __wss_outreg(WSSR_COUNT_LOW, 1);
+                       __wss_outreg(WSSR_COUNT_HIGH, 0);
+                       /* Tell codec to start transfer */
+                       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+                       _farsetsel(_dos_ds);
+                       timer = _farnspeekl(0x46c);
+
+                       while (_farnspeekl(0x46c) - timer <= 2)
+                               if (dma_get_count(wss.dma) == 0)
+                                       break;
+                       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+                       dma_disable(wss.dma);
+
+                       /* Now check if DMA transfer count is zero and an IRQ is pending */
+                       status = inportb(WSS_STATUS);
+                       outportb(WSS_STATUS, 0);
+                       if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))
+                               break;
+
+                       wss.dma = 0;
+               }
+
+               if (!wss.dma)
+                       return FALSE;
+       }
+
+       /* Now detect the IRQ number */
+       if (!wss.irq) {
+               unsigned int i, irqmask, freq = 5510;
+               unsigned long timer, delta = 0x7fffffff;
+
+               /* IRQ can be one of 2,3,5,7,10 */
+               irq_detect_start(0x04ac, __wss_irq_irqdetect);
+
+               dma_disable(wss.dma);
+               dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+               dma_clear_ff(wss.dma);
+               dma_set_count(wss.dma, 1);
+               dma_enable(wss.dma);
+
+               __wss_setformat(__wss_getrate(&freq));
+
+               /* Clear IRQ status */
+               outportb(WSS_STATUS, 0);
+
+               __wss_outreg(WSSR_COUNT_LOW, 0);
+               __wss_outreg(WSSR_COUNT_HIGH, 0);
+
+               /* Prepare timeout counter */
+               _farsetsel(_dos_ds);
+               timer = _farnspeekl(0x46c);
+               while (timer == _farnspeekl(0x46c));
+               timer = _farnspeekl(0x46c);
+
+               /* Reset all IRQ counters */
+               irq_detect_clear();
+
+               /* Tell codec to start transfer */
+               __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+               /* Now wait 1/18 seconds */
+               while (timer == _farnspeekl(0x46c));
+               __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+               dma_disable(wss.dma);
+
+               /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval
+                  of 1/18.2 second, we should have received about 302 interrupts */
+               for (i = 2; i <= 10; i++) {
+                       int count = abs(302 - irq_detect_get(i, &irqmask));
+                       if (count < delta)
+                               wss.irq = i, delta = count;
+               }
+               if (delta > 150)
+                       wss.irq = 0;
+
+               irq_detect_end();
+               if (!wss.irq)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever WSS is present and fill "wss" structure */
+boolean wss_detect()
+{
+       char *env;
+
+       /* Try to find the port and DMA from environment */
+       env = getenv("WSS");
+
+       while (env && *env) {
+               /* Skip whitespace */
+               while ((*env == ' ') || (*env == '\t'))
+                       env++;
+               if (!*env)
+                       break;
+
+               switch (*env++) {
+                 case 'A':
+                 case 'a':
+                       if (!wss.port)
+                               wss.port = strtol(env, &env, 16);
+                       break;
+                 case 'I':
+                 case 'i':
+                       if (!wss.irq)
+                               wss.irq = strtol(env, &env, 10);
+                       break;
+                 case 'D':
+                 case 'd':
+                       if (!wss.dma)
+                               wss.dma = strtol(env, &env, 10);
+                       break;
+                 default:
+                       /* Skip other values */
+                       while (*env && (*env != ' ') && (*env != '\t'))
+                               env++;
+                       break;
+               }
+       }
+
+       /* Try to fill the gaps in wss hardware parameters */
+       __wss_detect();
+
+       if (!wss.port || !wss.irq || !wss.dma)
+               return FALSE;
+
+       if (!__wss_ping())
+               return FALSE;
+
+       if (!__wss_reset())
+               return FALSE;
+
+       wss.ok = 1;
+       return TRUE;
+}
+
+/* Reset WSS */
+void wss_reset()
+{
+       wss_stop_dma();
+       __wss_reset();
+}
+
+/* Open WSS for usage */
+boolean wss_open()
+{
+       __dpmi_meminfo struct_info;
+
+       if (!wss.ok)
+               if (!wss_detect())
+                       return FALSE;
+
+       if (wss.open)
+               return FALSE;
+
+       /* Now lock the wss structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+       struct_info.size = sizeof(wss);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return FALSE;
+
+       /* Hook the WSS IRQ */
+       wss.irq_handle =
+         irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);
+       if (!wss.irq_handle) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return FALSE;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(wss.irq_handle);
+       if (wss.irq > 7)
+               _irq_enable(2);
+
+       wss.open++;
+
+       return TRUE;
+}
+
+/* Finish working with WSS */
+boolean wss_close()
+{
+       __dpmi_meminfo struct_info;
+       if (!wss.open)
+               return FALSE;
+
+       wss.open--;
+
+       /* Stop/free DMA buffer */
+       wss_stop_dma();
+
+       /* Unhook IRQ */
+       irq_unhook(wss.irq_handle);
+       wss.irq_handle = NULL;
+
+       /* Unlock the wss structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+       struct_info.size = sizeof(wss);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       return TRUE;
+}
+
+/* Adjust frequency rate to nearest WSS available */
+unsigned int wss_adjust_freq(unsigned int freq)
+{
+       __wss_getrate(&freq);
+       return freq;
+}
+
+/* Enable/disable speaker output */
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+boolean wss_start_dma(unsigned char mode, unsigned int freq)
+{
+       int dmabuffsize;
+       unsigned char format;
+
+       /* Stop DMA transfer if it is enabled */
+       wss_stop_dma();
+
+       /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */
+       if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))
+               || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))
+               return FALSE;
+
+       /* Find the nearest frequency divisor (rate) */
+       format = __wss_getrate(&freq);
+       wss.mode = mode;
+
+       /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */
+       dmabuffsize = freq;
+       if (mode & WSSMODE_STEREO)
+               dmabuffsize *= 2;
+       if (mode & WSSMODE_16BITS)
+               dmabuffsize *= 2;
+       dmabuffsize >>= 2;
+       if (dmabuffsize < 4096)
+               dmabuffsize = 4096;
+       if (dmabuffsize > 32768)
+               dmabuffsize = 32768;
+       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+       wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);
+       if (!wss.dma_buff)
+               return FALSE;
+
+       /* Fill DMA buffer with silence */
+       dmabuffsize = wss.dma_buff->size;
+       if (mode & WSSMODE_SIGNED)
+               memset(wss.dma_buff->linear, 0, dmabuffsize);
+       else
+               memset(wss.dma_buff->linear, 0x80, dmabuffsize);
+
+       /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */
+       wss.samples = dmabuffsize;
+       if (mode & WSSMODE_16BITS) {
+               wss.samples >>= 1;
+               format |= WSSM_16BITS;
+       }
+
+       if (mode & WSSMODE_STEREO) {
+               wss.samples >>= 1;
+               format |= WSSM_STEREO;
+       }
+
+       if (!__wss_setformat(format)) {
+               wss_stop_dma();
+               return FALSE;
+       }
+
+       /* Prime DMA for transfer */
+       dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+       /* Tell codec how many samples to transfer */
+       wss.samples = (wss.samples >> 1) - 1;
+       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+
+       /* Tell codec to start transfer */
+       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+       return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void wss_stop_dma()
+{
+       if (!wss.dma_buff)
+               return;
+
+       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+       dma_disable(wss.dma);
+       dma_free(wss.dma_buff);
+       wss.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+       unsigned int dma_left;
+       *dma_size = wss.dma_buff->size;
+       /* It can happen we try to read DMA count when HI/LO bytes will be
+          inconsistent */
+       for (;;) {
+               unsigned int dma_left_test;
+               dma_clear_ff(wss.dma);
+               dma_left_test = dma_get_count(wss.dma);
+               dma_left = dma_get_count(wss.dma);
+               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+                       break;
+       }
+       *dma_pos = *dma_size - dma_left;
+}
+
+void wss_output(boolean enable)
+{
+       if (enable)
+               wss.curlevel = wss.level;
+       else
+               wss.curlevel = 0x3f;
+
+       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+void wss_level(int level)
+{
+       if (level < 0)
+               level = 0;
+       if (level > 63)
+               level = 63;
+       wss.curlevel = wss.level = level ^ 63;
+
+       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+#endif /* DRV_WSS */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/doswss.h b/libs/mikmod/drvdos/doswss.h
new file mode 100644 (file)
index 0000000..ae77bb5
--- /dev/null
@@ -0,0 +1,217 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  $Id$
+
+  Windows Sound System and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSWSS_H__
+#define __DOSWSS_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define WSS_ADDR                       (wss.port + 0x04)
+#define WSS_DATA                       (wss.port + 0x05)
+#define WSS_STATUS                     (wss.port + 0x06)
+#define WSS_PIO                                (wss.port + 0x07)
+
+/* WSS_ADDR: Bits 0-4 select an internal register to read/write */
+#define WSSR_INPUT_L                   0x00    /* Left input control register */
+#define WSSR_INPUT_R                   0x01    /* RIght input control register */
+#define WSSR_AUX1_L                    0x02    /* Left Aux #1 input control */
+#define WSSR_AUX1_R                    0x03    /* Right Aux #1 input control */
+#define WSSR_CD_L                      0x04    /* Left Aux #2 input control */
+#define WSSR_CD_R                      0x05    /* Right Aux #2 input control */
+#define WSSR_MASTER_L                  0x06    /* Left output control */
+#define WSSR_MASTER_R                  0x07    /* Right output control */
+#define WSSR_PLAY_FORMAT               0x08    /* Clock and data format */
+#define WSSR_IFACE_CTRL                        0x09    /* Interface control */
+#define WSSR_PIN_CTRL                  0x0a    /* Pin control */
+#define WSSR_TEST_INIT                 0x0b    /* Test and initialization */
+#define WSSR_MISC_INFO                 0x0c    /* Miscellaneaous information */
+#define WSSR_LOOPBACK                  0x0d    /* Digital Mix */
+#define WSSR_COUNT_HIGH                        0x0e    /* Playback Upper Base Count */
+#define WSSR_COUNT_LOW                 0x0f    /* Playback Lower Base Count */
+#define WSSR_ALT_FEATURE_1             0x10    /* alternate #1 feature enable */
+#define WSSR_ALT_FEATURE_2             0x11    /* alternate #2 feature enable */
+#define WSSR_LINE_IN_L                 0x12    /* left line input control */
+#define WSSR_LINE_IN_R                 0x13    /* right line input control */
+#define WSSR_TIMER_LOW                 0x14    /* timer low byte */
+#define WSSR_TIMER_HIGH                        0x15    /* timer high byte */
+#define WSSR_IRQ_STATUS                        0x18    /* irq status register */
+#define WSSR_MONO_IO_CTRL              0x1a    /* mono input/output control */
+#define WSSR_REC_FORMAT                        0x1c    /* record format */
+#define WSSR_REC_COUNT_HIGH            0x1e    /* record upper count */
+#define WSSR_REC_COUNT_LOW             0x1f    /* record lower count */
+
+/* WSS_ADDR bits 7-5 definition */
+#define WSSM_INIT                      0x80    /* Codec is initializing */
+#define WSSM_MCE                       0x40    /* Mode change enable */
+#define WSSM_TRD                       0x20    /* Transfer Request Disable */
+/* bits 4-0 are indirect register address (0-15) */
+
+/* WSS_STATUS bit masks */
+#define WSSM_CUL                       0x80    /* Capture data upper/lower byte */
+#define WSSM_CLR                       0x40    /* Capture left/right sample */
+#define WSSM_CRDY                      0x20    /* Capture data read */
+#define WSSM_SOUR                      0x10    /* Playback over/under run error */
+#define WSSM_PUL                       0x08    /* Playback upper/lower byte */
+#define WSSM_PLR                       0x04    /* Playback left/right sample */
+#define WSSM_PRDY                      0x02    /* Playback data register read */
+#define WSSM_INT                       0x01    /* interrupt status */
+
+/* Definitions for output level registers */
+#define WSSM_MUTE                      0x80    /* Mute this output source */
+/* bits 5-0 are left output attenuation select (0-63) */
+/* bits 5-0 are right output attenuation select (0-63) */
+
+/* Definitions for clock and data format register (WSSR_PLAY_FORMAT) */
+#define WSSM_STEREO                    0x10    /* stero mode */
+#define WSSM_ULAW_8                    0x20    /* 8-bit U-law companded */
+#define WSSM_16BITS                    0x40    /* 16 bit twos complement data - little endian */
+#define WSSM_ALAW_8                    0x60    /* 8-bit A-law companded */
+#define WSSM_16BITS_BE                 0xc0    /* 16-bit twos complement data - big endian */
+#define WSSM_ADPCM_16                  0xa0    /* 16-bit ADPCM */
+/* Bits 3-1 define frequency divisor */
+#define WSSM_XTAL1                     0x00    /* 24.576 crystal */
+#define WSSM_XTAL2                     0x01    /* 16.9344 crystal */
+
+/* Definitions for interface control register (WSSR_IFACE_CTRL) */
+#define WSSM_CAPTURE_PIO               0x80    /* Capture PIO enable */
+#define WSSM_PLAYBACK_PIO              0x40    /* Playback PIO enable */
+#define WSSM_AUTOCALIB                 0x08    /* auto calibrate */
+#define WSSM_SINGLE_DMA                        0x04    /* Use single DMA channel */
+#define WSSM_PLAYBACK_ENABLE           0x01    /* playback enable */
+
+/* Definitions for Pin control register (WSSR_PIN_CTRL) */
+#define WSSM_IRQ_ENABLE                        0x02    /* interrupt enable */
+#define WSSM_XCTL1                     0x40    /* external control #1 */
+#define WSSM_XCTL0                     0x80    /* external control #0 */
+
+/* Definitions for WSSR_TEST_INIT register */
+#define WSSM_CALIB_IN_PROGRESS 0x20    /* auto calibrate in progress */
+
+/* Definitions for misc control register (WSR_MISC_INFO) */
+#define WSSM_MODE2                     0x40    /* MODE 2 */
+#define WSSM_MODE3                     0x6c    /* MODE 3 - enhanced mode */
+
+/* Definitions for codec irq status (WSSR_IRQ_STATUS) */
+#define WSSM_PLAYBACK_IRQ              0x10
+#define WSSM_RECORD_IRQ                        0x20
+#define WSSM_TIMER_IRQ                 0x40
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE                          0
+#define TRUE                           1
+#endif
+
+/* Play mode bits */
+#define WSSMODE_16BITS                 0x0001
+#define WSSMODE_STEREO                 0x0002
+#define WSSMODE_SIGNED                 0x0004
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling wss_detect() or wss_open()... this will ignore environment settings.
+ */
+typedef struct __wss_state_s {
+       boolean ok;                     /* Set if this structure is properly filled */
+       int port;                       /* Base codec port */
+       int irq;                        /* codec IRQ */
+       int dma;                        /* codec DMA */
+       struct irq_handle *irq_handle;  /* The interrupt handler */
+       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
+       unsigned char mode;             /* Current WSS mode (WSSMODE_XXX) */
+       boolean open;                   /* Whenever the card has been opened */
+       int samples;                    /* Number of samples in DMA buffer */
+       unsigned char level;            /* Output level (63..0): doesn't change when mute */
+       unsigned char curlevel;         /* Current output level (63(min)..0(max)) */
+       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
+       void (*timer_callback) ();      /* Called TWICE per buffer play */
+} __wss_state;
+
+extern __wss_state wss;
+
+/* Wait until codec finishes initialization */
+static inline boolean __wss_wait()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if (!(inportb(WSS_ADDR) & WSSM_INIT))
+                       return TRUE;
+       return FALSE;
+}
+
+static inline void __wss_outreg(unsigned char reg, unsigned char val)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, val);
+}
+
+static inline unsigned char __wss_inreg(unsigned char reg)
+{
+       outportb(WSS_ADDR, reg);
+       return inportb(WSS_DATA);
+}
+
+/* Set some bits in a specific register */
+static inline void __wss_regbit_set(unsigned char reg, unsigned char mask)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, inportb(WSS_DATA) | mask);
+}
+
+/* Reset some bits in a specific register */
+static inline void __wss_regbit_reset(unsigned char reg, unsigned char mask)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, inportb(WSS_DATA) & ~mask);
+}
+
+/* Detect whenever WSS is present and fill "wss" structure */
+extern boolean wss_detect();
+/* Reset WSS */
+extern void wss_reset();
+/* Open WSS for usage */
+extern boolean wss_open();
+/* Finish working with WSS */
+extern boolean wss_close();
+/* Enable/disable speaker output */
+extern void wss_output(boolean enable);
+/* Adjust frequency rate to nearest WSS available */
+extern unsigned int wss_adjust_freq(unsigned int freq);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean wss_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void wss_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+/* Set output level (0(min)-63(max)) */
+extern void wss_level(int level);
+
+#endif /* __DOSWSS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drvdos/libgus.h b/libs/mikmod/drvdos/libgus.h
new file mode 100644 (file)
index 0000000..0d66ee9
--- /dev/null
@@ -0,0 +1,402 @@
+/*     MikMod sound library
+       (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+       complete list.
+
+       This library is free software; you can redistribute it and/or modify
+       it under the terms of the GNU Library General Public License as
+       published by the Free Software Foundation; either version 2 of
+       the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU Library General Public License for more details.
+
+       You should have received a copy of the GNU Library General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+       02111-1307, USA.
+*/
+
+/*==============================================================================
+
+  $Id$
+
+  Linux libGUS-alike library for DOS, used by drv_ultra.c under DOS.
+
+==============================================================================*/
+
+/*
+       Current limitations:
+       - Only a subset of libgus is supported
+       - Only one GUS card is supported (due to the fact that ULTRASND environment
+         variable is used)
+       - No Interwawe support (if IW works the old way, it's ok).
+*/
+
+#ifndef __LIBGUS_H__
+#define __LIBGUS_H__
+
+#include <stddef.h>
+
+#define __LITTLE_ENDIAN
+
+typedef struct _gus_info_t gus_info_t;
+typedef struct _gus_instrument_t gus_instrument_t;
+typedef struct _gus_wave_t gus_wave_t;
+typedef struct _gus_layer_t gus_layer_t;
+
+#define GUS_CARD_VERSION_CLASSIC       0x0024  /* revision 2.4 */
+#define GUS_CARD_VERSION_CLASSIC1      0x0034  /* revision 3.4? */
+#define GUS_CARD_VERSION_CLASSIC_ICS   0x0037  /* revision 3.7 (ICS mixer) */
+#define GUS_CARD_VERSION_EXTREME       0x0050  /* GUS Extreme */
+#define GUS_CARD_VERSION_ACE           0x0090  /* GUS ACE */
+#define GUS_CARD_VERSION_MAX           0x00a0  /* GUS MAX - revision 10 */
+#define GUS_CARD_VERSION_MAX1          0x00a1  /* GUS MAX - revision 11 */
+#define GUS_CARD_VERSION_PNP           0x0100  /* GUS Plug & Play */
+
+#define GUS_STRU_INFO_F_DB16           0x00000001      /* 16-bit daughter board present */
+#define GUS_STRU_INFO_F_PCM            0x00000004      /* GF1 PCM during SYNTH enabled */
+#define GUS_STRU_INFO_F_ENHANCED       0x00000008      /* InterWave - enhanced mode */
+#define GUS_STRU_INFO_F_DAEMON         0x00000010      /* instrument daemon is present */
+
+struct _gus_info_t {
+       unsigned char id[8];            /* id of this card (warning! maybe unterminated!!!) */
+
+       unsigned int flags;             /* some info flags - see to GUS_STRU_INFO_F_XXXX */
+       unsigned int version;           /* see to GUS_CARD_VERSION_XXXX constants */
+
+       unsigned short port;
+       unsigned short irq;
+       unsigned short dma1;            /* DMA1 - GF1 download & codec record */
+       unsigned short dma2;            /* DMA2 - GF1 record & codec playback */
+
+       unsigned int mixing_freq;       /* mixing frequency in Hz */
+
+       unsigned int memory_size;       /* in bytes */
+       unsigned int memory_free;       /* in bytes */
+       unsigned int memory_block_8;    /* largest free 8-bit block in memory */
+       unsigned int memory_block_16;   /* largest free 16-bit block in memory */
+};
+
+/* struct gus_instrument_t - mode */
+
+#define GUS_INSTR_SIMPLE       0x00    /* simple format - for MOD players */
+#define GUS_INSTR_PATCH                0x01    /* old GF1 patch format */
+#define GUS_INSTR_COUNT                2
+
+#define GUS_INSTR_F_NORMAL     0x0000  /* normal mode */
+#define GUS_INSTR_F_NOT_FOUND  0x0001  /* instrument can't be loaded */
+#define GUS_INSTR_F_ALIAS      0x0002  /* alias */
+#define GUS_INSTR_F_NOT_LOADED 0x00ff  /* instrument not loaded (not found) */
+
+#define GUS_INSTR_E_NONE       0x0000  /* exclusion mode - none */
+#define GUS_INSTR_E_SINGLE     0x0001  /* exclude single - single note from this instrument */
+#define GUS_INSTR_E_MULTIPLE   0x0002  /* exclude multiple - stop only same note from this instrument */
+
+#define GUS_INSTR_L_NONE       0x0000  /* not layered */
+#define GUS_INSTR_L_ON         0x0001  /* layered */
+#define GUS_INSTR_L_VELOCITY   0x0002  /* layered by velocity */
+#define GUS_INSTR_L_FREQUENCY  0x0003  /* layered by frequency */
+
+struct _gus_instrument_t {
+       union {
+               unsigned int instrument;/* instrument number */
+       } number;
+
+       char *name;                     /* name of this instrument or NULL */
+
+       unsigned int mode:8,            /* see to GUS_INSTR_XXXX */
+           flags:8,                    /* see to GUS_INSTR_F_XXXX */
+           exclusion:4,                /* see to GUS_INSTR_E_XXXX */
+           layer:4;                    /* see to GUS_INSTR_L_XXXX */
+       unsigned short exclusion_group; /* 0 - none, 1-65535 */
+
+       struct {
+               unsigned char effect1:4,/* use global effect if available */
+                   effect2:4;          /* use global effect if available */
+               unsigned char effect1_depth;/* 0-127 */
+               unsigned char effect2_depth;/* 0-127 */
+       } patch;
+
+       union {
+               gus_layer_t *layer;     /* first layer */
+               unsigned int alias;     /* pointer to instrument */
+       } info;
+       gus_instrument_t *next;         /* next instrument */
+};
+
+struct _gus_layer_t {
+       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
+
+       gus_wave_t *wave;
+       gus_layer_t *next;
+};
+
+/* bits for format variable in gus_wave_t */
+
+#define GUS_WAVE_16BIT          0x0001 /* 16-bit wave */
+#define GUS_WAVE_UNSIGNED       0x0002 /* unsigned wave */
+#define GUS_WAVE_INVERT         0x0002 /* same as unsigned wave */
+#define GUS_WAVE_BACKWARD       0x0004 /* forward mode */
+#define GUS_WAVE_LOOP           0x0008 /* loop mode */
+#define GUS_WAVE_BIDIR          0x0010 /* bidirectional mode */
+#define GUS_WAVE_ULAW           0x0020 /* uLaw compressed wave */
+#define GUS_WAVE_RAM            0x0040 /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
+#define GUS_WAVE_ROM            0x0080 /* wave is in ROM */
+#define GUS_WAVE_DELTA          0x0100
+
+#define GUS_WAVE_PATCH_ENVELOPE 0x01   /* envelopes on */
+#define GUS_WAVE_PATCH_SUSTAIN  0x02   /* sustain mode */
+
+struct _gus_wave_t {
+       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
+       unsigned char format;           /* see to GUS_WAVE_XXXX constants */
+       unsigned int size;              /* size of waveform in bytes */
+       unsigned int start;             /* start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned int loop_start;        /* bits loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned int loop_end;          /* loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
+       struct {
+               unsigned int memory;    /* begin of waveform in GUS's memory */
+               unsigned char *ptr;     /* pointer to waveform in system memory */
+       } begin;
+
+       struct {
+               unsigned char flags;
+               unsigned int sample_rate;
+               unsigned int low_frequency;/* low frequency range for this waveform */
+               unsigned int high_frequency;/* high frequency range for this waveform */
+               unsigned int root_frequency;/* root frequency for this waveform */
+               signed short tune;
+               unsigned char balance;
+               unsigned char envelope_rate[6];
+               unsigned char envelope_offset[6];
+               unsigned char tremolo_sweep;
+               unsigned char tremolo_rate;
+               unsigned char tremolo_depth;
+               unsigned char vibrato_sweep;
+               unsigned char vibrato_rate;
+               unsigned char vibrato_depth;
+               unsigned short scale_frequency;
+               unsigned short scale_factor;/* 0-2048 or 0-2 */
+       } patch;
+
+       gus_wave_t *next;
+};
+
+/* defines for gus_memory_reset () */
+#define GUS_DOWNLOAD_MODE_NORMAL 0x0000
+#define GUS_DOWNLOAD_MODE_TEST  0x0001
+
+/*
+    A subset of libgus functions (used by MikMod Ultrasound driver)
+*/
+int gus_cards(void);
+  /*
+   * return value:      number of GUS cards installed in system or
+   *                    zero if driver isn't installed
+   */
+int gus_close(int card);
+  /*
+   * close file (gus synthesizer) previously opened with gusOpen function
+   * return value:      zero if success
+   */
+int gus_do_flush(void);
+  /*
+   * return value:      zero if command queue was successfully flushed
+   *                    in non block mode - number of written bytes
+   */
+void gus_do_tempo(unsigned int tempo);
+  /*
+   * set new tempo
+   */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq);
+  /*
+   * set voice frequency in Hz
+   */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan);
+  /*
+   * set voice pan (0-16384) (full left - full right)
+   */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+                        unsigned int freq, unsigned short volume,
+                        unsigned short pan);
+  /*
+   * start voice
+   *            voice    : voice #
+   *            program  : program # or ~0 = current
+   *            freq     : frequency in Hz
+   *            volume   : volume level (0-16384) or ~0 = current
+   *            pan      : pan level (0-16384) or ~0 = current
+   */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+                                 unsigned int freq, unsigned short volume,
+                                 unsigned short pan, unsigned int position);
+  /*
+   * start voice
+   *            voice    : voice #
+   *            program  : program # or ~0 = current
+   *            freq     : frequency in Hz
+   *            volume   : volume level (0-16384) or ~0 = current
+   *            pan      : pan level (0-16384) or ~0 = current
+   *            position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+   */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode);
+  /*
+   * stop voice
+   *            mode = 0 : stop voice now
+   *            mode = 1 : disable wave loop and finish it
+   */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol);
+  /*
+   * set voice volume level 0-16384 (linear)
+   */
+void gus_do_wait(unsigned int ticks);
+  /*
+   * wait x ticks - this command is block separator
+   * all commands between blocks are interpreted in the begining of one tick
+   */
+int gus_get_voice_status(int voice);
+  /*
+   * THIS IS NOT A FUNCTION OF ORIGINAL libGUS!
+   * Return voice status: -1 on error, 0 if voice stopped, 1 if playing
+   */
+int gus_get_handle(void);
+  /*
+   * return value:      file handle (descriptor) for /dev/gus
+   */
+int gus_info(gus_info_t * info, int reread);
+  /*
+   * return value:      filled info variable with actual values
+   *                    (look at gus.h header file for more informations)
+   * version field:     0x0024  - GUS revision 2.4
+   *                    0x0035  - GUS revision 3.7 with flipped mixer channels
+   *                    0x0037  - GUS revision 3.7
+   *                    0x0090  - GUS ACE
+   *                    0x00a0  - GUS MAX revision 10
+   *                    0x00a1  - GUS MAX revision 11
+   *                    0x0100  - InterWave (full version)
+   * flags field:       see to GUS_STRU_INFO_F_???? constants (gus.h header file)
+   * port field:        port number (for example 0x220)
+   * irq field:         irq number (for example 11)
+   * dma1 field:        dma1 number (for example 5)
+   * dma2 field:        dma2 number (for example 6)
+   * note:              dma1 and dma2 could be same in case of only one dma channel used
+   */
+int gus_memory_alloc(gus_instrument_t * instrument);
+  /*
+   * input value:       look at gus.h for more details about gus_instrument_t structure
+   * return value:      zero if instrument was successfully allocated
+   */
+int gus_memory_free(gus_instrument_t * instrument);
+  /*
+   * input value:       look at gus.h for more details about gus_instrument_t structure
+   * return value:      zero if instrument was successfully removed
+   */
+int gus_memory_size(void);
+  /*
+   * return value:  gus memory size in bytes
+   */
+int gus_memory_free_size(void);
+  /*
+   * return value:      unused gus memory in bytes
+   * warning:           reset function must be called before
+   */
+int gus_memory_free_block(int w_16bit);
+  /*
+   * return value:  current largest free block for 8-bit or 16-bit wave
+   */
+int gus_memory_pack(void);
+  /*
+   * return value:      zero if success
+   */
+int gus_memory_reset(int mode);
+  /*
+   * input value:   see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+   * return value:  zero if samples & instruments was successfully removed
+   *            from GF1 memory manager
+   */
+
+int gus_open(int card, size_t queue_buffer_size, int non_block);
+  /*
+   * input values:      card number,
+   *                    size of command queue buffer (512-1MB)
+   *                    buffer is allocated dynamically,
+   *                    non block mode
+   * return value:      zero if success
+   * note 1:            this function must be called as first
+   *                    open file /dev/gus
+   * note 2:            you can open more cards with one process
+   */
+int gus_queue_flush(void);
+  /*
+   * return value:      zero if command queue was successfully flushed
+   */
+int gus_queue_read_set_size(int items);
+  /*
+   * input value:       echo buffer size in items (if 0 - erase echo buffer)
+   */
+int gus_queue_write_set_size(int items);
+  /*
+   * input value:       write queue size in items (each item have 8 bytes)
+   */
+int gus_reset(int voices, unsigned int channel_voices);
+  /*
+   * input values:      active voices and channel voices (for dynamic allocation)
+   * return value:      number of active voices if reset was successfull (GF1 chip active)
+   */
+int gus_reset_engine_only(void);
+  /*
+   * return value:  same as gus_reset function
+   * note:      this command doesn't change number of active
+   *            voices and doesn't do hardware reset
+   */
+int gus_select(int card);
+  /*
+   * select specified card
+   * return value:      zero if success
+   */
+int gus_timer_start(void);
+  /*
+   * return value:      zero if successfull
+   */
+int gus_timer_stop(void);
+  /*
+   * return value:      zero if timer was stoped
+   */
+int gus_timer_continue(void);
+  /*
+   * return value:  zero if timer will be continue
+   */
+int gus_timer_tempo(int ticks);
+  /*
+   * return value:      zero if setup was success
+   */
+int gus_timer_base(int base);
+  /*
+   * return value:  zero if setup was success (default timebase = 100)
+   */
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+                       unsigned char *src, size_t size);
+  /*
+   * note: dest and src pointers can be equal
+   */
+
+void gus_timer_callback(void (*timer_callback) ());
+  /*
+   * Set a callback to be called once per tempo tick
+   */
+
+int gus_dma_usage (int use);
+  /*
+   * Tell GUS library to use/to not use DMA for sample transfer.
+   * In some environments/on some hardware platforms you will need
+   * to disable DMA in order to function properly. You should call
+   * this function before opening the card.
+   */
+
+#endif /* __LIBGUS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/oldmik/Makefile b/libs/oldmik/Makefile
new file mode 100644 (file)
index 0000000..433b6e2
--- /dev/null
@@ -0,0 +1,39 @@
+oloader = mloader.obj load_s3m.obj load_mod.obj load_uni.obj load_mtm.obj &
+load_m15.obj load_ult.obj load_stm.obj load_xm.obj 
+odriver = mdriver.obj drv_nos.obj drv_gus.obj drv_sb.obj drv_ss.obj
+
+obj = mmio.obj mirq.obj mdma.obj virtch.obj resample.obj munitrk.obj mplayer.obj &
+$(oloader) $(odriver)
+
+alib = mikmod.lib
+
+opt = -5 -fp5 -otexan
+dbg = -d1
+def =
+
+CC = wcc386
+AS = wasm
+CFLAGS = $(dbg) $(opt) $(def) -zq -zu -bt=dos -Isrc
+ASFLAGS = -zq -5pr
+
+$(alib): cflags.occ $(obj)
+       %write objects.lbc $(obj)
+       wlib -b -n $@ @objects
+
+.c: src
+.asm: src
+
+cflags.occ: Makefile
+       %write $@ $(CFLAGS)
+
+.c.obj: .autodepend
+       $(CC) -fo=$@ @cflags.occ $[*
+
+.asm.obj:
+       $(AS) -fo=$@ $(ASFLAGS) $[*
+
+clean: .symbolic
+       del *.obj
+       del *.occ
+       del *.lbc
+       del $(alib)
diff --git a/libs/oldmik/credits.txt b/libs/oldmik/credits.txt
new file mode 100644 (file)
index 0000000..ba45f84
--- /dev/null
@@ -0,0 +1,26 @@
+MikMod 2.10\r
+===========\r
+\r
+\r
+Main programmer:\r
+\r
+        Jean-Paul Mikkers (MikMak)\r
+\r
+\r
+Additional programming:                 what:\r
+\r
+        Paul Fisher (Rao)               everything\r
+        Jake Stine (Air Richter)        everything\r
+        Peter Breitling                 DJGPP porting\r
+        Kodiak                          interfacing\r
+        Sylvain Marchand                GNU-C portability, portable loaders\r
+        Vince Vu (Judge Dredd)          helped with AWE driver\r
+        Mike Leibow                     GUS driver\r
+        Jean Phillippe Ajirent          EMS routines\r
+        Frank Becker                    Sun audio driver\r
+        Roine Gustafsson                Dec Alpha AF audio driver\r
+        Tom Stokes                      Os/2 porting\r
+\r
+If you feel you deserve a place here, please remind mikmak@via.nl.\r
+Sometimes email & code gets lost, ya know ! :)\r
+\r
diff --git a/libs/oldmik/src/drv_gus.c b/libs/oldmik/src/drv_gus.c
new file mode 100644 (file)
index 0000000..7d65432
--- /dev/null
@@ -0,0 +1,1985 @@
+/*\r
+\r
+Name:\r
+DRV_GUS.C\r
+\r
+Description:\r
+Mikmod driver for output on Gravis Ultrasound (native mode i.e. using\r
+the onboard DRAM)\r
+\r
+Portability:\r
+\r
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)\r
+Win95: n\r
+Os2:   n\r
+Linux: n\r
+\r
+(y) - yes\r
+(n) - no (not possible or not useful)\r
+(?) - may be possible, but not tested\r
+\r
+*/\r
+#include <dos.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <conio.h>\r
+#include "mikmod.h"\r
+#include "mirq.h"\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel GUS defines <<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+/* Special macros for Least-most sig. bytes */\r
+#define MAKE_MSW(x)     ((long)((long)(x)) << 16)\r
+#define LSW(x)          ((unsigned int)(x))\r
+#define MSW(x)          ((unsigned int)(((long)x)>>16))\r
+#define MSB(x)          (unsigned char)((unsigned int)(x)>>8)\r
+#define LSB(x)          ((unsigned char)(x))\r
+\r
+/* Make GF1 address for direct chip i/o. */\r
+#define ADDR_HIGH(x) ((unsigned int)((unsigned int)((x>>7L)&0x1fffL)))\r
+#define ADDR_LOW(x)  ((unsigned int)((unsigned int)((x&0x7fL)<<9L)))\r
+\r
+#define JOYSTICK_TIMER  (GUS_PORT+0x201)                /* 201 */\r
+#define JOYSTICK_DATA   (GUS_PORT+0x201)                /* 201 */\r
+\r
+#define GF1_MIDI_CTRL   (GUS_PORT+0x100)                /* 3X0 */\r
+#define GF1_MIDI_DATA   (GUS_PORT+0x101)                /* 3X1 */\r
+\r
+#define GF1_PAGE        (GUS_PORT+0x102)                /* 3X2 */\r
+#define GF1_REG_SELECT  (GUS_PORT+0x103)                /* 3X3 */\r
+#define GF1_VOICE_SELECT (GUS_PORT+0x102)               /* 3X3 */\r
+#define GF1_DATA_LOW    (GUS_PORT+0x104)                /* 3X4 */\r
+#define GF1_DATA_HI     (GUS_PORT+0x105)                /* 3X5 */\r
+#define GF1_IRQ_STAT    (GUS_PORT+0x006)                /* 2X6 */\r
+#define GF1_DRAM        (GUS_PORT+0x107)                /* 3X7 */\r
+\r
+#define GF1_MIX_CTRL    (GUS_PORT+0x000)                /* 2X0 */\r
+#define GF1_TIMER_CTRL  (GUS_PORT+0x008)                /* 2X8 */\r
+#define GF1_TIMER_DATA  (GUS_PORT+0x009)                /* 2X9 */\r
+#define GF1_IRQ_CTRL    (GUS_PORT+0x00B)                /* 2XB */\r
+\r
+/* The GF1 Hardware clock. */\r
+#define CLOCK_RATE              9878400L\r
+\r
+/* Mixer control bits. */\r
+#define ENABLE_LINE             0x01\r
+#define ENABLE_DAC              0x02\r
+#define ENABLE_MIC              0x04\r
+\r
+/* interrupt controller 1 */\r
+#define CNTRL_8259              0x21\r
+#define OCR_8259                0x20\r
+#define EOI                     0x20\r
+#define REARM3                  0x2F3\r
+#define REARM5                  0x2F5\r
+\r
+/* interrupt controller 2 */\r
+#define CNTRL_M_8259                   0x21\r
+#define CNTRL_M2_8259                          0xA1\r
+#define OCR_2_8259              0xA0\r
+\r
+#define DMA_CONTROL             0x41\r
+#define SET_DMA_ADDRESS         0x42\r
+#define SET_DRAM_LOW            0x43\r
+#define SET_DRAM_HIGH           0x44\r
+\r
+#define TIMER_CONTROL           0x45\r
+#define TIMER1                  0x46\r
+#define TIMER2                  0x47\r
+\r
+#define SET_SAMPLE_RATE         0x48\r
+#define SAMPLE_CONTROL          0x49\r
+\r
+#define SET_JOYSTICK            0x4B\r
+#define MASTER_RESET            0x4C\r
+\r
+/* Voice register mapping. */\r
+#define SET_CONTROL                     0x00\r
+#define SET_FREQUENCY           0x01\r
+#define SET_START_HIGH          0x02\r
+#define SET_START_LOW           0x03\r
+#define SET_END_HIGH            0x04\r
+#define SET_END_LOW                     0x05\r
+#define SET_VOLUME_RATE         0x06\r
+#define SET_VOLUME_START        0x07\r
+#define SET_VOLUME_END          0x08\r
+#define SET_VOLUME                      0x09\r
+#define SET_ACC_HIGH            0x0a\r
+#define SET_ACC_LOW                     0x0b\r
+#define SET_BALANCE                     0x0c\r
+#define SET_VOLUME_CONTROL      0x0d\r
+#define SET_VOICES                      0x0e\r
+\r
+#define GET_CONTROL                     0x80\r
+#define GET_FREQUENCY           0x81\r
+#define GET_START_HIGH          0x82\r
+#define GET_START_LOW           0x83\r
+#define GET_END_HIGH            0x84\r
+#define GET_END_LOW                     0x85\r
+#define GET_VOLUME_RATE         0x86\r
+#define GET_VOLUME_START        0x87\r
+#define GET_VOLUME_END          0x88\r
+#define GET_VOLUME                      0x89\r
+#define GET_ACC_HIGH            0x8a\r
+#define GET_ACC_LOW                     0x8b\r
+#define GET_BALANCE                     0x8c\r
+#define GET_VOLUME_CONTROL      0x8d\r
+#define GET_VOICES                      0x8e\r
+#define GET_IRQV                        0x8f\r
+\r
+/********************************************************************\r
+ *\r
+ * MIDI defines\r
+ *\r
+ *******************************************************************/\r
+\r
+#define MIDI_RESET      0x03\r
+#define MIDI_ENABLE_XMIT        0x20\r
+#define MIDI_ENABLE_RCV         0x80\r
+\r
+#define MIDI_RCV_FULL           0x01\r
+#define MIDI_XMIT_EMPTY         0x02\r
+#define MIDI_FRAME_ERR          0x10\r
+#define MIDI_OVERRUN            0x20\r
+#define MIDI_IRQ_PEND           0x80\r
+\r
+/********************************************************************\r
+ *\r
+ * JOYSTICK defines\r
+ *\r
+ *******************************************************************/\r
+\r
+#define JOY_POSITION            0x0f\r
+#define JOY_BUTTONS                     0xf0\r
+\r
+/********************************************************************\r
+ *\r
+ * GF1 irq/dma programmable latches\r
+ *\r
+ *******************************************************************/\r
+\r
+/* GF1_IRQ_STATUS (port 3X6) */\r
+#define MIDI_TX_IRQ                     0x01            /* pending MIDI xmit IRQ */\r
+#define MIDI_RX_IRQ                     0x02            /* pending MIDI recv IRQ */\r
+#define GF1_TIMER1_IRQ          0x04            /* general purpose timer */\r
+#define GF1_TIMER2_IRQ          0x08            /* general purpose timer */\r
+#define WAVETABLE_IRQ           0x20            /* pending wavetable IRQ */\r
+#define ENVELOPE_IRQ            0x40            /* pending volume envelope IRQ */\r
+#define DMA_TC_IRQ                      0x80            /* pending dma tc IRQ */\r
+\r
+\r
+/* GF1_MIX_CTRL (port 2X0) */\r
+#define ENABLE_LINE_IN          0x01            /* 0=enable */\r
+#define ENABLE_OUTPUT           0x02            /* 0=enable */\r
+#define ENABLE_MIC_IN           0x04            /* 1=enable */\r
+#define ENABLE_GF1_IRQ          0x08            /* 1=enable */\r
+#define GF122                           0x10            /* ?? */\r
+#define ENABLE_MIDI_LOOP        0x20            /* 1=enable loop back */\r
+#define SELECT_GF1_REG          0x40            /* 0=irq latches */\r
+                                                                               /* 1=dma latches */\r
+\r
+/********************************************************************\r
+ *\r
+ * GF1 global registers ($41-$4C)\r
+ *\r
+ *******************************************************************/\r
+\r
+/* DMA control register */\r
+#define DMA_ENABLE                      0x01\r
+#define DMA_READ                        0x02            /* 1=read,0=write */\r
+#define DMA_WIDTH_16            0x04            /* 1=16 bit,0=8 bit (dma chan width)*/\r
+#define DMA_RATE                        0x18            /* 00=fast, 11=slow */\r
+#define DMA_IRQ_ENABLE          0x20            /* 1=enable */\r
+#define DMA_IRQ_PENDING         0x40            /* read */\r
+#define DMA_DATA_16                     0x40            /* write (data width) */\r
+#define DMA_TWOS_COMP           0x80            /* 1=do twos comp */\r
+\r
+/* These are the xfer rate bits ... */\r
+#define DMA_R0          0x00            /* Fastest DMA xfer (~650khz) */\r
+#define DMA_R1          0x08            /* fastest / 2 */\r
+#define DMA_R2          0x10            /* fastest / 4 */\r
+#define DMA_R3          0x18            /* Slowest DMA xfer (fastest / 8) */\r
+\r
+/* SAMPLE control register */\r
+#define ENABLE_ADC                      0x01\r
+#define ADC_MODE                        0x02            /* 0=mono, 1=stereo */\r
+#define ADC_DMA_WIDTH           0x04            /* 0=8 bit, 1=16 bit */\r
+#define ADC_IRQ_ENABLE          0x20            /* 1=enable */\r
+#define ADC_IRQ_PENDING         0x40            /* 1=irq pending */\r
+#define ADC_TWOS_COMP           0x80            /* 1=do twos comp */\r
+\r
+/* RESET control register */\r
+#define GF1_MASTER_RESET        0x01            /* 0=hold in reset */\r
+#define GF1_OUTPUT_ENABLE       0x02            /* enable output */\r
+#define GF1_MASTER_IRQ          0x04            /* master IRQ enable */\r
+\r
+/********************************************************************\r
+ *\r
+ * GF1 voice specific registers ($00 - $0E and $80-$8f)\r
+ *\r
+ *******************************************************************/\r
+\r
+/* ($0,$80) Voice control register */\r
+#define VOICE_STOPPED           0x01            /* voice has stopped */\r
+#define STOP_VOICE                      0x02            /* stop voice */\r
+#define VC_DATA_TYPE            0x04            /* 0=8 bit,1=16 bit */\r
+#define VC_LOOP_ENABLE          0x08            /* 1=enable */\r
+#define VC_BI_LOOP                      0x10            /* 1=bi directional looping */\r
+#define VC_WAVE_IRQ                     0x20            /* 1=enable voice's wave irq */\r
+#define VC_DIRECT                       0x40            /* 0=increasing,1=decreasing */\r
+#define VC_IRQ_PENDING          0x80            /* 1=wavetable irq pending */\r
+\r
+/* ($1,$81) Frequency control */\r
+/* Bit 0  - Unused */\r
+/* Bits 1-9 - Fractional portion */\r
+/* Bits 10-15 - Integer portion */\r
+\r
+/* ($2,$82) Accumulator start address (high) */\r
+/* Bits 0-11 - HIGH 12 bits of address */\r
+/* Bits 12-15 - Unused */\r
+\r
+/* ($3,$83) Accumulator start address (low) */\r
+/* Bits 0-4 - Unused */\r
+/* Bits 5-8 - Fractional portion */\r
+/* Bits 9-15 - Low 7 bits of integer portion */\r
+\r
+/* ($4,$84) Accumulator end address (high) */\r
+/* Bits 0-11 - HIGH 12 bits of address */\r
+/* Bits 12-15 - Unused */\r
+\r
+/* ($5,$85) Accumulator end address (low) */\r
+/* Bits 0-4 - Unused */\r
+/* Bits 5-8 - Fractional portion */\r
+/* Bits 9-15 - Low 7 bits of integer portion */\r
+\r
+\r
+/* ($6,$86) Volume Envelope control register */\r
+#define VL_RATE_MANTISSA                0x3f\r
+#define VL_RATE_RANGE                   0xC0\r
+\r
+/* ($7,$87) Volume envelope start */\r
+#define VL_START_MANT                   0x0F\r
+#define VL_START_EXP                    0xF0\r
+\r
+/* ($8,$88) Volume envelope end */\r
+#define VL_END_MANT                             0x0F\r
+#define VL_END_EXP                              0xF0\r
+\r
+/* ($9,$89) Current volume register */\r
+/* Bits 0-3 are unused */\r
+/* Bits 4-11 - Mantissa of current volume */\r
+/* Bits 10-15 - Exponent of current volume */\r
+\r
+/* ($A,$8A) Accumulator value (high) */\r
+/* Bits 0-12 - HIGH 12 bits of current position (a19-a7) */\r
+\r
+/* ($B,$8B) Accumulator value (low) */\r
+/* Bits 0-8 - Fractional portion */\r
+/* Bits 9-15 - Integer portion of low adress (a6-a0) */\r
+\r
+/* ($C,$8C) Pan (balance) position */\r
+/* Bits 0-3 - Balance position  0=full left, 0x0f=full right */\r
+\r
+/* ($D,$8D) Volume control register */\r
+#define VOLUME_STOPPED          0x01            /* volume has stopped */\r
+#define STOP_VOLUME                     0x02            /* stop volume */\r
+#define VC_ROLLOVER                     0x04            /* Roll PAST end & gen IRQ */\r
+#define VL_LOOP_ENABLE          0x08            /* 1=enable */\r
+#define VL_BI_LOOP                      0x10            /* 1=bi directional looping */\r
+#define VL_WAVE_IRQ                     0x20            /* 1=enable voice's wave irq */\r
+#define VL_DIRECT                       0x40            /* 0=increasing,1=decreasing */\r
+#define VL_IRQ_PENDING          0x80            /* 1=wavetable irq pending */\r
+\r
+/* ($E,$8E) # of Active voices */\r
+/* Bits 0-5 - # of active voices -1 */\r
+\r
+/* ($F,$8F) - Sources of IRQs */\r
+/* Bits 0-4 - interrupting voice number */\r
+/* Bit 5 - Always a 1 */\r
+#define VOICE_VOLUME_IRQ        0x40            /* individual voice irq bit */\r
+#define VOICE_WAVE_IRQ          0x80            /* individual waveform irq bit */\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel GUS code <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+static UWORD GUS_PORT;\r
+static UBYTE GUS_VOICES;\r
+static UBYTE GUS_TIMER_CTRL;\r
+static UBYTE GUS_TIMER_MASK;\r
+static UBYTE GUS_MIX_IMAGE;\r
+\r
+static UWORD GUS_DRAM_DMA;\r
+static UWORD GUS_ADC_DMA;\r
+static UWORD GUS_GF1_IRQ;\r
+static UWORD GUS_MIDI_IRQ;\r
+static ULONG GUS_POOL;         /* dram address of first gusmem pool node */\r
+\r
+static UBYTE GUS_SELECT;          /* currently selected GF1 register */\r
+\r
+static void (*GUS_TIMER1_FUNC)(void);\r
+static void (*GUS_TIMER2_FUNC)(void);\r
+\r
+#define UltraSelect(x) outportb(GF1_REG_SELECT,GUS_SELECT=x)\r
+\r
+#define USE_ROLLOVER 0\r
+\r
+/***************************************************************\r
+ * This function will convert the value read from the GF1 registers\r
+ * back to a 'real' address.\r
+ ***************************************************************/\r
+\r
+#define MAKE_MS_SWORD( x )       ((unsigned long)((unsigned long)(x)) << 16)\r
+\r
+static ULONG make_physical_address(UWORD low,UWORD high,UBYTE mode)\r
+{\r
+       UWORD lower_16, upper_16;\r
+       ULONG ret_address, bit_19_20;\r
+\r
+       upper_16 = high >> 9;\r
+       lower_16 = ((high & 0x01ff) << 7) | ((low >> 9) & 0x007f);\r
+\r
+       ret_address = MAKE_MS_SWORD(upper_16) + lower_16;\r
+\r
+       if (mode & VC_DATA_TYPE)\r
+               {\r
+               bit_19_20 = ret_address & 0xC0000;\r
+               ret_address <<= 1;\r
+               ret_address &= 0x3ffff;\r
+               ret_address |= bit_19_20;\r
+               }\r
+\r
+       return( ret_address );\r
+}\r
+\r
+/***************************************************************\r
+ * This function will translate the address if the dma channel\r
+ * is a 16 bit channel. This translation is not necessary for\r
+ * an 8 bit dma channel.\r
+ ***************************************************************/\r
+\r
+static ULONG convert_to_16bit(ULONG address)\r
+/* unsigned long address;               /* 20 bit ultrasound dram address */\r
+{\r
+       ULONG hold_address;\r
+\r
+       hold_address = address;\r
+\r
+       /* Convert to 16 translated address. */\r
+       address = address >> 1;\r
+\r
+       /* Zero out bit 17. */\r
+       address &= 0x0001ffffL;\r
+\r
+       /* Reset bits 18 and 19. */\r
+       address |= (hold_address & 0x000c0000L);\r
+\r
+       return(address);\r
+}\r
+\r
+\r
+static void GF1OutB(UBYTE x,UBYTE y)\r
+{\r
+       UltraSelect(x);\r
+       outportb(GF1_DATA_HI,y);\r
+}\r
+\r
+\r
+static void GF1OutW(UBYTE x,UWORD y)\r
+{\r
+       UltraSelect(x);\r
+       outport(GF1_DATA_LOW,y);\r
+}\r
+\r
+\r
+static UBYTE GF1InB(UBYTE x)\r
+{\r
+       UltraSelect(x);\r
+       return inportb(GF1_DATA_HI);\r
+}\r
+\r
+\r
+static UWORD GF1InW(UBYTE x)\r
+{\r
+       UltraSelect(x);\r
+       return inport(GF1_DATA_LOW);\r
+}\r
+\r
+\r
+static void gf1_delay(void)\r
+{\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+       inportb(GF1_DRAM);\r
+}\r
+\r
+\r
+static UBYTE UltraPeek(ULONG address)\r
+{\r
+       GF1OutW(SET_DRAM_LOW,address);\r
+       GF1OutB(SET_DRAM_HIGH,(address>>16)&0xff);      /* 8 bits */\r
+       return(inportb(GF1_DRAM));\r
+}\r
+\r
+\r
+static void UltraPoke(ULONG address,UBYTE data)\r
+{\r
+       GF1OutW(SET_DRAM_LOW,address);\r
+       GF1OutB(SET_DRAM_HIGH,(address>>16)&0xff);\r
+       outportb(GF1_DRAM,data);\r
+}\r
+\r
+\r
+static void UltraPokeFast(ULONG address,UBYTE *src,ULONG size)\r
+/*\r
+       [address,size> doesn't cross 64k page boundary\r
+*/\r
+{\r
+       if(!size) return;\r
+\r
+       UltraSelect(SET_DRAM_HIGH);\r
+       outportb(GF1_DATA_HI,(address>>16)&0xff);       /* 8 bits */\r
+       UltraSelect(SET_DRAM_LOW);\r
+\r
+       while(size--){\r
+               outport(GF1_DATA_LOW,address);\r
+               outportb(GF1_DRAM,*src);\r
+               address++;\r
+               src++;\r
+       }\r
+}\r
+\r
+\r
+static void UltraPokeChunk(ULONG address,UBYTE *src,ULONG size)\r
+{\r
+       ULONG todo;\r
+\r
+       /* first 'todo' is number of bytes 'till first 64k boundary */\r
+\r
+       todo=0x10000-(address&0xffff);\r
+       if(todo>size) todo=size;\r
+\r
+       do{\r
+               UltraPokeFast(address,src,todo);\r
+               address+=todo;\r
+               src+=todo;\r
+               size-=todo;\r
+\r
+               /* next 'todo' is in chunks of max 64k at once. */\r
+               todo=(size>0xffff) ? 0x10000 : size;\r
+\r
+       } while(todo);\r
+}\r
+\r
+\r
+static ULONG UltraPeekLong(ULONG address)\r
+{\r
+       ULONG data;\r
+       char *s=(char *)&data;\r
+       s[0]=UltraPeek(address);\r
+       s[1]=UltraPeek(address+1);\r
+       s[2]=UltraPeek(address+2);\r
+       s[3]=UltraPeek(address+3);\r
+       return data;\r
+}\r
+\r
+\r
+static void UltraPokeLong(ULONG address,ULONG data)\r
+{\r
+        UltraPokeChunk(address,(UBYTE *)&data,4);\r
+}\r
+\r
+\r
+static void UltraEnableOutput(void)\r
+{\r
+       GUS_MIX_IMAGE &= ~ENABLE_OUTPUT;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+static void UltraDisableOutput(void)\r
+{\r
+       GUS_MIX_IMAGE |= ENABLE_OUTPUT;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+static void UltraEnableLineIn(void)\r
+{\r
+       GUS_MIX_IMAGE &= ~ENABLE_LINE_IN;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+static void UltraDisableLineIn(void)\r
+{\r
+       GUS_MIX_IMAGE |= ENABLE_LINE_IN;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+static void UltraEnableMicIn(void)\r
+{\r
+       GUS_MIX_IMAGE |= ENABLE_MIC_IN;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+\r
+static void UltraDisableMicIn(void)\r
+{\r
+       GUS_MIX_IMAGE &= ~ENABLE_MIC_IN;\r
+       outportb(GF1_MIX_CTRL,GUS_MIX_IMAGE);\r
+}\r
+\r
+\r
+static void UltraReset(int voices)\r
+{\r
+       int v;\r
+\r
+       if(voices<14) voices=14;\r
+       if(voices>32) voices=32;\r
+\r
+       GUS_VOICES=voices;\r
+       GUS_TIMER_CTRL=0;\r
+       GUS_TIMER_MASK=0;\r
+\r
+       UltraPokeLong(0,0);\r
+\r
+       GF1OutB(MASTER_RESET,0x00);\r
+       for(v=0;v<10;v++) gf1_delay();\r
+\r
+       /* Release Reset and wait */\r
+       GF1OutB(MASTER_RESET,GF1_MASTER_RESET);\r
+       for (v=0;v<10;v++) gf1_delay();\r
+\r
+       /* Reset the MIDI port also */\r
+       outportb(GF1_MIDI_CTRL,MIDI_RESET);\r
+       for (v=0;v<10;v++) gf1_delay();\r
+       outportb(GF1_MIDI_CTRL,0x00);\r
+\r
+       /* Clear all interrupts. */\r
+       GF1OutB(DMA_CONTROL,0x00);\r
+       GF1OutB(TIMER_CONTROL,0x00);\r
+       GF1OutB(SAMPLE_CONTROL,0x00);\r
+\r
+       /* Set the number of active voices */\r
+       GF1OutB(SET_VOICES,((voices-1) | 0xC0));\r
+\r
+       /* Clear interrupts on voices. */\r
+       /* Reading the status ports will clear the irqs. */\r
+\r
+       inportb(GF1_IRQ_STAT);\r
+\r
+       GF1InB(DMA_CONTROL);\r
+       GF1InB(SAMPLE_CONTROL);\r
+       GF1InB(GET_IRQV);\r
+\r
+       for(v=0;v<voices;v++){\r
+\r
+               /* Select the proper voice */\r
+               outportb(GF1_PAGE,v);\r
+\r
+               /* Stop the voice and volume */\r
+               GF1OutB(SET_CONTROL,VOICE_STOPPED|STOP_VOICE);\r
+               GF1OutB(SET_VOLUME_CONTROL,VOLUME_STOPPED|STOP_VOLUME);\r
+\r
+               gf1_delay(); /* Wait 4.8 micos. or more. */\r
+\r
+               /* Initialize each voice specific registers. This is not */\r
+               /* really necessary, but is nice for completeness sake .. */\r
+               /* Each application will set up these to whatever values */\r
+               /* it needs. */\r
+\r
+               GF1OutW(SET_FREQUENCY,0x0400);\r
+               GF1OutW(SET_START_HIGH,0);\r
+               GF1OutW(SET_START_LOW,0);\r
+               GF1OutW(SET_END_HIGH,0);\r
+               GF1OutW(SET_END_LOW,0);\r
+               GF1OutB(SET_VOLUME_RATE,0x01);\r
+               GF1OutB(SET_VOLUME_START,0x10);\r
+               GF1OutB(SET_VOLUME_END,0xe0);\r
+               GF1OutW(SET_VOLUME,0x0000);\r
+\r
+               GF1OutW(SET_ACC_HIGH,0);\r
+               GF1OutW(SET_ACC_LOW,0);\r
+               GF1OutB(SET_BALANCE,0x07);\r
+       }\r
+\r
+       inportb(GF1_IRQ_STAT);\r
+\r
+       GF1InB(DMA_CONTROL);\r
+       GF1InB(SAMPLE_CONTROL);\r
+       GF1InB(GET_IRQV);\r
+\r
+       /* Set up GF1 Chip for interrupts & enable DACs. */\r
+/*     GF1OutB(MASTER_RESET,GF1_MASTER_RESET|GF1_OUTPUT_ENABLE); */\r
+       GF1OutB(MASTER_RESET,GF1_MASTER_RESET|GF1_OUTPUT_ENABLE|GF1_MASTER_IRQ);\r
+}\r
+\r
+\r
+static BOOL UltraProbe(void)\r
+{\r
+       UBYTE s1,s2,t1,t2;\r
+\r
+       /* Pull a reset on the GF1 */\r
+\r
+       GF1OutB(MASTER_RESET,0x00);\r
+\r
+       /* Wait a little while ... */\r
+       gf1_delay();\r
+       gf1_delay();\r
+\r
+       /* Release Reset */\r
+       GF1OutB(MASTER_RESET,GF1_MASTER_RESET);\r
+\r
+       gf1_delay();\r
+       gf1_delay();\r
+\r
+       s1=UltraPeek(0); s2=UltraPeek(1);\r
+       UltraPoke(0,0xaa); t1=UltraPeek(0);\r
+       UltraPoke(1,0x55); t2=UltraPeek(1);\r
+       UltraPoke(0,s1); UltraPoke(1,s2);\r
+\r
+       return(t1==0xaa && t2==0x55);\r
+}\r
+\r
+\r
+\r
+static BOOL UltraDetect(void)\r
+{\r
+       char *ptr;\r
+\r
+       if((ptr=getenv("ULTRASND"))==NULL) return 0;\r
+\r
+       if(sscanf(ptr,"%hx,%hd,%hd,%hd,%hd",\r
+                               &GUS_PORT,\r
+                               &GUS_DRAM_DMA,\r
+                               &GUS_ADC_DMA,\r
+                               &GUS_GF1_IRQ,\r
+                               &GUS_MIDI_IRQ)!=5) return 0;\r
+\r
+       return(UltraProbe());\r
+}\r
+\r
+\r
+\r
+\r
+static UBYTE dmalatch[8]       ={ 0,1,0,2,0,3,4,5 };\r
+static UBYTE irqlatch[16]      ={ 0,0,1,3,0,2,0,4,0,0,0,5,6,0,0,7 };\r
+\r
+\r
+static void UltraSetInterface(int dram,int adc,int gf1,int midi)\r
+/* int dram;    /* dram dma chan */\r
+/* int adc;             /* adc dma chan */\r
+/* int gf1;             /* gf1 irq # */\r
+/* int midi;    /* midi irq # */\r
+{\r
+       UBYTE gf1_irq, midi_irq,dram_dma,adc_dma;\r
+       UBYTE irq_control,dma_control;\r
+       UBYTE mix_image;\r
+\r
+       /* Don't need to check for 0 irq #. Its latch entry = 0 */\r
+       gf1_irq =irqlatch[gf1];\r
+       midi_irq=irqlatch[midi];\r
+       midi_irq<<=3;\r
+\r
+       dram_dma=dmalatch[dram];\r
+       adc_dma =dmalatch[adc];\r
+       adc_dma<<=3;\r
+\r
+       irq_control=dma_control=0x0;\r
+\r
+       mix_image=GUS_MIX_IMAGE;\r
+\r
+       irq_control|=gf1_irq;\r
+\r
+       if((gf1==midi) && (gf1!=0))\r
+               irq_control|=0x40;\r
+       else\r
+               irq_control|=midi_irq;\r
+\r
+       dma_control|=dram_dma;\r
+\r
+       if((dram==adc) && (dram!=0))\r
+               dma_control|=0x40;\r
+       else\r
+               dma_control|=adc_dma;\r
+\r
+       /* Set up for Digital ASIC */\r
+       outportb(GUS_PORT+0x0f,0x5);\r
+       outportb(GF1_MIX_CTRL,mix_image);\r
+       outportb(GF1_IRQ_CTRL,0x0);\r
+       outportb(GUS_PORT+0x0f,0x0);\r
+\r
+       /* First do DMA control register */\r
+       outportb(GF1_MIX_CTRL,mix_image);\r
+       outportb(GF1_IRQ_CTRL,dma_control|0x80);\r
+\r
+       /* IRQ CONTROL REG */\r
+       outportb(GF1_MIX_CTRL,mix_image|0x40);\r
+       outportb(GF1_IRQ_CTRL,irq_control);\r
+\r
+       /* First do DMA control register */\r
+       outportb(GF1_MIX_CTRL,mix_image);\r
+       outportb(GF1_IRQ_CTRL,dma_control);\r
+\r
+       /* IRQ CONTROL REG */\r
+       outportb(GF1_MIX_CTRL,mix_image|0x40);\r
+       outportb(GF1_IRQ_CTRL,irq_control);\r
+\r
+       /* IRQ CONTROL, ENABLE IRQ */\r
+       /* just to Lock out writes to irq\dma register ... */\r
+       outportb(GF1_VOICE_SELECT,0);\r
+\r
+       /* enable output & irq, disable line & mic input */\r
+       mix_image|=0x09;\r
+       outportb(GF1_MIX_CTRL,mix_image);\r
+\r
+       /* just to Lock out writes to irq\dma register ... */\r
+       outportb(GF1_VOICE_SELECT,0x0);\r
+\r
+       /* put image back .... */\r
+       GUS_MIX_IMAGE=mix_image;\r
+}\r
+\r
+\r
+static BOOL UltraPP(ULONG address)\r
+{\r
+       UBYTE s,t;\r
+       s=UltraPeek(address);\r
+       UltraPoke(address,0xaa);\r
+       t=UltraPeek(address);\r
+       UltraPoke(address,s);\r
+       return(t==0xaa);\r
+}\r
+\r
+\r
+static UWORD UltraSizeDram(void)\r
+{\r
+       if(!UltraPP(0))      return 0;\r
+       if(!UltraPP(262144)) return 256;\r
+       if(!UltraPP(524288)) return 512;\r
+       if(!UltraPP(786432)) return 768;\r
+       return 1024;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+static ULONG UltraMemTotal(void)\r
+{\r
+       ULONG node=GUS_POOL,nsize,total=0;\r
+\r
+       while(node!=0){\r
+               nsize=UltraPeekLong(node);\r
+               total+=nsize;\r
+               node=UltraPeekLong(node+4);\r
+       }\r
+       return total;\r
+}\r
+\r
+\r
+\r
+static BOOL Mergeable(ULONG a,ULONG b)\r
+{\r
+       return(a && b && (a+UltraPeekLong(a))==b);\r
+}\r
+\r
+\r
+\r
+static ULONG Merge(ULONG a,ULONG b)\r
+{\r
+       UltraPokeLong(a,UltraPeekLong(a)+UltraPeekLong(b));\r
+       UltraPokeLong(a+4,UltraPeekLong(b+4));\r
+       return a;\r
+}\r
+\r
+\r
+\r
+static void UltraFree(ULONG size,ULONG location)\r
+{\r
+       ULONG pred=0,succ=GUS_POOL;\r
+\r
+       if(!size) return;\r
+       size+=31;\r
+       size&=-32L;\r
+\r
+       UltraPokeLong(location,size);\r
+\r
+       while(succ!=0 && succ<=location){\r
+               pred=succ;\r
+               succ=UltraPeekLong(succ+4);\r
+       }\r
+\r
+       if(pred)\r
+               UltraPokeLong(pred+4,location);\r
+       else\r
+               GUS_POOL=location;\r
+\r
+       UltraPokeLong(location+4,succ);\r
+\r
+       if(Mergeable(pred,location)){\r
+               location=Merge(pred,location);\r
+       }\r
+\r
+       if(Mergeable(location,succ)){\r
+               Merge(location,succ);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+void DumpPool(void)\r
+{\r
+       ULONG node=GUS_POOL;\r
+\r
+       while(node!=0){\r
+               printf("Node %ld, size %ld, next %ld\n",node,UltraPeekLong(node),UltraPeekLong(node+4));\r
+               node=UltraPeekLong(node+4);\r
+       }\r
+}\r
+*/\r
+\r
+\r
+\r
+\r
+\r
+\r
+static ULONG UltraMalloc(ULONG reqsize)\r
+{\r
+       ULONG curnode=GUS_POOL,cursize,newnode,newsize,pred,succ;\r
+\r
+       if(!reqsize) return 0;\r
+\r
+       /* round size to 32 bytes */\r
+\r
+       reqsize+=31;\r
+       reqsize&=-32L;\r
+\r
+       /* as long as there are nodes: */\r
+\r
+       pred=0;\r
+\r
+       while(curnode!=0){\r
+\r
+               succ=UltraPeekLong(curnode+4);\r
+\r
+               /* get current node size */\r
+\r
+               cursize=UltraPeekLong(curnode);\r
+\r
+               /* requested block fits? */\r
+\r
+               if(cursize>=reqsize){\r
+\r
+                       /* it fits, so we're allocating the first\r
+                          'size' bytes of this node */\r
+\r
+                       /* find new node position and size */\r
+\r
+                       newnode=curnode+reqsize;\r
+                       newsize=cursize-reqsize;\r
+\r
+                       /* create a new freenode if needed: */\r
+\r
+                       if(newsize>=8){\r
+                               UltraPokeLong(newnode,newsize);\r
+                               UltraPokeLong(newnode+4,succ);\r
+                               succ=newnode;\r
+                       }\r
+\r
+                       /* link prednode & succnode */\r
+\r
+                       if(pred)\r
+                               UltraPokeLong(pred+4,succ);\r
+                       else\r
+                               GUS_POOL=succ;\r
+\r
+                       /* store size of allocated memory block in block itself: */\r
+\r
+                       UltraPokeLong(curnode,reqsize);\r
+                       return curnode;\r
+               }\r
+\r
+               /* doesn't fit, try next node */\r
+               curnode=succ;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+static ULONG UltraMalloc16(ULONG reqsize)\r
+/*\r
+       Allocates a free block of gus memory, suited for 16 bit samples i.e.\r
+       smaller than 256k and doesn't cross a 256k page.\r
+*/\r
+{\r
+       ULONG p,spage,epage;\r
+\r
+       if(reqsize>262144) return 0;\r
+\r
+       /* round size to 32 bytes */\r
+\r
+       reqsize+=31;\r
+       reqsize&=-32L;\r
+\r
+       p=UltraMalloc(reqsize);\r
+       spage=p>>18;\r
+       epage=(p+reqsize-1)>>18;\r
+\r
+       if(p && spage!=epage){\r
+               ULONG newp,esize;\r
+\r
+               /* free the second part of the block, and try again */\r
+\r
+               esize=(p+reqsize)-(epage<<18);\r
+               UltraFree(esize,epage<<18);\r
+\r
+               newp=UltraMalloc16(reqsize);\r
+\r
+               /* free first part of the previous block */\r
+\r
+               UltraFree(reqsize-esize,p);\r
+               p=newp;\r
+       }\r
+\r
+       return p;\r
+}\r
+\r
+\r
+\r
+static void UltraMemInit(void)\r
+{\r
+       UWORD memsize;\r
+       GUS_POOL=32;\r
+       memsize=UltraSizeDram();\r
+       UltraPokeLong(GUS_POOL,((ULONG)memsize<<10)-32);\r
+       UltraPokeLong(GUS_POOL+4,0);\r
+}\r
+\r
+\r
+static void UltraNumVoices(int voices)\r
+{\r
+       UltraDisableLineIn();\r
+       UltraDisableMicIn();\r
+       UltraDisableOutput();\r
+       UltraReset(voices);\r
+       UltraSetInterface(GUS_DRAM_DMA,GUS_ADC_DMA,GUS_GF1_IRQ,GUS_MIDI_IRQ);\r
+}\r
+\r
+\r
+static void interrupt gf1handler(MIRQARGS)\r
+{\r
+       UBYTE irq_source;\r
+       UBYTE oldselect=GUS_SELECT;\r
+\r
+       while(irq_source=inportb(GF1_IRQ_STAT)){\r
+\r
+/*             if(irq_source & DMA_TC_IRQ){\r
+                       no provisions for DMA-ready irq yet\r
+               }\r
+\r
+               if(irq_source & (MIDI_TX_IRQ|MIDI_RX_IRQ)){\r
+                       no provisions for MIDI-ready irq yet\r
+               }\r
+*/\r
+               if (irq_source & GF1_TIMER1_IRQ){\r
+                       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL & ~0x04);\r
+                       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL);\r
+                       if(GUS_TIMER1_FUNC!=NULL) GUS_TIMER1_FUNC();\r
+               }\r
+\r
+               if (irq_source & GF1_TIMER2_IRQ){\r
+                       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL & ~0x08);\r
+                       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL);\r
+                       if(GUS_TIMER2_FUNC!=NULL) GUS_TIMER2_FUNC();\r
+               }\r
+\r
+/*             if (irq_source & (WAVETABLE_IRQ | ENVELOPE_IRQ)){\r
+                       no wavetable or envelope irq provisions yet\r
+               }\r
+*/\r
+       }\r
+\r
+       MIrq_EOI(GUS_GF1_IRQ);\r
+       UltraSelect(oldselect);\r
+}\r
+\r
+\r
+static PVI oldhandler;\r
+typedef void (*PFV)(void);\r
+\r
+\r
+static PFV UltraTimer1Handler(PFV handler)\r
+{\r
+       PFV old=GUS_TIMER1_FUNC;\r
+       GUS_TIMER1_FUNC=handler;\r
+       return old;\r
+}\r
+\r
+\r
+static PFV UltraTimer2Handler(PFV handler)\r
+{\r
+       PFV old=GUS_TIMER1_FUNC;\r
+       GUS_TIMER1_FUNC=handler;\r
+       return old;\r
+}\r
+\r
+\r
+static void UltraOpen(int voices)\r
+{\r
+       GUS_MIX_IMAGE=0x0b;\r
+       GUS_TIMER1_FUNC=NULL;\r
+       GUS_TIMER2_FUNC=NULL;\r
+\r
+       UltraDisableLineIn();\r
+       UltraDisableMicIn();\r
+       UltraDisableOutput();\r
+\r
+       UltraReset(voices);\r
+       UltraSetInterface(GUS_DRAM_DMA,GUS_ADC_DMA,GUS_GF1_IRQ,GUS_MIDI_IRQ);\r
+       UltraMemInit();\r
+       oldhandler=MIrq_SetHandler(GUS_GF1_IRQ,gf1handler);\r
+       MIrq_OnOff(GUS_GF1_IRQ,1);\r
+}\r
+\r
+\r
+static void UltraClose(void)\r
+{\r
+       MIrq_OnOff(GUS_GF1_IRQ,0);\r
+       MIrq_SetHandler(GUS_GF1_IRQ,oldhandler);\r
+       UltraDisableOutput();\r
+       UltraDisableLineIn();\r
+       UltraDisableMicIn();\r
+       UltraReset(14);\r
+}\r
+\r
+\r
+static void UltraSelectVoice(UBYTE voice)\r
+{\r
+       /* Make sure was are talking to proper voice */\r
+       outportb(GF1_VOICE_SELECT,voice);\r
+}\r
+\r
+\r
+\r
+static void UltraSetVoiceEnd(ULONG end)\r
+{\r
+       ULONG phys_end;\r
+       UBYTE data;\r
+\r
+       data=GF1InB(GET_CONTROL);\r
+\r
+       phys_end=(data&VC_DATA_TYPE)?convert_to_16bit(end):end;\r
+\r
+       /* Set end address of buffer */\r
+       GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));\r
+       GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));\r
+\r
+       data&=~(VC_IRQ_PENDING|VOICE_STOPPED|STOP_VOICE);\r
+\r
+       GF1OutB(SET_CONTROL,data);\r
+       gf1_delay();\r
+\r
+       GF1OutB(SET_CONTROL,data);\r
+}\r
+\r
+\r
+/* The formula for this table is:\r
+       1,000,000 / (1.619695497 * # of active voices)\r
+\r
+       The 1.619695497 is calculated by knowing that 14 voices\r
+               gives exactly 44.1 Khz. Therefore,\r
+               1,000,000 / (X * 14) = 44100\r
+               X = 1.619695497\r
+*/\r
+\r
+static UWORD freq_divisor[19] = {\r
+       44100,          /* 14 active voices */\r
+       41160,          /* 15 active voices */\r
+       38587,          /* 16 active voices */\r
+       36317,          /* 17 active voices */\r
+       34300,          /* 18 active voices */\r
+       32494,          /* 19 active voices */\r
+       30870,          /* 20 active voices */\r
+       29400,          /* 21 active voices */\r
+       28063,          /* 22 active voices */\r
+       26843,          /* 23 active voices */\r
+       25725,          /* 24 active voices */\r
+       24696,          /* 25 active voices */\r
+       23746,          /* 26 active voices */\r
+       22866,          /* 27 active voices */\r
+       22050,          /* 28 active voices */\r
+       21289,          /* 29 active voices */\r
+       20580,          /* 30 active voices */\r
+       19916,          /* 31 active voices */\r
+       19293}          /* 32 active voices */\r
+;\r
+\r
+static void UltraSetFrequency(ULONG speed_khz)\r
+{\r
+       UWORD fc;\r
+       ULONG temp;\r
+\r
+       /* FC is calculated based on the # of active voices ... */\r
+       temp=freq_divisor[GUS_VOICES-14];\r
+\r
+       fc=(((speed_khz<<9L)+(temp>>1L))/temp);\r
+       GF1OutW(SET_FREQUENCY,fc<<1);\r
+}\r
+\r
+\r
+static void UltraSetLoopMode(UBYTE mode)\r
+{\r
+       UBYTE data;\r
+       UBYTE vmode;\r
+\r
+       /* set/reset the rollover bit as per user request */\r
+\r
+       vmode=GF1InB(GET_VOLUME_CONTROL);\r
+\r
+       if(mode&USE_ROLLOVER)\r
+               vmode|=VC_ROLLOVER;\r
+       else\r
+               vmode&=~VC_ROLLOVER;\r
+\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+       gf1_delay();\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+\r
+       data=GF1InB(GET_CONTROL);\r
+\r
+       data&=~(VC_WAVE_IRQ|VC_BI_LOOP|VC_LOOP_ENABLE); /* isolate the bits */\r
+       mode&=VC_WAVE_IRQ|VC_BI_LOOP|VC_LOOP_ENABLE;    /* no bad bits passed in */\r
+       data|=mode;             /* turn on proper bits ... */\r
+\r
+       GF1OutB(SET_CONTROL,data);\r
+       gf1_delay();\r
+       GF1OutB(SET_CONTROL,data);\r
+}\r
+\r
+\r
+static ULONG UltraReadVoice(void)\r
+{\r
+       UWORD count_low,count_high;\r
+       ULONG acc;\r
+       UBYTE mode;\r
+\r
+       /* Get the high & low portion of the accumulator */\r
+       count_high = GF1InW(GET_ACC_HIGH);\r
+       count_low = GF1InW(GET_ACC_LOW);\r
+\r
+       /* convert from UltraSound's format to a physical address */\r
+\r
+       mode=GF1InB(GET_CONTROL);\r
+\r
+       acc=make_physical_address(count_low,count_high,mode);\r
+       acc&=0xfffffL;          /* Only 20 bits please ... */\r
+\r
+       return(acc);\r
+}\r
+\r
+\r
+\r
+static void UltraSetVoice(ULONG location)\r
+{\r
+       ULONG phys_loc;\r
+       UBYTE data;\r
+\r
+       data=GF1InB(GET_CONTROL);\r
+\r
+       phys_loc=(data&VC_DATA_TYPE)?convert_to_16bit(location):location;\r
+\r
+       /* First set accumulator to beginning of data */\r
+       GF1OutW(SET_ACC_HIGH,ADDR_HIGH(phys_loc));\r
+       GF1OutW(SET_ACC_LOW,ADDR_LOW(phys_loc));\r
+}\r
+\r
+\r
+\r
+static UBYTE UltraPrimeVoice(ULONG begin,ULONG start,ULONG end,UBYTE mode)\r
+{\r
+       ULONG phys_start,phys_end;\r
+       ULONG phys_begin;\r
+       ULONG temp;\r
+       UBYTE vmode;\r
+\r
+       /* if start is greater than end, flip 'em and turn on */\r
+       /* decrementing addresses */\r
+       if(start>end){\r
+               temp=start;\r
+               start=end;\r
+               end=temp;\r
+               mode|=VC_DIRECT;\r
+       }\r
+\r
+       /* if 16 bit data, must convert addresses */\r
+       if(mode&VC_DATA_TYPE){\r
+               phys_begin = convert_to_16bit(begin);\r
+               phys_start = convert_to_16bit(start);\r
+               phys_end   = convert_to_16bit(end);\r
+       }\r
+       else{\r
+               phys_begin = begin;\r
+               phys_start = start;\r
+               phys_end = end;\r
+       }\r
+\r
+       /* set/reset the rollover bit as per user request */\r
+       vmode=GF1InB(GET_VOLUME_CONTROL);\r
+\r
+       if(mode&USE_ROLLOVER)\r
+               vmode |= VC_ROLLOVER;\r
+       else\r
+               vmode &= ~VC_ROLLOVER;\r
+\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+       gf1_delay();\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+\r
+       /* First set accumulator to beginning of data */\r
+       GF1OutW(SET_ACC_LOW,ADDR_LOW(phys_begin));\r
+       GF1OutW(SET_ACC_HIGH,ADDR_HIGH(phys_begin));\r
+\r
+       /* Set start loop address of buffer */\r
+       GF1OutW(SET_START_HIGH,ADDR_HIGH(phys_start));\r
+       GF1OutW(SET_START_LOW,ADDR_LOW(phys_start));\r
+\r
+       /* Set end address of buffer */\r
+       GF1OutW(SET_END_HIGH,ADDR_HIGH(phys_end));\r
+       GF1OutW(SET_END_LOW,ADDR_LOW(phys_end));\r
+       return(mode);\r
+}\r
+\r
+\r
+static void UltraGoVoice(UBYTE mode)\r
+{\r
+       mode&=~(VOICE_STOPPED|STOP_VOICE);      /* turn 'stop' bits off ... */\r
+\r
+       /* NOTE: no irq's from the voice ... */\r
+\r
+       GF1OutB(SET_CONTROL,mode);\r
+       gf1_delay();\r
+       GF1OutB(SET_CONTROL,mode);\r
+}\r
+\r
+\r
+/**********************************************************************\r
+ *\r
+ * This function will start playing a wave out of DRAM. It assumes\r
+ * the playback rate, volume & balance have been set up before ...\r
+ *\r
+ *********************************************************************/\r
+\r
+static void UltraStartVoice(ULONG begin,ULONG start,ULONG end,UBYTE mode)\r
+{\r
+       mode=UltraPrimeVoice(begin,start,end,mode);\r
+       UltraGoVoice(mode);\r
+}\r
+\r
+\r
+\r
+/***************************************************************\r
+ * This function will stop a given voices output. Note that a delay\r
+ * is necessary after the stop is issued to ensure the self-\r
+ * modifying bits aren't a problem.\r
+ ***************************************************************/\r
+\r
+static void UltraStopVoice(void)\r
+{\r
+       UBYTE data;\r
+\r
+       /* turn off the roll over bit first ... */\r
+\r
+       data=GF1InB(GET_VOLUME_CONTROL);\r
+       data&=~VC_ROLLOVER;\r
+\r
+       GF1OutB(SET_VOLUME_CONTROL,data);\r
+       gf1_delay();\r
+       GF1OutB(SET_VOLUME_CONTROL,data);\r
+\r
+       /* Now stop the voice  */\r
+\r
+       data=GF1InB(GET_CONTROL);\r
+       data&=~VC_WAVE_IRQ;             /* disable irq's & stop voice .. */\r
+       data|=VOICE_STOPPED|STOP_VOICE;\r
+\r
+       GF1OutB(SET_CONTROL,data);                      /* turn it off */\r
+       gf1_delay();\r
+       GF1OutB(SET_CONTROL,data);\r
+}\r
+\r
+\r
+static int UltraVoiceStopped(void)\r
+{\r
+       return(GF1InB(GET_CONTROL) & (VOICE_STOPPED|STOP_VOICE));\r
+}\r
+\r
+\r
+static void UltraSetBalance(UBYTE pan)\r
+{\r
+       GF1OutB(SET_BALANCE,pan&0xf);\r
+}\r
+\r
+\r
+static void UltraSetVolume(UWORD volume)\r
+{\r
+       GF1OutW(SET_VOLUME,volume<<4);\r
+}\r
+\r
+\r
+static UWORD UltraReadVolume(void)\r
+{\r
+       return(GF1InW(GET_VOLUME)>>4);\r
+}\r
+\r
+\r
+static void UltraStopVolume(void)\r
+{\r
+       UBYTE vmode;\r
+\r
+       vmode=GF1InB(GET_VOLUME_CONTROL);\r
+       vmode|=(VOLUME_STOPPED|STOP_VOLUME);\r
+\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+       gf1_delay();\r
+       GF1OutB(SET_VOLUME_CONTROL,vmode);\r
+}\r
+\r
+\r
+static void UltraRampVolume(UWORD start,UWORD end,UBYTE rate,UBYTE mode)\r
+{\r
+       UWORD begin;\r
+       UBYTE vmode;\r
+\r
+       if(start==end) return;\r
+/*********************************************************************\r
+ * If the start volume is greater than the end volume, flip them and\r
+ * turn on decreasing volume. Note that the GF1 requires that the\r
+ * programmed start volume MUST be less than or equal to the end\r
+ * volume.\r
+ *********************************************************************/\r
+       /* Don't let bad bits thru ... */\r
+       mode&=~(VL_IRQ_PENDING|VC_ROLLOVER|STOP_VOLUME|VOLUME_STOPPED);\r
+\r
+       begin = start;\r
+\r
+       if(start>end){\r
+               /* flip start & end if decreasing numbers ... */\r
+               start = end;\r
+               end = begin;\r
+               mode |= VC_DIRECT;              /* decreasing volumes */\r
+       }\r
+\r
+       /* looping below 64 or greater that 4032 can cause strange things */\r
+       if(start<64) start=64;\r
+       if(end>4032) end=4032;\r
+\r
+       GF1OutB(SET_VOLUME_RATE,rate);\r
+       GF1OutB(SET_VOLUME_START,start>>4);\r
+       GF1OutB(SET_VOLUME_END,end>>4);\r
+\r
+       /* Also MUST set the current volume to the start volume ... */\r
+       UltraSetVolume(begin);\r
+\r
+       vmode=GF1InB(GET_VOLUME_CONTROL);\r
+\r
+       if(vmode&VC_ROLLOVER) mode|=VC_ROLLOVER;\r
+\r
+       /* start 'er up !!! */\r
+       GF1OutB(SET_VOLUME_CONTROL,mode);\r
+       gf1_delay();\r
+       GF1OutB(SET_VOLUME_CONTROL,mode);\r
+}\r
+\r
+\r
+static void UltraVectorVolume(UWORD end,UBYTE rate,UBYTE mode)\r
+{\r
+       UltraStopVolume();\r
+       UltraRampVolume(UltraReadVolume(),end,rate,mode);\r
+}\r
+\r
+\r
+static int UltraVolumeStopped(void)\r
+{\r
+       return(GF1InB(GET_VOLUME_CONTROL) & (VOLUME_STOPPED|STOP_VOLUME));\r
+}\r
+\r
+\r
+static UWORD vol_rates[19]={\r
+23,24,26,28,29,31,32,34,36,37,39,40,42,44,45,47,49,50,52\r
+};\r
+\r
+\r
+static UBYTE UltraCalcRate(UWORD start,UWORD end,ULONG mil_secs)\r
+{\r
+       ULONG gap,mic_secs;\r
+       UWORD i,range,increment;\r
+       UBYTE rate_val;\r
+       UWORD value;\r
+\r
+       gap = (start>end) ? (start-end) : (end-start);\r
+       mic_secs = (mil_secs * 1000L)/gap;\r
+\r
+/* OK. We now have the # of microseconds for each update to go from */\r
+/* A to B in X milliseconds. See what the best fit is in the table */\r
+\r
+       range = 4;\r
+       value = vol_rates[GUS_VOICES-14];\r
+\r
+       for(i=0;i<3;i++){\r
+               if(mic_secs<value){\r
+                       range = i;\r
+                       break;\r
+               }\r
+               else value<<=3;\r
+       }\r
+\r
+       if(range==4){\r
+               range = 3;\r
+               increment = 1;\r
+       }\r
+       else{\r
+               /* calculate increment value ... (round it up ?) */\r
+               increment=(unsigned int)((value + (value>>1)) / mic_secs);\r
+       }\r
+\r
+       rate_val=range<<6;\r
+       rate_val|=(increment&0x3F);\r
+       return(rate_val);\r
+}\r
+\r
+\r
+static UWORD _gf1_volumes[512] = {\r
+ 0x0000,\r
+ 0x0700, 0x07ff, 0x0880, 0x08ff, 0x0940, 0x0980, 0x09c0, 0x09ff, 0x0a20,\r
+ 0x0a40, 0x0a60, 0x0a80, 0x0aa0, 0x0ac0, 0x0ae0, 0x0aff, 0x0b10, 0x0b20,\r
+ 0x0b30, 0x0b40, 0x0b50, 0x0b60, 0x0b70, 0x0b80, 0x0b90, 0x0ba0, 0x0bb0,\r
+ 0x0bc0, 0x0bd0, 0x0be0, 0x0bf0, 0x0bff, 0x0c08, 0x0c10, 0x0c18, 0x0c20,\r
+ 0x0c28, 0x0c30, 0x0c38, 0x0c40, 0x0c48, 0x0c50, 0x0c58, 0x0c60, 0x0c68,\r
+ 0x0c70, 0x0c78, 0x0c80, 0x0c88, 0x0c90, 0x0c98, 0x0ca0, 0x0ca8, 0x0cb0,\r
+ 0x0cb8, 0x0cc0, 0x0cc8, 0x0cd0, 0x0cd8, 0x0ce0, 0x0ce8, 0x0cf0, 0x0cf8,\r
+ 0x0cff, 0x0d04, 0x0d08, 0x0d0c, 0x0d10, 0x0d14, 0x0d18, 0x0d1c, 0x0d20,\r
+ 0x0d24, 0x0d28, 0x0d2c, 0x0d30, 0x0d34, 0x0d38, 0x0d3c, 0x0d40, 0x0d44,\r
+ 0x0d48, 0x0d4c, 0x0d50, 0x0d54, 0x0d58, 0x0d5c, 0x0d60, 0x0d64, 0x0d68,\r
+ 0x0d6c, 0x0d70, 0x0d74, 0x0d78, 0x0d7c, 0x0d80, 0x0d84, 0x0d88, 0x0d8c,\r
+ 0x0d90, 0x0d94, 0x0d98, 0x0d9c, 0x0da0, 0x0da4, 0x0da8, 0x0dac, 0x0db0,\r
+ 0x0db4, 0x0db8, 0x0dbc, 0x0dc0, 0x0dc4, 0x0dc8, 0x0dcc, 0x0dd0, 0x0dd4,\r
+ 0x0dd8, 0x0ddc, 0x0de0, 0x0de4, 0x0de8, 0x0dec, 0x0df0, 0x0df4, 0x0df8,\r
+ 0x0dfc, 0x0dff, 0x0e02, 0x0e04, 0x0e06, 0x0e08, 0x0e0a, 0x0e0c, 0x0e0e,\r
+ 0x0e10, 0x0e12, 0x0e14, 0x0e16, 0x0e18, 0x0e1a, 0x0e1c, 0x0e1e, 0x0e20,\r
+ 0x0e22, 0x0e24, 0x0e26, 0x0e28, 0x0e2a, 0x0e2c, 0x0e2e, 0x0e30, 0x0e32,\r
+ 0x0e34, 0x0e36, 0x0e38, 0x0e3a, 0x0e3c, 0x0e3e, 0x0e40, 0x0e42, 0x0e44,\r
+ 0x0e46, 0x0e48, 0x0e4a, 0x0e4c, 0x0e4e, 0x0e50, 0x0e52, 0x0e54, 0x0e56,\r
+ 0x0e58, 0x0e5a, 0x0e5c, 0x0e5e, 0x0e60, 0x0e62, 0x0e64, 0x0e66, 0x0e68,\r
+ 0x0e6a, 0x0e6c, 0x0e6e, 0x0e70, 0x0e72, 0x0e74, 0x0e76, 0x0e78, 0x0e7a,\r
+ 0x0e7c, 0x0e7e, 0x0e80, 0x0e82, 0x0e84, 0x0e86, 0x0e88, 0x0e8a, 0x0e8c,\r
+ 0x0e8e, 0x0e90, 0x0e92, 0x0e94, 0x0e96, 0x0e98, 0x0e9a, 0x0e9c, 0x0e9e,\r
+ 0x0ea0, 0x0ea2, 0x0ea4, 0x0ea6, 0x0ea8, 0x0eaa, 0x0eac, 0x0eae, 0x0eb0,\r
+ 0x0eb2, 0x0eb4, 0x0eb6, 0x0eb8, 0x0eba, 0x0ebc, 0x0ebe, 0x0ec0, 0x0ec2,\r
+ 0x0ec4, 0x0ec6, 0x0ec8, 0x0eca, 0x0ecc, 0x0ece, 0x0ed0, 0x0ed2, 0x0ed4,\r
+ 0x0ed6, 0x0ed8, 0x0eda, 0x0edc, 0x0ede, 0x0ee0, 0x0ee2, 0x0ee4, 0x0ee6,\r
+ 0x0ee8, 0x0eea, 0x0eec, 0x0eee, 0x0ef0, 0x0ef2, 0x0ef4, 0x0ef6, 0x0ef8,\r
+ 0x0efa, 0x0efc, 0x0efe, 0x0eff, 0x0f01, 0x0f02, 0x0f03, 0x0f04, 0x0f05,\r
+ 0x0f06, 0x0f07, 0x0f08, 0x0f09, 0x0f0a, 0x0f0b, 0x0f0c, 0x0f0d, 0x0f0e,\r
+ 0x0f0f, 0x0f10, 0x0f11, 0x0f12, 0x0f13, 0x0f14, 0x0f15, 0x0f16, 0x0f17,\r
+ 0x0f18, 0x0f19, 0x0f1a, 0x0f1b, 0x0f1c, 0x0f1d, 0x0f1e, 0x0f1f, 0x0f20,\r
+ 0x0f21, 0x0f22, 0x0f23, 0x0f24, 0x0f25, 0x0f26, 0x0f27, 0x0f28, 0x0f29,\r
+ 0x0f2a, 0x0f2b, 0x0f2c, 0x0f2d, 0x0f2e, 0x0f2f, 0x0f30, 0x0f31, 0x0f32,\r
+ 0x0f33, 0x0f34, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3b,\r
+ 0x0f3c, 0x0f3d, 0x0f3e, 0x0f3f, 0x0f40, 0x0f41, 0x0f42, 0x0f43, 0x0f44,\r
+ 0x0f45, 0x0f46, 0x0f47, 0x0f48, 0x0f49, 0x0f4a, 0x0f4b, 0x0f4c, 0x0f4d,\r
+ 0x0f4e, 0x0f4f, 0x0f50, 0x0f51, 0x0f52, 0x0f53, 0x0f54, 0x0f55, 0x0f56,\r
+ 0x0f57, 0x0f58, 0x0f59, 0x0f5a, 0x0f5b, 0x0f5c, 0x0f5d, 0x0f5e, 0x0f5f,\r
+ 0x0f60, 0x0f61, 0x0f62, 0x0f63, 0x0f64, 0x0f65, 0x0f66, 0x0f67, 0x0f68,\r
+ 0x0f69, 0x0f6a, 0x0f6b, 0x0f6c, 0x0f6d, 0x0f6e, 0x0f6f, 0x0f70, 0x0f71,\r
+ 0x0f72, 0x0f73, 0x0f74, 0x0f75, 0x0f76, 0x0f77, 0x0f78, 0x0f79, 0x0f7a,\r
+ 0x0f7b, 0x0f7c, 0x0f7d, 0x0f7e, 0x0f7f, 0x0f80, 0x0f81, 0x0f82, 0x0f83,\r
+ 0x0f84, 0x0f85, 0x0f86, 0x0f87, 0x0f88, 0x0f89, 0x0f8a, 0x0f8b, 0x0f8c,\r
+ 0x0f8d, 0x0f8e, 0x0f8f, 0x0f90, 0x0f91, 0x0f92, 0x0f93, 0x0f94, 0x0f95,\r
+ 0x0f96, 0x0f97, 0x0f98, 0x0f99, 0x0f9a, 0x0f9b, 0x0f9c, 0x0f9d, 0x0f9e,\r
+ 0x0f9f, 0x0fa0, 0x0fa1, 0x0fa2, 0x0fa3, 0x0fa4, 0x0fa5, 0x0fa6, 0x0fa7,\r
+ 0x0fa8, 0x0fa9, 0x0faa, 0x0fab, 0x0fac, 0x0fad, 0x0fae, 0x0faf, 0x0fb0,\r
+ 0x0fb1, 0x0fb2, 0x0fb3, 0x0fb4, 0x0fb5, 0x0fb6, 0x0fb7, 0x0fb8, 0x0fb9,\r
+ 0x0fba, 0x0fbb, 0x0fbc, 0x0fbd, 0x0fbe, 0x0fbf, 0x0fc0, 0x0fc1, 0x0fc2,\r
+ 0x0fc3, 0x0fc4, 0x0fc5, 0x0fc6, 0x0fc7, 0x0fc8, 0x0fc9, 0x0fca, 0x0fcb,\r
+ 0x0fcc, 0x0fcd, 0x0fce, 0x0fcf, 0x0fd0, 0x0fd1, 0x0fd2, 0x0fd3, 0x0fd4,\r
+ 0x0fd5, 0x0fd6, 0x0fd7, 0x0fd8, 0x0fd9, 0x0fda, 0x0fdb, 0x0fdc, 0x0fdd,\r
+ 0x0fde, 0x0fdf, 0x0fe0, 0x0fe1, 0x0fe2, 0x0fe3, 0x0fe4, 0x0fe5, 0x0fe6,\r
+ 0x0fe7, 0x0fe8, 0x0fe9, 0x0fea, 0x0feb, 0x0fec, 0x0fed, 0x0fee, 0x0fef,\r
+ 0x0ff0, 0x0ff1, 0x0ff2, 0x0ff3, 0x0ff4, 0x0ff5, 0x0ff6, 0x0ff7, 0x0ff8,\r
+ 0x0ff9, 0x0ffa, 0x0ffb, 0x0ffc, 0x0ffd, 0x0ffe, 0x0fff\r
+};\r
+\r
+\r
+static void UltraSetLinearVolume(UWORD index)\r
+{\r
+       UltraSetVolume(_gf1_volumes[index]);\r
+}\r
+\r
+\r
+static void UltraRampLinearVolume(UWORD start_idx,UWORD end_idx,ULONG msecs,UBYTE mode)\r
+{\r
+       UWORD start,end;\r
+       UBYTE rate;\r
+\r
+       /* Ramp from start to end in x milliseconds */\r
+\r
+       start = _gf1_volumes[start_idx];\r
+       end   = _gf1_volumes[end_idx];\r
+\r
+       /* calculate a rate to get from start to end in msec milliseconds .. */\r
+       rate=UltraCalcRate(start,end,msecs);\r
+       UltraRampVolume(start,end,rate,mode);\r
+}\r
+\r
+\r
+static void UltraVectorLinearVolume(UWORD end_idx,UBYTE rate,UBYTE mode)\r
+{\r
+       UltraStopVolume();\r
+       UltraRampVolume(UltraReadVolume(),_gf1_volumes[end_idx],rate,mode);\r
+}\r
+\r
+\r
+static void UltraStartTimer(UBYTE timer,UBYTE time)\r
+{\r
+       UBYTE temp;\r
+\r
+       if (timer == 1){\r
+               GUS_TIMER_CTRL |= 0x04;\r
+               GUS_TIMER_MASK |= 0x01;\r
+               temp = TIMER1;\r
+       }\r
+       else{\r
+               GUS_TIMER_CTRL |= 0x08;\r
+               GUS_TIMER_MASK |= 0x02;\r
+               temp = TIMER2;\r
+       }\r
+\r
+/*     ENTER_CRITICAL; */\r
+\r
+       time = 256 - time;\r
+\r
+       GF1OutB(temp,time);                                                     /* set timer speed */\r
+       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL);          /* enable timer interrupt on gf1 */\r
+       outportb(GF1_TIMER_CTRL,0x04);                          /* select timer stuff */\r
+       outportb(GF1_TIMER_DATA,GUS_TIMER_MASK);        /* start the timers */\r
+\r
+/*     LEAVE_CRITICAL; */\r
+}\r
+\r
+\r
+static void UltraStopTimer(int timer)\r
+{\r
+       if (timer == 1){\r
+               GUS_TIMER_CTRL &= ~0x04;\r
+               GUS_TIMER_MASK &= ~0x01;\r
+       }\r
+       else{\r
+               GUS_TIMER_CTRL &= ~0x08;\r
+               GUS_TIMER_MASK &= ~0x02;\r
+       }\r
+\r
+/*     ENTER_CRITICAL; */\r
+\r
+       GF1OutB(TIMER_CONTROL,GUS_TIMER_CTRL);          /* disable timer interrupts */\r
+       outportb(GF1_TIMER_CTRL,0x04);                          /* select timer stuff */\r
+       outportb(GF1_TIMER_DATA,GUS_TIMER_MASK | 0x80);\r
+\r
+/*     LEAVE_CRITICAL; */\r
+}\r
+\r
+\r
+static BOOL UltraTimerStopped(UBYTE timer)\r
+{\r
+       UBYTE value;\r
+       UBYTE temp;\r
+\r
+       if (timer == 1)\r
+               temp = 0x40;\r
+       else\r
+               temp = 0x20;\r
+\r
+       value = (inportb(GF1_TIMER_CTRL)) & temp;\r
+\r
+       return(value);\r
+}\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> The actual GUS driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+\r
+static ULONG Ultra[MAXSAMPLEHANDLES];\r
+static ULONG Ultrs[MAXSAMPLEHANDLES];\r
+\r
+/* Ultra[] holds the sample dram adresses\r
+   of the samples of a module */\r
+\r
+typedef struct{\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
+       UBYTE vol;                      /* current volume */\r
+       UBYTE pan;                                              /* current panning position */\r
+} GHOLD;\r
+\r
+static GHOLD ghld[32];\r
+\r
+\r
+static UBYTE timeskip;\r
+static UBYTE timecount;\r
+static UBYTE GUS_BPM;\r
+\r
+\r
+void UltraSetBPM(UBYTE bpm)\r
+{\r
+       /* The player routine has to be called (bpm*50)/125 times a second,\r
+          so the interval between calls takes 125/(bpm*50) seconds (amazing!).\r
+\r
+          The Timer1 handler has a resolution of 80 microseconds.\r
+\r
+          So the timer value to program:\r
+\r
+          (125/(bpm*50)) / 80e-6 = 31250/bpm\r
+       */\r
+       UWORD rate=31250/bpm;\r
+\r
+       timeskip=0;\r
+       timecount=0;\r
+\r
+       while(rate>255){\r
+               rate>>=1;\r
+               timeskip++;\r
+       }\r
+       UltraStartTimer(1,rate);\r
+}\r
+\r
+\r
+\r
+void GUS_Update(void)\r
+{\r
+       UBYTE t;\r
+       GHOLD *aud;\r
+       UWORD vol;\r
+       ULONG base,start,size,reppos,repend;\r
+\r
+       UWORD curvol,bigvol=0,bigvoc=0;\r
+\r
+       if(timecount<timeskip){\r
+               timecount++;\r
+               return;\r
+       }\r
+       timecount=0;\r
+\r
+       md_player();\r
+\r
+       if(GUS_BPM != md_bpm){\r
+               UltraSetBPM(md_bpm);\r
+               GUS_BPM=md_bpm;\r
+       }\r
+\r
+       /* ramp down voices that need to be started next */\r
+\r
+       for(t=0;t<md_numchn;t++){\r
+               UltraSelectVoice(t);\r
+               aud=&ghld[t];\r
+               if(aud->kick){\r
+                       curvol=UltraReadVolume();\r
+                       if(bigvol<=curvol){\r
+                               bigvol=curvol;\r
+                               bigvoc=t;\r
+                       }\r
+                       UltraVectorLinearVolume(0,0x3f,0);\r
+               }\r
+       }\r
+\r
+/*      while(!UltraVolumeStopped(bigvoc)); */\r
+\r
+       for(t=0;t<md_numchn;t++){\r
+               UltraSelectVoice(t);\r
+               aud=&ghld[t];\r
+\r
+               if(aud->kick){\r
+                       aud->kick=0;\r
+\r
+                       base=Ultra[aud->handle];\r
+\r
+                       start=aud->start;\r
+                       reppos=aud->reppos;\r
+                       repend=aud->repend;\r
+                       size=aud->size;\r
+\r
+                       if(aud->flags&SF_16BITS){\r
+                               start<<=1;\r
+                               reppos<<=1;\r
+                               repend<<=1;\r
+                               size<<=1;\r
+                       }\r
+\r
+                       /* Stop current sample and start a new one */\r
+\r
+                       UltraStopVoice();\r
+\r
+                       UltraSetFrequency(aud->frq);\r
+                       UltraVectorLinearVolume(6U*aud->vol,0x3f,0);\r
+                       UltraSetBalance(aud->pan>>4);\r
+\r
+                       if(aud->flags&SF_LOOP){\r
+\r
+                               /* Start a looping sample */\r
+\r
+                               UltraStartVoice(base+start,\r
+                                                               base+reppos,\r
+                                                               base+repend,0x8|((aud->flags&SF_16BITS)?4:0)|\r
+                                                               ((aud->flags&SF_BIDI)?16:0));\r
+                       }\r
+                       else{\r
+\r
+                               /* Start a one-shot sample */\r
+\r
+                               UltraStartVoice(base+start,\r
+                                                               base+start,\r
+                                                               base+size+2,(aud->flags&SF_16BITS)?4:0);\r
+                       }\r
+               }\r
+               else{\r
+                       UltraSetFrequency(aud->frq);\r
+                       UltraVectorLinearVolume(6U*aud->vol,0x3f,0);\r
+                       UltraSetBalance(aud->pan>>4);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+SWORD GUS_Load(FILE *fp,ULONG length,ULONG loopstart,ULONG loopend,UWORD flags)\r
+/*\r
+       callback routine for the MODLOAD module.\r
+*/\r
+{\r
+       int handle,t;\r
+       long p,l;\r
+\r
+       SL_Init(fp,flags,flags|SF_SIGNED);\r
+\r
+       /* Find empty slot to put sample address in */\r
+\r
+       for(handle=0;handle<MAXSAMPLEHANDLES;handle++){\r
+               if(Ultra[handle]==0) break;\r
+       }\r
+\r
+       if(handle==MAXSAMPLEHANDLES){\r
+               myerr=ERROR_OUT_OF_HANDLES;\r
+               return -1;\r
+       }\r
+\r
+       if(flags&SF_16BITS){\r
+               length<<=1;\r
+               loopstart<<=1;\r
+               loopend<<=1;\r
+       }\r
+\r
+       /* Allocate GUS dram and store the address in Ultra[handle] */\r
+       /* Alloc 8 bytes more for anticlick measures. see below. */\r
+\r
+       /* 2.04: use UltraMalloc16 to allocate 16 bit samples */\r
+\r
+       if(!(Ultra[handle]=(flags&SF_16BITS) ? UltraMalloc16(length+8) : UltraMalloc(length+8) )){\r
+               myerr=ERROR_SAMPLE_TOO_BIG;\r
+               return -1;\r
+       }\r
+\r
+       /* Load the sample */\r
+\r
+       Ultrs[handle]=length+8;\r
+       p=Ultra[handle];\r
+       l=length;\r
+\r
+       while(l>0){\r
+                static UBYTE buffer[1024];\r
+               long todo;\r
+\r
+               todo=(l>1024) ? 1024 : l;\r
+\r
+               SL_Load(buffer,todo);\r
+\r
+               UltraPokeChunk(p,buffer,todo);\r
+\r
+               p+=todo;\r
+               l-=todo;\r
+       }\r
+\r
+       if(flags&SF_LOOP && !(flags&SF_BIDI)){  /* looping sample ? */\r
+\r
+               /*      Anticlick for looping samples:\r
+                       Copy the first bytes in the loop\r
+                       beyond the end of the loop */\r
+\r
+               for(t=0;t<8;t++){\r
+                       UltraPoke(Ultra[handle]+loopend+t,\r
+                                         UltraPeek(Ultra[handle]+loopstart+t));\r
+               }\r
+       }\r
+       else{\r
+\r
+               /*      Anticlick for one-shot samples:\r
+                       Zero the bytes beyond the end of the sample.\r
+               */\r
+\r
+               for(t=0;t<8;t++){\r
+                       UltraPoke(Ultra[handle]+length+t,0);\r
+               }\r
+       }\r
+\r
+       return handle;\r
+}\r
+\r
+\r
+\r
+void GUS_UnLoad(SWORD handle)\r
+/*\r
+       callback routine to unload samples\r
+\r
+       smp                     :sampleinfo of sample that is being freed\r
+*/\r
+{\r
+       UltraFree(Ultrs[handle],Ultra[handle]);\r
+       Ultra[handle]=0;\r
+}\r
+\r
+\r
+\r
+\r
+BOOL GUS_Init(void)\r
+{\r
+       ULONG p1,p2;\r
+       int irq;\r
+\r
+       if(!(md_mode&DMODE_16BITS)){\r
+               md_mode|=DMODE_16BITS;          /* gus can't do 8 bit mixing */\r
+       }\r
+\r
+       if(!(md_mode&DMODE_STEREO)){\r
+               md_mode|=DMODE_STEREO;          /* gus can't do mono mixing */\r
+       }\r
+\r
+       if(!UltraDetect()){\r
+               myerr="Couldn't detect gus, please check env. string";\r
+               return 0;\r
+       }\r
+\r
+       UltraOpen(14);\r
+       UltraTimer1Handler(GUS_Update);\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+void GUS_Exit(void)\r
+{\r
+       UltraClose();\r
+}\r
+\r
+\r
+\r
+void GUS_PlayStart(void)\r
+{\r
+       int t;\r
+       for(t=0;t<md_numchn;t++){\r
+               ghld[t].flags=0;\r
+               ghld[t].handle=0;\r
+               ghld[t].kick=0;\r
+               ghld[t].active=0;\r
+               ghld[t].frq=10000;\r
+               ghld[t].vol=0;\r
+               ghld[t].pan=(t&1)?0:255;\r
+       }\r
+       UltraNumVoices(md_numchn);\r
+       UltraEnableOutput();\r
+       GUS_BPM=125;\r
+       UltraSetBPM(125);\r
+}\r
+\r
+\r
+\r
+void GUS_PlayStop(void)\r
+{\r
+       UltraStopTimer(1);\r
+       UltraDisableOutput();\r
+}\r
+\r
+\r
+BOOL GUS_IsThere(void)\r
+{\r
+       return(getenv("ULTRASND")!=NULL);\r
+}\r
+\r
+\r
+void GUS_VoiceSetVolume(UBYTE voice,UBYTE vol)\r
+{\r
+       ghld[voice].vol=vol;\r
+}\r
+\r
+\r
+void GUS_VoiceSetFrequency(UBYTE voice,ULONG frq)\r
+{\r
+       ghld[voice].frq=frq;\r
+}\r
+\r
+void GUS_VoiceSetPanning(UBYTE voice,UBYTE pan)\r
+{\r
+       ghld[voice].pan=pan;\r
+}\r
+\r
+void GUS_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+       if(start>=size) return;\r
+\r
+       if(flags&SF_LOOP){\r
+               if(repend>size) repend=size;    /* repend can't be bigger than size */\r
+       }\r
+\r
+       ghld[voice].flags=flags;\r
+       ghld[voice].handle=handle;\r
+       ghld[voice].start=start;\r
+       ghld[voice].size=size;\r
+       ghld[voice].reppos=reppos;\r
+       ghld[voice].repend=repend;\r
+       ghld[voice].kick=1;\r
+}\r
+\r
+void GUS_Dummy(void)\r
+{\r
+}\r
+\r
+\r
+DRIVER drv_gus={\r
+       NULL,\r
+       "Gravis Ultrasound",\r
+       "MikMod GUS Driver v2.1 (uses gus timer interrupt)",\r
+       GUS_IsThere,\r
+       GUS_Load,\r
+       GUS_UnLoad,\r
+       GUS_Init,\r
+       GUS_Exit,\r
+       GUS_PlayStart,\r
+       GUS_PlayStop,\r
+       GUS_Dummy,\r
+       GUS_VoiceSetVolume,\r
+       GUS_VoiceSetFrequency,\r
+       GUS_VoiceSetPanning,\r
+       GUS_VoicePlay\r
+};\r
diff --git a/libs/oldmik/src/drv_nos.c b/libs/oldmik/src/drv_nos.c
new file mode 100644 (file)
index 0000000..2b58030
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+
+Name:
+DRV_NOS.C
+
+Description:
+Mikmod driver for no output on any soundcard, monitor, keyboard, or whatever :)
+
+Portability:
+All systems - All compilers
+
+*/
+#include <stdio.h>
+#include "mikmod.h"
+
+
+BOOL NS_IsThere(void)
+{
+       return 1;
+}
+
+
+SWORD NS_SampleLoad(FILE *fp,ULONG s,ULONG a,ULONG b,UWORD f)
+{
+       return 1;
+}
+
+
+void NS_SampleUnload(SWORD h)
+{
+}
+
+
+BOOL NS_Init(void)
+{
+       return 1;
+}
+
+
+void NS_Exit(void)
+{
+}
+
+
+void NS_PlayStart(void)
+{
+}
+
+
+void NS_PlayStop(void)
+{
+}
+
+
+void NS_Update(void)
+{
+}
+
+
+void NS_VoiceSetVolume(UBYTE voice,UBYTE vol)
+{
+}
+
+
+void NS_VoiceSetFrequency(UBYTE voice,ULONG frq)
+{
+}
+
+
+void NS_VoiceSetPanning(UBYTE voice,UBYTE pan)
+{
+}
+
+
+void NS_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
+{
+}
+
+
+DRIVER drv_nos={
+       NULL,
+       "No Sound",
+       "MikMod Nosound Driver v2.0 - (c) Creative Silence",
+       NS_IsThere,
+       NS_SampleLoad,
+       NS_SampleUnload,
+       NS_Init,
+       NS_Exit,
+       NS_PlayStart,
+       NS_PlayStop,
+       NS_Update,
+       NS_VoiceSetVolume,
+       NS_VoiceSetFrequency,
+       NS_VoiceSetPanning,
+       NS_VoicePlay
+};
diff --git a/libs/oldmik/src/drv_raw.c b/libs/oldmik/src/drv_raw.c
new file mode 100644 (file)
index 0000000..c6b25d7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+
+Name:
+DRV_RAW.C
+
+Description:
+Mikmod driver for output to a file called MUSIC.RAW
+
+!! DO NOT CALL MD_UPDATE FROM A INTERRUPT IF YOU USE THIS DRIVER !!
+
+Portability:
+
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)
+Win95: BC(y)
+Linux: y
+
+(y) - yes
+(n) - no (not possible or not useful)
+(?) - may be possible, but not tested
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mikmod.h"
+
+#define RAWBUFFERSIZE 8192
+
+static FILE *rawout;
+
+static char RAW_DMABUF[RAWBUFFERSIZE];
+
+
+static BOOL RAW_IsThere(void)
+{
+       return 1;
+}
+
+
+static BOOL RAW_Init(void)
+{
+       if(!(rawout=fopen("music.raw","wb"))){
+               myerr="Couldn't open output file 'music.raw'";
+               return 0;
+       }
+
+       if(!VC_Init()){
+               fclose(rawout);
+               return 0;
+       }
+
+       return 1;
+}
+
+
+
+static void RAW_Exit(void)
+{
+       VC_Exit();
+       fclose(rawout);
+}
+
+
+static void RAW_Update(void)
+{
+       VC_WriteBytes(RAW_DMABUF,RAWBUFFERSIZE);
+       fwrite(RAW_DMABUF,RAWBUFFERSIZE,1,rawout);
+}
+
+
+DRIVER drv_raw={
+       NULL,
+       "music.raw file",
+       "MikMod music.raw file output driver v1.0",
+       RAW_IsThere,
+       VC_SampleLoad,
+       VC_SampleUnload,
+       RAW_Init,
+       RAW_Exit,
+       VC_PlayStart,
+       VC_PlayStop,
+       RAW_Update,
+       VC_VoiceSetVolume,
+       VC_VoiceSetFrequency,
+       VC_VoiceSetPanning,
+       VC_VoicePlay
+};
diff --git a/libs/oldmik/src/drv_sb.c b/libs/oldmik/src/drv_sb.c
new file mode 100644 (file)
index 0000000..6d85d47
--- /dev/null
@@ -0,0 +1,511 @@
+/*\r
+\r
+Name:\r
+DRV_SB.C\r
+\r
+Description:\r
+Mikmod driver for output on Creative Labs Soundblasters & compatibles\r
+(through DSP)\r
+\r
+Portability:\r
+\r
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)\r
+Win95: n\r
+Os2:   n\r
+Linux: n\r
+\r
+(y) - yes\r
+(n) - no (not possible or not useful)\r
+(?) - may be possible, but not tested\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <dos.h>\r
+#include <malloc.h>\r
+#include <conio.h>\r
+#ifndef __DJGPP__\r
+#include <mem.h>\r
+#endif\r
+\r
+#include "mikmod.h"\r
+#include "mdma.h"\r
+#include "mirq.h"\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel SB stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+static UWORD sb_port;          /* sb base port */\r
+\r
+/*\r
+       Define some important SB i/o ports:\r
+*/\r
+\r
+#define MIXER_ADDRESS          (sb_port+0x4)\r
+#define MIXER_DATA                     (sb_port+0x5)\r
+#define DSP_RESET                      (sb_port+0x6)\r
+#define DSP_READ_DATA          (sb_port+0xa)\r
+#define DSP_WRITE_DATA         (sb_port+0xc)\r
+#define DSP_WRITE_STATUS       (sb_port+0xc)\r
+#define DSP_DATA_AVAIL         (sb_port+0xe)\r
+\r
+\r
+static void SB_MixerStereo(void)\r
+/*\r
+       Enables stereo output for DSP versions 3.00 >= ver < 4.00\r
+*/\r
+{\r
+       outportb(MIXER_ADDRESS,0xe);\r
+       outportb(MIXER_DATA,inportb(MIXER_DATA)|2);\r
+}\r
+\r
+\r
+\r
+static void SB_MixerMono(void)\r
+/*\r
+       Disables stereo output for DSP versions 3.00 >= ver < 4.00\r
+*/\r
+{\r
+       outportb(MIXER_ADDRESS,0xe);\r
+       outportb(MIXER_DATA,inportb(MIXER_DATA)&0xfd);\r
+}\r
+\r
+\r
+\r
+static BOOL SB_WaitDSPWrite(void)\r
+/*\r
+       Waits until the DSP is ready to be written to.\r
+\r
+       returns FALSE on timeout\r
+*/\r
+{\r
+       UWORD timeout=32767;\r
+\r
+       while(timeout--){\r
+               if(!(inportb(DSP_WRITE_STATUS)&0x80)) return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+static BOOL SB_WaitDSPRead(void)\r
+/*\r
+       Waits until the DSP is ready to read from.\r
+\r
+       returns FALSE on timeout\r
+*/\r
+{\r
+       UWORD timeout=32767;\r
+\r
+       while(timeout--){\r
+               if(inportb(DSP_DATA_AVAIL)&0x80) return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+static BOOL SB_WriteDSP(UBYTE data)\r
+/*\r
+       Writes byte 'data' to the DSP.\r
+\r
+       returns FALSE on timeout.\r
+*/\r
+{\r
+       if(!SB_WaitDSPWrite()) return 0;\r
+       outportb(DSP_WRITE_DATA,data);\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+static UWORD SB_ReadDSP(void)\r
+/*\r
+       Reads a byte from the DSP.\r
+\r
+       returns 0xffff on timeout.\r
+*/\r
+{\r
+       if(!SB_WaitDSPRead()) return 0xffff;\r
+       return(inportb(DSP_READ_DATA));\r
+}\r
+\r
+\r
+\r
+static void SB_SpeakerOn(void)\r
+/*\r
+       Enables DAC speaker output.\r
+*/\r
+{\r
+       SB_WriteDSP(0xd1);\r
+}\r
+\r
+\r
+\r
+static void SB_SpeakerOff(void)\r
+/*\r
+       Disables DAC speaker output\r
+*/\r
+{\r
+       SB_WriteDSP(0xd3);\r
+}\r
+\r
+\r
+\r
+static void SB_ResetDSP(void)\r
+/*\r
+       Resets the DSP.\r
+*/\r
+{\r
+       int t;\r
+       /* reset the DSP by sending 1, (delay), then 0 */\r
+       outportb(DSP_RESET,1);\r
+       for(t=0;t<8;t++) inportb(DSP_RESET);\r
+       outportb(DSP_RESET,0);\r
+}\r
+\r
+\r
+\r
+static BOOL SB_Ping(void)\r
+/*\r
+       Checks if a SB is present at the current baseport by\r
+       resetting the DSP and checking if it returned the value 0xaa.\r
+\r
+       returns: TRUE   => SB is present\r
+                        FALSE  => No SB detected\r
+*/\r
+{\r
+       SB_ResetDSP();\r
+       return(SB_ReadDSP()==0xaa);\r
+}\r
+\r
+\r
+\r
+static UWORD SB_GetDSPVersion(void)\r
+/*\r
+       Gets SB-dsp version. returns 0xffff if dsp didn't respond.\r
+*/\r
+{\r
+       UWORD hi,lo;\r
+\r
+       if(!SB_WriteDSP(0xe1)) return 0xffff;\r
+\r
+       hi=SB_ReadDSP();\r
+       lo=SB_ReadDSP();\r
+\r
+       return((hi<<8)|lo);\r
+}\r
+\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> The actual SB driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+static DMAMEM *SB_DMAMEM;\r
+static signed char *SB_DMABUF;\r
+\r
+static UBYTE SB_TIMECONSTANT;\r
+\r
+static UBYTE PIC1MSK;\r
+static UBYTE PIC2MSK;\r
+\r
+static UWORD sb_int;           /* interrupt vector that belongs to sb_irq */\r
+static UWORD sb_ver;           /* DSP version number */\r
+static UBYTE sb_irq;           /* sb irq */\r
+static UBYTE sb_lodma;         /* 8 bit dma channel (1.0/2.0/pro) */\r
+static UBYTE sb_hidma;         /* 16 bit dma channel (16/16asp) */\r
+static UBYTE sb_dma;           /* current dma channel */\r
+\r
+\r
+static BOOL SB_IsThere(void)\r
+{\r
+       char *envptr,c;\r
+       static char *endptr;\r
+\r
+       sb_port =0xffff;\r
+       sb_irq  =0xff;\r
+       sb_lodma=0xff;\r
+       sb_hidma=0xff;\r
+\r
+       if((envptr=getenv("BLASTER"))==NULL) return 0;\r
+\r
+       while(1){\r
+\r
+               /* skip whitespace */\r
+\r
+               do c=*(envptr++); while(c==' ' || c=='\t');\r
+\r
+               /* reached end of string? -> exit */\r
+\r
+               if(c==0) break;\r
+\r
+               switch(c){\r
+\r
+                       case 'a':\r
+                       case 'A':\r
+                               sb_port=strtol(envptr,&endptr,16);\r
+                               break;\r
+\r
+                       case 'i':\r
+                       case 'I':\r
+                               sb_irq=strtol(envptr,&endptr,10);\r
+                               break;\r
+\r
+                       case 'd':\r
+                       case 'D':\r
+                               sb_lodma=strtol(envptr,&endptr,10);\r
+                               break;\r
+\r
+                       case 'h':\r
+                       case 'H':\r
+                               sb_hidma=strtol(envptr,&endptr,10);\r
+                               break;\r
+\r
+                       default:\r
+                               strtol(envptr,&endptr,16);\r
+                               break;\r
+               }\r
+               envptr=endptr;\r
+       }\r
+\r
+       if(sb_port==0xffff || sb_irq==0xff || sb_lodma==0xff) return 0;\r
+\r
+       /* determine interrupt vector */\r
+\r
+       sb_int = (sb_irq>7) ? sb_irq+104 : sb_irq+8;\r
+\r
+       if(!SB_Ping()) return 0;\r
+\r
+       /* get dsp version. */\r
+\r
+       if((sb_ver=SB_GetDSPVersion())==0xffff) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+static void interrupt newhandler(MIRQARGS)\r
+{\r
+       if(sb_ver<0x200){\r
+               SB_WriteDSP(0x14);\r
+               SB_WriteDSP(0xff);\r
+               SB_WriteDSP(0xfe);\r
+       }\r
+\r
+        if(md_mode & DMODE_16BITS)\r
+               inportb(sb_port+0xf);\r
+       else\r
+                inportb(DSP_DATA_AVAIL);\r
+\r
+       MIrq_EOI(sb_irq);\r
+}\r
+\r
+\r
+static PVI oldhandler;\r
+\r
+\r
+static BOOL SB_Init(void)\r
+{\r
+       ULONG t;\r
+\r
+       if(!SB_IsThere()){\r
+               myerr="No such hardware detected, check your 'BLASTER' env. variable";\r
+               return 0;\r
+       }\r
+\r
+/*      printf("SB version %x\n",sb_ver); */\r
+/*      if(sb_ver>0x200) sb_ver=0x200; */\r
+\r
+       if(sb_ver>=0x400 && sb_hidma==0xff){\r
+               myerr="High-dma setting in 'BLASTER' variable is required for SB-16";\r
+               return 0;\r
+       }\r
+\r
+       if(sb_ver<0x400 && md_mode&DMODE_16BITS){\r
+               /* DSP versions below 4.00 can't do 16 bit sound. */\r
+               md_mode&=~DMODE_16BITS;\r
+       }\r
+\r
+       if(sb_ver<0x300 && md_mode&DMODE_STEREO){\r
+               /* DSP versions below 3.00 can't do stereo sound. */\r
+               md_mode&=~DMODE_STEREO;\r
+       }\r
+\r
+       /* Use low dma channel for 8 bit, high dma for 16 bit */\r
+\r
+       sb_dma=(md_mode & DMODE_16BITS) ? sb_hidma : sb_lodma;\r
+\r
+       if(sb_ver<0x400){\r
+\r
+               t=md_mixfreq;\r
+               if(md_mode & DMODE_STEREO) t<<=1;\r
+\r
+               SB_TIMECONSTANT=256-(1000000L/t);\r
+\r
+               if(sb_ver<0x201){\r
+                       if(SB_TIMECONSTANT>210) SB_TIMECONSTANT=210;\r
+               }\r
+               else{\r
+                       if(SB_TIMECONSTANT>233) SB_TIMECONSTANT=233;\r
+               }\r
+\r
+               md_mixfreq=1000000L/(256-SB_TIMECONSTANT);\r
+               if(md_mode & DMODE_STEREO) md_mixfreq>>=1;\r
+       }\r
+\r
+       if(!VC_Init()) return 0;\r
+\r
+       SB_DMAMEM=MDma_AllocMem(md_dmabufsize);\r
+\r
+       if(SB_DMAMEM==NULL){\r
+               VC_Exit();\r
+               myerr="Couldn't allocate page-contiguous dma-buffer";\r
+               return 0;\r
+       }\r
+\r
+       SB_DMABUF=(char *)MDma_GetPtr(SB_DMAMEM);\r
+\r
+       oldhandler=MIrq_SetHandler(sb_irq,newhandler);\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+static void SB_Exit(void)\r
+{\r
+       MIrq_SetHandler(sb_irq,oldhandler);\r
+       MDma_FreeMem(SB_DMAMEM);\r
+       VC_Exit();\r
+}\r
+\r
+\r
+static UWORD last=0;\r
+static UWORD curr=0;\r
+\r
+\r
+static void SB_Update(void)\r
+{\r
+       UWORD todo,index;\r
+\r
+       curr=(md_dmabufsize-MDma_Todo(sb_dma))&0xfffc;\r
+\r
+       if(curr==last) return;\r
+\r
+       if(curr>last){\r
+               todo=curr-last; index=last;\r
+               last+=VC_WriteBytes(&SB_DMABUF[index],todo);\r
+               MDma_Commit(SB_DMAMEM,index,todo);\r
+               if(last>=md_dmabufsize) last=0;\r
+       }\r
+       else{\r
+               todo=md_dmabufsize-last;\r
+               VC_WriteBytes(&SB_DMABUF[last],todo);\r
+               MDma_Commit(SB_DMAMEM,last,todo);\r
+               last=VC_WriteBytes(SB_DMABUF,curr);\r
+               MDma_Commit(SB_DMAMEM,0,curr);\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+static void SB_PlayStart(void)\r
+{\r
+       VC_PlayStart();\r
+\r
+       MIrq_OnOff(sb_irq,1);\r
+\r
+       if(sb_ver>=0x300 && sb_ver<0x400){\r
+               if(md_mode & DMODE_STEREO){\r
+                       SB_MixerStereo();\r
+               }\r
+               else{\r
+                       SB_MixerMono();\r
+               }\r
+       }\r
+\r
+       /* clear the dma buffer */\r
+\r
+       VC_SilenceBytes(SB_DMABUF,md_dmabufsize);\r
+       MDma_Commit(SB_DMAMEM,0,md_dmabufsize);\r
+\r
+       if(!MDma_Start(sb_dma,SB_DMAMEM,md_dmabufsize,INDEF_WRITE)){\r
+               return;\r
+       }\r
+\r
+       if(sb_ver<0x400){\r
+               SB_SpeakerOn();\r
+\r
+               SB_WriteDSP(0x40);\r
+               SB_WriteDSP(SB_TIMECONSTANT);\r
+\r
+               if(sb_ver<0x200){\r
+                       SB_WriteDSP(0x14);\r
+                       SB_WriteDSP(0xff);\r
+                       SB_WriteDSP(0xfe);\r
+               }\r
+               else if(sb_ver==0x200){\r
+                       SB_WriteDSP(0x48);\r
+                       SB_WriteDSP(0xff);\r
+                       SB_WriteDSP(0xfe);\r
+                       SB_WriteDSP(0x1c);\r
+               }\r
+               else{\r
+                       SB_WriteDSP(0x48);\r
+                       SB_WriteDSP(0xff);\r
+                       SB_WriteDSP(0xfe);\r
+                       SB_WriteDSP(0x90);\r
+               }\r
+       }\r
+       else{\r
+               SB_WriteDSP(0x41);\r
+\r
+               SB_WriteDSP(md_mixfreq>>8);\r
+               SB_WriteDSP(md_mixfreq&0xff);\r
+\r
+               if(md_mode & DMODE_16BITS){\r
+                       SB_WriteDSP(0xb6);\r
+                       SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x30 : 0x10);\r
+               }\r
+               else{\r
+                       SB_WriteDSP(0xc6);\r
+                       SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x20 : 0x00);\r
+               }\r
+\r
+               SB_WriteDSP(0xff);\r
+               SB_WriteDSP(0xef);\r
+       }\r
+}\r
+\r
+\r
+static void SB_PlayStop(void)\r
+{\r
+       VC_PlayStop();\r
+       SB_SpeakerOff();\r
+       SB_ResetDSP();\r
+       SB_ResetDSP();\r
+       MDma_Stop(sb_dma);\r
+       MIrq_OnOff(sb_irq,0);\r
+}\r
+\r
+\r
+DRIVER drv_sb={\r
+       NULL,\r
+       "Soundblaster & compatibles",\r
+       "MikMod Soundblaster Driver v2.1 for 1.0 / 2.0 / Pro / 16",\r
+       SB_IsThere,\r
+       VC_SampleLoad,\r
+       VC_SampleUnload,\r
+       SB_Init,\r
+       SB_Exit,\r
+       SB_PlayStart,\r
+       SB_PlayStop,\r
+       SB_Update,\r
+       VC_VoiceSetVolume,\r
+       VC_VoiceSetFrequency,\r
+       VC_VoiceSetPanning,\r
+       VC_VoicePlay\r
+};\r
diff --git a/libs/oldmik/src/drv_ss.c b/libs/oldmik/src/drv_ss.c
new file mode 100644 (file)
index 0000000..4d0ff26
--- /dev/null
@@ -0,0 +1,714 @@
+/*\r
+\r
+Name:\r
+DRV_SS.C\r
+\r
+Description:\r
+Mikmod driver for output on Ensoniq Soundscape / Soundscape ELITE\r
+\r
+Portability:\r
+\r
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)\r
+Win95: n\r
+Os2:   n\r
+Linux: n\r
+\r
+(y) - yes\r
+(n) - no (not possible or not useful)\r
+(?) - may be possible, but not tested\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <dos.h>\r
+#include <malloc.h>\r
+#include <conio.h>\r
+#include <string.h>\r
+\r
+#include "mikmod.h"\r
+#include "mdma.h"\r
+#include "mirq.h"\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel SS stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+/* Ensoniq gate-array chip defines ... */\r
+\r
+#define ODIE            0       /* ODIE gate array */\r
+#define OPUS            1       /* OPUS gate array */\r
+#define MMIC            2       /* MiMIC gate array */\r
+\r
+/* relevant direct register defines - offsets from base address */\r
+#define GA_HOSTCTL_OFF  2       /* host port ctrl/stat reg */\r
+#define GA_ADDR_OFF     4       /* indirect address reg */\r
+#define GA_DATA_OFF     5       /* indirect data reg */\r
+#define GA_CODEC_OFF    8       /* for some boards CoDec is fixed from base */\r
+\r
+/* relevant indirect register defines */\r
+#define GA_DMAB_REG     3       /* DMA chan B assign reg */\r
+#define GA_INTCFG_REG   4       /* interrupt configuration reg */\r
+#define GA_DMACFG_REG   5       /* DMA configuration reg */\r
+#define GA_CDCFG_REG    6       /* CD-ROM/CoDec config reg */\r
+#define GA_HMCTL_REG   9       /* host master control reg */\r
+\r
+\r
+/* AD-1848 or compatible CoDec defines ... */\r
+/* relevant direct register defines - offsets from base */\r
+#define CD_ADDR_OFF     0       /* indirect address reg */\r
+#define CD_DATA_OFF     1       /* indirect data reg */\r
+#define CD_STATUS_OFF   2       /* status register */\r
+\r
+/* relevant indirect register defines */\r
+#define CD_ADCL_REG            0       /* left DAC input control reg */\r
+#define CD_ADCR_REG            1       /* right DAC input control reg */\r
+#define CD_CDAUXL_REG   2       /* left DAC output control reg */\r
+#define CD_CDAUXR_REG   3       /* right DAC output control reg */\r
+#define CD_DACL_REG     6       /* left DAC output control reg */\r
+#define CD_DACR_REG     7       /* right DAC output control reg */\r
+#define CD_FORMAT_REG   8       /* clock and data format reg */\r
+#define CD_CONFIG_REG   9       /* interface config register */\r
+#define CD_PINCTL_REG   10      /* external pin control reg */\r
+#define CD_UCOUNT_REG   14      /* upper count reg */\r
+#define CD_LCOUNT_REG   15      /* lower count reg */\r
+#define CD_XFORMAT_REG 28      /* extended format reg - 1845 record */\r
+#define CD_XUCOUNT_REG 30      /* extended upper count reg - 1845 record */\r
+#define CD_XLCOUNT_REG 31      /* extended lower count reg - 1845 record */\r
+\r
+#define CD_MODE_CHANGE 0x40    /* mode change mask for addr reg */\r
+\r
+/****************************************************************************\r
+hardware config info ...\r
+****************************************************************************/\r
+\r
+static UWORD   BasePort;       /* Gate Array/MPU-401 base port */\r
+static UWORD   MidiIrq;        /* the MPU-401 IRQ */\r
+static UWORD   WavePort;       /* the AD-1848 base port */\r
+static UWORD   WaveIrq;        /* the PCM IRQ */\r
+static UWORD   DmaChan;        /* the PCM DMA channel */\r
+\r
+/****************************************************************************\r
+all kinds of stuff ...\r
+****************************************************************************/\r
+\r
+static UWORD Windx;            /* Wave IRQ index - for reg writes */\r
+static UWORD Mindx;            /* MIDI IRQ index - for reg writes */\r
+\r
+static UBYTE IcType;           /* the Ensoniq chip type */\r
+static UBYTE CdCfgSav;         /* gate array register save area */\r
+static UBYTE DmaCfgSav;                /* gate array register save area */\r
+static UBYTE IntCfgSav;                /* gate array register save area */\r
+\r
+static UWORD const SsIrqs[4] = { 9, 5, 7, 10 };  /* Soundscape IRQs */\r
+static UWORD const RsIrqs[4] = { 9, 7, 5, 15 };  /* an older IRQ set */\r
+static UWORD const *Irqs;           /* pointer to one of the IRQ sets */\r
+\r
+static UBYTE DacSavL;        /* DAC left volume save */\r
+static UBYTE DacSavR;        /* DAC right volume save */\r
+static UBYTE CdxSavL;        /* CD/Aux left volume save */\r
+static UBYTE CdxSavR;        /* CD/Aux right volume save */\r
+static UBYTE AdcSavL;        /* ADC left volume save */\r
+static UBYTE AdcSavR;        /* ADC right volume save */\r
+\r
+static DMAMEM *SS_DMAMEM;\r
+static char   *SS_DMABUF;\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>>>>>>>>>>>>>>>> The actual SS driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+\r
+\r
+UBYTE GaRead(UWORD rnum)\r
+/*\r
+  This function is used to read the indirect addressed registers in the\r
+  Ensoniq Soundscape gate array.\r
+\r
+  INPUTS:\r
+       rnum  - the numner of the indirect register to be read\r
+\r
+  RETURNS:\r
+       the contents of the indirect register are returned\r
+*/\r
+{\r
+       outportb(BasePort + GA_ADDR_OFF, rnum);\r
+       return inportb(BasePort + GA_DATA_OFF);\r
+}\r
+\r
+\r
+\r
+void GaWrite(UWORD rnum,UBYTE value)\r
+/*\r
+  This function is used to write the indirect addressed registers in the\r
+  Ensoniq Soundscape gate array.\r
+\r
+  INPUTS:\r
+       rnum   - the numner of the indirect register to be read\r
+       value  - the byte value to be written to the indirect register\r
+\r
+  RETURNS:\r
+       Nothing\r
+*/\r
+{\r
+       outportb(BasePort + GA_ADDR_OFF, rnum);\r
+       outportb(BasePort + GA_DATA_OFF, value);\r
+}\r
+\r
+\r
+UBYTE CdRead(UWORD rnum)\r
+/*\r
+  This function is used to read the indirect addressed registers in the\r
+  AD-1848 or compatible CoDec. It will preserve the special function bits\r
+  in the upper-nibble of the indirect address register.\r
+\r
+  INPUTS:\r
+       rnum  - the numner of the indirect register to be read\r
+\r
+  RETURNS:\r
+       the contents of the indirect register are returned\r
+\r
+*/\r
+{\r
+       outportb(WavePort + CD_ADDR_OFF,\r
+               (inportb(WavePort + CD_ADDR_OFF) & 0xf0) | rnum);\r
+       return inportb(WavePort+CD_DATA_OFF);\r
+}\r
+\r
+\r
+\r
+void CdWrite(UWORD rnum,UBYTE value)\r
+/*\r
+  This function is used to write the indirect addressed registers in the\r
+  Ad-1848 or compatible CoDec. It will preserve the special function bits\r
+  in the upper-nibble of the indirect address register.\r
+\r
+  INPUTS:\r
+       rnum   - the numner of the indirect register to be read\r
+       value  - the byte value to be written to the indirect register\r
+\r
+  RETURNS:\r
+       Nothing\r
+*/\r
+{\r
+       outportb(WavePort + CD_ADDR_OFF,\r
+               (inportb(WavePort + CD_ADDR_OFF) & 0xf0) | rnum);\r
+       outportb(WavePort + CD_DATA_OFF, value);\r
+}\r
+\r
+\r
+\r
+\r
+void SetDacVol(UBYTE lvol,UBYTE rvol)\r
+/*\r
+  This function sets the left and right DAC output level in the CoDec.\r
+\r
+  INPUTS:\r
+       lvol  - left volume, 0-127\r
+       rvol  - right volume, 0-127\r
+\r
+  RETURNS:\r
+       Nothing\r
+\r
+*/\r
+{\r
+       CdWrite(CD_DACL_REG, ~(lvol >> 1) & 0x3f);\r
+       CdWrite(CD_DACR_REG, ~(rvol >> 1) & 0x3f);\r
+}\r
+\r
+\r
+\r
+void SetCdRomVol(UBYTE lvol,UBYTE rvol)\r
+/*\r
+  This function sets the left and right CD-ROM output level in the CoDec.\r
+\r
+  INPUTS:\r
+       lvol  - left volume, 0-127\r
+       rvol  - right volume, 0-127\r
+\r
+  RETURNS:\r
+       Nothing\r
+*/\r
+{\r
+       CdWrite(CD_CDAUXL_REG, ~(lvol >> 2) & 0x1f);\r
+       CdWrite(CD_CDAUXR_REG, ~(rvol >> 2) & 0x1f);\r
+}\r
+\r
+\r
+void SetAdcVol(UBYTE lvol,UBYTE rvol)\r
+/*\r
+  This function sets the left and right ADC input level in the CoDec.\r
+\r
+  INPUTS:\r
+       lvol  - left volume, 0-127\r
+       rvol  - right volume, 0-127\r
+\r
+  RETURNS:\r
+       Nothing\r
+\r
+*/\r
+{\r
+       CdWrite(CD_ADCL_REG, (CdRead(CD_ADCL_REG) & 0xf0) | (lvol & 0x7f) >> 3);\r
+       CdWrite(CD_ADCR_REG, (CdRead(CD_ADCR_REG) & 0xf0) | (rvol & 0x7f) >> 3);\r
+}\r
+\r
+\r
+void StopCoDec(void)\r
+{\r
+       UWORD i;\r
+\r
+       CdWrite(CD_CONFIG_REG,CdRead(CD_CONFIG_REG)&0xfc);\r
+\r
+       /* Let the CoDec receive its last DACK(s). The DMAC must not be */\r
+       /*  masked while the CoDec has DRQs pending. */\r
+/*     for(i=0; i<256; ++i )\r
+               if(!(inportb(DmacRegP->status) & (0x10 << DmaChan))) break;\r
+*/\r
+}\r
+\r
+\r
+\r
+BOOL GetConfigEntry(char *entry, char *dest, FILE *fp)\r
+/*\r
+  This function parses a file (SNDSCAPE.INI) for a left-hand string and,\r
+  if found, writes its associated right-hand value to a destination buffer.\r
+  This function is case-insensitive.\r
+\r
+  INPUTS:\r
+       fp  - a file pointer to the open SNDSCAPE.INI config file\r
+       dst - the destination buffer pointer\r
+       lhp - a pointer to the right-hand string\r
+\r
+  RETURNS:\r
+       1   - if successful\r
+       0   - if the right-hand string is not found or has no equate\r
+*/\r
+{\r
+       char static str[83];\r
+       char static tokstr[33];\r
+       char *p;\r
+\r
+       /* make a local copy of the entry, upper-case it */\r
+       strcpy(tokstr, entry);\r
+       strupr(tokstr);\r
+\r
+       /* rewind the file and try to find it ... */\r
+       rewind(fp);\r
+\r
+       for( ;; ) {\r
+               /* get the next string from the file */\r
+\r
+               fgets(str, 83, fp);\r
+               if(feof(fp)) return 0;\r
+\r
+               /* properly terminate the string */\r
+               for( p = str; *p != '\0'; ++p ) {\r
+                       if( *p == ' ' || *p == '\t' || *p == 0x0a || *p == 0x0d ) {\r
+                               *p = '\0';\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               /* see if it's an 'equate' string; if so, zero the '=' */\r
+               if( !(p = strchr(str, '=')) ) continue;\r
+               *p = '\0';\r
+\r
+               /* upper-case the current string and test it */\r
+               strupr(str);\r
+               if( strcmp(str, tokstr) )\r
+                       continue;\r
+\r
+               /* it's our string - copy the right-hand value to buffer */\r
+               for( p = str + strlen(str) + 1; (*dest++ = *p++) != '\0'; );\r
+               break;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+static BOOL SS_IsThere(void)\r
+{\r
+       static char str[78];\r
+       char *envptr;\r
+       FILE *fp;\r
+       UBYTE tmp;\r
+\r
+       if((envptr=getenv("SNDSCAPE"))==NULL) return 0;\r
+\r
+       strcpy(str, envptr);\r
+       if( str[strlen(str) - 1] == '\\' )\r
+               str[strlen(str) - 1] = '\0';\r
+\r
+       strcat(str, "\\SNDSCAPE.INI");\r
+\r
+       if(!(fp=fopen(str, "r"))) return 0;\r
+\r
+       /* read all of the necessary config info ... */\r
+       if(!GetConfigEntry("Product",str,fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       /* if an old product name is read, set the IRQs accordingly */\r
+       strupr(str);\r
+       if(strstr(str,"SOUNDFX") || strstr(str,"MEDIA_FX"))\r
+               Irqs = RsIrqs;\r
+       else\r
+               Irqs = SsIrqs;\r
+\r
+       if(!GetConfigEntry("Port", str, fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       BasePort=strtol(str,NULL,16);\r
+\r
+       if(!GetConfigEntry("WavePort",str,fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       WavePort=strtol(str,NULL,16);\r
+\r
+       if(!GetConfigEntry("IRQ",str,fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       MidiIrq=strtol(str,NULL,10);\r
+       if(MidiIrq==2) MidiIrq = 9;\r
+\r
+       if(!GetConfigEntry("SBIRQ",str,fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       WaveIrq=strtol(str,NULL,10);\r
+       if(WaveIrq==2) WaveIrq=9;\r
+\r
+       if(!GetConfigEntry("DMA",str,fp)){\r
+               fclose(fp);\r
+               return 0;\r
+       }\r
+\r
+       DmaChan=strtol(str,NULL,10);\r
+\r
+       fclose(fp);\r
+\r
+       /* see if Soundscape is there by reading HW ... */\r
+       if((inportb(BasePort+GA_HOSTCTL_OFF)&0x78) != 0x00)     return 0;\r
+       if((inportb(BasePort+GA_ADDR_OFF)&0xf0)==0xf0) return 0;\r
+\r
+       outportb(BasePort+GA_ADDR_OFF,0xf5);\r
+\r
+       tmp=inportb(BasePort+GA_ADDR_OFF);\r
+\r
+       if((tmp & 0xf0)==0xf0) return 0;\r
+       if((tmp & 0x0f)!=0x05) return 0;\r
+\r
+       /* formulate the chip ID */\r
+       if( (tmp & 0x80) != 0x00 )\r
+               IcType = MMIC;\r
+       else if((tmp & 0x70) != 0x00)\r
+               IcType = OPUS;\r
+       else\r
+               IcType = ODIE;\r
+\r
+       /* now do a quick check to make sure the CoDec is there too */\r
+       if((inportb(WavePort)&0x80)!=0x00) return 0;\r
+       return 1;\r
+}\r
+\r
+\r
+#ifdef NEVER\r
+\r
+static void interrupt newhandler(void)\r
+{\r
+       if(WaveIrq==7){\r
+               outportb(0x20,0x0b);\r
+               inportb(0x21);\r
+               if(!(inportb(0x20)&0x80)) return;\r
+       }\r
+       else if(WaveIrq==15){\r
+               outportb(0xa0,0x0b);\r
+               inportb(0xa1);\r
+               if(!(inportb(0xa0)&0x80)) return;\r
+       }\r
+\r
+       interruptcount++;\r
+\r
+       /* if the CoDec is interrupting clear the AD-1848 interrupt */\r
+       if(inportb(WavePort+CD_STATUS_OFF)&0x01)\r
+               outportb(WavePort+CD_STATUS_OFF,0x00);\r
+\r
+       MIrq_EOI(WaveIrq);\r
+}\r
+\r
+\r
+static PVI oldhandler;\r
+\r
+#endif\r
+\r
+\r
+static UWORD codecfreqs[14]={\r
+       5512, 6615, 8000, 9600,11025,16000,18900,\r
+       22050,27428,32000,33075,37800,44100,48000\r
+};\r
+\r
+\r
+static UWORD codecformats[14]={\r
+       0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, 0x05,\r
+       0x07, 0x04,     0x06, 0x0d,     0x09, 0x0b,     0x0c\r
+};\r
+\r
+\r
+static UBYTE codecformat;\r
+\r
+\r
+static BOOL SS_Init(void)\r
+{\r
+       int t;\r
+\r
+       if(!SS_IsThere()){\r
+               myerr="No such hardware detected, check your 'SNDSCAPE' env. variable";\r
+               return 0;\r
+       }\r
+\r
+       printf("Ensoniq Soundscape at port 0x%x, irq %d, dma %d\n",WavePort,WaveIrq,DmaChan);\r
+\r
+       /* find closest codec frequency */\r
+\r
+       for(t=0;t<14;t++){\r
+               if(t==13 || md_mixfreq<=codecfreqs[t]){\r
+                       md_mixfreq=codecfreqs[t];\r
+                       break;\r
+               }\r
+       }\r
+\r
+       codecformat=codecformats[t];\r
+       if(md_mode & DMODE_STEREO) codecformat|=0x10;\r
+       if(md_mode & DMODE_16BITS) codecformat|=0x40;\r
+\r
+       if(!VC_Init()) return 0;\r
+\r
+       SS_DMAMEM=MDma_AllocMem(md_dmabufsize);\r
+\r
+       if(SS_DMAMEM==NULL){\r
+               VC_Exit();\r
+               myerr="Couldn't allocate page-contiguous dma-buffer";\r
+               return 0;\r
+       }\r
+\r
+       SS_DMABUF=(char *)MDma_GetPtr(SS_DMAMEM);\r
+\r
+       /* In case the CoDec is running, stop it */\r
+       StopCoDec();\r
+\r
+       /* Clear possible CoDec and SoundBlaster emulation interrupts */\r
+       outportb(WavePort+CD_STATUS_OFF,0x00);\r
+       inportb(0x22e);\r
+\r
+       /* If necessary, save some regs, do some resource re-routing */\r
+       if( IcType != MMIC) {\r
+\r
+               /* derive the MIDI and Wave IRQ indices (0-3) for reg writes */\r
+               for( Mindx = 0; Mindx < 4; ++Mindx )\r
+                       if( MidiIrq == *(Irqs + Mindx) )\r
+                               break;\r
+               for( Windx = 0; Windx < 4; ++Windx )\r
+                       if( WaveIrq == *(Irqs + Windx) )\r
+                               break;\r
+\r
+               /* setup the CoDec DMA polarity */\r
+               GaWrite(GA_DMACFG_REG, 0x50);\r
+\r
+               /* give the CoDec control of the DMA and Wave IRQ resources */\r
+                       CdCfgSav = GaRead(GA_CDCFG_REG);\r
+               GaWrite(GA_CDCFG_REG, 0x89 | (DmaChan << 4) | (Windx << 1));\r
+\r
+               /* pull the Sound Blaster emulation off of those resources */\r
+               DmaCfgSav = GaRead(GA_DMAB_REG);\r
+               GaWrite(GA_DMAB_REG, 0x20);\r
+               IntCfgSav = GaRead(GA_INTCFG_REG);\r
+               GaWrite(GA_INTCFG_REG, 0xf0 | (Mindx << 2) | Mindx);\r
+       }\r
+\r
+       /* Save all volumes that we might use, init some levels */\r
+       DacSavL = CdRead(CD_DACL_REG);\r
+       DacSavR = CdRead(CD_DACR_REG);\r
+       CdxSavL = CdRead(CD_CDAUXL_REG);\r
+       CdxSavR = CdRead(CD_CDAUXL_REG);\r
+       AdcSavL = CdRead(CD_ADCL_REG);\r
+       AdcSavR = CdRead(CD_ADCR_REG);\r
+\r
+       SetDacVol(127, 127);\r
+       SetAdcVol(96, 96);\r
+\r
+       /* Select the mic/line input to the record mux; */\r
+       /* if not ODIE, set the mic gain bit too */\r
+       CdWrite(CD_ADCL_REG, (CdRead(CD_ADCL_REG) & 0x3f) |\r
+               (IcType == ODIE ? 0x80 : 0xa0));\r
+       CdWrite(CD_ADCR_REG, (CdRead(CD_ADCR_REG) & 0x3f) |\r
+               (IcType == ODIE ? 0x80 : 0xa0));\r
+\r
+       /* Put the CoDec into mode change state */\r
+       outportb(WavePort + CD_ADDR_OFF, 0x40);\r
+\r
+       /* Setup CoDec mode - single DMA chan, AutoCal on */\r
+       CdWrite(CD_CONFIG_REG, 0x0c);\r
+\r
+#ifdef NEVER\r
+       /* enable the CoDec interrupt pin */\r
+       CdWrite(CD_PINCTL_REG, CdRead(CD_PINCTL_REG) | 0x02);\r
+       oldhandler=MIrq_SetHandler(WaveIrq,newhandler);\r
+       MIrq_OnOff(WaveIrq,1);\r
+#else\r
+       /* disable the interrupt for mikmod */\r
+       CdWrite(CD_PINCTL_REG, CdRead(CD_PINCTL_REG) & 0xfd);\r
+#endif\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+static void SS_Exit(void)\r
+{\r
+       /* in case the CoDec is running, stop it */\r
+       StopCoDec();\r
+\r
+       /* mask the PC DMA Controller */\r
+/*     outportb(DmacRegP->mask, 0x04 | DmaChan); */\r
+\r
+#ifdef NEVER\r
+       /* disable the CoDec interrupt pin */\r
+       CdWrite(CD_PINCTL_REG, CdRead(CD_PINCTL_REG) & 0xfd);\r
+       MIrq_OnOff(WaveIrq,0);\r
+       MIrq_SetHandler(WaveIrq,oldhandler);\r
+#endif\r
+\r
+       /* restore all volumes ... */\r
+       CdWrite(CD_DACL_REG, DacSavL);\r
+       CdWrite(CD_DACR_REG, DacSavR);\r
+       CdWrite(CD_CDAUXL_REG, CdxSavL);\r
+       CdWrite(CD_CDAUXL_REG, CdxSavR);\r
+       CdWrite(CD_ADCL_REG, AdcSavL);\r
+       CdWrite(CD_ADCR_REG, AdcSavR);\r
+\r
+       /* if necessary, restore gate array resource registers */\r
+       if(IcType!=MMIC){\r
+               GaWrite(GA_INTCFG_REG, IntCfgSav);\r
+               GaWrite(GA_DMAB_REG, DmaCfgSav);\r
+               GaWrite(GA_CDCFG_REG, CdCfgSav);\r
+       }\r
+\r
+       MDma_FreeMem(SS_DMAMEM);\r
+       VC_Exit();\r
+}\r
+\r
+\r
+static UWORD last=0;\r
+static UWORD curr=0;\r
+\r
+\r
+static void SS_Update(void)\r
+{\r
+       UWORD todo,index;\r
+\r
+       curr=(md_dmabufsize-MDma_Todo(DmaChan))&0xfffc;\r
+\r
+       if(curr>=md_dmabufsize) return;\r
+       if(curr==last) return;\r
+\r
+       if(curr>last){\r
+               todo=curr-last; index=last;\r
+               last+=VC_WriteBytes(&SS_DMABUF[index],todo);\r
+               MDma_Commit(SS_DMAMEM,index,todo);\r
+               if(last>=md_dmabufsize) last=0;\r
+       }\r
+       else{\r
+               todo=md_dmabufsize-last;\r
+               VC_WriteBytes(&SS_DMABUF[last],todo);\r
+               MDma_Commit(SS_DMAMEM,last,todo);\r
+               last=VC_WriteBytes(SS_DMABUF,curr);\r
+               MDma_Commit(SS_DMAMEM,0,curr);\r
+       }\r
+}\r
+\r
+\r
+static void SS_PlayStart(void)\r
+{\r
+       int direction=0;\r
+       long i;\r
+       UWORD tmp;\r
+\r
+       VC_PlayStart();\r
+\r
+       /* make sure the the CoDec is in mode change state */\r
+       outportb(WavePort + CD_ADDR_OFF, 0x40);\r
+\r
+       /* and write the format register */\r
+       CdWrite(CD_FORMAT_REG, codecformat);\r
+\r
+       /* if not using ODIE and recording, setup extended format register */\r
+       if( IcType != ODIE && direction )\r
+               CdWrite(CD_XFORMAT_REG, codecformat & 0x70);\r
+\r
+       /* delay for internal re-synch */\r
+       for( i = 0; i < 200000UL; ++i )\r
+               inportb(BasePort + GA_ADDR_OFF);\r
+\r
+       /* clear the dma buffer */\r
+\r
+       VC_SilenceBytes(SS_DMABUF,md_dmabufsize);\r
+       MDma_Commit(SS_DMAMEM,0,md_dmabufsize);\r
+\r
+       /* Write the CoDec interrupt count - sample frames per half-buffer. */\r
+       /* If not using ODIE and recording, use extended count regs */\r
+       tmp = md_dmabufsize;\r
+       if(md_mode&DMODE_STEREO) tmp>>=1;\r
+       if(md_mode&DMODE_16BITS) tmp>>=1;\r
+       tmp--;\r
+\r
+       if( IcType != ODIE && direction ) {\r
+               CdWrite(CD_XLCOUNT_REG, tmp);\r
+               CdWrite(CD_XUCOUNT_REG, tmp >> 8);\r
+       }\r
+       else {\r
+               CdWrite(CD_LCOUNT_REG, tmp);\r
+               CdWrite(CD_UCOUNT_REG, tmp >> 8);\r
+       }\r
+\r
+       if(!MDma_Start(DmaChan,SS_DMAMEM,md_dmabufsize,INDEF_WRITE)){\r
+               return;\r
+       }\r
+\r
+       /* disable mode change state and start the CoDec */\r
+       outportb(WavePort + CD_ADDR_OFF, 0x00);\r
+       CdWrite(CD_CONFIG_REG, direction ? 0x02 : 0x01);\r
+}\r
+\r
+\r
+static void SS_PlayStop(void)\r
+{\r
+       StopCoDec();\r
+       VC_PlayStop();\r
+}\r
+\r
+\r
+DRIVER drv_ss={\r
+       NULL,\r
+       "Ensoniq Soundscape",\r
+       "MikMod Ensoniq Soundscape Driver v0.0 - Thanks to CyberCerus",\r
+       SS_IsThere,\r
+       VC_SampleLoad,\r
+       VC_SampleUnload,\r
+       SS_Init,\r
+       SS_Exit,\r
+       SS_PlayStart,\r
+       SS_PlayStop,\r
+       SS_Update,\r
+       VC_VoiceSetVolume,\r
+       VC_VoiceSetFrequency,\r
+       VC_VoiceSetPanning,\r
+       VC_VoicePlay\r
+};\r
diff --git a/libs/oldmik/src/load_m15.c b/libs/oldmik/src/load_m15.c
new file mode 100644 (file)
index 0000000..6186a03
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+
+Name:
+LOAD_M15.C
+
+Description:
+15 instrument MOD loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mikmod.h"
+
+/*************************************************************************
+*************************************************************************/
+
+
+typedef struct MSAMPINFO{       /* sample header as it appears in a module */
+        char  samplename[22];
+       UWORD length;
+       UBYTE finetune;
+       UBYTE volume;
+       UWORD reppos;
+       UWORD replen;
+} MSAMPINFO;
+
+
+typedef struct MODULEHEADER{                 /* verbatim module header */
+        char       songname[20];                /* the songname.. */
+       MSAMPINFO  samples[15];                         /* all sampleinfo */
+       UBYTE      songlength;                          /* number of patterns used */
+       UBYTE      magic1;                                      /* should be 127 */
+       UBYTE      positions[128];                      /* which pattern to play at pos */
+} MODULEHEADER;
+
+
+typedef struct MODNOTE{
+       UBYTE a,b,c,d;
+} MODNOTE;
+
+
+/*************************************************************************
+*************************************************************************/
+
+static MODULEHEADER *mh;        /* raw as-is module header */
+static MODNOTE *patbuf;
+
+
+static BOOL LoadModuleHeader(MODULEHEADER *mh)
+{
+       int t;
+
+       _mm_read_str(mh->songname,20,modfp);
+
+       for(t=0;t<15;t++){
+               MSAMPINFO *s= &mh->samples[t];
+               _mm_read_str(s->samplename,22,modfp);
+               s->length       =_mm_read_M_UWORD(modfp);
+               s->finetune     =_mm_read_UBYTE(modfp);
+               s->volume       =_mm_read_UBYTE(modfp);
+               s->reppos       =_mm_read_M_UWORD(modfp);
+               s->replen       =_mm_read_M_UWORD(modfp);
+       }
+
+       mh->songlength  =_mm_read_UBYTE(modfp);
+       mh->magic1              =_mm_read_UBYTE(modfp);                                      /* should be 127 */
+       _mm_read_UBYTES(mh->positions,128,modfp);
+
+       return(!feof(modfp));
+}
+
+
+
+BOOL M15_Test(void)
+{
+       int t;
+       MODULEHEADER mh;
+
+       if(!LoadModuleHeader(&mh)) return 0;
+
+       for(t=0;t<15;t++){
+
+               /* all finetunes should be zero */
+               if(mh.samples[t].finetune!=0) return 0;
+
+               /* all volumes should be <=64 */
+               if(mh.samples[t].volume>64) return 0;
+       }
+       if(mh.magic1>127) return 0;    /* and magic1 should be <128 */
+
+       return 1;
+}
+
+
+BOOL M15_Init(void)
+{
+       patbuf=NULL;
+       if(!(mh=(MODULEHEADER *)MyCalloc(1,sizeof(MODULEHEADER)))) return 0;
+       return 1;
+}
+
+
+void M15_Cleanup(void)
+{
+       if(mh!=NULL) free(mh);
+       if(patbuf!=NULL) free(patbuf);
+}
+
+
+/*
+
+Old (amiga) noteinfo:
+
+ _____byte 1_____   byte2_    _____byte 3_____   byte4_
+/                \ /      \  /                \ /      \
+0000          0000-00000000  0000          0000-00000000
+
+Upper four    12 bits for    Lower four    Effect command.
+bits of sam-  note period.   bits of sam-
+ple number.                  ple number.
+
+
+*/
+
+
+UWORD M15_npertab[60]={
+
+/* -> Tuning 0 */
+
+       1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
+       856,808,762,720,678,640,604,570,538,508,480,453,
+       428,404,381,360,339,320,302,285,269,254,240,226,
+       214,202,190,180,170,160,151,143,135,127,120,113,
+       107,101,95,90,85,80,75,71,67,63,60,56
+};
+
+
+void M15_ConvertNote(MODNOTE *n)
+{
+       UBYTE instrument,effect,effdat,note;
+       UWORD period;
+
+       /* extract the various information from the 4 bytes that
+          make up a single note */
+
+       instrument=(n->a&0x10)|(n->c>>4);
+       period=(((UWORD)n->a&0xf)<<8)+n->b;
+       effect=n->c&0xf;
+       effdat=n->d;
+
+       /* Convert the period to a note number */
+
+       note=0;
+       if(period!=0){
+               for(note=0;note<60;note++){
+                       if(period>=M15_npertab[note]) break;
+               }
+               note++;
+               if(note==61) note=0;
+       }
+
+       if(instrument!=0){
+               UniInstrument(instrument-1);
+       }
+
+       if(note!=0){
+               UniNote(note+23);
+       }
+
+       UniPTEffect(effect,effdat);
+}
+
+
+
+UBYTE *M15_ConvertTrack(MODNOTE *n)
+{
+       int t;
+
+       UniReset();
+       for(t=0;t<64;t++){
+               M15_ConvertNote(n);
+               UniNewline();
+               n+=of.numchn;
+       }
+       return UniDup();
+}
+
+
+
+BOOL M15_LoadPatterns(void)
+/*
+       Loads all patterns of a modfile and converts them into the
+       3 byte format.
+*/
+{
+       int t,s,tracks=0;
+
+       if(!AllocPatterns()) return 0;
+       if(!AllocTracks()) return 0;
+
+       /* Allocate temporary buffer for loading
+          and converting the patterns */
+
+       if(!(patbuf=(MODNOTE *)MyCalloc(64U*of.numchn,sizeof(MODNOTE)))) return 0;
+
+       for(t=0;t<of.numpat;t++){
+
+               /* Load the pattern into the temp buffer
+                  and convert it */
+
+               for(s=0;s<(64U*of.numchn);s++){
+                       patbuf[s].a=_mm_read_UBYTE(modfp);
+                       patbuf[s].b=_mm_read_UBYTE(modfp);
+                       patbuf[s].c=_mm_read_UBYTE(modfp);
+                       patbuf[s].d=_mm_read_UBYTE(modfp);
+               }
+
+               for(s=0;s<of.numchn;s++){
+                       if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
+               }
+       }
+
+       return 1;
+}
+
+
+
+BOOL M15_Load(void)
+{
+       int t;
+       INSTRUMENT *d;          /* new sampleinfo structure */
+       SAMPLE *q;
+       MSAMPINFO *s;           /* old module sampleinfo */
+
+       /* try to read module header */
+
+       if(!LoadModuleHeader(mh)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* set module variables */
+
+       of.initspeed=6;
+       of.inittempo=125;
+       of.numchn=4;                                                    /* get number of channels */
+       of.modtype=strdup("15-instrument");             /* get ascii type of mod */
+       of.songname=DupStr(mh->songname,20);        /* make a cstr of songname */
+       of.numpos=mh->songlength;                       /* copy the songlength */
+       memcpy(of.positions,mh->positions,128);     /* copy the position array */
+
+       /* Count the number of patterns */
+
+       of.numpat=0;
+
+       for(t=0;t<128;t++){             /* <-- BUGFIX... have to check ALL positions */
+               if(of.positions[t] > of.numpat){
+                       of.numpat=of.positions[t];
+               }
+       }
+       of.numpat++;
+       of.numtrk=of.numpat*of.numchn;
+
+       /* Finally, init the sampleinfo structures */
+
+       of.numins=15;
+       if(!AllocInstruments()) return 0;
+
+       s=mh->samples;          /* init source pointer */
+       d=of.instruments;       /* init dest pointer */
+
+       for(t=0;t<of.numins;t++){
+
+               d->numsmp=1;
+               if(!AllocSamples(d)) return 0;
+
+               q=d->samples;
+
+               /* convert the samplename */
+
+               d->insname=DupStr(s->samplename,22);
+
+               /* init the sampleinfo variables and
+                  convert the size pointers to longword format */
+
+               q->c2spd=finetune[s->finetune&0xf];
+               q->volume=s->volume;
+               q->loopstart=s->reppos;
+               q->loopend=q->loopstart+(s->replen<<1);
+               q->length=s->length<<1;
+               q->seekpos=0;
+
+               q->flags=SF_SIGNED;
+               if(s->replen>1) q->flags|=SF_LOOP;
+
+               /* fix replen if repend>length */
+
+               if(q->loopend>q->length) q->loopend=q->length;
+
+               s++;    /* point to next source sampleinfo */
+               d++;    /* point to next destiny sampleinfo */
+       }
+
+       if(!M15_LoadPatterns()) return 0;
+       return 1;
+}
+
+
+
+LOADER load_m15={
+       NULL,
+       "15-instrument module",
+       "Portable MOD-15 loader v0.1",
+       M15_Init,
+       M15_Test,
+       M15_Load,
+       M15_Cleanup
+};
diff --git a/libs/oldmik/src/load_mod.c b/libs/oldmik/src/load_mod.c
new file mode 100644 (file)
index 0000000..f8698f1
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+
+Name:
+LOAD_MOD.C
+
+Description:
+Generic MOD loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mikmod.h"
+
+/*************************************************************************
+*************************************************************************/
+
+
+typedef struct MSAMPINFO{       /* sample header as it appears in a module */
+        char  samplename[22];
+       UWORD length;
+       UBYTE finetune;
+       UBYTE volume;
+       UWORD reppos;
+       UWORD replen;
+} MSAMPINFO;
+
+
+typedef struct MODULEHEADER{    /* verbatim module header */
+        char       songname[20];                /* the songname.. */
+       MSAMPINFO  samples[31];                         /* all sampleinfo */
+       UBYTE      songlength;                          /* number of patterns used */
+       UBYTE      magic1;                                      /* should be 127 */
+       UBYTE      positions[128];                      /* which pattern to play at pos */
+       UBYTE      magic2[4];                           /* string "M.K." or "FLT4" or "FLT8" */
+} MODULEHEADER;
+
+#define MODULEHEADERSIZE 1084
+
+
+typedef struct MODTYPE{                         /* struct to identify type of module */
+        char    id[5];
+       UBYTE   channels;
+       char    *name;
+} MODTYPE;
+
+
+typedef struct MODNOTE{
+       UBYTE a,b,c,d;
+} MODNOTE;
+
+
+/*************************************************************************
+*************************************************************************/
+
+
+char protracker[]="Protracker";
+char startracker[]="Startracker";
+char fasttracker[]="Fasttracker";
+char ins15tracker[]="15-instrument";
+char oktalyzer[]="Oktalyzer";
+char taketracker[]="TakeTracker";
+
+
+MODTYPE modtypes[]={
+       "M.K.",4,protracker,    /* protracker 4 channel */
+       "M!K!",4,protracker,    /* protracker 4 channel */
+       "FLT4",4,startracker,   /* startracker 4 channel */
+       "4CHN",4,fasttracker,   /* fasttracker 4 channel */
+       "6CHN",6,fasttracker,   /* fasttracker 6 channel */
+       "8CHN",8,fasttracker,   /* fasttracker 8 channel */
+       "CD81",8,oktalyzer,     /* atari oktalyzer 8 channel */
+       "OKTA",8,oktalyzer,     /* atari oktalyzer 8 channel */
+       "16CN",16,taketracker,  /* taketracker 16 channel */
+       "32CN",32,taketracker,  /* taketracker 32 channel */
+       "    ",4,ins15tracker   /* 15-instrument 4 channel */
+};
+
+static MODULEHEADER *mh;        /* raw as-is module header */
+static MODNOTE *patbuf;
+
+
+BOOL MOD_Test(void)
+{
+       int t;
+
+       char id[4];
+
+       _mm_fseek(modfp,MODULEHEADERSIZE-4,SEEK_SET);
+       if(!fread(id,4,1,modfp)) return 0;
+
+       /* find out which ID string */
+
+       for(t=0;t<10;t++){
+               if(!memcmp(id,modtypes[t].id,4)) return 1;
+       }
+
+       return 0;
+}
+
+
+BOOL MOD_Init(void)
+{
+       patbuf=NULL;
+       if(!(mh=(MODULEHEADER *)MyCalloc(1,sizeof(MODULEHEADER)))) return 0;
+       return 1;
+}
+
+
+void MOD_Cleanup(void)
+{
+       if(mh!=NULL) free(mh);
+       if(patbuf!=NULL) free(patbuf);
+}
+
+
+/*
+
+Old (amiga) noteinfo:
+
+ _____byte 1_____   byte2_    _____byte 3_____   byte4_
+/                \ /      \  /                \ /      \
+0000          0000-00000000  0000          0000-00000000
+
+Upper four    12 bits for    Lower four    Effect command.
+bits of sam-  note period.   bits of sam-
+ple number.                  ple number.
+
+
+*/
+
+
+UWORD npertab[60]={
+
+/* -> Tuning 0 */
+
+       1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
+       856,808,762,720,678,640,604,570,538,508,480,453,
+       428,404,381,360,339,320,302,285,269,254,240,226,
+       214,202,190,180,170,160,151,143,135,127,120,113,
+       107,101,95,90,85,80,75,71,67,63,60,56
+};
+
+
+void ConvertNote(MODNOTE *n)
+{
+       UBYTE instrument,effect,effdat,note;
+       UWORD period;
+
+       /* extract the various information from the 4 bytes that
+          make up a single note */
+
+       instrument=(n->a&0x10)|(n->c>>4);
+       period=(((UWORD)n->a&0xf)<<8)+n->b;
+       effect=n->c&0xf;
+       effdat=n->d;
+
+       /* Convert the period to a note number */
+
+       note=0;
+       if(period!=0){
+               for(note=0;note<60;note++){
+                       if(period>=npertab[note]) break;
+               }
+               note++;
+               if(note==61) note=0;
+       }
+
+       if(instrument!=0){
+               UniInstrument(instrument-1);
+       }
+
+       if(note!=0){
+               UniNote(note+23);
+       }
+
+       UniPTEffect(effect,effdat);
+}
+
+
+UBYTE *ConvertTrack(MODNOTE *n)
+{
+       int t;
+
+       UniReset();
+       for(t=0;t<64;t++){
+               ConvertNote(n);
+               UniNewline();
+               n+=of.numchn;
+       }
+       return UniDup();
+}
+
+
+BOOL ML_LoadPatterns(void)
+/*
+       Loads all patterns of a modfile and converts them into the
+       3 byte format.
+*/
+{
+       int t,s,tracks=0;
+
+       if(!AllocPatterns()) return 0;
+       if(!AllocTracks()) return 0;
+
+       /* Allocate temporary buffer for loading
+          and converting the patterns */
+
+       if(!(patbuf=(MODNOTE *)MyCalloc(64U*of.numchn,sizeof(MODNOTE)))) return 0;
+
+       for(t=0;t<of.numpat;t++){
+
+               /* Load the pattern into the temp buffer
+                  and convert it */
+
+               for(s=0;s<(64U*of.numchn);s++){
+                       patbuf[s].a=_mm_read_UBYTE(modfp);
+                       patbuf[s].b=_mm_read_UBYTE(modfp);
+                       patbuf[s].c=_mm_read_UBYTE(modfp);
+                       patbuf[s].d=_mm_read_UBYTE(modfp);
+               }
+
+               for(s=0;s<of.numchn;s++){
+                       if(!(of.tracks[tracks++]=ConvertTrack(patbuf+s))) return 0;
+               }
+       }
+
+       return 1;
+}
+
+
+BOOL MOD_Load(void)
+{
+       int t,modtype;
+       INSTRUMENT *d;          /* new sampleinfo structure */
+       SAMPLE *q;
+       MSAMPINFO *s;           /* old module sampleinfo */
+
+       /* try to read module header */
+
+        _mm_read_str((char *)mh->songname,20,modfp);
+
+       for(t=0;t<31;t++){
+               s=&mh->samples[t];
+                _mm_read_str(s->samplename,22,modfp);
+               s->length       =_mm_read_M_UWORD(modfp);
+               s->finetune     =_mm_read_UBYTE(modfp);
+               s->volume       =_mm_read_UBYTE(modfp);
+               s->reppos       =_mm_read_M_UWORD(modfp);
+               s->replen       =_mm_read_M_UWORD(modfp);
+       }
+
+       mh->songlength  =_mm_read_UBYTE(modfp);
+       mh->magic1              =_mm_read_UBYTE(modfp);
+
+       _mm_read_UBYTES(mh->positions,128,modfp);
+       _mm_read_UBYTES(mh->magic2,4,modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* find out which ID string */
+
+       for(modtype=0;modtype<10;modtype++){
+               if(!memcmp(mh->magic2,modtypes[modtype].id,4)) break;
+       }
+
+       if(modtype==10){
+
+               /* unknown modtype */
+               myerr=ERROR_NOT_A_MODULE;
+               return 0;
+       }
+
+       /* set module variables */
+
+       of.initspeed=6;
+       of.inittempo=125;
+       of.numchn=modtypes[modtype].channels;      /* get number of channels */
+       of.modtype=strdup(modtypes[modtype].name);      /* get ascii type of mod */
+       of.songname=DupStr(mh->songname,20);            /* make a cstr of songname */
+       of.numpos=mh->songlength;               /* copy the songlength */
+       memcpy(of.positions,mh->positions,128);         /* copy the position array */
+
+       /* Count the number of patterns */
+
+       of.numpat=0;
+
+       for(t=0;t<128;t++){             /* <-- BUGFIX... have to check ALL positions */
+               if(of.positions[t] > of.numpat){
+                       of.numpat=of.positions[t];
+               }
+       }
+       of.numpat++;
+       of.numtrk=of.numpat*of.numchn;
+
+       /* Finally, init the sampleinfo structures */
+
+       of.numins=31;
+
+       if(!AllocInstruments()) return 0;
+
+       s=mh->samples;   /* init source pointer */
+       d=of.instruments;  /* init dest pointer */
+
+       for(t=0;t<of.numins;t++){
+
+               d->numsmp=1;
+               if(!AllocSamples(d)) return 0;
+
+               q=d->samples;
+
+               /* convert the samplename */
+
+               d->insname=DupStr(s->samplename,22);
+
+               /* init the sampleinfo variables and
+                  convert the size pointers to longword format */
+
+               q->c2spd=finetune[s->finetune&0xf];
+               q->volume=s->volume;
+               q->loopstart=(ULONG)s->reppos<<1;
+               q->loopend=q->loopstart+((ULONG)s->replen<<1);
+               q->length=(ULONG)s->length<<1;
+               q->seekpos=0;
+
+               q->flags=SF_SIGNED;
+               if(s->replen>1) q->flags|=SF_LOOP;
+
+               /* fix replen if repend>length */
+
+               if(q->loopend>q->length) q->loopend=q->length;
+
+               s++;    /* point to next source sampleinfo */
+               d++;    /* point to next destiny sampleinfo */
+       }
+
+       if(!ML_LoadPatterns()) return 0;
+       return 1;
+}
+
+
+
+LOADER load_mod={
+       NULL,
+       "Standard module",
+       "Portable MOD loader v0.11",
+       MOD_Init,
+       MOD_Test,
+       MOD_Load,
+       MOD_Cleanup
+};
diff --git a/libs/oldmik/src/load_mtm.c b/libs/oldmik/src/load_mtm.c
new file mode 100644 (file)
index 0000000..b7ad052
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+
+Name:
+LOAD_MTM.C
+
+Description:
+MTM module loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mikmod.h"
+
+/**************************************************************************
+**************************************************************************/
+
+
+typedef struct MTMSAMPLE{
+       char  samplename[22];
+       ULONG length;
+       ULONG reppos;
+       ULONG repend;
+       UBYTE finetune;
+       UBYTE volume;
+       UBYTE attribute;
+} MTMSAMPLE;
+
+
+
+typedef struct MTMHEADER{
+       UBYTE id[3];                            /* MTM file marker */
+       UBYTE version;                          /* upper major, lower nibble minor version number */
+       char  songname[20];                     /* ASCIIZ songname */
+       UWORD numtracks;                        /* number of tracks saved */
+       UBYTE lastpattern;                      /* last pattern number saved */
+       UBYTE lastorder;                        /* last order number to play (songlength-1) */
+       UWORD commentsize;                      /* length of comment field */
+       UBYTE numsamples;                       /* number of samples saved */
+       UBYTE attribute;                        /* attribute byte (unused) */
+       UBYTE beatspertrack;            /* */
+       UBYTE numchannels;                      /* number of channels used */
+       UBYTE panpos[32];                       /* voice pan positions */
+} MTMHEADER;
+
+
+typedef struct MTMNOTE{
+       UBYTE a,b,c;
+} MTMNOTE;
+
+
+/**************************************************************************
+**************************************************************************/
+
+
+
+static MTMHEADER *mh;
+MTMNOTE *mtmtrk;
+UWORD pat[32];
+
+char MTM_Version[]="MTM";
+
+
+
+BOOL MTM_Test(void)
+{
+       char id[3];
+       if(!fread(id,3,1,modfp)) return 0;
+       if(!memcmp(id,"MTM",3)) return 1;
+       return 0;
+}
+
+
+BOOL MTM_Init(void)
+{
+       mtmtrk=NULL;
+       mh=NULL;
+
+       if(!(mtmtrk=(MTMNOTE *)MyCalloc(64,sizeof(MTMNOTE)))) return 0;
+       if(!(mh=(MTMHEADER *)MyCalloc(1,sizeof(MTMHEADER)))) return 0;
+
+       return 1;
+}
+
+
+void MTM_Cleanup(void)
+{
+       if(mtmtrk!=NULL) free(mtmtrk);
+       if(mh!=NULL) free(mh);
+}
+
+
+
+UBYTE *MTM_Convert(void)
+{
+       int t;
+       UBYTE a,b,c,inst,note,eff,dat;
+
+       UniReset();
+       for(t=0;t<64;t++){
+
+               a=mtmtrk[t].a;
+               b=mtmtrk[t].b;
+               c=mtmtrk[t].c;
+
+               inst=((a&0x3)<<4)|(b>>4);
+               note=a>>2;
+
+               eff=b&0xf;
+               dat=c;
+
+
+               if(inst!=0){
+                       UniInstrument(inst-1);
+               }
+
+               if(note!=0){
+                       UniNote(note+24);
+               }
+
+               /* mtm bug bugfix: when the effect is volslide,
+                  slide-up _always_ overrides slide-dn. */
+
+               if(eff==0xa && dat&0xf0) dat&=0xf0;
+
+               UniPTEffect(eff,dat);
+               UniNewline();
+       }
+       return UniDup();
+}
+
+
+BOOL MTM_Load(void)
+{
+       MTMSAMPLE s;
+       INSTRUMENT *d;
+       SAMPLE *q;
+
+       int t,u;
+
+       /* try to read module header */
+
+        _mm_read_UBYTES(mh->id,3,modfp);
+       mh->version             =_mm_read_UBYTE(modfp);
+       _mm_read_str(mh->songname,20,modfp);
+       mh->numtracks   =_mm_read_I_UWORD(modfp);
+       mh->lastpattern =_mm_read_UBYTE(modfp);
+       mh->lastorder   =_mm_read_UBYTE(modfp);
+       mh->commentsize =_mm_read_I_UWORD(modfp);
+       mh->numsamples  =_mm_read_UBYTE(modfp);
+       mh->attribute   =_mm_read_UBYTE(modfp);
+       mh->beatspertrack=_mm_read_UBYTE(modfp);
+       mh->numchannels =_mm_read_UBYTE(modfp);
+       _mm_read_UBYTES(mh->panpos,32,modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* set module variables */
+
+       of.initspeed=6;
+       of.inittempo=125;
+       of.modtype=strdup(MTM_Version);
+       of.numchn=mh->numchannels;
+       of.numtrk=mh->numtracks+1;                              /* get number of channels */
+       of.songname=DupStr(mh->songname,20);    /* make a cstr of songname */
+       of.numpos=mh->lastorder+1;              /* copy the songlength */
+       of.numpat=mh->lastpattern+1;
+       for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<<4;
+
+       of.numins=mh->numsamples;
+       if(!AllocInstruments()) return 0;
+
+       d=of.instruments;
+
+       for(t=0;t<of.numins;t++){
+
+               d->numsmp=1;
+               if(!AllocSamples(d)) return 0;
+               q=d->samples;
+
+               /* try to read sample info */
+
+               _mm_read_str(s.samplename,22,modfp);
+               s.length        =_mm_read_I_ULONG(modfp);
+               s.reppos        =_mm_read_I_ULONG(modfp);
+               s.repend        =_mm_read_I_ULONG(modfp);
+               s.finetune      =_mm_read_UBYTE(modfp);
+               s.volume        =_mm_read_UBYTE(modfp);
+               s.attribute     =_mm_read_UBYTE(modfp);
+
+               if(feof(modfp)){
+                       myerr=ERROR_LOADING_SAMPLEINFO;
+                       return 0;
+               }
+
+               d->insname=DupStr(s.samplename,22);
+               q->seekpos=0;
+               q->c2spd=finetune[s.finetune];
+               q->length=s.length;
+               q->loopstart=s.reppos;
+               q->loopend=s.repend;
+               q->volume=s.volume;
+
+               q->flags=0;
+
+               if(s.repend-s.reppos>2) q->flags|=SF_LOOP;      /* <- 1.00 bugfix */
+
+               if(s.attribute&1){
+
+                       /* If the sample is 16-bits, convert the length
+                          and replen byte-values into sample-values */
+
+                       q->flags|=SF_16BITS;
+                       q->length>>=1;
+                       q->loopstart>>=1;
+                       q->loopend>>=1;
+               }
+
+               d++;
+       }
+
+       _mm_read_UBYTES(of.positions,128,modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       if(!AllocTracks()) return 0;
+       if(!AllocPatterns()) return 0;
+
+       of.tracks[0]=MTM_Convert();             /* track 0 is empty */
+
+       for(t=1;t<of.numtrk;t++){
+               int s;
+
+               for(s=0;s<64;s++){
+                       mtmtrk[s].a=_mm_read_UBYTE(modfp);
+                       mtmtrk[s].b=_mm_read_UBYTE(modfp);
+                       mtmtrk[s].c=_mm_read_UBYTE(modfp);
+               }
+
+               if(feof(modfp)){
+                       myerr="Error loading track";
+                       return 0;
+               }
+
+               if(!(of.tracks[t]=MTM_Convert())) return 0;
+       }
+
+       for(t=0;t<of.numpat;t++){
+
+               _mm_read_I_UWORDS(pat,32,modfp);
+
+               for(u=0;u<of.numchn;u++){
+                       of.patterns[((long)t*of.numchn)+u]=pat[u];
+               }
+       }
+
+       /* read comment field */
+
+       if(!ReadComment(mh->commentsize)) return 0;
+
+       return 1;
+}
+
+
+
+LOADER load_mtm={
+       NULL,
+       "MTM",
+       "Portable MTM loader v0.1",
+       MTM_Init,
+       MTM_Test,
+       MTM_Load,
+       MTM_Cleanup
+};
+
diff --git a/libs/oldmik/src/load_s3m.c b/libs/oldmik/src/load_s3m.c
new file mode 100644 (file)
index 0000000..07425ec
--- /dev/null
@@ -0,0 +1,570 @@
+/*\r
+\r
+Name:\r
+LOAD_S3M.C\r
+\r
+Description:\r
+Screamtracker (S3M) module loader\r
+\r
+Portability:\r
+All systems - all compilers (hopefully)\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include "mikmod.h"\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+typedef struct S3MNOTE{\r
+       UBYTE note,ins,vol,cmd,inf;\r
+} S3MNOTE;\r
+\r
+typedef S3MNOTE S3MTRACK[64];\r
+\r
+\r
+/* Raw S3M header struct: */\r
+\r
+typedef struct S3MHEADER{\r
+       char  songname[28];\r
+       char  t1a;\r
+       char  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
+\r
+/* Raw S3M sampleinfo struct: */\r
+\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
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+\r
+S3MNOTE *s3mbuf;        /* pointer to a complete S3M pattern */\r
+UWORD *paraptr;         /* parapointer array (see S3M docs) */\r
+static S3MHEADER *mh;\r
+UBYTE remap[32];\r
+\r
+\r
+char S3M_Version[]="Screamtracker 3.xx";\r
+\r
+\r
+\r
+BOOL S3M_Test(void)\r
+{\r
+       char id[4];\r
+       _mm_fseek(modfp,0x2c,SEEK_SET);\r
+       if(!fread(id,4,1,modfp)) return 0;\r
+       if(!memcmp(id,"SCRM",4)) return 1;\r
+       return 0;\r
+}\r
+\r
+BOOL S3M_Init(void)\r
+{\r
+       s3mbuf=NULL;\r
+       paraptr=NULL;\r
+\r
+       if(!(s3mbuf=(S3MNOTE *)MyMalloc(16*64*sizeof(S3MNOTE)))) return 0;\r
+       if(!(mh=(S3MHEADER *)MyCalloc(1,sizeof(S3MHEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void S3M_Cleanup(void)\r
+{\r
+       if(s3mbuf!=NULL) free(s3mbuf);\r
+       if(paraptr!=NULL) free(paraptr);\r
+       if(mh!=NULL) free(mh);\r
+}\r
+\r
+\r
+\r
+\r
+BOOL S3M_ReadPattern(void)\r
+{\r
+       int row=0,flag,ch;\r
+       S3MNOTE *n;\r
+       S3MNOTE dummy;\r
+\r
+       /* clear pattern data */\r
+\r
+       memset(s3mbuf,255,16*64*sizeof(S3MNOTE));\r
+\r
+       while(row<64){\r
+\r
+               flag=fgetc(modfp);\r
+\r
+               if(flag==EOF){\r
+                       myerr="Error loading pattern";\r
+                       return 0;\r
+               }\r
+\r
+               if(flag){\r
+\r
+                       ch=flag&31;\r
+\r
+                       if(mh->channels[ch]<16){\r
+                               n=&s3mbuf[(64U*remap[ch])+row];\r
+                       }\r
+                       else{\r
+                               n=&dummy;\r
+                       }\r
+\r
+                       if(flag&32){\r
+                               n->note=fgetc(modfp);\r
+                               n->ins=fgetc(modfp);\r
+                       }\r
+\r
+                       if(flag&64){\r
+                               n->vol=fgetc(modfp);\r
+                       }\r
+\r
+                       if(flag&128){\r
+                               n->cmd=fgetc(modfp);\r
+                               n->inf=fgetc(modfp);\r
+                       }\r
+               }\r
+               else row++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+UBYTE *S3M_ConvertTrack(S3MNOTE *tr)\r
+{\r
+       int t;\r
+\r
+       UBYTE note,ins,vol,cmd,inf,lo,hi;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++){\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
+               lo=inf&0xf;\r
+               hi=inf>>4;\r
+\r
+\r
+               if(ins!=0 && ins!=255){\r
+                       UniInstrument(ins-1);\r
+               }\r
+\r
+               if(note!=255){\r
+                       if(note==254) UniPTEffect(0xc,0);                       /* <- note off command */\r
+                       else UniNote(((note>>4)*12)+(note&0xf));        /* <- normal note */\r
+               }\r
+\r
+               if(vol<255){\r
+                       UniPTEffect(0xc,vol);\r
+/*                     UniWrite(UNI_S3MVOLUME); */\r
+/*                     UniWrite(vol); */\r
+               }\r
+\r
+               if(cmd!=255){\r
+                       switch(cmd){\r
+\r
+                               case 1:                 /* Axx set speed to xx */\r
+                                       UniWrite(UNI_S3MEFFECTA);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 2:                 /* Bxx position jump */\r
+                                       UniPTEffect(0xb,inf);\r
+                                       break;\r
+\r
+                               case 3:                 /* Cxx patternbreak to row xx */\r
+                                       UniPTEffect(0xd,inf);\r
+                                       break;\r
+\r
+                               case 4:                 /* Dxy volumeslide */\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 5:                 /* Exy toneslide down */\r
+                                       UniWrite(UNI_S3MEFFECTE);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 6:                 /* Fxy toneslide up */\r
+                                       UniWrite(UNI_S3MEFFECTF);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 7:                 /* Gxx Tone portamento,speed xx */\r
+                                       UniPTEffect(0x3,inf);\r
+                                       break;\r
+\r
+                               case 8:                 /* Hxy vibrato */\r
+                                       UniPTEffect(0x4,inf);\r
+                                       break;\r
+\r
+                               case 9:                 /* Ixy tremor, ontime x, offtime y */\r
+                                       UniWrite(UNI_S3MEFFECTI);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xa:               /* Jxy arpeggio */\r
+                                       UniPTEffect(0x0,inf);\r
+                                       break;\r
+\r
+                               case 0xb:               /* Kxy Dual command H00 & Dxy */\r
+                                       UniPTEffect(0x4,0);\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xc:               /* Lxy Dual command G00 & Dxy */\r
+                                       UniPTEffect(0x3,0);\r
+                                       UniWrite(UNI_S3MEFFECTD);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0xf:               /* Oxx set sampleoffset xx00h */\r
+                                       UniPTEffect(0x9,inf);\r
+                                       break;\r
+\r
+                               case 0x11:              /* Qxy Retrig (+volumeslide) */\r
+                                       UniWrite(UNI_S3MEFFECTQ);\r
+                                       UniWrite(inf);\r
+                                       break;\r
+\r
+                               case 0x12:              /* Rxy tremolo speed x, depth y */\r
+                                       UniPTEffect(0x6,inf);\r
+                                       break;\r
+\r
+                               case 0x13:              /* Sxx special commands */\r
+                                       switch(hi){\r
+\r
+                                               case 0: /* S0x set filter */\r
+                                                       UniPTEffect(0xe,0x00|lo);\r
+                                                       break;\r
+\r
+                                               case 1: /* S1x set glissando control */\r
+                                                       UniPTEffect(0xe,0x30|lo);\r
+                                                       break;\r
+\r
+                                               case 2: /* S2x set finetune */\r
+                                                       UniPTEffect(0xe,0x50|lo);\r
+                                                       break;\r
+\r
+                                               case 3: /* S3x set vibrato waveform */\r
+                                                       UniPTEffect(0xe,0x40|lo);\r
+                                                       break;\r
+\r
+                                               case 4: /* S4x set tremolo waveform */\r
+                                                       UniPTEffect(0xe,0x70|lo);\r
+                                                       break;\r
+\r
+                                               case 8: /* S8x set panning position */\r
+                                                       UniPTEffect(0xe,0x80|lo);\r
+                                                       break;\r
+\r
+                                               case 0xb:       /* SBx pattern loop */\r
+                                                       UniPTEffect(0xe,0x60|lo);\r
+                                                       break;\r
+\r
+                                               case 0xc:       /* SCx notecut */\r
+                                                       UniPTEffect(0xe,0xC0|lo);\r
+                                                       break;\r
+\r
+                                               case 0xd:       /* SDx notedelay */\r
+                                                       UniPTEffect(0xe,0xD0|lo);\r
+                                                       break;\r
+\r
+                                               case 0xe:       /* SDx patterndelay */\r
+                                                       UniPTEffect(0xe,0xE0|lo);\r
+                                                       break;\r
+                                       }\r
+                                       break;\r
+\r
+                               case 0x14:      /* Txx tempo */\r
+                                       if(inf>0x20){\r
+                                               UniWrite(UNI_S3MEFFECTT);\r
+                                               UniWrite(inf);\r
+                                       }\r
+                                       break;\r
+\r
+                               case 0x18:      /* Xxx amiga command 8xx */\r
+                                       UniPTEffect(0x8,inf);\r
+                                       break;\r
+                       }\r
+               }\r
+\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+\r
+\r
+\r
+BOOL S3M_Load(void)\r
+{\r
+       int t,u,track=0;\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       UBYTE isused[16];\r
+       UBYTE pan[32];\r
+\r
+       /* try to read module header */\r
+\r
+       _mm_read_str(mh->songname,28,modfp);\r
+       mh->t1a                 =_mm_read_UBYTE(modfp);\r
+       mh->type                =_mm_read_UBYTE(modfp);\r
+       _mm_read_UBYTES(mh->unused1,2,modfp);\r
+       mh->ordnum              =_mm_read_I_UWORD(modfp);\r
+       mh->insnum              =_mm_read_I_UWORD(modfp);\r
+       mh->patnum              =_mm_read_I_UWORD(modfp);\r
+       mh->flags               =_mm_read_I_UWORD(modfp);\r
+       mh->tracker             =_mm_read_I_UWORD(modfp);\r
+       mh->fileformat  =_mm_read_I_UWORD(modfp);\r
+       _mm_read_str(mh->scrm,4,modfp);\r
+\r
+       mh->mastervol   =_mm_read_UBYTE(modfp);\r
+       mh->initspeed   =_mm_read_UBYTE(modfp);\r
+       mh->inittempo   =_mm_read_UBYTE(modfp);\r
+       mh->mastermult  =_mm_read_UBYTE(modfp);\r
+       mh->ultraclick  =_mm_read_UBYTE(modfp);\r
+       mh->pantable    =_mm_read_UBYTE(modfp);\r
+       _mm_read_UBYTES(mh->unused2,8,modfp);\r
+       mh->special             =_mm_read_I_UWORD(modfp);\r
+       _mm_read_UBYTES(mh->channels,32,modfp);\r
+\r
+       if(feof(modfp)){\r
+               myerr="Error loading header";\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+\r
+       of.modtype=strdup(S3M_Version);\r
+       of.songname=DupStr(mh->songname,28);    /* make a cstr of songname */\r
+       of.numpat=mh->patnum;\r
+       of.numins=mh->insnum;\r
+       of.initspeed=mh->initspeed;\r
+       of.inittempo=mh->inittempo;\r
+\r
+       /* count the number of channels used */\r
+\r
+       of.numchn=0;\r
+\r
+/*      for(t=0;t<32;t++) printf("%2.2x ",mh->channels[t]);\r
+*/\r
+       for(t=0;t<32;t++) remap[t]=0;\r
+       for(t=0;t<16;t++) isused[t]=0;\r
+\r
+       /* set a flag for each channel (1 out of of 16) thats being used: */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       isused[mh->channels[t]]=1;\r
+               }\r
+       }\r
+\r
+       /* give each of them a different number */\r
+\r
+       for(t=0;t<16;t++){\r
+               if(isused[t]){\r
+                       isused[t]=of.numchn;\r
+                       of.numchn++;\r
+               }\r
+       }\r
+\r
+       /* build the remap array */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       remap[t]=isused[mh->channels[t]];\r
+               }\r
+       }\r
+\r
+       /* set panning positions */\r
+\r
+       for(t=0;t<32;t++){\r
+               if(mh->channels[t]<16){\r
+                       if(mh->channels[t]<8){\r
+                               of.panning[remap[t]]=0x30;\r
+                       }\r
+                       else{\r
+                               of.panning[remap[t]]=0xc0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       of.numtrk=of.numpat*of.numchn;\r
+\r
+/*      printf("Uses %d channels\n",of.numchn);\r
+*/\r
+       /* read the order data */\r
+\r
+       _mm_read_UBYTES(of.positions,mh->ordnum,modfp);\r
+\r
+       of.numpos=0;\r
+       for(t=0;t<mh->ordnum;t++){\r
+               of.positions[of.numpos]=of.positions[t];\r
+               if(of.positions[t]<254) of.numpos++;\r
+       }\r
+\r
+       if((paraptr=(UWORD *)MyMalloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0;\r
+\r
+       /* read the instrument+pattern parapointers */\r
+\r
+       _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp);\r
+\r
+/*      printf("pantab %d\n",mh->pantable);\r
+*/\r
+       if(mh->pantable==252){\r
+\r
+               /* read the panning table */\r
+\r
+               _mm_read_UBYTES(pan,32,modfp);\r
+\r
+               /* set panning positions according to panning table (new for st3.2) */\r
+\r
+               for(t=0;t<32;t++){\r
+                       if((pan[t]&0x20) && mh->channels[t]<16){\r
+                               of.panning[remap[t]]=(pan[t]&0xf)<<4;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* now is a good time to check if the header was too short :) */\r
+\r
+       if(feof(modfp)){\r
+               myerr="Error loading header";\r
+               return 0;\r
+       }\r
+\r
+       if(!AllocInstruments()) return 0;\r
+\r
+       d=of.instruments;\r
+\r
+       for(t=0;t<of.numins;t++){\r
+               S3MSAMPLE s;\r
+\r
+               d->numsmp=1;\r
+               if(!AllocSamples(d)) return 0;\r
+               q=d->samples;\r
+\r
+               /* seek to instrument position */\r
+\r
+               _mm_fseek(modfp,((long)paraptr[t])<<4,SEEK_SET);\r
+\r
+               /* and load sample info */\r
+\r
+               s.type          =_mm_read_UBYTE(modfp);\r
+               _mm_read_str(s.filename,12,modfp);\r
+               s.memsegh       =_mm_read_UBYTE(modfp);\r
+               s.memsegl       =_mm_read_I_UWORD(modfp);\r
+               s.length        =_mm_read_I_ULONG(modfp);\r
+               s.loopbeg       =_mm_read_I_ULONG(modfp);\r
+               s.loopend       =_mm_read_I_ULONG(modfp);\r
+               s.volume        =_mm_read_UBYTE(modfp);\r
+               s.dsk           =_mm_read_UBYTE(modfp);\r
+               s.pack          =_mm_read_UBYTE(modfp);\r
+               s.flags         =_mm_read_UBYTE(modfp);\r
+               s.c2spd         =_mm_read_I_ULONG(modfp);\r
+               _mm_read_UBYTES(s.unused,12,modfp);\r
+               _mm_read_str(s.sampname,28,modfp);\r
+               _mm_read_str(s.scrs,4,modfp);\r
+\r
+               if(feof(modfp)){\r
+                       myerr=ERROR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               d->insname=DupStr(s.sampname,28);\r
+               q->c2spd=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
+               q->flags=0;\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
+\r
+               if(memcmp(s.scrs,"SCRS",4)!=0) q->length=0;\r
+\r
+/*              printf("%s\n",d->insname);\r
+*/\r
+               d++;\r
+       }\r
+\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++){\r
+\r
+               /* seek to pattern position ( + 2 skip pattern length ) */\r
+\r
+               _mm_fseek(modfp,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);\r
+\r
+               if(!S3M_ReadPattern()) return 0;\r
+\r
+               for(u=0;u<of.numchn;u++){\r
+                       if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+LOADER load_s3m={\r
+       NULL,\r
+       "S3M",\r
+       "Portable S3M loader v0.2",\r
+       S3M_Init,\r
+       S3M_Test,\r
+       S3M_Load,\r
+       S3M_Cleanup\r
+};\r
diff --git a/libs/oldmik/src/load_stm.c b/libs/oldmik/src/load_stm.c
new file mode 100644 (file)
index 0000000..b7bec87
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+
+Name:
+LOAD_STM.C
+
+Description:
+ScreamTracker 2 (STM) module Loader - Version 1.oOo Release 2 
+A Coding Nightmare by Rao and Air Richter of HaRDCoDE
+You can now play all of those wonderful old C.C. Catch STM's!
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mikmod.h"
+
+typedef struct STMNOTE{
+   UBYTE note,insvol,volcmd,cmdinf;
+} STMNOTE;
+
+
+/* Raw STM sampleinfo struct: */
+
+typedef struct STMSAMPLE{
+   char  filename[12]; /* Can't have long comments - just filename comments :) */
+   char  unused;       /* 0x00 */
+   UBYTE instdisk;     /* Instrument disk */
+   UWORD reserved;     /* ISA in memory when in ST 2 */
+   UWORD length;       /* Sample length */
+   UWORD loopbeg;      /* Loop start point */
+   UWORD loopend;      /* Loop end point */
+   UBYTE volume;       /* Volume */
+   UBYTE reserved2;    /* More reserved crap */
+   UWORD c2spd;        /* Good old c2spd */
+   UBYTE reserved3[4]; /* Yet more of PSi's reserved crap */
+   UWORD isa;          /* Internal Segment Address -> */
+                                          /*    contrary to the tech specs, this is NOT actually */
+                                          /*    written to the stm file. */
+} STMSAMPLE;
+
+/* Raw STM header struct: */
+
+typedef struct STMHEADER{
+   char songname[20];
+   char trackername[8];   /* !SCREAM! for ST 2.xx */
+   char unused;           /* 0x1A */
+   char filetype;         /* 1=song, 2=module (only 2 is supported, of course) :) */
+   char ver_major;        /* Like 2 */
+   char ver_minor;        /* "ditto" */
+   UBYTE inittempo;       /* initspeed= stm inittempo>>4 */
+   UBYTE  numpat;         /* number of patterns */
+   UBYTE   globalvol;     /* <- WoW! a RiGHT TRiANGLE =8*) */
+   UBYTE    reserved[13]; /* More of PSi's internal crap */
+   STMSAMPLE sample[31];  /* STM sample data */
+   UBYTE patorder[128];   /* Docs say 64 - actually 128 */
+} STMHEADER;
+
+
+static STMNOTE *stmbuf;
+static STMHEADER *mh;
+
+char STM_Version[]="Screamtracker 2";
+
+
+
+BOOL STM_Test(void)
+{
+   char str[9],filetype;
+
+   _mm_fseek(modfp,21,SEEK_SET);
+   fread(str,1,9,modfp);
+   fread(&filetype,1,1,modfp);
+   if(!memcmp(str,"!SCREAM!",8) || (filetype!=2)) /* STM Module = filetype 2 */
+         return 0;
+   return 1;
+}
+
+
+
+BOOL STM_Init(void)
+{
+       stmbuf=NULL;
+       if(!(mh=(STMHEADER *)MyCalloc(1,sizeof(STMHEADER)))) return 0;
+       return 1;
+}
+
+void STM_Cleanup(void)
+{
+       if(mh!=NULL) free(mh);
+       if(stmbuf!=NULL) free(stmbuf);
+}
+
+
+
+void STM_ConvertNote(STMNOTE *n)
+{
+       UBYTE note,ins,vol,cmd,inf;
+
+       /* extract the various information from the 4 bytes that
+          make up a single note */
+
+               note=n->note;
+               ins=n->insvol>>3;
+               vol=(n->insvol&7)+(n->volcmd>>1);
+               cmd=n->volcmd&15;
+               inf=n->cmdinf;
+
+               if(ins!=0 && ins<32){
+                       UniInstrument(ins-1);
+               }
+
+      /* special values of [SBYTE0] are handled here -> */
+      /* we have no idea if these strange values will ever be encountered */
+         /* but it appears as though stms sound correct. */
+      if(note==254 || note==252) UniPTEffect(0xc,0); /* <- note off command (???) */
+            else
+      /* if note < 251, then all three bytes are stored in the file */
+      if(note<251) UniNote((((note>>4)+2)*12)+(note&0xf));      /* <- normal note and up the octave by two */
+
+               if(vol<65){
+                       UniPTEffect(0xc,vol);
+               }
+
+               if(cmd!=255){
+                       switch(cmd){
+
+                               case 1:                 /* Axx set speed to xx and add 0x1c to fix StoOoPiD STM 2.x */
+                                       UniPTEffect(0xf,inf>>4);
+                                       break;
+
+                               case 2:                 /* Bxx position jump */
+                                       UniPTEffect(0xb,inf);
+                                       break;
+
+                               case 3:                 /* Cxx patternbreak to row xx */
+                                       UniPTEffect(0xd,inf);
+                                       break;
+
+                               case 4:                 /* Dxy volumeslide */
+                                       UniWrite(UNI_S3MEFFECTD);
+                                       UniWrite(inf);
+                                       break;
+
+                               case 5:                 /* Exy toneslide down */
+                                       UniWrite(UNI_S3MEFFECTE);
+                                       UniWrite(inf);
+                                       break;
+
+                               case 6:                 /* Fxy toneslide up */
+                                       UniWrite(UNI_S3MEFFECTF);
+                                       UniWrite(inf);
+                                       break;
+
+                               case 7:                 /* Gxx Tone portamento,speed xx */
+                                       UniPTEffect(0x3,inf);
+                                       break;
+
+                               case 8:                 /* Hxy vibrato */
+                                       UniPTEffect(0x4,inf);
+                                       break;
+
+                               case 9:                 /* Ixy tremor, ontime x, offtime y */
+                                       UniWrite(UNI_S3MEFFECTI);
+                                       UniWrite(inf);
+                                       break;
+
+                               case 0xa:               /* Jxy arpeggio */
+                                       UniPTEffect(0x0,inf);
+                                       break;
+
+                               case 0xb:               /* Kxy Dual command H00 & Dxy */
+                                       UniPTEffect(0x4,0);
+                                       UniWrite(UNI_S3MEFFECTD);
+                                       UniWrite(inf);
+                                       break;
+
+                               case 0xc:               /* Lxy Dual command G00 & Dxy */
+                                       UniPTEffect(0x3,0);
+                                       UniWrite(UNI_S3MEFFECTD);
+                                       UniWrite(inf);
+                                       break;
+
+               /* Support all these above, since ST2 can LOAD these values */
+               /* but can actually only play up to J - and J is only */
+               /* half-way implemented in ST2 */
+
+                               case 0x18:      /* Xxx amiga command 8xx - What the hell, support panning. :) */
+                                       UniPTEffect(0x8,inf);
+                                       break;
+                       }
+               }
+
+}
+
+
+UBYTE *STM_ConvertTrack(STMNOTE *n)
+{
+       int t;
+
+       UniReset();
+       for(t=0;t<64;t++)
+       {       STM_ConvertNote(n);
+               UniNewline();
+               n+=of.numchn;
+       }
+       return UniDup();
+}
+
+
+
+
+BOOL STM_LoadPatterns(void)
+{
+       int t,s,tracks=0;
+
+       if(!AllocPatterns()) return 0;
+       if(!AllocTracks()) return 0;
+
+       /* Allocate temporary buffer for loading
+          and converting the patterns */
+
+       if(!(stmbuf=(STMNOTE *)MyCalloc(64U*of.numchn,sizeof(STMNOTE)))) return 0;
+
+       for(t=0;t<of.numpat;t++){
+
+               for(s=0;s<(64U*of.numchn);s++){
+                       stmbuf[s].note=_mm_read_UBYTE(modfp);
+                       stmbuf[s].insvol=_mm_read_UBYTE(modfp);
+                       stmbuf[s].volcmd=_mm_read_UBYTE(modfp);
+                       stmbuf[s].cmdinf=_mm_read_UBYTE(modfp);
+               }
+
+               if(feof(modfp)){
+                       myerr=ERROR_LOADING_PATTERN;
+                       return 0;
+               }
+
+               for(s=0;s<of.numchn;s++){
+                       if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
+               }
+       }
+
+       return 1;
+}
+
+
+
+BOOL STM_Load(void)
+{
+       int t;
+       ULONG MikMod_ISA; /* We MUST generate our own ISA - NOT stored in the stm */
+       INSTRUMENT *d;
+       SAMPLE *q;
+
+       /* try to read stm header */
+
+       _mm_read_str(mh->songname,20,modfp);
+       _mm_read_str(mh->trackername,8,modfp);
+       mh->unused              =_mm_read_UBYTE(modfp);
+       mh->filetype    =_mm_read_UBYTE(modfp);
+       mh->ver_major   =_mm_read_UBYTE(modfp);
+       mh->ver_minor   =_mm_read_UBYTE(modfp);
+       mh->inittempo   =_mm_read_UBYTE(modfp);
+       mh->numpat              =_mm_read_UBYTE(modfp);
+       mh->globalvol   =_mm_read_UBYTE(modfp);
+       _mm_read_UBYTES(mh->reserved,13,modfp);
+
+       for(t=0;t<31;t++){
+               STMSAMPLE *s=&mh->sample[t];  /* STM sample data */
+               _mm_read_str(s->filename,12,modfp);
+               s->unused       =_mm_read_UBYTE(modfp);
+               s->instdisk     =_mm_read_UBYTE(modfp);
+               s->reserved     =_mm_read_I_UWORD(modfp);
+               s->length       =_mm_read_I_UWORD(modfp);
+               s->loopbeg      =_mm_read_I_UWORD(modfp);
+               s->loopend      =_mm_read_I_UWORD(modfp);
+               s->volume       =_mm_read_UBYTE(modfp);
+               s->reserved2=_mm_read_UBYTE(modfp);
+               s->c2spd        =_mm_read_I_UWORD(modfp);
+               _mm_read_UBYTES(s->reserved3,4,modfp);
+               s->isa          =_mm_read_I_UWORD(modfp);
+       }
+       _mm_read_UBYTES(mh->patorder,128,modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* set module variables */
+
+       of.modtype=strdup(STM_Version);
+       of.songname=DupStr(mh->songname,20); /* make a cstr of songname */
+
+       of.numpat=mh->numpat;
+
+       of.initspeed=6; /* Always this */
+
+       /* STM 2.x tempo has always been fucked... The default of 96 */
+       /* is actually 124, so we add 1ch to the initial value of 60h */
+
+       /* MikMak: No it's not.. STM tempo is UNI speed << 4 */
+
+       of.inittempo=125;               /* mh->inittempo+0x1c; */
+       of.initspeed=mh->inittempo>>4;
+       of.numchn=4; /* get number of channels */
+
+       t=0;
+       while(mh->patorder[t]!=99){ /* 99 terminates the patorder list */
+               of.positions[t]=mh->patorder[t];
+               t++;
+       }
+       of.numpos=--t;
+       of.numtrk=of.numpat*of.numchn;
+
+       /* Finally, init the sampleinfo structures */
+
+       of.numins=31; /* always this */
+
+       if(!AllocInstruments()) return 0;
+       if(!STM_LoadPatterns()) return 0;
+
+       d=of.instruments;
+
+       MikMod_ISA=ftell(modfp);
+       MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
+
+       for(t=0;t<of.numins;t++){
+
+               d->numsmp=1;
+               if(!AllocSamples(d)) return 0;
+               q=d->samples;
+
+               /* load sample info */
+
+               d->insname=DupStr(mh->sample[t].filename,12);
+               q->c2spd=mh->sample[t].c2spd;
+               q->volume=mh->sample[t].volume;
+               q->length=mh->sample[t].length;
+               if (!mh->sample[t].volume || q->length==1 ) q->length = 0; /* if vol = 0 or length = 1, then no sample */
+               q->loopstart=mh->sample[t].loopbeg;
+               q->loopend=mh->sample[t].loopend;
+               q->seekpos=MikMod_ISA;
+
+               MikMod_ISA+=q->length;
+
+               MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
+
+         /* Once again, contrary to the STM specs, all the sample data is */
+         /* actually SIGNED! Sheesh */
+
+               q->flags=SF_SIGNED;
+
+               if(mh->sample[t].loopend>0 && mh->sample[t].loopend!=0xffff) q->flags|=SF_LOOP;
+
+               /* fix replen if repend>length */
+
+               if(q->loopend>q->length) q->loopend=q->length;
+
+               d++;
+       }
+
+       return 1;
+}
+
+
+LOADER load_stm={
+       NULL,
+       "STM",
+       "Portable STM Loader - V 1.2 - A Coding Nightmare by Rao and Air Richter of HaRDCoDE",
+       STM_Init,
+       STM_Test,
+       STM_Load,
+       STM_Cleanup
+};
diff --git a/libs/oldmik/src/load_ult.c b/libs/oldmik/src/load_ult.c
new file mode 100644 (file)
index 0000000..a60325a
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+
+Name:
+LOAD_ULT.C
+
+Description:
+Ultratracker (ULT) module loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "mikmod.h"
+
+#define ULTS_16BITS     4
+#define ULTS_LOOP       8
+#define ULTS_REVERSE    16
+
+
+/* Raw ULT header struct: */
+
+typedef struct ULTHEADER{
+       char  id[15];
+       char  songtitle[32];
+       UBYTE reserved;
+} ULTHEADER;
+
+
+/* Raw ULT sampleinfo struct: */
+
+typedef struct ULTSAMPLE{
+       char  samplename[32];
+       char  dosname[12];
+       SLONG  loopstart;
+       SLONG  loopend;
+       SLONG  sizestart;
+       SLONG  sizeend;
+       UBYTE volume;
+       UBYTE flags;
+       SWORD  finetune;
+} ULTSAMPLE;
+
+
+typedef struct ULTEVENT{
+       UBYTE note,sample,eff,dat1,dat2;
+} ULTEVENT;
+
+
+char *ULT_Version[]={
+       "Ultra Tracker V1.3",
+       "Ultra Tracker V1.4",
+       "Ultra Tracker V1.5",
+       "Ultra Tracker V1.6"
+};
+
+
+BOOL ULT_Test(void)
+{
+       char id[15];
+
+       if(!fread(&id,15,1,modfp)) return 0;
+       return(!strncmp(id,"MAS_UTrack_V00",14));
+}
+
+
+BOOL ULT_Init(void)
+{
+       return 1;
+}
+
+
+void ULT_Cleanup(void)
+{
+}
+
+ULTEVENT ev;
+
+
+
+int ReadUltEvent(ULTEVENT *event)
+{
+       UBYTE flag,rep=1;
+
+       flag=_mm_read_UBYTE(modfp);
+
+       if(flag==0xfc){
+               fread(&rep,1,1,modfp);
+               event->note     =_mm_read_UBYTE(modfp);
+       }
+       else{
+               event->note=flag;
+       }
+
+       event->sample   =_mm_read_UBYTE(modfp);
+       event->eff              =_mm_read_UBYTE(modfp);
+       event->dat1             =_mm_read_UBYTE(modfp);
+       event->dat2             =_mm_read_UBYTE(modfp);
+
+       return rep;
+}
+
+
+
+
+BOOL ULT_Load(void)
+{
+       int t,u,tracks=0;
+       INSTRUMENT *d;
+       SAMPLE *q;
+       ULTSAMPLE s;
+       ULTHEADER mh;
+       UBYTE nos,noc,nop;
+
+       /* try to read module header */
+
+       _mm_read_str(mh.id,15,modfp);
+       _mm_read_str(mh.songtitle,32,modfp);
+       mh.reserved=_mm_read_UBYTE(modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       if(mh.id[14]<'1' || mh.id[14]>'4'){
+               printf("This version is not yet supported\n");
+               return 0;
+       }
+
+       of.modtype=strdup(ULT_Version[mh.id[14]-'1']);
+       of.initspeed=6;
+       of.inittempo=125;
+
+       /* read songtext */
+
+       if(!ReadComment((UWORD)mh.reserved*32)) return 0;
+
+       nos=_mm_read_UBYTE(modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       of.songname=DupStr(mh.songtitle,32);
+       of.numins=nos;
+
+       if(!AllocInstruments()) return 0;
+
+       d=of.instruments;
+
+       for(t=0;t<nos;t++){
+
+               d->numsmp=1;
+               if(!AllocSamples(d)) return 0;
+               q=d->samples;
+
+               /* try to read sample info */
+
+               _mm_read_str(s.samplename,32,modfp);
+               _mm_read_str(s.dosname,12,modfp);
+               s.loopstart     =_mm_read_I_ULONG(modfp);
+               s.loopend       =_mm_read_I_ULONG(modfp);
+               s.sizestart     =_mm_read_I_ULONG(modfp);
+               s.sizeend       =_mm_read_I_ULONG(modfp);
+               s.volume        =_mm_read_UBYTE(modfp);
+               s.flags         =_mm_read_UBYTE(modfp);
+               s.finetune      =_mm_read_I_SWORD(modfp);
+
+               if(feof(modfp)){
+                       myerr=ERROR_LOADING_SAMPLEINFO;
+                       return 0;
+               }
+
+               d->insname=DupStr(s.samplename,32);
+
+               q->seekpos=0;
+
+               q->c2spd=8363;
+
+               if(mh.id[14]>='4'){
+                       _mm_read_I_UWORD(modfp);        /* read 1.6 extra info(??) word */
+                       q->c2spd=s.finetune;
+               }
+
+               q->length=s.sizeend-s.sizestart;
+               q->volume=s.volume>>2;
+               q->loopstart=s.loopstart;
+               q->loopend=s.loopend;
+
+               q->flags=SF_SIGNED;
+
+               if(s.flags&ULTS_LOOP){
+                       q->flags|=SF_LOOP;
+               }
+
+               if(s.flags&ULTS_16BITS){
+                       q->flags|=SF_16BITS;
+                       q->loopstart>>=1;
+                       q->loopend>>=1;
+               }
+
+/*      printf("Sample %d %s length %ld\n",t,d->samplename,d->length); */
+               d++;
+       }
+
+       _mm_read_UBYTES(of.positions,256,modfp);
+
+       for(t=0;t<256;t++){
+               if(of.positions[t]==255) break;
+       }
+       of.numpos=t;
+
+       noc=_mm_read_UBYTE(modfp);
+       nop=_mm_read_UBYTE(modfp);
+
+       of.numchn=noc+1;
+       of.numpat=nop+1;
+       of.numtrk=of.numchn*of.numpat;
+
+       if(!AllocTracks()) return 0;
+       if(!AllocPatterns()) return 0;
+
+       for(u=0;u<of.numchn;u++){
+               for(t=0;t<of.numpat;t++){
+                       of.patterns[(t*of.numchn)+u]=tracks++;
+               }
+       }
+
+       /* read pan position table for v1.5 and higher */
+
+       if(mh.id[14]>='3'){
+               for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modfp)<<4;
+       }
+
+
+       for(t=0;t<of.numtrk;t++){
+               int rep,s,done;
+
+               UniReset();
+               done=0;
+
+               while(done<64){
+
+                       rep=ReadUltEvent(&ev);
+
+                       if(feof(modfp)){
+                               myerr=ERROR_LOADING_TRACK;
+                               return 0;
+                       }
+
+/*                      printf("rep %d: n %d i %d e %x d1 %d d2 %d \n",rep,ev.note,ev.sample,ev.eff,ev.dat1,ev.dat2); */
+
+
+                       for(s=0;s<rep;s++){
+                               UBYTE eff;
+
+
+                               if(ev.sample){
+                                       UniInstrument(ev.sample-1);
+                               }
+
+                               if(ev.note){
+                                       UniNote(ev.note+23);
+                               }
+
+                               eff=ev.eff>>4;
+
+
+                               /*
+                                       ULT panning effect fixed by Alexander Kerkhove :
+                               */
+
+
+                               if(eff==0xc) UniPTEffect(eff,ev.dat2>>2);
+                               else if(eff==0xb) UniPTEffect(8,ev.dat2*0xf);
+                               else UniPTEffect(eff,ev.dat2);
+
+                               eff=ev.eff&0xf;
+
+                               if(eff==0xc) UniPTEffect(eff,ev.dat1>>2);
+                               else if(eff==0xb) UniPTEffect(8,ev.dat1*0xf);
+                               else UniPTEffect(eff,ev.dat1);
+
+                               UniNewline();
+                               done++;
+                       }
+               }
+/*              printf("----------------"); */
+
+               if(!(of.tracks[t]=UniDup())) return 0;
+       }
+
+/*      printf("%d channels %d patterns\n",of.numchn,of.numpat); */
+/*      printf("Song %32.32s: There's %d samples\n",mh.songtitle,nos); */
+       return 1;
+}
+
+
+
+LOADER load_ult={
+       NULL,
+       "ULT",
+       "Portable ULT loader v0.1",
+       ULT_Init,
+       ULT_Test,
+       ULT_Load,
+       ULT_Cleanup
+};
diff --git a/libs/oldmik/src/load_uni.c b/libs/oldmik/src/load_uni.c
new file mode 100644 (file)
index 0000000..27b7407
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+
+Name:
+LOAD_UNI.C
+
+Description:
+UNIMOD (mikmod's internal format) module loader.
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mikmod.h"
+
+
+BOOL UNI_Test(void)
+{
+       char id[4];
+       if(!fread(id,4,1,modfp)) return 0;
+       if(!memcmp(id,"UN05",4)) return 1;
+       return 0;
+}
+
+
+BOOL UNI_Init(void)
+{
+       return 1;
+}
+
+
+void UNI_Cleanup(void)
+{
+       ;
+}
+
+
+char *StrRead(void)
+{
+       char *s;
+       UWORD len;
+
+       len=_mm_read_I_UWORD(modfp);
+       if(!len) return NULL;
+
+       s=(char *)malloc(len+1);
+       fread(s,len,1,modfp);
+       s[len]=0;
+
+       return s;
+}
+
+
+UBYTE *TrkRead(void)
+{
+       UBYTE *t;
+       UWORD len;
+
+       len=_mm_read_I_UWORD(modfp);
+       t=(UBYTE *)malloc(len);
+       fread(t,len,1,modfp);
+       return t;
+}
+
+
+
+BOOL UNI_Load(void)
+{
+       int t,u;
+
+       _mm_fseek(modfp,4,SEEK_SET);
+
+       /* try to read module header */
+
+       of.numchn       =_mm_read_UBYTE(modfp);
+       of.numpos       =_mm_read_I_UWORD(modfp);
+       of.reppos       =_mm_read_I_UWORD(modfp);
+       of.numpat       =_mm_read_I_UWORD(modfp);
+       of.numtrk       =_mm_read_I_UWORD(modfp);
+       of.numins       =_mm_read_I_UWORD(modfp);
+       of.initspeed=_mm_read_UBYTE(modfp);
+       of.inittempo=_mm_read_UBYTE(modfp);
+       _mm_read_UBYTES(of.positions,256,modfp);
+       _mm_read_UBYTES(of.panning,32,modfp);
+       of.flags        =_mm_read_UBYTE(modfp);
+
+       if(feof(modfp)){
+               myerr=ERROR_LOADING_HEADER;
+               return 0;
+       }
+
+       of.songname=StrRead();
+       of.modtype=StrRead();
+       of.comment=StrRead();   /* <- new since UN01 */
+
+/*     printf("Song: %s\nModty: %s\n",of.songname,of.modtype);
+*/
+
+       if(!AllocInstruments()) return 0;
+       if(!AllocTracks()) return 0;
+       if(!AllocPatterns()) return 0;
+
+       /* Read sampleinfos */
+
+       for(t=0;t<of.numins;t++){
+
+               INSTRUMENT *i=&of.instruments[t];
+
+               i->numsmp=_mm_read_UBYTE(modfp);
+               _mm_read_UBYTES(i->samplenumber,96,modfp);
+
+               i->volflg=_mm_read_UBYTE(modfp);
+               i->volpts=_mm_read_UBYTE(modfp);
+               i->volsus=_mm_read_UBYTE(modfp);
+               i->volbeg=_mm_read_UBYTE(modfp);
+               i->volend=_mm_read_UBYTE(modfp);
+
+               for(u=0;u<12;u++){
+                       i->volenv[u].pos=_mm_read_I_SWORD(modfp);
+                       i->volenv[u].val=_mm_read_I_SWORD(modfp);
+               }
+
+               i->panflg=_mm_read_UBYTE(modfp);
+               i->panpts=_mm_read_UBYTE(modfp);
+               i->pansus=_mm_read_UBYTE(modfp);
+               i->panbeg=_mm_read_UBYTE(modfp);
+               i->panend=_mm_read_UBYTE(modfp);
+
+               for(u=0;u<12;u++){
+                       i->panenv[u].pos=_mm_read_I_SWORD(modfp);
+                       i->panenv[u].val=_mm_read_I_SWORD(modfp);
+               }
+
+               i->vibtype      =_mm_read_UBYTE(modfp);
+               i->vibsweep     =_mm_read_UBYTE(modfp);
+               i->vibdepth     =_mm_read_UBYTE(modfp);
+               i->vibrate      =_mm_read_UBYTE(modfp);
+
+               i->volfade      =_mm_read_I_UWORD(modfp);
+               i->insname      =StrRead();
+
+/*             printf("Ins: %s\n",i->insname);
+*/
+               if(!AllocSamples(i)) return 0;
+
+               for(u=0;u<i->numsmp;u++){
+
+                       SAMPLE *s=&i->samples[u];
+
+                       s->c2spd        = _mm_read_I_UWORD(modfp);
+                       s->transpose= _mm_read_SBYTE(modfp);
+                       s->volume       = _mm_read_UBYTE(modfp);
+                       s->panning      = _mm_read_UBYTE(modfp);
+                       s->length       = _mm_read_I_ULONG(modfp);
+                       s->loopstart= _mm_read_I_ULONG(modfp);
+                       s->loopend      = _mm_read_I_ULONG(modfp);
+                       s->flags        = _mm_read_I_UWORD(modfp);
+                       s->seekpos      = 0;
+
+                       s->samplename=StrRead();
+               }
+       }
+
+       /* Read patterns */
+
+       _mm_read_I_UWORDS(of.pattrows,of.numpat,modfp);
+       _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modfp);
+
+       /* Read tracks */
+
+       for(t=0;t<of.numtrk;t++){
+               of.tracks[t]=TrkRead();
+       }
+
+       return 1;
+}
+
+
+LOADER load_uni={
+       NULL,
+       "UNI",
+       "Portable UNI loader v0.3",
+       UNI_Init,
+       UNI_Test,
+       UNI_Load,
+       UNI_Cleanup
+};
+
diff --git a/libs/oldmik/src/load_xm.c b/libs/oldmik/src/load_xm.c
new file mode 100644 (file)
index 0000000..a593b42
--- /dev/null
@@ -0,0 +1,603 @@
+/*\r
+\r
+Name:\r
+LOAD_XM.C\r
+\r
+Description:\r
+Fasttracker (XM) module loader\r
+\r
+Portability:\r
+All systems - all compilers (hopefully)\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <malloc.h>\r
+#include "mikmod.h"\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+typedef struct XMHEADER{\r
+       char  id[17];                   /* ID text: 'Extended module: ' */\r
+       char  songname[21];             /* Module name, padded with zeroes and 0x1a at the end */\r
+       char  trackername[20];  /* Tracker name */\r
+       UWORD version;                  /* (word) Version number, hi-byte major and low-byte minor */\r
+       ULONG headersize;               /* Header size */\r
+       UWORD songlength;               /* (word) Song length (in patten order table) */\r
+       UWORD restart;                  /* (word) Restart position */\r
+       UWORD numchn;                   /* (word) Number of channels (2,4,6,8,10,...,32) */\r
+       UWORD numpat;                   /* (word) Number of patterns (max 256) */\r
+       UWORD numins;                   /* (word) Number of instruments (max 128) */\r
+       UWORD flags;                    /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */\r
+       UWORD tempo;                    /* (word) Default tempo */\r
+       UWORD bpm;                              /* (word) Default BPM */\r
+       UBYTE orders[256];              /* (byte) Pattern order table */\r
+} XMHEADER;\r
+\r
+\r
+typedef struct XMINSTHEADER{\r
+       ULONG size;                             /* (dword) Instrument size */\r
+       char  name[22];                 /* (char) Instrument name */\r
+       UBYTE type;                             /* (byte) Instrument type (always 0) */\r
+       UWORD numsmp;                   /* (word) Number of samples in instrument */\r
+       ULONG ssize;                    /* */\r
+} XMINSTHEADER;\r
+\r
+\r
+typedef struct XMPATCHHEADER{\r
+       UBYTE what[96];         /* (byte) Sample number for all notes */\r
+       UBYTE volenv[48];       /* (byte) Points for volume envelope */\r
+       UBYTE panenv[48];       /* (byte) Points for panning envelope */\r
+       UBYTE volpts;           /* (byte) Number of volume points */\r
+       UBYTE panpts;           /* (byte) Number of panning points */\r
+       UBYTE volsus;           /* (byte) Volume sustain point */\r
+       UBYTE volbeg;           /* (byte) Volume loop start point */\r
+       UBYTE volend;           /* (byte) Volume loop end point */\r
+       UBYTE pansus;           /* (byte) Panning sustain point */\r
+       UBYTE panbeg;           /* (byte) Panning loop start point */\r
+       UBYTE panend;           /* (byte) Panning loop end point */\r
+       UBYTE volflg;           /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE panflg;           /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */\r
+       UBYTE vibflg;           /* (byte) Vibrato type */\r
+       UBYTE vibsweep;         /* (byte) Vibrato sweep */\r
+       UBYTE vibdepth;         /* (byte) Vibrato depth */\r
+       UBYTE vibrate;          /* (byte) Vibrato rate */\r
+       UWORD volfade;          /* (word) Volume fadeout */\r
+       UWORD reserved[11];     /* (word) Reserved */\r
+} XMPATCHHEADER;\r
+\r
+\r
+typedef struct XMWAVHEADER{\r
+       ULONG length;           /* (dword) Sample length */\r
+       ULONG loopstart;        /* (dword) Sample loop start */\r
+       ULONG looplength;       /* (dword) Sample loop length */\r
+       UBYTE volume;           /* (byte) Volume */\r
+       SBYTE finetune;          /* (byte) Finetune (signed byte -128..+127) */\r
+       UBYTE type;                     /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */\r
+/*                                        2 = Ping-pong loop; */\r
+/*                                        4: 16-bit sampledata */\r
+       UBYTE panning;          /* (byte) Panning (0-255) */\r
+       SBYTE  relnote;          /* (byte) Relative note number (signed byte) */\r
+       UBYTE reserved;         /* (byte) Reserved */\r
+       char  samplename[22];   /* (char) Sample name */\r
+} XMWAVHEADER;\r
+\r
+\r
+typedef struct XMPATHEADER{\r
+       ULONG size;                             /* (dword) Pattern header length */\r
+       UBYTE packing;                  /* (byte) Packing type (always 0) */\r
+       UWORD numrows;                  /* (word) Number of rows in pattern (1..256) */\r
+       UWORD packsize;                 /* (word) Packed patterndata size */\r
+} XMPATHEADER;\r
+\r
+typedef struct MTMNOTE{\r
+       UBYTE a,b,c;\r
+} MTMNOTE;\r
+\r
+\r
+typedef struct XMNOTE{\r
+       UBYTE note,ins,vol,eff,dat;\r
+}XMNOTE;\r
+\r
+XMNOTE *xmpat;\r
+\r
+/**************************************************************************\r
+**************************************************************************/\r
+\r
+\r
+\r
+static XMHEADER *mh;\r
+\r
+char XM_Version[]="XM";\r
+\r
+\r
+\r
+BOOL XM_Test(void)\r
+{\r
+       char id[17];\r
+       if(!fread(id,17,1,modfp)) return 0;\r
+       if(!memcmp(id,"Extended Module: ",17)) return 1;\r
+       return 0;\r
+}\r
+\r
+\r
+BOOL XM_Init(void)\r
+{\r
+       mh=NULL;\r
+       if(!(mh=(XMHEADER *)MyCalloc(1,sizeof(XMHEADER)))) return 0;\r
+       return 1;\r
+}\r
+\r
+\r
+void XM_Cleanup(void)\r
+{\r
+       if(mh!=NULL) free(mh);\r
+}\r
+\r
+\r
+void XM_ReadNote(XMNOTE *n)\r
+{\r
+       UBYTE cmp;\r
+       memset(n,0,sizeof(XMNOTE));\r
+\r
+       cmp=fgetc(modfp);\r
+\r
+       if(cmp&0x80){\r
+               if(cmp&1) n->note=fgetc(modfp);\r
+               if(cmp&2) n->ins=fgetc(modfp);\r
+               if(cmp&4) n->vol=fgetc(modfp);\r
+               if(cmp&8) n->eff=fgetc(modfp);\r
+               if(cmp&16) n->dat=fgetc(modfp);\r
+       }\r
+       else{\r
+               n->note=cmp;\r
+               n->ins=fgetc(modfp);\r
+               n->vol=fgetc(modfp);\r
+               n->eff=fgetc(modfp);\r
+               n->dat=fgetc(modfp);\r
+       }\r
+}\r
+\r
+\r
+UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows)\r
+{\r
+       int t;\r
+       UBYTE note,ins,vol,eff,dat;\r
+\r
+       UniReset();\r
+\r
+       for(t=0;t<rows;t++){\r
+\r
+               note=xmtrack->note;\r
+               ins=xmtrack->ins;\r
+               vol=xmtrack->vol;\r
+               eff=xmtrack->eff;\r
+               dat=xmtrack->dat;\r
+\r
+                if(note!=0) UniNote(note-1);\r
+\r
+                if(ins!=0) UniInstrument(ins-1);\r
+\r
+/*              printf("Vol:%d\n",vol); */\r
+\r
+               switch(vol>>4){\r
+\r
+                       case 0x6:                                       /* volslide down */\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(vol&0xf);\r
+                               }\r
+                               break;\r
+\r
+                       case 0x7:                                       /* volslide up */\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(vol<<4);\r
+                               }\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
+                       */\r
+\r
+                       case 0x8:                                               /* finevol down */\r
+                               UniPTEffect(0xe,0xb0 | (vol&0xf));\r
+                               break;\r
+\r
+                       case 0x9:                       /* finevol up */\r
+                               UniPTEffect(0xe,0xa0 | (vol&0xf));\r
+                               break;\r
+\r
+                       case 0xa:                       /* set vibrato speed */\r
+                               UniPTEffect(0x4,vol<<4);\r
+                               break;\r
+\r
+                       case 0xb:                       /* vibrato */\r
+                               UniPTEffect(0x4,vol&0xf);\r
+                               break;\r
+\r
+                       case 0xc:                       /* set panning */\r
+                               UniPTEffect(0x8,vol<<4);\r
+                               break;\r
+\r
+                       case 0xd:                       /* panning slide left */\r
+                               /* only slide when data nibble not zero: */\r
+\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTP);\r
+                                       UniWrite(vol&0xf);\r
+                               }\r
+                               break;\r
+\r
+                       case 0xe:                       /* panning slide right */\r
+                               /* only slide when data nibble not zero: */\r
+\r
+                               if(vol&0xf){\r
+                                       UniWrite(UNI_XMEFFECTP);\r
+                                       UniWrite(vol<<4);\r
+                               }\r
+                               break;\r
+\r
+                       case 0xf:                       /* tone porta */\r
+                               UniPTEffect(0x3,vol<<4);\r
+                               break;\r
+\r
+                       default:\r
+                               if(vol>=0x10 && vol<=0x50){\r
+                                       UniPTEffect(0xc,vol-0x10);\r
+                               }\r
+               }\r
+\r
+/*              if(eff>0xf) printf("Effect %d",eff); */\r
+\r
+               switch(eff){\r
+\r
+                       case 'G'-55:                    /* G - set global volume */\r
+                               if(dat>64) dat=64;\r
+                               UniWrite(UNI_XMEFFECTG);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'H'-55:                    /* H - global volume slide */\r
+                               UniWrite(UNI_XMEFFECTH);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'K'-55:                    /* K - keyoff */\r
+                               UniNote(96);\r
+                               break;\r
+\r
+                       case 'L'-55:                    /* L - set envelope position */\r
+                               break;\r
+\r
+                       case 'P'-55:                    /* P - panning slide */\r
+                               UniWrite(UNI_XMEFFECTP);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'R'-55:                    /* R - multi retrig note */\r
+                               UniWrite(UNI_S3MEFFECTQ);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'T'-55:                            /* T - Tremor !! (== S3M effect I) */\r
+                               UniWrite(UNI_S3MEFFECTI);\r
+                               UniWrite(dat);\r
+                               break;\r
+\r
+                       case 'X'-55:\r
+                               if((dat>>4)==1){                /* X1 extra fine porta up */\r
+\r
+\r
+                               }\r
+                               else{                                   /* X2 extra fine porta down */\r
+\r
+                               }\r
+                               break;\r
+\r
+                       default:\r
+                               if(eff==0xa){\r
+                                       UniWrite(UNI_XMEFFECTA);\r
+                                       UniWrite(dat);\r
+                               }\r
+                               else if(eff<=0xf) UniPTEffect(eff,dat);\r
+                               break;\r
+               }\r
+\r
+               UniNewline();\r
+               xmtrack++;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+\r
+\r
+BOOL XM_Load(void)\r
+{\r
+       INSTRUMENT *d;\r
+       SAMPLE *q;\r
+       int t,u,v,p,numtrk;\r
+       long next;\r
+\r
+       /* try to read module header */\r
+\r
+       _mm_read_str(mh->id,17,modfp);\r
+       _mm_read_str(mh->songname,21,modfp);\r
+       _mm_read_str(mh->trackername,20,modfp);\r
+       mh->version             =_mm_read_I_UWORD(modfp);\r
+       mh->headersize  =_mm_read_I_ULONG(modfp);\r
+       mh->songlength  =_mm_read_I_UWORD(modfp);\r
+       mh->restart             =_mm_read_I_UWORD(modfp);\r
+       mh->numchn              =_mm_read_I_UWORD(modfp);\r
+       mh->numpat              =_mm_read_I_UWORD(modfp);\r
+       mh->numins              =_mm_read_I_UWORD(modfp);\r
+       mh->flags               =_mm_read_I_UWORD(modfp);\r
+       mh->tempo               =_mm_read_I_UWORD(modfp);\r
+       mh->bpm                 =_mm_read_I_UWORD(modfp);\r
+       _mm_read_UBYTES(mh->orders,256,modfp);\r
+\r
+       if(feof(modfp)){\r
+               myerr = ERROR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* set module variables */\r
+\r
+       of.initspeed=mh->tempo;\r
+       of.inittempo=mh->bpm;\r
+       of.modtype=DupStr(mh->trackername,20);\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);    /* make a cstr of songname */\r
+       of.numpos=mh->songlength;                       /* copy the songlength */\r
+       of.reppos=mh->restart;\r
+       of.numins=mh->numins;\r
+       of.flags|=UF_XMPERIODS;\r
+       if(mh->flags&1) of.flags|=UF_LINEAR;\r
+\r
+       memcpy(of.positions,mh->orders,256);\r
+\r
+/*\r
+        WHY THIS CODE HERE?? I CAN'T REMEMBER!\r
+\r
+        of.numpat=0;\r
+       for(t=0;t<of.numpos;t++){\r
+               if(of.positions[t]>of.numpat) of.numpat=of.positions[t];\r
+       }\r
+       of.numpat++;\r
+*/\r
+\r
+/*     printf("Modtype :%s\n",of.modtype);\r
+       printf("Version :%x\n",mh->version);\r
+       printf("Song    :%s\n",of.songname);\r
+       printf("Speed   :%d,%d\n",of.initspeed,of.inittempo);\r
+       printf("Channels:%d\n",of.numchn);\r
+       printf("Numins  :%d\n",mh->numins);\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
+/*             printf("Reading pattern %d\n",t); */\r
+\r
+               ph.size         =_mm_read_I_ULONG(modfp);\r
+               ph.packing      =_mm_read_UBYTE(modfp);\r
+               ph.numrows      =_mm_read_I_UWORD(modfp);\r
+               ph.packsize     =_mm_read_I_UWORD(modfp);\r
+\r
+/*             printf("headln:  %ld\n",ph.size); */\r
+/*             printf("numrows: %d\n",ph.numrows); */\r
+/*             printf("packsize:%d\n",ph.packsize); */\r
+\r
+                of.pattrows[t]=ph.numrows;\r
+\r
+               /*\r
+                       Gr8.. when packsize is 0, don't try to load a pattern.. it's empty.\r
+                       This bug was discovered thanks to Khyron's module..\r
+               */\r
+\r
+               if(!(xmpat=(XMNOTE *)MyCalloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0;\r
+\r
+               if(ph.packsize>0){\r
+                       for(u=0;u<ph.numrows;u++){\r
+                               for(v=0;v<of.numchn;v++){\r
+                                       XM_ReadNote(&xmpat[(v*ph.numrows)+u]);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               for(v=0;v<of.numchn;v++){\r
+                       of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);\r
+               }\r
+\r
+               free(xmpat);\r
+       }\r
+\r
+       if(!AllocInstruments()) return 0;\r
+\r
+       d=of.instruments;\r
+\r
+       for(t=0;t<of.numins;t++){\r
+               XMINSTHEADER ih;\r
+\r
+               /* read instrument header */\r
+\r
+               ih.size         =_mm_read_I_ULONG(modfp);\r
+               _mm_read_str (ih.name, 22, modfp);\r
+               ih.type         =_mm_read_UBYTE(modfp);\r
+               ih.numsmp       =_mm_read_I_UWORD(modfp);\r
+               ih.ssize        =_mm_read_I_ULONG(modfp);\r
+\r
+/*      printf("Size: %ld\n",ih.size);\r
+               printf("Name:   %22.22s\n",ih.name);\r
+               printf("Samples:%d\n",ih.numsmp);\r
+               printf("sampleheadersize:%ld\n",ih.ssize);\r
+*/\r
+               d->insname=DupStr(ih.name,22);\r
+               d->numsmp=ih.numsmp;\r
+\r
+               if(!AllocSamples(d)) return 0;\r
+\r
+               if(ih.numsmp>0){\r
+                       XMPATCHHEADER pth;\r
+                       XMWAVHEADER wh;\r
+\r
+                       _mm_read_UBYTES (pth.what, 96, modfp);\r
+                       _mm_read_UBYTES (pth.volenv, 48, modfp);\r
+                       _mm_read_UBYTES (pth.panenv, 48, modfp);\r
+                       pth.volpts              =_mm_read_UBYTE(modfp);\r
+                       pth.panpts              =_mm_read_UBYTE(modfp);\r
+                       pth.volsus              =_mm_read_UBYTE(modfp);\r
+                       pth.volbeg              =_mm_read_UBYTE(modfp);\r
+                       pth.volend              =_mm_read_UBYTE(modfp);\r
+                       pth.pansus              =_mm_read_UBYTE(modfp);\r
+                       pth.panbeg              =_mm_read_UBYTE(modfp);\r
+                       pth.panend              =_mm_read_UBYTE(modfp);\r
+                       pth.volflg              =_mm_read_UBYTE(modfp);\r
+                       pth.panflg              =_mm_read_UBYTE(modfp);\r
+                       pth.vibflg              =_mm_read_UBYTE(modfp);\r
+                       pth.vibsweep    =_mm_read_UBYTE(modfp);\r
+                       pth.vibdepth    =_mm_read_UBYTE(modfp);\r
+                       pth.vibrate             =_mm_read_UBYTE(modfp);\r
+                       pth.volfade             =_mm_read_I_UWORD(modfp);\r
+                       _mm_read_I_UWORDS(pth.reserved, 11, modfp);\r
+\r
+                       memcpy(d->samplenumber,pth.what,96);\r
+\r
+                       d->volfade=pth.volfade;\r
+\r
+/*                     printf("Volfade %x\n",d->volfade); */\r
+\r
+                       memcpy(d->volenv,pth.volenv,24);\r
+                       d->volflg=pth.volflg;\r
+                       d->volsus=pth.volsus;\r
+                       d->volbeg=pth.volbeg;\r
+                       d->volend=pth.volend;\r
+                       d->volpts=pth.volpts;\r
+\r
+/*                     printf("volume points   : %d\n"\r
+                                  "volflg                      : %d\n"\r
+                                  "volbeg                      : %d\n"\r
+                                  "volend                      : %d\n"\r
+                                  "volsus                      : %d\n",\r
+                                  d->volpts,\r
+                                  d->volflg,\r
+                                  d->volbeg,\r
+                                  d->volend,\r
+                                  d->volsus);\r
+*/\r
+                       /* scale volume envelope: */\r
+\r
+                       for(p=0;p<12;p++){\r
+                               d->volenv[p].val<<=2;\r
+/*                             printf("%d,%d,",d->volenv[p].pos,d->volenv[p].val); */\r
+                       }\r
+\r
+                       memcpy(d->panenv,pth.panenv,24);\r
+                       d->panflg=pth.panflg;\r
+                       d->pansus=pth.pansus;\r
+                       d->panbeg=pth.panbeg;\r
+                       d->panend=pth.panend;\r
+                       d->panpts=pth.panpts;\r
+\r
+/*                                       printf("Panning points        : %d\n"\r
+                                  "panflg                      : %d\n"\r
+                                  "panbeg                      : %d\n"\r
+                                  "panend                      : %d\n"\r
+                                  "pansus                      : %d\n",\r
+                                  d->panpts,\r
+                                  d->panflg,\r
+                                  d->panbeg,\r
+                                  d->panend,\r
+                                  d->pansus);\r
+*/\r
+                       /* scale panning envelope: */\r
+\r
+                       for(p=0;p<12;p++){\r
+                               d->panenv[p].val<<=2;\r
+/*                             printf("%d,%d,",d->panenv[p].pos,d->panenv[p].val); */\r
+                       }\r
+\r
+/*                      for(u=0;u<256;u++){ */\r
+/*                              printf("%2.2x ",fgetc(modfp)); */\r
+/*                      } */\r
+\r
+                       next=0;\r
+\r
+                       for(u=0;u<ih.numsmp;u++){\r
+                               q=&d->samples[u];\r
+\r
+                               wh.length               =_mm_read_I_ULONG (modfp);\r
+                               wh.loopstart    =_mm_read_I_ULONG (modfp);\r
+                               wh.looplength   =_mm_read_I_ULONG (modfp);\r
+                               wh.volume               =_mm_read_UBYTE (modfp);\r
+                               wh.finetune             =_mm_read_SBYTE (modfp);\r
+                               wh.type                 =_mm_read_UBYTE (modfp);\r
+                               wh.panning              =_mm_read_UBYTE (modfp);\r
+                               wh.relnote              =_mm_read_SBYTE (modfp);\r
+                               wh.reserved             =_mm_read_UBYTE (modfp);\r
+                               _mm_read_str(wh.samplename, 22, modfp);\r
+\r
+/*              printf("wav %d:%22.22s\n",u,wh.samplename); */\r
+\r
+                               q->samplename   =DupStr(wh.samplename,22);\r
+                               q->length       =wh.length;\r
+                               q->loopstart    =wh.loopstart;\r
+                               q->loopend      =wh.loopstart+wh.looplength;\r
+                               q->volume       =wh.volume;\r
+                               q->c2spd                =wh.finetune+128;\r
+                               q->transpose    =wh.relnote;\r
+                               q->panning      =wh.panning;\r
+                               q->seekpos              =next;\r
+\r
+                               if(wh.type&0x10){\r
+                                       q->length>>=1;\r
+                                       q->loopstart>>=1;\r
+                                       q->loopend>>=1;\r
+                               }\r
+\r
+                               next+=wh.length;\r
+\r
+/*                              printf("Type %u\n",wh.type); */\r
+/*                             printf("Trans %d\n",wh.relnote); */\r
+\r
+                               q->flags|=SF_OWNPAN;\r
+                               if(wh.type&0x3) q->flags|=SF_LOOP;\r
+                               if(wh.type&0x2) q->flags|=SF_BIDI;\r
+\r
+                               if(wh.type&0x10) q->flags|=SF_16BITS;\r
+                               q->flags|=SF_DELTA;\r
+                               q->flags|=SF_SIGNED;\r
+                       }\r
+\r
+                       for(u=0;u<ih.numsmp;u++) d->samples[u].seekpos+=_mm_ftell(modfp);\r
+\r
+                       _mm_fseek(modfp,next,SEEK_CUR);\r
+               }\r
+\r
+               d++;\r
+       }\r
+\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+LOADER load_xm={\r
+       NULL,\r
+       "XM",\r
+       "Portable XM loader v0.4 - for your ears only / MikMak",\r
+       XM_Init,\r
+       XM_Test,\r
+       XM_Load,\r
+       XM_Cleanup\r
+};\r
diff --git a/libs/oldmik/src/mdma.c b/libs/oldmik/src/mdma.c
new file mode 100644 (file)
index 0000000..aac6cc9
--- /dev/null
@@ -0,0 +1,515 @@
+/*\r
+\r
+Name:\r
+MDMA.C\r
+\r
+Description:\r
+DMA routines\r
+\r
+Portability:\r
+\r
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)\r
+Win95: n\r
+Os2:   n\r
+Linux: n\r
+\r
+(y) - yes\r
+(n) - no (not possible or not useful)\r
+(?) - may be possible, but not tested\r
+\r
+*/\r
+#include <dos.h>\r
+#include <malloc.h>\r
+#include <conio.h>\r
+#include "mdma.h"\r
+\r
+\r
+/* DMA Controler #1 (8-bit controller) */\r
+#define DMA1_STAT       0x08            /* read status register */\r
+#define DMA1_WCMD       0x08            /* write command register */\r
+#define DMA1_WREQ       0x09            /* write request register */\r
+#define DMA1_SNGL       0x0A            /* write single bit register */\r
+#define DMA1_MODE       0x0B            /* write mode register */\r
+#define DMA1_CLRFF      0x0C            /* clear byte ptr flip/flop */\r
+#define DMA1_MCLR       0x0D            /* master clear register */\r
+#define DMA1_CLRM       0x0E            /* clear mask register */\r
+#define DMA1_WRTALL     0x0F            /* write all mask register */\r
+\r
+/* DMA Controler #2 (16-bit controller) */\r
+#define DMA2_STAT       0xD0            /* read status register */\r
+#define DMA2_WCMD       0xD0            /* write command register */\r
+#define DMA2_WREQ       0xD2            /* write request register */\r
+#define DMA2_SNGL       0xD4            /* write single bit register */\r
+#define DMA2_MODE       0xD6            /* write mode register */\r
+#define DMA2_CLRFF      0xD8            /* clear byte ptr flip/flop */\r
+#define DMA2_MCLR       0xDA            /* master clear register */\r
+#define DMA2_CLRM       0xDC            /* clear mask register */\r
+#define DMA2_WRTALL     0xDE            /* write all mask register */\r
+\r
+#define DMA0_ADDR       0x00            /* chan 0 base adddress */\r
+#define DMA0_CNT        0x01            /* chan 0 base count */\r
+#define DMA1_ADDR       0x02            /* chan 1 base adddress */\r
+#define DMA1_CNT        0x03            /* chan 1 base count */\r
+#define DMA2_ADDR       0x04            /* chan 2 base adddress */\r
+#define DMA2_CNT        0x05            /* chan 2 base count */\r
+#define DMA3_ADDR       0x06            /* chan 3 base adddress */\r
+#define DMA3_CNT        0x07            /* chan 3 base count */\r
+#define DMA4_ADDR       0xC0            /* chan 4 base adddress */\r
+#define DMA4_CNT        0xC2            /* chan 4 base count */\r
+#define DMA5_ADDR       0xC4            /* chan 5 base adddress */\r
+#define DMA5_CNT        0xC6            /* chan 5 base count */\r
+#define DMA6_ADDR       0xC8            /* chan 6 base adddress */\r
+#define DMA6_CNT        0xCA            /* chan 6 base count */\r
+#define DMA7_ADDR       0xCC            /* chan 7 base adddress */\r
+#define DMA7_CNT        0xCE            /* chan 7 base count */\r
+\r
+#define DMA0_PAGE       0x87            /* chan 0 page register (refresh)*/\r
+#define DMA1_PAGE       0x83            /* chan 1 page register */\r
+#define DMA2_PAGE       0x81            /* chan 2 page register */\r
+#define DMA3_PAGE       0x82            /* chan 3 page register */\r
+#define DMA4_PAGE       0x8F            /* chan 4 page register (unuseable)*/\r
+#define DMA5_PAGE       0x8B            /* chan 5 page register */\r
+#define DMA6_PAGE       0x89            /* chan 6 page register */\r
+#define DMA7_PAGE       0x8A            /* chan 7 page register */\r
+\r
+#define MAX_DMA         8\r
+\r
+#define DMA_DECREMENT   0x20    /* mask to make DMA hardware go backwards */\r
+\r
+typedef struct {\r
+       UBYTE dma_disable;      /* bits to disable dma channel */\r
+       UBYTE dma_enable;       /* bits to enable dma channel */\r
+       UWORD page;                     /* page port location */\r
+       UWORD addr;                     /* addr port location */\r
+       UWORD count;            /* count port location */\r
+       UWORD single;           /* single mode port location */\r
+       UWORD mode;                     /* mode port location */\r
+       UWORD clear_ff;         /* clear flip-flop port location */\r
+       UBYTE write;            /* bits for write transfer */\r
+       UBYTE read;                     /* bits for read transfer */\r
+} DMA_ENTRY;\r
+\r
+/* Variables needed ... */\r
+\r
+static DMA_ENTRY mydma[MAX_DMA] = {\r
+\r
+/* DMA channel 0 */\r
+                       {0x04,0x00,DMA0_PAGE,DMA0_ADDR,DMA0_CNT,\r
+                        DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x48,0x44},\r
+\r
+/* DMA channel 1 */\r
+                       {0x05,0x01,DMA1_PAGE,DMA1_ADDR,DMA1_CNT,\r
+                        DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45},\r
+\r
+/* DMA channel 2 */\r
+                       {0x06,0x02,DMA2_PAGE,DMA2_ADDR,DMA2_CNT,\r
+                        DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4A,0x46},\r
+\r
+/* DMA channel 3 */\r
+                       {0x07,0x03,DMA3_PAGE,DMA3_ADDR,DMA3_CNT,\r
+                        DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4B,0x47},\r
+\r
+/* DMA channel 4 */\r
+                       {0x04,0x00,DMA4_PAGE,DMA4_ADDR,DMA4_CNT,\r
+                        DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x48,0x44},\r
+\r
+/* DMA channel 5 */\r
+                       {0x05,0x01,DMA5_PAGE,DMA5_ADDR,DMA5_CNT,\r
+                        DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x49,0x45},\r
+\r
+/* DMA channel 6 */\r
+                       {0x06,0x02,DMA6_PAGE,DMA6_ADDR,DMA6_CNT,\r
+                        DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4A,0x46},\r
+\r
+/* DMA channel 7 */\r
+                       {0x07,0x03,DMA7_PAGE,DMA7_ADDR,DMA7_CNT,\r
+                        DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4B,0x47},\r
+};\r
+\r
+\r
+/*\r
+\r
+Each specialised DMA code part should provide the following things:\r
+\r
+In MDMA.H:\r
+\r
+  -    a DMAMEM typedef, which should contain all the data that the\r
+       routines need for maintaining/allocating/freeing dma memory.\r
+\r
+\r
+In MDMA.C:\r
+\r
+  -    2 macros ENTER_CRITICAL and LEAVE_CRITICAL\r
+\r
+  - A function 'static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)'\r
+       which should perform the actual dma-memory allocation. It should\r
+       use DMAMEM *dm to store all it's information.\r
+\r
+  - A function 'static void MDma_FreeMem0(DMAMEM *dm)' to free the memory\r
+\r
+  - A function 'static ULONG MDma_GetLinearPtr(DMAMEM *dm)' which should\r
+       return the linear 20 bits pointer to the actual dmabuffer.. this\r
+       function is     used by MDma_Start\r
+\r
+  - A function 'void *MDma_GetPtr(DMAMEM *dm)' which should return a pointer\r
+       to the dmabuffer. If the dma memory can't be accessed directly it should\r
+       return a pointer to a FAKE dma buffer (DJGPP!!)\r
+\r
+  - A function 'void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)'. This\r
+       function will be called each time a routine wrote something to the\r
+       dmabuffer (returned by MDma_GetPtr()). In the case of a FAKE dmabuffer\r
+       this routine should take care of copying the data from the fake buffer to\r
+       the real dma memory ('count' bytes from byteoffset 'index').\r
+\r
+*/\r
+\r
+\r
+\r
+#ifdef __WATCOMC__\r
+\r
+/****************************************************************************\r
+********************* Watcom C specialised DMA code: ************************\r
+****************************************************************************/\r
+\r
+#define ENTER_CRITICAL IRQ_PUSH_OFF()\r
+extern void IRQ_PUSH_OFF (void);\r
+#pragma aux IRQ_PUSH_OFF =      \\r
+       "pushfd",                   \\r
+               "cli"           \\r
+                modify [esp];\r
+\r
+#define LEAVE_CRITICAL IRQ_POP()\r
+extern void IRQ_POP (void);\r
+#pragma aux IRQ_POP =   \\r
+               "popfd"         \\r
+                modify [esp];\r
+\r
+\r
+static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)\r
+/*\r
+       Allocates a dma buffer of 'size' bytes.\r
+       returns FALSE if failed.\r
+*/\r
+{\r
+       static union REGS r;\r
+       ULONG p;\r
+\r
+       /* allocate TWICE the size of the requested dma buffer..\r
+       this fixes the 'page-crossing' bug of previous versions */\r
+\r
+       r.x.eax = 0x0100;           /* DPMI allocate DOS memory */\r
+       r.x.ebx = ((size*2) + 15) >> 4; /* Number of paragraphs requested */\r
+\r
+       int386 (0x31, &r, &r);\r
+\r
+       if( r.x.cflag ) return 0;       /* failed */\r
+\r
+       dm->raw_selector=r.x.edx;\r
+\r
+       /* convert the segment into a linear address */\r
+\r
+       p=(r.x.eax&0xffff)<<4;\r
+\r
+       /* if the first half of the allocated memory crosses a page\r
+       boundary, return the second half which is then guaranteed to\r
+       be page-continuous */\r
+\r
+       if( (p>>16) != ((p+size-1)>>16) ) p+=size;\r
+\r
+               dm->continuous=(void *)p;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+static void MDma_FreeMem0(DMAMEM *dm)\r
+{\r
+       static union REGS r;\r
+       r.x.eax = 0x0101;               /* DPMI free DOS memory */\r
+       r.x.edx = dm->raw_selector;     /* base selector */\r
+       int386 (0x31, &r, &r);\r
+}\r
+\r
+\r
+static ULONG MDma_GetLinearPtr(DMAMEM *dm)\r
+{\r
+       return (ULONG)dm->continuous;\r
+}\r
+\r
+\r
+void *MDma_GetPtr(DMAMEM *dm)\r
+{\r
+       return(dm->continuous);\r
+}\r
+\r
+\r
+void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)\r
+{\r
+       /* This function doesnt do anything here (WATCOM C\r
+          can access dma memory directly) */\r
+}\r
+\r
+\r
+#elif defined(__DJGPP__)\r
+/****************************************************************************\r
+*********************** DJGPP specialised DMA code: *************************\r
+****************************************************************************/\r
+#define ENTER_CRITICAL __asm__( "pushf \n\t cli" )\r
+#define LEAVE_CRITICAL __asm__( "popf \n\t" )\r
+#include <sys/farptr.h>\r
+\r
+static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)\r
+/*\r
+       Allocates a dma buffer of 'size' bytes - one in the code segment and\r
+               one in the lower 1 Mb physical mem.\r
+       It doesn't check if the dma mem is page-continuous, and can only be\r
+               used to allocate exactly 1 block.\r
+*/\r
+{\r
+       dm->raw.size = (size + 15) >> 4;\r
+       if (_go32_dpmi_allocate_dos_memory(&(dm->raw)))\r
+         return 0;\r
+       dm->continuous = (void *) malloc(size);\r
+               return 1;\r
+}\r
+\r
+\r
+\r
+static void MDma_FreeMem0(DMAMEM *dm)\r
+{\r
+       _go32_dpmi_free_dos_memory(&(dm->raw));\r
+       free(dm->continuous);\r
+}\r
+\r
+static ULONG MDma_GetLinearPtr(DMAMEM *dm)\r
+{\r
+       return (ULONG) dm->raw.rm_segment << 4;\r
+}\r
+\r
+\r
+void *MDma_GetPtr(DMAMEM *dm)\r
+{\r
+       return(dm->continuous);\r
+}\r
+\r
+void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)\r
+{\r
+   char *src = &(((UBYTE*)dm->continuous)[index]);\r
+   ULONG dest = 16 * dm->raw.rm_segment + (ULONG) index;\r
+   _farsetsel(_go32_conventional_mem_selector());\r
+   while(count--) {\r
+         _farnspokeb(dest++, *(src++));\r
+   }\r
+}\r
+\r
+#else\r
+\r
+/****************************************************************************\r
+********************* Borland C specialised DMA code: ***********************\r
+****************************************************************************/\r
+\r
+#define ENTER_CRITICAL asm{ pushf; cli }\r
+#define LEAVE_CRITICAL asm{ popf }\r
+\r
+#define LPTR(ptr) (((ULONG)FP_SEG(ptr)<<4)+FP_OFF(ptr))\r
+#define NPTR(ptr) MK_FP(FP_SEG(p)+(FP_OFF(p)>>4),FP_OFF(p)&15)\r
+\r
+\r
+static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)\r
+/*\r
+       Allocates a dma buffer of 'size' bytes.\r
+       returns FALSE if failed.\r
+*/\r
+{\r
+       char huge *p;\r
+       ULONG s;\r
+\r
+       /* allocate TWICE the size of the requested dma buffer..\r
+       so we can always get a page-contiguous dma buffer */\r
+\r
+       if((dm->raw=malloc((ULONG)size*2))==NULL) return 0;\r
+\r
+       p=(char huge *)dm->raw;\r
+       s=LPTR(p);\r
+\r
+       /* if the first half of the allocated memory crosses a page\r
+       boundary, return the second half which is then guaranteed to\r
+       be page-continuous */\r
+\r
+       if( (s>>16) != ((s+size-1)>>16) ) p+=size;\r
+\r
+       /* put the page-continuous pointer into DMAMEM */\r
+\r
+       dm->continuous=NPTR(p);\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+static void MDma_FreeMem0(DMAMEM *dm)\r
+{\r
+       free(dm->raw);\r
+}\r
+\r
+\r
+static ULONG MDma_GetLinearPtr(DMAMEM *dm)\r
+{\r
+       return LPTR(dm->continuous);\r
+}\r
+\r
+\r
+void *MDma_GetPtr(DMAMEM *dm)\r
+{\r
+       return(dm->continuous);\r
+}\r
+\r
+#pragma argsused\r
+\r
+void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)\r
+{\r
+       /* This function doesnt do anything here (BORLAND C\r
+          can access dma memory directly) */\r
+}\r
+\r
+#endif\r
+\r
+\r
+/****************************************************************************\r
+************************* General DMA code: *********************************\r
+****************************************************************************/\r
+\r
+\r
+DMAMEM *MDma_AllocMem(UWORD size)\r
+{\r
+       DMAMEM *p;\r
+\r
+       /* allocate dma memory structure */\r
+\r
+       if(!(p=(DMAMEM *)malloc(sizeof(DMAMEM)))) return NULL;\r
+\r
+       /* allocate dma memory */\r
+\r
+       if(!MDma_AllocMem0(p,size)){\r
+\r
+               /* didn't succeed? -> free everything & return NULL */\r
+\r
+               free(p);\r
+               return NULL;\r
+       }\r
+\r
+       return p;\r
+}\r
+\r
+\r
+void MDma_FreeMem(DMAMEM *p)\r
+{\r
+       MDma_FreeMem0(p);\r
+       free(p);\r
+}\r
+\r
+\r
+int MDma_Start(int channel,DMAMEM *dm,UWORD size,int type)\r
+{\r
+       DMA_ENTRY *tdma;\r
+       ULONG s_20bit,e_20bit;\r
+       UWORD spage,saddr,tcount;\r
+       UWORD epage,eaddr;\r
+       UBYTE cur_mode;\r
+\r
+       tdma=&mydma[channel];           /* point to this dma data */\r
+\r
+       /* Convert the pc address to a 20 bit physical\r
+          address that the DMA controller needs */\r
+\r
+       s_20bit = MDma_GetLinearPtr(dm);\r
+\r
+       e_20bit = s_20bit + size - 1;\r
+       spage = s_20bit>>16;\r
+       epage = e_20bit>>16;\r
+\r
+       if(spage != epage) return 0;\r
+\r
+       if(channel>=4){\r
+               /* if 16-bit xfer, then addr,count & size are divided by 2 */\r
+               s_20bit = s_20bit >> 1;\r
+               e_20bit = e_20bit >> 1;\r
+               size = size >> 1;\r
+       }\r
+\r
+       saddr=s_20bit&0xffff;\r
+\r
+       tcount = size-1;\r
+\r
+       switch (type){\r
+\r
+               case READ_DMA:\r
+                       cur_mode = tdma->read;\r
+                       break;\r
+\r
+               case WRITE_DMA:\r
+                       cur_mode = tdma->write;\r
+                       break;\r
+\r
+               case INDEF_READ:\r
+                       cur_mode = tdma->read | 0x10;   /* turn on auto init */\r
+                       break;\r
+\r
+               case INDEF_WRITE:\r
+                       cur_mode = tdma->write | 0x10;  /* turn on auto init */\r
+                       break;\r
+       }\r
+\r
+       ENTER_CRITICAL;\r
+       outportb(tdma->single,tdma->dma_disable);               /* disable channel */\r
+       outportb(tdma->mode,cur_mode);                                  /* set mode */\r
+       outportb(tdma->clear_ff,0);                                             /* clear f/f */\r
+       outportb(tdma->addr,saddr&0xff);                                /* LSB */\r
+       outportb(tdma->addr,saddr>>8);                                  /* MSB */\r
+       outportb(tdma->page,spage);                                             /* page # */\r
+       outportb(tdma->clear_ff,0);                                             /* clear f/f */\r
+       outportb(tdma->count,tcount&0x0ff);                             /* LSB count */\r
+       outportb(tdma->count,tcount>>8);                                /* MSB count */\r
+       outportb(tdma->single,tdma->dma_enable);                /* enable */\r
+       LEAVE_CRITICAL;\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+void MDma_Stop(int channel)\r
+{\r
+       DMA_ENTRY *tdma;\r
+       tdma=&mydma[channel];                                           /* point to this dma data */\r
+       outportb(tdma->single,tdma->dma_disable);   /* disable chan */\r
+}\r
+\r
+\r
+UWORD MDma_Todo(int channel)\r
+{\r
+       UWORD creg;\r
+       UWORD val1,val2;\r
+\r
+       DMA_ENTRY *tdma=&mydma[channel];\r
+\r
+       creg=tdma->count;\r
+\r
+       ENTER_CRITICAL;\r
+\r
+       outportb(tdma->clear_ff,0xff);\r
+\r
+       redo:\r
+       val1=inportb(creg);\r
+       val1|=inportb(creg)<<8;\r
+       val2=inportb(creg);\r
+       val2|=inportb(creg)<<8;\r
+\r
+       val1-=val2;\r
+       if((SWORD)val1>64) goto redo;\r
+       if((SWORD)val1<-64) goto redo;\r
+\r
+       LEAVE_CRITICAL;\r
+\r
+       if(channel>3) val2<<=1;\r
+\r
+       return val2;\r
+}\r
diff --git a/libs/oldmik/src/mdma.h b/libs/oldmik/src/mdma.h
new file mode 100644 (file)
index 0000000..893d359
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef MDMA_H
+#define MDMA_H
+
+#include "mtypes.h"
+
+#define READ_DMA                0
+#define WRITE_DMA               1
+#define INDEF_READ              2
+#define INDEF_WRITE             3
+
+#ifdef __WATCOMC__
+
+typedef struct{
+       void *continuous;       /* the pointer to a page-continous dma buffer */
+       UWORD raw_selector;     /* the raw allocated dma selector */
+} DMAMEM;
+
+#elif defined(__DJGPP__)
+
+typedef struct{
+               void *continuous;       /* the pointer to a page-continous dma buffer */
+               _go32_dpmi_seginfo raw; /* points to the memory that was allocated */
+} DMAMEM;
+
+#else
+
+typedef struct{
+       void *continuous;       /* the pointer to a page-continous dma buffer */
+       void *raw;                      /* points to the memory that was allocated */
+} DMAMEM;
+
+#endif
+
+DMAMEM *MDma_AllocMem(UWORD size);
+void    MDma_FreeMem(DMAMEM *dm);
+int     MDma_Start(int channel,DMAMEM *dm,UWORD size,int type);
+void    MDma_Stop(int channel);
+void   *MDma_GetPtr(DMAMEM *dm);
+void    MDma_Commit(DMAMEM *dm,UWORD index,UWORD count);
+UWORD   MDma_Todo(int channel);
+
+#endif
diff --git a/libs/oldmik/src/mdriver.c b/libs/oldmik/src/mdriver.c
new file mode 100644 (file)
index 0000000..d7c5de9
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+
+Name:
+MDRIVER.C
+
+Description:
+These routines are used to access the available soundcard drivers.
+
+Portability:
+All systems - all compilers
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "mikmod.h"
+
+DRIVER *firstdriver=NULL,*md_driver;
+
+UWORD md_device         =0;
+UWORD md_mixfreq        =44100;
+UWORD md_mode           =0;
+UWORD md_dmabufsize     =8192;
+UBYTE md_numchn         =0;
+UBYTE md_bpm            =125;
+
+static void dummyplay(void)
+{
+}
+
+void (*md_player)(void)=dummyplay;
+
+static FILE *sl_fp;
+static SWORD sl_old;
+static UWORD sl_infmt;
+static UWORD sl_outfmt;
+static SWORD sl_buffer[1024];
+
+static BOOL isplaying=0;
+
+
+void SL_Init(FILE *fp,UWORD infmt,UWORD outfmt)
+{
+       sl_old=0;
+       sl_fp=fp;
+       sl_infmt=infmt;
+       sl_outfmt=outfmt;
+}
+
+
+void SL_Exit(void)
+{
+}
+
+
+void SL_Load(void *buffer,ULONG length)
+{
+       SBYTE *bptr=(SBYTE *)buffer;
+       SWORD *wptr=(SWORD *)buffer;
+       UWORD stodo;
+       int t;
+
+       /* compute number of samples to load */
+       if(sl_outfmt & SF_16BITS) length>>=1;
+
+       while(length){
+
+               stodo=(length<1024) ? length : 1024;
+
+               if(sl_infmt&SF_16BITS){
+                       fread(sl_buffer,sizeof(SWORD),stodo,sl_fp);
+#ifdef MM_BIG_ENDIAN
+                       if(!(sl_infmt&SF_BIG_ENDIAN))
+                               swab((char *)sl_buffer,(char *)sl_buffer,stodo<<1);
+#else
+                        /* assume machine is little endian by default */
+                       if(sl_infmt&SF_BIG_ENDIAN)
+                               swab((char *)sl_buffer,(char *)sl_buffer,stodo<<1);
+#endif
+               }
+               else{
+                       SBYTE *s;
+                       SWORD *d;
+
+                       fread(sl_buffer,sizeof(SBYTE),stodo,sl_fp);
+
+                       s=(SBYTE *)sl_buffer;
+                       d=sl_buffer;
+                       s+=stodo;
+                       d+=stodo;
+
+                        for(t=0;t<stodo;t++){
+                               s--;
+                               d--;
+                               *d=(*s)<<8;
+                       }
+               }
+
+               if(sl_infmt & SF_DELTA){
+                       for(t=0;t<stodo;t++){
+                               sl_buffer[t]+=sl_old;
+                               sl_old=sl_buffer[t];
+                       }
+               }
+
+               if((sl_infmt^sl_outfmt) & SF_SIGNED){
+                       for(t=0;t<stodo;t++){
+                               sl_buffer[t]^=0x8000;
+                       }
+               }
+
+               if(sl_outfmt & SF_16BITS){
+                       for(t=0;t<stodo;t++) *(wptr++)=sl_buffer[t];
+               }
+               else{
+                       for(t=0;t<stodo;t++) *(bptr++)=sl_buffer[t]>>8;
+               }
+
+               length-=stodo;
+       }
+}
+
+
+void MD_InfoDriver(void)
+{
+       int t;
+       DRIVER *l;
+
+       /* list all registered devicedrivers: */
+
+       for(t=1,l=firstdriver; l!=NULL; l=l->next, t++){
+               printf("%d. %s\n",t,l->Version);
+       }
+}
+
+
+void MD_RegisterDriver(DRIVER *drv)
+{
+       if(firstdriver==NULL){
+               firstdriver=drv;
+               drv->next=NULL;
+       }
+       else{
+               drv->next=firstdriver;
+               firstdriver=drv;
+       }
+}
+
+
+SWORD MD_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
+{
+       SWORD result=md_driver->SampleLoad(fp,size,reppos,repend,flags);
+       SL_Exit();
+       return result;
+}
+
+
+void MD_SampleUnLoad(SWORD handle)
+{
+       md_driver->SampleUnLoad(handle);
+}
+
+
+BOOL MD_Init(void)
+{
+       UWORD t;
+
+       /* if md_device==0, try to find a device number */
+
+       if(md_device==0){
+
+               for(t=1,md_driver=firstdriver; md_driver!=NULL; md_driver=md_driver->next, t++){
+                       if(md_driver->IsPresent()) break;
+               }
+
+               if(md_driver==NULL){
+                       myerr="You don't have any of the supported sound-devices";
+                       return 0;
+               }
+
+               md_device=t;
+       }
+
+       /* if n>0 use that driver */
+
+       for(t=1,md_driver=firstdriver; md_driver!=NULL && t!=md_device; md_driver=md_driver->next, t++);
+
+       if(md_driver==NULL){
+               myerr="Device number out of range";
+               return 0;
+       }
+
+       return(md_driver->Init());
+}
+
+
+void MD_Exit(void)
+{
+       md_driver->Exit();
+}
+
+
+void MD_PlayStart(void)
+{
+       /* safety valve, prevents entering
+          playstart twice: */
+
+       if(isplaying) return;
+       md_driver->PlayStart();
+       isplaying=1;
+}
+
+
+void MD_PlayStop(void)
+{
+       /* safety valve, prevents calling playStop when playstart
+          hasn't been called: */
+
+       if(isplaying){
+               isplaying=0;
+               md_driver->PlayStop();
+       }
+}
+
+
+void MD_SetBPM(UBYTE bpm)
+{
+       md_bpm=bpm;
+}
+
+
+void MD_RegisterPlayer(void (*player)(void))
+{
+       md_player=player;
+}
+
+
+void MD_Update(void)
+{
+       if(isplaying) md_driver->Update();
+}
+
+
+void MD_VoiceSetVolume(UBYTE voice,UBYTE vol)
+{
+       md_driver->VoiceSetVolume(voice,vol);
+}
+
+
+void MD_VoiceSetFrequency(UBYTE voice,ULONG frq)
+{
+       md_driver->VoiceSetFrequency(voice,frq);
+}
+
+
+void MD_VoiceSetPanning(UBYTE voice,ULONG pan)
+{
+       md_driver->VoiceSetPanning(voice,pan);
+}
+
+
+void MD_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
+{
+       md_driver->VoicePlay(voice,handle,start,size,reppos,repend,flags);
+}
diff --git a/libs/oldmik/src/mikmod.h b/libs/oldmik/src/mikmod.h
new file mode 100644 (file)
index 0000000..0111ccb
--- /dev/null
@@ -0,0 +1,580 @@
+#ifndef MIKMOD_H\r
+#define MIKMOD_H\r
+\r
+#include <stdio.h>\r
+#include "mtypes.h"                    /* include atomic mikmod types */\r
+\r
+\r
+#define mikbanner \\r
+"=======================================================================\n" \\r
+"MIKMOD v2.10 - Portable version -  Programmed by MikMak of HaRDCoDE '95\n" \\r
+"=======================================================================\n" \\r
+"This program is SHAREWARE - Read MIKMOD.TXT for more info\n" \\r
+"E-Mail : mikmak@stack.urc.tue.nl\n"\r
+\r
+\r
+/*\r
+       error variables:\r
+       ===============\r
+*/\r
+\r
+extern char *ERROR_ALLOC_STRUCT;\r
+extern char *ERROR_LOADING_PATTERN;\r
+extern char *ERROR_LOADING_TRACK;\r
+extern char *ERROR_LOADING_HEADER;\r
+extern char *ERROR_NOT_A_MODULE;\r
+extern char *ERROR_LOADING_SAMPLEINFO;\r
+extern char *ERROR_OUT_OF_HANDLES;\r
+extern char *ERROR_SAMPLE_TOO_BIG;\r
+extern char *myerr;\r
+\r
+\r
+\r
+#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)\r
+int  _mm_fseek(FILE *stream,long offset,int whence);\r
+void _mm_setiobase(long iobase);\r
+long _mm_ftell(FILE *stream);\r
+\r
+\r
+extern SBYTE  _mm_read_SBYTE   (FILE *fp);\r
+extern UBYTE _mm_read_UBYTE  (FILE *fp);\r
+\r
+extern SWORD  _mm_read_M_SWORD (FILE *fp);\r
+extern SWORD  _mm_read_I_SWORD (FILE *fp);\r
+\r
+extern UWORD _mm_read_M_UWORD(FILE *fp);\r
+extern UWORD _mm_read_I_UWORD(FILE *fp);\r
+\r
+extern SLONG  _mm_read_M_SLONG (FILE *fp);\r
+extern SLONG  _mm_read_I_SLONG (FILE *fp);\r
+\r
+extern ULONG _mm_read_M_ULONG(FILE *fp);\r
+extern ULONG _mm_read_I_ULONG(FILE *fp);\r
+\r
+extern int _mm_read_str(char *str, int size, FILE *fp);\r
+\r
+extern int _mm_read_SBYTES    (SBYTE  *buffer, int number, FILE *fp);\r
+extern int _mm_read_UBYTES   (UBYTE *buffer, int number, FILE *fp);\r
+\r
+extern int _mm_read_M_SWORDS  (SWORD  *buffer, int number, FILE *fp);\r
+extern int _mm_read_I_SWORDS  (SWORD  *buffer, int number, FILE *fp);\r
+\r
+extern int _mm_read_M_UWORDS (UWORD *buffer, int number, FILE *fp);\r
+extern int _mm_read_I_UWORDS (UWORD *buffer, int number, FILE *fp);\r
+\r
+extern int _mm_read_M_SLONGS  (SLONG  *buffer, int number, FILE *fp);\r
+extern int _mm_read_I_SLONGS  (SLONG  *buffer, int number, FILE *fp);\r
+\r
+extern int _mm_read_M_ULONGS (ULONG *buffer, int number, FILE *fp);\r
+extern int _mm_read_I_ULONGS (ULONG *buffer, int number, FILE *fp);\r
+\r
+\r
+extern void _mm_write_SBYTE            (SBYTE data,FILE *fp);\r
+extern void _mm_write_UBYTE    (UBYTE data,FILE *fp);\r
+\r
+extern void _mm_write_M_SWORD  (SWORD data,FILE *fp);\r
+extern void _mm_write_I_SWORD  (SWORD data,FILE *fp);\r
+\r
+extern void _mm_write_M_UWORD  (UWORD data,FILE *fp);\r
+extern void _mm_write_I_UWORD  (UWORD data,FILE *fp);\r
+\r
+extern void _mm_write_M_SLONG  (SLONG data,FILE *fp);\r
+extern void _mm_write_I_SLONG  (SLONG data,FILE *fp);\r
+\r
+extern void _mm_write_M_ULONG  (ULONG data,FILE *fp);\r
+extern void _mm_write_I_ULONG  (ULONG data,FILE *fp);\r
+\r
+extern void _mm_write_SBYTES           (SBYTE *data,  int number,FILE *fp);\r
+extern void _mm_write_UBYTES   (UBYTE *data, int number,FILE *fp);\r
+\r
+extern void _mm_write_M_SWORDS (SWORD *data,  int number,FILE *fp);\r
+extern void _mm_write_I_SWORDS (SWORD *data,  int number,FILE *fp);\r
+\r
+extern void _mm_write_M_UWORDS (UWORD *data, int number,FILE *fp);\r
+extern void _mm_write_I_UWORDS (UWORD *data, int number,FILE *fp);\r
+\r
+extern void _mm_write_M_SLONGS (SLONG *data,  int number,FILE *fp);\r
+extern void _mm_write_I_SLONGS (SLONG *data,  int number,FILE *fp);\r
+\r
+extern void _mm_write_M_ULONGS (ULONG *data, int number,FILE *fp);\r
+extern void _mm_write_I_ULONGS (ULONG *data, int number,FILE *fp);\r
+\r
+\r
+/**************************************************************************\r
+****** Unitrack stuff: ****************************************************\r
+**************************************************************************/\r
+\r
+/*\r
+       prototypes:\r
+*/\r
+\r
+void   UniSetRow(UBYTE *t);\r
+UBYTE  UniGetByte(void);\r
+UBYTE  *UniFindRow(UBYTE *t,UWORD row);\r
+void           UniReset(void);\r
+void           UniWrite(UBYTE data);\r
+void           UniNewline(void);\r
+void   UniInstrument(UBYTE ins);\r
+void   UniNote(UBYTE note);\r
+void   UniPTEffect(UBYTE eff,UBYTE dat);\r
+UBYTE  *UniDup(void);\r
+void   UniSkipOpcode(UBYTE op);\r
+BOOL   UniInit(void);\r
+void   UniCleanup(void);\r
+UWORD   TrkLen(UBYTE *t);\r
+BOOL    MyCmp(UBYTE *a,UBYTE *b,UWORD l);\r
+\r
+/*\r
+       all known effects:\r
+*/\r
+\r
+enum {\r
+               UNI_NOTE=1,\r
+               UNI_INSTRUMENT,\r
+               UNI_PTEFFECT0,\r
+               UNI_PTEFFECT1,\r
+               UNI_PTEFFECT2,\r
+               UNI_PTEFFECT3,\r
+               UNI_PTEFFECT4,\r
+               UNI_PTEFFECT5,\r
+               UNI_PTEFFECT6,\r
+               UNI_PTEFFECT7,\r
+               UNI_PTEFFECT8,\r
+               UNI_PTEFFECT9,\r
+               UNI_PTEFFECTA,\r
+               UNI_PTEFFECTB,\r
+               UNI_PTEFFECTC,\r
+               UNI_PTEFFECTD,\r
+               UNI_PTEFFECTE,\r
+               UNI_PTEFFECTF,\r
+               UNI_S3MEFFECTA,\r
+               UNI_S3MEFFECTD,\r
+               UNI_S3MEFFECTE,\r
+               UNI_S3MEFFECTF,\r
+               UNI_S3MEFFECTI,\r
+               UNI_S3MEFFECTQ,\r
+               UNI_S3MEFFECTT,\r
+               UNI_XMEFFECTA,\r
+                UNI_XMEFFECTG,\r
+                UNI_XMEFFECTH,\r
+               UNI_XMEFFECTP\r
+};\r
+\r
+\r
+/**************************************************************************\r
+****** mikmod types: ******************************************************\r
+**************************************************************************/\r
+\r
+\r
+/*\r
+       Sample format flags:\r
+*/\r
+\r
+#define SF_16BITS       1\r
+#define SF_SIGNED      2\r
+#define SF_DELTA        4\r
+#define SF_BIG_ENDIAN  8\r
+#define SF_LOOP         16\r
+#define SF_BIDI         32\r
+#define SF_OWNPAN       64\r
+#define SF_REVERSE             128\r
+\r
+\r
+/*\r
+       Envelope flags:\r
+*/\r
+\r
+#define EF_ON           1\r
+#define EF_SUSTAIN      2\r
+#define EF_LOOP         4\r
+\r
+\r
+/*\r
+       Unimod flags\r
+*/\r
+\r
+#define UF_XMPERIODS    1               /* if set use XM periods/finetuning */\r
+#define UF_LINEAR       2               /* if set use LINEAR periods */\r
+\r
+\r
+typedef struct ENVPT{\r
+       SWORD pos;\r
+       SWORD val;\r
+} ENVPT;\r
+\r
+\r
+typedef struct SAMPLE{\r
+       UWORD c2spd;            /* finetune frequency */\r
+       SBYTE transpose;        /* transpose value */\r
+       UBYTE volume;           /* volume 0-64 */\r
+       UBYTE panning;          /* panning */\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 flags;            /* sample format */\r
+       ULONG seekpos;                  /* seek position in file */\r
+       char *samplename;       /* name of the sample */\r
+       SWORD handle;           /* sample handle */\r
+} SAMPLE;\r
+\r
+\r
+typedef struct INSTRUMENT{\r
+       UBYTE numsmp;\r
+       UBYTE samplenumber[96];\r
+\r
+       UBYTE volflg;           /* bit 0: on 1: sustain 2: loop */\r
+       UBYTE volpts;\r
+       UBYTE volsus;\r
+       UBYTE volbeg;\r
+       UBYTE volend;\r
+       ENVPT volenv[12];\r
+\r
+       UBYTE panflg;           /* bit 0: on 1: sustain 2: loop */\r
+       UBYTE panpts;\r
+       UBYTE pansus;\r
+       UBYTE panbeg;\r
+       UBYTE panend;\r
+       ENVPT panenv[12];\r
+\r
+       UBYTE vibtype;\r
+       UBYTE vibsweep;\r
+       UBYTE vibdepth;\r
+       UBYTE vibrate;\r
+\r
+       UWORD volfade;\r
+       char  *insname;\r
+       SAMPLE *samples;\r
+} INSTRUMENT;\r
+\r
+\r
+/*\r
+       MikMod UNImod types:\r
+       ====================\r
+*/\r
+\r
+typedef struct UNIMOD{\r
+       UBYTE           numchn;                 /* number of channels */\r
+       UWORD       numpos;         /* number of positions in this song */\r
+       UWORD           reppos;                 /* restart position */\r
+       UWORD       numpat;         /* number of patterns in this song */\r
+       UWORD       numtrk;         /* number of tracks */\r
+       UWORD       numins;         /* number of samples */\r
+       UBYTE       initspeed;      /* */\r
+       UBYTE       inittempo;      /* */\r
+       UBYTE       positions[256]; /* all positions */\r
+       UBYTE       panning[32];        /* 32 panning positions */\r
+       UBYTE       flags;          /* */\r
+       char       *songname;       /* name of the song */\r
+       char       *modtype;        /* string type of module */\r
+       char       *comment;        /* module comments */\r
+       INSTRUMENT *instruments;    /* all samples */\r
+       UWORD      *patterns;       /* array of PATTERN */\r
+       UWORD      *pattrows;       /* array of number of rows for each pattern */\r
+       UBYTE     **tracks;         /* array of pointers to tracks */\r
+} UNIMOD;\r
+\r
+\r
+/**************************************************************************\r
+****** Loader stuff: ******************************************************\r
+**************************************************************************/\r
+\r
+/*\r
+       loader structure:\r
+*/\r
+\r
+typedef struct LOADER{\r
+       struct LOADER *next;\r
+       char    *type;\r
+       char    *version;\r
+       BOOL    (*Init)(void);\r
+       BOOL    (*Test)(void);\r
+       BOOL    (*Load)(void);\r
+       void    (*Cleanup)(void);\r
+} LOADER;\r
+\r
+\r
+/*\r
+       public loader variables:\r
+*/\r
+\r
+extern UNIMOD of;\r
+extern FILE *modfp;\r
+extern UWORD finetune[16];\r
+\r
+\r
+/*\r
+       main loader prototypes:\r
+*/\r
+\r
+void   ML_InfoLoader(void);\r
+void   ML_RegisterLoader(LOADER *ldr);\r
+UNIMOD *ML_LoadFP(FILE *fp);\r
+UNIMOD *ML_LoadFN(char *filename);\r
+void   ML_Free(UNIMOD *mf);\r
+\r
+\r
+/*\r
+       other loader prototypes: (used by the loader modules)\r
+*/\r
+\r
+BOOL   InitTracks(void);\r
+void   AddTrack(UBYTE *tr);\r
+BOOL   ReadComment(UWORD len);\r
+BOOL   AllocPatterns(void);\r
+BOOL   AllocTracks(void);\r
+BOOL   AllocInstruments(void);\r
+BOOL   AllocSamples(INSTRUMENT *i);\r
+char    *DupStr(char *s,UWORD len);\r
+void   *MyMalloc(size_t size);\r
+void   *MyCalloc(size_t nitems,size_t size);\r
+\r
+\r
+/*\r
+       Declare external loaders:\r
+*/\r
+extern LOADER load_uni;\r
+extern LOADER load_mod;\r
+extern LOADER load_m15;\r
+extern LOADER load_mtm;\r
+extern LOADER load_s3m;\r
+extern LOADER load_stm;\r
+extern LOADER load_ult;\r
+extern LOADER load_xm;\r
+\r
+\r
+/**************************************************************************\r
+****** Wavload stuff: *****************************************************\r
+**************************************************************************/\r
+\r
+SAMPLE *MW_LoadWavFP(FILE *fp);\r
+SAMPLE *MW_LoadWavFN(char *filename);\r
+void MW_FreeWav(SAMPLE *si);\r
+\r
+\r
+/**************************************************************************\r
+****** Driver stuff: ******************************************************\r
+**************************************************************************/\r
+\r
+/*\r
+       max. number of handles a driver has to provide. (not strict)\r
+*/\r
+\r
+#define MAXSAMPLEHANDLES 128\r
+\r
+\r
+/*\r
+       possible mixing mode bits:\r
+*/\r
+\r
+#define DMODE_STEREO    1\r
+#define DMODE_16BITS    2\r
+#define DMODE_INTERP   4\r
+\r
+\r
+/*\r
+       driver structure:\r
+*/\r
+\r
+typedef struct DRIVER{\r
+       struct DRIVER *next;\r
+       char    *Name;\r
+       char    *Version;\r
+       BOOL    (*IsPresent)            (void);\r
+       SWORD   (*SampleLoad)           (FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+       void    (*SampleUnLoad)         (SWORD handle);\r
+       BOOL    (*Init)                 (void);\r
+       void    (*Exit)                 (void);\r
+       void    (*PlayStart)            (void);\r
+       void    (*PlayStop)             (void);\r
+       void    (*Update)               (void);\r
+       void    (*VoiceSetVolume)               (UBYTE voice,UBYTE vol);\r
+       void    (*VoiceSetFrequency)    (UBYTE voice,ULONG frq);\r
+       void    (*VoiceSetPanning)              (UBYTE voice,UBYTE pan);\r
+       void    (*VoicePlay)                    (UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+} DRIVER;\r
+\r
+\r
+/*\r
+       public driver variables:\r
+*/\r
+\r
+extern DRIVER *md_driver;\r
+extern UWORD md_device;\r
+extern UWORD md_mixfreq;\r
+extern UWORD md_dmabufsize;\r
+extern UWORD md_mode;\r
+extern UBYTE md_numchn;\r
+extern UBYTE md_bpm;\r
+extern void (*md_player)(void);\r
+\r
+/*\r
+       main driver prototypes:\r
+*/\r
+\r
+void MD_InfoDriver(void);\r
+void MD_RegisterDriver(DRIVER *drv);\r
+void MD_RegisterPlayer(void (*plr)(void));\r
+SWORD MD_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+void MD_SampleUnLoad(SWORD handle);\r
+BOOL MD_Init(void);\r
+void MD_Exit(void);\r
+void MD_PlayStart(void);\r
+void MD_PlayStop(void);\r
+void MD_SetBPM(UBYTE bpm);\r
+void MD_Update(void);\r
+void MD_VoiceSetVolume(UBYTE voice,UBYTE ivol);\r
+void MD_VoiceSetFrequency(UBYTE voice,ULONG frq);\r
+void MD_VoiceSetPanning(UBYTE voice,ULONG pan);\r
+void MD_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+void SL_Init(FILE *fp,UWORD infmt,UWORD outfmt);\r
+void SL_Load(void *buffer,ULONG length);\r
+\r
+/*\r
+       Declare external drivers:\r
+*/\r
+\r
+extern DRIVER drv_gus;         /* gravis ultrasound driver */\r
+extern DRIVER drv_sb;          /* soundblaster DSP driver */\r
+extern DRIVER drv_ss;          /* ensoniq soundscape driver */\r
+extern DRIVER drv_nos;         /* nosound driver */\r
+extern DRIVER drv_raw;         /* file output driver */\r
+extern DRIVER drv_w95;         /* win95 driver */\r
+extern DRIVER drv_awe;         /* experimental SB-AWE driver */\r
+extern DRIVER drv_vox;         /* linux voxware driver */\r
+extern DRIVER drv_af;       /* Dec Alpha AudioFile driver */\r
+extern DRIVER drv_sun;      /* Sun driver */\r
+extern DRIVER drv_os2;      /* Os2 driver */\r
+extern DRIVER drv_tim;          /* timing driver */\r
+\r
+/**************************************************************************\r
+****** Player stuff: ******************************************************\r
+**************************************************************************/\r
+\r
+\r
+typedef struct ENVPR{\r
+       UBYTE flg;          /* envelope flag */\r
+       UBYTE pts;                      /* number of envelope points */\r
+       UBYTE sus;                      /* envelope sustain index */\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
+\r
+typedef struct AUDTMP{\r
+       INSTRUMENT      *i;\r
+       SAMPLE      *s;\r
+\r
+        UWORD fadevol;          /* fading volume */\r
+\r
+       ENVPR venv;\r
+       ENVPR penv;\r
+\r
+       UBYTE keyon;            /* if true=key is pressed. */\r
+       UBYTE kick;                     /* if true=sample has to be restarted */\r
+       UBYTE sample;           /* which sample number (0-31) */\r
+       SWORD handle;           /* which sample-handle */\r
+\r
+       ULONG start;            /* The start byte index in the sample */\r
+\r
+       UBYTE panning;          /* panning position */\r
+       UBYTE pansspd;          /* panslide speed */\r
+\r
+       SBYTE volume;           /* amiga volume (0 t/m 64) to play the sample at */\r
+       UWORD period;           /* period to play the sample at */\r
+\r
+       /* You should not have to use the values\r
+          below in the player routine */\r
+\r
+       SBYTE transpose;\r
+\r
+       UBYTE note;                     /* */\r
+\r
+       SWORD ownper;\r
+       SWORD ownvol;\r
+\r
+       UBYTE *row;                     /* row currently playing on this channel */\r
+\r
+       SBYTE retrig;           /* retrig value (0 means don't retrig) */\r
+       UWORD c2spd;            /* what finetune to use */\r
+\r
+       SBYTE tmpvolume;        /* tmp volume */\r
+\r
+       UWORD tmpperiod;        /* tmp period */\r
+       UWORD wantedperiod;     /* period to slide to (with effect 3 or 5) */\r
+\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
+\r
+       UBYTE s3mvolslide;      /* last used volslide */\r
+\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
+       UWORD soffset;          /* last used sample-offset (effect 9) */\r
+} AUDTMP;\r
+\r
+\r
+extern AUDTMP mp_audio[32];            /* max eight channels */\r
+extern UBYTE  mp_bpm;                  /* beats-per-minute speed */\r
+extern UWORD  mp_patpos;               /* current row number (0-63) */\r
+extern SWORD  mp_sngpos;               /* current song position */\r
+extern UWORD  mp_sngspd;               /* current songspeed */\r
+\r
+extern BOOL  mp_loop;\r
+extern BOOL  mp_panning;\r
+extern BOOL  mp_extspd;\r
+extern UBYTE mp_volume;\r
+\r
+/*\r
+       player prototypes:\r
+*/\r
+\r
+int     MP_Ready(void);\r
+void MP_NextPosition(void);\r
+void MP_PrevPosition(void);\r
+void MP_SetPosition(UWORD pos);\r
+void MP_HandleTick(void);\r
+void MP_Init(UNIMOD *m);\r
+\r
+\r
+/**************************************************************************\r
+****** Virtual channel stuff: *********************************************\r
+**************************************************************************/\r
+\r
+BOOL    VC_Init(void);\r
+void    VC_Exit(void);\r
+\r
+void    VC_PlayStart(void);\r
+void    VC_PlayStop(void);\r
+\r
+SWORD   VC_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+void    VC_SampleUnload(SWORD handle);\r
+\r
+void    VC_WriteSamples(SBYTE *buf,UWORD todo);\r
+UWORD   VC_WriteBytes(SBYTE *buf,UWORD todo);\r
+void    VC_SilenceBytes(SBYTE *buf,UWORD todo);\r
+\r
+void   VC_VoiceSetVolume(UBYTE voice,UBYTE vol);\r
+void   VC_VoiceSetFrequency(UBYTE voice,ULONG frq);\r
+void   VC_VoiceSetPanning(UBYTE voice,UBYTE pan);\r
+void   VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);\r
+\r
+#endif\r
diff --git a/libs/oldmik/src/mirq.c b/libs/oldmik/src/mirq.c
new file mode 100644 (file)
index 0000000..96cbcf7
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+\r
+Name:\r
+MDMA.C\r
+\r
+Description:\r
+Some general purpose IRQ routines\r
+\r
+Portability:\r
+\r
+MSDOS: BC(y)   Watcom(y)       DJGPP(y)\r
+Win95: n\r
+Os2:   n\r
+Linux: n\r
+\r
+(y) - yes\r
+(n) - no (not possible or not useful)\r
+(?) - may be possible, but not tested\r
+\r
+*/\r
+#include <dos.h>\r
+#include <conio.h>\r
+#include "mirq.h"\r
+\r
+#define OCR1   0x20                    /* 8259-1 Operation control register */\r
+#define IMR1   0x21                    /* 8259-1 Mask register */\r
+\r
+#define OCR2   0xA0                    /* 8259-2 Operation control register */\r
+#define IMR2   0xA1                    /* 8259-2 Mask register */\r
+\r
+\r
+BOOL MIrq_IsEnabled(UBYTE irqno)\r
+/*\r
+       Returns true if the specified hardware irq is enabled.\r
+*/\r
+{\r
+       UBYTE imr=(irqno>7) ? IMR2 : IMR1;              /* interrupt mask register */\r
+       UBYTE msk=1<<(irqno&7);                                 /* interrupt mask */\r
+       return((inportb(imr) & msk) == 0);\r
+}\r
+\r
+\r
+BOOL MIrq_OnOff(UBYTE irqno,UBYTE onoff)\r
+/*\r
+       Use to enable or disable the specified irq.\r
+*/\r
+{\r
+       UBYTE imr=(irqno>7) ? IMR2 : IMR1;              /* interrupt mask register */\r
+       UBYTE ocr=(irqno>7) ? OCR2 : OCR1;              /* ocr */\r
+       UBYTE msk=1<<(irqno&7);                                 /* interrupt mask */\r
+       UBYTE eoi=0x60|(irqno&7);                               /* specific end-of-interrupt */\r
+       BOOL oldstate;\r
+\r
+       /* save current setting of this irq */\r
+       oldstate=((inportb(imr) & msk) == 0);\r
+\r
+       if(onoff){\r
+               outportb(imr,inportb(imr) & ~msk);\r
+               outportb(ocr,eoi);\r
+               if(irqno>7) MIrq_OnOff(2,1);\r
+       }\r
+       else{\r
+               outportb(imr,inportb(imr) | msk);\r
+       }\r
+\r
+       return oldstate;\r
+}\r
+\r
+\r
+void MIrq_EOI(UBYTE irqno)\r
+/*\r
+       Clears the specified interrupt request at the interrupt controller.\r
+*/\r
+{\r
+        outportb(0x20,0x20);\r
+        if(irqno>7) outportb(0xa0,0x20);\r
+}\r
+\r
+\r
+PVI MIrq_SetHandler(UBYTE irqno,PVI handler)\r
+{\r
+#ifdef __DJGPP__\r
+       _go32_dpmi_seginfo seginfo;\r
+#endif\r
+       PVI oldvect;\r
+       int vecno=(irqno>7) ? irqno+0x68 : irqno+0x8;\r
+#ifdef __DJGPP__\r
+       _go32_dpmi_get_protected_mode_interrupt_vector(vecno, &seginfo);\r
+       oldvect = seginfo.pm_offset;\r
+       seginfo.pm_offset = handler;\r
+       seginfo.pm_selector = _go32_my_cs();\r
+       _go32_dpmi_allocate_iret_wrapper(&seginfo);\r
+       _go32_dpmi_set_protected_mode_interrupt_vector(vecno, &seginfo);\r
+#else\r
+       oldvect=_dos_getvect(vecno);\r
+       _dos_setvect(vecno,handler);\r
+#endif\r
+       return oldvect;\r
+}\r
diff --git a/libs/oldmik/src/mirq.h b/libs/oldmik/src/mirq.h
new file mode 100644 (file)
index 0000000..7fcf97f
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef MIRQ_H
+#define MIRQ_H
+
+#include "mtypes.h"
+
+
+#ifdef __WATCOMC__
+       #define MIRQARGS void
+       typedef void (interrupt far *PVI)(MIRQARGS);
+#endif
+
+#ifdef __DJGPP__
+       #define MIRQARGS void
+       typedef void (*PVI)(MIRQARGS);
+#endif
+
+#ifdef __BORLANDC__
+
+       #ifdef __cplusplus
+               #define MIRQARGS ...
+       #else
+               #define MIRQARGS
+       #endif
+
+       typedef void interrupt (far *PVI)(MIRQARGS);
+
+#endif
+
+
+BOOL MIrq_IsEnabled(UBYTE irqno);
+BOOL MIrq_OnOff(UBYTE irqno,UBYTE onoff);
+PVI  MIrq_SetHandler(UBYTE irqno,PVI handler);
+void MIrq_EOI(UBYTE irqno);
+
+#endif
diff --git a/libs/oldmik/src/mloader.c b/libs/oldmik/src/mloader.c
new file mode 100644 (file)
index 0000000..6e135fc
--- /dev/null
@@ -0,0 +1,406 @@
+/*\r
+\r
+Name:\r
+MLOADER.C\r
+\r
+Description:\r
+These routines are used to access the available module loaders\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "mikmod.h"\r
+\r
+\r
+FILE *modfp;\r
+UNIMOD of;\r
+\r
+LOADER *firstloader=NULL;\r
+\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
+\r
+\r
+\r
+\r
+void ML_InfoLoader(void)\r
+{\r
+       int t;\r
+       LOADER *l;\r
+\r
+       /* list all registered devicedrivers: */\r
+\r
+       for(t=1,l=firstloader; l!=NULL; l=l->next, t++){\r
+               printf("%d. %s\n",t,l->version);\r
+       }\r
+}\r
+\r
+\r
+void ML_RegisterLoader(LOADER *ldr)\r
+{\r
+       LOADER *l;\r
+\r
+       if(firstloader==NULL){\r
+               firstloader=ldr;\r
+               ldr->next=NULL;\r
+       }\r
+       else{\r
+               ldr->next=firstloader;\r
+               firstloader=ldr;\r
+       }\r
+}\r
+\r
+\r
+\r
+void *MyMalloc(size_t size)\r
+/*\r
+       Same as malloc, but sets error variable ml_errno when it failed\r
+*/\r
+{\r
+       void *d;\r
+\r
+       d=malloc(size);\r
+       if(d==NULL){\r
+               myerr="Error allocating structure";\r
+       }\r
+       return d;\r
+}\r
+\r
+\r
+\r
+void *MyCalloc(size_t nitems,size_t size)\r
+/*\r
+       Same as calloc, but sets error variable ml_errno when it failed\r
+*/\r
+{\r
+       void *d;\r
+\r
+       d=calloc(nitems,size);\r
+       if(d==NULL){\r
+               myerr="Error allocating structure";\r
+       }\r
+       return d;\r
+}\r
+\r
+\r
+\r
+BOOL ReadComment(UWORD len)\r
+{\r
+       int t;\r
+\r
+       if(len){\r
+                if(!(of.comment=(char *)MyMalloc(len+1))) return 0;\r
+               fread(of.comment,len,1,modfp);\r
+               of.comment[len]=0;\r
+\r
+               /* strip any control-characters in the comment: */\r
+\r
+               for(t=0;t<len;t++){\r
+                       if(of.comment[t]<32) of.comment[t]=' ';\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+BOOL AllocPatterns(void)\r
+{\r
+       int s,t,tracks=0;\r
+\r
+       /* Allocate track sequencing array */\r
+\r
+       if(!(of.patterns=(UWORD *)MyCalloc((ULONG)of.numpat*of.numchn,sizeof(UWORD)))) return 0;\r
+       if(!(of.pattrows=(UWORD *)MyCalloc(of.numpat,sizeof(UWORD)))) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++){\r
+\r
+               of.pattrows[t]=64;\r
+\r
+               for(s=0;s<of.numchn;s++){\r
+                       of.patterns[(t*of.numchn)+s]=tracks++;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+BOOL AllocTracks(void)\r
+{\r
+       if(!(of.tracks=(UBYTE **)MyCalloc(of.numtrk,sizeof(UBYTE *)))) return 0;\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+BOOL AllocInstruments(void)\r
+{\r
+       UWORD t;\r
+\r
+       if(!(of.instruments=(INSTRUMENT *)MyCalloc(of.numins,sizeof(INSTRUMENT)))) return 0;\r
+       return 1;\r
+}\r
+\r
+\r
+BOOL AllocSamples(INSTRUMENT *i)\r
+{\r
+       UWORD u,n;\r
+\r
+       if(n=i->numsmp){\r
+               if(!(i->samples=(SAMPLE *)MyCalloc(n,sizeof(SAMPLE)))) return 0;\r
+\r
+               for(u=0; u<n; u++){\r
+                       i->samples[u].panning=128;\r
+                       i->samples[u].handle=-1;\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+char *DupStr(char *s,UWORD len)\r
+/*\r
+       Creates a CSTR out of a character buffer of 'len' bytes, but strips\r
+       any terminating non-printing characters like 0, spaces etc.\r
+*/\r
+{\r
+       UWORD t;\r
+       char *d=NULL;\r
+\r
+       /* Scan for first printing char in buffer [includes high ascii up to 254] */\r
+\r
+       while(len){\r
+               if(!(s[len-1]>=0 && s[len-1]<=0x20)) break;\r
+               len--;\r
+       }\r
+\r
+       if(len){\r
+\r
+               /* When the buffer wasn't completely empty, allocate\r
+                  a cstring and copy the buffer into that string, except\r
+                  for any control-chars */\r
+\r
+               if((d=(char *)malloc(len+1))!=NULL){\r
+                       for(t=0;t<len;t++) {\r
+                               d[t]=(s[t]>=0 && s[t]<32) ? ' ': s[t];\r
+                       }\r
+                       d[t]=0;\r
+               }\r
+       }\r
+\r
+       return d;\r
+}\r
+\r
+\r
+\r
+BOOL ML_LoadSamples(void)\r
+{\r
+       UWORD t,u;\r
+       INSTRUMENT *i;\r
+       SAMPLE *s;\r
+\r
+       for(t=0;t<of.numins;t++){\r
+\r
+               i=&of.instruments[t];\r
+\r
+               for(u=0; u<i->numsmp; u++){\r
+\r
+                       s=&i->samples[u];\r
+\r
+/*             printf("Loading Sample %d\n",t); */\r
+\r
+               /* sample has to be loaded ? -> increase\r
+                  number of samples and allocate memory and\r
+                  load sample */\r
+\r
+                       if(s->length){\r
+\r
+                               if(s->seekpos){\r
+                                       _mm_fseek(modfp,s->seekpos,SEEK_SET);\r
+                               }\r
+\r
+                               /* Call the sample load routine of the driver module.\r
+                                  It has to return a 'handle' (>=0) that identifies\r
+                                  the sample */\r
+\r
+                               s->handle=MD_SampleLoad(modfp,\r
+                                                                               s->length,\r
+                                                                               s->loopstart,\r
+                                                                               s->loopend,\r
+                                                                               s->flags);\r
+\r
+                               if(s->handle<0) return 0;\r
+                       }\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+BOOL ML_LoadHeader(void)\r
+{\r
+       BOOL ok=0;\r
+       LOADER *l;\r
+\r
+       /* Try to find a loader that recognizes the module */\r
+\r
+       for(l=firstloader; l!=NULL; l=l->next){\r
+               _mm_rewind(modfp);\r
+               if(l->Test()) break;\r
+       }\r
+\r
+       if(l==NULL){\r
+               myerr="Unknown module format.";\r
+               return 0;\r
+       }\r
+\r
+       /* init unitrk routines */\r
+\r
+       if(!UniInit()) return 0;\r
+\r
+       /* init module loader */\r
+\r
+       if(l->Init()){\r
+               _mm_rewind(modfp);\r
+                ok=l->Load();\r
+       }\r
+\r
+       l->Cleanup();\r
+\r
+       /* free unitrk allocations */\r
+\r
+       UniCleanup();\r
+       return ok;\r
+}\r
+\r
+\r
+\r
+void ML_XFreeInstrument(INSTRUMENT *i)\r
+{\r
+       UWORD t;\r
+\r
+       if(i->samples!=NULL){\r
+               for(t=0; t<i->numsmp; t++){\r
+                       if(i->samples[t].handle>=0){\r
+                               MD_SampleUnLoad(i->samples[t].handle);\r
+                       }\r
+               }\r
+               free(i->samples);\r
+       }\r
+       if(i->insname!=NULL) free(i->insname);\r
+}\r
+\r
+\r
+void ML_FreeEx(UNIMOD *mf)\r
+{\r
+       UWORD t;\r
+\r
+        if(mf->modtype!=NULL) free(mf->modtype);\r
+       if(mf->patterns!=NULL) free(mf->patterns);\r
+       if(mf->pattrows!=NULL) free(mf->pattrows);\r
+\r
+       if(mf->tracks!=NULL){\r
+               for(t=0;t<mf->numtrk;t++){\r
+                       if(mf->tracks[t]!=NULL) free(mf->tracks[t]);\r
+               }\r
+               free(mf->tracks);\r
+       }\r
+\r
+       if(mf->instruments!=NULL){\r
+               for(t=0;t<mf->numins;t++){\r
+                       ML_XFreeInstrument(&mf->instruments[t]);\r
+               }\r
+               free(mf->instruments);\r
+       }\r
+\r
+       if(mf->songname!=NULL) free(mf->songname);\r
+       if(mf->comment!=NULL) free(mf->comment);\r
+}\r
+\r
+\r
+\r
+/******************************************\r
+\r
+       Next are the user-callable functions\r
+\r
+******************************************/\r
+\r
+\r
+void ML_Free(UNIMOD *mf)\r
+{\r
+       if(mf!=NULL){\r
+               ML_FreeEx(mf);\r
+               free(mf);\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+UNIMOD *ML_LoadFP(FILE *fp)\r
+{\r
+       int t;\r
+       UNIMOD *mf;\r
+\r
+       /* init fileptr, clear errorcode, clear static modfile: */\r
+\r
+       modfp=fp;\r
+       myerr=NULL;\r
+       memset(&of,0,sizeof(UNIMOD));\r
+\r
+       /* init panning array */\r
+\r
+       for(t=0;t<32;t++){\r
+               of.panning[t]=((t+1)&2)?255:0;\r
+       }\r
+\r
+       if(!ML_LoadHeader()){\r
+               ML_FreeEx(&of);\r
+               return NULL;\r
+       }\r
+\r
+       if(!ML_LoadSamples()){\r
+               ML_FreeEx(&of);\r
+               return NULL;\r
+       }\r
+\r
+       if(!(mf=(UNIMOD *)MyCalloc(1,sizeof(UNIMOD)))){\r
+               ML_FreeEx(&of);\r
+               return NULL;\r
+       }\r
+\r
+       /* Copy the static UNIMOD contents\r
+       into the dynamic UNIMOD struct */\r
+\r
+       memcpy(mf,&of,sizeof(UNIMOD));\r
+\r
+       return mf;\r
+}\r
+\r
+\r
+\r
+UNIMOD *ML_LoadFN(char *filename)\r
+{\r
+       FILE *fp;\r
+       UNIMOD *mf;\r
+\r
+       if((fp=fopen(filename,"rb"))==NULL){\r
+               myerr="Error opening file";\r
+               return NULL;\r
+       }\r
+\r
+       mf=ML_LoadFP(fp);\r
+       fclose(fp);\r
+\r
+       return mf;\r
+}\r
+\r
diff --git a/libs/oldmik/src/mmio.c b/libs/oldmik/src/mmio.c
new file mode 100644 (file)
index 0000000..1cedb8f
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+
+Name:
+MMIO.C
+
+Description:
+Miscellaneous I/O routines.. used to solve some portability issues
+(like big/little endian machines and word alignment in structures )
+Also includes mikmod's ingenious error handling variable + some much
+used error strings.
+
+Portability:
+All systems - all compilers
+
+*/
+#include <stdio.h>
+#include "mikmod.h"
+
+char *ERROR_ALLOC_STRUCT="Error allocating structure";
+char *ERROR_LOADING_PATTERN="Error loading pattern";
+char *ERROR_LOADING_TRACK="Error loading track";
+char *ERROR_LOADING_HEADER="Error loading header";
+char *ERROR_NOT_A_MODULE="Unknown module format";
+char *ERROR_LOADING_SAMPLEINFO="Error loading sampleinfo";
+char *ERROR_OUT_OF_HANDLES="Out of sample-handles";
+char *ERROR_SAMPLE_TOO_BIG="Sample too big, out of memory";
+
+char *myerr;
+
+static long _mm_iobase=0;
+
+int _mm_fseek(FILE *stream, long offset, int whence)
+{
+       return fseek(stream,
+                                (whence==SEEK_SET) ? offset+_mm_iobase : offset,
+                                whence);
+}
+
+long _mm_ftell(FILE *stream)
+{
+       return ftell(stream)-_mm_iobase;
+}
+
+void _mm_setiobase(long iobase)
+{
+       _mm_iobase=iobase;
+}
+
+void _mm_write_SBYTE(SBYTE data,FILE *fp)
+{
+       fputc(data,fp);
+}
+
+void _mm_write_UBYTE(UBYTE data,FILE *fp)
+{
+       fputc(data,fp);
+}
+
+void _mm_write_M_UWORD(UWORD data,FILE *fp)
+{
+       _mm_write_UBYTE(data>>8,fp);
+       _mm_write_UBYTE(data&0xff,fp);
+}
+
+void _mm_write_I_UWORD(UWORD data,FILE *fp)
+{
+       _mm_write_UBYTE(data&0xff,fp);
+       _mm_write_UBYTE(data>>8,fp);
+}
+
+void _mm_write_M_SWORD(SWORD data,FILE *fp)
+{
+       _mm_write_M_UWORD((UWORD)data,fp);
+}
+
+void _mm_write_I_SWORD(SWORD data,FILE *fp)
+{
+       _mm_write_I_UWORD((UWORD)data,fp);
+}
+
+void _mm_write_M_ULONG(ULONG data,FILE *fp)
+{
+       _mm_write_M_UWORD(data>>16,fp);
+       _mm_write_M_UWORD(data&0xffff,fp);
+}
+
+void _mm_write_I_ULONG(ULONG data,FILE *fp)
+{
+       _mm_write_I_UWORD(data&0xffff,fp);
+       _mm_write_I_UWORD(data>>16,fp);
+}
+
+void _mm_write_M_SLONG(SLONG data,FILE *fp)
+{
+       _mm_write_M_ULONG((ULONG)data,fp);
+}
+
+void _mm_write_I_SLONG(SLONG data,FILE *fp)
+{
+       _mm_write_I_ULONG((ULONG)data,fp);
+}
+
+
+#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name, type)        \
+void                                                           \
+_mm_write_##type_name##S (type *buffer, int number, FILE *fp)  \
+{                                                              \
+       while(number>0){                                           \
+               _mm_write_##type_name(*(buffer++),fp);                             \
+               number--;                                                                                          \
+       }                                                                                                                  \
+}
+
+DEFINE_MULTIPLE_WRITE_FUNCTION ( SBYTE,  SBYTE)
+DEFINE_MULTIPLE_WRITE_FUNCTION (UBYTE, UBYTE)
+
+DEFINE_MULTIPLE_WRITE_FUNCTION (M_SWORD,   SWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION (M_UWORD, UWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION (I_SWORD,   SWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION (I_UWORD, UWORD)
+
+DEFINE_MULTIPLE_WRITE_FUNCTION (M_SLONG,   SLONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION (M_ULONG, ULONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION (I_SLONG,   SLONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION (I_ULONG, ULONG)
+
+
+SBYTE _mm_read_SBYTE(FILE *fp)
+{
+       return(fgetc(fp));
+}
+
+UBYTE _mm_read_UBYTE(FILE *fp)
+{
+       return(fgetc(fp));
+}
+
+UWORD _mm_read_M_UWORD(FILE *fp)
+{
+       UWORD result=((UWORD)_mm_read_UBYTE(fp))<<8;
+       result|=_mm_read_UBYTE(fp);
+       return result;
+}
+
+UWORD _mm_read_I_UWORD(FILE *fp)
+{
+       UWORD result=_mm_read_UBYTE(fp);
+       result|=((UWORD)_mm_read_UBYTE(fp))<<8;
+       return result;
+}
+
+SWORD _mm_read_M_SWORD(FILE *fp)
+{
+       return((SWORD)_mm_read_M_UWORD(fp));
+}
+
+SWORD _mm_read_I_SWORD(FILE *fp)
+{
+       return((SWORD)_mm_read_I_UWORD(fp));
+}
+
+ULONG _mm_read_M_ULONG(FILE *fp)
+{
+       ULONG result=((ULONG)_mm_read_M_UWORD(fp))<<16;
+       result|=_mm_read_M_UWORD(fp);
+       return result;
+}
+
+ULONG _mm_read_I_ULONG(FILE *fp)
+{
+       ULONG result=_mm_read_I_UWORD(fp);
+       result|=((ULONG)_mm_read_I_UWORD(fp))<<16;
+       return result;
+}
+
+SLONG _mm_read_M_SLONG(FILE *fp)
+{
+       return((SLONG)_mm_read_M_ULONG(fp));
+}
+
+SLONG _mm_read_I_SLONG(FILE *fp)
+{
+       return((SLONG)_mm_read_I_ULONG(fp));
+}
+
+
+int _mm_read_str(char *buffer,int number,FILE *fp)
+{
+       fread(buffer,1,number,fp);
+       return !feof(fp);
+}
+
+
+#define DEFINE_MULTIPLE_READ_FUNCTION(type_name, type)         \
+int                                                            \
+_mm_read_##type_name##S (type *buffer, int number, FILE *fp)   \
+{                                                              \
+       while(number>0){                                           \
+               *(buffer++)=_mm_read_##type_name(fp);                              \
+               number--;                                                                                          \
+       }                                                                                                                  \
+       return !feof(fp);                                                                                  \
+}
+
+DEFINE_MULTIPLE_READ_FUNCTION ( SBYTE,  SBYTE)
+DEFINE_MULTIPLE_READ_FUNCTION (UBYTE, UBYTE)
+
+DEFINE_MULTIPLE_READ_FUNCTION (M_SWORD,   SWORD)
+DEFINE_MULTIPLE_READ_FUNCTION (M_UWORD, UWORD)
+DEFINE_MULTIPLE_READ_FUNCTION (I_SWORD,   SWORD)
+DEFINE_MULTIPLE_READ_FUNCTION (I_UWORD, UWORD)
+
+DEFINE_MULTIPLE_READ_FUNCTION (M_SLONG,   SLONG)
+DEFINE_MULTIPLE_READ_FUNCTION (M_ULONG, ULONG)
+DEFINE_MULTIPLE_READ_FUNCTION (I_SLONG,   SLONG)
+DEFINE_MULTIPLE_READ_FUNCTION (I_ULONG, ULONG)
diff --git a/libs/oldmik/src/mplayer.c b/libs/oldmik/src/mplayer.c
new file mode 100644 (file)
index 0000000..cbf642b
--- /dev/null
@@ -0,0 +1,1386 @@
+/*\r
+\r
+Name:\r
+MPLAYER.C\r
+\r
+Description:\r
+The actual modplaying routines\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <stdlib.h>\r
+#include "mikmod.h"\r
+\r
+UNIMOD *pf;                     /* <- this modfile is being played */\r
+UWORD reppos;                   /* patternloop position */\r
+UWORD repcnt;                   /* times to loop */\r
+UWORD vbtick;                   /* tick counter */\r
+UWORD patbrk;                   /* position where to start a new pattern */\r
+UBYTE patdly;                   /* patterndelay counter */\r
+UBYTE patdly2;                  /* patterndelay counter */\r
+UWORD numrow;                   /* number of rows on current pattern */\r
+SWORD  posjmp;                   /*      flag to indicate a position jump is needed...\r
+                                                       changed since 1.00: now also indicates the\r
+                                                       direction the position has to jump to:\r
+\r
+                                                       0: Don't do anything\r
+                                                       1: Jump back 1 position\r
+                                                       2: Restart on current position\r
+                                                       3: Jump forward 1 position\r
+                                               */\r
+int   forbid;                   /* forbidflag */\r
+static int isfirst;\r
+\r
+/*\r
+       Set forbid to 1 when you want to modify any of the mp_sngpos, mp_patpos etc.\r
+       variables and clear it when you're done. This prevents getting strange\r
+       results due to intermediate interrupts.\r
+*/\r
+\r
+\r
+AUDTMP mp_audio[32];    /* max 32 channels */\r
+UBYTE  mp_bpm;          /* beats-per-minute speed */\r
+UWORD  mp_patpos;       /* current row number (0-255) */\r
+SWORD  mp_sngpos;       /* current song position */\r
+UWORD  mp_sngspd;       /* current songspeed */\r
+UWORD  mp_channel;      /* channel it's working on */\r
+BOOL   mp_extspd=1;     /* extended speed flag, default enabled */\r
+BOOL   mp_panning=1;    /* panning flag, default enabled */\r
+BOOL   mp_loop=0;       /* loop module ? */\r
+UBYTE  mp_volume=100;   /* song volume (0-100) (or user volume) */\r
+\r
+static SBYTE globalvolume=64;  /* global volume */\r
+static UBYTE globalslide;\r
+\r
+AUDTMP *a;                              /* current AUDTMP it's working on */\r
+\r
+\r
+UWORD mytab[12]={\r
+       1712*16,1616*16,1524*16,1440*16,1356*16,1280*16,\r
+       1208*16,1140*16,1076*16,1016*16,960*16,907*16\r
+};\r
+\r
+static UBYTE VibratoTable[32]={\r
+       0,24,49,74,97,120,141,161,\r
+       180,197,212,224,235,244,250,253,\r
+       255,253,250,244,235,224,212,197,\r
+       180,161,141,120,97,74,49,24\r
+};\r
+\r
+\r
+/* linear periods to frequency translation table: */\r
+\r
+UWORD lintab[768]={\r
+16726,16741,16756,16771,16786,16801,16816,16832,16847,16862,16877,16892,16908,16923,16938,16953,\r
+16969,16984,16999,17015,17030,17046,17061,17076,17092,17107,17123,17138,17154,17169,17185,17200,\r
+17216,17231,17247,17262,17278,17293,17309,17325,17340,17356,17372,17387,17403,17419,17435,17450,\r
+17466,17482,17498,17513,17529,17545,17561,17577,17593,17608,17624,17640,17656,17672,17688,17704,\r
+17720,17736,17752,17768,17784,17800,17816,17832,17848,17865,17881,17897,17913,17929,17945,17962,\r
+17978,17994,18010,18027,18043,18059,18075,18092,18108,18124,18141,18157,18174,18190,18206,18223,\r
+18239,18256,18272,18289,18305,18322,18338,18355,18372,18388,18405,18421,18438,18455,18471,18488,\r
+18505,18521,18538,18555,18572,18588,18605,18622,18639,18656,18672,18689,18706,18723,18740,18757,\r
+18774,18791,18808,18825,18842,18859,18876,18893,18910,18927,18944,18961,18978,18995,19013,19030,\r
+19047,19064,19081,19099,19116,19133,19150,19168,19185,19202,19220,19237,19254,19272,19289,19306,\r
+19324,19341,19359,19376,19394,19411,19429,19446,19464,19482,19499,19517,19534,19552,19570,19587,\r
+19605,19623,19640,19658,19676,19694,19711,19729,19747,19765,19783,19801,19819,19836,19854,19872,\r
+19890,19908,19926,19944,19962,19980,19998,20016,20034,20052,20071,20089,20107,20125,20143,20161,\r
+20179,20198,20216,20234,20252,20271,20289,20307,20326,20344,20362,20381,20399,20418,20436,20455,\r
+20473,20492,20510,20529,20547,20566,20584,20603,20621,20640,20659,20677,20696,20715,20733,20752,\r
+20771,20790,20808,20827,20846,20865,20884,20902,20921,20940,20959,20978,20997,21016,21035,21054,\r
+21073,21092,21111,21130,21149,21168,21187,21206,21226,21245,21264,21283,21302,21322,21341,21360,\r
+21379,21399,21418,21437,21457,21476,21496,21515,21534,21554,21573,21593,21612,21632,21651,21671,\r
+21690,21710,21730,21749,21769,21789,21808,21828,21848,21867,21887,21907,21927,21946,21966,21986,\r
+22006,22026,22046,22066,22086,22105,22125,22145,22165,22185,22205,22226,22246,22266,22286,22306,\r
+22326,22346,22366,22387,22407,22427,22447,22468,22488,22508,22528,22549,22569,22590,22610,22630,\r
+22651,22671,22692,22712,22733,22753,22774,22794,22815,22836,22856,22877,22897,22918,22939,22960,\r
+22980,23001,23022,23043,23063,23084,23105,23126,23147,23168,23189,23210,23230,23251,23272,23293,\r
+23315,23336,23357,23378,23399,23420,23441,23462,23483,23505,23526,23547,23568,23590,23611,23632,\r
+23654,23675,23696,23718,23739,23761,23782,23804,23825,23847,23868,23890,23911,23933,23954,23976,\r
+23998,24019,24041,24063,24084,24106,24128,24150,24172,24193,24215,24237,24259,24281,24303,24325,\r
+24347,24369,24391,24413,24435,24457,24479,24501,24523,24545,24567,24590,24612,24634,24656,24679,\r
+24701,24723,24746,24768,24790,24813,24835,24857,24880,24902,24925,24947,24970,24992,25015,25038,\r
+25060,25083,25105,25128,25151,25174,25196,25219,25242,25265,25287,25310,25333,25356,25379,25402,\r
+25425,25448,25471,25494,25517,25540,25563,25586,25609,25632,25655,25678,25702,25725,25748,25771,\r
+25795,25818,25841,25864,25888,25911,25935,25958,25981,26005,26028,26052,26075,26099,26123,26146,\r
+26170,26193,26217,26241,26264,26288,26312,26336,26359,26383,26407,26431,26455,26479,26502,26526,\r
+26550,26574,26598,26622,26646,26670,26695,26719,26743,26767,26791,26815,26839,26864,26888,26912,\r
+26937,26961,26985,27010,27034,27058,27083,27107,27132,27156,27181,27205,27230,27254,27279,27304,\r
+27328,27353,27378,27402,27427,27452,27477,27502,27526,27551,27576,27601,27626,27651,27676,27701,\r
+27726,27751,27776,27801,27826,27851,27876,27902,27927,27952,27977,28003,28028,28053,28078,28104,\r
+28129,28155,28180,28205,28231,28256,28282,28307,28333,28359,28384,28410,28435,28461,28487,28513,\r
+28538,28564,28590,28616,28642,28667,28693,28719,28745,28771,28797,28823,28849,28875,28901,28927,\r
+28953,28980,29006,29032,29058,29084,29111,29137,29163,29190,29216,29242,29269,29295,29322,29348,\r
+29375,29401,29428,29454,29481,29507,29534,29561,29587,29614,29641,29668,29694,29721,29748,29775,\r
+29802,29829,29856,29883,29910,29937,29964,29991,30018,30045,30072,30099,30126,30154,30181,30208,\r
+30235,30263,30290,30317,30345,30372,30400,30427,30454,30482,30509,30537,30565,30592,30620,30647,\r
+30675,30703,30731,30758,30786,30814,30842,30870,30897,30925,30953,30981,31009,31037,31065,31093,\r
+31121,31149,31178,31206,31234,31262,31290,31319,31347,31375,31403,31432,31460,31489,31517,31546,\r
+31574,31602,31631,31660,31688,31717,31745,31774,31803,31832,31860,31889,31918,31947,31975,32004,\r
+32033,32062,32091,32120,32149,32178,32207,32236,32265,32295,32324,32353,32382,32411,32441,32470,\r
+32499,32529,32558,32587,32617,32646,32676,32705,32735,32764,32794,32823,32853,32883,32912,32942,\r
+32972,33002,33031,33061,33091,33121,33151,33181,33211,33241,33271,33301,33331,33361,33391,33421\r
+};\r
+\r
+\r
+\r
+\r
+#define LOGFAC 2*16\r
+\r
+UWORD logtab[]={\r
+       LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,\r
+       LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,\r
+       LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,\r
+       LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,\r
+       LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,\r
+       LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,\r
+       LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,\r
+       LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,\r
+       LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,\r
+       LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,\r
+       LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,\r
+       LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,\r
+       LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431\r
+};\r
+\r
+\r
+SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)\r
+{\r
+       SWORD dp,dv,di;\r
+\r
+       if(p1==p2) return v1;\r
+\r
+       dv=v2-v1;\r
+       dp=p2-p1;\r
+       di=p-p1;\r
+\r
+       return v1 + ((SLONG)(di*dv) / dp);\r
+}\r
+\r
+\r
+UWORD getlinearperiod(UBYTE note,UWORD fine)\r
+{\r
+       return((10L*12*16*4)-((UWORD)note*16*4)-(fine/2)+64);\r
+}\r
+\r
+\r
+UWORD getlogperiod(UBYTE note,UWORD fine)\r
+{\r
+       UBYTE n,o;\r
+       UWORD p1,p2,i;\r
+\r
+       n=note%12;\r
+       o=note/12;\r
+       i=(n<<3)+(fine>>4);                     /* n*8 + fine/16 */\r
+\r
+       p1=logtab[i];\r
+       p2=logtab[i+1];\r
+\r
+       return(Interpolate(fine/16,0,15,p1,p2)>>o);\r
+}\r
+\r
+\r
+UWORD getoldperiod(UBYTE note,UWORD c2spd)\r
+{\r
+       UBYTE n,o;\r
+       ULONG period;\r
+\r
+       if(!c2spd) return 4242;         /* <- prevent divide overflow.. (42 eheh) */\r
+\r
+       n=note%12;\r
+       o=note/12;\r
+       period=((8363L*mytab[n]) >> o )/c2spd;\r
+       return period;\r
+}\r
+\r
+\r
+\r
+UWORD GetPeriod(UBYTE note,UWORD c2spd)\r
+{\r
+       if(pf->flags&UF_XMPERIODS){\r
+               return (pf->flags&UF_LINEAR) ? getlinearperiod(note,c2spd) : getlogperiod(note,c2spd);\r
+       }\r
+       return(getoldperiod(note,c2spd));\r
+}\r
+\r
+\r
+\r
+void DoEEffects(UBYTE dat)\r
+{\r
+       UBYTE nib;\r
+\r
+       nib=dat&0xf;\r
+\r
+       switch(dat>>4){\r
+\r
+               case 0x0:       /* filter toggle, not supported */\r
+                               break;\r
+\r
+               case 0x1:       /* fineslide up */\r
+                               if(!vbtick) a->tmpperiod-=(nib<<2);\r
+                               break;\r
+\r
+               case 0x2:       /* fineslide dn */\r
+                               if(!vbtick) a->tmpperiod+=(nib<<2);\r
+                               break;\r
+\r
+               case 0x3:       /* glissando ctrl */\r
+                               a->glissando=nib;\r
+                               break;\r
+\r
+               case 0x4:       /* set vibrato waveform */\r
+                               a->wavecontrol&=0xf0;\r
+                               a->wavecontrol|=nib;\r
+                               break;\r
+\r
+               case 0x5:       /* set finetune */\r
+/*                              a->c2spd=finetune[nib]; */\r
+/*                              a->tmpperiod=GetPeriod(a->note,pf->samples[a->sample].transpose,a->c2spd); */\r
+                               break;\r
+\r
+               case 0x6:       /* set patternloop */\r
+\r
+                               if(vbtick) break;\r
+\r
+                               /* hmm.. this one is a real kludge. But now it\r
+                                  works. */\r
+\r
+                               if(nib){                /* set reppos or repcnt ? */\r
+\r
+                                       /* set repcnt, so check if repcnt already is set,\r
+                                          which means we are already looping */\r
+\r
+                                       if(repcnt>0)\r
+                                               repcnt--;               /* already looping, decrease counter */\r
+                                       else\r
+                                               repcnt=nib;             /* not yet looping, so set repcnt */\r
+\r
+                                       if(repcnt)                      /* jump to reppos if repcnt>0 */\r
+                                               mp_patpos=reppos;\r
+                               }\r
+                               else{\r
+                                       reppos=mp_patpos-1;     /* set reppos */\r
+                               }\r
+                               break;\r
+\r
+\r
+               case 0x7:       /* set tremolo waveform */\r
+                               a->wavecontrol&=0x0f;\r
+                               a->wavecontrol|=nib<<4;\r
+                               break;\r
+\r
+                case 0x8:       /* set panning */\r
+                                if(mp_panning){\r
+                                        nib<<=4;\r
+                                        a->panning=nib;\r
+                                        pf->panning[mp_channel]=nib;\r
+                                }\r
+                               break;\r
+\r
+               case 0x9:       /* retrig note */\r
+\r
+                               /* only retrigger if\r
+                                  data nibble > 0 */\r
+\r
+                               if(nib>0){\r
+                                       if(a->retrig==0){\r
+\r
+                                               /* when retrig counter reaches 0,\r
+                                                  reset counter and restart the sample */\r
+\r
+                                               a->kick=1;\r
+                                               a->retrig=nib;\r
+                                       }\r
+                                       a->retrig--; /* countdown */\r
+                               }\r
+                               break;\r
+\r
+               case 0xa:       /* fine volume slide up */\r
+                               if(vbtick) break;\r
+\r
+                               a->tmpvolume+=nib;\r
+                               if(a->tmpvolume>64) a->tmpvolume=64;\r
+                               break;\r
+\r
+               case 0xb:       /* fine volume slide dn */\r
+                               if(vbtick) break;\r
+\r
+                               a->tmpvolume-=nib;\r
+                               if(a->tmpvolume<0) a->tmpvolume=0;\r
+                               break;\r
+\r
+               case 0xc:       /* cut note */\r
+\r
+                               /* When vbtick reaches the cut-note value,\r
+                                  turn the volume to zero ( Just like\r
+                                  on the amiga) */\r
+\r
+                               if(vbtick>=nib){\r
+                                       a->tmpvolume=0;                 /* just turn the volume down */\r
+                               }\r
+                               break;\r
+\r
+               case 0xd:       /* note delay */\r
+\r
+                               /* delay the start of the\r
+                                  sample until vbtick==nib */\r
+\r
+                               if(vbtick==nib){\r
+                                       a->kick=1;\r
+                               }\r
+                               else a->kick=0;\r
+                               break;\r
+\r
+               case 0xe:       /* pattern delay */\r
+                               if(vbtick) break;\r
+                               if(!patdly2) patdly=nib+1;                              /* only once (when vbtick=0) */\r
+                               break;\r
+\r
+               case 0xf:       /* invert loop, not supported */\r
+                               break;\r
+       }\r
+}\r
+\r
+\r
+void DoVibrato(void)\r
+{\r
+       UBYTE q;\r
+       UWORD temp;\r
+\r
+       q=(a->vibpos>>2)&0x1f;\r
+\r
+       switch(a->wavecontrol&3){\r
+\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+\r
+               case 1: /* ramp down */\r
+                       q<<=3;\r
+                       if(a->vibpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+\r
+               case 2: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+       }\r
+\r
+       temp*=a->vibdepth;\r
+       temp>>=7;\r
+       temp<<=2;\r
+\r
+       if(a->vibpos>=0)\r
+               a->period=a->tmpperiod+temp;\r
+       else\r
+               a->period=a->tmpperiod-temp;\r
+\r
+       if(vbtick) a->vibpos+=a->vibspd;        /* do not update when vbtick==0 */\r
+}\r
+\r
+\r
+\r
+void DoTremolo(void)\r
+{\r
+       UBYTE q;\r
+       UWORD temp;\r
+\r
+       q=(a->trmpos>>2)&0x1f;\r
+\r
+       switch((a->wavecontrol>>4)&3){\r
+\r
+               case 0: /* sine */\r
+                       temp=VibratoTable[q];\r
+                       break;\r
+\r
+               case 1: /* ramp down */\r
+                       q<<=3;\r
+                       if(a->trmpos<0) q=255-q;\r
+                       temp=q;\r
+                       break;\r
+\r
+               case 2: /* square wave */\r
+                       temp=255;\r
+                       break;\r
+       }\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
+       }\r
+       else{\r
+               a->volume=a->tmpvolume-temp;\r
+               if(a->volume<0) a->volume=0;\r
+       }\r
+\r
+       if(vbtick) a->trmpos+=a->trmspd;        /* do not update when vbtick==0 */\r
+}\r
+\r
+\r
+void DoVolSlide(UBYTE dat)\r
+{\r
+       if(!vbtick) return;             /* do not update when vbtick==0 */\r
+\r
+       a->tmpvolume+=dat>>4;           /* volume slide */\r
+       a->tmpvolume-=dat&0xf;\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoS3MVolSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               a->s3mvolslide=inf;\r
+       }\r
+       inf=a->s3mvolslide;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0){\r
+               a->tmpvolume-=lo;\r
+       }\r
+       else if(lo==0){\r
+               a->tmpvolume+=hi;\r
+       }\r
+       else if(hi==0xf){\r
+               if(!vbtick) a->tmpvolume-=lo;\r
+       }\r
+       else if(lo==0xf){\r
+               if(!vbtick) a->tmpvolume+=hi;\r
+       }\r
+\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMVolSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               a->s3mvolslide=inf;\r
+       }\r
+       inf=a->s3mvolslide;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0)\r
+               a->tmpvolume-=lo;\r
+       else\r
+               a->tmpvolume+=hi;\r
+\r
+       if(a->tmpvolume<0) a->tmpvolume=0;\r
+       else if(a->tmpvolume>64) a->tmpvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMGlobalSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+\r
+       if(inf){\r
+               globalslide=inf;\r
+       }\r
+       inf=globalslide;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       if(hi==0)\r
+               globalvolume-=lo;\r
+       else\r
+               globalvolume+=hi;\r
+\r
+       if(globalvolume<0) globalvolume=0;\r
+       else if(globalvolume>64) globalvolume=64;\r
+}\r
+\r
+\r
+\r
+void DoXMPanSlide(UBYTE inf)\r
+{\r
+       UBYTE lo,hi;\r
+       SWORD pan;\r
+\r
+\r
+       if(inf!=0) a->pansspd=inf;\r
+       else inf=a->pansspd;\r
+\r
+       if(!vbtick) return;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       /* slide right has absolute priority: */\r
+\r
+       if(hi) lo=0;\r
+\r
+       pan=a->panning;\r
+\r
+       pan-=lo;\r
+       pan+=hi;\r
+\r
+       if(pan<0) pan=0;\r
+       if(pan>255) pan=255;\r
+\r
+       a->panning=pan;\r
+}\r
+\r
+\r
+\r
+void DoS3MSlideDn(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if(inf!=0) a->slidespeed=inf;\r
+       else inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(hi==0xf){\r
+               if(!vbtick) a->tmpperiod+=(UWORD)lo<<2;\r
+       }\r
+       else if(hi==0xe){\r
+               if(!vbtick) a->tmpperiod+=lo;\r
+       }\r
+       else{\r
+               if(vbtick) a->tmpperiod+=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+\r
+\r
+void DoS3MSlideUp(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       if(inf!=0) a->slidespeed=inf;\r
+       else inf=a->slidespeed;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(hi==0xf){\r
+               if(!vbtick) a->tmpperiod-=(UWORD)lo<<2;\r
+       }\r
+       else if(hi==0xe){\r
+               if(!vbtick) a->tmpperiod-=lo;\r
+       }\r
+       else{\r
+               if(vbtick) a->tmpperiod-=(UWORD)inf<<2;\r
+       }\r
+}\r
+\r
+\r
+\r
+void DoS3MTremor(UBYTE inf)\r
+{\r
+       UBYTE on,off;\r
+\r
+       if(inf!=0) a->s3mtronof=inf;\r
+       else inf=a->s3mtronof;\r
+\r
+       if(!vbtick) return;\r
+\r
+       on=(inf>>4)+1;\r
+       off=(inf&0xf)+1;\r
+\r
+       a->s3mtremor%=(on+off);\r
+       a->volume=(a->s3mtremor < on ) ? a->tmpvolume:0;\r
+       a->s3mtremor++;\r
+}\r
+\r
+\r
+\r
+void DoS3MRetrig(UBYTE inf)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       hi=inf>>4;\r
+       lo=inf&0xf;\r
+\r
+       if(lo){\r
+               a->s3mrtgslide=hi;\r
+               a->s3mrtgspeed=lo;\r
+       }\r
+\r
+       if(hi){\r
+               a->s3mrtgslide=hi;\r
+       }\r
+\r
+       /* only retrigger if\r
+          lo nibble > 0 */\r
+\r
+       if(a->s3mrtgspeed>0){\r
+               if(a->retrig==0){\r
+\r
+                       /* when retrig counter reaches 0,\r
+                          reset counter and restart the sample */\r
+\r
+                       a->kick=1;\r
+                       a->retrig=a->s3mrtgspeed;\r
+\r
+                       if(vbtick){                     /* don't slide on first retrig */\r
+                               switch(a->s3mrtgslide){\r
+\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
+\r
+                                       case 6:\r
+                                               a->tmpvolume=(2*a->tmpvolume)/3;\r
+                                               break;\r
+\r
+                                       case 7:\r
+                                               a->tmpvolume=a->tmpvolume>>1;\r
+                                               break;\r
+\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
+\r
+                                       case 0xe:\r
+                                               a->tmpvolume=(3*a->tmpvolume)/2;\r
+                                               break;\r
+\r
+                                       case 0xf:\r
+                                               a->tmpvolume=a->tmpvolume<<1;\r
+                                               break;\r
+                               }\r
+                               if(a->tmpvolume<0) a->tmpvolume=0;\r
+                               if(a->tmpvolume>64) a->tmpvolume=64;\r
+                       }\r
+               }\r
+               a->retrig--; /* countdown */\r
+       }\r
+}\r
+\r
+\r
+void DoS3MSpeed(UBYTE speed)\r
+{\r
+       if(vbtick || patdly2) return;\r
+\r
+       if(speed){                      /* <- v0.44 bugfix */\r
+               mp_sngspd=speed;\r
+               vbtick=0;\r
+       }\r
+}\r
+\r
+\r
+void DoS3MTempo(UBYTE tempo)\r
+{\r
+       if(vbtick || patdly2) return;\r
+       mp_bpm=tempo;\r
+}\r
+\r
+\r
+void DoToneSlide(void)\r
+{\r
+       int dist,t;\r
+\r
+       if(!vbtick){\r
+               a->tmpperiod=a->period;\r
+               return;\r
+       }\r
+\r
+       /* We have to slide a->period towards a->wantedperiod, so\r
+          compute the difference between those two values */\r
+\r
+       dist=a->period-a->wantedperiod;\r
+\r
+       if( dist==0 ||                          /* if they are equal */\r
+               a->portspeed>abs(dist) ){       /* or if portamentospeed is too big */\r
+\r
+               a->period=a->wantedperiod;      /* make tmpperiod equal tperiod */\r
+       }\r
+       else if(dist>0){                                /* dist>0 ? */\r
+               a->period-=a->portspeed;        /* then slide up */\r
+       }\r
+       else\r
+               a->period+=a->portspeed;        /* dist<0 -> slide down */\r
+\r
+/*      if(a->glissando){\r
+\r
+                If glissando is on, find the nearest\r
+                  halfnote to a->tmpperiod\r
+\r
+               for(t=0;t<60;t++){\r
+                       if(a->tmpperiod>=npertab[a->finetune][t]) break;\r
+               }\r
+\r
+               a->period=npertab[a->finetune][t];\r
+       }\r
+       else\r
+*/\r
+       a->tmpperiod=a->period;\r
+}\r
+\r
+\r
+void DoPTEffect0(UBYTE dat)\r
+{\r
+       UBYTE note;\r
+\r
+       note=a->note;\r
+\r
+       if(dat!=0){\r
+               switch(vbtick%3){\r
+                       case 1:\r
+                               note+=(dat>>4); break;\r
+                       case 2:\r
+                               note+=(dat&0xf); break;\r
+               }\r
+               a->period=GetPeriod(note+a->transpose,a->c2spd);\r
+               a->ownper=1;\r
+       }\r
+}\r
+\r
+\r
+void PlayNote(void)\r
+{\r
+       INSTRUMENT *i;\r
+       SAMPLE *s;\r
+       UWORD period;\r
+       UBYTE inst,c;\r
+       UBYTE note;\r
+\r
+       if(a->row==NULL) return;\r
+\r
+       UniSetRow(a->row);\r
+\r
+       while(c=UniGetByte()){\r
+\r
+               switch(c){\r
+\r
+                       case UNI_NOTE:\r
+                               note=UniGetByte();\r
+\r
+                               if(note==96){                   /* key off ? */\r
+                                       a->keyon=0;\r
+                                       if(a->i && !(a->i->volflg & EF_ON)){\r
+                                               a->tmpvolume=0;\r
+                                       }\r
+                               }\r
+                               else{\r
+                                       a->note=note;\r
+\r
+                                       period=GetPeriod(note+a->transpose,a->c2spd);\r
+\r
+                                       a->wantedperiod=period;\r
+                                       a->tmpperiod=period;\r
+\r
+                                       a->kick=1;\r
+                                       a->start=0;\r
+\r
+                                       /* retrig tremolo and vibrato waves ? */\r
+\r
+                                       if(!(a->wavecontrol&0x80)) a->trmpos=0;\r
+                                       if(!(a->wavecontrol&0x08)) a->vibpos=0;\r
+                               }\r
+                               break;\r
+\r
+                       case UNI_INSTRUMENT:\r
+                               inst=UniGetByte();\r
+                               if(inst>=pf->numins) break;             /* <- safety valve */\r
+\r
+                               a->sample=inst;\r
+\r
+                               i=&pf->instruments[inst];\r
+                               a->i=i;\r
+\r
+                               if(i->samplenumber[a->note]>=i->numsmp) break;\r
+\r
+                               s=&i->samples[i->samplenumber[a->note]];\r
+                               a->s=s;\r
+\r
+                               /* channel or instrument determined panning ? */\r
+\r
+                               if(s->flags& SF_OWNPAN){\r
+                                       a->panning=s->panning;\r
+                               }\r
+                               else{\r
+                                       a->panning=pf->panning[mp_channel];\r
+                               }\r
+\r
+                               a->transpose=s->transpose;\r
+                               a->handle=s->handle;\r
+                               a->tmpvolume=s->volume;\r
+                               a->volume=s->volume;\r
+                               a->c2spd=s->c2spd;\r
+                               a->retrig=0;\r
+                               a->s3mtremor=0;\r
+\r
+                               period=GetPeriod(a->note+a->transpose,a->c2spd);\r
+\r
+                               a->wantedperiod=period;\r
+                               a->tmpperiod=period;\r
+                               break;\r
+\r
+                       default:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+void PlayEffects(void)\r
+{\r
+       UBYTE c,dat;\r
+\r
+       if(a->row==NULL) return;\r
+\r
+       UniSetRow(a->row);\r
+\r
+       a->ownper=0;\r
+       a->ownvol=0;\r
+\r
+       while(c=UniGetByte()){\r
+\r
+               switch(c){\r
+\r
+                       case UNI_NOTE:\r
+                       case UNI_INSTRUMENT:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT0:\r
+                               DoPTEffect0(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT1:\r
+                               dat=UniGetByte();\r
+                               if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
+                               if(vbtick) a->tmpperiod-=a->slidespeed;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT2:\r
+                               dat=UniGetByte();\r
+                               if(dat!=0) a->slidespeed=(UWORD)dat<<2;\r
+                               if(vbtick) a->tmpperiod+=a->slidespeed;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT3:\r
+                               dat=UniGetByte();\r
+                               a->kick=0;                              /* temp XM fix */\r
+                               if(dat!=0){\r
+                                       a->portspeed=dat;\r
+                                       a->portspeed<<=2;\r
+                               }\r
+                               DoToneSlide();\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT4:\r
+                               dat=UniGetByte();\r
+                               if(dat&0x0f) a->vibdepth=dat&0xf;\r
+                               if(dat&0xf0) a->vibspd=(dat&0xf0)>>2;\r
+                               DoVibrato();\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT5:\r
+                               dat=UniGetByte();\r
+                               a->kick=0;\r
+                               DoToneSlide();\r
+                               DoVolSlide(dat);\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT6:\r
+                               dat=UniGetByte();\r
+                               DoVibrato();\r
+                               DoVolSlide(dat);\r
+                               a->ownper=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT7:\r
+                               dat=UniGetByte();\r
+                               if(dat&0x0f) a->trmdepth=dat&0xf;\r
+                               if(dat&0xf0) a->trmspd=(dat&0xf0)>>2;\r
+                               DoTremolo();\r
+                               a->ownvol=1;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT8:\r
+                               dat=UniGetByte();\r
+                                if(mp_panning){\r
+                                        a->panning=dat;\r
+                                        pf->panning[mp_channel]=dat;\r
+                                }\r
+                               break;\r
+\r
+                       case UNI_PTEFFECT9:\r
+                               dat=UniGetByte();\r
+                               if(dat) a->soffset=(UWORD)dat<<8;       /* <- 0.43 fix.. */\r
+                               a->start=a->soffset;\r
+                               if(a->start>a->s->length) a->start=a->s->length;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTA:\r
+                               DoVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTB:\r
+                               dat=UniGetByte();\r
+                               if(patdly2) break;\r
+                               patbrk=0;\r
+                               mp_sngpos=dat-1;\r
+                               posjmp=3;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTC:\r
+                               dat=UniGetByte();\r
+                               if(vbtick) break;\r
+                               if(dat>64) dat=64;\r
+                               a->tmpvolume=dat;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTD:\r
+                               dat=UniGetByte();\r
+                               if(patdly2) break;\r
+                               {\r
+                                       int hi=(dat&0xf0)>>4;\r
+                                       int     lo=(dat&0xf);\r
+                                       patbrk=(hi*10)+lo;\r
+                               }\r
+                               if(patbrk>64) patbrk=64;        /* <- v0.42 fix */\r
+                               posjmp=3;\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTE:\r
+                               DoEEffects(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_PTEFFECTF:\r
+                               dat=UniGetByte();\r
+\r
+                               if(vbtick || patdly2) break;\r
+\r
+                               if(mp_extspd && dat>=0x20){\r
+                                       mp_bpm=dat;\r
+                               }\r
+                               else{\r
+                                       if(dat){                        /* <- v0.44 bugfix */\r
+                                               mp_sngspd=dat;\r
+                                               vbtick=0;\r
+                                       }\r
+                               }\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTD:\r
+                               DoS3MVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTE:\r
+                               DoS3MSlideDn(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTF:\r
+                               DoS3MSlideUp(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTI:\r
+                               DoS3MTremor(UniGetByte());\r
+                               a->ownvol=1;\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTQ:\r
+                               DoS3MRetrig(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTA:\r
+                               DoS3MSpeed(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_S3MEFFECTT:\r
+                               DoS3MTempo(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTA:\r
+                               DoXMVolSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTG:\r
+                               globalvolume=UniGetByte();\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTH:\r
+                               DoXMGlobalSlide(UniGetByte());\r
+                               break;\r
+\r
+                       case UNI_XMEFFECTP:\r
+                               DoXMPanSlide(UniGetByte());\r
+                               break;\r
+\r
+                       default:\r
+                               UniSkipOpcode(c);\r
+                               break;\r
+               }\r
+       }\r
+\r
+       if(!a->ownper){\r
+               a->period=a->tmpperiod;\r
+       }\r
+\r
+       if(!a->ownvol){\r
+               a->volume=a->tmpvolume;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)\r
+{\r
+       return(Interpolate(p,a->pos,b->pos,a->val,b->val));\r
+}\r
+\r
+\r
+SWORD DoPan(SWORD envpan,SWORD pan)\r
+{\r
+       return(pan + (((envpan-128)*(128-abs(pan-128)))/128));\r
+}\r
+\r
+\r
+\r
+void StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE sus,UBYTE beg,UBYTE end,ENVPT *p)\r
+{\r
+       t->flg=flg;\r
+       t->pts=pts;\r
+       t->sus=sus;\r
+       t->beg=beg;\r
+       t->end=end;\r
+       t->env=p;\r
+       t->p=0;\r
+       t->a=0;\r
+       t->b=1;\r
+}\r
+\r
+\r
+\r
+SWORD ProcessEnvelope(ENVPR *t,SWORD v,UBYTE keyon)\r
+{\r
+       if(t->flg & EF_ON){\r
+\r
+               /* panning active? -> copy variables */\r
+\r
+               UBYTE a,b;\r
+               UWORD p;\r
+\r
+               a=t->a;\r
+               b=t->b;\r
+               p=t->p;\r
+\r
+               /* compute the envelope value between points a and b */\r
+\r
+               v=InterpolateEnv(p,&t->env[a],&t->env[b]);\r
+\r
+               /* Should we sustain? (sustain flag on, key-on, point a is the sustain\r
+                  point, and the pointer is exactly on point a) */\r
+\r
+               if((t->flg & EF_SUSTAIN) && keyon && a==t->sus && p==t->env[a].pos){\r
+                       /* do nothing */\r
+               }\r
+               else{\r
+                       /* don't sustain, so increase pointer. */\r
+\r
+                       p++;\r
+\r
+                       /* pointer reached point b? */\r
+\r
+                       if(p >= t->env[b].pos){\r
+\r
+                               /* shift points a and b */\r
+\r
+                               a=b; b++;\r
+\r
+                               if(t->flg & EF_LOOP){\r
+                                       if(b > t->end){\r
+                                               a=t->beg;\r
+                                               b=a+1;\r
+                                               p=t->env[a].pos;\r
+                                       }\r
+                               }\r
+                               else{\r
+                                       if(b >= t->pts){\r
+                                               b--;\r
+                                               p--;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               t->a=a;\r
+               t->b=b;\r
+               t->p=p;\r
+       }\r
+       return v;\r
+}\r
+\r
+/*\r
+long GetFreq2(long period)\r
+{\r
+       float frequency;\r
+\r
+       frequency=8363.0*pow(2,((6*12*16*4.0)-period)/(12*16*4.0));\r
+       return(floor(frequency));\r
+}\r
+*/\r
+\r
+long GetFreq2(long period)\r
+{\r
+       int okt;\r
+       long frequency;\r
+       period=7680-period;\r
+       okt=period/768;\r
+       frequency=lintab[period%768];\r
+       frequency<<=2;\r
+       return(frequency>>(7-okt));\r
+}\r
+\r
+void MP_HandleTick(void)\r
+{\r
+       int z,t,tr;\r
+       ULONG tmpvol;\r
+\r
+       if(isfirst){           \r
+               /* don't handle the very first ticks, this allows the\r
+                  other hardware to settle down so we don't loose any \r
+                  starting notes\r
+               */\r
+               isfirst--;\r
+               return;\r
+       }\r
+\r
+       if(forbid) return;      /* don't go any further when forbid is true */\r
+\r
+       if(MP_Ready()) return;\r
+\r
+       if(++vbtick>=mp_sngspd){\r
+\r
+               mp_patpos++;\r
+               vbtick=0;\r
+\r
+               if(patdly){\r
+                       patdly2=patdly;\r
+                       patdly=0;\r
+               }\r
+\r
+               if(patdly2){\r
+\r
+                       /* patterndelay active */\r
+\r
+                       if(--patdly2){\r
+                               mp_patpos--;    /* so turn back mp_patpos by 1 */\r
+                       }\r
+               }\r
+\r
+               /* Do we have to get a new patternpointer ?\r
+                  (when mp_patpos reaches 64 or when\r
+                  a patternbreak is active) */\r
+\r
+               if( mp_patpos == numrow ) posjmp=3;\r
+\r
+\r
+               if( posjmp ){\r
+                       mp_patpos=patbrk;\r
+                       mp_sngpos+=(posjmp-2);\r
+                       patbrk=posjmp=0;\r
+                       if(mp_sngpos>=pf->numpos){\r
+                               if(!mp_loop) return;\r
+                               mp_sngpos=pf->reppos;\r
+                       }\r
+                       if(mp_sngpos<0) mp_sngpos=pf->numpos-1;\r
+               }\r
+\r
+\r
+               if(!patdly2){\r
+\r
+                       for(t=0;t<pf->numchn;t++){\r
+\r
+                               tr=pf->patterns[(pf->positions[mp_sngpos]*pf->numchn)+t];\r
+                               numrow=pf->pattrows[pf->positions[mp_sngpos]];\r
+\r
+                               mp_channel=t;\r
+                               a=&mp_audio[t];\r
+                               a->row=(tr<pf->numtrk) ? UniFindRow(pf->tracks[tr],mp_patpos) : NULL;\r
+\r
+                               PlayNote();\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* Update effects */\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               mp_channel=t;\r
+               a=&mp_audio[t];\r
+               PlayEffects();\r
+       }\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               INSTRUMENT *i;\r
+               SAMPLE *s;\r
+               SWORD envpan,envvol;\r
+\r
+               a=&mp_audio[t];\r
+               i=a->i;\r
+               s=a->s;\r
+\r
+               if(i==NULL || s==NULL) continue;\r
+\r
+               if(a->period<40) a->period=40;\r
+               if(a->period>8000) a->period=8000;\r
+\r
+               if(a->kick){\r
+                       MD_VoicePlay(t,a->handle,a->start,s->length,s->loopstart,s->loopend,s->flags);\r
+                       a->kick=0;\r
+                       a->keyon=1;\r
+\r
+                       a->fadevol=32768;\r
+\r
+                       StartEnvelope(&a->venv,i->volflg,i->volpts,i->volsus,i->volbeg,i->volend,i->volenv);\r
+                       StartEnvelope(&a->penv,i->panflg,i->panpts,i->pansus,i->panbeg,i->panend,i->panenv);\r
+               }\r
+\r
+               envvol=ProcessEnvelope(&a->venv,256,a->keyon);\r
+               envpan=ProcessEnvelope(&a->penv,128,a->keyon);\r
+\r
+               tmpvol=a->fadevol;              /* max 32768 */\r
+               tmpvol*=envvol;                 /* * max 256 */\r
+               tmpvol*=a->volume;              /* * max 64 */\r
+               tmpvol/=16384;                  /* tmpvol/(256*64) => tmpvol is max 32768 */\r
+\r
+               tmpvol*=globalvolume;   /* * max 64 */\r
+               tmpvol*=mp_volume;              /* * max 100 */\r
+               tmpvol/=3276800UL;              /* tmpvol/(64*100*512) => tmpvol is max 64 */\r
+\r
+               MD_VoiceSetVolume(t,tmpvol);\r
+\r
+               if(s->flags& SF_OWNPAN){\r
+                       MD_VoiceSetPanning(t,DoPan(envpan,a->panning));\r
+               }\r
+               else{\r
+                       MD_VoiceSetPanning(t,a->panning);\r
+               }\r
+\r
+               if(pf->flags&UF_LINEAR)\r
+                       MD_VoiceSetFrequency(t,GetFreq2(a->period));\r
+               else\r
+                       MD_VoiceSetFrequency(t,(3579546UL<<2)/a->period);\r
+\r
+               /*  if key-off, start substracting\r
+                       fadeoutspeed from fadevol: */\r
+\r
+               if(!a->keyon){\r
+                       if(a->fadevol>=i->volfade)\r
+                               a->fadevol-=i->volfade;\r
+                       else\r
+                               a->fadevol=0;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+void MP_Init(UNIMOD *m)\r
+{\r
+       int t;\r
+\r
+       pf=m;\r
+       reppos=0;\r
+       repcnt=0;\r
+       mp_sngpos=0;\r
+       mp_sngspd=m->initspeed;\r
+\r
+       vbtick=mp_sngspd;\r
+       patdly=0;\r
+       patdly2=0;\r
+       mp_bpm=m->inittempo;\r
+\r
+       forbid=0;\r
+       mp_patpos=0;\r
+       posjmp=2;               /* <- make sure the player fetches the first note */\r
+       patbrk=0;\r
+\r
+       isfirst=2;              /* delay start by 2 ticks */\r
+\r
+       globalvolume=64;                /* reset global volume */\r
+\r
+       /* Make sure the player doesn't start with garbage: */\r
+\r
+       for(t=0;t<pf->numchn;t++){\r
+               mp_audio[t].kick=0;\r
+               mp_audio[t].tmpvolume=0;\r
+               mp_audio[t].retrig=0;\r
+               mp_audio[t].wavecontrol=0;\r
+               mp_audio[t].glissando=0;\r
+               mp_audio[t].soffset=0;\r
+       }\r
+}\r
+\r
+\r
+\r
+int MP_Ready(void)\r
+{\r
+       return(mp_sngpos>=pf->numpos);\r
+}\r
+\r
+\r
+void MP_NextPosition(void)\r
+{\r
+       forbid=1;\r
+       posjmp=3;\r
+       patbrk=0;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r
+\r
+\r
+void MP_PrevPosition(void)\r
+{\r
+       forbid=1;\r
+       posjmp=1;\r
+       patbrk=0;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r
+\r
+\r
+void MP_SetPosition(UWORD pos)\r
+{\r
+       if(pos>=pf->numpos) pos=pf->numpos;\r
+       forbid=1;\r
+       posjmp=2;\r
+       patbrk=0;\r
+       mp_sngpos=pos;\r
+       vbtick=mp_sngspd;\r
+       forbid=0;\r
+}\r
diff --git a/libs/oldmik/src/mtypes.h b/libs/oldmik/src/mtypes.h
new file mode 100644 (file)
index 0000000..65cda6d
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef MTYPES_H\r
+#define MTYPES_H\r
+\r
+/*\r
+       MikMod atomic types:\r
+       ====================\r
+*/\r
+\r
+\r
+#ifdef __OS2__\r
+\r
+typedef signed char     SBYTE;          /* has to be 1 byte signed */\r
+typedef unsigned char   UBYTE;          /* has to be 1 byte unsigned */\r
+typedef short           SWORD;          /* has to be 2 bytes signed */\r
+typedef unsigned short  UWORD;          /* has to be 2 bytes unsigned */\r
+typedef long            SLONG;          /* has to be 4 bytes signed */\r
+/* ULONG and BOOL are already defined in OS2.H */\r
+\r
+#elif defined(__alpha)\r
+\r
+typedef char            SBYTE;          /* has to be 1 byte signed */\r
+typedef unsigned char   UBYTE;          /* has to be 1 byte unsigned */\r
+typedef short           SWORD;          /* has to be 2 bytes signed */\r
+typedef unsigned short  UWORD;          /* has to be 2 bytes unsigned */\r
+/* long is 8 bytes on dec alpha - RCA */\r
+typedef int             SLONG;          /* has to be 4 bytes signed */\r
+typedef unsigned int    ULONG;          /* has to be 4 bytes unsigned */\r
+typedef int             BOOL;           /* doesn't matter.. 0=FALSE, <>0 true */\r
+\r
+#else\r
+\r
+typedef signed char     SBYTE;          /* has to be 1 byte signed */\r
+typedef unsigned char   UBYTE;          /* has to be 1 byte unsigned */\r
+typedef short           SWORD;          /* has to be 2 bytes signed */\r
+typedef unsigned short  UWORD;          /* has to be 2 bytes unsigned */\r
+typedef long            SLONG;          /* has to be 4 bytes signed */\r
+typedef unsigned long   ULONG;          /* has to be 4 bytes unsigned */\r
+typedef int             BOOL;           /* doesn't matter.. 0=FALSE, <>0 true */\r
+\r
+#endif\r
+\r
+\r
+#ifdef __OS2__\r
+#define INCL_DOS\r
+#define INCL_MCIOS2\r
+#define INCL_MMIOOS2\r
+#include <os2.h>\r
+#include <os2me.h>\r
+#include <mmio.h>\r
+#endif\r
+\r
+\r
+#ifdef __WATCOMC__\r
+#define inportb(x) inp(x)\r
+#define outportb(x,y) outp(x,y)\r
+#define inport(x) inpw(x)\r
+#define outport(x,y) outpw(x,y)\r
+#define disable() _disable()\r
+#define enable() _enable()\r
+#endif\r
+\r
+\r
+#ifdef __DJGPP__\r
+#include <dpmi.h>\r
+#include <go32.h>\r
+#include <pc.h>\r
+#define inp inportw\r
+#define outport outportw\r
+#define inport inportw\r
+#define interrupt \r
+#endif\r
+\r
+#endif\r
diff --git a/libs/oldmik/src/munitrk.c b/libs/oldmik/src/munitrk.c
new file mode 100644 (file)
index 0000000..e976e79
--- /dev/null
@@ -0,0 +1,346 @@
+/*\r
+\r
+Name:\r
+MUNITRK.C\r
+\r
+Description:\r
+All routines dealing with the manipulation of UNITRK(tm) streams\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <malloc.h>\r
+#include <string.h>\r
+#include "mikmod.h"\r
+\r
+#define BUFPAGE  128            /* smallest unibuffer size */\r
+#define TRESHOLD 16\r
+\r
+/* unibuffer is increased by BUFPAGE\r
+  bytes when unipc reaches unimax-TRESHOLD */\r
+\r
+\r
+\r
+/*\r
+       Ok.. I'll try to explain the new internal module format.. so here it goes:\r
+\r
+\r
+       The UNITRK(tm) Format:\r
+       ======================\r
+\r
+       A UNITRK stream is an array of bytes representing a single track\r
+       of a pattern. It's made up of 'repeat/length' bytes, opcodes and\r
+       operands (sort of a assembly 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
+\r
+       The rep/len byte contains the number of bytes in the current row,\r
+       _including_ the length byte itself (So the LENGTH byte of row 0 in the\r
+       previous example would have a value of 5). This makes it easy to search\r
+       through a stream for a particular row. A track is concluded by a 0-value\r
+       length byte.\r
+\r
+       The upper 3 bits of the rep/len byte contain the number of times -1 this\r
+       row is repeated for this track. (so a value of 7 means this row is repeated\r
+       8 times)\r
+\r
+       Opcodes can range from 1 to 255 but currently only opcodes 1 to 19 are\r
+       being used. Each opcode can have a different number of operands. You can\r
+       find the number of operands to a particular opcode by using the opcode\r
+       as an index into the 'unioperands' table.\r
+\r
+*/\r
+\r
+\r
+\r
+UWORD unioperands[256]={\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_S3MEFFECTT */\r
+       1,                              /* UNI_XMEFFECTA */\r
+       1,                              /* UNI_XMEFFECTG */\r
+       1,                              /* UNI_XMEFFECTH */\r
+       1                               /* UNI_XMEFFECTP */\r
+};\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>> Next are the routines for reading a UNITRK stream: <<<<<<<<<<<<<\r
+***************************************************************************/\r
+\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
+\r
+void UniSetRow(UBYTE *t)\r
+{\r
+       rowstart=t;\r
+       rowpc=rowstart;\r
+       rowend=rowstart+(*(rowpc++)&0x1f);\r
+}\r
+\r
+\r
+UBYTE UniGetByte(void)\r
+{\r
+       return (rowpc<rowend) ? *(rowpc++) : 0;\r
+}\r
+\r
+\r
+void UniSkipOpcode(UBYTE op)\r
+{\r
+       UWORD t=unioperands[op];\r
+       while(t--) UniGetByte();\r
+}\r
+\r
+\r
+UBYTE *UniFindRow(UBYTE *t,UWORD row)\r
+/*\r
+       Finds the address of row number 'row' in the UniMod(tm) stream 't'\r
+\r
+       returns NULL if the row can't be found.\r
+*/\r
+{\r
+       UBYTE c,l;\r
+\r
+       while(1){\r
+\r
+               c=*t;                                   /* get rep/len byte */\r
+\r
+               if(!c) return NULL;             /* zero ? -> end of track.. */\r
+\r
+               l=(c>>5)+1;                             /* extract repeat value */\r
+\r
+               if(l>row) break;                /* reached wanted row? -> return pointer */\r
+\r
+               row-=l;                                 /* havn't reached row yet.. update row */\r
+               t+=c&0x1f;                              /* point t to the next row */\r
+       }\r
+\r
+       return t;\r
+}\r
+\r
+\r
+\r
+/***************************************************************************\r
+>>>>>>>>>>> Next are the routines for CREATING UNITRK streams: <<<<<<<<<<<<<\r
+***************************************************************************/\r
+\r
+\r
+static UBYTE *unibuf;          /* pointer to the temporary unitrk buffer */\r
+static UWORD unimax;           /* maximum number of bytes to be written to this buffer */\r
+\r
+static UWORD unipc;                    /* index in the buffer where next opcode will be written */\r
+static UWORD unitt;            /* holds index of the rep/len byte of a row */\r
+static UWORD lastp;                    /* holds index to the previous row (needed for compressing) */\r
+\r
+\r
+void UniReset(void)\r
+/*\r
+       Resets index-pointers to create a new track.\r
+*/\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
+\r
+void UniWrite(UBYTE data)\r
+/*\r
+       Appends one byte of data to the current row of a track.\r
+*/\r
+{\r
+       /* write byte to current position and update */\r
+\r
+       unibuf[unipc++]=data;\r
+\r
+       /* Check if we've reached the end of the buffer */\r
+\r
+       if(unipc>(unimax-TRESHOLD)){\r
+\r
+               UBYTE *newbuf;\r
+\r
+               /* We've reached the end of the buffer, so expand\r
+                  the buffer by BUFPAGE bytes */\r
+\r
+               newbuf=(UBYTE *)realloc(unibuf,unimax+BUFPAGE);\r
+\r
+               /* Check if realloc succeeded */\r
+\r
+               if(newbuf!=NULL){\r
+                       unibuf=newbuf;\r
+                       unimax+=BUFPAGE;\r
+               }\r
+               else{\r
+                       /* realloc failed, so decrease unipc so we won't write beyond\r
+                          the end of the buffer.. I don't report the out-of-memory\r
+                          here; the UniDup() will fail anyway so that's where the\r
+                          loader sees that something went wrong */\r
+\r
+                       unipc--;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+void UniInstrument(UBYTE ins)\r
+/*\r
+       Appends UNI_INSTRUMENT opcode to the unitrk stream.\r
+*/\r
+{\r
+       UniWrite(UNI_INSTRUMENT);\r
+       UniWrite(ins);\r
+}\r
+\r
+\r
+void UniNote(UBYTE note)\r
+/*\r
+       Appends UNI_NOTE opcode to the unitrk stream.\r
+*/\r
+{\r
+       UniWrite(UNI_NOTE);\r
+       UniWrite(note);\r
+}\r
+\r
+\r
+void UniPTEffect(UBYTE eff,UBYTE dat)\r
+/*\r
+       Appends UNI_PTEFFECTX opcode to the unitrk stream.\r
+*/\r
+{\r
+       if(eff!=0 || dat!=0){                           /* don't write empty effect */\r
+               UniWrite(UNI_PTEFFECT0+eff);\r
+               UniWrite(dat);\r
+       }\r
+}\r
+\r
+\r
+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
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+void UniNewline(void)\r
+/*\r
+       Closes the current row of a unitrk stream (updates the rep/len byte)\r
+       and sets pointers to start a new row.\r
+*/\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..\r
+          when they are, just increase the repeat field of the previous row */\r
+\r
+       if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)){\r
+               unibuf[lastp]+=0x20;\r
+               unipc=unitt+1;\r
+       }\r
+       else{\r
+               /* current and previous row aren't equal.. so just update the pointers */\r
+\r
+               unibuf[unitt]=len;\r
+               lastp=unitt;\r
+               unitt=unipc;\r
+               unipc++;\r
+       }\r
+}\r
+\r
+\r
+UBYTE *UniDup(void)\r
+/*\r
+       Terminates the current unitrk stream and returns a pointer\r
+       to a copy of the stream.\r
+*/\r
+{\r
+       UBYTE *d;\r
+\r
+       unibuf[unitt]=0;\r
+\r
+       if((d=(UBYTE *)malloc(unipc))==NULL){\r
+               myerr=ERROR_ALLOC_STRUCT;\r
+               return NULL;\r
+       }\r
+       memcpy(d,unibuf,unipc);\r
+\r
+       return d;\r
+}\r
+\r
+\r
+UWORD TrkLen(UBYTE *t)\r
+/*\r
+       Determines the length (in rows) of a unitrk stream 't'\r
+*/\r
+{\r
+       UWORD len=0;\r
+       UBYTE c;\r
+\r
+       while(c=*t&0x1f){\r
+               len+=c;\r
+               t+=c;\r
+       }\r
+       len++;\r
+\r
+       return len;\r
+}\r
+\r
+\r
+BOOL UniInit(void)\r
+{\r
+       unimax=BUFPAGE;\r
+\r
+       if(!(unibuf=(UBYTE *)malloc(unimax))){\r
+               myerr=ERROR_ALLOC_STRUCT;\r
+               return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+void UniCleanup(void)\r
+{\r
+       if(unibuf!=NULL) free(unibuf);\r
+       unibuf=NULL;\r
+}\r
+\r
diff --git a/libs/oldmik/src/resample.asm b/libs/oldmik/src/resample.asm
new file mode 100644 (file)
index 0000000..afb2540
--- /dev/null
@@ -0,0 +1,132 @@
+.386p\r
+\r
+       NAME    resample\r
+        EXTRN   _rvolsel :WORD\r
+        EXTRN   _lvolsel :WORD\r
+\r
+       .model small,c\r
+\r
+DGROUP  GROUP   _DATA\r
+\r
+_TEXT   SEGMENT DWORD PUBLIC USE32 'CODE'\r
+        ASSUME  CS:_TEXT ,DS:DGROUP,SS:DGROUP\r
+\r
+        PUBLIC  AsmStereoNormal_\r
+        PUBLIC  AsmMonoNormal_\r
+        \r
+SS2     MACRO index\r
+        even\r
+        mov   edx,ebx\r
+        sar   edx,0bh\r
+        mov   al,[esi+edx]\r
+        add   ebx,ecx\r
+        mov   edx,es:[eax*4]\r
+        add   (index*8)[edi],edx\r
+        mov   edx,fs:[eax*4]\r
+        add   (4+(index*8))[edi],edx\r
+        ENDM\r
+\r
+SM2     MACRO index\r
+        even\r
+        mov   edx,ebx\r
+        add   ebx,ecx\r
+        sar   edx,0bh\r
+        mov   al,[esi+edx]\r
+        mov   edx,es:[eax*4]\r
+        add   (index*4)[edi],edx\r
+        ENDM\r
+\r
+\r
+AsmStereoNormal_ proc USES ebp fs es\r
+        mov    ax,_lvolsel\r
+        mov    es,ax                       ; voltab selector naar fs\r
+        mov    ax,_rvolsel\r
+        mov    fs,ax\r
+        xor    eax,eax\r
+        push   edx\r
+        shr    edx,4\r
+        jz     sskip16\r
+        mov    ebp,edx\r
+sagain16:\r
+        SS2    0\r
+        SS2    1\r
+        SS2    2\r
+        SS2    3\r
+        SS2    4\r
+        SS2    5\r
+        SS2    6\r
+        SS2    7\r
+        SS2    8\r
+        SS2    9\r
+        SS2    10\r
+        SS2    11\r
+        SS2    12\r
+        SS2    13\r
+        SS2    14\r
+        SS2    15\r
+        add    edi,(16*8)\r
+        dec    ebp\r
+        jnz    sagain16\r
+sskip16:\r
+        pop    edx\r
+        and    edx,15\r
+        jz     sskip1\r
+        mov    ebp,edx\r
+sagain1:\r
+        SS2    0\r
+        add    edi,8\r
+        dec    ebp\r
+        jnz    sagain1\r
+sskip1:\r
+       ret\r
+AsmStereoNormal_ endp\r
+\r
+\r
+AsmMonoNormal_ proc USES ebp es\r
+        mov    ax,_lvolsel\r
+        mov    es,ax                       ; voltab selector naar fs\r
+        xor    eax,eax\r
+        push   edx\r
+        shr    edx,4\r
+        jz     mskip16\r
+        mov    ebp,edx\r
+magain16:\r
+        SM2    0\r
+        SM2    1\r
+        SM2    2\r
+        SM2    3\r
+        SM2    4\r
+        SM2    5\r
+        SM2    6\r
+        SM2    7\r
+        SM2    8\r
+        SM2    9\r
+        SM2    10\r
+        SM2    11\r
+        SM2    12\r
+        SM2    13\r
+        SM2    14\r
+        SM2    15\r
+        add    edi,(16*4)\r
+        dec    ebp\r
+        jnz    magain16\r
+mskip16:\r
+        pop    edx\r
+        and    edx,15\r
+        jz     mskip1\r
+        mov    ebp,edx\r
+magain1:\r
+        SM2    0\r
+        add    edi,4\r
+        dec    ebp\r
+        jnz    magain1\r
+mskip1:\r
+       ret\r
+AsmMonoNormal_ endp\r
+\r
+_TEXT   ENDS\r
+\r
+_DATA   SEGMENT DWORD PUBLIC USE32 'DATA'\r
+_DATA   ENDS\r
+\r
+        END\r
diff --git a/libs/oldmik/src/virtch.c b/libs/oldmik/src/virtch.c
new file mode 100644 (file)
index 0000000..8f7e357
--- /dev/null
@@ -0,0 +1,852 @@
+/*\r
+\r
+Name:\r
+VIRTCH.C\r
+\r
+Description:\r
+All-c sample mixing routines, using a 32 bits mixing buffer\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <malloc.h>\r
+#include "mikmod.h"\r
+\r
+#define FRACBITS 11\r
+#define FRACMASK ((1L<<FRACBITS)-1)\r
+\r
+#define TICKLSIZE 3600\r
+#define TICKWSIZE (TICKLSIZE*2)\r
+#define TICKBSIZE (TICKWSIZE*2)\r
+static SLONG VC_TICKBUF[TICKLSIZE];\r
+\r
+#ifndef min\r
+#define min(a,b) (((a)<(b)) ? (a) : (b))\r
+#endif\r
+\r
+typedef struct{\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
+       UBYTE vol;                      /* current volume */\r
+       UBYTE pan;                                              /* current panning position */\r
+       SLONG current;                  /* current index in the sample */\r
+       SLONG increment;                /* fixed-point increment value */\r
+#ifdef __WATCOMC__\r
+       UWORD lvolsel;                                  /* left volume table selector */\r
+       UWORD rvolsel;                                  /* right volume table selector */\r
+#else\r
+       SLONG lvolmul;                                  /* left volume multiply */\r
+       SLONG rvolmul;                                  /* right volume multiply */\r
+#endif\r
+} VINFO;\r
+\r
+\r
+static VINFO vinf[32];\r
+static VINFO *vnf;\r
+\r
+static UWORD samplesthatfit;\r
+static SLONG idxsize,idxlpos,idxlend,maxvol;\r
+\r
+static long per256;\r
+static int ampshift;\r
+\r
+\r
+#ifdef __WATCOMC__\r
+\r
+static SLONG voltab[65][256];\r
+static UWORD volsel[65];\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+UWORD lvolsel,rvolsel;\r
+\r
+void AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);\r
+#pragma aux AsmStereoNormal    \\r
+               parm [esi] [edi] [ebx] [ecx] [edx] \\r
+               modify [eax];\r
+\r
+\r
+void AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);\r
+#pragma aux AsmMonoNormal     \\r
+        parm [esi] [edi] [ebx] [ecx] [edx] \\r
+        modify [eax];\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+void freedescriptor(unsigned short selector);\r
+#pragma aux freedescriptor =    \\r
+       "mov    ax,0001h"       \\r
+       "int    31h"            \\r
+       parm    [bx]            \\r
+       modify  [ax];\r
+\r
+unsigned short getalias(void);\r
+#pragma aux getalias =          \\r
+       "mov    ax,cs   "       \\r
+       "mov    bx,ax   "       \\r
+       "mov    ax,000ah"       \\r
+       "int    31h     "       \\r
+       "jnc    isok    "       \\r
+       "xor    ax,ax   "       \\r
+       "isok:          "       \\r
+       modify  [bx]            \\r
+       value   [ax];\r
+\r
+void setbase(unsigned short selector,unsigned long offset);\r
+#pragma aux setbase =           \\r
+       "mov    ax,0007h"       \\r
+       "mov    ecx,edx"        \\r
+       "ror    ecx,16"         \\r
+       "int    31h"            \\r
+       parm    [bx] [edx]      \\r
+       modify  [ax ecx] ;\r
+\r
+void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift);\r
+#pragma aux VC_Sample32To16Copy =      \\r
+"again:"                                       \\r
+       "mov   eax,[esi]"               \\r
+       "sar   eax,cl"          \\r
+       "cmp   eax,32767"               \\r
+       "jg    toobig"                  \\r
+       "cmp   eax,-32768"              \\r
+       "jl    toosmall"                \\r
+"write:"                                       \\r
+       "mov   [edi],ax"                \\r
+       "add   esi,4"           \\r
+       "add   edi,2"                   \\r
+       "dec   edx"             \\r
+       "jnz   again"           \\r
+       "jmp   ready"                   \\r
+"toobig:"                   \\r
+       "mov   eax,32767"               \\r
+       "jmp   write"                   \\r
+"toosmall:"                 \\r
+       "mov   eax,-32768"              \\r
+       "jmp   write"                   \\r
+"ready:"                                       \\r
+       parm [esi] [edi] [edx] [cl]     \\r
+       modify [eax] ;\r
+\r
+\r
+void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift);\r
+#pragma aux VC_Sample32To8Copy =       \\r
+"again:"                       \\r
+       "mov   eax,[esi]"               \\r
+       "sar   eax,cl"          \\r
+       "cmp   eax,127"         \\r
+       "jg    toobig"                  \\r
+       "cmp   eax,-128"        \\r
+       "jl    toosmall"                \\r
+"write:"                    \\r
+       "add   al,080h"         \\r
+       "mov   [edi],al"        \\r
+       "add   esi,4"           \\r
+       "inc   edi"             \\r
+       "dec   edx"             \\r
+       "jnz   again"                   \\r
+       "jmp   ready"                   \\r
+"toobig:"                   \\r
+       "mov   eax,127"         \\r
+       "jmp   write"                   \\r
+"toosmall:"                 \\r
+       "mov   eax,-128"        \\r
+       "jmp   write"                   \\r
+"ready:"                    \\r
+       parm [esi] [edi] [edx] [cl]     \\r
+       modify [eax] ;\r
+\r
+\r
+#else\r
+\r
+\r
+static SLONG lvolmul,rvolmul;\r
+\r
+\r
+static void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift)\r
+{\r
+       SLONG c;\r
+       int shift=(24-ampshift);\r
+\r
+       while(count--){\r
+               c=*srce >> shift;\r
+               if(c>127) c=127;\r
+               else if(c<-128) c=-128;\r
+               *dest++=c+128;\r
+               srce++;\r
+       }\r
+}\r
+\r
+\r
+static void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift)\r
+{\r
+       SLONG c;\r
+       int shift=(16-ampshift);\r
+\r
+       while(count--){\r
+               c=*srce >> shift;\r
+               if(c>32767) c=32767;\r
+               else if(c<-32768) c=-32768;\r
+               *dest++=c;\r
+               srce++;\r
+       }\r
+}\r
+\r
+#endif\r
+\r
+\r
+static SLONG fraction2long(ULONG dividend,UWORD divisor)\r
+/*\r
+       Converts the fraction 'dividend/divisor' into a fixed point longword.\r
+*/\r
+{\r
+       ULONG whole,part;\r
+\r
+       whole=dividend/divisor;\r
+       part=((dividend%divisor)<<FRACBITS)/divisor;\r
+\r
+       return((whole<<FRACBITS)|part);\r
+}\r
+\r
+\r
+static UWORD samples2bytes(UWORD samples)\r
+{\r
+       if(md_mode & DMODE_16BITS) samples<<=1;\r
+       if(md_mode & DMODE_STEREO) samples<<=1;\r
+       return samples;\r
+}\r
+\r
+\r
+static UWORD bytes2samples(UWORD bytes)\r
+{\r
+       if(md_mode & DMODE_16BITS) bytes>>=1;\r
+       if(md_mode & DMODE_STEREO) bytes>>=1;\r
+       return bytes;\r
+}\r
+\r
+\r
+/**************************************************\r
+***************************************************\r
+***************************************************\r
+**************************************************/\r
+\r
+\r
+static SBYTE *Samples[MAXSAMPLEHANDLES];\r
+\r
+\r
+BOOL LargeRead(SBYTE *buffer,ULONG size)\r
+{\r
+       int t;\r
+       ULONG todo;\r
+\r
+       while(size){\r
+               /* how many bytes to load (in chunks of 8000) ? */\r
+\r
+               todo=(size>8000)?8000:size;\r
+\r
+               /* read data */\r
+\r
+               SL_Load(buffer,todo);\r
+               /* and update pointers.. */\r
+\r
+               size-=todo;\r
+               buffer+=todo;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+\r
+SWORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+       int handle;\r
+       ULONG t;\r
+\r
+       SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS);\r
+\r
+       /* Find empty slot to put sample address in */\r
+\r
+       for(handle=0;handle<MAXSAMPLEHANDLES;handle++){\r
+               if(Samples[handle]==NULL) break;\r
+       }\r
+\r
+       if(handle==MAXSAMPLEHANDLES){\r
+               myerr=ERROR_OUT_OF_HANDLES;\r
+               return -1;\r
+       }\r
+\r
+        if((Samples[handle]=(SBYTE *)malloc(length+16))==NULL){\r
+               myerr=ERROR_SAMPLE_TOO_BIG;\r
+               return -1;\r
+       }\r
+\r
+       /* read sample into buffer. */\r
+       LargeRead(Samples[handle],length);\r
+\r
+       /* Unclick samples: */\r
+\r
+       if(flags & SF_LOOP){\r
+               if(flags & SF_BIDI)\r
+                       for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][(repend-t)-1];\r
+               else\r
+                       for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][t+reppos];\r
+       }\r
+       else{\r
+               for(t=0;t<16;t++) Samples[handle][t+length]=0;\r
+       }\r
+\r
+       return handle;\r
+}\r
+\r
+\r
+\r
+void VC_SampleUnload(SWORD handle)\r
+{\r
+       void *sampleadr=Samples[handle];\r
+\r
+       free(sampleadr);\r
+       Samples[handle]=NULL;\r
+}\r
+\r
+\r
+/**************************************************\r
+***************************************************\r
+***************************************************\r
+**************************************************/\r
+\r
+\r
+#ifndef __WATCOMC__\r
+\r
+\r
+static void (*SampleMix)(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo);\r
+\r
+\r
+static void MixStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+       SBYTE sample;\r
+\r
+       while(todo>0){\r
+               sample=srce[index>>FRACBITS];\r
+               *(dest++)+=lvolmul*sample;\r
+               *(dest++)+=rvolmul*sample;\r
+               index+=increment;\r
+               todo--;\r
+       }\r
+}\r
+\r
+\r
+static void MixMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+       SBYTE sample;\r
+\r
+       while(todo>0){\r
+               sample=srce[index>>FRACBITS];\r
+               *(dest++)+=lvolmul*sample;\r
+               index+=increment;\r
+               todo--;\r
+       }\r
+}\r
+\r
+\r
+static void MixStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+       SWORD sample,a,b;\r
+\r
+       while(todo>0){\r
+               a=srce[index>>FRACBITS];\r
+               b=srce[1+(index>>FRACBITS)];\r
+               sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);\r
+\r
+               *(dest++)+=lvolmul*sample;\r
+               *(dest++)+=rvolmul*sample;\r
+               index+=increment;\r
+               todo--;\r
+       }\r
+}\r
+\r
+\r
+static void MixMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+       SWORD sample,a,b;\r
+\r
+       while(todo>0){\r
+               a=srce[index>>FRACBITS];\r
+               b=srce[1+(index>>FRACBITS)];\r
+               sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);\r
+\r
+               *(dest++)+=lvolmul*sample;\r
+\r
+               index+=increment;\r
+               todo--;\r
+       }\r
+}\r
+\r
+#endif\r
+\r
+\r
+static UWORD NewPredict(SLONG index,SLONG end,SLONG increment,UWORD todo)\r
+/*\r
+       This functions returns the number of resamplings we can do so that:\r
+\r
+               - it never accesses indexes bigger than index 'end'\r
+               - it doesn't do more than 'todo' resamplings\r
+*/\r
+{\r
+       SLONG di;\r
+\r
+       di=(end-index)/increment;\r
+       index+=(di*increment);\r
+\r
+       if(increment<0){\r
+               while(index>=end){\r
+                       index+=increment;\r
+                       di++;\r
+               }\r
+       }\r
+       else{\r
+               while(index<=end){\r
+                       index+=increment;\r
+                       di++;\r
+               }\r
+       }\r
+       return ((di<todo) ? di : todo);\r
+}\r
+\r
+\r
+static void VC_AddChannel(SLONG *ptr,UWORD todo)\r
+/*\r
+       Mixes 'todo' stereo or mono samples of the current channel to the tickbuffer.\r
+*/\r
+{\r
+       SLONG end;\r
+       UWORD done,needs;\r
+        SBYTE *s;\r
+\r
+       while(todo>0){\r
+\r
+               /* update the 'current' index so the sample loops, or\r
+                  stops playing if it reached the end of the sample */\r
+\r
+               if(vnf->flags&SF_REVERSE){\r
+\r
+                       /* The sample is playing in reverse */\r
+\r
+                               if(vnf->flags&SF_LOOP){\r
+\r
+                                       /* the sample is looping, so check if\r
+                                          it reached the loopstart index */\r
+\r
+                                       if(vnf->current<idxlpos){\r
+                                       if(vnf->flags&SF_BIDI){\r
+\r
+                                               /* sample is doing bidirectional loops, so 'bounce'\r
+                                                       the current index against the idxlpos */\r
+\r
+                                               vnf->current=idxlpos+(idxlpos-vnf->current);\r
+                                               vnf->flags&=~SF_REVERSE;\r
+                                               vnf->increment=-vnf->increment;\r
+                                       }\r
+                                       else\r
+                                               /* normal backwards looping, so set the\r
+                                                       current position to loopend index */\r
+\r
+                                                       vnf->current=idxlend-(idxlpos-vnf->current);\r
+                                       }\r
+                               }\r
+                               else{\r
+\r
+                                       /* the sample is not looping, so check\r
+                                               if it reached index 0 */\r
+\r
+                                       if(vnf->current<0){\r
+\r
+                                               /* playing index reached 0, so stop\r
+                                                       playing this sample */\r
+\r
+                                               vnf->current=0;\r
+                                               vnf->active=0;\r
+                                               break;\r
+                                       }\r
+                               }\r
+               }\r
+               else{\r
+\r
+                       /* The sample is playing forward */\r
+\r
+                               if(vnf->flags&SF_LOOP){\r
+\r
+                                       /* the sample is looping, so check if\r
+                                               it reached the loopend index */\r
+\r
+                                       if(vnf->current>idxlend){\r
+                                               if(vnf->flags&SF_BIDI){\r
+\r
+                                               /* sample is doing bidirectional loops, so 'bounce'\r
+                                                       the current index against the idxlend */\r
+\r
+                                                       vnf->flags|=SF_REVERSE;\r
+                                                       vnf->increment=-vnf->increment;\r
+                                                       vnf->current=idxlend-(vnf->current-idxlend); /* ?? */\r
+                                               }\r
+                                               else\r
+                                               /* normal backwards looping, so set the\r
+                                                       current position to loopend index */\r
+\r
+                                                       vnf->current=idxlpos+(vnf->current-idxlend);\r
+                                       }\r
+                               }\r
+                               else{\r
+\r
+                                       /* sample is not looping, so check\r
+                                               if it reached the last position */\r
+\r
+                                       if(vnf->current>idxsize){\r
+\r
+                                               /* yes, so stop playing this sample */\r
+\r
+                                               vnf->current=0;\r
+                                               vnf->active=0;\r
+                                               break;\r
+                                       }\r
+                               }\r
+               }\r
+\r
+               /* Vraag een far ptr op van het sampleadres\r
+                       op byte offset vnf->current, en hoeveel samples\r
+                       daarvan geldig zijn (VOORDAT segment overschrijding optreed) */\r
+\r
+               if(!(s=Samples[vnf->handle])){\r
+                       vnf->current=0;\r
+                       vnf->active=0;\r
+                       break;\r
+               }\r
+\r
+               if(vnf->flags & SF_REVERSE)\r
+                       end = (vnf->flags & SF_LOOP) ? idxlpos : 0;\r
+               else\r
+                       end = (vnf->flags & SF_LOOP) ? idxlend : idxsize;\r
+\r
+               /* Als de sample simpelweg niet beschikbaar is, of als\r
+                       sample gestopt moet worden sample stilleggen en stoppen */\r
+               /* mix 'em: */\r
+\r
+               done=NewPredict(vnf->current,end,vnf->increment,todo);\r
+\r
+               if(!done){\r
+/*                     printf("predict stopped it. current %ld, end %ld\n",vnf->current,end);\r
+*/                     vnf->active=0;\r
+                       break;\r
+               }\r
+\r
+               /* optimisation: don't mix anything if volume is zero */\r
+\r
+               if(vnf->vol){\r
+#ifdef __WATCOMC__\r
+                       if(md_mode & DMODE_STEREO)\r
+                               AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done);\r
+                       else\r
+                               AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done);\r
+#else\r
+                       SampleMix(s,ptr,vnf->current,vnf->increment,done);\r
+#endif\r
+               }\r
+               vnf->current+=(vnf->increment*done);\r
+\r
+               todo-=done;\r
+               ptr+=(md_mode & DMODE_STEREO) ? (done<<1) : done;\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+static void VC_FillTick(SBYTE *buf,UWORD todo)\r
+/*\r
+       Mixes 'todo' samples to 'buf'.. The number of samples has\r
+       to fit into the tickbuffer.\r
+*/\r
+{\r
+       int t;\r
+\r
+       /* clear the mixing buffer: */\r
+\r
+       memset(VC_TICKBUF,0,(md_mode & DMODE_STEREO) ? todo<<3 : todo<<2);\r
+\r
+       for(t=0;t<md_numchn;t++){\r
+               vnf=&vinf[t];\r
+\r
+               if(vnf->active){\r
+                       idxsize=(vnf->size<<FRACBITS)-1;\r
+                       idxlpos=vnf->reppos<<FRACBITS;\r
+                       idxlend=(vnf->repend<<FRACBITS)-1;\r
+#ifdef __WATCOMC__\r
+                        lvolsel=vnf->lvolsel;\r
+                        rvolsel=vnf->rvolsel;\r
+#else\r
+                       lvolmul=vnf->lvolmul;\r
+                       rvolmul=vnf->rvolmul;\r
+#endif\r
+                       VC_AddChannel(VC_TICKBUF,todo);\r
+               }\r
+       }\r
+\r
+       if(md_mode & DMODE_16BITS)\r
+               VC_Sample32To16Copy(VC_TICKBUF,(SWORD *)buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,16-ampshift);\r
+       else\r
+               VC_Sample32To8Copy(VC_TICKBUF,buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,24-ampshift);\r
+}\r
+\r
+\r
+\r
+static void VC_WritePortion(SBYTE *buf,UWORD todo)\r
+/*\r
+       Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the\r
+       number of samples that fit into VC_TICKBUF, the mixing operation is split\r
+       up into a number of smaller chunks.\r
+*/\r
+{\r
+       UWORD part;\r
+\r
+       /* write 'part' samples to the buffer */\r
+\r
+       while(todo){\r
+               part=min(todo,samplesthatfit);\r
+               VC_FillTick(buf,part);\r
+               buf+=samples2bytes(part);\r
+               todo-=part;\r
+       }\r
+}\r
+\r
+\r
+static UWORD TICKLEFT;\r
+\r
+\r
+void VC_WriteSamples(SBYTE *buf,UWORD todo)\r
+{\r
+       int t;\r
+       UWORD part;\r
+\r
+       while(todo>0){\r
+\r
+               if(TICKLEFT==0){\r
+                       md_player();\r
+\r
+                       TICKLEFT=(125L*md_mixfreq)/(50L*md_bpm);\r
+\r
+                       /* compute volume, frequency counter & panning parameters for each channel. */\r
+\r
+                       for(t=0;t<md_numchn;t++){\r
+                               int pan,vol,lvol,rvol;\r
+\r
+                               if(vinf[t].kick){\r
+                                       vinf[t].current=(vinf[t].start << FRACBITS);\r
+                                       vinf[t].active=1;\r
+                                       vinf[t].kick=0;\r
+                               }\r
+\r
+                               if(vinf[t].frq==0) vinf[t].active=0;\r
+\r
+                               if(vinf[t].active){\r
+                                       vinf[t].increment=fraction2long(vinf[t].frq,md_mixfreq);\r
+\r
+                                       if(vinf[t].flags & SF_REVERSE) vinf[t].increment=-vinf[t].increment;\r
+\r
+                                       vol=vinf[t].vol;\r
+                                       pan=vinf[t].pan;\r
+\r
+#ifdef __WATCOMC__\r
+                                       if(md_mode & DMODE_STEREO){\r
+                                               lvol= ( vol * (255-pan) ) / 255;\r
+                                               rvol= ( vol * pan ) / 255;\r
+                                               vinf[t].lvolsel=volsel[lvol];\r
+                                               vinf[t].rvolsel=volsel[rvol];\r
+                                       }\r
+                                       else{\r
+                                               vinf[t].lvolsel=volsel[vol];\r
+                                       }\r
+#else\r
+                                       if(md_mode & DMODE_STEREO){\r
+                                               lvol= ( vol * (255-pan) ) / 255;\r
+                                               rvol= ( vol * pan ) / 255;\r
+                                               vinf[t].lvolmul=(maxvol*lvol)/64;\r
+                                               vinf[t].rvolmul=(maxvol*rvol)/64;\r
+                                       }\r
+                                       else{\r
+                                               vinf[t].lvolmul=(maxvol*vol)/64;\r
+                                       }\r
+#endif\r
+                               }\r
+                       }\r
+               }\r
+\r
+               part=min(TICKLEFT,todo);\r
+\r
+               VC_WritePortion(buf,part);\r
+\r
+               TICKLEFT-=part;\r
+               todo-=part;\r
+\r
+               buf+=samples2bytes(part);\r
+       }\r
+}\r
+\r
+\r
+UWORD VC_WriteBytes(SBYTE *buf,UWORD todo)\r
+/*\r
+       Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of\r
+       SBYTES actually written to 'buf' (which is rounded to number of samples\r
+       that fit into 'todo' bytes).\r
+*/\r
+{\r
+       todo=bytes2samples(todo);\r
+       VC_WriteSamples(buf,todo);\r
+       return samples2bytes(todo);\r
+}\r
+\r
+\r
+void VC_SilenceBytes(SBYTE *buf,UWORD todo)\r
+/*\r
+       Fill the buffer with 'todo' bytes of silence (it depends on the mixing\r
+       mode how the buffer is filled)\r
+*/\r
+{\r
+       /* clear the buffer to zero (16 bits\r
+          signed ) or 0x80 (8 bits unsigned) */\r
+\r
+       if(md_mode & DMODE_16BITS)\r
+               memset(buf,0,todo);\r
+       else\r
+               memset(buf,0x80,todo);\r
+}\r
+\r
+\r
+void VC_PlayStart(void)\r
+{\r
+       int t;\r
+\r
+       maxvol=16777216L / md_numchn;\r
+\r
+#ifdef __WATCOMC__\r
+       for(t=0;t<65;t++){\r
+               int c;\r
+               SLONG volmul=(maxvol*t)/64;\r
+               for(c=-128;c<128;c++){\r
+                       voltab[t][(UBYTE)c]=(SLONG)c*volmul;\r
+               }\r
+       }\r
+#endif\r
+\r
+       /* instead of using a amplifying lookup table, I'm using a simple shift\r
+          amplify now.. amplifying doubles with every extra 4 channels, and also\r
+          doubles in stereo mode.. this seems to give similar volume levels\r
+          across the channel range */\r
+\r
+       ampshift=md_numchn/8;\r
+       if(md_mode & DMODE_STEREO) ampshift++;\r
+\r
+#ifndef __WATCOMC__\r
+       if(md_mode & DMODE_INTERP)\r
+               SampleMix=(md_mode & DMODE_STEREO) ? MixStereoInterp : MixMonoInterp;\r
+       else\r
+               SampleMix=(md_mode & DMODE_STEREO) ? MixStereoNormal : MixMonoNormal;\r
+#endif\r
+\r
+       samplesthatfit=TICKLSIZE;\r
+       if(md_mode & DMODE_STEREO) samplesthatfit>>=1;\r
+       TICKLEFT=0;\r
+}\r
+\r
+\r
+void VC_PlayStop(void)\r
+{\r
+}\r
+\r
+\r
+BOOL VC_Init(void)\r
+{\r
+       int t;\r
+       for(t=0;t<32;t++){\r
+               vinf[t].current=0;\r
+               vinf[t].flags=0;\r
+               vinf[t].handle=0;\r
+               vinf[t].kick=0;\r
+               vinf[t].active=0;\r
+               vinf[t].frq=10000;\r
+               vinf[t].vol=0;\r
+               vinf[t].pan=(t&1)?0:255;\r
+       }\r
+\r
+#ifdef __WATCOMC__\r
+       if(md_mode & DMODE_INTERP) md_mode&=~DMODE_INTERP;\r
+\r
+       for(t=0;t<65;t++) volsel[t]=0;\r
+\r
+       for(t=0;t<65;t++){\r
+               if(!(volsel[t]=getalias())) return 0;\r
+               setbase(volsel[t],(ULONG)voltab[t]);\r
+       }\r
+#endif\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+void VC_Exit(void)\r
+{\r
+#ifdef __WATCOMC__\r
+       int t;\r
+       for(t=0;t<65;t++){\r
+               if(volsel[t]) freedescriptor(volsel[t]);\r
+       }\r
+#endif\r
+}\r
+\r
+\r
+void VC_VoiceSetVolume(UBYTE voice,UBYTE vol)\r
+{\r
+       vinf[voice].vol=vol;\r
+}\r
+\r
+\r
+void VC_VoiceSetFrequency(UBYTE voice,ULONG frq)\r
+{\r
+       vinf[voice].frq=frq;\r
+}\r
+\r
+\r
+void VC_VoiceSetPanning(UBYTE voice,UBYTE pan)\r
+{\r
+       vinf[voice].pan=pan;\r
+}\r
+\r
+\r
+void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+       if(start>=size) return;\r
+\r
+       if(flags&SF_LOOP){\r
+               if(repend>size) repend=size;    /* repend can't be bigger than size */\r
+       }\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
index 72b4d8d..51f4b28 100644 (file)
@@ -1,3 +1,5 @@
 cd libs\imago\r
 wmake %1 %2 %3 %4 %5 %6 %7 %8\r
+cd ..\oldmik\r
+wmake %1 %2 %3 %4 %5 %6 %7 %8\r
 cd ..\..\r
index 9133a26..3a99314 100644 (file)
@@ -35,7 +35,6 @@ int demo_init(int argc, char **argv)
        g3d_framebuffer(fb_width, fb_height, fb_pixels);
 
        if(music_open("data/test.mod") == -1) {
-               fprintf(stderr, "failed to open music: data/test.mod\n");
                return -1;
        }
 
diff --git a/src/dos/music.c b/src/dos/music.c
new file mode 100644 (file)
index 0000000..5ed6b48
--- /dev/null
@@ -0,0 +1,81 @@
+#include <stdlib.h>
+#include "music.h"
+#include "mikmod.h"
+
+static void update_callback(void);
+
+static UNIMOD *mod;
+static int initialized;
+
+static int init(void)
+{
+       ML_RegisterLoader(&load_mod);
+       ML_RegisterLoader(&load_s3m);
+       ML_RegisterLoader(&load_xm);
+
+       MD_RegisterDriver(&drv_nos);
+       MD_RegisterDriver(&drv_ss);
+       MD_RegisterDriver(&drv_sb);
+       MD_RegisterDriver(&drv_gus);
+
+       MD_RegisterPlayer(&update_callback);
+
+       /*md_mode |= DMODE_INTERP;*/
+       if(!MD_Init()) {
+               fprintf(stderr, "mikmod init failed: %s\n", myerr);
+               return -1;
+       }
+       printf("using mikmod driver %s\n", md_driver->Name);
+       printf(" %d bits, %s, %s mixing at %d Hz\n", md_mode & DMODE_16BITS ? 16 : 8,
+                       md_mode & DMODE_STEREO ? "stereo" : "mono",
+                       md_mode & DMODE_INTERP ? "interpolated" : "normal",
+                       md_mixfreq);
+
+       atexit(MD_Exit);
+       return 0;
+}
+
+int music_open(const char *fname)
+{
+       if(!initialized) {
+               if(init() == -1) {
+                       return -1;
+               }
+               initialized = 1;
+       }
+
+       if(!(mod = ML_LoadFN((const signed char*)fname))) {
+               fprintf(stderr, "failed to load music: %s: %s\n", fname, myerr);
+               return -1;
+       }
+       md_numchn = mod->numchn;
+       return 0;
+}
+
+void music_close(void)
+{
+       if(mod) {
+               music_stop();
+               ML_Free(mod);
+               mod = 0;
+       }
+}
+
+void music_play(void)
+{
+       MD_PlayStart();
+}
+
+void music_stop(void)
+{
+       MD_PlayStop();
+}
+
+void music_update(void)
+{
+       MD_Update();
+}
+
+static void update_callback(void)
+{
+}
diff --git a/src/music.c b/src/music.c
deleted file mode 100644 (file)
index 365ad01..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "music.h"
-#include "mikmod.h"
-
-static MODULE *mod;
-static int initialized;
-
-
-static int init(void)
-{
-       MikMod_RegisterAllDrivers();
-       MikMod_RegisterAllLoaders();
-
-       md_mode |= DMODE_SOFT_MUSIC;
-       if(MikMod_Init("") != 0) {
-               fprintf(stderr, "mikmod init failed: %s\n",
-                               MikMod_strerror(MikMod_errno));
-               return -1;
-       }
-       return 0;
-}
-
-int music_open(const char *fname)
-{
-       if(!initialized) {
-               if(init() == -1) {
-                       return -1;
-               }
-               initialized = 1;
-       }
-
-       if(!(mod = Player_Load(fname, 64, 0))) {
-               fprintf(stderr, "failed to load music: %s: %s\n", fname,
-                               MikMod_strerror(MikMod_errno));
-               return -1;
-       }
-       return 0;
-}
-
-void music_close(void)
-{
-       if(mod) {
-               music_stop();
-               Player_Free(mod);
-       }
-}
-
-void music_play(void)
-{
-       Player_Start(mod);
-}
-
-void music_stop(void)
-{
-       Player_Stop();
-}
-
-void music_update(void)
-{
-       if(Player_Active()) {
-               MikMod_Update();
-       }
-}
index 9d9cb01..7f388ae 100644 (file)
@@ -4,6 +4,7 @@
 int music_open(const char *fname);
 void music_close(void);
 void music_play(void);
+void music_stop(void);
 void music_update(void);
 
 #endif /* MUSIC_H_ */
diff --git a/src/sdl/music.c b/src/sdl/music.c
new file mode 100644 (file)
index 0000000..e194764
--- /dev/null
@@ -0,0 +1,63 @@
+#include "music.h"
+#include "mikmod.h"
+
+static MODULE *mod;
+static int initialized;
+
+
+static int init(void)
+{
+       MikMod_RegisterAllDrivers();
+       MikMod_RegisterAllLoaders();
+
+       md_mode |= DMODE_SOFT_MUSIC;
+       if(MikMod_Init("") != 0) {
+               fprintf(stderr, "mikmod init failed: %s\n",
+                               MikMod_strerror(MikMod_errno));
+               return -1;
+       }
+       return 0;
+}
+
+int music_open(const char *fname)
+{
+       if(!initialized) {
+               if(init() == -1) {
+                       return -1;
+               }
+               initialized = 1;
+       }
+
+       if(!(mod = Player_Load(fname, 64, 0))) {
+               fprintf(stderr, "failed to load music: %s: %s\n", fname,
+                               MikMod_strerror(MikMod_errno));
+               return -1;
+       }
+       return 0;
+}
+
+void music_close(void)
+{
+       if(mod) {
+               music_stop();
+               Player_Free(mod);
+               mod = 0;
+       }
+}
+
+void music_play(void)
+{
+       Player_Start(mod);
+}
+
+void music_stop(void)
+{
+       Player_Stop();
+}
+
+void music_update(void)
+{
+       if(Player_Active()) {
+               MikMod_Update();
+       }
+}