summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/load_amf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_amf.c')
-rw-r--r--apps/plugins/mikmod/load_amf.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_amf.c b/apps/plugins/mikmod/load_amf.c
new file mode 100644
index 0000000000..12e0af0738
--- /dev/null
+++ b/apps/plugins/mikmod/load_amf.c
@@ -0,0 +1,569 @@
1/* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for 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_amf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
24
25 DMP Advanced Module Format loader
26
27==============================================================================*/
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36
37#include <stdio.h>
38#ifdef HAVE_MEMORY_H
39#include <memory.h>
40#endif
41#include <string.h>
42
43#include "mikmod_internals.h"
44
45#ifdef SUNOS
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef struct AMFHEADER {
52 UBYTE id[3]; /* AMF file marker */
53 UBYTE version; /* upper major, lower nibble minor version number */
54 CHAR songname[32]; /* ASCIIZ songname */
55 UBYTE numsamples; /* number of samples saved */
56 UBYTE numorders;
57 UWORD numtracks; /* number of tracks saved */
58 UBYTE numchannels; /* number of channels used */
59 SBYTE panpos[32]; /* voice pan positions */
60 UBYTE songbpm;
61 UBYTE songspd;
62} AMFHEADER;
63
64typedef struct AMFSAMPLE {
65 UBYTE type;
66 CHAR samplename[32];
67 CHAR filename[13];
68 ULONG offset;
69 ULONG length;
70 UWORD c2spd;
71 UBYTE volume;
72 ULONG reppos;
73 ULONG repend;
74} AMFSAMPLE;
75
76typedef struct AMFNOTE {
77 UBYTE note,instr,volume,fxcnt;
78 UBYTE effect[3];
79 SBYTE parameter[3];
80} AMFNOTE;
81
82/*========== Loader variables */
83
84static AMFHEADER *mh = NULL;
85#define AMFTEXTLEN 22
86static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0";
87static AMFNOTE *track = NULL;
88
89/*========== Loader code */
90
91int AMF_Test(void)
92{
93 UBYTE id[3],ver;
94
95 if(!_mm_read_UBYTES(id,3,modreader)) return 0;
96 if(memcmp(id,"AMF",3)) return 0;
97
98 ver=_mm_read_UBYTE(modreader);
99 if((ver>=10)&&(ver<=14)) return 1;
100 return 0;
101}
102
103int AMF_Init(void)
104{
105 if(!(mh=(AMFHEADER*)MikMod_malloc(sizeof(AMFHEADER)))) return 0;
106 if(!(track=(AMFNOTE*)MikMod_calloc(64,sizeof(AMFNOTE)))) return 0;
107
108 return 1;
109}
110
111void AMF_Cleanup(void)
112{
113 MikMod_free(mh);
114 MikMod_free(track);
115}
116
117static int AMF_UnpackTrack(MREADER* modreader)
118{
119 ULONG tracksize;
120 UBYTE row,cmd;
121 SBYTE arg;
122
123 /* empty track */
124 memset(track,0,64*sizeof(AMFNOTE));
125
126 /* read packed track */
127 if (modreader) {
128 tracksize=_mm_read_I_UWORD(modreader);
129 tracksize+=((ULONG)_mm_read_UBYTE(modreader))<<16;
130 if (tracksize)
131 while(tracksize--) {
132 row=_mm_read_UBYTE(modreader);
133 cmd=_mm_read_UBYTE(modreader);
134 arg=_mm_read_SBYTE(modreader);
135 /* unexpected end of track */
136 if(!tracksize) {
137 if((row==0xff)&&(cmd==0xff)&&(arg==-1))
138 break;
139 /* the last triplet should be FF FF FF, but this is not
140 always the case... maybe a bug in m2amf ?
141 else
142 return 0;
143 */
144
145 }
146 /* invalid row (probably unexpected end of row) */
147 if (row>=64)
148 return 0;
149 if (cmd<0x7f) {
150 /* note, vol */
151 track[row].note=cmd;
152 track[row].volume=(UBYTE)arg+1;
153 } else
154 if (cmd==0x7f) {
155 /* duplicate row */
156 if ((arg<0)&&(row+arg>=0)) {
157 memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
158 }
159 } else
160 if (cmd==0x80) {
161 /* instr */
162 track[row].instr=arg+1;
163 } else
164 if (cmd==0x83) {
165 /* volume without note */
166 track[row].volume=(UBYTE)arg+1;
167 } else
168 if (cmd==0xff) {
169 /* apparently, some M2AMF version fail to estimate the
170 size of the compressed patterns correctly, and end
171 up with blanks, i.e. dead triplets. Those are marked
172 with cmd == 0xff. Let's ignore them. */
173 } else
174 if(track[row].fxcnt<3) {
175 /* effect, param */
176 if(cmd>0x97)
177 return 0;
178 track[row].effect[track[row].fxcnt]=cmd&0x7f;
179 track[row].parameter[track[row].fxcnt]=arg;
180 track[row].fxcnt++;
181 } else
182 return 0;
183 }
184 }
185 return 1;
186}
187
188static UBYTE* AMF_ConvertTrack(void)
189{
190 int row,fx4memory=0;
191
192 /* convert track */
193 UniReset();
194 for (row=0;row<64;row++) {
195 if (track[row].instr) UniInstrument(track[row].instr-1);
196 if (track[row].note>OCTAVE) UniNote(track[row].note-OCTAVE);
197
198 /* AMF effects */
199 while(track[row].fxcnt--) {
200 SBYTE inf=track[row].parameter[track[row].fxcnt];
201
202 switch(track[row].effect[track[row].fxcnt]) {
203 case 1: /* Set speed */
204 UniEffect(UNI_S3MEFFECTA,inf);
205 break;
206 case 2: /* Volume slide */
207 if(inf) {
208 UniWriteByte(UNI_S3MEFFECTD);
209 if (inf>=0)
210 UniWriteByte((inf&0xf)<<4);
211 else
212 UniWriteByte((-inf)&0xf);
213 }
214 break;
215 /* effect 3, set channel volume, done in UnpackTrack */
216 case 4: /* Porta up/down */
217 if(inf) {
218 if(inf>0) {
219 UniEffect(UNI_S3MEFFECTE,inf);
220 fx4memory=UNI_S3MEFFECTE;
221 } else {
222 UniEffect(UNI_S3MEFFECTF,-inf);
223 fx4memory=UNI_S3MEFFECTF;
224 }
225 } else if(fx4memory)
226 UniEffect(fx4memory,0);
227 break;
228 /* effect 5, "Porta abs", not supported */
229 case 6: /* Porta to note */
230 UniEffect(UNI_ITEFFECTG,inf);
231 break;
232 case 7: /* Tremor */
233 UniEffect(UNI_S3MEFFECTI,inf);
234 break;
235 case 8: /* Arpeggio */
236 UniPTEffect(0x0,inf);
237 break;
238 case 9: /* Vibrato */
239 UniPTEffect(0x4,inf);
240 break;
241 case 0xa: /* Porta + Volume slide */
242 UniPTEffect(0x3,0);
243 if(inf) {
244 UniWriteByte(UNI_S3MEFFECTD);
245 if (inf>=0)
246 UniWriteByte((inf&0xf)<<4);
247 else
248 UniWriteByte((-inf)&0xf);
249 }
250 break;
251 case 0xb: /* Vibrato + Volume slide */
252 UniPTEffect(0x4,0);
253 if(inf) {
254 UniWriteByte(UNI_S3MEFFECTD);
255 if (inf>=0)
256 UniWriteByte((inf&0xf)<<4);
257 else
258 UniWriteByte((-inf)&0xf);
259 }
260 break;
261 case 0xc: /* Pattern break (in hex) */
262 UniPTEffect(0xd,inf);
263 break;
264 case 0xd: /* Pattern jump */
265 UniPTEffect(0xb,inf);
266 break;
267 /* effect 0xe, "Sync", not supported */
268 case 0xf: /* Retrig */
269 UniEffect(UNI_S3MEFFECTQ,inf&0xf);
270 break;
271 case 0x10: /* Sample offset */
272 UniPTEffect(0x9,inf);
273 break;
274 case 0x11: /* Fine volume slide */
275 if(inf) {
276 UniWriteByte(UNI_S3MEFFECTD);
277 if (inf>=0)
278 UniWriteByte((inf&0xf)<<4|0xf);
279 else
280 UniWriteByte(0xf0|((-inf)&0xf));
281 }
282 break;
283 case 0x12: /* Fine portamento */
284 if(inf) {
285 if(inf>0) {
286 UniEffect(UNI_S3MEFFECTE,0xf0|(inf&0xf));
287 fx4memory=UNI_S3MEFFECTE;
288 } else {
289 UniEffect(UNI_S3MEFFECTF,0xf0|((-inf)&0xf));
290 fx4memory=UNI_S3MEFFECTF;
291 }
292 } else if(fx4memory)
293 UniEffect(fx4memory,0);
294 break;
295 case 0x13: /* Delay note */
296 UniPTEffect(0xe,0xd0|(inf&0xf));
297 break;
298 case 0x14: /* Note cut */
299 UniPTEffect(0xc,0);
300 track[row].volume=0;
301 break;
302 case 0x15: /* Set tempo */
303 UniEffect(UNI_S3MEFFECTT,inf);
304 break;
305 case 0x16: /* Extra fine portamento */
306 if(inf) {
307 if(inf>0) {
308 UniEffect(UNI_S3MEFFECTE,0xe0|((inf>>2)&0xf));
309 fx4memory=UNI_S3MEFFECTE;
310 } else {
311 UniEffect(UNI_S3MEFFECTF,0xe0|(((-inf)>>2)&0xf));
312 fx4memory=UNI_S3MEFFECTF;
313 }
314 } else if(fx4memory)
315 UniEffect(fx4memory,0);
316 break;
317 case 0x17: /* Panning */
318 if (inf>64)
319 UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
320 else
321 UniPTEffect(0x8,(inf==64)?255:(inf+64)<<1);
322 of.flags |= UF_PANNING;
323 break;
324 }
325
326 }
327 if (track[row].volume) UniVolEffect(VOL_VOLUME,track[row].volume-1);
328 UniNewline();
329 }
330 return UniDup();
331}
332
333int AMF_Load(int curious)
334{
335 int t,u,realtrackcnt,realsmpcnt,defaultpanning;
336 AMFSAMPLE s;
337 SAMPLE *q;
338 UWORD *track_remap;
339 ULONG samplepos;
340 int channel_remap[16];
341
342 /* try to read module header */
343 _mm_read_UBYTES(mh->id,3,modreader);
344 mh->version =_mm_read_UBYTE(modreader);
345 _mm_read_string(mh->songname,32,modreader);
346 mh->numsamples =_mm_read_UBYTE(modreader);
347 mh->numorders =_mm_read_UBYTE(modreader);
348 mh->numtracks =_mm_read_I_UWORD(modreader);
349 mh->numchannels =_mm_read_UBYTE(modreader);
350 if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
351 _mm_errno=MMERR_NOT_A_MODULE;
352 return 0;
353 }
354
355 if(mh->version>=11) {
356 memset(mh->panpos,0,32);
357 _mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
358 } else
359 _mm_read_UBYTES(channel_remap,16,modreader);
360
361 if (mh->version>=13) {
362 mh->songbpm=_mm_read_UBYTE(modreader);
363 if(mh->songbpm<32) {
364 _mm_errno=MMERR_NOT_A_MODULE;
365 return 0;
366 }
367 mh->songspd=_mm_read_UBYTE(modreader);
368 if(mh->songspd>32) {
369 _mm_errno=MMERR_NOT_A_MODULE;
370 return 0;
371 }
372 } else {
373 mh->songbpm=125;
374 mh->songspd=6;
375 }
376
377 if(_mm_eof(modreader)) {
378 _mm_errno = MMERR_LOADING_HEADER;
379 return 0;
380 }
381
382 /* set module variables */
383 of.initspeed = mh->songspd;
384 of.inittempo = mh->songbpm;
385 AMF_Version[AMFTEXTLEN-3]='0'+(mh->version/10);
386 AMF_Version[AMFTEXTLEN-1]='0'+(mh->version%10);
387 of.modtype = StrDup(AMF_Version);
388 of.numchn = mh->numchannels;
389 of.numtrk = mh->numorders*mh->numchannels;
390 if (mh->numtracks>of.numtrk)
391 of.numtrk=mh->numtracks;
392 of.numtrk++; /* add room for extra, empty track */
393 of.songname = DupStr(mh->songname,32,1);
394 of.numpos = mh->numorders;
395 of.numpat = mh->numorders;
396 of.reppos = 0;
397 of.flags |= UF_S3MSLIDES;
398 /* XXX whenever possible, we should try to determine the original format.
399 Here we assume it was S3M-style wrt bpmlimit... */
400 of.bpmlimit = 32;
401
402 /*
403 * Play with the panning table. Although the AMF format embeds a
404 * panning table, if the module was a MOD or an S3M with default
405 * panning and didn't use any panning commands, don't flag
406 * UF_PANNING, to use our preferred panning table for this case.
407 */
408 defaultpanning = 1;
409 for (t = 0; t < 32; t++) {
410 if (mh->panpos[t] > 64) {
411 of.panning[t] = PAN_SURROUND;
412 defaultpanning = 0;
413 } else
414 if (mh->panpos[t] == 64)
415 of.panning[t] = PAN_RIGHT;
416 else
417 of.panning[t] = (mh->panpos[t] + 64) << 1;
418 }
419 if (defaultpanning) {
420 for (t = 0; t < of.numchn; t++)
421 if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
422 defaultpanning = 0; /* not MOD canonical panning */
423 break;
424 }
425 }
426 if (defaultpanning)
427 of.flags |= UF_PANNING;
428
429 of.numins=of.numsmp=mh->numsamples;
430
431 if(!AllocPositions(of.numpos)) return 0;
432 for(t=0;t<of.numpos;t++)
433 of.positions[t]=t;
434
435 if(!AllocTracks()) return 0;
436 if(!AllocPatterns()) return 0;
437
438 /* read AMF order table */
439 for (t=0;t<of.numpat;t++) {
440 if (mh->version>=14)
441 /* track size */
442 of.pattrows[t]=_mm_read_I_UWORD(modreader);
443 if (mh->version>=10)
444 _mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
445 else
446 for(u=0;u<of.numchn;u++)
447 of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
448 }
449 if(_mm_eof(modreader)) {
450 _mm_errno = MMERR_LOADING_HEADER;
451 return 0;
452 }
453
454 /* read sample information */
455 if(!AllocSamples()) return 0;
456 q=of.samples;
457 for(t=0;t<of.numins;t++) {
458 /* try to read sample info */
459 s.type=_mm_read_UBYTE(modreader);
460 _mm_read_string(s.samplename,32,modreader);
461 _mm_read_string(s.filename,13,modreader);
462 s.offset =_mm_read_I_ULONG(modreader);
463 s.length =_mm_read_I_ULONG(modreader);
464 s.c2spd =_mm_read_I_UWORD(modreader);
465 if(s.c2spd==8368) s.c2spd=8363;
466 s.volume =_mm_read_UBYTE(modreader);
467 if(mh->version>=11) {
468 s.reppos =_mm_read_I_ULONG(modreader);
469 s.repend =_mm_read_I_ULONG(modreader);
470 } else {
471 s.reppos =_mm_read_I_UWORD(modreader);
472 s.repend =s.length;
473 }
474
475 if(_mm_eof(modreader)) {
476 _mm_errno = MMERR_LOADING_SAMPLEINFO;
477 return 0;
478 }
479
480 q->samplename = DupStr(s.samplename,32,1);
481 q->speed = s.c2spd;
482 q->volume = s.volume;
483 if (s.type) {
484 q->seekpos = s.offset;
485 q->length = s.length;
486 q->loopstart = s.reppos;
487 q->loopend = s.repend;
488 if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;
489 }
490 q++;
491 }
492
493 /* read track table */
494 if(!(track_remap=MikMod_calloc(mh->numtracks+1,sizeof(UWORD))))
495 return 0;
496 _mm_read_I_UWORDS(track_remap+1,mh->numtracks,modreader);
497 if(_mm_eof(modreader)) {
498 MikMod_free(track_remap);
499 _mm_errno=MMERR_LOADING_TRACK;
500 return 0;
501 }
502
503 for(realtrackcnt=t=0;t<=mh->numtracks;t++)
504 if (realtrackcnt<track_remap[t])
505 realtrackcnt=track_remap[t];
506 for(t=0;t<of.numpat*of.numchn;t++)
507 of.patterns[t]=(of.patterns[t]<=mh->numtracks)?
508 track_remap[of.patterns[t]]-1:realtrackcnt;
509
510 MikMod_free(track_remap);
511
512 /* unpack tracks */
513 for(t=0;t<realtrackcnt;t++) {
514 if(_mm_eof(modreader)) {
515 _mm_errno = MMERR_LOADING_TRACK;
516 return 0;
517 }
518 if (!AMF_UnpackTrack(modreader)) {
519 _mm_errno = MMERR_LOADING_TRACK;
520 return 0;
521 }
522 if(!(of.tracks[t]=AMF_ConvertTrack()))
523 return 0;
524 }
525 /* add an extra void track */
526 UniReset();
527 for(t=0;t<64;t++) UniNewline();
528 of.tracks[realtrackcnt++]=UniDup();
529 for(t=realtrackcnt;t<of.numtrk;t++) of.tracks[t]=NULL;
530
531 /* compute sample offsets */
532 samplepos=_mm_ftell(modreader);
533 for(realsmpcnt=t=0;t<of.numsmp;t++)
534 if(realsmpcnt<of.samples[t].seekpos)
535 realsmpcnt=of.samples[t].seekpos;
536 for(t=1;t<=realsmpcnt;t++) {
537 q=of.samples;
538 while(q->seekpos!=t) q++;
539 q->seekpos=samplepos;
540 samplepos+=q->length;
541 }
542
543 return 1;
544}
545
546CHAR *AMF_LoadTitle(void)
547{
548 CHAR s[32];
549
550 _mm_fseek(modreader,4,SEEK_SET);
551 if(!_mm_read_UBYTES(s,32,modreader)) return NULL;
552
553 return(DupStr(s,32,1));
554}
555
556/*========== Loader information */
557
558MIKMODAPI MLOADER load_amf={
559 NULL,
560 "AMF",
561 "AMF (DSMI Advanced Module Format)",
562 AMF_Init,
563 AMF_Test,
564 AMF_Load,
565 AMF_Cleanup,
566 AMF_LoadTitle
567};
568
569/* ex:set ts=4: */