Timing is correct now! Forgot to update samples_per_tick when parsing the 0xf effect.
[pineappletracker.git] / mod / main.c
blob166765a13868829b7ad656419e9f1e5db618bdc5
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6 #include <unistd.h>
7 #include <SDL/SDL.h>
9 #include "main.h"
11 double smp_index = 0;
12 double note = 65.41; //c3
14 int currpatt = 0;
15 int currrow = 0;
16 int currorder = 0;
17 int currsample;
18 int currnote;
19 int tick = 6;
20 int last_sample;
21 int samples_per_tick;
22 int samples_left; //counter
24 int volume_levels = 64;
26 SDL_AudioSpec requested, obtained;
28 //static char *notenames[] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-",
29 // "G#", "A-", "A#", "H-"};
31 /*double note_table[] = {
32 //16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87, //C-1..B-1
33 32.7, 34.65, 36.71, 38.89, 41.2, 43.65, 46.25, 49.00, 51.91, 55, 58.27, 61.74, //C-2..B-2
34 65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.5, 98, 103.83, 110, 116.54, 123.47, //C-3..B-3
35 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94, //C-4..B-4
36 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88 //C-5..B-5
39 /*smp_index+=(
40 pow(2.0, (currnote-24.0)/12.0)*1.0)
41 /((float)FREQ/8363.0);*/
42 const double inc_table[60] = {
43 0.250000, 0.264866, 0.280616, 0.297302, 0.314980, 0.333710, 0.353553, 0.374577, 0.396850, 0.420448, 0.445449, 0.471937,
44 0.500000, 0.529732, 0.561231, 0.594604, 0.629961, 0.667420, 0.707107, 0.749154, 0.793701, 0.840896, 0.890899, 0.943874,
45 1.000000, 1.059463, 1.122462, 1.189207, 1.259921, 1.334840, 1.414214, 1.498307, 1.587401, 1.681793, 1.781797, 1.887749,
46 2.000000, 2.118926, 2.244924, 2.378414, 2.519842, 2.669680, 2.828427, 2.996614, 3.174802, 3.363586, 3.563595, 3.775497,
47 4.000000, 4.237852, 4.489848, 4.756828, 5.039684, 5.339359, 5.656854, 5.993228, 6.349604, 6.727171, 7.127190, 7.550995,
50 void init_player(void){
51 modheader.speed = 6;
52 modheader.tempo = 125;
53 samples_per_tick = FREQ / (2 * modheader.tempo / 5);
54 samples_left = samples_per_tick;
55 tick = 0;
56 currpatt = modheader.order[0];
57 currrow = 0;
58 currorder = 0;
59 for(int i = 0; i < 4; i++)
60 mix_channels[i].vol = 64;
63 s8 get_sample(struct mix_channel *chn){
64 //LOG(chn->currsample, i);
65 if(chn->currnote == 0)
66 return 0;
67 chn->smp_index+=inc_table[chn->currnote]/((float)FREQ/8363.0);
68 if(modheader.sample[chn->currsample].looplength > 2){ //looping
69 if(chn->smp_index >= (modheader.sample[chn->currsample].looplength + modheader.sample[chn->currsample].loopstart))
70 chn->smp_index = modheader.sample[chn->currsample].loopstart;
71 }else{ //not looping
72 if(chn->smp_index >= modheader.sample[chn->currsample].length){
73 chn->currnote = 0;
74 chn->smp_index = 0;
77 return modheader.sample[chn->currsample].smpdata[(int)chn->smp_index] * chn->vol / volume_levels;
80 /* the worst mixer in the wurld */
81 s8 mix(void){
82 s16 temp_buf = 0;
83 //only four channels for now...
84 for(int i = 0; i < 4; i++){
85 temp_buf += get_sample(&mix_channels[i]) * mix_channels[i].vol / volume_levels;
86 //LOG(i, i);
87 //LOG(temp_buf, i);
89 //LOG(temp_buf, i);
90 // >>6 to divide off the volume, >>2 to divide by 4 channels to prevent overflow
91 return temp_buf >> 2;
94 void process_tick(void){
95 tick++;
96 if(tick >= modheader.speed){
97 tick = 0;
98 process_row();
102 void process_row(void){
103 //iterate through channels
104 for(int i = 0; i < 4; i++){
105 if(modheader.patterns[currpatt].pattern_entry[currrow][i].sample == MOD_NO_SAMPLE)
106 mix_channels[i].currsample = mix_channels[i].last_sample;
107 else{
108 mix_channels[i].last_sample = modheader.patterns[currpatt].pattern_entry[currrow][i].sample;
109 mix_channels[i].currsample = mix_channels[i].last_sample;
110 mix_channels[i].smp_index = 0;
111 if(modheader.patterns[currpatt].pattern_entry[currrow][i].effect == 0xc)
112 mix_channels[i].vol = modheader.patterns[currpatt].pattern_entry[currrow][i].param;
113 else
114 mix_channels[i].vol = volume_levels;
116 if(modheader.patterns[currpatt].pattern_entry[currrow][i].period != MOD_NO_NOTE)
117 mix_channels[i].currnote = modheader.patterns[currpatt].pattern_entry[currrow][i].period;
118 if(modheader.patterns[currpatt].pattern_entry[currrow][i].effect == 0xc)
119 mix_channels[i].vol = modheader.patterns[currpatt].pattern_entry[currrow][i].param;
120 if(modheader.patterns[currpatt].pattern_entry[currrow][i].effect == 0xf){
121 if(modheader.patterns[currpatt].pattern_entry[currrow][i].param > 0x1f){
122 modheader.tempo = modheader.patterns[currpatt].pattern_entry[currrow][i].param;
123 samples_per_tick = FREQ / (2 * modheader.tempo / 5);
124 }else
125 modheader.speed = modheader.patterns[currpatt].pattern_entry[currrow][i].param;
127 //else
128 // mix_channels[i].vol = volume_levels;
130 currrow++;
131 if(currrow >= 64){
132 currrow = 0;
133 if(currorder++ >= modheader.orderCount)
134 currorder = 0;
135 currpatt = modheader.order[currorder];
139 void callback(void *data, Uint8 *buf, int len){
140 int pos = 0;
141 int buffer_left = len;
142 s8 *out;
143 out = (s8*) buf;
144 while(buffer_left > 0){
145 //LOG(buffer_left, i);
146 if(samples_left <= 0){
147 //CHECK(1);
148 process_tick();
149 samples_left = samples_per_tick;
150 //CHECK(ifstatement);
151 //LOG(buffer_left, i);
152 //LOG(samples_left, i);
154 while((buffer_left >= 0) && (samples_left >= 0)){
155 //for some reason i dont have to add 128 when i am using unsigned audio anymore ??
156 out[pos] += mix();
157 //out[pos] = (get_sample(&mix_channels[2]) * mix_channels[2].vol / volume_levels) + 128;
158 //out[pos] = get_sample(&mix_channels[3]) + 128;
159 //LOG(mix_channels[3].currsample + 1, x);
160 //LOG(out[pos], i);
161 pos += 1;
162 buffer_left -= 1;
163 samples_left -= 1;
168 int sdl_init(void){
170 if(SDL_Init(SDL_INIT_AUDIO) < 0){
171 printf("couldn't init SDL: %s\n", SDL_GetError());
172 SDL_Quit();
173 return 1;
176 requested.freq = FREQ;
177 requested.format = AUDIO_S8;
178 requested.samples = 1024;
179 requested.channels = 1;
180 requested.callback = callback;
182 SDL_OpenAudio(&requested, &obtained);
184 fprintf(stderr, "freq %d\n", obtained.freq);
185 if(obtained.format == 0x0008)
186 fprintf(stderr, "format: AUDIO_U8\n");
187 else if(obtained.format == 0x8008)
188 fprintf(stderr, "format: AUDIO_S8\n");
189 fprintf(stderr, "samples:%d\n", obtained.samples);
190 fprintf(stderr, "channels:%d\n", obtained.channels);
192 return 0;
195 int main(int argc, char **argv){
196 FILE *modfile;
197 FILE *samplefile;
198 int i;
199 int trash;
200 u8 highestPattern = 0;
202 const u16 octave1Period[12] = {
203 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453
206 /*const u16 period_table[60] = {
207 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906,
208 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
209 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
210 214, 202, 190, 180, 169, 160, 151, 142, 134, 127, 120, 113,
211 107, 101, 95, 90, 84, 80, 75, 71, 67, 63, 60, 56
212 };*/
214 u16 periodTable[12*5];
215 u8 octave,note;
216 char sig[4];
218 for(octave = 0; octave < 5; octave++){ //12 is c-3
219 for(note = 0; note < 12; note++){
220 //*2 to get us into octave 0, then divide by 2 for each
221 // octave from there
222 periodTable[octave*12 + note] =
223 (octave1Period[note]*2) >> octave;
227 /* ~opening the modfile~ */
228 modfile = fopen(argv[1], "rb");
230 samplefile = fopen("samp.raw", "wb");
232 if(!modfile){
233 printf("Couldn't open file!\n");
234 return 1;
237 /* ~is it a mod?~ */
238 fseek(modfile, 1080, SEEK_SET);
239 fread(&sig, 1, 4, modfile);
240 if(!strcmp(sig,"M.K.")){
241 printf("not a MOD\n");
242 printf(sig);
243 exit(1);
244 }else{
245 printf("YES");
247 /* need to check for other sigs later... */
249 /* ~what's its name?~ */
250 rewind(modfile);
251 fread(modheader.name, 20, 1, modfile);
252 modheader.name[19] = '\0';
254 /* ~ load samples ~*/
255 for(i = 0; i < 31; i++){
256 fread(&modheader.sample[i], 30, 1, modfile);
257 modheader.sample[i].smpdata = NULL;
258 /* these bit shifty hacks only work because length, loopstart and
259 looplength are u16 */
260 modheader.sample[i].length =
261 ( ((modheader.sample[i].length & 0xff) << 8) |
262 (modheader.sample[i].length >> 8) ) * 2; /*just times it by two when you
263 *load it the FIRST time.
264 *most samples will fit in a u16
265 *when multiplied by two but some
266 *probably won't!*/
267 modheader.sample[i].loopstart =
268 ( ((modheader.sample[i].loopstart & 0xff) << 8) |
269 (modheader.sample[i].loopstart >> 8) ) * 2;
271 modheader.sample[i].looplength =
272 ( ((modheader.sample[i].looplength & 0xff) << 8) |
273 (modheader.sample[i].looplength >> 8) ) * 2;
276 /*~ load orders ~*/
277 fread(&modheader.orderCount, 1, 1, modfile);
279 fread(&trash, 1, 1, modfile); //useless byte
281 fread(&modheader.order, 128, 1 , modfile);
283 fread(&trash, 4, 1, modfile);
285 /*~ load patterns ~*/
286 for(i = 0; i < modheader.orderCount; i++){
287 if(modheader.order[i] > highestPattern)
288 highestPattern = modheader.order[i];
291 modheader.patternCount = highestPattern + 1;
293 // allocate space for patterns
294 modheader.patterns = malloc(sizeof(struct pattern[modheader.patternCount]));
296 if(modheader.patterns==NULL){
297 printf("out of memory!\n");
298 exit(1);
302 //initialize modheader.pattern to 0
303 /* XXX SEGFAULT */
304 //memset(modheader.pattern, 0, modheader.patternCount*sizeof(u8*));
306 u8 curPattern, row, column;
308 for(curPattern = 0; curPattern < modheader.patternCount; curPattern++){
309 //modheader.patterns[curPattern] = malloc(1024); //patterns are always 1k
310 /*modheader.patterns[curPattern] = malloc(sizeof(struct pattern));
311 if(!modheader.patterns[curPattern]){
312 printf("out of memory!\n");
315 //initialize to 0
316 memset(modheader.patterns[curPattern], 0, 1024);
319 for(row = 0; row < 64; row++){
320 for(column = 0; column < 4; column++){
321 u8 cell[4];
322 u8 sample;
323 u16 period;
324 u8 effect;
325 u8 param;
326 u8 closestNote;
328 fread(cell, 4, 1, modfile);
330 sample = (cell[0] & 0xf0) | (cell[2] >> 4);
331 period = cell[1] | ((cell[0] & 0xf) << 8);
332 effect = cell[2] & 0xf;
333 param = cell[3];
335 if(period == 0){
336 closestNote = MOD_NO_NOTE; //period 0 is no note
339 else {
340 u16 closestDist = 0xffff; //make sure the first comparison sets the closet note
341 closestNote = 0;
342 //looping through the period table
343 for(i = 0; i < 12*5; i++){
344 u16 newDist = abs(period - periodTable[i]);
345 if(newDist < closestDist){
346 closestNote = (u8)i;
347 closestDist = newDist;
352 if(sample == 0){
353 sample = MOD_NO_SAMPLE;
354 }else {
355 sample -= 1;
358 //now that we have our note, we can store the data in our new pattern
359 //calculate the address of the cell to output to
360 // rowoffset = row * 4 columns per row * 4 bytes per cell
361 // columnoffset = column * 4 bytes per cell
363 /*u8 *outCell = &modheader.pattern[curPattern][row*4*4 + column*4];
364 outCell[0] = closestNote;
365 outCell[1] = sample;
366 outCell[2] = effect;
367 outCell[3] = param;
369 modheader.patterns[curPattern].pattern_entry[row][column].period = closestNote;
370 modheader.patterns[curPattern].pattern_entry[row][column].sample = sample;
371 modheader.patterns[curPattern].pattern_entry[row][column].effect = effect;
372 modheader.patterns[curPattern].pattern_entry[row][column].param = param;
378 /* ~~ load sample datas ~~ */
379 for(i = 0; i < 31; i++){
380 int realLength = (modheader.sample[i].length);
381 if(realLength != 0){
382 modheader.sample[i].smpdata = malloc(realLength);
383 if(modheader.sample[i].smpdata != NULL){
384 fread(modheader.sample[i].smpdata, realLength, 1, modfile);
389 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
390 //done reading modfile
391 fclose(modfile);
393 fwrite(modheader.sample[30].smpdata, (modheader.sample[30].length), 1, samplefile);
395 fclose(samplefile);
397 printf("%s\n", modheader.name);
399 for(i = 0; i < 31; i++) {
400 printf("%0x: %s\n", i, modheader.sample[i].name);
401 printf("%0x: length:%x\n", i, modheader.sample[i].length);
402 printf("%0x: loopstart:%x\n", i, modheader.sample[i].loopstart);
403 printf("%0x: looplength:%x\n", i, modheader.sample[i].looplength);
406 printf("highest pattern: %i\n", highestPattern);
408 printf("orderCount: %i\n", modheader.orderCount);
410 printf("patternCount: %i\n", modheader.patternCount);
412 //printf("%i\n", sizeof(u8*[modheader.patternCount])); //36
413 //printf("%i\n", sizeof(u8*)); //4
415 /*for(i = 0; i < modheader.patternCount+1; i++)
416 for(row = 0; row < 64; row++)
417 printf("%i\n", modheader.pattern[i][row]);
420 for(i = 0; i < modheader.orderCount; i++)
421 printf("%i : %i\n", i, modheader.order[i]);
423 for(row = 0; row < 64; row++){
424 printf("%i %x %x %02x\n", modheader.patterns[0].pattern_entry[row][0].period,
425 modheader.patterns[0].pattern_entry[row][0].sample + 1,
426 modheader.patterns[0].pattern_entry[row][0].effect,
427 modheader.patterns[0].pattern_entry[row][0].param);
430 if(sdl_init() == 0){
431 init_player();
432 SDL_PauseAudio(0);
433 //while(1){
434 // update();
435 // usleep(5000);
437 getchar();
438 SDL_PauseAudio(1);
439 SDL_Quit();
442 return 0;