Skip to content

Commit

Permalink
Add async resampling to max rate for device using -u X (66c9585bfb4bf…
Browse files Browse the repository at this point in the history
…56056993043e298eb912027448a)

Increased squeezelite revision to v1.3-dev-255
  • Loading branch information
ralph-irving committed Jul 14, 2013
1 parent 51ebcf1 commit 0073162
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 38 deletions.
4 changes: 2 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ static void usage(const char *argv0) {
#endif
" -r <rate>\t\tMax sample rate for output device, enables output device to be off when squeezelite is started\n"
#if RESAMPLE
" -u [params]\t\tUpsample to max rate for device, params = <quality>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
" \t\t\t quality = (v|h|m|l|q)(|L|I|M)(|s),\n"
" -u [params]\t\tUpsample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
" \t\t\t recipe = (v|h|m|l|q)(|L|I|M)(|s), (|X) = async - resample to max rate for device, otherwise resample to max sync rate\n"
" \t\t\t flags = num in hex,\n"
" \t\t\t attenuation = attenuation in dB to apply (default is -1db if not explicitly set),\n"
" \t\t\t precision = number of bits precision (NB. HQ = 20. VHQ = 28),\n"
Expand Down
5 changes: 4 additions & 1 deletion output.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,14 @@ void list_devices(void) {
printf("Output devices:\n");
#ifndef PA18API
for (i = 0; i < Pa_GetDeviceCount(); ++i) {
printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name,
Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
#else
for (i = 0; i < Pa_CountDevices(); ++i) {
#endif
printf(" %i - %s\n", i, Pa_GetDeviceInfo(i)->name);
#endif
}

printf("\n");

if ((err = Pa_Terminate()) != paNoError) {
Expand Down
44 changes: 30 additions & 14 deletions process.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ void process_drain(void) {

} while (!done);

LOG_DEBUG("processing track complete - frames in: %lu out: %lu diff: %i", process.total_in, process.total_out,
process.total_in * process.sample_factor - process.total_out);
LOG_DEBUG("processing track complete - frames in: %lu out: %lu", process.total_in, process.total_out);
}

// new stream - called with decode mutex set
Expand All @@ -127,26 +126,41 @@ unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned max_

if (active) {

if (process.inbuf) free(process.inbuf);
if (process.outbuf) free(process.outbuf);
unsigned max_in_frames, max_out_frames;

process.in_frames = process.out_frames = 0;
process.total_in = process.total_out = 0;

max_in_frames = codec->min_space / BYTES_PER_FRAME ;

// increase size of output buffer by 10% as output rate is not an exact multiple of input rate
if (process.out_sample_rate % process.in_sample_rate == 0) {
max_out_frames = max_in_frames * process.out_sample_rate / process.in_sample_rate;
} else {
max_out_frames = (int)(1.1 * (float)max_in_frames * (float)process.out_sample_rate / (float)process.in_sample_rate);
}

if (process.max_in_frames != max_in_frames) {
LOG_DEBUG("creating process buf in frames: %u", max_in_frames);
if (process.inbuf) free(process.inbuf);
process.inbuf = malloc(max_in_frames * BYTES_PER_FRAME);
process.max_in_frames = max_in_frames;
}

process.inbuf = malloc(codec->min_space);
process.outbuf = malloc(codec->min_space * process.sample_factor);
if (process.max_out_frames != max_out_frames) {
LOG_DEBUG("creating process buf out frames: %u", max_out_frames);
if (process.outbuf) free(process.outbuf);
process.outbuf = malloc(max_out_frames * BYTES_PER_FRAME);
process.max_out_frames = max_out_frames;
}

if (!process.inbuf || !process.outbuf) {
LOG_ERROR("malloc fail creating process buffers");
*direct = true;
return raw_sample_rate;
}

process.sample_rate = raw_sample_rate;
process.max_in_frames = codec->min_space / BYTES_PER_FRAME ;
process.max_out_frames = codec->min_space / BYTES_PER_FRAME * process.sample_factor;

process.in_frames = process.out_frames = 0;
process.total_in = process.total_out = 0;

return raw_sample_rate * process.sample_factor;
return process.out_sample_rate;
}

return raw_sample_rate;
Expand All @@ -167,6 +181,8 @@ void process_init(char *opt) {

bool enabled = INIT_FUNC(opt);

memset(&process, 0, sizeof(process));

if (enabled) {
LOCK_D;
decode.process = true;
Expand Down
49 changes: 31 additions & 18 deletions resample.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct soxr {
void (* soxr_delete)(soxr_t);
soxr_error_t (* soxr_process)(soxr_t, soxr_in_t, size_t, size_t *, soxr_out_t, size_t olen, size_t *);
size_t *(* soxr_num_clips)(soxr_t);
bool max_rate;
};

static struct soxr *r;
Expand All @@ -74,7 +75,8 @@ void resample_samples(struct processstate *process) {

if (idone != process->in_frames) {
// should not get here if buffers are big enough...
LOG_ERROR("should not get here - partial sox process: %u of %u", (unsigned)idone, process->in_frames);
LOG_ERROR("should not get here - partial sox process: %u of %u processed %u of %u out",
(unsigned)idone, process->in_frames, (unsigned)odone, process->max_out_frames);
}

process->out_frames = odone;
Expand Down Expand Up @@ -122,11 +124,18 @@ bool resample_drain(struct processstate *process) {
}

bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned max_sample_rate) {
unsigned outrate = raw_sample_rate;
while (outrate <= max_sample_rate) outrate <<= 1;
outrate >>= 1;
unsigned outrate;

process->sample_factor = outrate / raw_sample_rate;
if (r->max_rate) {
outrate = max_sample_rate;
} else {
outrate = raw_sample_rate;
while (outrate <= max_sample_rate) outrate <<= 1;
outrate >>= 1;
}

process->in_sample_rate = raw_sample_rate;
process->out_sample_rate = outrate;

if (r->resampler) {
r->soxr_delete(r->resampler);
Expand Down Expand Up @@ -198,6 +207,7 @@ static bool load_soxr(void) {

r->resampler = NULL;
r->old_clips = 0;
r->max_rate = false;
r->soxr_io_spec = dlsym(handle, "soxr_io_spec");
r->soxr_quality_spec = dlsym(handle, "soxr_quality_spec");
r->soxr_create = dlsym(handle, "soxr_create");
Expand All @@ -215,7 +225,7 @@ static bool load_soxr(void) {
}

bool resample_init(char *opt) {
char *qual = NULL, *flags = NULL;
char *recipe = NULL, *flags = NULL;
char *atten = NULL;
char *precision = NULL, *passband_end = NULL, *stopband_begin = NULL, *phase_response = NULL;

Expand All @@ -225,7 +235,7 @@ bool resample_init(char *opt) {
}

if (opt) {
qual = next_param(opt, ':');
recipe = next_param(opt, ':');
flags = next_param(NULL, ':');
atten = next_param(NULL, ':');
precision = next_param(NULL, ':');
Expand All @@ -245,16 +255,18 @@ bool resample_init(char *opt) {
r->q_stopband_begin = 0;
r->q_phase_response = -1;

if (qual && qual[0] != '\0') {
if (strchr(qual, 'v')) r->q_recipe = SOXR_VHQ;
if (strchr(qual, 'h')) r->q_recipe = SOXR_HQ;
if (strchr(qual, 'm')) r->q_recipe = SOXR_MQ;
if (strchr(qual, 'l')) r->q_recipe = SOXR_LQ;
if (strchr(qual, 'q')) r->q_recipe = SOXR_QQ;
if (strchr(qual, 'L')) r->q_recipe |= SOXR_LINEAR_PHASE;
if (strchr(qual, 'I')) r->q_recipe |= SOXR_INTERMEDIATE_PHASE;
if (strchr(qual, 'M')) r->q_recipe |= SOXR_MINIMUM_PHASE;
if (strchr(qual, 's')) r->q_recipe |= SOXR_STEEP_FILTER;
if (recipe && recipe[0] != '\0') {
if (strchr(recipe, 'v')) r->q_recipe = SOXR_VHQ;
if (strchr(recipe, 'h')) r->q_recipe = SOXR_HQ;
if (strchr(recipe, 'm')) r->q_recipe = SOXR_MQ;
if (strchr(recipe, 'l')) r->q_recipe = SOXR_LQ;
if (strchr(recipe, 'q')) r->q_recipe = SOXR_QQ;
if (strchr(recipe, 'L')) r->q_recipe |= SOXR_LINEAR_PHASE;
if (strchr(recipe, 'I')) r->q_recipe |= SOXR_INTERMEDIATE_PHASE;
if (strchr(recipe, 'M')) r->q_recipe |= SOXR_MINIMUM_PHASE;
if (strchr(recipe, 's')) r->q_recipe |= SOXR_STEEP_FILTER;
// X = async resampling to max_rate
if (strchr(recipe, 'X')) r->max_rate = true;
}

if (flags) {
Expand Down Expand Up @@ -284,7 +296,8 @@ bool resample_init(char *opt) {
r->q_phase_response = atof(phase_response);
}

LOG_INFO("resampling enabled recipe: 0x%02x, flags: 0x%02x, scale: %03.2f, precision: %03.1f, passband_end: %03.5f, stopband_begin: %03.5f, phase_response: %03.1f",
LOG_INFO("resampling %s recipe: 0x%02x, flags: 0x%02x, scale: %03.2f, precision: %03.1f, passband_end: %03.5f, stopband_begin: %03.5f, phase_response: %03.1f",
r->max_rate ? "async" : "sync",
r->q_recipe, r->q_flags, r->scale, r->q_precision, r->q_passband_end, r->q_stopband_begin, r->q_phase_response);

return true;
Expand Down
5 changes: 2 additions & 3 deletions squeezelite.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

// make may define: PORTAUDIO, SELFPIPE or RESAMPLE to influence build

#define VERSION "v1.3-dev-254"
#define VERSION "v1.3-dev-255"

// build detection
#if defined(linux)
Expand Down Expand Up @@ -403,8 +403,7 @@ struct processstate {
u8_t *inbuf, *outbuf;
unsigned max_in_frames, max_out_frames;
unsigned in_frames, out_frames;
unsigned sample_factor;
unsigned sample_rate;
unsigned in_sample_rate, out_sample_rate;
unsigned long total_in, total_out;
};
#endif
Expand Down

0 comments on commit 0073162

Please sign in to comment.