Anonymous avatar Anonymous committed 8b3f06d

Importing the files into the source directory

Comments (0)

Files changed (47)

source/java/docs/Changes_From_C.txt

+
+This document lists the changes I made to the ANSI C code to convert it
+to Java. I ported MikMod to Java in the following manner:
+
+I first converted the original ANSI C source code to a C++ class-based
+code. Then, I gradually replaced more and more C features or code
+styles with their Java equivalents.
+
+Afterwards, I renamed the files to  hava a '.java' extension and
+applied the appropriate changes so it will compile. Finally, during
+run-time there were various Error notices and bugs, that pointed to
+other required alterations, which I also applied to the code.
+
+Converting MikMod to Java was fairly easy in that manner, because
+MikMod was already quite well-designed and modulated.
+
+Here are the changes that are apparaerant by comparing between the
+original code and the Java code:
+
+
+
+
+1. Every module was encapsulated in its own class, the functions were
+turned to methods and the global variables converted to member
+variables. Some modules were implemented as a base class with two
+derived classes: one for the MikMod player and one for MikCvt:
+
+MikMod.clMainBase
+    |
+    |- MikMod.clMain
+    |
+    \- MikMod.clMikCvtMain
+
+MikMod.clMDriverBase
+    |
+    |- MikMod.MDriver.clMDriver
+    |
+    \- MikMod.clMikCvtMDriver  (inside clMikCvtMain.java)
+    
+
+MikMod.clDisplayBase       (intended for mikcvt)
+    |
+    \- MikMod.Display.clDisplay     (intended for mikmod)
+
+The basic architecture is that the main class (clMain or clMikCvtMain)
+contains pointers to the instances of the other module-objects, while
+every one of the latter have a pointer to the main class. In order to
+access a function or variable of another module one uses the
+"m_.[Module Name].[FuncName/VarName]" syntax (m_ points to the main
+class in all the objects).
+
+As an examples:
+
+m_.MDriver.SL_Load( my_buffer, start_from, len);
+
+m_.mmIO.myerr = "An error string";
+
+
+
+2. The drivers and loaders architecture is implemented by managing a
+list of references to classes that are derived from the generic classes
+MikMod.clDRIVER and MikMod.clLOADER.
+
+For every loader or driver, I create an instance of its class and then
+adds it to the array of references, which is handled by clMDriver or
+clMLoader. Then the management module/class can access each different
+loader or driver by its index in the array.
+
+For example, to check which loader can recognize a file, clMLoader uses
+the following code:
+
+for(t=num_loaders-1; t >= 0; t--){
+        m_.mmIO._mm_rewind(modfp);
+        //l=loaders[t];
+        if(loaders[t].Test()) break;
+}
+
+The drivers reside in the MikMod.Drivers namespace and the loaders in
+MikMod.Loaders.
+
+
+
+3. Whenever the typedefs SBYTE, SWORD and SLONG were used, they were
+replaced by "byte", "short" and "int" respectively. UBYTE, UWORD and
+ULONG as well as standard references to unsigned data types, were
+replaced by signed data types. I sometimes had to upgrade them to a
+greater byte-size (e.g. an 8-bit unsigned integer converted to a
+"short", which is a 16-bit signed integer).
+
+I also replaced integer variables and constants by Java's booleans
+where appropriate. Moreover, "NULL" and sometimes "0" was replaced by
+"null".
+
+Note: in Java "long" is a 64-bit integer, and only "int" is a 32-bit
+integer. Thus, if a variable was declared as long in the C code, I had
+to change it to an "int" declaration.
+
+
+
+4. I replaced traditional C file I/O and string handling with Java's.
+Calls to other libc routines (especially malloc, memcmp and
+friends) that may not be compatible with Java, were replaced by code
+that uses only the C/Java operators.
+
+Note: some of those conversion could be re-implemented with Java
+methods like System.arraycopy. I'd rather not because of byte-sex
+compatibility.
+
+Another note: as I found out, when allocating an array of strings in
+Java, one also has to instantize every member. For example where in ANSI C
+one would use:
+
+mystruct * array = malloc(sizeof(mystruct) * 10);
+
+In C++ it would read:
+
+mystruct * array = new mystruct [10];
+
+And in Java it should be:
+
+mystruct [] array = new mystruct [10];
+for(i=0;i<10;i++)
+    array[i] = new mystruct;
+
+
+
+5. Pointer arithmetics and pointer casting were eliminated. I sometimes
+needed to add extra parameters to functions that will denote the array offset
+of the beginning of the data.
+
+
+
+7. I made sure that all conditions in ifs, loops, etc. return a boolean
+expression and not a mere integer. Java does not accept such constructs
+as 'if (1)' or 'if (my_int)', so they had to be changed to 'if (true)'
+and 'if (my_int != 0)'.
+
+I sometimes had to add some extra parenthesis. For example:
+"if (md_mode & DMODE_16BITS)" was converted to
+"if ((m_MDriver.md_mode & m_.DMODE_16BITS) != 0)"
+
+
+
+8. The Java compiler does not automatically converts an arithmetic
+expression that evaluates to an int, into a short or a byte. Thus, some
+expressions were surrounded by parenthesis and preceded by "(short)" or
+"(byte)". Since Java constants are normally ints, it had to be done
+quite often.
+
+
+
+9. I've added a lot of "try { <main code ...> } catch (SomeException
+some_exc) <catch handler code ...> }" constructs around function code
+to catch the various exceptions that Java often throws.
+
+The catch handler usually only contains a "return" statement or a
+similiar instruction so the function will return an error-code. I
+relied on MikMod's error-handling and just didn't have the nerve to
+figure out what all those catch clauses should contain.
+
+

source/java/docs/Optimizing.txt

+Ideas on how to optimize the Java version of MikMod
+---------------------------------------------------
+
+
+The speed of JMikMod and its CPU consumption are very unsatisfactory,
+at least on the non-JIT compilation based Java runtime environments I
+tested it on. The easiest thing would be to say that Java is not
+intended for real-time applications, and that it isn't realistic to
+think one can efficiently run MikMod on it.
+
+Still, I believe that there are several ways in which the code I have
+now can be modified to make it faster. I deduced them from my
+general knowledge of programming, and not much from a specialized
+understanding of how Java programs are executed.
+
+Ideas number 4 & 5 were suggested by Urban D. Mueler. 
+
+1. Converting "bytes" and "shorts" to "ints"
+
+MikMod's roots as a DOS program are evident in its extensive use of
+8-bit and 16-bit integers. Since Java is a 32-bit environment, those
+data types are handled slower than ints, which are 32-bit integers.
+
+Even if the value those variables contain never exceeds the ranges of
+-127 to 128 or -32768 - 32767 then declaring them as "ints" will still
+make the calculations faster.
+
+This modification may require the addition of more range checks. Plus,
+there are times when they should not be modified. For example, the
+array of bytes that contains the sound data and is sent to the audio
+driver.
+
+I had to add some "(short)( expression )" or "(byte)( expression )"
+casts too, and this modification may make it possible to eliminate
+them. (which should be done, for the same reason)
+
+
+
+2. Making more methods and variables "static"
+
+A non-static method requires the interpreter to pass the object's
+reference as an invisible first parameter. A static method, which can
+be called without an object instance, probably does not pass the object
+reference. Thus, we can save some precious time by converting large
+hierarchies of methods and the member variables they use into static
+ones.
+
+Basically, one can make all the methods and member variables in the
+program (except perhaps of the various loaders and drivers) static and
+thus save a lot of time, because we will not have to pass the
+references to the calling object, or keep using "m_" to get a reference
+to a different module.
+
+This proposal however, will enable only one MOD playing routine to be
+active in a single process. Thus, it's not very OOPish, because it's
+possible that a program will wish to keep several player instances,
+either to play simultaenously (via multi-threading) or switch between
+one another.
+
+
+
+3. Reducing the number of functions in the audio-generation core.
+
+The loading process of the module in JMikMod is slow, but the main
+concern should be with optimizing the speed and CPU consumption of the
+program's core. I'm refering to the routines that take the UNIMOD data
+and generate an array of bytes or shorts that contain audio data, and
+which can be sent to the audio driver.
+
+Calling a function is always a relatively time-consuming process, and
+the more functions there are in the core, the more time the calling
+itself consumes. If we combine several functions into one, we can
+eliminate a large part of this overhead.
+
+This proposal will result in a deviation from the original MikMod code.
+
+
+
+4. Optimizing the code of MixMonoNormal and friends
+
+The clVirtch.Mix* functions is where most of the overhead takes place.
+One can try to optimize them by:
+
+A. Eliminating the use of the extra variable sample, and using dest_idx
+in a more optimized way.
+B. Loop unrolling: more than one mixing instruction inside a loop.
+
+
+5. Sample Prerendering
+
+We can prerender the samples with the appropriate mixing function and
+keep a
+(sample_index, lvolmul, increment) -> buffer_index
+hash to map them to their prerendered buffers. Then the mixing routine
+will look like that:
+dest[idx] = src1[idx] + src2[idx] + src3[idx] + src4[idx];
+
+
+
+
+
+
+
+
+
+
+
+
+

source/java/docs/PortingNotes.txt

+Info about MMcpp v. 2.13
+
+Welcome to MMcpp - a C++ port of MikMod version 2.13 for UNIX. The
+sources in this distribution have the same functionality as MikMod and
+MikCvt, but with a different program structure. The reason for doing
+the conversion was to provide a C source that will be as close to Java
+as possible.
+
+The following changes were applied to the original source:
+
+1. Every module was encapsulated in its own class, the functions were
+turned to methods and the global variables converted to member
+variables. Some modules were implemented as a base class with two
+derived classes: one for the MikMod player and one for MikCvt.
+
+The basic architecture is that the main class (clMain or clMikCvtMain)
+contains pointers to the instances of the other module-objects, while
+every one of the latter have a pointer to the main class. In order to
+access a function or variable of another module one uses the
+"m_->[Module Name]->[FuncName/VarName]" syntax (m_ points to the main
+class in all the objects).
+
+2. The drivers and loaders architecture is implemented by managing a
+list of pointers to classes that are derived from the generic classes
+clDRIVER and clLOADER. Those contain a number of methods declared as
+'virtual', which are overrided by the specific loaders or modules.
+
+3. The typedefs UBYTE, SBYTE, UWORD, etc, were removed and replaced
+with their native C declarations. Unsigned bytes, words or double-words
+, that are not present in Java, were eliminated and replaced with
+signed data types.
+
+The header file "mtypes.h" now contains a Java-compatible "byte" alias
+for signed char, and a 'boolean' type with "true" and "false" values
+defined. The type 'char' was replaced with 'byte' were appropriated and
+'boolean' was used to declare True/False variables.
+
+Finally, the keyword 'null' now comes instead of 'NULL' in the source.
+
+Important Note:
+---------------
+
+Like Java, 'int' stands for a 32-bit signed integer. 'long' is not used
+because in Java, it represents a 64-bit integer. Therefore, it is
+possible that the code compile only on 32-bit platforms.
+
+
+4. I added two classes: String and RandomAccessFile that act much like
+their Java equivalents. They are used to replace the traditional C
+string operations and file I/O in the source.
+
+5. Calls to other libc routines (especially malloc, memcmp and
+friends) that may not be compatible with Java, were replaced by code
+that uses only the C/Java operators.
+
+6. Pointer arithmetics and pointer casting were eliminated.
+
+7. I make sure that all conditions in ifs, loops, etc. accept a boolean
+expression and not a mere integer. Java will not accept such constructs
+as 'if (1)'.

source/java/docs/README.java.txt

+
+Welcome to the beta port of MikMod to Java. This document is made of
+the following sections:
+
+-1- Introduction
+-2- Compatibility
+-3- Building the program
+-4- Running the program
+-5- Copyright
+-6- Why did I do it and future intentions
+-7- List of relevant URLs
+
+
+
+
+-1- Introduction
+
+This is a port of the MikMod MOD-player to Java. MikMod is basically
+written in ANSI C, so a lot of recoding was involved in converting it
+to Java. The documents in this directory are specific for the Java
+port; for more information about the structure of the code, you should
+consult the documents in the docs/ sub-directory of the standard MikMod
+for UNIX distribution.
+
+The other file in this directory are:
+
+Changes_From_C.txt  - lists the changes I applied to convert the code
+                      from C to Java.
+license.txt         - the copyright policy (copied from the ANSI C
+                      distribution)
+Optimizing.txt      - some ideas about how to optimize the code.
+
+This distribution is source only, so you'll need a Java compiler (such
+as the JDK's 'javac' to compile it). Please read the other sections of
+this document before you try to use it.
+
+	Shlomi Fish
+
+
+
+
+-2- Compatibility
+
+This package was developed on the JDK v. 1.0.2 on an i386-Linux. I
+tested it and it compiled on JDK 1.1.x, but with many warnings about
+"depracated" API functions.
+
+To play sound through the audio driver, one needs to write a native
+Java extension in C. The archive contains the code for a Linux
+extension for JDK 1.0.2. I think the code for other platforms can be
+written without modifying the Java source. "Playing" by writing to the
+"music.raw" file can be done on any Java virtual machine.
+
+JavaSoft's site mentions that a "Java Sound API" is planned, so a
+MikMod driver that uses it can be written, once the sound API becomes
+available to the public.
+
+The code is based on mikmod for UNIX v. 2.14 which is available in the
+Linux archive on sunsite.unc.edu . (I think it's some 2.13-2.14
+intermediate version) To modify it to the latest version, I suggest
+running 'diff' between the two versions, to see where changes were
+applied. Then find the corresponding places in the Java code, and
+modify it accordingly.
+
+This code was tested on a Pentium 166 running Linux (2.0.x) with
+JDK1.0.2. Both mikmod and mikcvt run smoothly but very slow. Java
+mikmod took on average 80% of the system's CPU according to the output
+of the "ps" command.
+
+It was also compiled and run on a Pentium Pro with WinNT 4.0 and JDK
+1.1.4. Both programs run much faster, but it's probably because of the
+faster computer.
+
+
+
+
+
+-3- Building the program
+
+The make file "source/Makefile" is intended for GNU make, so if it's
+present you can just type 'make' to build everything. The default java
+compiler name is javac, and if it isn't you'll need to modify the
+makefile a bit.
+
+Building the audio-driver is not trivial on a machine which isn't
+Linux. The makefile and and source files under the sub-directory
+'source/dll' can generate it on a Linux, but they need to be modified,
+and possibly re-generated by "javah" so they'll compile on another
+platform. You can use the drivers in the MikMod for UNIX package to 
+code the native driver for your platform.
+
+
+
+
+
+
+-4- Running the program
+
+Both programs should be run from a command shell (they are Java
+applications that make use of the command line arguments). To invoke
+Java MikMod type:
+
+java MikModApp [standard mikmod arguments]
+
+and for Java mikcvt:
+
+java MikCvtApp [file path]
+
+Everything should work much like the C programs except that:
+
+1. Output is not fully compatible.
+
+2. Input is not available. (press Ctrl-C to abort the program).
+
+3. It could be much slower.
+
+
+
+
+-5- Copyright
+
+The copyright policy remains the same as in mikmod for UNIX. Since it
+turns out that Jean-Paul Mikkers cancelled the shareware status of
+MikMod and made it "free" software.
+
+You can inspect the updated license (taken from mikmod-3.0.3) in the
+file license.txt.
+
+
+
+-6- Why did I do it and future intentions
+
+Well, I did it for fun and so I can experience more with the Java
+language. As far as I'm concerned those objectives were achieved, even
+though MikMod for Java is not very operational because it's slow.
+
+There is a list of code modifications I believe can be applied to
+optimize it in the file Optimizations.txt. Also, can someone test it on
+a JIT-based Java runtime environment? (and let me know of the results)
+
+Finally, if someone (preferablly with some time, and a
+computer that is permanently connected to the Internet) wishes to take
+over this "project", I would be more than happy to do so. Right now, it
+doesn't look like there's much interest in it anyway.
+
+
+
+
+
+-7- List of relevant URLs
+
+http://www.chiark.greenend.org.uk/~stevem/mikmod/
+
+       The MikMod Developement Homepage - contains latest sources to
+the UNIX version, info on several mailing lists and links to other
+MikMod related sites.
+
+http://www.javasoft.com/product/jdk/
+
+	Various Information about Sun's JDK.
+
+http://www.kaffe.org/
+
+	Kaffe is a freely available JIT-based runtime environment for
+UNIXes. 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

source/java/docs/license.txt

+MikMod is now under a "free-with-no-strings-attached-if-it-breaks-you-get-to-
+keep-both-pieces" type of license.  Basically this means:
+
+a) We're not responsible for anything you do with this program, anything
+anything this program does to you, or for the little incident involving
+the goat, the nun, and the jar of vasoline that occurred last summer.
+
+b) We're not charging you anything for this.  You don't owe us anything.
+On the other hand, we don't owe you anything, either.  Try to keep that in
+mind when writing us...  We'd also prefer that, should you pass this program
+on to friends, that you keep it free for them too.  And keep this message 
+intact as well.
+
+
+This is open-source software.  That means the source code is free
+for you to inspect and dissect, learn from, be disgusted by, whatever.
+If you make any great additions to MikMod, we'd like to see them!
+
+											- Peter Amstutz

source/java/source/Makefile

+# A GNU make makefile for MikMod for Java
+# 
+# May be compatible with other make programs too, but I cannot guarantee
+# that
+#
+
+
+
+COMPILE = javac
+
+CFLAGS = -g
+
+LOADERS = MikMod/Loaders/MOD_Loader.class \
+	MikMod/Loaders/S3M_Loader.class \
+        MikMod/Loaders/M15_Loader.class \
+        MikMod/Loaders/UNI_Loader.class \
+        MikMod/Loaders/MTM_Loader.class \
+        MikMod/Loaders/S69_Loader.class \
+        MikMod/Loaders/ULT_Loader.class \
+        MikMod/Loaders/XM_Loader.class \
+        MikMod/Loaders/STM_Loader.class
+
+DRIVERS = MikMod/Drivers/Raw_Driver.class  \
+        MikMod/Drivers/NS_Driver.class  \
+        MikMod/Drivers/Native_Driver.class
+
+OBJS =  MikMod/clMainBase.class \
+        MikMod/MUniTrk/clMUniTrk.class \
+        MikMod/MLoader/clMLoader.class  \
+	MikMod/clDisplayBase.class \
+        MikMod/MMIO/MMIO.class \
+	MikMod/UNIMOD.class \
+        MikMod/INSTRUMENT.class \
+        MikMod/SAMPLE.class \
+        MikMod/ENVPT.class \
+        MikMod/curmod.class \
+	MikMod/clLOADER.class \
+        $(LOADERS)
+
+
+MIKCVT_OBJS = MikMod/clMDriverBase.class \
+	MikMod/clMikCvtMain.class \
+        MikCvtApp.class
+
+
+
+MIKMOD_OBJS = MikMod/ENVPR.class MikMod/AUDTMP.class MikMod/VINFO.class \
+	MikMod/UI/myUI.class MikMod/MDriver/clMDriver.class MikMod/Display/clDisplay.class \
+	MikMod/clMain.class MikMod/MPlayer/clMPlayer.class MikMod/Virtch/clVirtch.class \
+        MikMod/clDRIVER.class \
+        $(DRIVERS) \
+        MikModApp.class
+
+
+all: mikcvt mikmod
+
+$(OBJS) $(MIKMOD_OBJS) $(MIKCVT_OBJS): %.class: %.java
+	$(COMPILE) $(CFLAGS) $<
+
+#$(MIKMOD_OBJS): %.class: %.java
+#	$(COMPILE) $(CFLAGS) $<
+
+#$(MIKCVT_OBJS): %.class: %.java
+#	$(COMPILE) $(CFLAGS) $<
+
+native_driver: dummy
+	make -C dll/
+
+dummy:
+
+
+mikcvt: $(OBJS) $(MIKCVT_OBJS)
+
+mikmod: $(OBJS) $(MIKMOD_OBJS) native_driver

source/java/source/MikCvtApp.java

+/*
+
+Name:
+MikCvtApp.java
+
+Description:
+The Applet class that creates an instance of clMikCvtMain and calls
+clMikCvtMain.main() that operates all the runtime code. It calls it with the
+necessary "char * argv[]"-like argument.
+
+So far it's a console application (X-Windows need not be run on UNIXes) whose
+output corresponds with the UNIX version.
+
+Shlomi Fish <shlomif@ibm.net>
+
+HISTORY   (DD/MM/YY)
+=======
+
+v1.00 (20/Dec/96) - first "versioned" version
+v1.01 (03/Jan/96) - Removed argc passing, because Java can tell what is the length
+of an array length.
+
+ */
+
+import java.applet.*;
+import java.awt.*;
+
+import MikMod.*;
+
+public class MikCvtApp extends Applet implements Runnable
+{
+
+	Thread	 m_MikCvtApp = null;
+
+
+	boolean m_fStandAlone = false;
+
+
+        public static String [] my_argv = null;
+
+
+        // The main function of a standalone application.
+        public static void main(String args[])
+	{
+		MikCvtApp applet_MikCvtApp = new MikCvtApp();
+
+		applet_MikCvtApp.m_fStandAlone = true;
+                {
+                    my_argv = new String[args.length+1];
+                    my_argv[0] = new String("mikcvt");
+                    int i;
+                    for(i=0;i<args.length;i++)
+                    {
+                        my_argv[i+1] = new String(args[i]);
+                    }
+                }
+		applet_MikCvtApp.init();
+		applet_MikCvtApp.start();
+	}
+
+	public MikCvtApp()
+	{
+	}
+
+        // Return some text that identifies us
+	public String getAppletInfo()
+	{
+            return "Name: MikCvtApp: Java version of MikMod's mikcvt utility\r\n" +
+                "Original Code: Jean-Paul Mikkers and others\r\n" +
+                "Java Porting: Shlomi Fish";
+	}
+
+
+        // init() is useful only for applets.
+	public void init()
+	{
+
+	}
+
+
+	public void destroy()
+        {
+            
+	}
+
+        // This function is only used for applets, so it's not implemented
+        public void paint(Graphics g)
+	{
+	}
+
+	public void start()
+	{
+		if (m_MikCvtApp == null)
+		{
+			m_MikCvtApp = new Thread(this);
+			m_MikCvtApp.start();
+		}
+	}
+	
+	public void stop()
+	{
+		if (m_MikCvtApp != null)
+		{
+			m_MikCvtApp.stop();
+			m_MikCvtApp = null;
+		}
+
+	}
+
+	public void run()
+	{
+            clMikCvtMain mikCvt = new clMikCvtMain();
+            
+            mikCvt.main(my_argv);
+
+            stop();
+
+	}
+
+
+
+
+}

