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