1 /* MikMod sound library
\r
2 (c) 2004, Raphael Assenat and others - see file AUTHORS for
\r
5 This library is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU Library General Public License as
\r
7 published by the Free Software Foundation; either version 2 of
\r
8 the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU Library General Public License for more details.
\r
15 You should have received a copy of the GNU Library General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
\r
21 /*==============================================================================
\r
23 $Id: load_asy.c,v 1.3 2004/01/28 01:18:22 raph Exp $
\r
25 ASYLUM Music Format v1.0 (.amf) loader
\r
26 adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>,
\r
27 with the help of the AMF2MOD utility sourcecode,
\r
28 written to convert crusader's amf files into 8
\r
29 channels mod file in 1995 by Mr. P / Powersource
\r
30 mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca
\r
33 ==============================================================================*/
\r
35 #ifdef HAVE_CONFIG_H
\r
39 #ifdef HAVE_UNISTD_H
\r
43 //#include <ctype.h>
\r
46 #include "mikmod_internals.h"
\r
48 /*========== Module structure */
\r
50 typedef struct MSAMPINFO {
\r
51 CHAR samplename[24];
\r
59 typedef struct MODULEHEADER {
\r
61 UBYTE num_patterns; /* number of patterns used */
\r
63 UBYTE positions[256]; /* which pattern to play at pos */
\r
64 MSAMPINFO samples[64]; /* all sampleinfo */
\r
67 typedef struct MODTYPE {
\r
73 typedef struct MODNOTE {
\r
77 /* This table is taken from AMF2MOD.C
\r
78 * written in 1995 by Mr. P / Powersource
\r
79 * mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */
\r
80 UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304,
\r
81 4064,3840,3628,3424,3232,3048,2880,2712,2560,
\r
82 2416,2280,2152,2032,1920,1814,1712,1616,1524,
\r
83 1440,1356,1280,1208,1140,1076,1016, 960, 907,
\r
84 856, 808, 762, 720, 678, 640, 604, 570, 538,
\r
85 508, 480, 453, 428, 404, 381, 360, 339, 320,
\r
86 302, 285, 269, 254, 240, 226, 214, 202, 190,
\r
87 180, 170, 160, 151, 143, 135, 127, 120, 113,
\r
88 107, 101, 95, 90, 85, 80, 75, 71, 67,
\r
89 63, 60, 56, 53, 50, 47, 45, 42, 40,
\r
90 37, 35, 33, 31, 30, 28};
\r
92 /*========== Loader variables */
\r
94 static CHAR asylum[] = "Asylum 1.0";
\r
96 static MODULEHEADER *mh = NULL;
\r
97 static MODNOTE *patbuf = NULL;
\r
98 static int modtype = 0;
\r
100 /*========== Loader code */
\r
102 static BOOL ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
\r
104 if (!memcmp(id, "ASYLUM Music Format V1.0", 24))
\r
115 static BOOL ASY_Test(void)
\r
117 UBYTE namestring[24], numchn;
\r
120 /* Read the magic string */
\r
121 _mm_fseek(modreader, 0, SEEK_SET);
\r
122 if (!_mm_read_UBYTES(namestring, 24, modreader))
\r
125 /* Test if the string is what we expect */
\r
126 if (ASY_CheckType(namestring, &numchn, &descr))
\r
132 static BOOL ASY_Init(void)
\r
134 if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))
\r
139 static void ASY_Cleanup(void)
\r
145 static void ConvertNote(MODNOTE *n)
\r
147 UBYTE instrument, effect, effdat, note;
\r
149 UBYTE lastnote = 0;
\r
151 instrument = n->b&0x1f;
\r
155 /* convert amf note to mod period */
\r
157 period = periodtable[n->a];
\r
162 /* Convert the period to a note number */
\r
166 for (note = 0; note < 7 * OCTAVE; note++)
\r
167 if (period >= npertab[note])
\r
169 if (note == 7 * OCTAVE)
\r
176 /* if instrument does not exist, note cut */
\r
177 if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
\r
178 UniPTEffect(0xc, 0);
\r
180 effect = effdat = 0;
\r
182 /* Protracker handling */
\r
184 /* if we had a note, then change instrument...*/
\r
186 UniInstrument(instrument - 1);
\r
187 /* ...otherwise, only adjust volume... */
\r
189 /* ...unless an effect was specified,
\r
190 * which forces a new note to be
\r
192 if (effect || effdat) {
\r
193 UniInstrument(instrument - 1);
\r
197 mh->samples[instrument -
\r
201 /* Fasttracker handling */
\r
202 UniInstrument(instrument - 1);
\r
209 UniNote(note + 2 * OCTAVE - 1);
\r
213 /* Convert pattern jump from Dec to Hex */
\r
215 effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
\r
217 /* Volume slide, up has priority */
\r
218 if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
\r
221 UniPTEffect(effect, effdat);
\r
224 static UBYTE *ConvertTrack(MODNOTE *n)
\r
229 for (t = 0; t < 64; t++) {
\r
237 /* Loads all patterns of a modfile and converts them into the 3 byte format. */
\r
238 static BOOL ML_LoadPatterns(void)
\r
240 int t, s, tracks = 0;
\r
242 if (!AllocPatterns()) {
\r
245 if (!AllocTracks()) {
\r
249 /* Allocate temporary buffer for loading and converting the patterns */
\r
250 if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))
\r
254 /* patterns start here */
\r
255 _mm_fseek(modreader, 0xA66, SEEK_SET);
\r
256 for (t = 0; t < of.numpat; t++) {
\r
257 /* Load the pattern into the temp buffer and convert it */
\r
258 for (s = 0; s < (64U * of.numchn); s++) {
\r
259 patbuf[s].a = _mm_read_UBYTE(modreader);
\r
260 patbuf[s].b = _mm_read_UBYTE(modreader);
\r
261 patbuf[s].c = _mm_read_UBYTE(modreader);
\r
262 patbuf[s].d = _mm_read_UBYTE(modreader);
\r
264 for (s = 0; s < of.numchn; s++) {
\r
265 if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {
\r
273 static BOOL ASY_Load(BOOL curious)
\r
278 CHAR *descr=asylum;
\r
282 // no title in asylum amf files :(
\r
283 strcpy(mh->songname, "");
\r
285 _mm_fseek(modreader, 0x23, SEEK_SET);
\r
286 mh->num_patterns = _mm_read_UBYTE(modreader);
\r
287 mh->num_orders = _mm_read_UBYTE(modreader);
\r
289 // skip unknown byte
\r
290 _mm_read_UBYTE(modreader);
\r
291 _mm_read_UBYTES(mh->positions, 256, modreader);
\r
293 /* read samples headers*/
\r
294 for (t = 0; t < 64; t++) {
\r
295 s = &mh->samples[t];
\r
297 _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
\r
299 _mm_read_string(s->samplename, 22, modreader);
\r
300 s->samplename[21] = 0; /* just in case */
\r
302 s->finetune = _mm_read_UBYTE(modreader);
\r
303 s->volume = _mm_read_UBYTE(modreader);
\r
304 _mm_read_UBYTE(modreader); // skip unknown byte
\r
305 s->length = _mm_read_I_ULONG(modreader);
\r
306 s->reppos = _mm_read_I_ULONG(modreader);
\r
307 s->replen = _mm_read_I_ULONG(modreader);
\r
310 if (_mm_eof(modreader)) {
\r
311 _mm_errno = MMERR_LOADING_HEADER;
\r
315 /* set module variables */
\r
317 of.inittempo = 125;
\r
320 of.songname = DupStr(mh->songname, 21, 1);
\r
321 of.numpos = mh->num_orders;
\r
323 of.numpat = mh->num_patterns;
\r
324 of.numtrk = of.numpat * of.numchn;
\r
327 /* Copy positions (orders) */
\r
328 if (!AllocPositions(of.numpos))
\r
330 for (t = 0; t < of.numpos; t++) {
\r
331 of.positions[t] = mh->positions[t];
\r
334 /* Finally, init the sampleinfo structures */
\r
337 if (!AllocSamples())
\r
341 seekpos = 2662+(2048*(of.numpat));
\r
342 for (t = 0; t < of.numins; t++) {
\r
343 /* convert the samplename */
\r
344 q->samplename = DupStr(s->samplename, 23, 1);
\r
346 /* init the sampleinfo variables */
\r
347 q->speed = finetune[s->finetune & 0xf];
\r
348 q->volume = s->volume & 0x7f;
\r
350 q->loopstart = (ULONG)s->reppos;
\r
351 q->loopend = (ULONG)q->loopstart + (s->replen);
\r
352 q->length = (ULONG)s->length;
\r
354 q->flags = SF_SIGNED;
\r
356 q->seekpos = seekpos;
\r
357 seekpos += q->length;
\r
359 if ((s->replen) > 2) {
\r
360 q->flags |= SF_LOOP;
\r
363 /* fix replen if repend > length */
\r
364 if (q->loopend > q->length)
\r
365 q->loopend = q->length;
\r
371 of.modtype = strdup(descr);
\r
373 if (!ML_LoadPatterns())
\r
379 static CHAR *ASY_LoadTitle(void)
\r
381 CHAR *s = ""; // no titles
\r
383 return (DupStr(s, 21, 1));
\r
386 /*========== Loader information */
\r
388 MLOADER load_asy = {
\r
391 "AMF (ASYLUM Music Format V1.0)",
\r