diff options
Diffstat (limited to 'apps/plugins/mikmod/load_gdm.c')
-rw-r--r-- | apps/plugins/mikmod/load_gdm.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_gdm.c b/apps/plugins/mikmod/load_gdm.c new file mode 100644 index 0000000000..616a2b56a3 --- /dev/null +++ b/apps/plugins/mikmod/load_gdm.c | |||
@@ -0,0 +1,558 @@ | |||
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_gdm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | General DigiMusic (GDM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Written by Kev Vance<kvance@zeux.org> | ||
32 | based on the file format description written by 'MenTaLguY' | ||
33 | <mental@kludge.org> | ||
34 | |||
35 | */ | ||
36 | |||
37 | #ifdef HAVE_CONFIG_H | ||
38 | #include "config.h" | ||
39 | #endif | ||
40 | |||
41 | #ifdef HAVE_UNISTD_H | ||
42 | #include <unistd.h> | ||
43 | #endif | ||
44 | |||
45 | #include <stdio.h> | ||
46 | #ifdef HAVE_MEMORY_H | ||
47 | #include <memory.h> | ||
48 | #endif | ||
49 | #include <string.h> | ||
50 | |||
51 | #include "mikmod_internals.h" | ||
52 | |||
53 | #ifdef SUNOS | ||
54 | extern int fprintf(FILE *, const char *, ...); | ||
55 | #endif | ||
56 | |||
57 | typedef struct GDMNOTE { | ||
58 | UBYTE note; | ||
59 | UBYTE samp; | ||
60 | struct { | ||
61 | UBYTE effect; | ||
62 | UBYTE param; | ||
63 | } effect[4]; | ||
64 | } GDMNOTE; | ||
65 | |||
66 | typedef GDMNOTE GDMTRACK[64]; | ||
67 | |||
68 | typedef struct GDMHEADER { | ||
69 | CHAR id1[4]; | ||
70 | CHAR songname[32]; | ||
71 | CHAR author[32]; | ||
72 | CHAR eofmarker[3]; | ||
73 | CHAR id2[4]; | ||
74 | |||
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; | ||
85 | |||
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; | ||
100 | |||
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; | ||
113 | |||
114 | static GDMHEADER *mh=NULL; /* pointer to GDM header */ | ||
115 | static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */ | ||
116 | |||
117 | CHAR GDM_Version[]="General DigiMusic 1.xx"; | ||
118 | |||
119 | int GDM_Test(void) | ||
120 | { | ||
121 | /* test for gdm magic numbers */ | ||
122 | UBYTE id[4]; | ||
123 | |||
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; | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | int GDM_Init(void) | ||
138 | { | ||
139 | if (!(gdmbuf=(GDMNOTE*)MikMod_malloc(32*64*sizeof(GDMNOTE)))) return 0; | ||
140 | if (!(mh=(GDMHEADER*)MikMod_malloc(sizeof(GDMHEADER)))) return 0; | ||
141 | |||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | void GDM_Cleanup(void) | ||
146 | { | ||
147 | MikMod_free(mh); | ||
148 | MikMod_free(gdmbuf); | ||
149 | } | ||
150 | |||
151 | int GDM_ReadPattern(void) | ||
152 | { | ||
153 | int pos,flag,ch,i,maxch; | ||
154 | GDMNOTE n; | ||
155 | UWORD length,x=0; | ||
156 | |||
157 | /* get pattern length */ | ||
158 | length=_mm_read_I_UWORD(modreader)-2; | ||
159 | |||
160 | /* clear pattern data */ | ||
161 | memset(gdmbuf,255,32*64*sizeof(GDMNOTE)); | ||
162 | pos=0; | ||
163 | maxch=0; | ||
164 | |||
165 | while (x<length) { | ||
166 | memset(&n,255,sizeof(GDMNOTE)); | ||
167 | flag=_mm_read_UBYTE(modreader); | ||
168 | x++; | ||
169 | |||
170 | if (_mm_eof(modreader)) { | ||
171 | _mm_errno=MMERR_LOADING_PATTERN; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | ch=flag&31; | ||
176 | if (ch>maxch) maxch=ch; | ||
177 | if (!flag) { | ||
178 | pos++; | ||
179 | continue; | ||
180 | } | ||
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; | ||
187 | } | ||
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); | ||
196 | } | ||
197 | memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE)); | ||
198 | } | ||
199 | } | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | UBYTE *GDM_ConvertTrack(GDMNOTE*tr) | ||
204 | { | ||
205 | int t,i=0; | ||
206 | UBYTE note,ins,inf; | ||
207 | |||
208 | UniReset(); | ||
209 | for (t=0;t<64;t++) { | ||
210 | note=tr[t].note; | ||
211 | ins=tr[t].samp; | ||
212 | |||
213 | if ((ins)&&(ins!=255)) | ||
214 | UniInstrument(ins-1); | ||
215 | if (note!=255) { | ||
216 | UniNote(((note>>4)*OCTAVE)+(note&0xf)-1); | ||
217 | } | ||
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; | ||
302 | } | ||
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; | ||
327 | } | ||
328 | break; | ||
329 | case 0x1f: /* set bpm */ | ||
330 | if (inf >=0x20) | ||
331 | UniEffect(UNI_S3MEFFECTT,inf); | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | UniNewline(); | ||
336 | } | ||
337 | return UniDup(); | ||
338 | } | ||
339 | |||
340 | int GDM_Load(int curious) | ||
341 | { | ||
342 | int i,x,u,track; | ||
343 | SAMPLE *q; | ||
344 | GDMSAMPLE s; | ||
345 | ULONG position; | ||
346 | |||
347 | /* read header */ | ||
348 | _mm_read_string(mh->id1,4,modreader); | ||
349 | _mm_read_string(mh->songname,32,modreader); | ||
350 | _mm_read_string(mh->author,32,modreader); | ||
351 | _mm_read_string(mh->eofmarker,3,modreader); | ||
352 | _mm_read_string(mh->id2,4,modreader); | ||
353 | |||
354 | mh->majorver=_mm_read_UBYTE(modreader); | ||
355 | mh->minorver=_mm_read_UBYTE(modreader); | ||
356 | mh->trackerid=_mm_read_I_UWORD(modreader); | ||
357 | mh->t_majorver=_mm_read_UBYTE(modreader); | ||
358 | mh->t_minorver=_mm_read_UBYTE(modreader); | ||
359 | _mm_read_UBYTES(mh->pantable,32,modreader); | ||
360 | mh->mastervol=_mm_read_UBYTE(modreader); | ||
361 | mh->mastertempo=_mm_read_UBYTE(modreader); | ||
362 | mh->masterbpm=_mm_read_UBYTE(modreader); | ||
363 | mh->flags=_mm_read_I_UWORD(modreader); | ||
364 | |||
365 | mh->orderloc=_mm_read_I_ULONG(modreader); | ||
366 | mh->ordernum=_mm_read_UBYTE(modreader); | ||
367 | mh->patternloc=_mm_read_I_ULONG(modreader); | ||
368 | mh->patternnum=_mm_read_UBYTE(modreader); | ||
369 | mh->samhead=_mm_read_I_ULONG(modreader); | ||
370 | mh->samdata=_mm_read_I_ULONG(modreader); | ||
371 | mh->samnum=_mm_read_UBYTE(modreader); | ||
372 | mh->messageloc=_mm_read_I_ULONG(modreader); | ||
373 | mh->messagelen=_mm_read_I_ULONG(modreader); | ||
374 | mh->scrollyloc=_mm_read_I_ULONG(modreader); | ||
375 | mh->scrollylen=_mm_read_I_UWORD(modreader); | ||
376 | mh->graphicloc=_mm_read_I_ULONG(modreader); | ||
377 | mh->graphiclen=_mm_read_I_UWORD(modreader); | ||
378 | |||
379 | /* have we ended abruptly? */ | ||
380 | if (_mm_eof(modreader)) { | ||
381 | _mm_errno=MMERR_LOADING_HEADER; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | /* any orders? */ | ||
386 | if(mh->ordernum==255) { | ||
387 | _mm_errno=MMERR_LOADING_PATTERN; | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | /* now we fill */ | ||
392 | of.modtype=StrDup(GDM_Version); | ||
393 | of.modtype[18]=mh->majorver+'0'; | ||
394 | of.modtype[20]=mh->minorver/10+'0'; | ||
395 | of.modtype[21]=mh->minorver%10+'0'; | ||
396 | of.songname=DupStr(mh->songname,32,0); | ||
397 | of.numpat=mh->patternnum+1; | ||
398 | of.reppos=0; | ||
399 | of.numins=of.numsmp=mh->samnum+1; | ||
400 | of.initspeed=mh->mastertempo; | ||
401 | of.inittempo=mh->masterbpm; | ||
402 | of.initvolume=mh->mastervol<<1; | ||
403 | of.flags|=UF_S3MSLIDES | UF_PANNING; | ||
404 | /* XXX whenever possible, we should try to determine the original format. | ||
405 | Here we assume it was S3M-style wrt bpmlimit... */ | ||
406 | of.bpmlimit = 32; | ||
407 | |||
408 | /* read the order data */ | ||
409 | if (!AllocPositions(mh->ordernum+1)) { | ||
410 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | _mm_fseek(modreader,mh->orderloc,SEEK_SET); | ||
415 | for (i=0;i<mh->ordernum+1;i++) | ||
416 | of.positions[i]=_mm_read_UBYTE(modreader); | ||
417 | |||
418 | of.numpos=0; | ||
419 | for (i=0;i<mh->ordernum+1;i++) { | ||
420 | int order=of.positions[i]; | ||
421 | if(order==255) order=LAST_PATTERN; | ||
422 | of.positions[of.numpos]=order; | ||
423 | if (of.positions[i]<254) of.numpos++; | ||
424 | } | ||
425 | |||
426 | /* have we ended abruptly yet? */ | ||
427 | if (_mm_eof(modreader)) { | ||
428 | _mm_errno=MMERR_LOADING_HEADER; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* time to load the samples */ | ||
433 | if (!AllocSamples()) { | ||
434 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | q=of.samples; | ||
439 | position=mh->samdata; | ||
440 | |||
441 | /* seek to instrument position */ | ||
442 | _mm_fseek(modreader,mh->samhead,SEEK_SET); | ||
443 | |||
444 | for (i=0;i<of.numins;i++) { | ||
445 | /* load sample info */ | ||
446 | _mm_read_UBYTES(s.sampname,32,modreader); | ||
447 | _mm_read_UBYTES(s.filename,12,modreader); | ||
448 | s.ems=_mm_read_UBYTE(modreader); | ||
449 | s.length=_mm_read_I_ULONG(modreader); | ||
450 | s.loopbeg=_mm_read_I_ULONG(modreader); | ||
451 | s.loopend=_mm_read_I_ULONG(modreader); | ||
452 | s.flags=_mm_read_UBYTE(modreader); | ||
453 | s.c4spd=_mm_read_I_UWORD(modreader); | ||
454 | s.vol=_mm_read_UBYTE(modreader); | ||
455 | s.pan=_mm_read_UBYTE(modreader); | ||
456 | |||
457 | if (_mm_eof(modreader)) { | ||
458 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
459 | return 0; | ||
460 | } | ||
461 | q->samplename=DupStr(s.sampname,32,0); | ||
462 | q->speed=s.c4spd; | ||
463 | q->length=s.length; | ||
464 | q->loopstart=s.loopbeg; | ||
465 | q->loopend=s.loopend; | ||
466 | q->volume=s.vol; | ||
467 | q->panning=s.pan; | ||
468 | q->seekpos=position; | ||
469 | |||
470 | position +=s.length; | ||
471 | |||
472 | if (s.flags&1) | ||
473 | q->flags |=SF_LOOP; | ||
474 | if (s.flags&2) | ||
475 | q->flags |=SF_16BITS; | ||
476 | if (s.flags&16) | ||
477 | q->flags |=SF_STEREO; | ||
478 | q++; | ||
479 | } | ||
480 | |||
481 | /* set the panning */ | ||
482 | for (i=x=0;i<32;i++) { | ||
483 | of.panning[i]=mh->pantable[i]; | ||
484 | if (!of.panning[i]) | ||
485 | of.panning[i]=PAN_LEFT; | ||
486 | else if (of.panning[i]==8) | ||
487 | of.panning[i]=PAN_CENTER; | ||
488 | else if (of.panning[i]==15) | ||
489 | of.panning[i]=PAN_RIGHT; | ||
490 | else if (of.panning[i]==16) | ||
491 | of.panning[i]=PAN_SURROUND; | ||
492 | else if (of.panning[i]==255) | ||
493 | of.panning[i]=128; | ||
494 | else | ||
495 | of.panning[i]<<=3; | ||
496 | if (mh->pantable[i]!=255) | ||
497 | x=i; | ||
498 | } | ||
499 | |||
500 | of.numchn=x+1; | ||
501 | if (of.numchn<1) | ||
502 | of.numchn=1; /* for broken counts */ | ||
503 | |||
504 | /* load the pattern info */ | ||
505 | of.numtrk=of.numpat*of.numchn; | ||
506 | |||
507 | /* jump to patterns */ | ||
508 | _mm_fseek(modreader,mh->patternloc,SEEK_SET); | ||
509 | |||
510 | if (!AllocTracks()) { | ||
511 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | if (!AllocPatterns()) { | ||
516 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | for (i=track=0;i<of.numpat;i++) { | ||
521 | if (!GDM_ReadPattern()) { | ||
522 | _mm_errno=MMERR_LOADING_PATTERN; | ||
523 | return 0; | ||
524 | } | ||
525 | for (u=0;u<of.numchn;u++,track++) { | ||
526 | of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]); | ||
527 | if (!of.tracks[track]) { | ||
528 | _mm_errno=MMERR_LOADING_TRACK; | ||
529 | return 0; | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | return 1; | ||
534 | } | ||
535 | |||
536 | CHAR *GDM_LoadTitle(void) | ||
537 | { | ||
538 | CHAR s[32]; | ||
539 | |||
540 | _mm_fseek(modreader,4,SEEK_SET); | ||
541 | if (!_mm_read_UBYTES(s,32,modreader)) return NULL; | ||
542 | |||
543 | return DupStr(s,28,0); | ||
544 | } | ||
545 | |||
546 | MIKMODAPI MLOADER load_gdm= | ||
547 | { | ||
548 | NULL, | ||
549 | "GDM", | ||
550 | "GDM (General DigiMusic)", | ||
551 | GDM_Init, | ||
552 | GDM_Test, | ||
553 | GDM_Load, | ||
554 | GDM_Cleanup, | ||
555 | GDM_LoadTitle | ||
556 | }; | ||
557 | |||
558 | /* ex:set ts=4: */ | ||