source/java/source/MikMod/AUDTMP.java

+package MikMod;
+
+public class AUDTMP extends Object
+{
+	public INSTRUMENT 	i;
+	public SAMPLE      s;
+
+	public int fadevol;		/* fading volume */
+
+	public ENVPR venv;
+	public ENVPR penv;
+
+	public boolean keyon;		/* if true=key is pressed. */
+	public boolean kick;			/* if true=sample has to be restarted */
+	public short sample;		/* which sample number (0-31) */
+	public short handle;		/* which sample-handle */
+
+	public int start;		/* The start byte index in the sample */
+
+	public short panning;		/* panning position */
+	public short pansspd;		/* panslide speed */
+
+	public byte volume;		/* amiga volume (0 t/m 64) to play the sample at */
+	public int period;		/* period to play the sample at */
+
+	/* You should not have to use the values
+	   below in the player routine */
+
+	public byte transpose;
+
+	public short note;			/* */
+
+	public short ownper;
+	public short ownvol;
+
+        public short [] row;			/* row currently playing on this channel */
+        public int row_pos;
+
+	public byte retrig;		/* retrig value (0 means don't retrig) */
+	public int c2spd;		/* what finetune to use */
+
+	public byte tmpvolume;	/* tmp volume */
+
+	public int tmpperiod;	/* tmp period */
+	public int wantedperiod;	/* period to slide to (with effect 3 or 5) */
+
+	public int slidespeed;	/* */
+	public int portspeed;	/* noteslide speed (toneportamento) */
+
+	public short s3mtremor;	/* s3m tremor (effect I) counter */
+	public short s3mtronof;	/* s3m tremor ontime/offtime */
+
+	public short s3mvolslide;	/* last used volslide */
+
+	public short s3mrtgspeed;	/* last used retrig speed */
+	public short s3mrtgslide;	/* last used retrig slide */
+
+	public short glissando;	/* glissando (0 means off) */
+	public short wavecontrol;	/* */
+
+	public byte vibpos;		/* current vibrato position */
+	public short vibspd;		/* "" speed */
+	public short vibdepth;		/* "" depth */
+
+	public byte trmpos;		/* current tremolo position */
+	public short trmspd;		/* "" speed */
+	public short trmdepth;		/* "" depth */
+
+        public int soffset;		/* last used sample-offset (effect 9) */
+
+        public AUDTMP()
+        {
+            venv = new ENVPR();
+            penv = new ENVPR();
+        }
+}

source/java/source/MikMod/Display/clDisplay.java

+/*
+
+Name:
+DISPLAY.C
+
+Description:
+Ncurses display section of mikmod - bare unix version.
+
+Should deal with all the m_.quiet options and refresh() after ncurses calls,
+so just call these functions direct wherever needed. 
+
+Steve McIntyre <stevem@chiark.greenend.org.uk>
+
+HISTORY
+=======
+
+v1.00 (06/12/96) - first "versioned" version
+v1.01 (06/12/96) - fixed update_name_display for Solaris - add "(null)" if necessary
+v1.02 (16/12/96) - minor cosmetic change to display_error()
+
+*/
+
+package MikMod.Display;
+
+import MikMod.*;
+import MikMod.MUniTrk.*;
+
+public class clDisplay extends clDisplayBase
+{
+
+        public clMain m_;
+
+        public final String pausebanner =
+"'||''|.    |   '||'  '|' .|'''.| '||''''| '||''|.\n" +
+" ||   ||  |||   ||    |  ||..  '  ||  .    ||   || \n" +
+" ||...|' |  ||  ||    |   ''|||.  ||''|    ||    ||\n"+
+" ||     .''''|. ||    | .     '|| ||       ||    ||\n"+
+".||.   .|.  .||. '|..'  |'....|' .||.....|.||...|'\n"
+        ;
+
+        public final String loadbanner =
+"'||'                          '||   ||\n"+
+" ||         ...    ....     .. ||  ...  .. ...    ... . \n"+
+" ||       .|  '|. '' .||  .'  '||   ||   ||  ||  || ||  \n"+
+" ||       ||   || .|' ||  |.   ||   ||   ||  ||   |''   \n"+
+".||.....|  '|..|' '|..'|' '|..'||. .||. .||. || .'||||. \n"+
+"                                                .|....'\n"
+
+        ;
+            
+        public final String extractbanner =
+"'||''''|          .                         .   ||\n"+
+" ||  .   ... ....||. ... ..  ....    .... .||. ... .. ...   ... . \n"+
+" ||''|    '|..'  ||   ||' '''' .|| .|   '' ||   ||  ||  || || || \n"+
+" ||        .|.   ||   ||    .|' || ||      ||   ||  ||  ||  |'' \n"+
+".||.....|.|  ||. '|.'.||.   '|..'|' '|...' '|.'.||..||. ||.'||||. \n"+
+"                                                          .|....'\n"
+    
+        ;
+            
+
+	protected int cWritten;
+    
+
+public clDisplay(clMain theMain)
+{
+    m_ = theMain;
+}
+
+protected final int stdscr=0;
+
+public void initscr() {}
+public void cbreak() {}
+public void noecho() {}
+public void nonl() {}
+public void nodelay(int i, boolean b) {}
+public void keypad(int i, boolean b) {}
+public void clear() {}
+public void addstr(String s)
+{
+    System.out.print(s);
+}
+public void refresh() {}
+public void endwin() {}
+
+public void init_display()
+{
+	if(m_.quiet) return;
+	initscr(); 
+	cbreak(); 
+	noecho(); 
+	nonl(); 
+	nodelay(stdscr, true);
+	keypad(stdscr, true);
+        m_.cur_mod.version = m_.mikversion;
+}
+
+
+public void display_version()
+{
+	if(m_.quiet) return;
+
+	/* always use display_verion first, so clear call is OK here... */
+	clear(); 
+
+	addstr(m_.cur_mod.version);
+	refresh();
+}	
+
+public void display_driver()
+{
+	if(m_.quiet) return;
+	addstr(m_.cur_mod.driver);
+	refresh();
+}	
+
+public void display_file()
+{
+        if(m_.quiet) return;
+        addstr(m_.cur_mod.file_output);
+	refresh();
+}	
+
+public void display_name()
+{
+	if(m_.quiet) return;
+	addstr(m_.cur_mod.name_type);
+	refresh();
+}	
+
+public void display_status()
+{
+	if(m_.quiet) return;
+	addstr(m_.cur_mod.status);
+	refresh();
+}	
+
+public void display_pausebanner()
+{
+	if(m_.quiet) return;
+	addstr(pausebanner);
+	refresh();
+}	
+
+public void display_extractbanner()
+{
+	if(m_.quiet) return;
+	addstr(extractbanner);
+	refresh();
+}	
+
+public void display_loadbanner()
+{
+	if(m_.quiet) return;
+	addstr(loadbanner);
+	refresh();
+}	
+
+public void display_error(String myerr, String myerr_file)
+{
+        if(m_.quiet) return;
+        //printw("Non-fatal Error:\n %s: \"%s\".\n",(const char *)*myerr,(const char *)*myerr_file);
+        addstr("Non-fatal Error:\n " + myerr + ": \"" + myerr_file + "\".\n");
+        refresh();
+        try {
+            Thread.sleep(3000); //sleep(3);
+        }
+        catch (InterruptedException intexp1)
+        {
+        }
+}	
+
+public void display_driver_error(String myerr)
+{
+	if(m_.quiet) return;
+        //printw("Driver error: %s.\n",(const char *)*myerr);
+        addstr("Driver error: " + myerr + ".\n");
+	refresh();
+}	
+
+public void display_all()
+{
+	if(m_.quiet) return;
+	display_version();
+	display_driver();
+	display_file();
+	display_name();
+	display_status();
+}	
+
+public void update_driver_display()
+{
+        if(m_.quiet) return;
+
+        m_.cur_mod.driver = m_.MDriver.GetActiveDriver().Name + ": " +
+            (((m_.MDriver.md_mode & m_.DMODE_16BITS) != 0) ? 16:8) + " bit " +
+            (((m_.MDriver.md_mode & m_.DMODE_INTERP) != 0) ? "interpolated":"normal") + " " +
+            (((m_.MDriver.md_mode & m_.DMODE_STEREO) != 0) ? "stereo":"mono") + ", " +
+            m_.MDriver.md_mixfreq + " Hz\n";
+            
+}
+
+public void update_file_display()
+{
+        if(m_.quiet) return;
+        m_.cur_mod.file_output = "File: " + m_.cur_mod.filename + m_.d_text[m_.cur_mod.deleted?1:0] + "\n";
+}
+
+public void update_name_display()
+{
+	if(m_.quiet) return;
+
+        m_.cur_mod.name_type = "Name: "  +
+            ((m_.cur_mod.songname.length()==0) ? "(null)" : (m_.cur_mod.songname)) +
+            "\n" +
+            "Type: " + m_.cur_mod.modtype + ", " +
+            "Periods: " + (((m_.cur_mod.flags & m_.MUniTrk.UF_XMPERIODS) != 0) ? "XM type" : "mod type") +
+            "," + (((m_.cur_mod.flags & m_.MUniTrk.UF_LINEAR) != 0) ? "Linear" : "Log") + "\n";
+}
+
+public void update_status_display()
+{
+        if(m_.quiet) return;
+        m_.cur_mod.status = "\rpat:" + m_.cur_mod.sngpos + "/" + m_.cur_mod.numpat +
+            " pos:" + m_.cur_mod.patpos +
+            " spd:" + m_.MPlayer.mp_sngspd +
+            " bpm:" + (m_.MPlayer.speed_constant*100) +
+            "% vol:" + m_.MPlayer.mp_volume + "% ";
+}
+
+public void exit_display()
+{
+	if(m_.quiet) return;
+	endwin();
+}
+
+
+    
+
+}

