Commit 630080c7 authored by Michael Smith's avatar Michael Smith

Resampling and downmixing integrated into oggenc.

Resampler contributed by Simon Hosie <gumboot@clear.net.nz>

svn path=/trunk/vorbis-tools/; revision=3330
parent 50530312
......@@ -17,7 +17,7 @@ oggenc_LDADD = @VORBISENC_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @LIBICONV@ \
oggenc_DEPENDENCIES = @SHARE_LIBS@
oggenc_SOURCES = oggenc.c audio.c encode.c platform.c \
audio.h encode.h platform.h
audio.h encode.h platform.h resample.c resample.h
debug:
$(MAKE) all CFLAGS="@DEBUG@"
......
......@@ -17,6 +17,7 @@
#include "audio.h"
#include "platform.h"
#include "i18n.h"
#include "resample.h"
#define WAV_HEADER_SIZE 44
......@@ -582,3 +583,142 @@ int raw_open(FILE *in, oe_enc_opt *opt)
opt->total_samples_per_channel = 0; /* raw mode, don't bother */
return 1;
}
typedef struct {
res_state resampler;
audio_read_func real_reader;
void *real_readdata;
float **bufs;
int channels;
int bufsize;
int done;
} resampler;
long read_resampled(void *d, float **buffer, int samples)
{
resampler *rs = d;
long in_samples;
int out_samples;
int i;
in_samples = res_push_max_input(&rs->resampler, samples);
if(in_samples > rs->bufsize)
in_samples = rs->bufsize;
in_samples = rs->real_reader(rs->real_readdata, rs->bufs, in_samples);
if(in_samples <= 0) {
if(!rs->done) {
rs->done = 1;
out_samples = res_drain(&rs->resampler, buffer);
return out_samples;
}
return 0;
}
out_samples = res_push(&rs->resampler, buffer, (float const **)rs->bufs, in_samples);
if(out_samples <= 0) {
fprintf(stderr, _("BUG: Got zero samples from resampler: your file will be truncated. Please report this.\n"));
}
return out_samples;
}
int setup_resample(oe_enc_opt *opt) {
resampler *rs = calloc(1, sizeof(resampler));
int c;
rs->bufsize = 4096; /* Shrug */
rs->real_reader = opt->read_samples;
rs->real_readdata = opt->readdata;
rs->bufs = malloc(sizeof(float *) * opt->channels);
rs->channels = opt->channels;
rs->done = 0;
if(res_init(&rs->resampler, rs->channels, opt->resamplefreq, opt->rate, RES_END))
{
fprintf(stderr, _("Couldn't initialise resampler\n"));
return -1;
}
for(c=0; c < opt->channels; c++)
rs->bufs[c] = malloc(sizeof(float) * rs->bufsize);
opt->read_samples = read_resampled;
opt->readdata = rs;
if(opt->total_samples_per_channel)
opt->total_samples_per_channel = (int)((float)opt->total_samples_per_channel *
((float)opt->resamplefreq/(float)opt->rate));
opt->rate = opt->resamplefreq;
return 0;
}
void clear_resample(oe_enc_opt *opt) {
resampler *rs = opt->readdata;
int i;
opt->read_samples = rs->real_reader;
opt->readdata = rs->real_readdata;
res_clear(&rs->resampler);
for(i = 0; i < rs->channels; i++)
free(rs->bufs[i]);
free(rs->bufs);
free(rs);
}
typedef struct {
audio_read_func real_reader;
void *real_readdata;
float **bufs;
} downmix;
long read_downmix(void *data, float **buffer, int samples)
{
downmix *d = data;
long in_samples = d->real_reader(d->real_readdata, d->bufs, samples);
int i;
for(i=0; i < in_samples; i++) {
buffer[0][i] = (d->bufs[0][i] + d->bufs[1][i])*0.5;
}
return in_samples;
}
void setup_downmix(oe_enc_opt *opt) {
downmix *d = calloc(1, sizeof(downmix));
if(opt->channels != 2) {
fprintf(stderr, "Internal error! Please report this bug.\n");
return;
}
d->bufs = malloc(2 * sizeof(float *));
d->bufs[0] = malloc(4096 * sizeof(float));
d->bufs[1] = malloc(4096 * sizeof(float));
d->real_reader = opt->read_samples;
d->real_readdata = opt->readdata;
opt->read_samples = read_downmix;
opt->readdata = d;
opt->channels = 1;
}
void clear_downmix(oe_enc_opt *opt) {
downmix *d = opt->readdata;
opt->read_samples = d->real_reader;
opt->readdata = d->real_readdata;
opt->channels = 2; /* other things in cleanup rely on this */
free(d->bufs[0]);
free(d->bufs[1]);
free(d->bufs);
free(d);
}
......@@ -5,6 +5,11 @@
#include "encode.h"
#include <stdio.h>
int setup_resample(oe_enc_opt *opt);
void clear_resample(oe_enc_opt *opt);
void setup_downmix(oe_enc_opt *opt);
void clear_downmix(oe_enc_opt *opt);
typedef struct
{
int (*id_func)(unsigned char *buf, int len); /* Returns true if can load file */
......
......@@ -73,6 +73,9 @@ typedef struct
/* Float from 0 to 1 (low->high) */
float quality;
int resamplefreq;
int downmix;
unsigned int serial;
} oe_options;
......@@ -94,6 +97,7 @@ typedef struct
long rate;
int samplesize;
int endianness;
int resamplefreq;
/* Various bitrate/quality options */
int managed;
......
......@@ -25,7 +25,7 @@
#include "i18n.h"
#define VERSION_STRING "OggEnc v0.9 (libvorbis rc3)\n"
#define VERSION_STRING "OggEnc v0.95 (libvorbis rc4)\n"
#define COPYRIGHT "(c) 2000-2002 Michael Smith <msmith@labyrinth.net.au>\n"
#define CHUNK 4096 /* We do reads, etc. in multiples of this */
......@@ -56,6 +56,8 @@ struct option long_options[] = {
{"tracknum",1,0,'N'},
{"serial",1,0,'s'},
{"managed", 0, 0, 0},
{"resample",1,0,0},
{"downmix", 0,0,0},
{NULL,0,0,0}
};
......@@ -73,7 +75,7 @@ int main(int argc, char **argv)
/* Default values */
oe_options opt = {NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL,
0, NULL, 0, NULL, 0, 0, 0,16,44100,2, 0, NULL,DEFAULT_NAMEFMT_REMOVE,
DEFAULT_NAMEFMT_REPLACE, NULL, 0, -1,128,-1,0.3,0};
DEFAULT_NAMEFMT_REPLACE, NULL, 0, -1,128,-1,0.3,0, 0,0};
int i;
char **infiles;
......@@ -286,6 +288,32 @@ int main(int argc, char **argv)
enc_opts.max_bitrate = opt.max_bitrate;
enc_opts.quality = opt.quality;
if(opt.resamplefreq && opt.resamplefreq != enc_opts.rate) {
enc_opts.resamplefreq = opt.resamplefreq;
if(setup_resample(&enc_opts)) {
errors++;
goto clear_all;
}
else if(!opt.quiet)
fprintf(stderr, _("Resampling input from %d Hz to %d Hz\n"), enc_opts.rate, opt.resamplefreq);
}
if(opt.downmix) {
if(enc_opts.channels == 2) {
setup_downmix(&enc_opts);
if(!opt.quiet)
fprintf(stderr, _("Downmixing stereo to mono\n"));
}
else {
fprintf(stderr, _("ERROR: Can't downmix except from stereo to mono\n"));
errors++;
if(opt.resamplefreq)
clear_resample(&enc_opts);
goto clear_all;
}
}
if(!enc_opts.total_samples_per_channel)
enc_opts.progress_update = update_statistics_notime;
......@@ -299,7 +327,14 @@ int main(int argc, char **argv)
if(oe_encode(&enc_opts))
errors++;
if(opt.downmix)
clear_downmix(&enc_opts);
if(opt.resamplefreq)
clear_resample(&enc_opts);
clear_all:
if(out_fn) free(out_fn);
if(opt.outfile) free(opt.outfile);
vorbis_comment_clear(&vc);
if(!opt.rawmode)
format->close_func(enc_opts.readdata);
......@@ -354,6 +389,9 @@ static void usage(void)
" instead of specifying a particular bitrate.\n"
" This is the normal mode of operation.\n"
" Fractional qualities (e.g. 2.75) are permitted\n"
" --resample n Resample input data to sampling rate n\n"
" --downmix Downmix stereo to mono. Only allowed on stereo\n"
" input.\n"
" -s, --serial Specify a serial number for the stream. If encoding\n"
" multiple files, this will be incremented for each\n"
" stream after the first.\n"
......@@ -532,7 +570,20 @@ static void parse_options(int argc, char **argv, oe_options *opt)
opt->rawmode = 1;
fprintf(stderr, _("WARNING: Raw endianness specified for non-raw data. Assuming input is raw.\n"));
}
opt->raw_endianness = atoi(optarg);
if(sscanf(optarg, "%d", &opt->raw_endianness) != 1) {
fprintf(stderr, _("WARNING: Couldn't read endianness argument \"%s\"\n"), optarg);
opt->raw_endianness = 0;
}
}
else if(!strcmp(long_options[option_index].name,
"resample")) {
if(sscanf(optarg, "%d", &opt->resamplefreq) != 1) {
fprintf(stderr, _("WARNING: Couldn't read resampling frequency \"%s\"\n"), optarg);
opt->resamplefreq = 0;
}
}
else if(!strcmp(long_options[option_index].name, "downmix")) {
opt->downmix = 1;
}
else {
fprintf(stderr, _("Internal error parsing command line options\n"));
......@@ -545,6 +596,8 @@ static void parse_options(int argc, char **argv, oe_options *opt)
opt->artist[opt->artist_count - 1] = strdup(optarg);
break;
case 'c':
if(strchr(optarg, '=') == NULL)
fprintf(stderr, _("Warning: Illegal comment used (\"%s\")\n"), optarg);
opt->comments = realloc(opt->comments, (++opt->comment_count)*sizeof(char *));
opt->comments[opt->comment_count - 1] = strdup(optarg);
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment