1 //---------------------------------------------------------------------------\\
3 // lft's musicchip song format
4 //---------------------------------------------------------------------------//
11 #include "filetypes.h"
13 volatile u8 callbackwait
;
14 u8 callbacktime
= 180;
20 /*const u16 freqtable[] = {
21 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165, 0x017a, 0x0191, 0x01a9,
22 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259, 0x027d, 0x02a3, 0x02cb,
23 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3, 0x042f, 0x046f, 0x04b2,
24 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5, 0x070a, 0x0775, 0x07e6,
25 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c, 0x0bd6, 0x0c8b, 0x0d4a,
26 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb, 0x13e9, 0x1518, 0x1659,
27 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b, 0x217c, 0x237a, 0x2596,
28 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528, 0x3851, 0x3bab, 0x3f37,
29 0x42f9, 0x46f5, 0x4b2d, 0x4fa6, 0x5462, 0x5967, 0x5eb7, 0x6459, 0x6a51,
30 0x70a3, 0x7756, 0x7e6f
34 /*const u16 freqtable[] = {
35 0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8, 0x00d4,
36 0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151, 0x0165,
37 0x017a, 0x0191, 0x01a9, 0x01c2, 0x01dd, 0x01f9, 0x0217, 0x0237, 0x0259,
38 0x027d, 0x02a3, 0x02cb, 0x02f5, 0x0322, 0x0352, 0x0385, 0x03ba, 0x03f3,
39 0x042f, 0x046f, 0x04b2, 0x04fa, 0x0546, 0x0596, 0x05eb, 0x0645, 0x06a5,
40 0x070a, 0x0775, 0x07e6, 0x085f, 0x08de, 0x0965, 0x09f4, 0x0a8c, 0x0b2c,
41 0x0bd6, 0x0c8b, 0x0d4a, 0x0e14, 0x0eea, 0x0fcd, 0x10be, 0x11bd, 0x12cb,
42 0x13e9, 0x1518, 0x1659, 0x17ad, 0x1916, 0x1a94, 0x1c28, 0x1dd5, 0x1f9b,
43 0x217c, 0x237a, 0x2596, 0x27d3, 0x2a31, 0x2cb3, 0x2f5b, 0x322c, 0x3528,
44 0x3851, 0x3bab, 0x3f37
48 const u16 freqtable
[] = {
49 0x002c, 0x002f, 0x0032, 0x0035, 0x0038, 0x003b, 0x003f, 0x0042, 0x0046,
50 0x004b, 0x004f, 0x0054, 0x0059, 0x005e, 0x0064, 0x006a, 0x0070, 0x0077,
51 0x007e, 0x0085, 0x008d, 0x0096, 0x009f, 0x00a8, 0x00b2, 0x00bd, 0x00c8,
52 0x00d4, 0x00e1, 0x00ee, 0x00fc, 0x010b, 0x011b, 0x012c, 0x013e, 0x0151,
53 0x0165, 0x017a, 0x0190, 0x01a8, 0x01c2, 0x01dc, 0x01f9, 0x0217, 0x0237,
54 0x0258, 0x027c, 0x02a2, 0x02ca, 0x02f4, 0x0321, 0x0351, 0x0384, 0x03b9,
55 0x03f2, 0x042e, 0x046e, 0x04b1, 0x04f8, 0x0544, 0x0594, 0x05e9, 0x0643,
56 0x06a3, 0x0708, 0x0773, 0x07e4, 0x085c, 0x08dc, 0x0962, 0x09f1, 0x0a89,
57 0x0b29, 0x0bd3, 0x0c87, 0x0d46, 0x0e10, 0x0ee6, 0x0fc9, 0x10b9, 0x11b8,
58 0x12c5, 0x13e3, 0x1512
61 const s8 sinetable
[] = {
62 0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
63 127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
64 0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
65 -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
66 -71, -60, -49, -37, -25, -12
89 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
90 \\\
< void runcmd(u8
,u8
,u8
) > .|
91 /// Executes a song command. .\
92 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
93 void runcmd(u8 ch
, u8 cmd
, u8 param
){
99 osc
[ch
].duty
= param
<< 8;
102 channel
[ch
].volumed
= param
;
105 channel
[ch
].inertia
= param
<< 1;
108 channel
[ch
].iptr
= param
;
111 channel
[ch
].bendd
= param
;
114 channel
[ch
].dutyd
= param
<< 6;
117 channel
[ch
].iwait
= (param
*6);
120 osc
[ch
].volume
= param
;
123 osc
[ch
].waveform
= param
;
126 channel
[ch
].inote
= param
+ channel
[ch
].tnote
- 12 * 4;
129 channel
[ch
].inote
= param
;
132 if(channel
[ch
].vdepth
!= (param
>> 4)){
133 channel
[ch
].vpos
= 0;
135 channel
[ch
].vdepth
= param
>> 4;
136 channel
[ch
].vrate
= (param
/2) & 0xf;
137 //channel[ch].vrate = param & 0xf;
140 callbacktime
= -param
;
145 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
146 \\\
< void silence() > .|
147 /// Stops all sound. .\
148 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
150 for(u8 i
= 0; i
< 4; i
++){
157 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
158 \\\
< void iedplonk(int,int) > .|
160 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
161 void iedplonk(int note
, int instr
){
162 channel
[0].tnote
= note
;
163 channel
[0].inum
= instr
;
165 channel
[0].iwait
= 0;
167 channel
[0].bendd
= 0;
168 channel
[0].volumed
= 0;
169 channel
[0].dutyd
= 0;
170 channel
[0].vdepth
= 0;
173 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
174 \\\
< void startplaytrack(int) > .|
175 /// Plays a track. .\
176 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
177 void startplaytrack(int t
){
188 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
189 \\\
< void startplaysong(int) > .|
190 /// Plays the song from a certain position. .\
191 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
192 void startplaysong(int p
){
200 void playroutine(){ // called at 50 Hz
203 if(playtrack
|| playsong
){
212 if(tune
->songpos
>= tune
->songlen
){
215 for(ch
= 0; ch
< 4; ch
++){
218 readsong(tune
->songpos
, ch
, tmp
);
219 channel
[ch
].tnum
= tmp
[0];
220 channel
[ch
].transp
= tmp
[1];
227 if(playtrack
|| playsong
){
228 for(ch
= 0; ch
< 4; ch
++){
229 if(channel
[ch
].tnum
){
233 readtrack(channel
[ch
].tnum
, trackpos
, &tl
);
235 channel
[ch
].tnote
= tl
.note
+ channel
[ch
].transp
;
236 instr
= channel
[ch
].lastinstr
;
242 channel
[ch
].lastinstr
= instr
;
243 channel
[ch
].inum
= instr
;
244 channel
[ch
].iptr
= 0;
245 channel
[ch
].iwait
= 0;
246 channel
[ch
].bend
= 0;
247 channel
[ch
].bendd
= 0;
248 channel
[ch
].volumed
= 0;
249 channel
[ch
].dutyd
= 0;
250 channel
[ch
].vdepth
= 0;
253 runcmd(ch
, tl
.cmd
[0], tl
.param
[0]);
255 runcmd(ch
, tl
.cmd
[1], tl
.param
[1]);
265 for(ch
= 0; ch
< 4; ch
++){
270 // i dunno if that last condition is correct...........................
271 while((channel
[ch
].inum
&& !channel
[ch
].iwait
) || channel
[0].iptr
== 0){
274 readinstr(channel
[ch
].inum
, channel
[ch
].iptr
, il
);
277 runcmd(ch
, il
[0], il
[1]);
279 if(channel
[ch
].iwait
) channel
[ch
].iwait
--;
281 if(channel
[ch
].inertia
){
284 slur
= channel
[ch
].slur
;
285 diff
= freqtable
[channel
[ch
].inote
] - slur
;
286 //diff >>= channel[ch].inertia;
288 if(diff
> channel
[ch
].inertia
) diff
= channel
[ch
].inertia
;
290 if(diff
< -channel
[ch
].inertia
) diff
= -channel
[ch
].inertia
;
293 channel
[ch
].slur
= slur
;
295 slur
= freqtable
[channel
[ch
].inote
];
300 ((channel
[ch
].vdepth
* sinetable
[channel
[ch
].vpos
& 63]) >> 2);
301 channel
[ch
].bend
+= channel
[ch
].bendd
;
302 vol
= osc
[ch
].volume
+ channel
[ch
].volumed
;
304 if(vol
> 255) vol
= 255;
305 osc
[ch
].volume
= vol
;
307 duty
= osc
[ch
].duty
+ channel
[ch
].dutyd
;
308 if(duty
> 0xe000) duty
= 0x2000;
309 if(duty
< 0x2000) duty
= 0xe000;
312 channel
[ch
].vpos
+= channel
[ch
].vrate
;
316 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
317 \\\
< void initchip() > .|
318 /// Initialize sound engine. .\
319 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
336 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
337 \\\
< void interrupthandler(int,int) > .|
338 /// Called by sdl_callbackbuffer. Computes a frame of audio. .\
339 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
340 u8
interrupthandler() // called at 9000 Hz
345 static u32 noiseseed
= 1;
348 if(noiseseed
& 0x80000000L
) newbit
^= 1;
349 if(noiseseed
& 0x01000000L
) newbit
^= 1;
350 if(noiseseed
& 0x00000040L
) newbit
^= 1;
351 if(noiseseed
& 0x00000200L
) newbit
^= 1;
352 noiseseed
= (noiseseed
<< 1) | newbit
;
358 callbackwait
= callbacktime
- 1;
362 for(i
= 0; i
< 4; i
++){
363 s8 value
; // [-32,31]
365 switch(osc
[i
].waveform
){
367 if(osc
[i
].phase
< 0x8000){
368 value
= -32 + (osc
[i
].phase
>> 9);
370 value
= 31 - ((osc
[i
].phase
- 0x8000) >> 9);
374 value
= -32 + (osc
[i
].phase
>> 10);
377 value
= (osc
[i
].phase
> osc
[i
].duty
)? -32 : 31;
380 value
= (noiseseed
& 63) - 32;
383 value
= sinetable
[j
];
384 if(j
>= sizeof(sinetable
)-1) j
= 0;
391 osc
[i
].phase
+= osc
[i
].freq
;
393 acc
+= value
* osc
[i
].volume
; // rhs = [-8160,7905]
396 // acc [-32640,31620]
397 return 128 + (acc
>> 8); // [1,251]
401 //--------------------------------------------------------------------------\\
403 //--------------------------------------------------------------------------//
405 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
406 \\\
< void lft_savefile(char *fname
) > .|
407 /// Save the currently loaded lft tune. .\
408 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
409 void lft_savefile(char *fname
){
413 f
= fopen(fname
, "w");
415 fprintf(stderr
, "save error!\n");
419 fprintf(f
, "musicchip tune\n");
420 fprintf(f
, "version 1\n");
422 fprintf(f
, "%s\n", filename
);
424 fprintf(f
, "#%s\n", comment
);
426 fprintf(f
, "tempo: %d\n", callbacktime
);
427 for(i
= 0; i
< tune
->songlen
; i
++){
428 fprintf(f
, "songline %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
440 for(i
= 1; i
< 256; i
++){
441 for(j
= 0; j
< tune
->tracklen
; j
++){
442 struct trackline
*tl
= &track
[i
].line
[j
];
444 if(tl
->note
|| tl
->instr
|| tl
->cmd
[0] || tl
->cmd
[1]){
445 fprintf(f
, "trackline %02x %02x %02x %02x %02x %02x %02x %02x\n",
458 for(i
= 1; i
< 256; i
++){
459 if(instrument
[i
].length
> 1){
460 for(j
= 0; j
< instrument
[i
].length
; j
++){
461 fprintf(f
, "instrumentline %02x %02x %02x %02x\n",
464 instrument
[i
].line
[j
].cmd
,
465 instrument
[i
].line
[j
].param
);
473 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
474 \\\
< pineapple_tune
*lft_loadfile(char *) > .|
475 /// Takes a filename. Returns a pineapple_tune struct. NULL on failure .\
476 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
477 pineapple_tune
*lft_loadfile(char *fname
){
483 int i1
, i2
, trk
[4], transp
[4], param
[3], note
, instr
;
485 t
= (pineapple_tune
*) malloc(sizeof(pineapple_tune
));
487 fprintf(stderr
, "couldn't malloc pineapple_tune *tune!\n");
491 snprintf(filename
, sizeof(filename
), "%s", fname
);
492 //snprintf(t->filename, sizeof(filename), "%s", fname);
494 f
= fopen(fname
, "r");
499 //check if its a musicchip file so we can return from this function and try to load the next type of file
500 fseek(f
, 0, SEEK_SET
);
501 fread(&header
, 1, 4, f
);
502 if(strncmp(header
, "musi", sizeof(header
)) == 0){
503 fprintf(stderr
, "loading .lft file\n");
505 fprintf(stderr
, "not a .lft file!\n");
506 fprintf(stderr
, "%s\n", header
);
512 t
->tracklen
= TRACKLEN
;
513 while(!feof(f
) && fgets(buf
, sizeof(buf
), f
)){
514 if(1 == sscanf(buf
, "#%1024c", &comment
)){
516 else if(1 == sscanf(buf
, "tempo: %hhd", &callbacktime
)){
517 t
->callbacktime
= (u8
)callbacktime
;
518 }else if(9 == sscanf(buf
, "songline %x %x %x %x %x %x %x %x %x",
529 for(i
= 0; i
< 4; i
++){
530 t
->sng
[i1
].track
[i
] = trk
[i
];
531 t
->sng
[i1
].transp
[i
] = transp
[i
];
533 if(t
->songlen
<= i1
) t
->songlen
= i1
+ 1;
534 }else if(8 == sscanf(buf
, "trackline %x %x %x %x %x %x %x %x",
544 t
->trk
[i1
].line
[i2
].note
= note
;
545 t
->trk
[i1
].line
[i2
].instr
= instr
;
546 for(i
= 0; i
< 2; i
++){
547 t
->trk
[i1
].line
[i2
].cmd
[i
] = cmd
[i
];
548 t
->trk
[i1
].line
[i2
].param
[i
] = param
[i
];
550 }else if(4 == sscanf(buf
, "instrumentline %x %x %x %x",
556 instrument
[i1
].line
[i2
].cmd
= cmd
[0];
557 instrument
[i1
].line
[i2
].param
= param
[0];
558 if(instrument
[i1
].length
<= i2
) instrument
[i1
].length
= i2
+ 1;
566 void lft_saveinstrument(char *fname
){
570 f
= fopen(fname
, "w");
572 fprintf(stderr
, "save error!\n");
576 fprintf(f
, "pineapple tune instrument\n");
577 fprintf(f
, "version alphamega\n");
579 fprintf(f
, "%s\n", filename
);
581 for(i
= 0; i
< instrument
[currinstr
].length
; i
++){
582 fprintf(f
, "instrumentline %02x %02x %02x\n",
584 instrument
[currinstr
].line
[i
].cmd
,
585 instrument
[currinstr
].line
[i
].param
);
591 int lft_loadinstrument(char *fname
){
594 int i
, cmd
[3], param
[3];
597 f
= fopen(fname
, "r");
602 fr
= nextfreeinstr();
604 while(!feof(f
) && fgets(buf
, sizeof(buf
), f
)){
605 if(3 == sscanf(buf
, "instrumentline %x %x %x",
610 instrument
[fr
].line
[i
].cmd
= cmd
[0];
611 instrument
[fr
].line
[i
].param
= param
[0];
612 if(instrument
[fr
].length
<= i
) instrument
[fr
].length
= i
+ 1;