Fix deadlock in PC attach wait vs. Lua VM termination
[jpcrr.git] / streamtools / audiofilter.c
blob0b393cd7d187b57d95a2bce188d3ebb01b47a8e7
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
6 #define BLOCKSIZE 2048
7 #define SAMPLESIZE 2
8 #define CHANNELS 2
10 typedef float* float_ptr;
12 void* xmalloc(size_t size)
14 void* x = malloc(size);
15 if(!x) {
16 fprintf(stderr, "Out of memory!\n");
17 exit(1);
19 return x;
22 double tonumber(const char* value)
24 char* end;
25 double x = strtod(value, &end);
26 if(*end) {
27 fprintf(stderr, "Invalid number %s!\n", value);
28 exit(1);
30 return x;
33 int main(int argc, char** argv)
35 unsigned char iobuffer[BLOCKSIZE * SAMPLESIZE];
36 float filterbuffer[BLOCKSIZE];
37 unsigned bufferfill = 0;
38 uint64_t cut = 0;
39 uint64_t total = 0;
40 uint64_t written = 0;
41 int eof = 0;
43 float_ptr past_input[CHANNELS];
44 float_ptr past_output[CHANNELS];
45 float* input_coeffs;
46 float* output_coeffs;
47 unsigned input_size;
48 unsigned output_size;
49 unsigned input_current = 0;
50 unsigned input_lag = 0;
52 if(argc < 4) {
53 fprintf(stderr, "Syntax: %s <in> <out> <coefficients>\n", argv[0]);
54 fprintf(stderr, "<in> and <out> are raw audio data (not audio dumps).\n");
55 fprintf(stderr, "Coefficient prefixed with '#' is b0 (if none is marked so,\n");
56 fprintf(stderr, "Then the first coefficient for numerator is b0 (the coefficients\n");
57 fprintf(stderr, "are in order of increasing index). Coefficients prefixed with '/'\n");
58 fprintf(stderr, "are sent to denominator (first as a0).\n");
59 return 1;
62 input_coeffs = xmalloc(argc * sizeof(float));
63 output_coeffs = xmalloc((argc + 1) * sizeof(float));
64 for(unsigned j = 0; j < CHANNELS; j++)
65 past_input[j] = xmalloc(argc * sizeof(float));;
66 for(unsigned j = 0; j < CHANNELS; j++)
67 past_output[j] = xmalloc(argc * sizeof(float));;
69 input_size = 0;
70 output_size = 0;
72 for(int i = 3; i < argc; i++) {
73 if(argv[i][0] == '#') {
74 input_lag = input_size;
75 input_coeffs[input_size++] = tonumber(argv[i] + 1);
76 } else if(argv[i][0] == '/') {
77 output_coeffs[output_size++] = tonumber(argv[i] + 1);
78 } else
79 input_coeffs[input_size++] = tonumber(argv[i]);
82 if(output_size < 1)
83 output_coeffs[output_size++] = 1;
86 FILE* in = fopen(argv[1], "rb");
87 if(!in) {
88 fprintf(stderr, "Can't open '%s' (for input)\n", argv[1]);
89 exit(1);
91 FILE* out = fopen(argv[2], "wb");
92 if(!out) {
93 fprintf(stderr, "Can't open '%s' (for output)\n", argv[2]);
94 exit(1);
97 //Prefill the previous input and output buffers.
98 for(unsigned i = 0; i < input_size; i++)
99 for(unsigned j = 0; j < CHANNELS; j++)
100 past_input[j][i] = 0;
101 for(unsigned i = 0; i < output_size; i++)
102 for(unsigned j = 0; j < CHANNELS; j++)
103 past_output[j][i] = 0;
105 while(1) {
106 //Read the sample data.
107 int r;
108 bufferfill = 0;
109 for(unsigned i = 0; i < BLOCKSIZE; i++)
110 filterbuffer[i] = 0;
112 for(unsigned i = 0; i < BLOCKSIZE * SAMPLESIZE; i++)
113 iobuffer[i] = 0;
115 if(eof)
116 r = 0;
117 else
118 r = fread(iobuffer, SAMPLESIZE, BLOCKSIZE, in);
119 bufferfill = r;
120 total += bufferfill;
121 if(r < BLOCKSIZE) {
122 eof = 1;
125 for(unsigned i = 0; i < BLOCKSIZE; i++) {
126 short sample = ((unsigned short)iobuffer[i * SAMPLESIZE + 0]) |
127 ((unsigned short)iobuffer[i * SAMPLESIZE + 1] << 8);
128 filterbuffer[i] += (float)sample;
131 //Filter the data.
132 bufferfill = 0;
133 for(unsigned i = 0; i < BLOCKSIZE; i++) {
134 float sample = 0;
135 unsigned old_lag = input_lag;
136 int chan = i % CHANNELS;
137 if(input_size > 1)
138 memmove(past_input[chan] + 1, past_input[chan], (input_size - 1) *
139 sizeof(float));
140 past_input[chan][0] = filterbuffer[i];
141 if(chan == CHANNELS - 1 && old_lag < input_current)
142 input_lag++;
143 if(old_lag < input_current)
144 continue;
146 for(unsigned j = 0; j < input_size; j++)
147 sample += input_coeffs[j] * past_input[chan][j];
148 for(unsigned j = 1; j < output_size; j++)
149 sample -= output_coeffs[j] * past_output[chan][j - 1];
150 sample /= output_coeffs[0];
152 filterbuffer[bufferfill++] = sample;
153 if(output_size > 1)
154 memmove(past_output[chan] + 1, past_output[chan], (output_size - 1) *
155 sizeof(float));
156 past_output[chan][0] = sample;
159 if(written + bufferfill > total)
160 bufferfill = total - written;
162 //Output the data.
163 for(unsigned i = 0; i < BLOCKSIZE; i++) {
164 int sample = (int)filterbuffer[i];
165 if(sample < -32768) {
166 sample = -32768;
167 cut++;
169 if(sample > 32767) {
170 sample = 32767;
171 cut++;
173 unsigned short value = (unsigned short)sample;
174 iobuffer[i * SAMPLESIZE + 0] = (unsigned char)sample;
175 iobuffer[i * SAMPLESIZE + 1] = (unsigned char)(sample >> 8);
177 if(fwrite(iobuffer, SAMPLESIZE, bufferfill, out) < bufferfill) {
178 fprintf(stderr, "Can't write output file.\n");
179 return 1;
181 written += bufferfill;
183 if(eof && total == written)
184 break;
187 if(fclose(out)) {
188 fprintf(stderr, "Can't close output file.\n");
189 return 1;
192 if(cut)
193 fprintf(stderr, "Warning: %llu of %llu sample(s) truncated in value.\n", cut, total);