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