1 /******************************************************************************
2  *
3  *  Copyright 2022 Google LLC
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #define _POSIX_C_SOURCE 199309L
20 
21 #include <stdalign.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <time.h>
28 #include <errno.h>
29 
30 #include <lc3.h>
31 #include "lc3bin.h"
32 #include "wave.h"
33 
34 #define MAX_CHANNELS 2
35 
36 #ifndef MIN
37 #define MIN(a, b)  ( (a) < (b) ? (a) : (b) )
38 #endif
39 
40 #ifndef MAX
41 #define MAX(a, b)  ( (a) > (b) ? (a) : (b) )
42 #endif
43 
44 
45 /**
46  * Error handling
47  */
48 
error(int status,const char * format,...)49 static void error(int status, const char *format, ...)
50 {
51     va_list args;
52 
53     fflush(stdout);
54 
55     va_start(args, format);
56     vfprintf(stderr, format, args);
57     va_end(args);
58 
59     fprintf(stderr, status ? ": %s\n" : "\n", strerror(status));
60     exit(status);
61 }
62 
63 
64 /**
65  * Parameters
66  */
67 
68 struct parameters {
69     const char *fname_in;
70     const char *fname_out;
71     int bitdepth;
72     int srate_hz;
73 };
74 
parse_args(int argc,char * argv[])75 static struct parameters parse_args(int argc, char *argv[])
76 {
77     static const char *usage =
78         "Usage: %s [wav_file] [out_file]\n"
79         "\n"
80         "wav_file\t"  "Input wave file, stdin if omitted\n"
81         "out_file\t"  "Output bitstream file, stdout if omitted\n"
82         "\n"
83         "Options:\n"
84         "\t-h\t"     "Display help\n"
85         "\t-b\t"     "Output bitdepth, 16 bits (default) or 24 bits\n"
86         "\t-r\t"     "Output samplerate, default is LC3 stream samplerate\n"
87         "\n";
88 
89     struct parameters p = { .bitdepth = 16 };
90 
91     for (int iarg = 1; iarg < argc; ) {
92         const char *arg = argv[iarg++];
93 
94         if (arg[0] == '-') {
95             if (arg[2] != '\0')
96                 error(EINVAL, "Option %s", arg);
97 
98             char opt = arg[1];
99             const char *optarg = NULL;
100 
101             switch (opt) {
102                 case 'b': case 'r':
103                     if (iarg >= argc)
104                         error(EINVAL, "Argument %s", arg);
105                     optarg = argv[iarg++];
106             }
107 
108             switch (opt) {
109                 case 'h': fprintf(stderr, usage, argv[0]); exit(0);
110                 case 'b': p.bitdepth = atoi(optarg); break;
111                 case 'r': p.srate_hz = atoi(optarg); break;
112                 default:
113                     error(EINVAL, "Option %s", arg);
114             }
115 
116         } else {
117 
118             if (!p.fname_in)
119                 p.fname_in = arg;
120             else if (!p.fname_out)
121                 p.fname_out = arg;
122             else
123                 error(EINVAL, "Argument %s", arg);
124         }
125     }
126 
127     return p;
128 }
129 
130 /**
131  * Return time in (us) from unspecified point in the past
132  */
clock_us(void)133 static unsigned clock_us(void)
134 {
135     struct timespec ts;
136 
137     clock_gettime(CLOCK_REALTIME, &ts);
138 
139     return (unsigned)(ts.tv_sec * 1000*1000) + (unsigned)(ts.tv_nsec / 1000);
140 }
141 
142 /**
143  * Entry point
144  */
main(int argc,char * argv[])145 int main(int argc, char *argv[])
146 {
147     /* --- Read parameters --- */
148 
149     struct parameters p = parse_args(argc, argv);
150     FILE *fp_in = stdin, *fp_out = stdout;
151 
152     if (p.fname_in && (fp_in = fopen(p.fname_in, "rb")) == NULL)
153         error(errno, "%s", p.fname_in);
154 
155     if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL)
156         error(errno, "%s", p.fname_out);
157 
158     if (p.bitdepth && p.bitdepth != 16 && p.bitdepth != 24)
159         error(EINVAL, "Bitdepth %d", p.bitdepth);
160 
161     /* --- Check parameters --- */
162 
163     int frame_us, srate_hz, nchannels, nsamples;
164     bool hrmode;
165 
166     if (lc3bin_read_header(fp_in,
167             &frame_us, &srate_hz, &hrmode, &nchannels, &nsamples) < 0)
168         error(EINVAL, "LC3 binary input file");
169 
170     if (nchannels < 1 || nchannels > MAX_CHANNELS)
171         error(EINVAL, "Number of channels %d", nchannels);
172 
173     if (!LC3_CHECK_DT_US(frame_us))
174         error(EINVAL, "Frame duration");
175 
176     if (!LC3_HR_CHECK_SR_HZ(hrmode, srate_hz))
177          error(EINVAL, "Samplerate %d Hz", srate_hz);
178 
179     if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(hrmode, p.srate_hz) ||
180                        p.srate_hz < srate_hz                     ))
181          error(EINVAL, "Output samplerate %d Hz", p.srate_hz);
182 
183     int pcm_sbits = p.bitdepth;
184     int pcm_sbytes = pcm_sbits / 8;
185 
186     int pcm_srate_hz = !p.srate_hz ? srate_hz : p.srate_hz;
187     int pcm_samples = !p.srate_hz ? nsamples :
188         ((int64_t)nsamples * pcm_srate_hz) / srate_hz;
189 
190     wave_write_header(fp_out,
191           pcm_sbits, pcm_sbytes, pcm_srate_hz, nchannels, pcm_samples);
192 
193     /* --- Setup decoding --- */
194 
195     uint8_t in[2 * LC3_HR_MAX_FRAME_BYTES];
196     int8_t alignas(int32_t) pcm[2 * LC3_HR_MAX_FRAME_SAMPLES*4];
197     lc3_decoder_t dec[2];
198 
199     int frame_samples = lc3_hr_frame_samples(hrmode, frame_us, pcm_srate_hz);
200     int encode_samples = pcm_samples +
201         lc3_hr_delay_samples(hrmode, frame_us, pcm_srate_hz);
202     enum lc3_pcm_format pcm_fmt =
203         pcm_sbits == 24 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
204 
205     for (int ich = 0; ich < nchannels; ich++) {
206         dec[ich] = lc3_hr_setup_decoder(
207             hrmode, frame_us, srate_hz, p.srate_hz,
208             malloc(lc3_hr_decoder_size(hrmode, frame_us, pcm_srate_hz)));
209 
210         if (!dec[ich])
211             error(EINVAL, "Decoder initialization failed");
212     }
213 
214     /* --- Decoding loop --- */
215 
216     static const char *dash_line = "========================================";
217 
218     int nsec = 0;
219     int nerr = 0;
220     unsigned t0 = clock_us();
221 
222     for (int i = 0; i * frame_samples < encode_samples; i++) {
223 
224         int block_bytes = lc3bin_read_data(fp_in, nchannels, in);
225 
226         if (floorf(i * frame_us * 1e-6) > nsec) {
227 
228             float progress = fminf((float)i * frame_samples / pcm_samples, 1);
229 
230             fprintf(stderr, "%02d:%02d [%-40s]\r",
231                     nsec / 60, nsec % 60,
232                     dash_line + (int)floorf((1 - progress) * 40));
233 
234             nsec = rint(i * frame_us * 1e-6);
235         }
236 
237         if (block_bytes <= 0)
238             memset(pcm, 0, nchannels * frame_samples * pcm_sbytes);
239         else {
240             const uint8_t *in_ptr = in;
241             for (int ich = 0; ich < nchannels; ich++) {
242                 int frame_bytes = block_bytes / nchannels
243                     + (ich < block_bytes % nchannels);
244 
245                 int res = lc3_decode(dec[ich], in_ptr, frame_bytes,
246                     pcm_fmt, pcm + ich * pcm_sbytes, nchannels);
247 
248                 nerr += (res != 0);
249                 in_ptr += frame_bytes;
250             }
251         }
252 
253         int pcm_offset = i > 0 ? 0 : encode_samples - pcm_samples;
254         int pcm_nwrite = MIN(frame_samples - pcm_offset,
255             encode_samples - i*frame_samples);
256 
257         wave_write_pcm(fp_out,
258             pcm_sbytes, pcm, nchannels, pcm_offset, pcm_nwrite);
259     }
260 
261     unsigned t = (clock_us() - t0) / 1000;
262     nsec = nsamples / srate_hz;
263 
264     fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n",
265         nsec / 60, nsec % 60, t / 1000, t % 1000, "");
266 
267     if (nerr)
268         fprintf(stderr, "Warning: Decoding of %d frames failed!\n", nerr);
269 
270     /* --- Cleanup --- */
271 
272     for (int ich = 0; ich < nchannels; ich++)
273         free(dec[ich]);
274 
275     if (fp_in != stdin)
276         fclose(fp_in);
277 
278     if (fp_out != stdout)
279         fclose(fp_out);
280 }
281