12 double note
= 65.41; //c3
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
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){
52 modheader
.tempo
= 125;
53 samples_per_tick
= FREQ
/ (2 * modheader
.tempo
/ 5);
54 samples_left
= samples_per_tick
;
56 currpatt
= modheader
.order
[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)
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
;
72 if(chn
->smp_index
>= modheader
.sample
[chn
->currsample
].length
){
77 return modheader
.sample
[chn
->currsample
].smpdata
[(int)chn
->smp_index
] * chn
->vol
/ volume_levels
;
80 /* the worst mixer in the wurld */
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
;
90 // >>6 to divide off the volume, >>2 to divide by 4 channels to prevent overflow
94 void process_tick(void){
95 if(tick
>= modheader
.speed
){
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
;
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
;
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
;
124 modheader
.speed
= modheader
.patterns
[currpatt
].pattern_entry
[currrow
][i
].param
;
127 // mix_channels[i].vol = volume_levels;
132 if(currorder
++ >= modheader
.orderCount
)
134 currpatt
= modheader
.order
[currorder
];
138 void callback(void *data
, Uint8
*buf
, int len
){
140 int buffer_left
= len
;
143 while(buffer_left
> 0){
144 //LOG(buffer_left, i);
145 if(samples_left
<= 0){
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 ??
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);
169 if(SDL_Init(SDL_INIT_AUDIO
) < 0){
170 printf("couldn't init SDL: %s\n", SDL_GetError());
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
);
194 int main(int argc
, char **argv
){
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
213 u16 periodTable
[12*5];
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
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");
232 printf("Couldn't open file!\n");
237 fseek(modfile
, 1080, SEEK_SET
);
238 fread(&sig
, 1, 4, modfile
);
239 if(!strcmp(sig
,"M.K.")){
240 printf("not a MOD\n");
246 /* need to check for other sigs later... */
248 /* ~what's its name?~ */
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
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;
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");
301 //initialize modheader.pattern to 0
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");
315 memset(modheader.patterns[curPattern], 0, 1024);
318 for(row
= 0; row
< 64; row
++){
319 for(column
= 0; column
< 4; column
++){
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;
335 closestNote
= MOD_NO_NOTE
; //period 0 is no note
339 u16 closestDist
= 0xffff; //make sure the first comparison sets the closet note
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
){
346 closestDist
= newDist
;
352 sample
= MOD_NO_SAMPLE
;
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;
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
);
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
392 fwrite(modheader
.sample
[30].smpdata
, (modheader
.sample
[30].length
), 1, 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
);