-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender_song.c
148 lines (127 loc) · 4.6 KB
/
render_song.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "io.h"
#include "wave.h"
typedef struct instrument_ {
unsigned waveform;
float pan;
unsigned isADSR;
float gain;
} Instrument;
void process_N(int16_t mono_buf[], int16_t mono_buf_copy[], int16_t stereo_buf[], Instrument arr_instruments[], unsigned inst_num_N, unsigned i_pos, unsigned end_pos, unsigned note, float gain) {
float freq = 440.0 * pow(2.0, ((float) note - 69.0) / 12.0);
unsigned num_samples = end_pos - i_pos;
//find instrument waveform
switch(arr_instruments[inst_num_N].waveform) {
case 0:
generate_sine_wave(&mono_buf[i_pos], num_samples, freq);
break;
case 1:
generate_square_wave(&mono_buf[i_pos], num_samples, freq);
break;
case 2:
generate_saw_wave(&mono_buf[i_pos], num_samples, freq);
break;
default:
break;
}
//apply gain
apply_gain(&mono_buf[i_pos], num_samples, gain * arr_instruments[inst_num_N].gain);
//apply ADSR (if enabled)
if (arr_instruments[inst_num_N].isADSR) {
apply_adsr_envelope(&mono_buf[i_pos], num_samples);
}
//compute pan
float pan[2];
compute_pan(arr_instruments[inst_num_N].pan, pan);
//apply pan
for (int i = 0; i < (int) num_samples; i++) {
mono_buf_copy[i + i_pos] = mono_buf[i + i_pos];
}
apply_gain(&mono_buf[i_pos], num_samples, pan[0]);
apply_gain(&mono_buf_copy[i_pos], num_samples, pan[1]);
//mix!
mix_in(&stereo_buf[i_pos * 2], 0, &mono_buf[i_pos], num_samples);
mix_in(&stereo_buf[i_pos * 2], 1, &mono_buf_copy[i_pos], num_samples);
}
int main(int argc, char ** argv) {
//error handling
if (argc!= 3) {
printf("ERROR: incorrect number of arguments");
return 1;
}
//open song input file
FILE *songinput = fopen(argv[1], "r");
//read number of samples from input file
unsigned num_samples = 0;
fscanf(songinput, " %u", &num_samples);
//create and initalize array of instruments
Instrument arr_instruments[16];
for (int i = 0; i < 16; i++) {
arr_instruments[i].waveform = 0;
arr_instruments[i].pan = 0.0f;
arr_instruments[i].isADSR = 0;
arr_instruments[i].gain = 0.2f;
}
//variables for directive case 'N'
unsigned inst_num_N = 0;
unsigned i_pos = 0;
unsigned end_pos = 0;
unsigned note = 0;
float gain = 0.0f;
int16_t * mono_buf = calloc(num_samples, (int) sizeof(int16_t));
int16_t * mono_buf_copy = calloc(num_samples, (int) sizeof(int16_t));
int16_t *stereo_buf = calloc(num_samples * 2, (int) sizeof(int16_t));
//dummy variables for fscanf (important, as fscanf doesn't work w/o these)
unsigned temp_waveform = 0;
float temp_pan = 0;
unsigned temp_isADSR = 0;
float temp_gain = 0.2f;
//begin directive
unsigned inst_num = 0;
char directive = 'Z';
int result = fscanf(songinput, " %c", &directive);
while (result != EOF) {
switch (directive) {
case 'W':
fscanf(songinput, " %u %u", &inst_num, &temp_waveform);
arr_instruments[inst_num].waveform = temp_waveform;
break;
case 'P':
fscanf(songinput, " %u %f", &inst_num, &temp_pan);
arr_instruments[inst_num].pan = temp_pan;
break;
case 'E':
fscanf(songinput, " %u %u", &inst_num, &temp_isADSR);
arr_instruments[inst_num].isADSR = temp_isADSR;
break;
case 'G':
fscanf(songinput, " %u %f", &inst_num, &temp_gain);
arr_instruments[inst_num].gain = temp_gain;
break;
case 'N':
fscanf(songinput, " %u %u %u %u %f", &inst_num_N, &i_pos, &end_pos, ¬e, &gain);
process_N(mono_buf, mono_buf_copy, stereo_buf, arr_instruments, inst_num_N, i_pos, end_pos, note, gain);
break;
default:
fatal_error("malformed expression");
break;
}
result = fscanf(songinput, " %c", &directive);
}
//open the output file and write wave header and wave info
FILE *wavfileout = fopen(argv[2], "wb");
write_wave_header(wavfileout, num_samples);
write_s16_buf(wavfileout, stereo_buf, num_samples * 2);
//free memory and close files
free(mono_buf);
free(mono_buf_copy);
free(stereo_buf);
fclose(songinput);
fclose(wavfileout);
return 0;
}