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