diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
commit | 26f2bfde03420edad4de1f22cb3d515dc063b20d (patch) | |
tree | 4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod/load_asy.c | |
parent | d192bdf11e06e50645ecb5726658d4b691480a9a (diff) | |
download | rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip |
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mikmod/load_asy.c')
-rw-r--r-- | apps/plugins/mikmod/load_asy.c | 398 |
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 | |||
50 | typedef struct MSAMPINFO { | ||
51 | CHAR samplename[24]; | ||
52 | UBYTE finetune; | ||
53 | UBYTE volume; | ||
54 | ULONG length; | ||
55 | ULONG reppos; | ||
56 | ULONG replen; | ||
57 | } MSAMPINFO; | ||
58 | |||
59 | typedef 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 | |||
67 | typedef struct MODTYPE { | ||
68 | CHAR id[5]; | ||
69 | UBYTE channels; | ||
70 | CHAR *name; | ||
71 | } MODTYPE; | ||
72 | |||
73 | typedef 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 */ | ||
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}; | ||
91 | |||
92 | /*========== Loader variables */ | ||
93 | |||
94 | static CHAR asylum[] = "Asylum 1.0"; | ||
95 | |||
96 | static MODULEHEADER *mh = NULL; | ||
97 | static MODNOTE *patbuf = NULL; | ||
98 | static int modtype = 0; | ||
99 | |||
100 | /*========== Loader code */ | ||
101 | |||
102 | static 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 | |||
115 | static 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 | |||
132 | static int ASY_Init(void) | ||
133 | { | ||
134 | if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER)))) | ||
135 | return 0; | ||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static void ASY_Cleanup(void) | ||
140 | { | ||
141 | MikMod_free(mh); | ||
142 | MikMod_free(patbuf); | ||
143 | } | ||
144 | |||
145 | static 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 | |||
224 | static 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. */ | ||
238 | static 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 | |||
273 | static 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 | |||
378 | static CHAR *ASY_LoadTitle(void) | ||
379 | { | ||
380 | CHAR *s = ""; // no titles | ||
381 | |||
382 | return (DupStr(s, 21, 1)); | ||
383 | } | ||
384 | |||
385 | /*========== Loader information */ | ||
386 | |||
387 | MLOADER 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: */ | ||