Add save/load of doubles
[jpcrr.git] / streamtools / audioconvert.cpp
blob1b5dbd6f969b50fdb37be1987d472c19a3633a59
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "opl.h"
6 #include "audioconvert.hpp"
8 #define BLOCKSAMPLES 1024
9 #define SAMPLESIZE 8
10 #define OUTSAMPLESIZE 4
12 #define INLINE inline
13 #define RIFF_MAGIC 0x46464952
14 #define WAVE_MAGIC 0x45564157
15 #define FMT_MAGIC 0x20746d66
16 #define DATA_MAGIC 0x61746164
18 static short do_filter(std::vector<double>* old_input, std::vector<double>* old_output,
19 std::vector<double>& numerator, std::vector<double>& denumerator, size_t* lag, size_t delay,
20 unsigned index, double amplification, double preamp, short sample, uint64_t& clipcount)
22 double out;
23 short out2;
24 double in = (double)sample * preamp;
25 size_t nsize = numerator.size();
26 size_t dsize = denumerator.size();
28 //Save input
29 if(nsize > 1)
30 memmove(&old_input[index][1], &old_input[index][0], (nsize - 1) * sizeof(double));
31 old_input[index][0] = in;
33 size_t old_lag = lag[index];
34 if(old_lag < delay)
35 lag[index]++;
36 if(old_lag < delay)
37 return 0; //No sample yet.
39 out = 0;
40 for(size_t j = 0; j < nsize; j++)
41 out += numerator[j] * old_input[index][j];
42 for(size_t j = 1; j < dsize; j++)
43 out -= denumerator[j] * old_output[index][j];
45 //Save output. The last sample needs to wind up into index 1. Also scale by denum[0].
46 out /= denumerator[0];
47 old_output[index][0] = out;
48 if(dsize > 1)
49 memmove(&old_output[index][1], &old_output[index][0], (dsize - 1) * sizeof(double));
51 //Finally amplify and cast back.
52 out *= amplification;
53 if(out < -32768) {
54 out2 = -32768;
55 clipcount++;
56 } else if(out > 32767) {
57 out2 = 32767;
58 clipcount++;
59 } else
60 out2 = (short)out;
61 return out2;
64 static void write_little32(unsigned char* to, uint32_t value)
66 to[0] = (value) & 0xFF;
67 to[1] = (value >> 8) & 0xFF;
68 to[2] = (value >> 16) & 0xFF;
69 to[3] = (value >> 24) & 0xFF;
72 static void write_little16(unsigned char* to, uint16_t value)
74 to[0] = (value) & 0xFF;
75 to[1] = (value >> 8) & 0xFF;
78 void write_wav_header(struct converter_parameters* params, FILE* out, uint64_t samples)
80 unsigned char header[44];
81 uint32_t size1;
82 uint32_t size2;
83 if(samples == OUTPUT_MAX_UNLIMITED) {
84 size1 = 0xFFFFFFFFU;
85 size2 = 0xFFFFFFFFU;
86 } else {
87 size2 = samples << 2;
88 size1 = size2 + 36;
89 if((size2 >> 2) != samples || size1 < 36 || size1 > 0x7FFFFFFF) {
90 fprintf(stderr, "Error: Too many samples for wav file.\n");
91 exit(1);
95 write_little32(header + 0, RIFF_MAGIC); //The main RIFF header.
96 write_little32(header + 4, size1); //File size.
97 write_little32(header + 8, WAVE_MAGIC); //This is wave data.
98 write_little32(header + 12, FMT_MAGIC); //Format data.
99 write_little32(header + 16, 16); //16 bytes of format for PCM.
100 write_little16(header + 20, 1); //PCM data.
101 write_little16(header + 22, 2); //Stereo
102 write_little32(header + 24, params->output_rate); //Sample rate.
103 write_little32(header + 28, params->output_rate << 2); //Data rate.
104 write_little16(header + 32, 4); //4 bytes per sample.
105 write_little16(header + 34, 16); //16 bits.
106 write_little32(header + 36, DATA_MAGIC); //Actual data.
107 write_little32(header + 40, size2); //Data size.
108 if(fwrite(header, 1, 44, out) < 44) {
109 fprintf(stderr, "Error: Can't write wave header.\n");
110 exit(1);
114 static void start_output_file(struct converter_parameters* params, FILE* out)
116 if(params->output_type == OUTPUT_TYPE_WAV) {
117 write_wav_header(params, out, OUTPUT_MAX_UNLIMITED);
121 static void finish_output_file(struct converter_parameters* params, FILE* out, uint64_t samples)
123 if(params->output_type == OUTPUT_TYPE_WAV) {
124 if(fseek(out, 0, SEEK_SET)) {
125 fprintf(stderr, "Warning: Can't seek output to fix wave header.");
126 } else
127 write_wav_header(params, out, samples);
129 if(fclose(out)) {
130 fprintf(stderr, "Error: Can't close output file.");
131 exit(1);
135 static short average_s(int64_t accumulator, uint64_t base, uint64_t bound)
137 if(bound <= base)
138 return 0;
139 return (short)(accumulator / (int64_t)(bound - base));
142 void audioconvert(struct converter_parameters* params, struct filter* filter)
144 unsigned char inbuf[SAMPLESIZE * BLOCKSAMPLES];
145 unsigned char outbuf[OUTSAMPLESIZE * BLOCKSAMPLES];
146 unsigned inbuf_usage = 0;
147 unsigned outbuf_usage = 0;
148 uint64_t output_time = 0;
149 uint64_t input_time = 0;
150 unsigned short active_left = 32768;
151 unsigned short active_right = 32768;
152 int64_t left_accumulator = 0;
153 int64_t right_accumulator = 0;
154 uint64_t last_accumulator_update = 0;
155 uint64_t accumulator_base = 0;
156 int rate;
157 int load_delta;
158 float left_volume = 1.0;
159 float right_volume = 1.0;
160 unsigned subsample = 0;
161 uint64_t seconds = 0;
162 uint64_t samples_in_file = 0;
163 uint64_t clipped = 0;
164 int eofd = 0;
165 int r;
167 std::vector<double>* filter_numerator_ptr = filter ? &(filter->numerator) : NULL;
168 std::vector<double>* filter_denumerator_ptr = filter ? &(filter->denumerator) : NULL;
169 std::vector<double> dummy_vector;
170 dummy_vector.push_back(1.0);
171 if(!filter_numerator_ptr || filter_numerator_ptr->size() == 0)
172 filter_numerator_ptr = &dummy_vector;
173 if(!filter_denumerator_ptr || filter_denumerator_ptr->size() == 0)
174 filter_denumerator_ptr = &dummy_vector;
176 //Define handy variables for filter stuff.
177 size_t filter_input_delay = filter ? filter->input_delay : 0;
178 std::vector<double>& filter_numerator = *filter_numerator_ptr;
179 std::vector<double>& filter_denumerator = *filter_denumerator_ptr;
180 if(filter_input_delay >= filter_numerator.size()) {
181 fprintf(stderr, "Error: Filter delay too large (not enough coefficients).\n");
182 exit(1);
185 //Old input/output buffers (also clear them).
186 size_t input_lag[2] = {0, 0};
187 std::vector<double> old_input[2];
188 std::vector<double> old_output[2];
189 old_input[0].resize(filter_numerator.size());
190 old_input[1].resize(filter_numerator.size());
191 for(size_t i = 0; i < filter_numerator.size(); i++) {
192 old_input[0][i] = 0;
193 old_input[1][i] = 0;
195 old_output[0].resize(filter_denumerator.size());
196 old_output[1].resize(filter_denumerator.size());
197 for(size_t i = 0; i < filter_denumerator.size(); i++) {
198 old_output[0][i] = 0;
199 old_output[1][i] = 0;
202 rate = params->output_rate;
203 FILE* in = params->in;
204 FILE* out = params->next_out(params->opaque);
205 if(!out) {
206 fprintf(stderr, "Error: Can't open output file.\n");
207 exit(1);
209 start_output_file(params, out);
211 if(params->input_type == INPUT_TYPE_FM) {
212 adlib_init(rate);
215 while(1) {
216 if(!eofd && inbuf_usage < BLOCKSAMPLES * SAMPLESIZE / 2) {
217 r = fread(inbuf + inbuf_usage, 1, BLOCKSAMPLES * SAMPLESIZE - inbuf_usage, in);
218 if(r < BLOCKSAMPLES * SAMPLESIZE - inbuf_usage)
219 eofd = 1;
220 inbuf_usage += (unsigned)r;
222 //Invariant: eofd || inbuf_usage == BLOCKSAMPLES.
223 if(outbuf_usage == BLOCKSAMPLES) {
224 // fprintf(stderr, "Dumping block. Input time %llu, Output time %llu.\n", input_time,
225 // output_time);
226 r = fwrite(outbuf, OUTSAMPLESIZE, BLOCKSAMPLES, out);
227 if(r < BLOCKSAMPLES) {
228 fprintf(stderr, "Error: Can't write to output file.\n");
229 exit(1);
231 samples_in_file += BLOCKSAMPLES;
232 if(samples_in_file > params->output_max) {
233 finish_output_file(params, out, samples_in_file);
234 out = params->next_out(params->opaque);
235 if(!out) {
236 fprintf(stderr, "Error: Can't open output file.\n");
237 exit(1);
239 start_output_file(params, out);
240 samples_in_file = 0;
242 outbuf_usage = 0;
244 //Invariant: outbuf_usage < BLOCKSAMPLES.
245 unsigned long delta = 0;
246 load_delta = 1;
247 if(eofd && inbuf_usage < SAMPLESIZE)
248 load_delta = 0;
250 if(load_delta)
251 delta = ((unsigned long)inbuf[0] << 24) | ((unsigned long)inbuf[1] << 16) |
252 ((unsigned long)inbuf[2] << 8) | (unsigned long)inbuf[3];
253 if(input_time + delta > output_time || !load_delta) {
254 short active_xleft, active_xright;
255 if(params->input_type == INPUT_TYPE_FM) {
256 short samples[2];
257 adlib_getsample(samples, 1);
258 active_xleft = samples[0];
259 active_xright = samples[1];
260 } else {
261 left_accumulator += (int64_t)(output_time - last_accumulator_update) *
262 (short)active_left;
263 right_accumulator += (int64_t)(output_time - last_accumulator_update) *
264 (short)active_right;
265 last_accumulator_update = output_time;
266 active_xleft = average_s(left_accumulator, accumulator_base, output_time);
267 active_xright = average_s(right_accumulator, accumulator_base, output_time);
271 active_xleft = do_filter(old_input, old_output, filter_numerator, filter_denumerator,
272 input_lag, filter_input_delay, 0, params->amplification, left_volume, active_xleft,
273 clipped);
274 active_xright = do_filter(old_input, old_output, filter_numerator, filter_denumerator,
275 input_lag, filter_input_delay, 1, params->amplification, right_volume, active_xright,
276 clipped);
278 outbuf[outbuf_usage * OUTSAMPLESIZE + 0] = (unsigned char)active_xleft;
279 outbuf[outbuf_usage * OUTSAMPLESIZE + 1] = (unsigned char)(active_xleft >> 8);
280 outbuf[outbuf_usage * OUTSAMPLESIZE + 2] = (unsigned char)active_xright;
281 outbuf[outbuf_usage * OUTSAMPLESIZE + 3] = (unsigned char)(active_xright >> 8);
282 left_accumulator = 0;
283 right_accumulator = 0;
284 accumulator_base = output_time;
285 outbuf_usage++;
286 subsample++;
287 if(subsample == (unsigned)rate) {
288 subsample = 0;
289 seconds++;
291 output_time = seconds * 1000000000 + (1000000000ULL * subsample) / rate;
292 if(!load_delta)
293 break;
294 } else if(delta == 0xFFFFFFFFUL) {
295 input_time = input_time + delta;
296 inbuf_usage -= 4;
297 memmove(inbuf, inbuf + 4, inbuf_usage);
298 } else {
299 input_time = input_time + delta;
300 if(params->input_type != INPUT_TYPE_FM) {
301 left_accumulator += (int64_t)(input_time - last_accumulator_update) *
302 (short)active_left;
303 right_accumulator += (int64_t)(input_time - last_accumulator_update) *
304 (short)active_right;
305 last_accumulator_update = input_time;
307 active_left = ((unsigned short)inbuf[4] << 8) | (unsigned short)inbuf[5];
308 active_right = ((unsigned short)inbuf[6] << 8) | (unsigned short)inbuf[7];
309 inbuf_usage -= SAMPLESIZE;
310 memmove(inbuf, inbuf + SAMPLESIZE, inbuf_usage);
311 if(params->input_type == INPUT_TYPE_FM) {
312 if(active_left & 0x800) {
313 left_volume = (float)(active_left & 0x7FF) / 255;
314 right_volume = (float)(active_right & 0x7FF) / 255;
315 fprintf(stderr, "Note: Volume now %f:%f.\n", (double)left_volume,
316 (double)right_volume);
317 } else if(active_left == 512) {
318 //RESET.
319 int i;
320 for(i = 0; i < 512; i++) {
321 adlib_write(i, 0);
323 } else if(active_left < 512) {
324 adlib_write(active_left, active_right);
325 } else {
326 fprintf(stderr, "Warning: Ignored unknown FM command: %04X/%04X\n",
327 active_left, active_right);
333 r = fwrite(outbuf, OUTSAMPLESIZE, outbuf_usage, out);
334 if(r < outbuf_usage) {
335 fprintf(stderr, "Error: Can't write to output file.\n");
336 exit(1);
338 samples_in_file += outbuf_usage;
339 outbuf_usage = 0;
340 finish_output_file(params, out, samples_in_file);
342 fclose(in);
343 fprintf(stderr, "Note: %llu samples clipped by filtering / amplification.\n",
344 (unsigned long long)clipped);