Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / mikmod / load_gdm.c
blob694d534236f2a202362b669dfaad0ef362af0a8d
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
18 02111-1307,USA.
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'
33 <mental@kludge.org>
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
45 #include <stdio.h>
46 #ifdef HAVE_MEMORY_H
47 #include <memory.h>
48 #endif
49 #include <string.h>
51 #include "mikmod_internals.h"
53 #ifdef SUNOS
54 extern int fprintf(FILE *, const char *, ...);
55 #endif
57 typedef struct GDMNOTE {
58 UBYTE note;
59 UBYTE samp;
60 struct {
61 UBYTE effect;
62 UBYTE param;
63 } effect[4];
64 } GDMNOTE;
66 typedef GDMNOTE GDMTRACK[64];
68 typedef struct GDMHEADER {
69 CHAR id1[4];
70 CHAR songname[32];
71 CHAR author[32];
72 CHAR eofmarker[3];
73 CHAR id2[4];
75 UBYTE majorver;
76 UBYTE minorver;
77 UWORD trackerid;
78 UBYTE t_majorver;
79 UBYTE t_minorver;
80 UBYTE pantable[32];
81 UBYTE mastervol;
82 UBYTE mastertempo;
83 UBYTE masterbpm;
84 UWORD flags;
86 ULONG orderloc;
87 UBYTE ordernum;
88 ULONG patternloc;
89 UBYTE patternnum;
90 ULONG samhead;
91 ULONG samdata;
92 UBYTE samnum;
93 ULONG messageloc;
94 ULONG messagelen;
95 ULONG scrollyloc;
96 UWORD scrollylen;
97 ULONG graphicloc;
98 UWORD graphiclen;
99 } GDMHEADER;
101 typedef struct GDMSAMPLE {
102 CHAR sampname[32];
103 CHAR filename[13];
104 UBYTE ems;
105 ULONG length;
106 ULONG loopbeg;
107 ULONG loopend;
108 UBYTE flags;
109 UWORD c4spd;
110 UBYTE vol;
111 UBYTE pan;
112 } 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 */
122 UBYTE id[4];
124 _mm_fseek(modreader,0x00,SEEK_SET);
125 if (!_mm_read_UBYTES(id,4,modreader))
126 return 0;
127 if (!memcmp(id,"GDM\xfe",4)) {
128 _mm_fseek(modreader,71,SEEK_SET);
129 if (!_mm_read_UBYTES(id,4,modreader))
130 return 0;
131 if (!memcmp(id,"GMFS",4))
132 return 1;
134 return 0;
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;
142 return 1;
145 static void GDM_Cleanup(void)
147 MikMod_free(mh);
148 MikMod_free(gdmbuf);
151 static int GDM_ReadPattern(void)
153 int pos,flag,ch,i,maxch;
154 GDMNOTE n;
155 UWORD length,x=0;
157 /* get pattern length */
158 length=_mm_read_I_UWORD(modreader)-2;
160 /* clear pattern data */
161 memset(gdmbuf,255,32*64*sizeof(GDMNOTE));
162 pos=0;
163 maxch=0;
165 while (x<length) {
166 memset(&n,255,sizeof(GDMNOTE));
167 flag=_mm_read_UBYTE(modreader);
168 x++;
170 if (_mm_eof(modreader)) {
171 _mm_errno=MMERR_LOADING_PATTERN;
172 return 0;
175 ch=flag&31;
176 if (ch>maxch) maxch=ch;
177 if (!flag) {
178 pos++;
179 continue;
181 if (flag&0x60) {
182 if (flag&0x20) {
183 /* new note */
184 n.note=_mm_read_UBYTE(modreader)&127;
185 n.samp=_mm_read_UBYTE(modreader);
186 x +=2;
188 if (flag&0x40) {
189 do {
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);
194 x +=2;
195 } while (i&32);
197 memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE));
200 return 1;
203 static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
205 int t,i=0;
206 UBYTE note,ins,inf;
208 UniReset();
209 for (t=0;t<64;t++) {
210 note=tr[t].note;
211 ins=tr[t].samp;
213 if ((ins)&&(ins!=255))
214 UniInstrument(ins-1);
215 if (note!=255) {
216 UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
218 for (i=0;i<4;i++) {
219 inf = tr[t].effect[i].param;
220 switch (tr[t].effect[i].effect) {
221 case 1: /* toneslide up */
222 UniEffect(UNI_S3MEFFECTF,inf);
223 break;
224 case 2: /* toneslide down */
225 UniEffect(UNI_S3MEFFECTE,inf);
226 break;
227 case 3: /* glissando to note */
228 UniEffect(UNI_ITEFFECTG,inf);
229 break;
230 case 4: /* vibrato */
231 UniEffect(UNI_ITEFFECTH,inf);
232 break;
233 case 5: /* portamento+volslide */
234 UniEffect(UNI_ITEFFECTG,0);
235 UniEffect(UNI_S3MEFFECTD,inf);
236 break;
237 case 6: /* vibrato+volslide */
238 UniEffect(UNI_ITEFFECTH,0);
239 UniEffect(UNI_S3MEFFECTD,inf);
240 break;
241 case 7: /* tremolo */
242 UniEffect(UNI_S3MEFFECTR,inf);
243 break;
244 case 8: /* tremor */
245 UniEffect(UNI_S3MEFFECTI,inf);
246 break;
247 case 9: /* offset */
248 UniPTEffect(0x09,inf);
249 break;
250 case 0x0a: /* volslide */
251 UniEffect(UNI_S3MEFFECTD,inf);
252 break;
253 case 0x0b: /* jump to order */
254 UniPTEffect(0x0b,inf);
255 break;
256 case 0x0c: /* volume set */
257 UniPTEffect(0x0c,inf);
258 break;
259 case 0x0d: /* pattern break */
260 UniPTEffect(0x0d,inf);
261 break;
262 case 0x0e: /* extended */
263 switch (inf&0xf0) {
264 case 0x10: /* fine portamento up */
265 UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f));
266 break;
267 case 0x20: /* fine portamento down */
268 UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
269 break;
270 case 0x30: /* glissando control */
271 UniEffect(SS_GLISSANDO, inf&0x0f);
272 break;
273 case 0x40: /* vibrato waveform */
274 UniEffect(SS_VIBWAVE, inf&0x0f);
275 break;
276 case 0x50: /* set c4spd */
277 UniEffect(SS_FINETUNE, inf&0x0f);
278 break;
279 case 0x60: /* loop fun */
280 UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0);
281 break;
282 case 0x70: /* tremolo waveform */
283 UniEffect(SS_TREMWAVE, inf&0x0f);
284 break;
285 case 0x80: /* extra fine porta up */
286 UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f));
287 break;
288 case 0x90: /* extra fine porta down */
289 UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
290 break;
291 case 0xa0: /* fine volslide up */
292 UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f));
293 break;
294 case 0xb0: /* fine volslide down */
295 UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
296 break;
297 case 0xc0: /* note cut */
298 case 0xd0: /* note delay */
299 case 0xe0: /* extend row */
300 UniPTEffect(0xe,inf);
301 break;
303 break;
304 case 0x0f: /* set tempo */
305 UniEffect(UNI_S3MEFFECTA,inf);
306 break;
307 case 0x10: /* arpeggio */
308 UniPTEffect(0x0,inf);
309 break;
310 case 0x12: /* retrigger */
311 UniEffect(UNI_S3MEFFECTQ,inf);
312 break;
313 case 0x13: /* set global volume */
314 UniEffect(UNI_XMEFFECTG,inf<<1);
315 break;
316 case 0x14: /* fine vibrato */
317 UniEffect(UNI_ITEFFECTU,inf);
318 break;
319 case 0x1e: /* special */
320 switch (inf&0xf0) {
321 case 8: /* set pan position */
322 if (inf >=128)
323 UniPTEffect(0x08,255);
324 else
325 UniPTEffect(0x08,inf<<1);
326 break;
328 break;
329 case 0x1f: /* set bpm */
330 if (inf >=0x20)
331 UniEffect(UNI_S3MEFFECTT,inf);
332 break;
335 UniNewline();
337 return UniDup();
340 static int GDM_Load(int curious)
342 int i,x,u,track;
343 SAMPLE *q;
344 GDMSAMPLE s;
345 ULONG position;
346 (void)curious;
348 /* read header */
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;
383 return 0;
386 /* any orders? */
387 if(mh->ordernum==255) {
388 _mm_errno=MMERR_LOADING_PATTERN;
389 return 0;
392 /* now we fill */
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;
399 of.reppos=0;
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... */
407 of.bpmlimit = 32;
409 /* read the order data */
410 if (!AllocPositions(mh->ordernum+1)) {
411 _mm_errno=MMERR_OUT_OF_MEMORY;
412 return 0;
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);
419 of.numpos=0;
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;
430 return 0;
433 /* time to load the samples */
434 if (!AllocSamples()) {
435 _mm_errno=MMERR_OUT_OF_MEMORY;
436 return 0;
439 q=of.samples;
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;
460 return 0;
462 q->samplename=DupStr(s.sampname,32,0);
463 q->speed=s.c4spd;
464 q->length=s.length;
465 q->loopstart=s.loopbeg;
466 q->loopend=s.loopend;
467 q->volume=s.vol;
468 q->panning=s.pan;
469 q->seekpos=position;
471 position +=s.length;
473 if (s.flags&1)
474 q->flags |=SF_LOOP;
475 if (s.flags&2)
476 q->flags |=SF_16BITS;
477 if (s.flags&16)
478 q->flags |=SF_STEREO;
479 q++;
482 /* set the panning */
483 for (i=x=0;i<32;i++) {
484 of.panning[i]=mh->pantable[i];
485 if (!of.panning[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)
494 of.panning[i]=128;
495 else
496 of.panning[i]<<=3;
497 if (mh->pantable[i]!=255)
498 x=i;
501 of.numchn=x+1;
502 if (of.numchn<1)
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;
513 return 0;
516 if (!AllocPatterns()) {
517 _mm_errno=MMERR_OUT_OF_MEMORY;
518 return 0;
521 for (i=track=0;i<of.numpat;i++) {
522 if (!GDM_ReadPattern()) {
523 _mm_errno=MMERR_LOADING_PATTERN;
524 return 0;
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;
530 return 0;
534 return 1;
537 static CHAR *GDM_LoadTitle(void)
539 CHAR s[32];
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=
549 NULL,
550 "GDM",
551 "GDM (General DigiMusic)",
552 GDM_Init,
553 GDM_Test,
554 GDM_Load,
555 GDM_Cleanup,
556 GDM_LoadTitle
559 /* ex:set ts=4: */