1 #include "audioconvert.hpp"
7 static FILE* open_next(void* opaque
)
9 static uint64_t counter
= 0;
10 char namebuffer
[8192];
13 sprintf(namebuffer
, "%s", (const char*)opaque
);
15 sprintf(namebuffer
, "%s.%llu", (const char*)opaque
, (unsigned long long)counter
);
17 FILE* out
= fopen(namebuffer
, "wb");
19 fprintf(stderr
, "Error: Can't open output '%s'.\n", namebuffer
);
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");
54 uint64_t parse_limit(const char* expr
)
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;
101 multiplier
= 1000ULL;
104 multiplier
= 1000000ULL;
107 multiplier
= 1000000000ULL;
110 multiplier
= 1000000000000ULL;
113 multiplier
= 1000000000000000ULL;
116 multiplier
= 1000000000000000000ULL;
121 if(numericvalue
>= 0) {
122 value
= 10 * value
+ numericvalue
;
123 if(value
/ 10 != ovalue
)
129 if(value
/ multiplier
!= ovalue
)
136 fprintf(stderr
, "Error: Invalid limit '%s'\n", expr
);
140 double parse_double(const char* value
)
143 double x
= strtod(value
, &end
);
145 fprintf(stderr
, "Invalid number %s!\n", value
);
151 void parse_filter(struct filter
& filt
, const char* value
)
157 filt
.input_delay
= lag
;
165 double x
= strtod(value
, &end
);
167 filt
.denumerator
.push_back(x
);
169 filt
.numerator
.push_back(x
);
172 if(*end
!= ',' && *end
) {
173 fprintf(stderr
, "Error: Invalid filter expression.\n");
176 value
= *end
? (end
+ 1) : end
;
180 int main(int argc
, char** argv
)
182 struct converter_parameters params
;
183 bool limit_set
= false;
185 struct filter
* active_filt
= NULL
;
187 filt
.input_delay
= 0;
188 params
.opaque
= 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");
201 fprintf(stderr
, "Error: Can't open input '%s'.\n", argv
[i
] + 13);
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");
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
;
216 fprintf(stderr
, "Error: Bad input format '%s'\n", argv
[i
] + 15);
219 } else if(!strncmp(argv
[i
], "--output-format=", 16)) {
220 if(!strcmp(argv
[i
] + 16, "raw")) {
221 params
.output_type
= OUTPUT_TYPE_RAW
;
223 params
.output_max
= OUTPUT_MAX_UNLIMITED
;
224 } else if(!strcmp(argv
[i
] + 16, "wav")) {
225 params
.output_type
= OUTPUT_TYPE_WAV
;
227 params
.output_max
= 500000000;
229 fprintf(stderr
, "Error: Bad output format '%s'\n", argv
[i
] + 16);
232 } else if(!strncmp(argv
[i
], "--output-rate=", 14)) {
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);
239 params
.output_rate
= rate
;
240 } else if(!strncmp(argv
[i
], "--output-split=", 15)) {
241 params
.output_max
= parse_limit(argv
[i
] + 15);
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);
255 fprintf(stderr
, "Error: --input-file is mandatory.\n");
259 fprintf(stderr
, "Error: --output-file is mandatory.\n");
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");
267 params
.amplification
= pow(10, gain
/ 10);
268 audioconvert(¶ms
, active_filt
);