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){
96 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
;
123 samples_per_tick
= FREQ
/ (2 * modheader
.tempo
/ 5);
125 modheader
.speed
= modheader
.patterns
[currpatt
].pattern_entry
[currrow
][i
].param
;
128 // mix_channels[i].vol = volume_levels;
133 if(currorder
++ >= modheader
.orderCount
)
135 currpatt
= modheader
.order
[currorder
];
139 void callback(void *data
, Uint8
*buf
, int len
){
141 int buffer_left
= len
;
144 while(buffer_left
> 0){
145 //LOG(buffer_left, i);
146 if(samples_left
<= 0){
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 ??
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);
170 if(SDL_Init(SDL_INIT_AUDIO
) < 0){
171 printf("couldn't init SDL: %s\n", SDL_GetError());
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
);
195 int main(int argc
, char **argv
){
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
214 u16 periodTable
[12*5];
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
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");
233 printf("Couldn't open file!\n");
238 fseek(modfile
, 1080, SEEK_SET
);
239 fread(&sig
, 1, 4, modfile
);
240 if(!strcmp(sig
,"M.K.")){
241 printf("not a MOD\n");
247 /* need to check for other sigs later... */
249 /* ~what's its name?~ */
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
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;
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");
302 //initialize modheader.pattern to 0
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");
316 memset(modheader.patterns[curPattern], 0, 1024);
319 for(row
= 0; row
< 64; row
++){
320 for(column
= 0; column
< 4; column
++){
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;
336 closestNote
= MOD_NO_NOTE
; //period 0 is no note
340 u16 closestDist
= 0xffff; //make sure the first comparison sets the closet note
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
){
347 closestDist
= newDist
;
353 sample
= MOD_NO_SAMPLE
;
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;
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
);
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
393 fwrite(modheader
.sample
[30].smpdata
, (modheader
.sample
[30].length
), 1, 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
);