summaryrefslogtreecommitdiffstats
path: root/apps/plugins/mikmod/load_asy.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_asy.c')
-rw-r--r--apps/plugins/mikmod/load_asy.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_asy.c b/apps/plugins/mikmod/load_asy.c
new file mode 100644
index 0000000000..356a686d92
--- /dev/null
+++ b/apps/plugins/mikmod/load_asy.c
@@ -0,0 +1,398 @@
+/* MikMod sound library
+ (c) 2004, Raphael Assenat 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: load_asy.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ ASYLUM Music Format v1.0 (.amf) loader
+ adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>,
+ with the help of the AMF2MOD utility sourcecode,
+ written to convert crusader's amf files into 8
+ channels mod file in 1995 by Mr. P / Powersource
+ mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca
+
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+/*========== Module structure */
+
+typedef struct MSAMPINFO {
+ CHAR samplename[24];
+ UBYTE finetune;
+ UBYTE volume;
+ ULONG length;
+ ULONG reppos;
+ ULONG replen;
+} MSAMPINFO;
+
+typedef struct MODULEHEADER {
+ CHAR songname[21];
+ UBYTE num_patterns; /* number of patterns used */
+ UBYTE num_orders;
+ UBYTE positions[256]; /* which pattern to play at pos */
+ MSAMPINFO samples[64]; /* all sampleinfo */
+} MODULEHEADER;
+
+typedef struct MODTYPE {
+ CHAR id[5];
+ UBYTE channels;
+ CHAR *name;
+} MODTYPE;
+
+typedef struct MODNOTE {
+ UBYTE a, b, c, d;
+} MODNOTE;
+
+/* This table is taken from AMF2MOD.C
+ * written in 1995 by Mr. P / Powersource
+ * mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */
+UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304,
+ 4064,3840,3628,3424,3232,3048,2880,2712,2560,
+ 2416,2280,2152,2032,1920,1814,1712,1616,1524,
+ 1440,1356,1280,1208,1140,1076,1016, 960, 907,
+ 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, 53, 50, 47, 45, 42, 40,
+ 37, 35, 33, 31, 30, 28};
+
+/*========== Loader variables */
+
+static CHAR asylum[] = "Asylum 1.0";
+
+static MODULEHEADER *mh = NULL;
+static MODNOTE *patbuf = NULL;
+static int modtype = 0;
+
+/*========== Loader code */
+
+static int ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
+{
+ if (!memcmp(id, "ASYLUM Music Format V1.0", 24))
+ {
+ *descr = asylum;
+ *numchn = 8;
+ modtype = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ASY_Test(void)
+{
+ UBYTE namestring[24], numchn;
+ CHAR *descr;
+
+ /* Read the magic string */
+ _mm_fseek(modreader, 0, SEEK_SET);
+ if (!_mm_read_UBYTES(namestring, 24, modreader))
+ return 0;
+
+ /* Test if the string is what we expect */
+ if (ASY_CheckType(namestring, &numchn, &descr))
+ return 1;
+
+ return 0;
+}
+
+static int ASY_Init(void)
+{
+ if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
+ return 0;
+ return 1;
+}
+
+static void ASY_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(patbuf);
+}
+
+static void ConvertNote(MODNOTE *n)
+{
+ UBYTE instrument, effect, effdat, note;
+ UWORD period;
+ UBYTE lastnote = 0;
+
+ instrument = n->b&0x1f;
+ effect = n->c;
+ effdat = n->d;
+
+ /* convert amf note to mod period */
+ if (n->a) {
+ period = periodtable[n->a];
+ } else {
+ period = 0;
+ }
+
+ /* Convert the period to a note number */
+ note = 0;
+ if (period)
+ {
+ for (note = 0; note < 7 * OCTAVE; note++)
+ if (period >= npertab[note])
+ break;
+ if (note == 7 * OCTAVE)
+ note = 0;
+ else
+ note++;
+ }
+
+ if (instrument) {
+ /* if instrument does not exist, note cut */
+ if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
+ UniPTEffect(0xc, 0);
+ if (effect == 0xc)
+ effect = effdat = 0;
+ } else {
+ /* Protracker handling */
+ if (!modtype) {
+ /* if we had a note, then change instrument...*/
+ if (note)
+ UniInstrument(instrument - 1);
+ /* ...otherwise, only adjust volume... */
+ else {
+ /* ...unless an effect was specified,
+ * which forces a new note to be
+ * played */
+ if (effect || effdat) {
+ UniInstrument(instrument - 1);
+ note = lastnote;
+ } else
+ UniPTEffect(0xc,
+ mh->samples[instrument -
+ 1].volume & 0x7f);
+ }
+ } else {
+ /* Fasttracker handling */
+ UniInstrument(instrument - 1);
+ if (!note)
+ note = lastnote;
+ }
+ }
+ }
+ if (note) {
+ UniNote(note + 2 * OCTAVE - 1);
+ lastnote = note;
+ }
+
+ /* Convert pattern jump from Dec to Hex */
+ if (effect == 0xd)
+ effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
+
+ /* Volume slide, up has priority */
+ if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
+ effdat &= 0xf0;
+
+ UniPTEffect(effect, effdat);
+}
+
+static UBYTE *ConvertTrack(MODNOTE *n)
+{
+ int t;
+
+ UniReset();
+ for (t = 0; t < 64; t++) {
+ ConvertNote(n);
+ UniNewline();
+ n += of.numchn;
+ }
+ return UniDup();
+}
+
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */
+static int ML_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 (!(patbuf = (MODNOTE *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE))))
+ return 0;
+
+
+ /* patterns start here */
+ _mm_fseek(modreader, 0xA66, SEEK_SET);
+ 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(modreader);
+ patbuf[s].b = _mm_read_UBYTE(modreader);
+ patbuf[s].c = _mm_read_UBYTE(modreader);
+ patbuf[s].d = _mm_read_UBYTE(modreader);
+ }
+ for (s = 0; s < of.numchn; s++) {
+ if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+static int ASY_Load(int curious)
+{
+ int t;
+ SAMPLE *q;
+ MSAMPINFO *s;
+ CHAR *descr=asylum;
+ ULONG seekpos;
+
+ // no title in asylum amf files :(
+ strcpy(mh->songname, "");
+
+ _mm_fseek(modreader, 0x23, SEEK_SET);
+ mh->num_patterns = _mm_read_UBYTE(modreader);
+ mh->num_orders = _mm_read_UBYTE(modreader);
+
+ // skip unknown byte
+ _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->positions, 256, modreader);
+
+ /* read samples headers*/
+ for (t = 0; t < 64; t++) {
+ s = &mh->samples[t];
+
+ _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
+
+ _mm_read_string(s->samplename, 22, modreader);
+ s->samplename[21] = 0; /* just in case */
+
+ s->finetune = _mm_read_UBYTE(modreader);
+ s->volume = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTE(modreader); // skip unknown byte
+ s->length = _mm_read_I_ULONG(modreader);
+ s->reppos = _mm_read_I_ULONG(modreader);
+ s->replen = _mm_read_I_ULONG(modreader);
+ }
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = 6;
+ of.inittempo = 125;
+ of.numchn = 8;
+ modtype = 0;
+ of.songname = DupStr(mh->songname, 21, 1);
+ of.numpos = mh->num_orders;
+ of.reppos = 0;
+ of.numpat = mh->num_patterns;
+ of.numtrk = of.numpat * of.numchn;
+
+
+ /* Copy positions (orders) */
+ if (!AllocPositions(of.numpos))
+ return 0;
+ for (t = 0; t < of.numpos; t++) {
+ of.positions[t] = mh->positions[t];
+ }
+
+ /* Finally, init the sampleinfo structures */
+ of.numins = 31;
+ of.numsmp = 31;
+ if (!AllocSamples())
+ return 0;
+ s = mh->samples;
+ q = of.samples;
+ seekpos = 2662+(2048*(of.numpat));
+ for (t = 0; t < of.numins; t++) {
+ /* convert the samplename */
+ q->samplename = DupStr(s->samplename, 23, 1);
+
+ /* init the sampleinfo variables */
+ q->speed = finetune[s->finetune & 0xf];
+ q->volume = s->volume & 0x7f;
+
+ q->loopstart = (ULONG)s->reppos;
+ q->loopend = (ULONG)q->loopstart + (s->replen);
+ q->length = (ULONG)s->length;
+
+ q->flags = SF_SIGNED;
+
+ q->seekpos = seekpos;
+ seekpos += q->length;
+
+ if ((s->replen) > 2) {
+ q->flags |= SF_LOOP;
+ }
+
+ /* fix replen if repend > length */
+ if (q->loopend > q->length)
+ q->loopend = q->length;
+
+ s++;
+ q++;
+ }
+
+ of.modtype = StrDup(descr);
+
+ if (!ML_LoadPatterns())
+ return 0;
+
+ return 1;
+}
+
+static CHAR *ASY_LoadTitle(void)
+{
+ CHAR *s = ""; // no titles
+
+ return (DupStr(s, 21, 1));
+}
+
+/*========== Loader information */
+
+MLOADER load_asy = {
+ NULL,
+ "AMF",
+ "AMF (ASYLUM Music Format V1.0)",
+ ASY_Init,
+ ASY_Test,
+ ASY_Load,
+ ASY_Cleanup,
+ ASY_LoadTitle
+};
+
+/* ex:set ts=4: */