A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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$
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
54extern int fprintf(FILE *, const char *, ...);
55#endif
56
57typedef struct GDMNOTE {
58 UBYTE note;
59 UBYTE samp;
60 struct {
61 UBYTE effect;
62 UBYTE param;
63 } effect[4];
64} GDMNOTE;
65
66typedef GDMNOTE GDMTRACK[64];
67
68typedef 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
101typedef 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
114static GDMHEADER *mh=NULL; /* pointer to GDM header */
115static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */
116
117static CHAR GDM_Version[]="General DigiMusic 1.xx";
118
119static 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
137static 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
145static void GDM_Cleanup(void)
146{
147 MikMod_free(mh);
148 MikMod_free(gdmbuf);
149 mh=NULL;
150 gdmbuf=NULL;
151}
152
153static int GDM_ReadPattern(void)
154{
155 int pos,flag,ch,i;
156 GDMNOTE n;
157 SLONG length,x=0;
158
159 /* get pattern length */
160 length=(SLONG)_mm_read_I_UWORD(modreader);
161 length-=2;
162
163 /* clear pattern data */
164 memset(gdmbuf,255,32*64*sizeof(GDMNOTE));
165 pos=0;
166
167 while (x<length) {
168 memset(&n,255,sizeof(GDMNOTE));
169 flag=_mm_read_UBYTE(modreader);
170 x++;
171
172 if (_mm_eof(modreader))
173 return 0;
174
175 ch=flag&31;
176 if (ch > of.numchn)
177 return 0;
178
179 if (!flag) {
180 pos++;
181 if (x==length) {
182 if (pos > 64)
183 return 0;
184 } else {
185 if (pos >= 64)
186 return 0;
187 }
188 continue;
189 }
190 if (flag&0x60) {
191 if (flag&0x20) {
192 /* new note */
193 n.note=_mm_read_UBYTE(modreader)&127;
194 n.samp=_mm_read_UBYTE(modreader);
195 x +=2;
196 }
197 if (flag&0x40) {
198 do {
199 /* effect channel set */
200 i=_mm_read_UBYTE(modreader);
201 n.effect[i>>6].effect=i&31;
202 n.effect[i>>6].param=_mm_read_UBYTE(modreader);
203 x +=2;
204 } while (i&32);
205 }
206 memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE));
207 }
208 }
209 return 1;
210}
211
212static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
213{
214 int t,i=0;
215 UBYTE note,ins,inf;
216
217 UniReset();
218 for (t=0;t<64;t++) {
219 note=tr[t].note;
220 ins=tr[t].samp;
221
222 if ((ins)&&(ins!=255))
223 UniInstrument(ins-1);
224 if (note && note!=255) {
225 UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
226 }
227 for (i=0;i<4;i++) {
228 inf = tr[t].effect[i].param;
229 switch (tr[t].effect[i].effect) {
230 case 1: /* toneslide up */
231 UniEffect(UNI_S3MEFFECTF,inf);
232 break;
233 case 2: /* toneslide down */
234 UniEffect(UNI_S3MEFFECTE,inf);
235 break;
236 case 3: /* glissando to note */
237 UniEffect(UNI_ITEFFECTG,inf);
238 break;
239 case 4: /* vibrato */
240 UniEffect(UNI_GDMEFFECT4,inf);
241 break;
242 case 5: /* portamento+volslide */
243 UniEffect(UNI_ITEFFECTG,0);
244 UniEffect(UNI_S3MEFFECTD,inf);
245 break;
246 case 6: /* vibrato+volslide */
247 UniEffect(UNI_GDMEFFECT4,0);
248 UniEffect(UNI_S3MEFFECTD,inf);
249 break;
250 case 7: /* tremolo */
251 UniEffect(UNI_GDMEFFECT7,inf);
252 break;
253 case 8: /* tremor */
254 UniEffect(UNI_S3MEFFECTI,inf);
255 break;
256 case 9: /* offset */
257 UniPTEffect(0x09,inf);
258 break;
259 case 0x0a: /* volslide */
260 UniEffect(UNI_S3MEFFECTD,inf);
261 break;
262 case 0x0b: /* jump to order */
263 UniPTEffect(0x0b,inf);
264 break;
265 case 0x0c: /* volume set */
266 UniPTEffect(0x0c,inf);
267 break;
268 case 0x0d: /* pattern break */
269 UniPTEffect(0x0d,inf);
270 break;
271 case 0x0e: /* extended */
272 switch (inf&0xf0) {
273 case 0x10: /* fine portamento up */
274 UniEffect(UNI_S3MEFFECTF, 0xf0|(inf&0x0f));
275 break;
276 case 0x20: /* fine portamento down */
277 UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
278 break;
279 case 0x30: /* glissando control */
280 case 0x40: /* vibrato waveform */
281 case 0x50: /* set c4spd */
282 case 0x60: /* loop fun */
283 case 0x70: /* tremolo waveform */
284 UniPTEffect(0xe, inf);
285 break;
286 case 0x80: /* extra fine porta up */
287 UniEffect(UNI_S3MEFFECTF, 0xe0|(inf&0x0f));
288 break;
289 case 0x90: /* extra fine porta down */
290 UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
291 break;
292 case 0xa0: /* fine volslide up */
293 UniEffect(UNI_S3MEFFECTD, 0x0f|((inf&0x0f)<<4));
294 break;
295 case 0xb0: /* fine volslide down */
296 UniEffect(UNI_S3MEFFECTD, 0xf0|(inf&0x0f));
297 break;
298 case 0xc0: /* note cut */
299 case 0xd0: /* note delay */
300 case 0xe0: /* extend row */
301 UniPTEffect(0xe,inf);
302 break;
303 }
304 break;
305 case 0x0f: /* set tempo */
306 UniEffect(UNI_S3MEFFECTA,inf);
307 break;
308 case 0x10: /* arpeggio */
309 UniPTEffect(0x0,inf);
310 break;
311 case 0x12: /* retrigger */
312 UniEffect(UNI_S3MEFFECTQ,inf);
313 break;
314 case 0x13: /* set global volume */
315 UniEffect(UNI_XMEFFECTG,inf);
316 break;
317 case 0x14: /* fine vibrato */
318 UniEffect(UNI_GDMEFFECT14,inf);
319 break;
320 case 0x1e: /* special */
321 switch (inf&0xf0) {
322 case 0x80: /* set pan position */
323 UniPTEffect(0xe,inf);
324 break;
325 }
326 break;
327 case 0x1f: /* set bpm */
328 if (inf >=0x20)
329 UniEffect(UNI_S3MEFFECTT,inf);
330 break;
331 }
332 }
333 UniNewline();
334 }
335 return UniDup();
336}
337
338static int GDM_Load(int curious)
339{
340 int i,x,u,track;
341 SAMPLE *q;
342 GDMSAMPLE s;
343 ULONG position;
344 (void)curious;
345
346 /* read header */
347 _mm_read_string(mh->id1,4,modreader);
348 _mm_read_string(mh->songname,32,modreader);
349 _mm_read_string(mh->author,32,modreader);
350 _mm_read_string(mh->eofmarker,3,modreader);
351 _mm_read_string(mh->id2,4,modreader);
352
353 mh->majorver=_mm_read_UBYTE(modreader);
354 mh->minorver=_mm_read_UBYTE(modreader);
355 mh->trackerid=_mm_read_I_UWORD(modreader);
356 mh->t_majorver=_mm_read_UBYTE(modreader);
357 mh->t_minorver=_mm_read_UBYTE(modreader);
358 _mm_read_UBYTES(mh->pantable,32,modreader);
359 mh->mastervol=_mm_read_UBYTE(modreader);
360 mh->mastertempo=_mm_read_UBYTE(modreader);
361 mh->masterbpm=_mm_read_UBYTE(modreader);
362 mh->flags=_mm_read_I_UWORD(modreader);
363
364 mh->orderloc=_mm_read_I_ULONG(modreader);
365 mh->ordernum=_mm_read_UBYTE(modreader);
366 mh->patternloc=_mm_read_I_ULONG(modreader);
367 mh->patternnum=_mm_read_UBYTE(modreader);
368 mh->samhead=_mm_read_I_ULONG(modreader);
369 mh->samdata=_mm_read_I_ULONG(modreader);
370 mh->samnum=_mm_read_UBYTE(modreader);
371 mh->messageloc=_mm_read_I_ULONG(modreader);
372 mh->messagelen=_mm_read_I_ULONG(modreader);
373 mh->scrollyloc=_mm_read_I_ULONG(modreader);
374 mh->scrollylen=_mm_read_I_UWORD(modreader);
375 mh->graphicloc=_mm_read_I_ULONG(modreader);
376 mh->graphiclen=_mm_read_I_UWORD(modreader);
377
378 /* have we ended abruptly? */
379 if (_mm_eof(modreader)) {
380 _mm_errno=MMERR_LOADING_HEADER;
381 return 0;
382 }
383
384 /* any orders? */
385 if(mh->ordernum==255) {
386 _mm_errno=MMERR_LOADING_PATTERN;
387 return 0;
388 }
389
390 /* now we fill */
391 of.modtype=MikMod_strdup(GDM_Version);
392 of.modtype[18]=mh->majorver+'0';
393 of.modtype[20]=mh->minorver/10+'0';
394 of.modtype[21]=mh->minorver%10+'0';
395 of.songname=DupStr(mh->songname,32,0);
396 of.numpat=mh->patternnum+1;
397 of.reppos=0;
398 of.numins=of.numsmp=mh->samnum+1;
399 of.initspeed=mh->mastertempo;
400 of.inittempo=mh->masterbpm;
401 of.initvolume=mh->mastervol<<1;
402 of.flags|=UF_S3MSLIDES | UF_PANNING;
403 /* XXX whenever possible, we should try to determine the original format.
404 Here we assume it was S3M-style wrt bpmlimit... */
405 of.bpmlimit = 32;
406
407 /* read the order data */
408 if (!AllocPositions(mh->ordernum+1)) {
409 _mm_errno=MMERR_OUT_OF_MEMORY;
410 return 0;
411 }
412
413 _mm_fseek(modreader,mh->orderloc,SEEK_SET);
414 for (i=0;i<mh->ordernum+1;i++)
415 of.positions[i]=_mm_read_UBYTE(modreader);
416
417 of.numpos=0;
418 for (i=0;i<mh->ordernum+1;i++) {
419 int order=of.positions[i];
420 if(order==255) order=LAST_PATTERN;
421 of.positions[of.numpos]=order;
422 if (of.positions[i]<254) of.numpos++;
423 }
424
425 /* have we ended abruptly yet? */
426 if (_mm_eof(modreader)) {
427 _mm_errno=MMERR_LOADING_HEADER;
428 return 0;
429 }
430
431 /* time to load the samples */
432 if (!AllocSamples()) {
433 _mm_errno=MMERR_OUT_OF_MEMORY;
434 return 0;
435 }
436
437 q=of.samples;
438 position=mh->samdata;
439
440 /* seek to instrument position */
441 _mm_fseek(modreader,mh->samhead,SEEK_SET);
442
443 for (i=0;i<of.numins;i++) {
444 /* load sample info */
445 _mm_read_UBYTES(s.sampname,32,modreader);
446 _mm_read_UBYTES(s.filename,12,modreader);
447 s.ems=_mm_read_UBYTE(modreader);
448 s.length=_mm_read_I_ULONG(modreader);
449 s.loopbeg=_mm_read_I_ULONG(modreader);
450 s.loopend=_mm_read_I_ULONG(modreader);
451 s.flags=_mm_read_UBYTE(modreader);
452 s.c4spd=_mm_read_I_UWORD(modreader);
453 s.vol=_mm_read_UBYTE(modreader);
454 s.pan=_mm_read_UBYTE(modreader);
455
456 if (_mm_eof(modreader)) {
457 _mm_errno=MMERR_LOADING_SAMPLEINFO;
458 return 0;
459 }
460 q->samplename=DupStr(s.sampname,32,0);
461 q->speed=s.c4spd;
462 q->length=s.length;
463 q->loopstart=s.loopbeg;
464 q->loopend=s.loopend;
465 q->volume=64;
466 q->seekpos=position;
467
468 position +=s.length;
469
470 /* Only use the sample volume byte if bit 2 is set. When bit 3 is set,
471 the sample panning is supposed to be used, but 2GDM isn't capable
472 of making a GDM using this feature; the panning byte is always 0xFF
473 or junk. Likewise, bit 5 is unused (supposed to be LZW compression). */
474 if (s.flags&1)
475 q->flags |=SF_LOOP;
476 if (s.flags&2)
477 q->flags |=SF_16BITS;
478 if ((s.flags&4) && s.vol<=64)
479 q->volume=s.vol;
480 if (s.flags&16)
481 q->flags |=SF_STEREO;
482 q++;
483 }
484
485 /* set the panning */
486 for (i=x=0;i<32;i++) {
487 of.panning[i]=mh->pantable[i];
488 if (!of.panning[i])
489 of.panning[i]=PAN_LEFT;
490 else if (of.panning[i]==8)
491 of.panning[i]=PAN_CENTER;
492 else if (of.panning[i]==15)
493 of.panning[i]=PAN_RIGHT;
494 else if (of.panning[i]==16)
495 of.panning[i]=PAN_SURROUND;
496 else if (of.panning[i]==255)
497 of.panning[i]=128;
498 else
499 of.panning[i]<<=3;
500 if (mh->pantable[i]!=255)
501 x=i;
502 }
503
504 of.numchn=x+1;
505 if (of.numchn<1)
506 of.numchn=1; /* for broken counts */
507
508 /* load the pattern info */
509 of.numtrk=of.numpat*of.numchn;
510
511 /* jump to patterns */
512 _mm_fseek(modreader,mh->patternloc,SEEK_SET);
513
514 if (!AllocTracks()) {
515 _mm_errno=MMERR_OUT_OF_MEMORY;
516 return 0;
517 }
518
519 if (!AllocPatterns()) {
520 _mm_errno=MMERR_OUT_OF_MEMORY;
521 return 0;
522 }
523
524 for (i=track=0;i<of.numpat;i++) {
525 if (!GDM_ReadPattern()) {
526 _mm_errno=MMERR_LOADING_PATTERN;
527 return 0;
528 }
529 for (u=0;u<of.numchn;u++,track++) {
530 of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]);
531 if (!of.tracks[track]) {
532 _mm_errno=MMERR_LOADING_TRACK;
533 return 0;
534 }
535 }
536 }
537 return 1;
538}
539
540static CHAR *GDM_LoadTitle(void)
541{
542 CHAR s[32];
543
544 _mm_fseek(modreader,4,SEEK_SET);
545 if (!_mm_read_UBYTES(s,32,modreader)) return NULL;
546
547 return DupStr(s,28,0);
548}
549
550MIKMODAPI MLOADER load_gdm=
551{
552 NULL,
553 "GDM",
554 "GDM (General DigiMusic)",
555 GDM_Init,
556 GDM_Test,
557 GDM_Load,
558 GDM_Cleanup,
559 GDM_LoadTitle
560};
561
562/* ex:set ts=4: */