1 //---------------------------------------------------------------------------\\
3 // lft's musicchip song format
4 //---------------------------------------------------------------------------//
11 #include "filetypes.h"
12 #include "hvl_replay.h"
15 volatile u8 callbackwait
;
16 u8 callbacktime
= 180;
22 /*const u16 freqtable[] = {
23 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
24 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
25 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
26 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
27 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
28 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
29 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
30 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
31 0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
32 0x70a3, 0x7756, 0x7e6f
36 /*const u16 freqtable[] = {
37 0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
38 0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
39 0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
40 0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
41 0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
42 0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
43 0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
44 0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
45 0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
46 0x3851, 0x3bab, 0x3f37
50 const u16 freqtable
[] = {
51 0x002c, 0x002f, 0x0032, 0x0035, 0x0038, 0x003b, 0x003f, 0x0042, 0x0046,
52 0x004b, 0x004f, 0x0054, 0x0059, 0x005e, 0x0064, 0x006a, 0x0070, 0x0077,
53 0x007e, 0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8,
54 0x00d4, 0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151,
55 0x0165, 0x017a, 0x0190, 0x01a8, 0x01c2, 0x01dc, 0x01f9, 0x0217, 0x0237,
56 0x0258, 0x027c, 0x02a2, 0x02ca, 0x02f4, 0x0321, 0x0351, 0x0384, 0x03b9,
57 0x03f2, 0x042e, 0x046e, 0x04b1, 0x04f8, 0x0544, 0x0594, 0x05e9, 0x0643,
58 0x06a3, 0x0708, 0x0773, 0x07e4, 0x085c, 0x08dc, 0x0962, 0x09f1, 0x0a89,
59 0x0b29, 0x0bd3, 0x0c87, 0x0d46, 0x0e10, 0x0ee6, 0x0fc9, 0x10b9, 0x11b8,
60 0x12c5, 0x13e3, 0x1512
63 const s8 sinetable
[] = {
64 0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
65 127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
66 0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
67 -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
68 -71, -60, -49, -37, -25, -12
91 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
92 \\\
< void readtrack(int,int,trackline
) > .\
93 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
94 void readtrack(int num
, int pos
, struct trackline
*tl
){
95 tl
->note
= tune
->trk
[num
].line
[pos
].note
;
96 tl
->instr
= tune
->trk
[num
].line
[pos
].instr
;
97 tl
->cmd
[0] = tune
->trk
[num
].line
[pos
].cmd
[0];
98 tl
->cmd
[1] = tune
->trk
[num
].line
[pos
].cmd
[1];
99 tl
->param
[0] = tune
->trk
[num
].line
[pos
].param
[0];
100 tl
->param
[1] = tune
->trk
[num
].line
[pos
].param
[1];
103 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
104 \\\
< void runcmd(u8
,u8
,u8
) > .|
105 /// Executes a song command. .\
106 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
107 void runcmd(u8 ch
, u8 cmd
, u8 param
){
110 channel
[ch
].inum
= 0;
113 osc
[ch
].duty
= param
<< 8;
116 channel
[ch
].volumed
= param
;
119 channel
[ch
].inertia
= param
<< 1;
122 channel
[ch
].iptr
= param
;
125 channel
[ch
].bendd
= param
;
128 channel
[ch
].dutyd
= param
<< 6;
131 channel
[ch
].iwait
= (param
*6);
134 osc
[ch
].volume
= param
;
137 osc
[ch
].waveform
= param
;
140 channel
[ch
].inote
= param
+ channel
[ch
].tnote
- 12 * 4;
143 channel
[ch
].inote
= param
;
146 if(channel
[ch
].vdepth
!= (param
>> 4)){
147 channel
[ch
].vpos
= 0;
149 channel
[ch
].vdepth
= param
>> 4;
150 channel
[ch
].vrate
= (param
/2) & 0xf;
151 //channel[ch].vrate = param & 0xf;
154 callbacktime
= -param
;
159 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
160 \\\
< void silence() > .|
161 /// Stops all sound. .\
162 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
164 for(u8 i
= 0; i
< 4; i
++){
171 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
172 \\\
< void lft_iedplonk(int,int) > .|
174 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
175 void lft_iedplonk(int note
, int instr
, pineapple_tune
*t
){
176 channel
[0].tnote
= note
;
177 channel
[0].inum
= instr
;
179 channel
[0].iwait
= 0;
181 channel
[0].bendd
= 0;
182 channel
[0].volumed
= 0;
183 channel
[0].dutyd
= 0;
184 channel
[0].vdepth
= 0;
187 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
188 \\\
< void startplaytrack(int) > .|
189 /// Plays a track. .\
190 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
191 void startplaytrack(int t
){
202 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
203 \\\
< void startplaysong(int) > .|
204 /// Plays the song from a certain position. .\
205 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
206 void startplaysong(int p
){
214 void playroutine(){ // called at 50 Hz
217 if(playtrack
|| playsong
){
226 if(tune
->songpos
>= tune
->songlen
){
229 for(ch
= 0; ch
< 4; ch
++){
232 readsong(tune
->songpos
, ch
, tmp
);
233 channel
[ch
].tnum
= tmp
[0];
234 channel
[ch
].transp
= tmp
[1];
241 if(playtrack
|| playsong
){
242 for(ch
= 0; ch
< 4; ch
++){
243 if(channel
[ch
].tnum
){
247 readtrack(channel
[ch
].tnum
, trackpos
, &tl
);
249 channel
[ch
].tnote
= tl
.note
+ channel
[ch
].transp
;
250 instr
= channel
[ch
].lastinstr
;
256 channel
[ch
].lastinstr
= instr
;
257 channel
[ch
].inum
= instr
;
258 channel
[ch
].iptr
= 0;
259 channel
[ch
].iwait
= 0;
260 channel
[ch
].bend
= 0;
261 channel
[ch
].bendd
= 0;
262 channel
[ch
].volumed
= 0;
263 channel
[ch
].dutyd
= 0;
264 channel
[ch
].vdepth
= 0;
267 runcmd(ch
, tl
.cmd
[0], tl
.param
[0]);
269 runcmd(ch
, tl
.cmd
[1], tl
.param
[1]);
279 for(ch
= 0; ch
< 4; ch
++){
284 // i dunno if that last condition is correct...........................
285 while((channel
[ch
].inum
&& !channel
[ch
].iwait
) || channel
[0].iptr
== 0){
288 readinstr(channel
[ch
].inum
, channel
[ch
].iptr
, il
);
291 runcmd(ch
, il
[0], il
[1]);
293 if(channel
[ch
].iwait
) channel
[ch
].iwait
--;
295 if(channel
[ch
].inertia
){
298 slur
= channel
[ch
].slur
;
299 diff
= freqtable
[channel
[ch
].inote
] - slur
;
300 //diff >>= channel[ch].inertia;
302 if(diff
> channel
[ch
].inertia
) diff
= channel
[ch
].inertia
;
304 if(diff
< -channel
[ch
].inertia
) diff
= -channel
[ch
].inertia
;
307 channel
[ch
].slur
= slur
;
309 slur
= freqtable
[channel
[ch
].inote
];
314 ((channel
[ch
].vdepth
* sinetable
[channel
[ch
].vpos
& 63]) >> 2);
315 channel
[ch
].bend
+= channel
[ch
].bendd
;
316 vol
= osc
[ch
].volume
+ channel
[ch
].volumed
;
318 if(vol
> 255) vol
= 255;
319 osc
[ch
].volume
= vol
;
321 duty
= osc
[ch
].duty
+ channel
[ch
].dutyd
;
322 if(duty
> 0xe000) duty
= 0x2000;
323 if(duty
< 0x2000) duty
= 0xe000;
326 channel
[ch
].vpos
+= channel
[ch
].vrate
;
330 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
331 \\\
< void initchip() > .|
332 /// Initialize sound engine. .\
333 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
350 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
351 \\\
< void interrupthandler(int,int) > .|
352 /// Called by sdl_callbackbuffer. Computes a frame of audio. .\
353 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
354 u8
interrupthandler() // called at 9000 Hz
359 static u32 noiseseed
= 1;
362 if(noiseseed
& 0x80000000L
) newbit
^= 1;
363 if(noiseseed
& 0x01000000L
) newbit
^= 1;
364 if(noiseseed
& 0x00000040L
) newbit
^= 1;
365 if(noiseseed
& 0x00000200L
) newbit
^= 1;
366 noiseseed
= (noiseseed
<< 1) | newbit
;
372 callbackwait
= callbacktime
- 1;
376 for(i
= 0; i
< 4; i
++){
377 s8 value
; // [-32,31]
379 switch(osc
[i
].waveform
){
381 if(osc
[i
].phase
< 0x8000){
382 value
= -32 + (osc
[i
].phase
>> 9);
384 value
= 31 - ((osc
[i
].phase
- 0x8000) >> 9);
388 value
= -32 + (osc
[i
].phase
>> 10);
391 value
= (osc
[i
].phase
> osc
[i
].duty
)? -32 : 31;
394 value
= (noiseseed
& 63) - 32;
397 value
= sinetable
[j
];
398 if(j
>= sizeof(sinetable
)-1) j
= 0;
405 osc
[i
].phase
+= osc
[i
].freq
;
407 acc
+= value
* osc
[i
].volume
; // rhs = [-8160,7905]
410 // acc [-32640,31620]
411 return 128 + (acc
>> 8); // [1,251]
415 //--------------------------------------------------------------------------\\
417 //--------------------------------------------------------------------------//
419 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
420 \\\
< void lft_savefile(char *fname
) > .|
421 /// Save the currently loaded lft tune. .\
422 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
423 void lft_savefile(char *fname
){
427 f
= fopen(fname
, "w");
429 fprintf(stderr
, "save error!\n");
433 fprintf(f
, "musicchip tune\n");
434 fprintf(f
, "version 1\n");
436 fprintf(f
, "%s\n", filename
);
438 fprintf(f
, "#%s\n", comment
);
440 fprintf(f
, "tempo: %d\n", callbacktime
);
441 for(i
= 0; i
< tune
->songlen
; i
++){
442 fprintf(f
, "songline %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
444 tune
->sng
[i
].track
[0],
445 tune
->sng
[i
].transp
[0],
446 tune
->sng
[i
].track
[1],
447 tune
->sng
[i
].transp
[1],
448 tune
->sng
[i
].track
[2],
449 tune
->sng
[i
].transp
[2],
450 tune
->sng
[i
].track
[3],
451 tune
->sng
[i
].transp
[3]);
454 for(i
= 1; i
< 256; i
++){
455 for(j
= 0; j
< tune
->tracklen
; j
++){
456 struct trackline
*tl
= &tune
->trk
[i
].line
[j
];
458 if(tl
->note
|| tl
->instr
|| tl
->cmd
[0] || tl
->cmd
[1]){
459 fprintf(f
, "trackline %02x %02x %02x %02x %02x %02x %02x %02x\n",
472 for(i
= 1; i
< 256; i
++){
473 if(instrument
[i
].length
> 1){
474 for(j
= 0; j
< instrument
[i
].length
; j
++){
475 fprintf(f
, "instrumentline %02x %02x %02x %02x\n",
478 instrument
[i
].line
[j
].cmd
,
479 instrument
[i
].line
[j
].param
);
487 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
488 \\\
< pineapple_tune
*lft_loadfile(char *) > .|
489 /// Takes a filename. Returns a pineapple_tune struct. NULL on failure .\
490 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
491 pineapple_tune
*lft_loadfile(char *fname
){
497 int i1
, i2
, trk
[4], transp
[4], param
[3], note
, instr
;
499 t
= (pineapple_tune
*) malloc(sizeof(pineapple_tune
));
501 fprintf(stderr
, "couldn't malloc pineapple_tune *tune!\n");
505 snprintf(filename
, sizeof(filename
), "%s", fname
);
506 //snprintf(t->filename, sizeof(filename), "%s", fname);
508 f
= fopen(fname
, "r");
513 //check if its a musicchip file so we can return from this function and try to load the next type of file
514 fseek(f
, 0, SEEK_SET
);
515 fread(&header
, 1, 4, f
);
516 if(strncmp(header
, "musi", sizeof(header
)) == 0){
517 fprintf(stderr
, "loading .lft file\n");
519 fprintf(stderr
, "not a .lft file!\n");
520 fprintf(stderr
, "%s\n", header
);
527 t
->tracklen
= TRACKLEN
;
528 while(!feof(f
) && fgets(buf
, sizeof(buf
), f
)){
529 if(1 == sscanf(buf
, "#%1024c", &comment
)){
531 else if(1 == sscanf(buf
, "tempo: %hhd", &callbacktime
)){
532 t
->callbacktime
= (u8
)callbacktime
;
533 }else if(9 == sscanf(buf
, "songline %x %x %x %x %x %x %x %x %x",
544 for(i
= 0; i
< 4; i
++){
545 t
->sng
[i1
].track
[i
] = trk
[i
];
546 t
->sng
[i1
].transp
[i
] = transp
[i
];
548 if(t
->songlen
<= i1
) t
->songlen
= i1
+ 1;
549 }else if(8 == sscanf(buf
, "trackline %x %x %x %x %x %x %x %x",
559 t
->trk
[i1
].line
[i2
].note
= note
;
560 t
->trk
[i1
].line
[i2
].instr
= instr
;
561 for(i
= 0; i
< 2; i
++){
562 t
->trk
[i1
].line
[i2
].cmd
[i
] = cmd
[i
];
563 t
->trk
[i1
].line
[i2
].param
[i
] = param
[i
];
565 }else if(4 == sscanf(buf
, "instrumentline %x %x %x %x",
571 instrument
[i1
].line
[i2
].cmd
= cmd
[0];
572 instrument
[i1
].line
[i2
].param
= param
[0];
573 if(instrument
[i1
].length
<= i2
) instrument
[i1
].length
= i2
+ 1;
577 t
->iedplonk
= lft_iedplonk
;
583 void lft_saveinstrument(char *fname
){
587 f
= fopen(fname
, "w");
589 fprintf(stderr
, "save error!\n");
593 fprintf(f
, "pineapple tune instrument\n");
594 fprintf(f
, "version alphamega\n");
596 fprintf(f
, "%s\n", filename
);
598 for(i
= 0; i
< instrument
[currinstr
].length
; i
++){
599 fprintf(f
, "instrumentline %02x %02x %02x\n",
601 instrument
[currinstr
].line
[i
].cmd
,
602 instrument
[currinstr
].line
[i
].param
);
608 int lft_loadinstrument(char *fname
){
611 int i
, cmd
[3], param
[3];
614 f
= fopen(fname
, "r");
619 fr
= nextfreeinstr();
621 while(!feof(f
) && fgets(buf
, sizeof(buf
), f
)){
622 if(3 == sscanf(buf
, "instrumentline %x %x %x",
627 instrument
[fr
].line
[i
].cmd
= cmd
[0];
628 instrument
[fr
].line
[i
].param
= param
[0];
629 if(instrument
[fr
].length
<= i
) instrument
[fr
].length
= i
+ 1;