Some coding style fixes
[jpcrr.git] / streamtools / rawtoaudio2.cpp
blob98f72a7d1cae6d6d0b9c3e6e9d8b76a31b250afc
1 #include "audioconvert.hpp"
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cstring>
5 #include <cmath>
7 static FILE* open_next(void* opaque)
9 static uint64_t counter = 0;
10 char namebuffer[8192];
12 if(!counter)
13 sprintf(namebuffer, "%s", (const char*)opaque);
14 else
15 sprintf(namebuffer, "%s.%llu", (const char*)opaque, (unsigned long long)counter);
16 counter++;
17 FILE* out = fopen(namebuffer, "wb");
18 if(!out) {
19 fprintf(stderr, "Error: Can't open output '%s'.\n", namebuffer);
20 exit(1);
22 return out;
25 void usage(char* argv0)
27 fprintf(stderr, "Usage: %s <parameters>...\n", argv0);
28 fprintf(stderr, "\t--input-file=<name>: Read input from <name> (mandatory)\n");
29 fprintf(stderr, "\t--input-format=<format>: set input format\n");
30 fprintf(stderr, "\t\tpcm\tInput is digital sound data (default).\n");
31 fprintf(stderr, "\t\tfm\tInput is FM commands.\n");
32 fprintf(stderr, "\t--output-file=<name>: Write output to <name> (mandatory)\n");
33 fprintf(stderr, "\t--output-format=<format>: set output format\n");
34 fprintf(stderr, "\t\traw\tWrite raw PCM data (default).\n");
35 fprintf(stderr, "\t\twav\tWrite WAV output.\n");
36 fprintf(stderr, "\t--output-rate=<rate>: set output sample rate (default is 44100)\n");
37 fprintf(stderr, "\t--output-split=<samples>: Split output file after approximately this \n"
38 "\t\tnumber of samples is reached (default is 500M for WAV, unlimited for RAW).\n"
39 "\t\tNote that there is some slop (not larger than few tens of thoursands of\n"
40 "\t\tsamples). Prefixes 'k', 'M', 'G', etc may be used. Maximum allowed value is\n"
41 "\t\t500M for WAV, 4E for RAW. Special value 'unlimited' stands for unlimited.\n");
42 fprintf(stderr, "\t--output-gain=<dB>: Amplify output by this many dB.\n");
43 fprintf(stderr, "\t--output-attenuation=<dB>: Attenuate output by this many dB.\n");
44 fprintf(stderr, "\t--output-filter=<filter-expr>: Fiter output using specified FIR/IIR filter.\n"
45 "\t\tfilter-expr is sequence of coefficients, delimited with ','.\n"
46 "\t\tPrefixing coefficient by '=' causes it to be a0.\n"
47 "\t\tPrefixing coefficient by '/' causes it to be denumerator coefficient.\n"
48 "\t\tNumerator coefficients start at a0 or whatever is needed to make the\n"
49 "\t\tspecified coefficient a0 and increase in delay. Denumerator coefficients\n"
50 "\t\tstart at b0 and increase in delay.\n");
51 exit(1);
54 uint64_t parse_limit(const char* expr)
56 uint64_t value = 0;
57 bool should_end = false;
58 size_t len = strlen(expr);
59 if(!strcmp(expr, "unlimited"))
60 return OUTPUT_MAX_UNLIMITED;
61 for(size_t i = 0; i < len; i++) {
62 uint64_t ovalue = value;
63 uint64_t multiplier = 0;
64 int numericvalue = -1;
65 if(should_end)
66 goto bad;
67 switch(expr[i]) {
68 case '0':
69 if(!value)
70 goto bad;
71 numericvalue = 0;
72 break;
73 case '1':
74 numericvalue = 1;
75 break;
76 case '2':
77 numericvalue = 2;
78 break;
79 case '3':
80 numericvalue = 3;
81 break;
82 case '4':
83 numericvalue = 4;
84 break;
85 case '5':
86 numericvalue = 5;
87 break;
88 case '6':
89 numericvalue = 6;
90 break;
91 case '7':
92 numericvalue = 7;
93 break;
94 case '8':
95 numericvalue = 8;
96 break;
97 case '9':
98 numericvalue = 9;
99 break;
100 case 'k':
101 multiplier = 1000ULL;
102 break;
103 case 'M':
104 multiplier = 1000000ULL;
105 break;
106 case 'G':
107 multiplier = 1000000000ULL;
108 break;
109 case 'T':
110 multiplier = 1000000000000ULL;
111 break;
112 case 'P':
113 multiplier = 1000000000000000ULL;
114 break;
115 case 'E':
116 multiplier = 1000000000000000000ULL;
117 break;
118 default:
119 goto bad;
121 if(numericvalue >= 0) {
122 value = 10 * value + numericvalue;
123 if(value / 10 != ovalue)
124 goto bad;
125 ovalue = value;
127 if(multiplier > 0) {
128 value *= multiplier;
129 if(value / multiplier != ovalue)
130 goto bad;
131 should_end = true;
134 return value;
135 bad:
136 fprintf(stderr, "Error: Invalid limit '%s'\n", expr);
137 exit(1);
140 double parse_double(const char* value)
142 char* end;
143 double x = strtod(value, &end);
144 if(*end) {
145 fprintf(stderr, "Invalid number %s!\n", value);
146 exit(1);
148 return x;
151 void parse_filter(struct filter& filt, const char* value)
153 size_t lag = 0;
154 while(*value) {
155 bool denum = false;
156 if(*value == '=') {
157 filt.input_delay = lag;
158 value++;
160 if(*value == '/') {
161 denum = true;
162 value++;
164 char* end;
165 double x = strtod(value, &end);
166 if(denum)
167 filt.denumerator.push_back(x);
168 else {
169 filt.numerator.push_back(x);
170 lag++;
172 if(*end != ',' && *end) {
173 fprintf(stderr, "Error: Invalid filter expression.\n");
174 exit(1);
176 value = *end ? (end + 1) : end;
180 int main(int argc, char** argv)
182 struct converter_parameters params;
183 bool limit_set = false;
184 struct filter filt;
185 struct filter* active_filt = NULL;
186 double gain = 0;
187 filt.input_delay = 0;
188 params.opaque = NULL;
189 params.in = NULL;
190 params.next_out = open_next;
191 params.input_type = INPUT_TYPE_PCM;
192 params.output_type = OUTPUT_TYPE_RAW;
193 params.output_rate = 44100;
194 params.output_max = OUTPUT_MAX_UNLIMITED;
195 params.amplification = 1;
197 for(int i = 1; i < argc; i++) {
198 if(!strncmp(argv[i], "--input-file=", 13)) {
199 params.in = fopen(argv[i] + 13, "rb");
200 if(!params.in) {
201 fprintf(stderr, "Error: Can't open input '%s'.\n", argv[i] + 13);
202 return 1;
204 } else if(!strncmp(argv[i], "--output-file=", 14)) {
205 if(strlen(argv[i]) == 14) {
206 fprintf(stderr, "Error: Blank --output-file not allowed.\n");
207 return 1;
209 params.opaque = argv[i] + 14;
210 } else if(!strncmp(argv[i], "--input-format=", 15)) {
211 if(!strcmp(argv[i] + 15, "pcm")) {
212 params.input_type = INPUT_TYPE_PCM;
213 } else if(!strcmp(argv[i] + 15, "fm")) {
214 params.input_type = INPUT_TYPE_FM;
215 } else {
216 fprintf(stderr, "Error: Bad input format '%s'\n", argv[i] + 15);
217 return 1;
219 } else if(!strncmp(argv[i], "--output-format=", 16)) {
220 if(!strcmp(argv[i] + 16, "raw")) {
221 params.output_type = OUTPUT_TYPE_RAW;
222 if(!limit_set)
223 params.output_max = OUTPUT_MAX_UNLIMITED;
224 } else if(!strcmp(argv[i] + 16, "wav")) {
225 params.output_type = OUTPUT_TYPE_WAV;
226 if(!limit_set)
227 params.output_max = 500000000;
228 } else {
229 fprintf(stderr, "Error: Bad output format '%s'\n", argv[i] + 16);
230 return 1;
232 } else if(!strncmp(argv[i], "--output-rate=", 14)) {
233 char* endat;
234 unsigned long rate = strtoul(argv[i] + 14, &endat, 10);
235 if(*endat || rate <= 0 || rate > 1000000000) {
236 fprintf(stderr, "Error: Bad rate '%s'\n", argv[i] + 14);
237 return 1;
239 params.output_rate = rate;
240 } else if(!strncmp(argv[i], "--output-split=", 15)) {
241 params.output_max = parse_limit(argv[i] + 15);
242 limit_set = true;
243 } else if(!strncmp(argv[i], "--output-gain=", 14)) {
244 gain += parse_double(argv[i] + 14);
245 } else if(!strncmp(argv[i], "--output-attenuation=", 21)) {
246 gain -= parse_double(argv[i] + 21);
247 } else if(!strncmp(argv[i], "--output-filter=", 16)) {
248 parse_filter(filt, argv[i] + 16);
249 active_filt = &filt;
250 } else
251 usage(argv[0]);
254 if(!params.in) {
255 fprintf(stderr, "Error: --input-file is mandatory.\n");
256 exit(1);
258 if(!params.opaque) {
259 fprintf(stderr, "Error: --output-file is mandatory.\n");
260 exit(1);
262 if(params.output_type == OUTPUT_TYPE_WAV && params.output_max > 500000000) {
263 fprintf(stderr, "Error: Maximum allowed --output-split for WAV output is 500M.\n");
264 exit(1);
267 params.amplification = pow(10, gain / 10);
268 audioconvert(&params, active_filt);