source/java/source/MikMod/Drivers/NS_Driver.java

+/*
+
+Name:
+DRV_NOS.C
+
+Description:
+Mikmod driver for no output on any soundcard, monitor, keyboard, or whatever :)
+
+Portability:
+All systems - All compilers
+
+*/
+
+package MikMod.Drivers;
+
+import java.io.*;
+import MikMod.*;
+
+public class NS_Driver extends clDRIVER
+{
+    byte buf[];
+    
+public NS_Driver(clMain theMain)
+{
+    super(theMain);
+    Name = new String("No Sound");
+    Version = new String("MikMod Nosound Driver v2.10 - (c) Creative Silence");
+
+    buf = new byte[1024];
+}
+
+public boolean IsPresent()
+{
+	return true;
+}
+
+public short SampleLoad(RandomAccessFile fp,int s,int a,int b,int f)
+{
+	return 1;
+}
+
+public int Init()
+{
+	return 1;
+}
+
+public void PlayStart()
+{
+	m_.Virtch.VC_PlayStart();
+}
+
+public void PlayStop()
+{
+	m_.Virtch.VC_PlayStop();
+}
+
+public void Update()
+{
+	m_.Virtch.VC_WriteBytes(buf, buf.length);
+}
+
+}

source/java/source/MikMod/Drivers/Native_Driver.java

