Fixed a bug where we wern't changing to the next order in time!
[pineappletracker.git] / mod / main.c
blob870790f7240d8c2a922e4759e36e8665ceb3a0ec
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 if(tick >= modheader.speed){
96 tick = 0;
97 process_row();
98 }else
99 tick++;
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 else
124 modheader.speed = modheader.patterns[currpatt].pattern_entry[currrow][i].param;
126 //else
127 // mix_channels[i].vol = volume_levels;
129 currrow++;
130 if(currrow >= 64){
131 currrow = 0;
132 if(currorder++ >= modheader.orderCount)
133 currorder = 0;
134 currpatt = modheader.order[currorder];
138 void callback(void *data, Uint8 *buf, int len){
139 int pos = 0;
140 int buffer_left = len;
141 s8 *out;
142 out = (s8*) buf;
143 while(buffer_left > 0){
144 //LOG(buffer_left, i);
145 if(samples_left <= 0){
146 //CHECK(1);
147 process_tick();
148 samples_left = samples_per_tick;
149 //CHECK(ifstatement);
150 //LOG(buffer_left, i);
151 //LOG(samples_left, i);
153 while((buffer_left > 0) && (samples_left > 0)){
154 //for some reason i dont have to add 128 when i am using unsigned audio anymore ??
155 out[pos] += mix();
156 //out[pos] = (get_sample(&mix_channels[2]) * mix_channels[2].vol / volume_levels) + 128;
157 //out[pos] = get_sample(&mix_channels[3]) + 128;
158 //LOG(mix_channels[3].currsample + 1, x);
159 //LOG(out[pos], i);
160 pos += 1;
161 buffer_left -= 1;
162 samples_left -= 1;
167 int sdl_init(void){
169 if(SDL_Init(SDL_INIT_AUDIO) < 0){
170 printf("couldn't init SDL: %s\n", SDL_GetError());
171 SDL_Quit();
172 return 1;
175 requested.freq = FREQ;
176 requested.format = AUDIO_S8;
177 requested.samples = 1024;
178 requested.channels = 1;
179 requested.callback = callback;
181 SDL_OpenAudio(&requested, &obtained);
183 fprintf(stderr, "freq %d\n", obtained.freq);
184 if(obtained.format == 0x0008)
185 fprintf(stderr, "format: AUDIO_U8\n");
186 else if(obtained.format == 0x8008)
187 fprintf(stderr, "format: AUDIO_S8\n");
188 fprintf(stderr, "samples:%d\n", obtained.samples);
189 fprintf(stderr, "channels:%d\n", obtained.channels);
191 return 0;
194 int main(int argc, char **argv){
195 FILE *modfile;
196 FILE *samplefile;
197 int i;
198 int trash;
199 u8 highestPattern = 0;
201 const u16 octave1Period[12] = {
202 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453
205 /*const u16 period_table[60] = {
206 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906,
207 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
208 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
209 214, 202, 190, 180, 169, 160, 151, 142, 134, 127, 120, 113,
210 107, 101, 95, 90, 84, 80, 75, 71, 67, 63, 60, 56
211 };*/
213 u16 periodTable[12*5];
214 u8 octave,note;
215 char sig[4];
217 for(octave = 0; octave < 5; octave++){ //12 is c-3
218 for(note = 0; note < 12; note++){
219 //*2 to get us into octave 0, then divide by 2 for each
220 // octave from there
221 periodTable[octave*12 + note] =
222 (octave1Period[note]*2) >> octave;
226 /* ~opening the modfile~ */
227 modfile = fopen(argv[1], "rb");
229 samplefile = fopen("samp.raw", "wb");
231 if(!modfile){
232 printf("Couldn't open file!\n");
233 return 1;
236 /* ~is it a mod?~ */
237 fseek(modfile, 1080, SEEK_SET);
238 fread(&sig, 1, 4, modfile);
239 if(!strcmp(sig,"M.K.")){
240 printf("not a MOD\n");
241 printf(sig);
242 exit(1);
243 }else{
244 printf("YES");
246 /* need to check for other sigs later... */
248 /* ~what's its name?~ */
249 rewind(modfile);
250 fread(modheader.name, 20, 1, modfile);
251 modheader.name[19] = '\0';
253 /* ~ load samples ~*/
254 for(i = 0; i < 31; i++){
255 fread(&modheader.sample[i], 30, 1, modfile);
256 modheader.sample[i].smpdata = NULL;
257 /* these bit shifty hacks only work because length, loopstart and
258 looplength are u16 */
259 modheader.sample[i].length =
260 ( ((modheader.sample[i].length & 0xff) << 8) |
261 (modheader.sample[i].length >> 8) ) * 2; /*just times it by two when you
262 *load it the FIRST time.
263 *most samples will fit in a u16
264 *when multiplied by two but some
265 *probably won't!*/
266 modheader.sample[i].loopstart =
267 ( ((modheader.sample[i].loopstart & 0xff) << 8) |
268 (modheader.sample[i].loopstart >> 8) ) * 2;
270 modheader.sample[i].looplength =
271 ( ((modheader.sample[i].looplength & 0xff) << 8) |
272 (modheader.sample[i].looplength >> 8) ) * 2;
275 /*~ load orders ~*/
276 fread(&modheader.orderCount, 1, 1, modfile);
278 fread(&trash, 1, 1, modfile); //useless byte
280 fread(&modheader.order, 128, 1 , modfile);
282 fread(&trash, 4, 1, modfile);
284 /*~ load patterns ~*/
285 for(i = 0; i < modheader.orderCount; i++){
286 if(modheader.order[i] > highestPattern)
287 highestPattern = modheader.order[i];
290 modheader.patternCount = highestPattern + 1;
292 // allocate space for patterns
293 modheader.patterns = malloc(sizeof(struct pattern[modheader.patternCount]));
295 if(modheader.patterns==NULL){
296 printf("out of memory!\n");
297 exit(1);
301 //initialize modheader.pattern to 0
302 /* XXX SEGFAULT */
303 //memset(modheader.pattern, 0, modheader.patternCount*sizeof(u8*));
305 u8 curPattern, row, column;
307 for(curPattern = 0; curPattern < modheader.patternCount; curPattern++){
308 //modheader.patterns[curPattern] = malloc(1024); //patterns are always 1k
309 /*modheader.patterns[curPattern] = malloc(sizeof(struct pattern));
310 if(!modheader.patterns[curPattern]){
311 printf("out of memory!\n");
314 //initialize to 0
315 memset(modheader.patterns[curPattern], 0, 1024);
318 for(row = 0; row < 64; row++){
319 for(column = 0; column < 4; column++){
320 u8 cell[4];
321 u8 sample;
322 u16 period;
323 u8 effect;
324 u8 param;
325 u8 closestNote;
327 fread(cell, 4, 1, modfile);
329 sample = (cell[0] & 0xf0) | (cell[2] >> 4);
330 period = cell[1] | ((cell[0] & 0xf) << 8);
331 effect = cell[2] & 0xf;
332 param = cell[3];
334 if(period == 0){
335 closestNote = MOD_NO_NOTE; //period 0 is no note
338 else {
339 u16 closestDist = 0xffff; //make sure the first comparison sets the closet note
340 closestNote = 0;
341 //looping through the period table
342 for(i = 0; i < 12*5; i++){
343 u16 newDist = abs(period - periodTable[i]);
344 if(newDist < closestDist){
345 closestNote = (u8)i;
346 closestDist = newDist;
351 if(sample == 0){
352 sample = MOD_NO_SAMPLE;
353 }else {
354 sample -= 1;
357 //now that we have our note, we can store the data in our new pattern
358 //calculate the address of the cell to output to
359 // rowoffset = row * 4 columns per row * 4 bytes per cell
360 // columnoffset = column * 4 bytes per cell
362 /*u8 *outCell = &modheader.pattern[curPattern][row*4*4 + column*4];
363 outCell[0] = closestNote;
364 outCell[1] = sample;
365 outCell[2] = effect;
366 outCell[3] = param;
368 modheader.patterns[curPattern].pattern_entry[row][column].period = closestNote;
369 modheader.patterns[curPattern].pattern_entry[row][column].sample = sample;
370 modheader.patterns[curPattern].pattern_entry[row][column].effect = effect;
371 modheader.patterns[curPattern].pattern_entry[row][column].param = param;
377 /* ~~ load sample datas ~~ */
378 for(i = 0; i < 31; i++){
379 int realLength = (modheader.sample[i].length);
380 if(realLength != 0){
381 modheader.sample[i].smpdata = malloc(realLength);
382 if(modheader.sample[i].smpdata != NULL){
383 fread(modheader.sample[i].smpdata, realLength, 1, modfile);
388 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
389 //done reading modfile
390 fclose(modfile);
392 fwrite(modheader.sample[30].smpdata, (modheader.sample[30].length), 1, samplefile);
394 fclose(samplefile);
396 printf("%s\n", modheader.name);
398 for(i = 0; i < 31; i++) {
399 printf("%0x: %s\n", i, modheader.sample[i].name);
400 printf("%0x: length:%x\n", i, modheader.sample[i].length);
401 printf("%0x: loopstart:%x\n", i, modheader.sample[i].loopstart);
402 printf("%0x: looplength:%x\n", i, modheader.sample[i].looplength);
405 printf("highest pattern: %i\n", highestPattern);
407 printf("orderCount: %i\n", modheader.orderCount);
409 printf("patternCount: %i\n", modheader.patternCount);
411 //printf("%i\n", sizeof(u8*[modheader.patternCount])); //36
412 //printf("%i\n", sizeof(u8*)); //4
414 /*for(i = 0; i < modheader.patternCount+1; i++)
415 for(row = 0; row < 64; row++)
416 printf("%i\n", modheader.pattern[i][row]);
419 for(i = 0; i < modheader.orderCount; i++)
420 printf("%i : %i\n", i, modheader.order[i]);
422 for(row = 0; row < 64; row++){
423 printf("%i %x %x %02x\n", modheader.patterns[0].pattern_entry[row][0].period,
424 modheader.patterns[0].pattern_entry[row][0].sample + 1,
425 modheader.patterns[0].pattern_entry[row][0].effect,
426 modheader.patterns[0].pattern_entry[row][0].param);
429 if(sdl_init() == 0){
430 init_player();
431 SDL_PauseAudio(0);
432 //while(1){
433 // update();
434 // usleep(5000);
436 getchar();
437 SDL_PauseAudio(1);
438 SDL_Quit();
441 return 0;