mirror of
https://github.com/google/liblc3.git
synced 2026-06-12 22:02:27 +00:00
feature: Add High-Resolution LC3 plus mode
Duplicate interfaces for HR mode spec: Remove intermediate quantized table fix: legacy lc3_frame_bytes() and lc3_resolve_bitrate() Cosmetic: rename fast_xxx math function to lc3_xxx
This commit is contained in:
+20
-12
@@ -153,17 +153,16 @@ int main(int argc, char *argv[])
|
||||
if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL)
|
||||
error(errno, "%s", p.fname_out);
|
||||
|
||||
if (p.srate_hz && !LC3_CHECK_SR_HZ(p.srate_hz))
|
||||
error(EINVAL, "Samplerate %d Hz", p.srate_hz);
|
||||
|
||||
if (p.bitdepth && p.bitdepth != 16 && p.bitdepth != 24)
|
||||
error(EINVAL, "Bitdepth %d", p.bitdepth);
|
||||
|
||||
/* --- Check parameters --- */
|
||||
|
||||
int frame_us, srate_hz, nch, nsamples;
|
||||
bool hrmode;
|
||||
|
||||
if (lc3bin_read_header(fp_in, &frame_us, &srate_hz, &nch, &nsamples) < 0)
|
||||
if (lc3bin_read_header(fp_in,
|
||||
&frame_us, &srate_hz, &hrmode, &nch, &nsamples) < 0)
|
||||
error(EINVAL, "LC3 binary input file");
|
||||
|
||||
if (nch < 1 || nch > 2)
|
||||
@@ -172,9 +171,13 @@ int main(int argc, char *argv[])
|
||||
if (!LC3_CHECK_DT_US(frame_us))
|
||||
error(EINVAL, "Frame duration");
|
||||
|
||||
if (!LC3_CHECK_SR_HZ(srate_hz) || (p.srate_hz && p.srate_hz < srate_hz))
|
||||
if (!LC3_CHECK_HR_SR_HZ(hrmode, srate_hz))
|
||||
error(EINVAL, "Samplerate %d Hz", srate_hz);
|
||||
|
||||
if (p.srate_hz && (!LC3_CHECK_HR_SR_HZ(hrmode, p.srate_hz) ||
|
||||
p.srate_hz < srate_hz ))
|
||||
error(EINVAL, "Output samplerate %d Hz", p.srate_hz);
|
||||
|
||||
int pcm_sbits = p.bitdepth;
|
||||
int pcm_sbytes = pcm_sbits / 8;
|
||||
|
||||
@@ -187,19 +190,24 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* --- Setup decoding --- */
|
||||
|
||||
uint8_t in[2 * LC3_MAX_FRAME_BYTES];
|
||||
int8_t alignas(int32_t) pcm[2 * LC3_MAX_FRAME_SAMPLES*4];
|
||||
uint8_t in[2 * LC3_MAX_HR_FRAME_BYTES];
|
||||
int8_t alignas(int32_t) pcm[2 * LC3_MAX_HR_FRAME_SAMPLES*4];
|
||||
lc3_decoder_t dec[2];
|
||||
|
||||
int frame_samples = lc3_frame_samples(frame_us, pcm_srate_hz);
|
||||
int frame_samples = lc3_hr_frame_samples(hrmode, frame_us, pcm_srate_hz);
|
||||
int encode_samples = pcm_samples +
|
||||
lc3_delay_samples(frame_us, pcm_srate_hz);
|
||||
lc3_hr_delay_samples(hrmode, frame_us, pcm_srate_hz);
|
||||
enum lc3_pcm_format pcm_fmt =
|
||||
pcm_sbits == 24 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
||||
|
||||
for (int ich = 0; ich < nch; ich++)
|
||||
dec[ich] = lc3_setup_decoder(frame_us, srate_hz, p.srate_hz,
|
||||
malloc(lc3_decoder_size(frame_us, pcm_srate_hz)));
|
||||
for (int ich = 0; ich < nch; ich++) {
|
||||
dec[ich] = lc3_hr_setup_decoder(
|
||||
hrmode, frame_us, srate_hz, p.srate_hz,
|
||||
malloc(lc3_hr_decoder_size(hrmode, frame_us, pcm_srate_hz)));
|
||||
|
||||
if (!dec[ich])
|
||||
error(EINVAL, "Decoder initialization failed");
|
||||
}
|
||||
|
||||
/* --- Decoding loop --- */
|
||||
|
||||
|
||||
+26
-13
@@ -60,6 +60,7 @@ struct parameters {
|
||||
const char *fname_out;
|
||||
float frame_ms;
|
||||
int srate_hz;
|
||||
bool hrmode;
|
||||
int bitrate;
|
||||
};
|
||||
|
||||
@@ -76,6 +77,7 @@ static struct parameters parse_args(int argc, char *argv[])
|
||||
"\t-b\t" "Bitrate in bps (mandatory)\n"
|
||||
"\t-m\t" "Frame duration in ms (default 10)\n"
|
||||
"\t-r\t" "Encoder samplerate (default is input samplerate)\n"
|
||||
"\t-H\t" "Enable high-resolution mode\n"
|
||||
"\n";
|
||||
|
||||
struct parameters p = { .frame_ms = 10 };
|
||||
@@ -102,6 +104,7 @@ static struct parameters parse_args(int argc, char *argv[])
|
||||
case 'b': p.bitrate = atoi(optarg); break;
|
||||
case 'm': p.frame_ms = atof(optarg); break;
|
||||
case 'r': p.srate_hz = atoi(optarg); break;
|
||||
case 'H': p.hrmode = true; break;
|
||||
default:
|
||||
error(EINVAL, "Option %s", arg);
|
||||
}
|
||||
@@ -152,9 +155,6 @@ int main(int argc, char *argv[])
|
||||
if (p.fname_out && (fp_out = fopen(p.fname_out, "wb")) == NULL)
|
||||
error(errno, "%s", p.fname_out);
|
||||
|
||||
if (p.srate_hz && !LC3_CHECK_SR_HZ(p.srate_hz))
|
||||
error(EINVAL, "Samplerate %d Hz", p.srate_hz);
|
||||
|
||||
/* --- Check parameters --- */
|
||||
|
||||
int frame_us = p.frame_ms * 1000;
|
||||
@@ -171,7 +171,7 @@ int main(int argc, char *argv[])
|
||||
if (!LC3_CHECK_DT_US(frame_us))
|
||||
error(EINVAL, "Frame duration");
|
||||
|
||||
if (!LC3_CHECK_SR_HZ(srate_hz) || (p.srate_hz && p.srate_hz > srate_hz))
|
||||
if (!LC3_CHECK_HR_SR_HZ(p.hrmode, srate_hz))
|
||||
error(EINVAL, "Samplerate %d Hz", srate_hz);
|
||||
|
||||
if (pcm_sbits != 16 && pcm_sbits != 24)
|
||||
@@ -184,29 +184,42 @@ int main(int argc, char *argv[])
|
||||
if (nch < 1 || nch > 2)
|
||||
error(EINVAL, "Number of channels %d", nch);
|
||||
|
||||
if (p.srate_hz && (!LC3_CHECK_HR_SR_HZ(p.hrmode, p.srate_hz) ||
|
||||
p.srate_hz > srate_hz ))
|
||||
error(EINVAL, "Encoder samplerate %d Hz", p.srate_hz);
|
||||
|
||||
int enc_srate_hz = !p.srate_hz ? srate_hz : p.srate_hz;
|
||||
int enc_samples = !p.srate_hz ? nsamples :
|
||||
((int64_t)nsamples * enc_srate_hz) / srate_hz;
|
||||
|
||||
lc3bin_write_header(fp_out,
|
||||
frame_us, enc_srate_hz, p.bitrate, nch, enc_samples);
|
||||
frame_us, enc_srate_hz, p.hrmode,
|
||||
p.bitrate, nch, enc_samples);
|
||||
|
||||
/* --- Setup encoding --- */
|
||||
|
||||
int8_t alignas(int32_t) pcm[2 * LC3_MAX_FRAME_SAMPLES*4];
|
||||
uint8_t out[2 * LC3_MAX_FRAME_BYTES];
|
||||
int8_t alignas(int32_t) pcm[2 * LC3_MAX_HR_FRAME_SAMPLES*4];
|
||||
uint8_t out[2 * LC3_MAX_HR_FRAME_BYTES];
|
||||
lc3_encoder_t enc[2];
|
||||
|
||||
int frame_bytes = lc3_frame_bytes(frame_us, p.bitrate / nch);
|
||||
int frame_samples = lc3_frame_samples(frame_us, srate_hz);
|
||||
int encode_samples = nsamples + lc3_delay_samples(frame_us, srate_hz);
|
||||
int frame_bytes = lc3_hr_frame_bytes(
|
||||
p.hrmode, frame_us, srate_hz, p.bitrate / nch);
|
||||
int frame_samples = lc3_hr_frame_samples(
|
||||
p.hrmode, frame_us, srate_hz);
|
||||
int encode_samples = nsamples + lc3_hr_delay_samples(
|
||||
p.hrmode, frame_us, srate_hz);
|
||||
enum lc3_pcm_format pcm_fmt =
|
||||
pcm_sbytes == 32/8 ? LC3_PCM_FORMAT_S24 :
|
||||
pcm_sbytes == 24/8 ? LC3_PCM_FORMAT_S24_3LE : LC3_PCM_FORMAT_S16;
|
||||
|
||||
for (int ich = 0; ich < nch; ich++)
|
||||
enc[ich] = lc3_setup_encoder(frame_us, enc_srate_hz, srate_hz,
|
||||
malloc(lc3_encoder_size(frame_us, srate_hz)));
|
||||
for (int ich = 0; ich < nch; ich++) {
|
||||
enc[ich] = lc3_hr_setup_encoder(
|
||||
p.hrmode, frame_us, enc_srate_hz, srate_hz,
|
||||
malloc(lc3_hr_encoder_size(p.hrmode, frame_us, srate_hz)));
|
||||
|
||||
if (!enc[ich])
|
||||
error(EINVAL, "Encoder initialization failed");
|
||||
}
|
||||
|
||||
/* --- Encoding loop --- */
|
||||
|
||||
|
||||
+14
-6
@@ -43,10 +43,10 @@ struct lc3bin_header {
|
||||
* Read LC3 binary header
|
||||
*/
|
||||
int lc3bin_read_header(FILE *fp,
|
||||
int *frame_us, int *srate_hz, int *nchannels, int *nsamples)
|
||||
int *frame_us, int *srate_hz, bool *hrmode, int *nchannels, int *nsamples)
|
||||
{
|
||||
struct lc3bin_header hdr;
|
||||
uint16_t hrmode = 0;
|
||||
uint16_t hdr_hrmode = 0;
|
||||
|
||||
if (fread(&hdr, sizeof(hdr), 1, fp) != 1
|
||||
|| hdr.file_id != LC3_FILE_ID
|
||||
@@ -55,15 +55,16 @@ int lc3bin_read_header(FILE *fp,
|
||||
|
||||
int num_extended_params = (hdr.header_size - sizeof(hdr)) / sizeof(uint16_t);
|
||||
if (num_extended_params >= 1 &&
|
||||
fread(&hrmode, sizeof(hrmode), 1, fp) != 1)
|
||||
fread(&hdr_hrmode, sizeof(hdr_hrmode), 1, fp) != 1)
|
||||
return -1;
|
||||
|
||||
*nchannels = hdr.channels;
|
||||
*frame_us = hdr.frame_10us * 10;
|
||||
*srate_hz = hdr.srate_100hz * 100;
|
||||
*nsamples = hdr.nsamples_low | (hdr.nsamples_high << 16);
|
||||
*hrmode = hdr_hrmode != 0;
|
||||
|
||||
if (hdr.epmode || hrmode)
|
||||
if (hdr.epmode)
|
||||
return -1;
|
||||
|
||||
fseek(fp, hdr.header_size, SEEK_SET);
|
||||
@@ -91,11 +92,15 @@ int lc3bin_read_data(FILE *fp, int nchannels, void *buffer)
|
||||
* Write LC3 binary header
|
||||
*/
|
||||
void lc3bin_write_header(FILE *fp,
|
||||
int frame_us, int srate_hz, int bitrate, int nchannels, int nsamples)
|
||||
int frame_us, int srate_hz, bool hrmode,
|
||||
int bitrate, int nchannels, int nsamples)
|
||||
{
|
||||
uint16_t hdr_hrmode = (hrmode != 0);
|
||||
|
||||
struct lc3bin_header hdr = {
|
||||
.file_id = LC3_FILE_ID,
|
||||
.header_size = sizeof(struct lc3bin_header),
|
||||
.header_size = sizeof(struct lc3bin_header) +
|
||||
(hrmode ? sizeof(hdr_hrmode) : 0),
|
||||
.srate_100hz = srate_hz / 100,
|
||||
.bitrate_100bps = bitrate / 100,
|
||||
.channels = nchannels,
|
||||
@@ -105,6 +110,9 @@ void lc3bin_write_header(FILE *fp,
|
||||
};
|
||||
|
||||
fwrite(&hdr, sizeof(hdr), 1, fp);
|
||||
|
||||
if (hrmode)
|
||||
fwrite(&hdr_hrmode, sizeof(hdr_hrmode), 1, fp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-2
@@ -29,12 +29,14 @@
|
||||
* fp Opened file, moved after header on return
|
||||
* frame_us Return frame duration, in us
|
||||
* srate_hz Return samplerate, in Hz
|
||||
* hrmode Return true when high-resolution mode enabled
|
||||
* nchannels Return number of channels
|
||||
* nsamples Return count of source samples by channels
|
||||
* return 0: Ok -1: Bad LC3 File
|
||||
*/
|
||||
int lc3bin_read_header(FILE *fp,
|
||||
int *frame_us, int *srate_hz, int *nchannels, int *nsamples);
|
||||
int *frame_us, int *srate_hz, bool *hrmode,
|
||||
int *nchannels, int *nsamples);
|
||||
|
||||
/**
|
||||
* Read LC3 block of data
|
||||
@@ -50,12 +52,14 @@ int lc3bin_read_data(FILE *fp, int nchannels, void *buffer);
|
||||
* fp Opened file, moved after header on return
|
||||
* frame_us Frame duration, in us
|
||||
* srate_hz Samplerate, in Hz
|
||||
* hrmode True when high-resolution mode enabled
|
||||
* bitrate Bitrate indication of the stream, in bps
|
||||
* nchannels Number of channels
|
||||
* nsamples Count of source samples by channels
|
||||
*/
|
||||
void lc3bin_write_header(FILE *fp,
|
||||
int frame_us, int srate_hz, int bitrate, int nchannels, int nsamples);
|
||||
int frame_us, int srate_hz, bool hrmode,
|
||||
int bitrate, int nchannels, int nsamples);
|
||||
|
||||
/**
|
||||
* Write LC3 block of data
|
||||
|
||||
+5
-3
@@ -49,7 +49,7 @@ struct wave_file {
|
||||
* Audio format statement
|
||||
* | id WAVE_FORMAT_ID
|
||||
* | size Size of the block - 8 bytes (= 16 bytes)
|
||||
* | format WAVE_FORMAT_PCM
|
||||
* | format WAVE_FORMAT_PCM or WAVE_FORMAT_EXT
|
||||
* | channels Number of channels
|
||||
* | samplerate Sampling rate
|
||||
* | byterate Bytes per secondes = `samplerate * framesize`
|
||||
@@ -58,7 +58,8 @@ struct wave_file {
|
||||
*/
|
||||
|
||||
#define WAVE_FORMAT_ID __WAVE_ID("fmt ")
|
||||
#define WAVE_FORMAT_PCM 1
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
#define WAVE_FORMAT_EXT 0xfffe
|
||||
|
||||
struct wave_format {
|
||||
uint32_t id;
|
||||
@@ -103,7 +104,8 @@ int wave_read_header(FILE *fp, int *bitdepth, int *samplesize,
|
||||
|
||||
if (fread(&format, sizeof(format), 1, fp) != 1
|
||||
|| format.id != WAVE_FORMAT_ID
|
||||
|| format.fmt != WAVE_FORMAT_PCM
|
||||
|| ( format.fmt != WAVE_FORMAT_PCM &&
|
||||
format.fmt != WAVE_FORMAT_EXT )
|
||||
|| format.channels <= 0
|
||||
|| format.samplerate <= 0
|
||||
|| format.framesize <= 0
|
||||
|
||||
Reference in New Issue
Block a user