+/*
+
+Name:
+DRV_VOX.C
+
+Description:
+Mikmod driver for output on linux and FreeBSD Open Sound System (OSS)
+(/dev/dsp) 
+
+Portability:  VoxWare/SS/OSS land. Linux, FreeBSD (NetBSD & SCO?)
+
+New fragment configuration code done by Rao:
+============================================
+
+You can use the environment variables 'MM_FRAGSIZE' and 'MM_NUMFRAGS' to 
+override the default size & number of audio buffer fragments. If you 
+experience crackles & pops, try experimenting with these values.
+
+Read experimental.txt within the VoxWare package for information on these 
+options. They are _VERY_ important with relation to sound popping and smooth
+playback.                                                        
+
+In general, the slower your system, the higher these values need to be. 
+
+MM_NUMFRAGS is within the range 2 to 255 (decimal)
+
+MM_FRAGSIZE is is within the range 7 to 17 (dec). The requested fragment size 
+will be 2^MM_FRAGSIZE
+
+*/
+
+package MikMod.Drivers;
+
+import java.io.*;
+import MikMod.*;
+
+public class Native_Driver extends clDRIVER
+{
+
+static {
+    System.loadLibrary("jmikmod_drv");
+}
+    
+    protected int sndfd;
+    protected int fragmentsize;
+    protected byte audiobuffer[];
+
+    protected final int DEFAULT_FRAGSIZE = 17;
+    protected final int DEFAULT_NUMFRAGS = 2;
+
+native int sysCheckAccess();
+native int sysOpenSound(int iFreq, int iBitsNum, int iStereo, int iBlockSize, String szError);
+native int sysCloseSound(int lHandle);
+native int sysWriteBuffer(int lHandle, byte bBuffer[], int iLen);
+
+    
+public Native_Driver(clMain theMain)
+{
+    super(theMain);
+    sndfd = 0;
+    fragmentsize = 0;
+    audiobuffer = null;
+
+    Name = new String("Native-API Sound Driver");
+    Version = new String("Native-API Sound Driver v1.0 - by Shlomi Fish");
+}
+
+public short SampleLoad(RandomAccessFile fp,int size,int reppos,int repend,int flags)
+{
+	return m_.Virtch.VC_SampleLoad(fp,size,reppos,repend,flags);
+}
+
+public void SampleUnLoad(short handle)
+{
+	m_.Virtch.VC_SampleUnload(handle);
+}
+
+
+public boolean IsPresent()
+{
+    //return (access("/dev/dsp",W_OK)==0);
+    return (sysCheckAccess() != 0);
+}
+
+
+public int Init()
+{
+	//char *env;
+	int play_precision,play_stereo,play_rate;
+	int fragsize,numfrags;
+
+        //fragsize=(env=getenv("MM_FRAGSIZE")) ? atoi(env) : DEFAULT_FRAGSIZE;
+        fragsize = DEFAULT_FRAGSIZE;
+        //numfrags=(env=getenv("MM_NUMFRAGS")) ? atoi(env) : DEFAULT_NUMFRAGS;
+        numfrags = DEFAULT_NUMFRAGS;
+		
+	if(fragsize<7 || fragsize>17)  fragsize=DEFAULT_FRAGSIZE;
+	if(numfrags<2 || numfrags>255) numfrags=DEFAULT_NUMFRAGS;
+
+	fragmentsize=(numfrags<<16) | fragsize;
+	
+/*#ifndef __FreeBSD__
+	if(ioctl(sndfd, SNDCTL_DSP_SETFRAGMENT, &fragmentsize)<0){
+		*m_.mmIO.myerr = "Buffer fragment failed";
+		close(sndfd);
+		return 0;
+	}
+#endif /* __FreeBSD__ */
+
+	play_precision = ((m_.MDriver.md_mode & m_.DMODE_16BITS) != 0) ? 16 : 8;
+	play_stereo= ((m_.MDriver.md_mode & m_.DMODE_STEREO) != 0) ? 1 : 0;
+	play_rate=m_.MDriver.md_mixfreq;
+
+        sndfd = sysOpenSound(play_rate, play_precision, play_stereo, fragmentsize, m_.mmIO.myerr);
+        
+        if (sndfd == -1)
+        {
+            return 0;
+        }
+
+/*	Lose this for now - it will confuse ncurses etc...
+	printf("Fragment size is %ld\n",fragmentsize); */
+
+        if(!m_.Virtch.VC_Init()){
+                sysCloseSound(sndfd);
+		return 0;
+	}
+
+        audiobuffer = new byte[fragmentsize];
+	
+	if(audiobuffer==null){
+		m_.Virtch.VC_Exit();
+		sysCloseSound(sndfd);
+		return 0;
+	}
+	
+	return 1;
+}
+
+
+public void Exit()
+{
+        //free(audiobuffer);
+        audiobuffer = null;
+	m_.Virtch.VC_Exit();
+	sysCloseSound(sndfd);
+}
+
+public void PlayStart()
+{
+	m_.Virtch.VC_PlayStart();
+}
+
+public void PlayStop()
+{
+	m_.Virtch.VC_PlayStop();
+}
+
+public void Update()
+{
+	m_.Virtch.VC_WriteBytes(audiobuffer,fragmentsize);
+        sysWriteBuffer(sndfd, audiobuffer, fragmentsize);
+}
+
+public void VoiceSetVolume(short voice,short vol)
+{
+	m_.Virtch.VC_VoiceSetVolume(voice, vol);
+}
+
+public void VoiceSetFrequency(short voice,int frq)
+{
+	m_.Virtch.VC_VoiceSetFrequency(voice,frq);
+}
+
+public void VoiceSetPanning(short voice,short pan)
+{
+	m_.Virtch.VC_VoiceSetPanning(voice,pan);
+}
+
+public void VoicePlay(short voice,short handle,int start,int size,int reppos,int repend,int flags)
+{
+	m_.Virtch.VC_VoicePlay(voice,handle,start,size,reppos,repend,flags);
+}
+
+
+}

source/java/source/MikMod/Drivers/Raw_Driver.java

+/*
+
+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
+
+*/
+
+package MikMod.Drivers;
+
+import java.io.*;
+import MikMod.*;
+
+public class Raw_Driver extends clDRIVER
+{
+    public final int RAWBUFFERSIZE = 8192;
+
+    protected RandomAccessFile rawout;
+
+    byte RAW_DMABUF[]; //[RAWBUFFERSIZE];
+    
+
+public Raw_Driver(clMain theMain)
+//	: clDRIVER(theMain)
+{
+        super(theMain);
+        int i;
+
+        Name = new String("music.raw file");
+	Version = new String("MikMod music.raw file output driver v1.10");
+
+        rawout = null;
+        RAW_DMABUF = new byte[RAWBUFFERSIZE];
+        for(i=0;i<RAWBUFFERSIZE;i++)
+            RAW_DMABUF[i] = 0;
+}
+
+
+public boolean IsPresent()
+{
+	return true;
+}
+
+
+public int Init()
+{
+        //if(!(rawout=fopen("music.raw","wb"))){
+    try {
+        if ((rawout = new RandomAccessFile("music.raw", "rw")) == null) {
+		m_.mmIO.myerr="Couldn't open output file 'music.raw'";
+		return 0;
+	}
+
+	if(!m_.Virtch.VC_Init()){
+                rawout.close();
+                rawout = null;
+		return 0;
+	}
+
+        return 1;
+    }
+    catch (IOException ioe1)
+    {
+        return 0;
+    }
+}
+
+
+
+public void Exit()
+{
+    try {
+	m_.Virtch.VC_Exit();
+        rawout.close();
+        rawout = null;
+    }
+    catch (IOException ioe1)
+    {
+    }
+}
+
+
+public void Update()
+{
+    try
+    {
+	m_.Virtch.VC_WriteBytes(RAW_DMABUF,RAWBUFFERSIZE);
+        //fwrite(RAW_DMABUF,RAWBUFFERSIZE,1,rawout);
+        rawout.write(RAW_DMABUF,0,RAWBUFFERSIZE);
+    }
+    catch (IOException ioe1)
+    {
+    }
+}
+
+public short SampleLoad(RandomAccessFile fp,int length,int reppos,int repend,int flags)
+{
+	return m_.Virtch.VC_SampleLoad(fp,length,reppos,repend,flags);
+}
+
+public void SampleUnLoad (short handle)
+{
+	m_.Virtch.VC_SampleUnload(handle);
+}
+
+public void PlayStart()
+{
+	m_.Virtch.VC_PlayStart();
+}
+
+public void PlayStop()
+{
+	m_.Virtch.VC_PlayStop();
+}
+
+public void VoiceSetVolume(short voice,short vol)
+{
+	m_.Virtch.VC_VoiceSetVolume(voice, vol);
+}
+
+public void VoiceSetFrequency(short voice,int frq)
+{
+	m_.Virtch.VC_VoiceSetFrequency(voice,frq);
+}
+
+public void VoiceSetPanning(short voice,short pan)
+{
+	m_.Virtch.VC_VoiceSetPanning(voice,pan);
+}
+
+public void VoicePlay(short voice,short handle,int start,int size,int reppos,int repend,int flags)
+{
+	m_.Virtch.VC_VoicePlay(voice,handle,start,size,reppos,repend,flags);
+}
+
+}

source/java/source/MikMod/ENVPR.java

+package MikMod;
+
+public class ENVPR extends Object
+{
+	public short flg;          /* envelope flag */
+	public short pts;			/* number of envelope points */
+	public short sus;			/* envelope sustain index */
+	public short beg;			/* envelope loop begin */
+	public short end;			/* envelope loop end */
+	public short p;			/* current envelope counter */
+	public short a;			/* envelope index a */
+	public short b;			/* envelope index b */
+        public ENVPT env[];			/* envelope points */
+
+        public ENVPR()
+        {
+        }
+};

source/java/source/MikMod/ENVPT.java

+package MikMod;
+
+public class ENVPT extends Object
+{
+	public short pos;
+	public short val;
+}

source/java/source/MikMod/INSTRUMENT.java

