summaryrefslogtreecommitdiff
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 @@
1/* MikMod sound library
2 (c) 2004, Raphael Assenat and others - see file AUTHORS for
3 complete list.
4
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.
9
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.
14
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
18 02111-1307, USA.
19*/
20
21/*==============================================================================
22
23 $Id: load_asy.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
24
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
31
32
33==============================================================================*/
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#include <ctype.h>
44#include <string.h>
45
46#include "mikmod_internals.h"
47
48/*========== Module structure */
49
50typedef struct MSAMPINFO {
51 CHAR samplename[24];
52 UBYTE finetune;
53 UBYTE volume;
54 ULONG length;
55 ULONG reppos;
56 ULONG replen;
57} MSAMPINFO;
58
59typedef struct MODULEHEADER {
60 CHAR songname[21];
61 UBYTE num_patterns; /* number of patterns used */
62 UBYTE num_orders;
63 UBYTE positions[256]; /* which pattern to play at pos */
64 MSAMPINFO samples[64]; /* all sampleinfo */
65} MODULEHEADER;
66
67typedef struct MODTYPE {
68 CHAR id[5];
69 UBYTE channels;
70 CHAR *name;
71} MODTYPE;
72
73typedef struct MODNOTE {
74 UBYTE a, b, c, d;
75} MODNOTE;
76
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 */
80UWORD 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};
91
92/*========== Loader variables */
93
94static CHAR asylum[] = "Asylum 1.0";
95
96static MODULEHEADER *mh = NULL;
97static MODNOTE *patbuf = NULL;
98static int modtype = 0;
99
100/*========== Loader code */
101
102static int ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
103{
104 if (!memcmp(id, "ASYLUM Music Format V1.0", 24))
105 {
106 *descr = asylum;
107 *numchn = 8;
108 modtype = 1;
109 return 1;
110 }
111
112 return 0;
113}
114
115static int ASY_Test(void)
116{
117 UBYTE namestring[24], numchn;
118 CHAR *descr;
119
120 /* Read the magic string */
121 _mm_fseek(modreader, 0, SEEK_SET);
122 if (!_mm_read_UBYTES(namestring, 24, modreader))
123 return 0;
124
125 /* Test if the string is what we expect */
126 if (ASY_CheckType(namestring, &numchn, &descr))
127 return 1;
128
129 return 0;
130}
131
132static int ASY_Init(void)
133{
134 if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
135 return 0;
136 return 1;
137}
138
139static void ASY_Cleanup(void)
140{
141 MikMod_free(mh);
142 MikMod_free(patbuf);
143}
144
145static void ConvertNote(MODNOTE *n)
146{
147 UBYTE instrument, effect, effdat, note;
148 UWORD period;
149 UBYTE lastnote = 0;
150
151 instrument = n->b&0x1f;
152 effect = n->c;
153 effdat = n->d;
154
155 /* convert amf note to mod period */
156 if (n->a) {
157 period = periodtable[n->a];
158 } else {
159 period = 0;
160 }
161
162 /* Convert the period to a note number */
163 note = 0;
164 if (period)
165 {
166 for (note = 0; note < 7 * OCTAVE; note++)
167 if (period >= npertab[note])
168 break;
169 if (note == 7 * OCTAVE)
170 note = 0;
171 else
172 note++;
173 }
174
175 if (instrument) {
176 /* if instrument does not exist, note cut */
177 if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
178 UniPTEffect(0xc, 0);
179 if (effect == 0xc)
180 effect = effdat = 0;
181 } else {
182 /* Protracker handling */
183 if (!modtype) {
184 /* if we had a note, then change instrument...*/
185 if (note)
186 UniInstrument(instrument - 1);
187 /* ...otherwise, only adjust volume... */
188 else {
189 /* ...unless an effect was specified,
190 * which forces a new note to be
191 * played */
192 if (effect || effdat) {
193 UniInstrument(instrument - 1);
194 note = lastnote;
195 } else
196 UniPTEffect(0xc,
197 mh->samples[instrument -
198 1].volume & 0x7f);
199 }
200 } else {
201 /* Fasttracker handling */
202 UniInstrument(instrument - 1);
203 if (!note)
204 note = lastnote;
205 }
206 }
207 }
208 if (note) {
209 UniNote(note + 2 * OCTAVE - 1);
210 lastnote = note;
211 }
212
213 /* Convert pattern jump from Dec to Hex */
214 if (effect == 0xd)
215 effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
216
217 /* Volume slide, up has priority */
218 if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
219 effdat &= 0xf0;
220
221 UniPTEffect(effect, effdat);
222}
223
224static UBYTE *ConvertTrack(MODNOTE *n)
225{
226 int t;
227
228 UniReset();
229 for (t = 0; t < 64; t++) {
230 ConvertNote(n);
231 UniNewline();
232 n += of.numchn;
233 }
234 return UniDup();
235}
236
237/* Loads all patterns of a modfile and converts them into the 3 byte format. */
238static int ML_LoadPatterns(void)
239{
240 int t, s, tracks = 0;
241
242 if (!AllocPatterns()) {
243 return 0;
244 }
245 if (!AllocTracks()) {
246 return 0;
247 }
248
249 /* Allocate temporary buffer for loading and converting the patterns */
250 if (!(patbuf = (MODNOTE *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE))))
251 return 0;
252
253
254 /* patterns start here */
255 _mm_fseek(modreader, 0xA66, SEEK_SET);
256 for (t = 0; t < of.numpat; t++) {
257 /* Load the pattern into the temp buffer and convert it */
258 for (s = 0; s < (64U * of.numchn); s++) {
259 patbuf[s].a = _mm_read_UBYTE(modreader);
260 patbuf[s].b = _mm_read_UBYTE(modreader);
261 patbuf[s].c = _mm_read_UBYTE(modreader);
262 patbuf[s].d = _mm_read_UBYTE(modreader);
263 }
264 for (s = 0; s < of.numchn; s++) {
265 if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {
266 return 0;
267 }
268 }
269 }
270 return 1;
271}
272
273static int ASY_Load(int curious)
274{
275 int t;
276 SAMPLE *q;
277 MSAMPINFO *s;
278 CHAR *descr=asylum;
279 ULONG seekpos;
280
281 // no title in asylum amf files :(
282 strcpy(mh->songname, "");
283
284 _mm_fseek(modreader, 0x23, SEEK_SET);
285 mh->num_patterns = _mm_read_UBYTE(modreader);
286 mh->num_orders = _mm_read_UBYTE(modreader);
287
288 // skip unknown byte
289 _mm_read_UBYTE(modreader);
290 _mm_read_UBYTES(mh->positions, 256, modreader);
291
292 /* read samples headers*/
293 for (t = 0; t < 64; t++) {
294 s = &mh->samples[t];
295
296 _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
297
298 _mm_read_string(s->samplename, 22, modreader);
299 s->samplename[21] = 0; /* just in case */
300
301 s->finetune = _mm_read_UBYTE(modreader);
302 s->volume = _mm_read_UBYTE(modreader);
303 _mm_read_UBYTE(modreader); // skip unknown byte
304 s->length = _mm_read_I_ULONG(modreader);
305 s->reppos = _mm_read_I_ULONG(modreader);
306 s->replen = _mm_read_I_ULONG(modreader);
307 }
308
309 if (_mm_eof(modreader)) {
310 _mm_errno = MMERR_LOADING_HEADER;
311 return 0;
312 }
313
314 /* set module variables */
315 of.initspeed = 6;
316 of.inittempo = 125;
317 of.numchn = 8;
318 modtype = 0;
319 of.songname = DupStr(mh->songname, 21, 1);
320 of.numpos = mh->num_orders;
321 of.reppos = 0;
322 of.numpat = mh->num_patterns;
323 of.numtrk = of.numpat * of.numchn;
324
325
326 /* Copy positions (orders) */
327 if (!AllocPositions(of.numpos))
328 return 0;
329 for (t = 0; t < of.numpos; t++) {
330 of.positions[t] = mh->positions[t];
331 }
332
333 /* Finally, init the sampleinfo structures */
334 of.numins = 31;
335 of.numsmp = 31;
336 if (!AllocSamples())
337 return 0;
338 s = mh->samples;
339 q = of.samples;
340 seekpos = 2662+(2048*(of.numpat));
341 for (t = 0; t < of.numins; t++) {
342 /* convert the samplename */
343 q->samplename = DupStr(s->samplename, 23, 1);
344
345 /* init the sampleinfo variables */
346 q->speed = finetune[s->finetune & 0xf];
347 q->volume = s->volume & 0x7f;
348
349 q->loopstart = (ULONG)s->reppos;
350 q->loopend = (ULONG)q->loopstart + (s->replen);
351 q->length = (ULONG)s->length;
352
353 q->flags = SF_SIGNED;
354
355 q->seekpos = seekpos;
356 seekpos += q->length;
357
358 if ((s->replen) > 2) {
359 q->flags |= SF_LOOP;
360 }
361
362 /* fix replen if repend > length */
363 if (q->loopend > q->length)
364 q->loopend = q->length;
365
366 s++;
367 q++;
368 }
369
370 of.modtype = StrDup(descr);
371
372 if (!ML_LoadPatterns())
373 return 0;
374
375 return 1;
376}
377
378static CHAR *ASY_LoadTitle(void)
379{
380 CHAR *s = ""; // no titles
381
382 return (DupStr(s, 21, 1));
383}
384
385/*========== Loader information */
386
387MLOADER load_asy = {
388 NULL,
389 "AMF",
390 "AMF (ASYLUM Music Format V1.0)",
391 ASY_Init,
392 ASY_Test,
393 ASY_Load,
394 ASY_Cleanup,
395 ASY_LoadTitle
396};
397
398/* ex:set ts=4: */