diff --git a/scripts/syn123-channelscaling.sh b/scripts/syn123-channelscaling.sh new file mode 100644 index 00000000..8d820466 --- /dev/null +++ b/scripts/syn123-channelscaling.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# This gives a view at the scaling of resampling runtime with channel count. +# The tested resampling mode involves 2X upsampling, lowpass, and interpolation. + +set -e + +export LANG=C +export LC_NUMERIC=C +chan_min=1 +chan_max=10 +chan_fit=3 + +out123=src/out123 +generate="--wave-freq 300 --inputrate 44100 --timelimit 4410000 -q" + +wd=$(mktemp -d channelscaling.XXXX) +echo "workdir: $wd" +for n in $(seq $chan_min $chan_max) +do + printf "generate with %d channels\n" "$n" >&2 + /usr/bin/time -f "$n\t%e" $out123 $generate -c $n --rate 44100 -t 2>&1 +done > $wd/generate.txd +for n in $(seq $chan_min $chan_max) +do + printf "resample with %d channels\n" "$n" >&2 + /usr/bin/time -f "$n\t%e" $out123 $generate -c $n --rate 44101 -t 2>&1 +done > $wd/resample.txd +txdcalc '[3]=[2]-[1,2]' $wd/generate.txd < $wd/resample.txd > $wd/resampling-overhead.txd +gpfit --plot -g=1 -r='[3:]' $wd/resampling-overhead.txd + +echo "Check results in $wd/." diff --git a/src/libsyn123/resample.c b/src/libsyn123/resample.c index cbfab9fb..f9a5f54a 100644 --- a/src/libsyn123/resample.c +++ b/src/libsyn123/resample.c @@ -739,6 +739,7 @@ static size_t decimate(struct decimator_state *rd, struct resample_data *rrd, fl } float *out = in; size_t outs = 0; +#ifndef SYN123_NO_CASES switch(rrd->channels) { case 1: for(size_t i=0; isflags |= decimate_store; } break; - default: for(size_t i=0; isflags |= decimate_store; } +#ifndef SYN123_NO_CASES } +#endif return outs; } @@ -955,6 +960,7 @@ static float df2_initval(unsigned int order, float *filter_a, float insample) // The parameter determines the number of repeated applications of the same // low pass. +#ifndef SYN123_NO_CASES #define LOWPASS_DF2_FUNCSX(times) \ \ static void lowpass##times##_df2_preemp_2x(struct resample_data *rd, float *in, size_t ins, float *out) \ @@ -1046,10 +1052,54 @@ static void lowpass##times##_df2_preemp(struct resample_data *rd, float *in, siz in += rd->channels; \ out += rd->channels; \ } \ - break; \ } \ LPF_DF2_END \ } +#else +#define LOWPASS_DF2_FUNCSX(times) \ +\ +static void lowpass##times##_df2_preemp_2x(struct resample_data *rd, float *in, size_t ins, float *out) \ +{ \ + if(!ins) \ + return; \ + LPF_DF2_BEGIN(times,in,rd->channels,) \ + PREEMP_DF2_BEGIN(in,rd->channels,); \ + for(size_t i=0; iframe, rd->channels) \ + /* Zero-stuffing! Insert zero after making up for energy loss. */ \ + for(unsigned int c=0; cchannels; ++c) \ + rd->frame[c] *= 2; \ + LPF_DF2_SAMPLE(times, rd->frame, out, rd->channels) \ + out += rd->channels; \ + for(unsigned int c=0; cchannels; ++c) \ + rd->frame[c] = 0; \ + LPF_DF2_SAMPLE(times, rd->frame, out, rd->channels) \ + out += rd->channels; \ + in += rd->channels; \ + } \ + LPF_DF2_END \ +} \ +\ +static void lowpass##times##_df2_preemp(struct resample_data *rd, float *in, size_t ins) \ +{ \ + if(!ins) \ + return; \ + float *out = in; \ + LPF_DF2_BEGIN(times, in, rd->channels,) \ + PREEMP_DF2_BEGIN(in, rd->channels,); \ + for(size_t i=0; iframe, rd->channels) \ + LPF_DF2_SAMPLE(times, rd->frame, out, rd->channels) \ + in += rd->channels; \ + out += rd->channels; \ + } \ + LPF_DF2_END \ +} +#endif + + // Need that indirection so that times is expanded properly for concatenation. #define LOWPASS_DF2_FUNCS(times) \ LOWPASS_DF2_FUNCSX(times) @@ -1130,6 +1180,7 @@ static size_t resample_opt4p4o(struct resample_data *rd, float*in if(!ins) return outs; OPT4P4O_BEGIN(in) +#ifndef SYN123_NO_CASES switch(rd->channels) { case 1: for(size_t i=0; ichannels) in += rd->channels; } +#ifndef SYN123_NO_CASES } +#endif OPT4P4O_END return outs; } @@ -1158,6 +1213,7 @@ static size_t resample_opt4p4o_2batch(struct resample_data *rd, float*in, float { size_t outs = 0; OPT4P4O_BEGIN(in) +#ifndef SYN123_NO_CASES switch(rd->channels) { case 1: for(size_t i=0; i<2*BATCH; ++i) @@ -1172,12 +1228,16 @@ static size_t resample_opt4p4o_2batch(struct resample_data *rd, float*in, float in += 2; } break; - default: for(size_t i=0; i<2*BATCH; ++i) + default: +#endif + for(size_t i=0; i<2*BATCH; ++i) { OPT4P4O_INTERPOL(in, out, outs, rd->channels) in += rd->channels; } +#ifndef SYN123_NO_CASES } +#endif OPT4P4O_END return outs; } @@ -1266,6 +1326,7 @@ static size_t resample_opt6p5o(struct resample_data *rd, float*in if(!ins) return outs; OPT6P5O_BEGIN(in) +#ifndef SYN123_NO_CASES switch(rd->channels) { case 1: for(size_t i=0; ichannels) in += rd->channels; } +#ifndef SYN123_NO_CASES } +#endif OPT6P5O_END return outs; } @@ -1296,6 +1361,7 @@ static size_t resample_opt6p5o_2batch(struct resample_data *rd, float*in { size_t outs = 0; OPT6P5O_BEGIN(in) +#ifndef SYN123_NO_CASES switch(rd->channels) { case 1: for(size_t i=0; i<2*BATCH; ++i) @@ -1310,12 +1376,16 @@ static size_t resample_opt6p5o_2batch(struct resample_data *rd, float*in in += 2; } break; - default: for(size_t i=0; i<2*BATCH; ++i) + default: +#endif + for(size_t i=0; i<2*BATCH; ++i) { OPT6P5O_INTERPOL(in, out, outs, rd->channels) in += rd->channels; } +#ifndef SYN123_NO_CASES } +#endif OPT6P5O_END return outs; } @@ -1888,7 +1958,9 @@ syn123_setup_resample( syn123_handle *sh, long inrate, long outrate rd->decim_hist = NULL; rd->channels = channels; rd->frame = NULL; +#ifndef SYN123_NO_CASES if(channels > 2) +#endif { rd->frame = malloc(sizeof(float)*channels); if(!rd->frame)