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_gdm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 General DigiMusic (GDM) module loader
27 ==============================================================================*/
31 Written by Kev Vance<kvance@zeux.org>
32 based on the file format description written by 'MenTaLguY'
51 #include "mikmod_internals.h"
54 extern int fprintf(FILE *, const char *, ...);
57 typedef struct GDMNOTE
{
66 typedef GDMNOTE GDMTRACK
[64];
68 typedef struct GDMHEADER
{
101 typedef struct GDMSAMPLE
{
114 static GDMHEADER
*mh
=NULL
; /* pointer to GDM header */
115 static GDMNOTE
*gdmbuf
=NULL
; /* pointer to a complete GDM pattern */
117 CHAR GDM_Version
[]="General DigiMusic 1.xx";
119 static int GDM_Test(void)
121 /* test for gdm magic numbers */
124 _mm_fseek(modreader
,0x00,SEEK_SET
);
125 if (!_mm_read_UBYTES(id
,4,modreader
))
127 if (!memcmp(id
,"GDM\xfe",4)) {
128 _mm_fseek(modreader
,71,SEEK_SET
);
129 if (!_mm_read_UBYTES(id
,4,modreader
))
131 if (!memcmp(id
,"GMFS",4))
137 static int GDM_Init(void)
139 if (!(gdmbuf
=(GDMNOTE
*)MikMod_malloc(32*64*sizeof(GDMNOTE
)))) return 0;
140 if (!(mh
=(GDMHEADER
*)MikMod_malloc(sizeof(GDMHEADER
)))) return 0;
145 static void GDM_Cleanup(void)
151 static int GDM_ReadPattern(void)
153 int pos
,flag
,ch
,i
,maxch
;
157 /* get pattern length */
158 length
=_mm_read_I_UWORD(modreader
)-2;
160 /* clear pattern data */
161 memset(gdmbuf
,255,32*64*sizeof(GDMNOTE
));
166 memset(&n
,255,sizeof(GDMNOTE
));
167 flag
=_mm_read_UBYTE(modreader
);
170 if (_mm_eof(modreader
)) {
171 _mm_errno
=MMERR_LOADING_PATTERN
;
176 if (ch
>maxch
) maxch
=ch
;
184 n
.note
=_mm_read_UBYTE(modreader
)&127;
185 n
.samp
=_mm_read_UBYTE(modreader
);
190 /* effect channel set */
191 i
=_mm_read_UBYTE(modreader
);
192 n
.effect
[i
>>6].effect
=i
&31;
193 n
.effect
[i
>>6].param
=_mm_read_UBYTE(modreader
);
197 memcpy(gdmbuf
+(64U*ch
)+pos
,&n
,sizeof(GDMNOTE
));
203 static UBYTE
*GDM_ConvertTrack(GDMNOTE
*tr
)
213 if ((ins
)&&(ins
!=255))
214 UniInstrument(ins
-1);
216 UniNote(((note
>>4)*OCTAVE
)+(note
&0xf)-1);
219 inf
= tr
[t
].effect
[i
].param
;
220 switch (tr
[t
].effect
[i
].effect
) {
221 case 1: /* toneslide up */
222 UniEffect(UNI_S3MEFFECTF
,inf
);
224 case 2: /* toneslide down */
225 UniEffect(UNI_S3MEFFECTE
,inf
);
227 case 3: /* glissando to note */
228 UniEffect(UNI_ITEFFECTG
,inf
);
230 case 4: /* vibrato */
231 UniEffect(UNI_ITEFFECTH
,inf
);
233 case 5: /* portamento+volslide */
234 UniEffect(UNI_ITEFFECTG
,0);
235 UniEffect(UNI_S3MEFFECTD
,inf
);
237 case 6: /* vibrato+volslide */
238 UniEffect(UNI_ITEFFECTH
,0);
239 UniEffect(UNI_S3MEFFECTD
,inf
);
241 case 7: /* tremolo */
242 UniEffect(UNI_S3MEFFECTR
,inf
);
245 UniEffect(UNI_S3MEFFECTI
,inf
);
248 UniPTEffect(0x09,inf
);
250 case 0x0a: /* volslide */
251 UniEffect(UNI_S3MEFFECTD
,inf
);
253 case 0x0b: /* jump to order */
254 UniPTEffect(0x0b,inf
);
256 case 0x0c: /* volume set */
257 UniPTEffect(0x0c,inf
);
259 case 0x0d: /* pattern break */
260 UniPTEffect(0x0d,inf
);
262 case 0x0e: /* extended */
264 case 0x10: /* fine portamento up */
265 UniEffect(UNI_S3MEFFECTF
, 0x0f|((inf
<<4)&0x0f));
267 case 0x20: /* fine portamento down */
268 UniEffect(UNI_S3MEFFECTE
, 0xf0|(inf
&0x0f));
270 case 0x30: /* glissando control */
271 UniEffect(SS_GLISSANDO
, inf
&0x0f);
273 case 0x40: /* vibrato waveform */
274 UniEffect(SS_VIBWAVE
, inf
&0x0f);
276 case 0x50: /* set c4spd */
277 UniEffect(SS_FINETUNE
, inf
&0x0f);
279 case 0x60: /* loop fun */
280 UniEffect(UNI_ITEFFECTS0
, (inf
&0x0f)|0xb0);
282 case 0x70: /* tremolo waveform */
283 UniEffect(SS_TREMWAVE
, inf
&0x0f);
285 case 0x80: /* extra fine porta up */
286 UniEffect(UNI_S3MEFFECTF
, 0x0e|((inf
<<4)&0x0f));
288 case 0x90: /* extra fine porta down */
289 UniEffect(UNI_S3MEFFECTE
, 0xe0|(inf
&0x0f));
291 case 0xa0: /* fine volslide up */
292 UniEffect(UNI_S3MEFFECTD
, 0x0f|((inf
<<4)&0x0f));
294 case 0xb0: /* fine volslide down */
295 UniEffect(UNI_S3MEFFECTE
, 0xf0|(inf
&0x0f));
297 case 0xc0: /* note cut */
298 case 0xd0: /* note delay */
299 case 0xe0: /* extend row */
300 UniPTEffect(0xe,inf
);
304 case 0x0f: /* set tempo */
305 UniEffect(UNI_S3MEFFECTA
,inf
);
307 case 0x10: /* arpeggio */
308 UniPTEffect(0x0,inf
);
310 case 0x12: /* retrigger */
311 UniEffect(UNI_S3MEFFECTQ
,inf
);
313 case 0x13: /* set global volume */
314 UniEffect(UNI_XMEFFECTG
,inf
<<1);
316 case 0x14: /* fine vibrato */
317 UniEffect(UNI_ITEFFECTU
,inf
);
319 case 0x1e: /* special */
321 case 8: /* set pan position */
323 UniPTEffect(0x08,255);
325 UniPTEffect(0x08,inf
<<1);
329 case 0x1f: /* set bpm */
331 UniEffect(UNI_S3MEFFECTT
,inf
);
340 static int GDM_Load(int curious
)
349 _mm_read_string(mh
->id1
,4,modreader
);
350 _mm_read_string(mh
->songname
,32,modreader
);
351 _mm_read_string(mh
->author
,32,modreader
);
352 _mm_read_string(mh
->eofmarker
,3,modreader
);
353 _mm_read_string(mh
->id2
,4,modreader
);
355 mh
->majorver
=_mm_read_UBYTE(modreader
);
356 mh
->minorver
=_mm_read_UBYTE(modreader
);
357 mh
->trackerid
=_mm_read_I_UWORD(modreader
);
358 mh
->t_majorver
=_mm_read_UBYTE(modreader
);
359 mh
->t_minorver
=_mm_read_UBYTE(modreader
);
360 _mm_read_UBYTES(mh
->pantable
,32,modreader
);
361 mh
->mastervol
=_mm_read_UBYTE(modreader
);
362 mh
->mastertempo
=_mm_read_UBYTE(modreader
);
363 mh
->masterbpm
=_mm_read_UBYTE(modreader
);
364 mh
->flags
=_mm_read_I_UWORD(modreader
);
366 mh
->orderloc
=_mm_read_I_ULONG(modreader
);
367 mh
->ordernum
=_mm_read_UBYTE(modreader
);
368 mh
->patternloc
=_mm_read_I_ULONG(modreader
);
369 mh
->patternnum
=_mm_read_UBYTE(modreader
);
370 mh
->samhead
=_mm_read_I_ULONG(modreader
);
371 mh
->samdata
=_mm_read_I_ULONG(modreader
);
372 mh
->samnum
=_mm_read_UBYTE(modreader
);
373 mh
->messageloc
=_mm_read_I_ULONG(modreader
);
374 mh
->messagelen
=_mm_read_I_ULONG(modreader
);
375 mh
->scrollyloc
=_mm_read_I_ULONG(modreader
);
376 mh
->scrollylen
=_mm_read_I_UWORD(modreader
);
377 mh
->graphicloc
=_mm_read_I_ULONG(modreader
);
378 mh
->graphiclen
=_mm_read_I_UWORD(modreader
);
380 /* have we ended abruptly? */
381 if (_mm_eof(modreader
)) {
382 _mm_errno
=MMERR_LOADING_HEADER
;
387 if(mh
->ordernum
==255) {
388 _mm_errno
=MMERR_LOADING_PATTERN
;
393 of
.modtype
=StrDup(GDM_Version
);
394 of
.modtype
[18]=mh
->majorver
+'0';
395 of
.modtype
[20]=mh
->minorver
/10+'0';
396 of
.modtype
[21]=mh
->minorver
%10+'0';
397 of
.songname
=DupStr(mh
->songname
,32,0);
398 of
.numpat
=mh
->patternnum
+1;
400 of
.numins
=of
.numsmp
=mh
->samnum
+1;
401 of
.initspeed
=mh
->mastertempo
;
402 of
.inittempo
=mh
->masterbpm
;
403 of
.initvolume
=mh
->mastervol
<<1;
404 of
.flags
|=UF_S3MSLIDES
| UF_PANNING
;
405 /* XXX whenever possible, we should try to determine the original format.
406 Here we assume it was S3M-style wrt bpmlimit... */
409 /* read the order data */
410 if (!AllocPositions(mh
->ordernum
+1)) {
411 _mm_errno
=MMERR_OUT_OF_MEMORY
;
415 _mm_fseek(modreader
,mh
->orderloc
,SEEK_SET
);
416 for (i
=0;i
<mh
->ordernum
+1;i
++)
417 of
.positions
[i
]=_mm_read_UBYTE(modreader
);
420 for (i
=0;i
<mh
->ordernum
+1;i
++) {
421 int order
=of
.positions
[i
];
422 if(order
==255) order
=LAST_PATTERN
;
423 of
.positions
[of
.numpos
]=order
;
424 if (of
.positions
[i
]<254) of
.numpos
++;
427 /* have we ended abruptly yet? */
428 if (_mm_eof(modreader
)) {
429 _mm_errno
=MMERR_LOADING_HEADER
;
433 /* time to load the samples */
434 if (!AllocSamples()) {
435 _mm_errno
=MMERR_OUT_OF_MEMORY
;
440 position
=mh
->samdata
;
442 /* seek to instrument position */
443 _mm_fseek(modreader
,mh
->samhead
,SEEK_SET
);
445 for (i
=0;i
<of
.numins
;i
++) {
446 /* load sample info */
447 _mm_read_UBYTES(s
.sampname
,32,modreader
);
448 _mm_read_UBYTES(s
.filename
,12,modreader
);
449 s
.ems
=_mm_read_UBYTE(modreader
);
450 s
.length
=_mm_read_I_ULONG(modreader
);
451 s
.loopbeg
=_mm_read_I_ULONG(modreader
);
452 s
.loopend
=_mm_read_I_ULONG(modreader
);
453 s
.flags
=_mm_read_UBYTE(modreader
);
454 s
.c4spd
=_mm_read_I_UWORD(modreader
);
455 s
.vol
=_mm_read_UBYTE(modreader
);
456 s
.pan
=_mm_read_UBYTE(modreader
);
458 if (_mm_eof(modreader
)) {
459 _mm_errno
=MMERR_LOADING_SAMPLEINFO
;
462 q
->samplename
=DupStr(s
.sampname
,32,0);
465 q
->loopstart
=s
.loopbeg
;
466 q
->loopend
=s
.loopend
;
476 q
->flags
|=SF_16BITS
;
478 q
->flags
|=SF_STEREO
;
482 /* set the panning */
483 for (i
=x
=0;i
<32;i
++) {
484 of
.panning
[i
]=mh
->pantable
[i
];
486 of
.panning
[i
]=PAN_LEFT
;
487 else if (of
.panning
[i
]==8)
488 of
.panning
[i
]=PAN_CENTER
;
489 else if (of
.panning
[i
]==15)
490 of
.panning
[i
]=PAN_RIGHT
;
491 else if (of
.panning
[i
]==16)
492 of
.panning
[i
]=PAN_SURROUND
;
493 else if (of
.panning
[i
]==255)
497 if (mh
->pantable
[i
]!=255)
503 of
.numchn
=1; /* for broken counts */
505 /* load the pattern info */
506 of
.numtrk
=of
.numpat
*of
.numchn
;
508 /* jump to patterns */
509 _mm_fseek(modreader
,mh
->patternloc
,SEEK_SET
);
511 if (!AllocTracks()) {
512 _mm_errno
=MMERR_OUT_OF_MEMORY
;
516 if (!AllocPatterns()) {
517 _mm_errno
=MMERR_OUT_OF_MEMORY
;
521 for (i
=track
=0;i
<of
.numpat
;i
++) {
522 if (!GDM_ReadPattern()) {
523 _mm_errno
=MMERR_LOADING_PATTERN
;
526 for (u
=0;u
<of
.numchn
;u
++,track
++) {
527 of
.tracks
[track
]=GDM_ConvertTrack(&gdmbuf
[u
<<6]);
528 if (!of
.tracks
[track
]) {
529 _mm_errno
=MMERR_LOADING_TRACK
;
537 static CHAR
*GDM_LoadTitle(void)
541 _mm_fseek(modreader
,4,SEEK_SET
);
542 if (!_mm_read_UBYTES(s
,32,modreader
)) return NULL
;
544 return DupStr(s
,28,0);
547 MIKMODAPI MLOADER load_gdm
=
551 "GDM (General DigiMusic)",