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 15 instrument MOD loader
26 Also supports Ultimate Sound Tracker (old M15 format)
27
28==============================================================================*/
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#include <ctype.h>
39#include <stdio.h>
40#ifdef HAVE_MEMORY_H
41#include <memory.h>
42#endif
43#include <string.h>
44
45#include "mikmod_internals.h"
46
47#ifdef SUNOS
48extern int fprintf(FILE *, const char *, ...);
49#endif
50
51/*========== Module Structure */
52
53typedef struct MSAMPINFO {
54 CHAR samplename[23]; /* 22 in module, 23 in memory */
55 UWORD length;
56 UBYTE finetune;
57 UBYTE volume;
58 UWORD reppos;
59 UWORD replen;
60} MSAMPINFO;
61
62typedef struct MODULEHEADER {
63 CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */
64 MSAMPINFO samples[15]; /* all sampleinfo */
65 UBYTE songlength; /* number of patterns used */
66 UBYTE magic1; /* should be 127 */
67 UBYTE positions[128]; /* which pattern to play at pos */
68} MODULEHEADER;
69
70typedef struct MODNOTE {
71 UBYTE a,b,c,d;
72} MODNOTE;
73
74/*========== Loader variables */
75
76static MODULEHEADER *mh = NULL;
77static MODNOTE *patbuf = NULL;
78static int ust_loader = 0; /* if TRUE, load as an ust module. */
79
80/* known file formats which can confuse the loader */
81#define REJECT 2
82static const char *signatures[REJECT]={
83 "CAKEWALK", /* cakewalk midi files */
84 "SZDD" /* Microsoft compressed files */
85};
86static const int siglen[REJECT]={8,4};
87
88/*========== Loader code */
89
90static int LoadModuleHeader(MODULEHEADER *h)
91{
92 int t,u;
93
94 _mm_read_string(h->songname,20,modreader);
95
96 /* sanity check : title should contain printable characters and a bunch
97 of null chars */
98 for(t=0;t<20;t++)
99 if((h->songname[t])&&(h->songname[t]<32)) return 0;
100 for(t=0;(h->songname[t])&&(t<20);t++);
101 if(t<20) for(;t<20;t++) if(h->songname[t]) return 0;
102
103 for(t=0;t<15;t++) {
104 MSAMPINFO *s=&h->samples[t];
105
106 _mm_read_string(s->samplename,22,modreader);
107 s->length =_mm_read_M_UWORD(modreader);
108 s->finetune =_mm_read_UBYTE(modreader);
109 s->volume =_mm_read_UBYTE(modreader);
110 s->reppos =_mm_read_M_UWORD(modreader);
111 s->replen =_mm_read_M_UWORD(modreader);
112
113 /* sanity check : sample title should contain printable characters and
114 a bunch of null chars */
115 for(u=0;u<20;u++)
116 if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0;
117 for(u=0;(s->samplename[u])&&(u<20);u++);
118 if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0;
119
120 /* sanity check : finetune values */
121 if(s->finetune>>4) return 0;
122 }
123
124 h->songlength =_mm_read_UBYTE(modreader);
125 h->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */
126
127 /* sanity check : no more than 128 positions, restart position in range */
128 if((!h->songlength)||(h->songlength>128)) return 0;
129 /* values encountered so far are 0x6a and 0x78 */
130 if(((h->magic1&0xf8)!=0x78)&&(h->magic1!=0x6a)&&(h->magic1>h->songlength)) return 0;
131
132 _mm_read_UBYTES(h->positions,128,modreader);
133
134 /* sanity check : pattern range is 0..63 */
135 for(t=0;t<128;t++)
136 if(h->positions[t]>63) return 0;
137
138 return(!_mm_eof(modreader));
139}
140
141/* Checks the patterns in the modfile for UST / 15-inst indications.
142 For example, if an effect 3xx is found, it is assumed that the song
143 is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST.
144
145 Returns: 0 indecisive; 1 = UST; 2 = 15-inst */
146static int CheckPatternType(int numpat)
147{
148 unsigned int t;
149 UBYTE eff, dat;
150
151 for(t=0;t<numpat*(64U*4);t++) {
152 /* Load the pattern into the temp buffer and scan it */
153 _mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader);
154 eff = _mm_read_UBYTE(modreader);
155 dat = _mm_read_UBYTE(modreader);
156
157 switch(eff) {
158 case 1:
159 if(dat>0x1f) return 1;
160 if(dat<0x3) return 2;
161 break;
162 case 2:
163 if(dat>0x1f) return 1;
164 return 2;
165 case 3:
166 if (dat) return 2;
167 break;
168 default:
169 return 2;
170 }
171 }
172 return 0;
173}
174
175static int M15_Test(void)
176{
177 int t, numpat;
178 MODULEHEADER h;
179
180 ust_loader = 0;
181 memset(&h, 0, sizeof(MODULEHEADER));
182 if(!LoadModuleHeader(&h)) return 0;
183
184 /* reject other file types */
185 for(t=0;t<REJECT;t++)
186 if(!memcmp(h.songname,signatures[t],siglen[t])) return 0;
187
188 if(h.magic1>127) return 0;
189 if((!h.songlength)||(h.songlength>h.magic1)) return 0;
190
191 for(t=0;t<15;t++) {
192 /* all finetunes should be zero */
193 if(h.samples[t].finetune) return 0;
194
195 /* all volumes should be <= 64 */
196 if(h.samples[t].volume>64) return 0;
197
198 /* all instrument names should begin with s, st-, or a number */
199 if((h.samples[t].samplename[0]=='s')||
200 (h.samples[t].samplename[0]=='S')) {
201 if((memcmp(h.samples[t].samplename,"st-",3)) &&
202 (memcmp(h.samples[t].samplename,"ST-",3)) &&
203 (*h.samples[t].samplename))
204 ust_loader = 1;
205 } else
206 if(!isdigit((int)h.samples[t].samplename[0]))
207 ust_loader = 1;
208
209 if(h.samples[t].length>4999||h.samples[t].reppos>9999) {
210 ust_loader = 0;
211 if(h.samples[t].length>32768) return 0;
212 }
213
214 /* if loop information is incorrect as words, but correct as bytes,
215 this is likely to be an ust-style module */
216 if((h.samples[t].reppos+h.samples[t].replen>h.samples[t].length)&&
217 (h.samples[t].reppos+h.samples[t].replen<(h.samples[t].length<<1))) {
218 ust_loader = 1;
219 return 1;
220 }
221
222 if(!ust_loader) return 1;
223 }
224
225 for(numpat=0,t=0;t<h.songlength;t++)
226 if(h.positions[t]>numpat)
227 numpat = h.positions[t];
228 numpat++;
229 switch(CheckPatternType(numpat)) {
230 case 0: /* indecisive, so check more clues... */
231 break;
232 case 1:
233 ust_loader = 1;
234 break;
235 case 2:
236 ust_loader = 0;
237 break;
238 }
239 return 1;
240}
241
242static int M15_Init(void)
243{
244 if(!(mh=(MODULEHEADER*)MikMod_calloc(1,sizeof(MODULEHEADER)))) return 0;
245 return 1;
246}
247
248static void M15_Cleanup(void)
249{
250 MikMod_free(mh);
251 MikMod_free(patbuf);
252 mh=NULL;
253 patbuf=NULL;
254}
255
256/*
257Old (amiga) noteinfo:
258
259 _____byte 1_____ byte2_ _____byte 3_____ byte4_
260/ \ / \ / \ / \
2610000 0000-00000000 0000 0000-00000000
262
263Upper four 12 bits for Lower four Effect command.
264bits of sam- note period. bits of sam-
265ple number. ple number.
266*/
267
268static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect)
269{
270 UBYTE instrument,effect,effdat,note;
271 UWORD period;
272 UBYTE lastnote=0;
273
274 /* decode the 4 bytes that make up a single note */
275 instrument = n->c>>4;
276 period = (((UWORD)n->a&0xf)<<8)+n->b;
277 effect = n->c&0xf;
278 effdat = n->d;
279
280 /* Convert the period to a note number */
281 note=0;
282 if(period) {
283 for(note=0;note<7*OCTAVE;note++)
284 if(period>=npertab[note]) break;
285 if(note==7*OCTAVE) note=0;
286 else note++;
287 }
288
289 if(instrument) {
290 /* if instrument does not exist, note cut */
291 if((instrument>15)||(!mh->samples[instrument-1].length)) {
292 UniPTEffect(0xc,0);
293 if(effect==0xc) effect=effdat=0;
294 } else {
295 /* if we had a note, then change instrument... */
296 if(note)
297 UniInstrument(instrument-1);
298 /* ...otherwise, only adjust volume... */
299 else {
300 /* ...unless an effect was specified, which forces a new note
301 to be played */
302 if(effect||effdat) {
303 UniInstrument(instrument-1);
304 note=lastnote;
305 } else
306 UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f);
307 }
308 }
309 }
310 if(note) {
311 UniNote(note+2*OCTAVE-1);
312 lastnote=note;
313 }
314
315 /* Convert pattern jump from Dec to Hex */
316 if(effect == 0xd)
317 effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);
318
319 /* Volume slide, up has priority */
320 if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0))
321 effdat&=0xf0;
322
323 /* Handle ``heavy'' volumes correctly */
324 if ((effect == 0xc) && (effdat > 0x40))
325 effdat = 0x40;
326
327 if(ust_loader) {
328 switch(effect) {
329 case 0:
330 case 3:
331 break;
332 case 1:
333 UniPTEffect(0,effdat);
334 break;
335 case 2:
336 if(effdat&0xf) UniPTEffect(1,effdat&0xf);
337 else if(effdat>>2) UniPTEffect(2,effdat>>2);
338 break;
339 default:
340 UniPTEffect(effect,effdat);
341 break;
342 }
343 } else {
344 /* An isolated 100, 200 or 300 effect should be ignored (no
345 "standalone" porta memory in mod files). However, a sequence
346 such as 1XX, 100, 100, 100 is fine. */
347 if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
348 (lasteffect < 0x10) && (effect != lasteffect))
349 effect = 0;
350
351 UniPTEffect(effect,effdat);
352 }
353 if (effect == 8)
354 of.flags |= UF_PANNING;
355
356 return effect;
357}
358
359static UBYTE *M15_ConvertTrack(MODNOTE* n)
360{
361 int t;
362 UBYTE lasteffect = 0x10; /* non existant effect */
363
364 UniReset();
365 for(t=0;t<64;t++) {
366 lasteffect = M15_ConvertNote(n,lasteffect);
367 UniNewline();
368 n+=4;
369 }
370 return UniDup();
371}
372
373/* Loads all patterns of a modfile and converts them into the 3 byte format. */
374static int M15_LoadPatterns(void)
375{
376 unsigned int t,s,tracks=0;
377
378 if(!AllocPatterns()) return 0;
379 if(!AllocTracks()) return 0;
380
381 /* Allocate temporary buffer for loading and converting the patterns */
382 if(!(patbuf=(MODNOTE*)MikMod_calloc(64U*4,sizeof(MODNOTE)))) return 0;
383
384 for(t=0;t<of.numpat;t++) {
385 /* Load the pattern into the temp buffer and convert it */
386 for(s=0;s<(64U*4);s++) {
387 patbuf[s].a=_mm_read_UBYTE(modreader);
388 patbuf[s].b=_mm_read_UBYTE(modreader);
389 patbuf[s].c=_mm_read_UBYTE(modreader);
390 patbuf[s].d=_mm_read_UBYTE(modreader);
391 }
392
393 for(s=0;s<4;s++)
394 if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
395 }
396 return 1;
397}
398
399static int M15_Load(int curious)
400{
401 unsigned int t,scan;
402 SAMPLE *q;
403 MSAMPINFO *s;
404 (void)curious;
405
406 /* try to read module header */
407 if(!LoadModuleHeader(mh)) {
408 _mm_errno = MMERR_LOADING_HEADER;
409 return 0;
410 }
411
412 if(ust_loader)
413 of.modtype = MikMod_strdup("Ultimate Soundtracker");
414 else
415 of.modtype = MikMod_strdup("Soundtracker");
416
417 /* set module variables */
418 of.initspeed = 6;
419 of.inittempo = 125;
420 of.numchn = 4;
421 of.songname = DupStr(mh->songname,21,1);
422 of.numpos = mh->songlength;
423 of.reppos = 0;
424
425 /* Count the number of patterns */
426 of.numpat = 0;
427 for(t=0;t<of.numpos;t++)
428 if(mh->positions[t]>of.numpat)
429 of.numpat=mh->positions[t];
430 /* since some old modules embed extra patterns, we have to check the
431 whole list to get the samples' file offsets right - however we can find
432 garbage here, so check carefully */
433 scan=1;
434 for(t=of.numpos;t<128;t++)
435 if(mh->positions[t]>=0x80) scan=0;
436 if (scan)
437 for(t=of.numpos;t<128;t++) {
438 if(mh->positions[t]>of.numpat)
439 of.numpat=mh->positions[t];
440 if((curious)&&(mh->positions[t])) of.numpos=t+1;
441 }
442 of.numpat++;
443 of.numtrk = of.numpat*of.numchn;
444
445 if(!AllocPositions(of.numpos)) return 0;
446 for(t=0;t<of.numpos;t++)
447 of.positions[t]=mh->positions[t];
448
449 /* Finally, init the sampleinfo structures */
450 of.numins=of.numsmp=15;
451 if(!AllocSamples()) return 0;
452
453 s = mh->samples;
454 q = of.samples;
455
456 for(t=0;t<of.numins;t++) {
457 /* convert the samplename */
458 q->samplename = DupStr(s->samplename,23,1);
459
460 /* init the sampleinfo variables and convert the size pointers */
461 q->speed = finetune[s->finetune&0xf];
462 q->volume = s->volume;
463 if(ust_loader)
464 q->loopstart = s->reppos;
465 else
466 q->loopstart = s->reppos<<1;
467 q->loopend = q->loopstart+(s->replen<<1);
468 q->length = s->length<<1;
469
470 q->flags = SF_SIGNED;
471 if(ust_loader) q->flags |= SF_UST_LOOP;
472 if(s->replen>2) q->flags |= SF_LOOP;
473
474 s++;
475 q++;
476 }
477
478 if(!M15_LoadPatterns()) return 0;
479 ust_loader = 0;
480
481 return 1;
482}
483
484static CHAR *M15_LoadTitle(void)
485{
486 CHAR s[21];
487
488 _mm_fseek(modreader,0,SEEK_SET);
489 if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
490 s[20]=0; /* just in case */
491 return(DupStr(s,21,1));
492}
493
494/*========== Loader information */
495
496MIKMODAPI MLOADER load_m15={
497 NULL,
498 "15-instrument module",
499 "MOD (15 instrument)",
500 M15_Init,
501 M15_Test,
502 M15_Load,
503 M15_Cleanup,
504 M15_LoadTitle
505};
506
507/* ex:set ts=4: */