Load ht->ht_Tracks into tune->struct track trk[]. Seems I got it working for lft...
[pineappletracker.git] / lft.c
blob3e11594bbf02eb96019ae2e606821f85cc2b2209
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"
13 volatile u8 callbackwait;
14 u8 callbacktime = 180;
16 u8 trackwait;
17 u8 trackpos;
18 u8 interruptwait = 0;
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
31 };*/
33 // for 16kHz
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
45 };*/
47 // for 48kHz
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
69 struct channel {
70 u8 tnum;
71 s8 transp;
72 u8 tnote;
73 u8 lastinstr;
74 u8 inum;
75 u8 iptr;
76 u8 iwait;
77 u8 inote;
78 s8 bendd;
79 s16 bend;
80 s8 volumed;
81 s16 dutyd;
82 u8 vdepth;
83 u8 vrate;
84 u8 vpos;
85 s16 inertia;
86 u16 slur;
87 } channel[4];
89 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
90 \\\ < void runcmd(u8,u8,u8) > .|
91 /// Executes a song command. .\
92 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
93 void runcmd(u8 ch, u8 cmd, u8 param){
94 switch(cmd){
95 case 0:
96 channel[ch].inum = 0;
97 break;
98 case 'd':
99 osc[ch].duty = param << 8;
100 break;
101 case 'f':
102 channel[ch].volumed = param;
103 break;
104 case 'i':
105 channel[ch].inertia = param << 1;
106 break;
107 case '@':
108 channel[ch].iptr = param;
109 break;
110 case 's':
111 channel[ch].bendd = param;
112 break;
113 case 'm':
114 channel[ch].dutyd = param << 6;
115 break;
116 case 't':
117 channel[ch].iwait = (param*6);
118 break;
119 case 'v':
120 osc[ch].volume = param;
121 break;
122 case 'w':
123 osc[ch].waveform = param;
124 break;
125 case '+':
126 channel[ch].inote = param + channel[ch].tnote - 12 * 4;
127 break;
128 case '=':
129 channel[ch].inote = param;
130 break;
131 case '~':
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;
138 break;
139 case '*':
140 callbacktime = -param;
141 break;
145 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
146 \\\ < void silence() > .|
147 /// Stops all sound. .\
148 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
149 void silence(void){
150 for(u8 i = 0; i < 4; i++){
151 osc[i].volume = 0;
153 playsong = 0;
154 playtrack = 0;
157 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
158 \\\ < void iedplonk(int,int) > .|
159 /// Plays a note. .\
160 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
161 void iedplonk(int note, int instr){
162 channel[0].tnote = note;
163 channel[0].inum = instr;
164 channel[0].iptr = 0;
165 channel[0].iwait = 0;
166 channel[0].bend = 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){
178 channel[0].tnum = t;
179 channel[1].tnum = 0;
180 channel[2].tnum = 0;
181 channel[3].tnum = 0;
182 trackpos = 0;
183 trackwait = 0;
184 playtrack = 1;
185 playsong = 0;
188 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
189 \\\ < void startplaysong(int) > .|
190 /// Plays the song from a certain position. .\
191 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
192 void startplaysong(int p){
193 tune->songpos = p;
194 trackpos = 0;
195 trackwait = 0;
196 playtrack = 0;
197 playsong = 1;
200 void playroutine(){ // called at 50 Hz
201 u8 ch;
203 if(playtrack || playsong){
204 if(trackwait){
205 trackwait--;
206 }else{
207 trackwait = 12;
208 //trackwait = 4;
210 if(!trackpos){
211 if(playsong){
212 if(tune->songpos >= tune->songlen){
213 playsong = 0;
214 }else{
215 for(ch = 0; ch < 4; ch++){
216 u8 tmp[2];
218 readsong(tune->songpos, ch, tmp);
219 channel[ch].tnum = tmp[0];
220 channel[ch].transp = tmp[1];
222 tune->songpos++;
227 if(playtrack || playsong){
228 for(ch = 0; ch < 4; ch++){
229 if(channel[ch].tnum){
230 struct trackline tl;
231 u8 instr = 0;
233 readtrack(channel[ch].tnum, trackpos, &tl);
234 if(tl.note){
235 channel[ch].tnote = tl.note + channel[ch].transp;
236 instr = channel[ch].lastinstr;
238 if(tl.instr){
239 instr = tl.instr;
241 if(instr){
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;
252 if(tl.cmd[0])
253 runcmd(ch, tl.cmd[0], tl.param[0]);
254 if(tl.cmd[1])
255 runcmd(ch, tl.cmd[1], tl.param[1]);
259 trackpos++;
260 trackpos &= 31;
265 for(ch = 0; ch < 4; ch++){
266 s16 vol;
267 u16 duty;
268 u16 slur;
270 // i dunno if that last condition is correct...........................
271 while((channel[ch].inum && !channel[ch].iwait) || channel[0].iptr == 0){
272 u8 il[2];
274 readinstr(channel[ch].inum, channel[ch].iptr, il);
275 channel[ch].iptr++;
277 runcmd(ch, il[0], il[1]);
279 if(channel[ch].iwait) channel[ch].iwait--;
281 if(channel[ch].inertia){
282 s16 diff;
284 slur = channel[ch].slur;
285 diff = freqtable[channel[ch].inote] - slur;
286 //diff >>= channel[ch].inertia;
287 if(diff > 0){
288 if(diff > channel[ch].inertia) diff = channel[ch].inertia;
289 }else if(diff < 0){
290 if(diff < -channel[ch].inertia) diff = -channel[ch].inertia;
292 slur += diff;
293 channel[ch].slur = slur;
294 }else{
295 slur = freqtable[channel[ch].inote];
297 osc[ch].freq =
298 slur +
299 channel[ch].bend +
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;
303 if(vol < 0) vol = 0;
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;
310 osc[ch].duty = duty;
312 channel[ch].vpos += channel[ch].vrate;
316 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
317 \\\ < void initchip() > .|
318 /// Initialize sound engine. .\
319 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
320 void initchip(){
321 trackwait = 0;
322 trackpos = 0;
323 playsong = 0;
324 playtrack = 0;
326 osc[0].volume = 0;
327 channel[0].inum = 0;
328 osc[1].volume = 0;
329 channel[1].inum = 0;
330 osc[2].volume = 0;
331 channel[2].inum = 0;
332 osc[3].volume = 0;
333 channel[3].inum = 0;
336 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
337 \\\ < void interrupthandler(int,int) > .|
338 /// Called by sdl_callbackbuffer. Computes a frame of audio. .\
339 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
340 u8 interrupthandler() // called at 9000 Hz
342 u8 i;
343 u8 j = 0;
344 s16 acc;
345 static u32 noiseseed = 1;
346 u8 newbit = 0;
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;
354 if(callbackwait){
355 callbackwait--;
356 }else{
357 playroutine();
358 callbackwait = callbacktime - 1;
361 acc = 0;
362 for(i = 0; i < 4; i++){
363 s8 value; // [-32,31]
365 switch(osc[i].waveform){
366 case WF_TRI:
367 if(osc[i].phase < 0x8000){
368 value = -32 + (osc[i].phase >> 9);
369 }else{
370 value = 31 - ((osc[i].phase - 0x8000) >> 9);
372 break;
373 case WF_SAW:
374 value = -32 + (osc[i].phase >> 10);
375 break;
376 case WF_PUL:
377 value = (osc[i].phase > osc[i].duty)? -32 : 31;
378 break;
379 case WF_NOI:
380 value = (noiseseed & 63) - 32;
381 break;
382 case WF_SINE:
383 value = sinetable[j];
384 if(j >= sizeof(sinetable)-1) j = 0;
385 else j++;
386 default:
387 value = 0;
388 break;
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 //--------------------------------------------------------------------------\\
402 // File operations
403 //--------------------------------------------------------------------------//
405 //\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\/\\
406 \\\ < void lft_savefile(char *fname) > .|
407 /// Save the currently loaded lft tune. .\
408 \\/\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\//
409 void lft_savefile(char *fname){
410 FILE *f;
411 int i, j;
413 f = fopen(fname, "w");
414 if(!f){
415 fprintf(stderr, "save error!\n");
416 return;
419 fprintf(f, "musicchip tune\n");
420 fprintf(f, "version 1\n");
421 fprintf(f, "\n");
422 fprintf(f, "%s\n", filename);
423 fprintf(f, "\n");
424 fprintf(f, "#%s\n", comment);
425 fprintf(f, "\n");
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",
430 song[i].track[0],
431 song[i].transp[0],
432 song[i].track[1],
433 song[i].transp[1],
434 song[i].track[2],
435 song[i].transp[2],
436 song[i].track[3],
437 song[i].transp[3]);
439 fprintf(f, "\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",
448 tl->note,
449 tl->instr,
450 tl->cmd[0],
451 tl->param[0],
452 tl->cmd[1],
453 tl->param[1]);
457 fprintf(f, "\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);
470 fclose(f);
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){
478 pineapple_tune *t;
479 FILE *f;
480 char header[4];
481 char buf[1024];
482 int cmd[3];
483 int i1, i2, trk[4], transp[4], param[3], note, instr;
484 int i;
485 t = (pineapple_tune*) malloc(sizeof(pineapple_tune));
486 if(!t) {
487 fprintf(stderr, "couldn't malloc pineapple_tune *tune!\n");
488 return NULL;
491 snprintf(filename, sizeof(filename), "%s", fname);
492 //snprintf(t->filename, sizeof(filename), "%s", fname);
494 f = fopen(fname, "r");
495 if(!f){
496 return NULL;
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");
504 }else {
505 fprintf(stderr, "not a .lft file!\n");
506 fprintf(stderr, "%s\n", header);
507 return NULL;
509 rewind(f);
511 t->songlen = 1;
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",
519 &i1,
520 &trk[0],
521 &transp[0],
522 &trk[1],
523 &transp[1],
524 &trk[2],
525 &transp[2],
526 &trk[3],
527 &transp[3])){
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",
535 &i1,
536 &i2,
537 &note,
538 &instr,
539 &cmd[0],
540 &param[0],
541 &cmd[1],
542 &param[1])){
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",
551 &i1,
552 &i2,
553 &cmd[0],
554 &param[0])){
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;
562 fclose(f);
563 return t;
566 void lft_saveinstrument(char *fname){
567 FILE *f;
568 int i;
570 f = fopen(fname, "w");
571 if(!f){
572 fprintf(stderr, "save error!\n");
573 return;
576 fprintf(f, "pineapple tune instrument\n");
577 fprintf(f, "version alphamega\n");
578 fprintf(f, "\n");
579 fprintf(f, "%s\n", filename);
580 fprintf(f, "\n");
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);
587 fclose(f);
588 return;
591 int lft_loadinstrument(char *fname){
592 FILE *f;
593 char buf[1024];
594 int i, cmd[3], param[3];
595 int fr;
597 f = fopen(fname, "r");
598 if(!f){
599 return -1;
602 fr = nextfreeinstr();
604 while(!feof(f) && fgets(buf, sizeof(buf), f)){
605 if(3 == sscanf(buf, "instrumentline %x %x %x",
607 &cmd[0],
608 &param[0])){
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;
616 fclose(f);
617 return 0;