+package MikMod;
+
+
+public class INSTRUMENT extends Object
+{
+	public short numsmp;
+	public short samplenumber[];
+
+	public short volflg;           /* bit 0: on 1: sustain 2: loop */
+	public short volpts;
+	public short volsus;
+	public short volbeg;
+	public short volend;
+	public ENVPT volenv[];
+
+	public short panflg;           /* bit 0: on 1: sustain 2: loop */
+	public short panpts;
+	public short pansus;
+	public short panbeg;
+	public short panend;
+	public ENVPT panenv[];
+
+	public short vibtype;
+	public short vibsweep;
+	public short vibdepth;
+	public short vibrate;
+
+	public int volfade;
+	public String  insname;
+	public SAMPLE samples[];
+
+	public INSTRUMENT()
+	{
+		samplenumber = new short[96];
+		volenv = new ENVPT[12];
+		panenv = new ENVPT[12];
+		int i;
+		for(i=0;i<12;i++)
+		{
+			volenv[i] = new ENVPT();
+			panenv[i] = new ENVPT();
+		}
+	}
+}

source/java/source/MikMod/Loaders/M15_Loader.java

+/*
+
+Name:
+LOAD_M15.C
+
+Description:
+15 instrument MOD loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+
+
+/*************************************************************************
+*************************************************************************/
+
+package MikMod.Loaders;
+
+import MikMod.*;
+import java.io.*;
+
+
+class M15_MSAMPINFO{       /* sample header as it appears in a module */
+        byte  samplename[];
+	int length;
+	short finetune;
+	short volume;
+	int reppos;
+        int replen;
+
+        public M15_MSAMPINFO()
+        {
+            samplename = new byte[22];
+        }
+}
+
+
+class M15_MODULEHEADER{                 /* verbatim module header */
+        byte       songname[];                /* the songname.. */
+	M15_MSAMPINFO  samples[];                         /* all sampleinfo */
+	short      songlength;                          /* number of patterns used */
+	short      magic1;                                      /* should be 127 */
+        byte      positions[];                      /* which pattern to play at pos */
+
+        public M15_MODULEHEADER()
+        {
+            songname = new byte[20];
+            samples = new M15_MSAMPINFO[15];
+            int i;
+            for(i=0;i<15;i++)
+                samples[i] = new M15_MSAMPINFO();
+            positions = new byte[128];
+        }
+}
+
+
+class M15_MODNOTE{
+	short a,b,c,d;
+};
+
+
+/*************************************************************************
+*************************************************************************/
+
+
+public class M15_Loader extends clLOADER
+{
+
+	protected M15_MODULEHEADER mh;        /* raw as-is module header */
+	protected M15_MODNOTE patbuf[];
+
+
+final public short M15_npertab[] = {
+
+/* -> 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
+};
+
+
+public M15_Loader(clMainBase theMain)
+{
+	super(theMain);
+
+	mh = null;
+	patbuf = null;
+	type = new String("15-instrument module");
+	version = new String("Portable MOD-15 loader v0.1");
+}
+
+
+public boolean LoadModuleHeader(M15_MODULEHEADER mh)
+{
+        try {
+
+        int t;
+
+	m_.mmIO._mm_read_str(mh.songname,20,m_.MLoader.modfp);
+
+	for(t=0;t<15;t++){
+		//M15_MSAMPINFO *s= &mh.samples[t];
+		m_.mmIO._mm_read_str(mh.samples[t].samplename,22,m_.MLoader.modfp);
+		mh.samples[t].length	=m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
+		mh.samples[t].finetune	=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+		mh.samples[t].volume	=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+		mh.samples[t].reppos	=m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
+		mh.samples[t].replen	=m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
+	}
+
+	mh.songlength	=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+	mh.magic1		=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);                                      /* should be 127 */
+	m_.mmIO._mm_read_SBYTES(mh.positions,128,m_.MLoader.modfp);
+
+        //return(!feof(m_.MLoader.modfp));
+        return (m_.MLoader.modfp.getFilePointer() < m_.MLoader.modfp.length());
+
+        }
+        catch (IOException ioe1)
+        {
+            return false;
+        }
+}
+
+
+
+public boolean Test()
+{
+	int t;
+	M15_MODULEHEADER mh = new M15_MODULEHEADER();
+
+	if(!LoadModuleHeader(mh)) return false;
+
+	for(t=0;t<15;t++){
+
+		/* all finetunes should be zero */
+		if(mh.samples[t].finetune!=0) return false;
+
+		/* all volumes should be <=64 */
+		if(mh.samples[t].volume>64) return false;
+	}
+	if(mh.magic1>127) return false;    /* and magic1 should be <128 */
+
+	return true;
+}
+
+
+public boolean Init()
+{
+        int i,j;
+
+        patbuf=null;
+        // if(!(mh=(M15_MODULEHEADER *)m_.MLoader.MyCalloc(1,sizeof(M15_MODULEHEADER)))) return 0;
+        mh = new M15_MODULEHEADER();
+
+        mh.songlength = mh.magic1 = 0;
+        for(i=0;i<20;i++)
+            mh.songname[i] = 0;
+
+        for(i=0;i<128;i++)
+            mh.positions[i] = 0;
+
+        for(i=0;i<15;i++)
+        {
+            mh.samples[i].length = mh.samples[i].reppos =
+                mh.samples[i].replen = 0;
+            mh.samples[i].finetune = mh.samples[i].volume = (short)0;
+            for(j=0;j<22;j++)
+                mh.samples[i].samplename[j] = 0;
+        }
+
+	return true;
+}
+
+
+public void Cleanup()
+{
+        if (mh != null) mh = null;
+	if(patbuf!=null) patbuf = null;
+}
+
+
+/*
+
+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 m_.MLoader.of sam-  note period.   bits m_.MLoader.of sam-
+ple number.                  ple number.
+
+
+*/
+
+
+public void M15_ConvertNote(M15_MODNOTE n)
+{
+	short instrument,effect,effdat,note;
+	int period;
+
+	/* extract the various information from the 4 bytes that
+	   make up a single note */
+
+	instrument=(short)((n.a&0x10)|(n.c>>4));
+	period=(((int)n.a&0xf)<<8)+n.b;
+	effect=(short)(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){
+		m_.MUniTrk.UniInstrument((short)(instrument-1));
+	}
+
+	if(note!=0){
+		m_.MUniTrk.UniNote((short)(note+23));
+	}
+
+	m_.MUniTrk.UniPTEffect(effect,effdat);
+}
+
+
+
+public short [] M15_ConvertTrack(M15_MODNOTE [] n, int offset)
+{
+	int t;
+
+        m_.MUniTrk.UniReset();
+        int n_ptr = offset;
+	for(t=0;t<64;t++){
+		M15_ConvertNote(n[n_ptr]);
+		m_.MUniTrk.UniNewline();
+		n_ptr+=m_.MLoader.of.numchn;
+	}
+	return m_.MUniTrk.UniDup();
+}
+
+
+
+public boolean M15_LoadPatterns()
+/*
+	Loads all patterns of a modfile and converts them into the
+	3 byte format.
+*/
+{
+	int t,s,tracks=0;
+
+	if(!m_.MLoader.AllocPatterns()) return false;
+	if(!m_.MLoader.AllocTracks()) return false;
+
+	/* Allocate temporary buffer for loading
+	   and converting the patterns */
+
+        // if(!(patbuf=(MODNOTE *)m_.MLoader.MyCalloc(64*m_.MLoader.of.numchn,sizeof(MODNOTE)))) return 0;
+        patbuf = new M15_MODNOTE[64*m_.MLoader.of.numchn];
+        for(t=0;t<64*m_.MLoader.of.numchn;t++)
+            patbuf[t] = new M15_MODNOTE();
+        
+        for(t=0;t<64*m_.MLoader.of.numchn;t++)
+        {
+            patbuf[t].a = patbuf[t].b = patbuf[t].c = patbuf[t].d = 0;
+        }
+
+	for(t=0;t<m_.MLoader.of.numpat;t++){
+
+		/* Load the pattern into the temp buffer
+		   and convert it */
+
+		for(s=0;s<(64*m_.MLoader.of.numchn);s++){
+			patbuf[s].a=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+			patbuf[s].b=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+			patbuf[s].c=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+			patbuf[s].d=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
+		}
+
+		for(s=0;s<m_.MLoader.of.numchn;s++){
+			if((m_.MLoader.of.tracks[tracks++]=M15_ConvertTrack(patbuf, s)) == null) return false;
+		}
+	}
+
+	return true;
+}
+
+
+
+public boolean Load()
+{
+	int t;
+	//INSTRUMENT *d;          /* new sampleinfo structure */
+	//SAMPLE *q;
+        //M15_MSAMPINFO *s;           /* old module sampleinfo */
+        int inst_num, smpinfo_num;
+
+	/* try to read module header */
+
+	if(!LoadModuleHeader(mh)){
+		m_.mmIO.myerr=m_.ERROR_LOADING_HEADER;
+		return false;
+	}
+
+	/* set module variables */
+
+	m_.MLoader.of.initspeed=6;
+	m_.MLoader.of.inittempo=125;
+	m_.MLoader.of.numchn=4;                                                    /* get number m_.MLoader.of channels */
+	m_.MLoader.of.modtype=new String("15-instrument");             /* get ascii type m_.MLoader.of mod */
+	m_.MLoader.of.songname=m_.MLoader.DupStr(mh.songname,20);        /* make a cstr m_.MLoader.of songname */
+	m_.MLoader.of.numpos=mh.songlength;                       /* copy the songlength */
+
+        /* copy the position array */
+        for(t=0;t<128;t++)
+        {
+            m_.MLoader.of.positions[t] = mh.positions[t];
+        }
+
+        
+	/* Count the of patterns */
+
+	m_.MLoader.of.numpat=0;
+
+	for(t=0;t<128;t++){             /* <-- BUGFIX... have to check ALL positions */
+		if(m_.MLoader.of.positions[t] > m_.MLoader.of.numpat){
+			m_.MLoader.of.numpat=m_.MLoader.of.positions[t];
+		}
+	}
+	m_.MLoader.of.numpat++;
+	m_.MLoader.of.numtrk= (short)(m_.MLoader.of.numpat * m_.MLoader.of.numchn);
+
+	/* Finally, init the sampleinfo structures */
+
+	m_.MLoader.of.numins=15;
+        if(!m_.MLoader.AllocInstruments())
+            return false;
+
+	//s=mh.samples;          /* init source pointer */
+        //d=m_.MLoader.of.instruments;       /* init dest pointer */
+        smpinfo_num = 0; /* init source pointer */
+        inst_num = 0;  /* init dest pointer */
+
+	for(t=0;t<m_.MLoader.of.numins;t++){
+
+		m_.MLoader.of.instruments[inst_num].numsmp=1;
+                if(!m_.MLoader.AllocSamples((m_.MLoader.of.instruments[inst_num])))
+                    return false;
+
+		//q=m_.MLoader.of.instruments[inst_num].samples;
+
+		/* convert the samplename */
+
+		m_.MLoader.of.instruments[inst_num].insname=m_.MLoader.DupStr(mh.samples[smpinfo_num].samplename,22);
+
+		/* init the sampleinfo variables and
+		   convert the size pointers to longword format */
+
+		m_.MLoader.of.instruments[inst_num].samples[0].c2spd=m_.MLoader.finetune[mh.samples[smpinfo_num].finetune&0xf];
+		m_.MLoader.of.instruments[inst_num].samples[0].volume=mh.samples[smpinfo_num].volume;
+		m_.MLoader.of.instruments[inst_num].samples[0].loopstart=mh.samples[smpinfo_num].reppos;
+		m_.MLoader.of.instruments[inst_num].samples[0].loopend=m_.MLoader.of.instruments[inst_num].samples[0].loopstart + (mh.samples[smpinfo_num].replen<<1);
+		m_.MLoader.of.instruments[inst_num].samples[0].length=mh.samples[smpinfo_num].length<<1;
+		m_.MLoader.of.instruments[inst_num].samples[0].seekpos=0;
+
+		m_.MLoader.of.instruments[inst_num].samples[0].flags = (m_.MDriver.SF_SIGNED);
+                if(mh.samples[smpinfo_num].replen>1)
+                    m_.MLoader.of.instruments[inst_num].samples[0].flags |= (m_.MDriver.SF_LOOP);
+
+		/* fix replen if repend>length */
+
+                if(m_.MLoader.of.instruments[inst_num].samples[0].loopend > m_.MLoader.of.instruments[inst_num].samples[0].length)
+                    m_.MLoader.of.instruments[inst_num].samples[0].loopend = m_.MLoader.of.instruments[inst_num].samples[0].length;
+
+		smpinfo_num++;    /* point to next source sampleinfo */
+		inst_num++;    /* point to next destiny sampleinfo */
+	}
+
+	if(!M15_LoadPatterns()) return false;
+	return true;
+}
+
+}

