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 #ifndef MIN
35 #define MIN(a, b)  ( (a) < (b) ? (a) : (b) )
36 #endif
37 
38 #ifndef MAX
39 #define MAX(a, b)  ( (a) > (b) ? (a) : (b) )
40 #endif
41 
42 
43 /**
44  * Error handling
45  */
46 
error(int status,const char * format,...)47 static void error(int status, const char *format, ...)
48 {
49     va_list args;
50 
51     fflush(stdout);
52 
53     va_start(args, format);
54     vfprintf(stderr, format, args);
55     va_end(args);
56 
57     fprintf(stderr, status ? ": %s\n" : "\n", strerror(status));
58     exit(status);
59 }
60 
61 
62 /**
63  * Parameters
64  */
65 
66 struct parameters {
67     const char *fname_in;
68     const char *fname_out;
69     int bitdepth;
70     int srate_hz;
71 };
72 
parse_args(int argc,char * argv[])73 static struct parameters parse_args(int argc, char *argv[])
74 {
75     static const char *usage =
76         "Usage: %s [in_file] [wav_file]\n"
77         "\n"
78         "wav_file\t"  "Input wave file, stdin if omitted\n"
79         "out_file\t"  "Output bitstream file, stdout if omitted\n"
80         "\n"
81         "Options:\n"
82         "\t-h\t"     "Display help\n"
83         "\t-b\t"     "Output bitdepth, 16 bits (default) or 24 bits\n"
84         "\t-r\t"     "Output samplerate, default is LC3 stream samplerate\n"
85         "\n";
86 
87     struct parameters p = { .bitdepth = 16 };
88 
89     for (int iarg = 1; iarg < argc; ) {
90         const char *arg = argv[iarg++];
91 
92         if (arg[0] == '-') {
93             if (arg[2] != '\0')
94                 error(EINVAL, "Option %s", arg);
95 
96             char opt = arg[1];
97             const char *optarg;
98 
99             switch (opt) {
100                 case 'b': case 'r':
101                     if (iarg >= argc)
102                         error(EINVAL, "Argument %s", arg);
103                     optarg = argv[iarg++];
104             }
105 
106             switch (opt) {
107                 case 'h': fprintf(stderr, usage, argv[0]); exit(0);
108                 case 'b': p.bitdepth = atoi(optarg); break;
109                 case 'r': p.srate_hz = atoi(optarg); break;
110                 default:
111                     error(EINVAL, "Option %s", arg);
112             }
113 
114         } else {
115 
116             if (!p.fname_in)
117                 p.fname_in = arg;
118             else if (!p.fname_out)
119                 p.fname_out = arg;
120             else
121                 error(EINVAL, "Argument %s", arg);
122         }
123     }
124 
125     return p;
126 }
127 
128 /**
129  * Return time in (us) from unspecified point in the past
130  */
clock_us(void)131 static unsigned clock_us(void)
132 {
133     struct timespec ts;
134 
135     clock_gettime(CLOCK_REALTIME, &ts);
136 
137     return (unsigned)(ts.tv_sec * 1000*1000) + (unsigned)(ts.tv_nsec / 1000);
138 }
139 
140 /**
141  * Entry point
142  */
main(int argc,char * argv[])143 int main(int argc, char *argv[])
144 {
145     /* --- Read parameters --- */
146 
147     struct parameters p = parse_args(argc, argv);
148     FILE *fp_in = stdin, *fp_out = stdout;
149 
150     if (p.fname_in && (fp_in = fopen(p.fname_in, "rb")) == NULL)
151         error(errno, "%s", p.fname_in);
152 
153     if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL)
154         error(errno, "%s", p.fname_out);
155 
156     if (p.srate_hz && !LC3_CHECK_SR_HZ(p.srate_hz))
157         error(EINVAL, "Samplerate %d Hz", p.srate_hz);
158 
159     if (p.bitdepth && p.bitdepth != 16 && p.bitdepth != 24)
160         error(EINVAL, "Bitdepth %d", p.bitdepth);
161 
162     /* --- Check parameters --- */
163 
164     int frame_us, srate_hz, nch, nsamples;
165 
166     if (lc3bin_read_header(fp_in, &frame_us, &srate_hz, &nch, &nsamples) < 0)
167         error(EINVAL, "LC3 binary input file");
168 
169     if (nch  < 1 || nch  > 2)
170         error(EINVAL, "Number of channels %d", nch);
171 
172     if (!LC3_CHECK_DT_US(frame_us))
173         error(EINVAL, "Frame duration");
174 
175     if (!LC3_CHECK_SR_HZ(srate_hz) || (p.srate_hz && p.srate_hz < srate_hz))
176          error(EINVAL, "Samplerate %d Hz", srate_hz);
177 
178     int pcm_sbits = p.bitdepth;
179     int pcm_sbytes = pcm_sbits / 8;
180 
181     int pcm_srate_hz = !p.srate_hz ? srate_hz : p.srate_hz;
182     int pcm_samples = !p.srate_hz ? nsamples :
183         ((int64_t)nsamples * pcm_srate_hz) / srate_hz;
184 
185     wave_write_header(fp_out,
186           pcm_sbits, pcm_sbytes, pcm_srate_hz, nch, pcm_samples);
187 
188     /* --- Setup decoding --- */
189 
190     int frame_samples = lc3_frame_samples(frame_us, pcm_srate_hz);
191     int encode_samples = pcm_samples +
192         lc3_delay_samples(frame_us, pcm_srate_hz);
193 
194     lc3_decoder_t dec[nch];
195     uint8_t in[nch * LC3_MAX_FRAME_BYTES];
196     int8_t alignas(int32_t) pcm[nch * frame_samples * pcm_sbytes];
197     enum lc3_pcm_format pcm_fmt =
198         pcm_sbits == 24 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
199 
200     for (int ich = 0; ich < nch; ich++)
201         dec[ich] = lc3_setup_decoder(frame_us, srate_hz, p.srate_hz,
202             malloc(lc3_decoder_size(frame_us, pcm_srate_hz)));
203 
204     /* --- Decoding loop --- */
205 
206     static const char *dash_line = "========================================";
207 
208     int nsec = 0;
209     unsigned t0 = clock_us();
210 
211     for (int i = 0; i * frame_samples < encode_samples; i++) {
212 
213         int frame_bytes = lc3bin_read_data(fp_in, nch, in);
214 
215         if (floorf(i * frame_us * 1e-6) > nsec) {
216 
217             float progress = fminf((float)i * frame_samples / pcm_samples, 1);
218 
219             fprintf(stderr, "%02d:%02d [%-40s]\r",
220                     nsec / 60, nsec % 60,
221                     dash_line + (int)floorf((1 - progress) * 40));
222 
223             nsec = rint(i * frame_us * 1e-6);
224         }
225 
226         if (frame_bytes <= 0)
227             memset(pcm, 0, nch * frame_samples * pcm_sbytes);
228         else
229             for (int ich = 0; ich < nch; ich++)
230                 lc3_decode(dec[ich],
231                     in + ich * frame_bytes, frame_bytes,
232                     pcm_fmt, pcm + ich * pcm_sbytes, nch);
233 
234         int pcm_offset = i > 0 ? 0 : encode_samples - pcm_samples;
235         int pcm_nwrite = MIN(frame_samples - pcm_offset,
236             encode_samples - i*frame_samples);
237 
238         wave_write_pcm(fp_out, pcm_sbytes, pcm, nch, pcm_offset, pcm_nwrite);
239     }
240 
241     unsigned t = (clock_us() - t0) / 1000;
242     nsec = nsamples / srate_hz;
243 
244     fprintf(stderr, "%02d:%02d Decoded in %d.%03d seconds %20s\n",
245         nsec / 60, nsec % 60, t / 1000, t % 1000, "");
246 
247     /* --- Cleanup --- */
248 
249     for (int ich = 0; ich < nch; ich++)
250         free(dec[ich]);
251 
252     if (fp_in != stdin)
253         fclose(fp_in);
254 
255     if (fp_out != stdout)
256         fclose(fp_out);
257 }
258