1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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_amf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 DMP Advanced Module Format loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
51 typedef 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 */
57 UWORD numtracks
; /* number of tracks saved */
58 UBYTE numchannels
; /* number of channels used */
59 SBYTE panpos
[32]; /* voice pan positions */
64 typedef struct AMFSAMPLE
{
76 typedef struct AMFNOTE
{
77 UBYTE note
,instr
,volume
,fxcnt
;
82 /*========== Loader variables */
84 static AMFHEADER
*mh
= NULL
;
86 static CHAR AMF_Version
[AMFTEXTLEN
+1] = "DSMI Module Format 0.0";
87 static AMFNOTE
*track
= NULL
;
89 /*========== Loader code */
95 if(!_mm_read_UBYTES(id
,3,modreader
)) return 0;
96 if(memcmp(id
,"AMF",3)) return 0;
98 ver
=_mm_read_UBYTE(modreader
);
99 if((ver
>=10)&&(ver
<=14)) return 1;
105 if(!(mh
=(AMFHEADER
*)MikMod_malloc(sizeof(AMFHEADER
)))) return 0;
106 if(!(track
=(AMFNOTE
*)MikMod_calloc(64,sizeof(AMFNOTE
)))) return 0;
111 void AMF_Cleanup(void)
117 static int AMF_UnpackTrack(MREADER
* modreader
)
124 memset(track
,0,64*sizeof(AMFNOTE
));
126 /* read packed track */
128 tracksize
=_mm_read_I_UWORD(modreader
);
129 tracksize
+=((ULONG
)_mm_read_UBYTE(modreader
))<<16;
132 row
=_mm_read_UBYTE(modreader
);
133 cmd
=_mm_read_UBYTE(modreader
);
134 arg
=_mm_read_SBYTE(modreader
);
135 /* unexpected end of track */
137 if((row
==0xff)&&(cmd
==0xff)&&(arg
==-1))
139 /* the last triplet should be FF FF FF, but this is not
140 always the case... maybe a bug in m2amf ?
146 /* invalid row (probably unexpected end of row) */
152 track
[row
].volume
=(UBYTE
)arg
+1;
156 if ((arg
<0)&&(row
+arg
>=0)) {
157 memcpy(track
+row
,track
+(row
+arg
),sizeof(AMFNOTE
));
162 track
[row
].instr
=arg
+1;
165 /* volume without note */
166 track
[row
].volume
=(UBYTE
)arg
+1;
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. */
174 if(track
[row
].fxcnt
<3) {
178 track
[row
].effect
[track
[row
].fxcnt
]=cmd
&0x7f;
179 track
[row
].parameter
[track
[row
].fxcnt
]=arg
;
188 static UBYTE
* AMF_ConvertTrack(void)
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
);
199 while(track
[row
].fxcnt
--) {
200 SBYTE inf
=track
[row
].parameter
[track
[row
].fxcnt
];
202 switch(track
[row
].effect
[track
[row
].fxcnt
]) {
203 case 1: /* Set speed */
204 UniEffect(UNI_S3MEFFECTA
,inf
);
206 case 2: /* Volume slide */
208 UniWriteByte(UNI_S3MEFFECTD
);
210 UniWriteByte((inf
&0xf)<<4);
212 UniWriteByte((-inf
)&0xf);
215 /* effect 3, set channel volume, done in UnpackTrack */
216 case 4: /* Porta up/down */
219 UniEffect(UNI_S3MEFFECTE
,inf
);
220 fx4memory
=UNI_S3MEFFECTE
;
222 UniEffect(UNI_S3MEFFECTF
,-inf
);
223 fx4memory
=UNI_S3MEFFECTF
;
226 UniEffect(fx4memory
,0);
228 /* effect 5, "Porta abs", not supported */
229 case 6: /* Porta to note */
230 UniEffect(UNI_ITEFFECTG
,inf
);
233 UniEffect(UNI_S3MEFFECTI
,inf
);
235 case 8: /* Arpeggio */
236 UniPTEffect(0x0,inf
);
238 case 9: /* Vibrato */
239 UniPTEffect(0x4,inf
);
241 case 0xa: /* Porta + Volume slide */
244 UniWriteByte(UNI_S3MEFFECTD
);
246 UniWriteByte((inf
&0xf)<<4);
248 UniWriteByte((-inf
)&0xf);
251 case 0xb: /* Vibrato + Volume slide */
254 UniWriteByte(UNI_S3MEFFECTD
);
256 UniWriteByte((inf
&0xf)<<4);
258 UniWriteByte((-inf
)&0xf);
261 case 0xc: /* Pattern break (in hex) */
262 UniPTEffect(0xd,inf
);
264 case 0xd: /* Pattern jump */
265 UniPTEffect(0xb,inf
);
267 /* effect 0xe, "Sync", not supported */
268 case 0xf: /* Retrig */
269 UniEffect(UNI_S3MEFFECTQ
,inf
&0xf);
271 case 0x10: /* Sample offset */
272 UniPTEffect(0x9,inf
);
274 case 0x11: /* Fine volume slide */
276 UniWriteByte(UNI_S3MEFFECTD
);
278 UniWriteByte((inf
&0xf)<<4|0xf);
280 UniWriteByte(0xf0|((-inf
)&0xf));
283 case 0x12: /* Fine portamento */
286 UniEffect(UNI_S3MEFFECTE
,0xf0|(inf
&0xf));
287 fx4memory
=UNI_S3MEFFECTE
;
289 UniEffect(UNI_S3MEFFECTF
,0xf0|((-inf
)&0xf));
290 fx4memory
=UNI_S3MEFFECTF
;
293 UniEffect(fx4memory
,0);
295 case 0x13: /* Delay note */
296 UniPTEffect(0xe,0xd0|(inf
&0xf));
298 case 0x14: /* Note cut */
302 case 0x15: /* Set tempo */
303 UniEffect(UNI_S3MEFFECTT
,inf
);
305 case 0x16: /* Extra fine portamento */
308 UniEffect(UNI_S3MEFFECTE
,0xe0|((inf
>>2)&0xf));
309 fx4memory
=UNI_S3MEFFECTE
;
311 UniEffect(UNI_S3MEFFECTF
,0xe0|(((-inf
)>>2)&0xf));
312 fx4memory
=UNI_S3MEFFECTF
;
315 UniEffect(fx4memory
,0);
317 case 0x17: /* Panning */
319 UniEffect(UNI_ITEFFECTS0
,0x91); /* surround */
321 UniPTEffect(0x8,(inf
==64)?255:(inf
+64)<<1);
322 of
.flags
|= UF_PANNING
;
327 if (track
[row
].volume
) UniVolEffect(VOL_VOLUME
,track
[row
].volume
-1);
333 int AMF_Load(int curious
)
335 int t
,u
,realtrackcnt
,realsmpcnt
,defaultpanning
;
340 int channel_remap
[16];
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
;
355 if(mh
->version
>=11) {
356 memset(mh
->panpos
,0,32);
357 _mm_read_SBYTES(mh
->panpos
,(mh
->version
>=13)?32:16,modreader
);
359 _mm_read_UBYTES(channel_remap
,16,modreader
);
361 if (mh
->version
>=13) {
362 mh
->songbpm
=_mm_read_UBYTE(modreader
);
364 _mm_errno
=MMERR_NOT_A_MODULE
;
367 mh
->songspd
=_mm_read_UBYTE(modreader
);
369 _mm_errno
=MMERR_NOT_A_MODULE
;
377 if(_mm_eof(modreader
)) {
378 _mm_errno
= MMERR_LOADING_HEADER
;
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
;
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... */
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.
409 for (t
= 0; t
< 32; t
++) {
410 if (mh
->panpos
[t
] > 64) {
411 of
.panning
[t
] = PAN_SURROUND
;
414 if (mh
->panpos
[t
] == 64)
415 of
.panning
[t
] = PAN_RIGHT
;
417 of
.panning
[t
] = (mh
->panpos
[t
] + 64) << 1;
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 */
427 of
.flags
|= UF_PANNING
;
429 of
.numins
=of
.numsmp
=mh
->numsamples
;
431 if(!AllocPositions(of
.numpos
)) return 0;
432 for(t
=0;t
<of
.numpos
;t
++)
435 if(!AllocTracks()) return 0;
436 if(!AllocPatterns()) return 0;
438 /* read AMF order table */
439 for (t
=0;t
<of
.numpat
;t
++) {
442 of
.pattrows
[t
]=_mm_read_I_UWORD(modreader
);
444 _mm_read_I_UWORDS(of
.patterns
+(t
*of
.numchn
),of
.numchn
,modreader
);
446 for(u
=0;u
<of
.numchn
;u
++)
447 of
.patterns
[t
*of
.numchn
+channel_remap
[u
]]=_mm_read_I_UWORD(modreader
);
449 if(_mm_eof(modreader
)) {
450 _mm_errno
= MMERR_LOADING_HEADER
;
454 /* read sample information */
455 if(!AllocSamples()) return 0;
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
);
471 s
.reppos
=_mm_read_I_UWORD(modreader
);
475 if(_mm_eof(modreader
)) {
476 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
480 q
->samplename
= DupStr(s
.samplename
,32,1);
482 q
->volume
= s
.volume
;
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
;
493 /* read track table */
494 if(!(track_remap
=MikMod_calloc(mh
->numtracks
+1,sizeof(UWORD
))))
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
;
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
;
510 MikMod_free(track_remap
);
513 for(t
=0;t
<realtrackcnt
;t
++) {
514 if(_mm_eof(modreader
)) {
515 _mm_errno
= MMERR_LOADING_TRACK
;
518 if (!AMF_UnpackTrack(modreader
)) {
519 _mm_errno
= MMERR_LOADING_TRACK
;
522 if(!(of
.tracks
[t
]=AMF_ConvertTrack()))
525 /* add an extra void track */
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
;
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
++) {
538 while(q
->seekpos
!=t
) q
++;
539 q
->seekpos
=samplepos
;
540 samplepos
+=q
->length
;
546 CHAR
*AMF_LoadTitle(void)
550 _mm_fseek(modreader
,4,SEEK_SET
);
551 if(!_mm_read_UBYTES(s
,32,modreader
)) return NULL
;
553 return(DupStr(s
,32,1));
556 /*========== Loader information */
558 MIKMODAPI MLOADER load_amf
={
561 "AMF (DSMI Advanced Module Format)",