Timing is correct now! Forgot to update samples_per_tick when parsing the 0xf effect.
[pineappletracker.git] / lft.c
blobde45a5e5c681085992a44e7988372fbb64e808d2
1 //---------------------------------------------------------------------------\\
2 // lft.c
3 // lft's musicchip song format
4 //---------------------------------------------------------------------------//
6 #include <stdio.h>
7 #include <string.h>
9 #include "pineapple.h"
10 #include "gui.h"
11 #include "filetypes.h"
12 #include "hvl_replay.h"
13 #include "lft.h"
15 volatile u8 callbackwait;
16 u8 callbacktime = 180;
18 u8 trackwait;
19 u8 trackpos;
20 u8 interruptwait = 0;
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
33 };*/
35 // for 16kHz
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
47 };*/
49 // for 48kHz
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
71 struct channel {
72 u8 tnum;
73 s8 transp;
74 u8 tnote;
75 u8 lastinstr;
76 u8 inum;
77 u8 iptr;
78 u8 iwait;
79 u8 inote;
80 s8 bendd;
81 s16 bend;
82 s8 volumed;
83 s16 dutyd;
84 u8 vdepth;
85 u8 vrate;
86 u8 vpos;
87 s16 inertia;
88 u16 slur;
89 } channel[4];
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){
108 switch(cmd){
109 case 0:
110 channel[ch].inum = 0;
111 break;
112 case 'd':
113 osc[ch].duty = param << 8;
114 break;
115 case 'f':
116 channel[ch].volumed = param;
117 break;
118 case 'i':
119 channel[ch].inertia = param << 1;
120 break;
121 case '@':
122 channel[ch].iptr = param;
123 break;
124 case 's':
125 channel[ch].bendd = param;
126 break;
127 case 'm':
128 channel[ch].dutyd = param << 6;
129 break;
130 case 't':
131 channel[ch].iwait = (param*6);
132 break;
133 case 'v':
134 osc[ch].volume = param;
135 break;
136 case 'w':
137 osc[ch].waveform = param;
138 break;
139 case '+':
140 channel[ch].inote = param + channel[ch].tnote - 12 * 4;
141 break;
142 case '=':
143 channel[ch].inote = param;
144 break;
145 case '~':
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;
152 break;
153 case '*':
154 callbacktime = -param;
155 break;
159 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
160 \\\ < void silence() > .|
161 /// Stops all sound. .\
162 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
163 void silence(void){
164 for(u8 i = 0; i < 4; i++){
165 osc[i].volume = 0;
167 playsong = 0;
168 playtrack = 0;
171 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
172 \\\ < void lft_iedplonk(int,int) > .|
173 /// Plays a note. .\
174 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
175 void lft_iedplonk(int note, int instr, pineapple_tune *t){
176 channel[0].tnote = note;
177 channel[0].inum = instr;
178 channel[0].iptr = 0;
179 channel[0].iwait = 0;
180 channel[0].bend = 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){
192 channel[0].tnum = t;
193 channel[1].tnum = 0;
194 channel[2].tnum = 0;
195 channel[3].tnum = 0;
196 trackpos = 0;
197 trackwait = 0;
198 playtrack = 1;
199 playsong = 0;
202 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
203 \\\ < void startplaysong(int) > .|
204 /// Plays the song from a certain position. .\
205 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
206 void startplaysong(int p){
207 tune->songpos = p;
208 trackpos = 0;
209 trackwait = 0;
210 playtrack = 0;
211 playsong = 1;
214 void playroutine(){ // called at 50 Hz
215 u8 ch;
217 if(playtrack || playsong){
218 if(trackwait){
219 trackwait--;
220 }else{
221 trackwait = 12;
222 //trackwait = 4;
224 if(!trackpos){
225 if(playsong){
226 if(tune->songpos >= tune->songlen){
227 playsong = 0;
228 }else{
229 for(ch = 0; ch < 4; ch++){
230 u8 tmp[2];
232 readsong(tune->songpos, ch, tmp);
233 channel[ch].tnum = tmp[0];
234 channel[ch].transp = tmp[1];
236 tune->songpos++;
241 if(playtrack || playsong){
242 for(ch = 0; ch < 4; ch++){
243 if(channel[ch].tnum){
244 struct trackline tl;
245 u8 instr = 0;
247 readtrack(channel[ch].tnum, trackpos, &tl);
248 if(tl.note){
249 channel[ch].tnote = tl.note + channel[ch].transp;
250 instr = channel[ch].lastinstr;
252 if(tl.instr){
253 instr = tl.instr;
255 if(instr){
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;
266 if(tl.cmd[0])
267 runcmd(ch, tl.cmd[0], tl.param[0]);
268 if(tl.cmd[1])
269 runcmd(ch, tl.cmd[1], tl.param[1]);
273 trackpos++;
274 trackpos &= 31;
279 for(ch = 0; ch < 4; ch++){
280 s16 vol;
281 u16 duty;
282 u16 slur;
284 // i dunno if that last condition is correct...........................
285 while((channel[ch].inum && !channel[ch].iwait) || channel[0].iptr == 0){
286 u8 il[2];
288 readinstr(channel[ch].inum, channel[ch].iptr, il);
289 channel[ch].iptr++;
291 runcmd(ch, il[0], il[1]);
293 if(channel[ch].iwait) channel[ch].iwait--;
295 if(channel[ch].inertia){
296 s16 diff;
298 slur = channel[ch].slur;
299 diff = freqtable[channel[ch].inote] - slur;
300 //diff >>= channel[ch].inertia;
301 if(diff > 0){
302 if(diff > channel[ch].inertia) diff = channel[ch].inertia;
303 }else if(diff < 0){
304 if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
306 slur += diff;
307 channel[ch].slur = slur;
308 }else{
309 slur = freqtable[channel[ch].inote];
311 osc[ch].freq =
312 slur +
313 channel[ch].bend +
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;
317 if(vol < 0) vol = 0;
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;
324 osc[ch].duty = duty;
326 channel[ch].vpos += channel[ch].vrate;
330 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
331 \\\ < void initchip() > .|
332 /// Initialize sound engine. .\
333 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
334 void initchip(){
335 trackwait = 0;
336 trackpos = 0;
337 playsong = 0;
338 playtrack = 0;
340 osc[0].volume = 0;
341 channel[0].inum = 0;
342 osc[1].volume = 0;
343 channel[1].inum = 0;
344 osc[2].volume = 0;
345 channel[2].inum = 0;
346 osc[3].volume = 0;
347 channel[3].inum = 0;
350 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
351 \\\ < void interrupthandler(int,int) > .|
352 /// Called by sdl_callbackbuffer. Computes a frame of audio. .\
353 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
354 u8 interrupthandler() // called at 9000 Hz
356 u8 i;
357 u8 j = 0;
358 s16 acc;
359 static u32 noiseseed = 1;
360 u8 newbit = 0;
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;
368 if(callbackwait){
369 callbackwait--;
370 }else{
371 playroutine();
372 callbackwait = callbacktime - 1;
375 acc = 0;
376 for(i = 0; i < 4; i++){
377 s8 value; // [-32,31]
379 switch(osc[i].waveform){
380 case WF_TRI:
381 if(osc[i].phase < 0x8000){
382 value = -32 + (osc[i].phase >> 9);
383 }else{
384 value = 31 - ((osc[i].phase - 0x8000) >> 9);
386 break;
387 case WF_SAW:
388 value = -32 + (osc[i].phase >> 10);
389 break;
390 case WF_PUL:
391 value = (osc[i].phase > osc[i].duty)? -32 : 31;
392 break;
393 case WF_NOI:
394 value = (noiseseed & 63) - 32;
395 break;
396 case WF_SINE:
397 value = sinetable[j];
398 if(j >= sizeof(sinetable)-1) j = 0;
399 else j++;
400 default:
401 value = 0;
402 break;
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 //--------------------------------------------------------------------------\\
416 // File operations
417 //--------------------------------------------------------------------------//
419 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
420 \\\ < void lft_savefile(char *fname) > .|
421 /// Save the currently loaded lft tune. .\
422 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
423 void lft_savefile(char *fname){
424 FILE *f;
425 int i, j;
427 f = fopen(fname, "w");
428 if(!f){
429 fprintf(stderr, "save error!\n");
430 return;
433 fprintf(f, "musicchip tune\n");
434 fprintf(f, "version 1\n");
435 fprintf(f, "\n");
436 fprintf(f, "%s\n", filename);
437 fprintf(f, "\n");
438 fprintf(f, "#%s\n", comment);
439 fprintf(f, "\n");
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]);
453 fprintf(f, "\n");
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",
462 tl->note,
463 tl->instr,
464 tl->cmd[0],
465 tl->param[0],
466 tl->cmd[1],
467 tl->param[1]);
471 fprintf(f, "\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);
484 fclose(f);
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){
492 pineapple_tune *t;
493 FILE *f;
494 char header[4];
495 char buf[1024];
496 int cmd[3];
497 int i1, i2, trk[4], transp[4], param[3], note, instr;
498 int i;
499 t = (pineapple_tune*) malloc(sizeof(pineapple_tune));
500 if(!t) {
501 fprintf(stderr, "couldn't malloc pineapple_tune *tune!\n");
502 return NULL;
505 snprintf(filename, sizeof(filename), "%s", fname);
506 //snprintf(t->filename, sizeof(filename), "%s", fname);
508 f = fopen(fname, "r");
509 if(!f){
510 return NULL;
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");
518 }else {
519 fprintf(stderr, "not a .lft file!\n");
520 fprintf(stderr, "%s\n", header);
521 return NULL;
523 rewind(f);
525 t->type = LFT;
526 t->songlen = 1;
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",
534 &i1,
535 &trk[0],
536 &transp[0],
537 &trk[1],
538 &transp[1],
539 &trk[2],
540 &transp[2],
541 &trk[3],
542 &transp[3])){
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",
550 &i1,
551 &i2,
552 &note,
553 &instr,
554 &cmd[0],
555 &param[0],
556 &cmd[1],
557 &param[1])){
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",
566 &i1,
567 &i2,
568 &cmd[0],
569 &param[0])){
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;
579 fclose(f);
580 return t;
583 void lft_saveinstrument(char *fname){
584 FILE *f;
585 int i;
587 f = fopen(fname, "w");
588 if(!f){
589 fprintf(stderr, "save error!\n");
590 return;
593 fprintf(f, "pineapple tune instrument\n");
594 fprintf(f, "version alphamega\n");
595 fprintf(f, "\n");
596 fprintf(f, "%s\n", filename);
597 fprintf(f, "\n");
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);
604 fclose(f);
605 return;
608 int lft_loadinstrument(char *fname){
609 FILE *f;
610 char buf[1024];
611 int i, cmd[3], param[3];
612 int fr;
614 f = fopen(fname, "r");
615 if(!f){
616 return -1;
619 fr = nextfreeinstr();
621 while(!feof(f) && fgets(buf, sizeof(buf), f)){
622 if(3 == sscanf(buf, "instrumentline %x %x %x",
624 &cmd[0],
625 &param[0])){
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;
633 fclose(f);
634 return 0;