source/java/source/MikMod/Loaders/MOD_Loader.java

+/*
+
+Name:
+LOAD_MOD.C
+
+Description:
+Generic MOD loader
+
+Portability:
+All systems - all compilers (hopefully)
+
+*/
+
+/*************************************************************************
+*************************************************************************/
+
+package MikMod.Loaders;
+
+import MikMod.*;
+import java.io.*;
+
+class MSAMPINFO
+{       /* sample header as it appears in a module */
+    public byte  samplename[];
+	public int length;
+	public short finetune;
+	public short volume;
+	public int reppos;
+	public int replen;
+
+	public MSAMPINFO()
+	{
+		samplename = new byte[22];
+	}
+};
+
+class MODNOTE{
+	public short a,b,c,d;
+};
+
+class MODULEHEADER{    /* verbatim module header */
+    public byte       songname[];                /* the songname.. */
+	public MSAMPINFO  samples[];                         /* all sampleinfo */
+	public short      songlength;                          /* number of patterns used */
+	public short      magic1;                                      /* should be 127 */
+	public byte      positions[];                      /* which pattern to play at pos */
+	public byte      magic2[];                           /* string "M.K." or "FLT4" or "FLT8" */
+	public MODULEHEADER()
+	{
+		songname = new byte [20];
+		samples = new MSAMPINFO[31];
+		int i;
+		for(i=0;i<31;i++)
+			samples[i] = new MSAMPINFO();
+		positions = new byte[128];
+		magic2 = new byte[4];
+	}
+};
+
+
+class MODTYPE
+{                         /* struct to identify type of module */
+    public byte    id[];
+	public short   channels;
+    public String name;    //char *    name;
+	public MODTYPE()
+	{
+		id = new byte[5];
+	}
+	public MODTYPE(String init_id, int init_chn, String init_name)
+	{
+		id = new byte[5]; 
+		init_id.getBytes(0,4,id,0);
+		id[4] = '\0';
+
+		channels = (short)init_chn;
+		name = new String(init_name);
+	}
+}
+
+public class MOD_Loader extends clLOADER
+{
+
+	protected MODULEHEADER mh;        /* raw as-is module header */
+	protected MODNOTE patbuf[];
+
+
+final int MODULEHEADERSIZE = 1084;