This patch adds the scripts src_std_int32.m and src_tiny_int16.m those were used to create the conversions matrices for the default and tiny profiles. The scripts call the included src_generate function that does the task with help from the filter design and coefficients export utilities.
The quality and resources consumption of SRC can be customized with this tool.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com --- tune/src/README | 36 +++++ tune/src/src_export_coef.m | 212 ++++++++++++++++++++++++++++ tune/src/src_export_defines.m | 66 +++++++++ tune/src/src_export_table_2s.m | 190 +++++++++++++++++++++++++ tune/src/src_factor1_lm.m | 44 ++++++ tune/src/src_factor2_lm.m | 155 ++++++++++++++++++++ tune/src/src_find_l0m0.m | 71 ++++++++++ tune/src/src_generate.m | 311 +++++++++++++++++++++++++++++++++++++++++ tune/src/src_get.m | 254 +++++++++++++++++++++++++++++++++ tune/src/src_param.m | 87 ++++++++++++ tune/src/src_std_int32.m | 30 ++++ tune/src/src_tiny_int16.m | 41 ++++++ 12 files changed, 1497 insertions(+) create mode 100644 tune/src/README create mode 100644 tune/src/src_export_coef.m create mode 100644 tune/src/src_export_defines.m create mode 100644 tune/src/src_export_table_2s.m create mode 100644 tune/src/src_factor1_lm.m create mode 100644 tune/src/src_factor2_lm.m create mode 100644 tune/src/src_find_l0m0.m create mode 100644 tune/src/src_generate.m create mode 100644 tune/src/src_get.m create mode 100644 tune/src/src_param.m create mode 100644 tune/src/src_std_int32.m create mode 100644 tune/src/src_tiny_int16.m
diff --git a/tune/src/README b/tune/src/README new file mode 100644 index 0000000..e135f9a --- /dev/null +++ b/tune/src/README @@ -0,0 +1,36 @@ +Sample rate converter (SRC) Setup Tools +======================================= + +This is a tool to set up SRC conversions sample rates list, define +quality related parameters, and test the C implementation for a number +of objective audio quality parameters. + +The tools need GNU Octave version 4.0.0 or later with octave-signal +package. + +src_std_int32.m +--------------- + +This script creates the default coefficient set and contains nothing +else but call for src_generate. + +src_tiny_int16.m +---------------- + +This script creates the tiny coefficient set. The script contains an +example how to customize the input/output rates matrix and in a simple +way the scale conversions quality. More controlled quality adjust can +be done by editing file src_param.m directly. Note that int16 +presentation for SRC coefficients will degrade even the default +quality. + +src_generate.m +-------------- + +Creates the header files to include to C into directory "include". A +report of create modes is written to directory "reports". The +coefficients need to be copied to directory +sof.git/src/include/sof/audio/coefficients/src. + +The default quality of SRC is defined in module src_param.m. The +quality impacts the complexity and coefficents tables size of SRC. diff --git a/tune/src/src_export_coef.m b/tune/src/src_export_coef.m new file mode 100644 index 0000000..f6fdbb4 --- /dev/null +++ b/tune/src/src_export_coef.m @@ -0,0 +1,212 @@ +function success=src_export_coef(src, ctype, vtype, hdir, profile) + +% src_export_coef - Export FIR coefficients +% +% success=src_export_coef(src, ctype, hdir, profile) +% +% src - src definition struct +% ctype - 'float','int32', or 'int24' +% vtype - 'float','int32_t' +% hdir - directory for header files +% profile - string to append to filename +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +if nargin < 5 + profile = ''; +end + +if src.L == src.M + success = 0; +else + pbi = round(src.c_pb*1e4); + sbi = round(src.c_sb*1e4); + if isempty(profile) + hfn = sprintf('%s/src_%s_%d_%d_%d_%d.h', ... + hdir, ctype, src.L, src.M, pbi, sbi); + else + hfn = sprintf('%s/src_%s_%s_%d_%d_%d_%d.h', ... + hdir, profile, ctype, src.L, src.M, pbi, sbi); + end + vfn = sprintf('src_%s_%d_%d_%d_%d_fir', ctype, src.L, src.M, pbi, sbi); + sfn = sprintf('src_%s_%d_%d_%d_%d', ctype, src.L, src.M, pbi, sbi); + + fprintf('Exporting %s ...\n', hfn); + fh = fopen(hfn, 'w'); + + switch ctype + case 'float' + fprintf(fh, 'const %s %s[%d] = {\n', ... + vtype, vfn, src.filter_length); + fprintf(fh,'\t%16.9e', src.coefs(1)); + for n=2:src.filter_length + fprintf(fh, ',\n'); + fprintf(fh,'\t%16.9e', src.coefs(n)); + end + fprintf(fh,'\n\n};'); + case 'int32' + print_int_coef(src, fh, vtype, vfn, 32); + case 'int24' + print_int_coef(src, fh, vtype, vfn, 24); + case 'int16' + print_int_coef(src, fh, vtype, vfn, 16); + otherwise + error('Unknown type %s !!!', ctype); + end + + fprintf(fh, '\n'); + switch ctype + case 'float' + fprintf(fh, 'struct src_stage %s = {\n', sfn); + fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %f,\n\t%s};\n', ... + src.idm, src.odm, src.num_of_subfilters, ... + src.subfilter_length, src.filter_length, ... + src.blk_in, src.blk_out, src.halfband, ... + src.gain, vfn); + case { 'int16' 'int24' 'int32' } + fprintf(fh, 'struct src_stage %s = {\n', sfn); + fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %d,\n\t%s};\n', ... + src.idm, src.odm, src.num_of_subfilters, ... + src.subfilter_length, src.filter_length, ... + src.blk_in, src.blk_out, src.halfband, ... + src.shift, vfn); + otherwise + error('Unknown type %s !!!', ctype); + end + %fprintf(fh, '\n'); + fclose(fh); + success = 1; +end + +end + +function print_int_coef(src, fh, vtype, vfn, nbits) + fprintf(fh, 'const %s %s[%d] = {\n', ... + vtype, vfn, src.filter_length); + + cint = coef_quant(src, nbits); + fprintf(fh,'\t%d', cint(1)); + for n=2:src.filter_length + fprintf(fh, ',\n'); + fprintf(fh,'\t%d', cint(n)); + end + fprintf(fh,'\n\n};'); +end + +function cint = coef_quant(src, nbits) + + sref = 2^(nbits-1); + pmax = sref-1; + nmin = -sref; + + if nbits > 16 + %% Round() is OK + cint0 = round(sref*src.coefs); + else + %% Prepare to optimize coefficient quantization + fs = max(src.fs1, src.fs2); + f = linspace(0, fs/2, 1000); + + %% Test sensitivity for stopband and find the most sensitive + % coefficients + sbf = linspace(src.f_sb,fs/2, 500); + n = src.filter_length; + psens = zeros(1,n); + bq0 = round(sref*src.coefs); + h = freqz(bq0/sref/src.L, 1, sbf, fs); + sb1 = 20*log10(sqrt(sum(h.*conj(h)))); + for i=1:n + bq = src.coefs; + bq(i) = round(sref*bq(i))/sref; + %tbq = bq; %tbq(i) = bq(i)+1; + h = freqz(bq, 1, sbf, fs); + psens(i) = sum(h.*conj(h)); + end + [spsens, pidx] = sort(psens, 'descend'); + + %% Test quantization in the found order + % The impact to passband is minimal so it's not tested + bi = round(sref*src.coefs); + bi0 = bi; + dl = -1:1; + nd = length(dl); + msb = zeros(1,nd); + for i=pidx + bit = bi; + for j=1:nd + bit(i) = bi(i) + dl(j); + h = freqz(bit, 1, sbf, fs); + msb(j) = sum(h.*conj(h)); + end + idx = find(msb == min(msb), 1, 'first'); + bi(i) = bi(i) + dl(idx); + end + h = freqz(bi/sref/src.L, 1, sbf, fs); + sb2 = 20*log10(sqrt(sum(h.*conj(h)))); + + %% Plot to compare + if 0 + f = linspace(0, fs/2, 1000); + h1 = freqz(src.coefs/src.L, 1, f, fs); + h2 = freqz(bq0/sref/src.L, 1, f, fs); + h3 = freqz(bi/sref/src.L, 1, f, fs); + figure; + plot(f, 20*log10(abs(h1)), f, 20*log10(abs(h2)), f, 20*log10(abs(h3))); + grid on; + fprintf('Original = %4.1f dB, optimized = %4.1f dB, delta = %4.1f dB\n', ... + sb1, sb2, sb1-sb2); + end + cint0 = bi; + end + + + %% Re-order coefficients for filter implementation + cint = zeros(src.filter_length,1); + for n = 1:src.num_of_subfilters + i11 = (n-1)*src.subfilter_length+1; + i12 = i11+src.subfilter_length-1; + cint(i11:i12) = cint0(n:src.num_of_subfilters:end); + end + + %% Done check for no overflow + max_fix = max(cint); + min_fix = min(cint); + if (max_fix > pmax) + printf('Fixed point coefficient %d exceeded %d\n.', max_fix, pmax); + error('Something went wrong!'); + end + if (min_fix < nmin) + printf('Fixed point coefficient %d exceeded %d\n.', min_fix, nmax); + error('Something went wrong!'); + end + + +end diff --git a/tune/src/src_export_defines.m b/tune/src/src_export_defines.m new file mode 100644 index 0000000..63fb4c2 --- /dev/null +++ b/tune/src/src_export_defines.m @@ -0,0 +1,66 @@ +function src_export_defines(defs, ctype, hdir, profile) + +% src_export_defines - Exports the constants to header files +% +% src_export_defines(defs, ctype, hdir) +% +% defs - defs struct +% ctype - e.g. 'int24' appended to file name +% hdir - directory for header file +% profile - string to append to file name +% + + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +if nargin < 4 + profile = ''; +end + +if isempty(profile) + hfn = sprintf('src_%s_define.h', ctype); +else + hfn = sprintf('src_%s_%s_define.h', profile, ctype); +end +fh = fopen(fullfile(hdir,hfn), 'w'); +fprintf(fh, '/* SRC constants */\n'); +fprintf(fh, '#define MAX_FIR_DELAY_SIZE %d\n', defs.fir_delay_size); +fprintf(fh, '#define MAX_OUT_DELAY_SIZE %d\n', defs.out_delay_size); +fprintf(fh, '#define MAX_BLK_IN %d\n', defs.blk_in); +fprintf(fh, '#define MAX_BLK_OUT %d\n', defs.blk_out); +fprintf(fh, '#define NUM_IN_FS %d\n', defs.num_in_fs); +fprintf(fh, '#define NUM_OUT_FS %d\n', defs.num_out_fs); +fprintf(fh, '#define STAGE1_TIMES_MAX %d\n', defs.stage1_times_max); +fprintf(fh, '#define STAGE2_TIMES_MAX %d\n', defs.stage2_times_max); +fprintf(fh, '#define STAGE_BUF_SIZE %d\n', defs.stage_buf_size); +fprintf(fh, '#define NUM_ALL_COEFFICIENTS %d\n', defs.sum_filter_lengths); +fclose(fh); + +end diff --git a/tune/src/src_export_table_2s.m b/tune/src/src_export_table_2s.m new file mode 100644 index 0000000..7772b93 --- /dev/null +++ b/tune/src/src_export_table_2s.m @@ -0,0 +1,190 @@ +function sfl = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ... + pb_2s, sb_2s, taps_2s, ctype, vtype, ppath, hdir, profile) + +% src_export_table_2s - Export src setup table +% +% src_export_table_2s(fs_in, fs_out, l, m, pb, sb, ctype, vtype, hdir, profile) +% +% The parameters are used to differentiate files for possibly many same +% conversion factor filters with possibly different characteristic. +% +% fs_in - input sample rates +% fs_out - output sample rates +% l - interpolation factors +% m - decimation factors +% pb - passband widths +% sb - stopband start frequencies +% ctype - coefficient quantization +% vtype - C variable type +% ppath - print directory prefix to header file name include +% hdir - directory for header files +% profile - string to append to file name +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +if nargin < 12 + profile = ''; +end + +if isempty(profile) + hfn = sprintf('src_%s_table.h', ctype); +else + hfn = sprintf('src_%s_%s_table.h', profile, ctype); +end +fh = fopen(fullfile(hdir,hfn), 'w'); + +fprintf(fh, '/* SRC conversions */\n'); +sfl = 0; +n_in = length(fs_in); +n_out = length(fs_out); +i=1; +all_modes = zeros(2*n_in*n_out, 7); +for n=1:2 + for b=1:n_out + for a=1:n_in + all_modes(i,:) = [ l_2s(n,a,b) m_2s(n,a,b) ... + pb_2s(n,a,b) sb_2s(n,a,b) n a b ]; + i=i+1; + end + end +end + +all_modes_sub = all_modes(:,1:4); +[unique_modes, ia] = unique(all_modes_sub,'rows'); +sm = size(unique_modes); + +if isempty(profile) + prof_ctype = ctype; +else + prof_ctype = sprintf('%s_%s', profile, ctype); +end +for i=1:sm(1) + um_tmp = unique_modes(i,:); + if isequal(um_tmp(1:2),[1 1]) || isequal(um_tmp(1:2),[0 0]) + else + fprintf(fh, '#include <%ssrc_%s_%d_%d_%d_%d.h>\n', ... + ppath, prof_ctype, um_tmp(1:4)); + + n = all_modes(ia(i), 5); + a = all_modes(ia(i), 6); + b = all_modes(ia(i), 7); + sfl = sfl +taps_2s(n, a, b); % Count sum of filter lengths + end +end +fprintf(fh,'\n'); + +fprintf(fh, '/* SRC table */\n'); +switch ctype + case 'float' + fprintf(fh, '%s fir_one = 1.0;\n', vtype); + fprintf(fh, 'struct src_stage src_double_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, 1.0, &fir_one };\n'); + fprintf(fh, 'struct src_stage src_double_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0.0, &fir_one };\n'); + case 'int16' + scale16 = 2^15; + fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale16*0.5)); + fprintf(fh, 'struct src_stage src_int16_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'struct src_stage src_int16_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + case 'int24' + scale24 = 2^23; + fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale24*0.5)); + fprintf(fh, 'struct src_stage src_int24_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'struct src_stage src_int24_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + case 'int32' + scale32 = 2^31; + fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale32*0.5)); + fprintf(fh, 'struct src_stage src_int32_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n'); + fprintf(fh, 'struct src_stage src_int32_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n'); + otherwise + error('Unknown coefficient type!'); +end + +fprintf(fh, 'int src_in_fs[%d] = {', n_in); +j = 1; +for i=1:n_in + fprintf(fh, ' %d', fs_in(i)); + if i < n_in + fprintf(fh, ','); + end + j = j + 1; + if (j > 8) + fprintf(fh, '\n\t'); + j = 1; + end +end +fprintf(fh, '};\n'); + +fprintf(fh, 'int src_out_fs[%d] = {', n_out); +j = 1; +for i=1:n_out + fprintf(fh, ' %d', fs_out(i)); + if i < n_out + fprintf(fh, ','); + end + j = j + 1; + if (j > 8) + fprintf(fh, '\n\t'); + j = 1; + end +end +fprintf(fh, '};\n'); + +for n = 1:2 + fprintf(fh, 'struct src_stage *src_table%d[%d][%d] = {\n', ... + n, n_out, n_in); + i = 1; + for b = 1:n_out + fprintf(fh, '\t{'); + for a = 1:n_in + fprintf(fh, ' &src_%s_%d_%d_%d_%d', ... + ctype, l_2s(n,a,b), m_2s(n,a,b), ... + pb_2s(n,a,b), sb_2s(n,a,b)); + if a < n_in + fprintf(fh, ','); + end + i = i + 1; + if i > 2 + fprintf(fh, '\n\t'); + i = 1; + end + end + fprintf(fh, '}'); + if b < n_out + fprintf(fh, ',\n'); + else + fprintf(fh, '\n'); + end + end + fprintf(fh, '};\n'); +end + +fclose(fh); + +end diff --git a/tune/src/src_factor1_lm.m b/tune/src/src_factor1_lm.m new file mode 100644 index 0000000..54e9173 --- /dev/null +++ b/tune/src/src_factor1_lm.m @@ -0,0 +1,44 @@ +function [l, m] = src_factor1_lm(fs1, fs2) + +% factor1_lm - factorize input and output sample rates ratio to fraction l/m +% +% [l, m] = factor1_lm(fs1, fs2) +% +% fs1 - input sample rate +% fs2 - output sample rate +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +k = gcd(fs1, fs2); +l = fs2/k; +m = fs1/k; + +end diff --git a/tune/src/src_factor2_lm.m b/tune/src/src_factor2_lm.m new file mode 100644 index 0000000..6ac8602 --- /dev/null +++ b/tune/src/src_factor2_lm.m @@ -0,0 +1,155 @@ +function [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2) + +% factor2_lm - factorize input and output sample rates ratio to fraction l1/m2*l2/m2 +% +% [l1, m1, l2, m2] = factor2_lm(fs1, fs2) +% +% fs1 - input sample rate +% fs2 - output sample rate +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + + +%% The same sample rate? +if abs(fs1-fs2) < eps + l1 = 1; m1 = 1; l2 = 1; m2 = 1; + return +end + +%% Find fraction, and factorize +k = gcd(fs1, fs2); +l = fs2/k; +m = fs1/k; +[l01, l02] = factor2(l); +[m01, m02] = factor2(m); + +%% Hand fixing for some ratios, guide to reuse some common filters +if (l==147) && (m==640) + l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 192 to 44.1 +end +if (l==147) && (m==320) + l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 96 to 44.1 +end +if (l==147) && (m==160) + l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 48 to 44.1 +end +if (l==160) && (m==147) + l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 48 +end +if (l==320) && (m==147) + l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 96 +end +if (l==4) && (m==3) + l01 = 4; m01 = 3; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage +end +if (l==3) && (m==4) + l01 = 3; m01 = 4; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage +end + + +r11 = l01/m01; +r22 = l02/m02; +r12 = l01/m02; +r21 = l02/m01; +fs3 = [r11 r12 r21 r22].*fs1; + + +if fs1 > fs2 % Decrease sample rate, dont go below output rate + idx = find(fs3 >= fs2); + if length(idx) < 1 + error('Cant factorise interpolations'); + end + fs3_possible = fs3(idx); + delta = fs3_possible-fs2; % Fs3 that is nearest to fs2 + idx = find(delta == min(delta), 1, 'first'); + fs3_min = fs3_possible(idx); + idx = find(fs3 == fs3_min, 1, 'first'); + switch idx + case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02; + case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01; + case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02; + case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01; + end +else % Increase sample rate, don't go below input rate + idx = find(fs3 >= fs1); + if length(idx) < 1 + error('Cant factorise interpolations'); + end + fs3_possible = fs3(idx); + delta = fs3_possible-fs1; % Fs2 that is nearest to fs1 + idx = find(delta == min(delta), 1, 'first'); + fs3_min = fs3_possible(idx); + idx = find(fs3 == fs3_min, 1, 'first'); + switch idx + case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02; + case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01; + case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02; + case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01; + end +end + +%% If 1st stage is 1:1 +if (l1 == 1) && (m1 == 1) + l1 = l2; + m1 = m2; + l2 = 1; + m2 = 1; +end + +f1=l/m; +f2=l1/m1*l2/m2; +if abs(f1 - f2) > 1e-6 + error('Bug in factorization code!'); +end + +end + + +function [a, b]=factor2(c) +x = round(sqrt(c)); +t1 = x:2*x; +d1 = c./t1; +idx1 = find(d1 == floor(d1), 1, 'first'); +a1 = t1(idx1); +t2 = x:-1:floor(x/2); +d2 = c./t2; +idx2 = find(d2 == floor(d2), 1, 'first'); +a2 = t2(idx2); +if (a1-x) < (x-a2) + a = a1; +else + a = a2; +end +b = c/a; +end + + + diff --git a/tune/src/src_find_l0m0.m b/tune/src/src_find_l0m0.m new file mode 100644 index 0000000..2a360a3 --- /dev/null +++ b/tune/src/src_find_l0m0.m @@ -0,0 +1,71 @@ +function [l0, m0] = src_find_l0m0(L, M) + +% find_l0m0 - find l0, m0 to meet -l0*L + m0*M == 1 +% +% [l0, m0] = find_l0m0(L, M) +% +% L - interpolatation factor +% M - decimation factor +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +if M == 1 + l0 = 0; + m0 = 1; + return +end + +if L == 1 + l0 = 1; + m0 = 0; + return +end + +l0 = []; +m0 = []; +for lt=1:4*L + mt = (1+lt*L)/M; % Check if -lt*L + mt*M == 1 + if floor(mt) == mt + l0 = [l0 lt]; + m0 = [m0 mt]; + end +end + +s = l0+m0; +idx = find(s == min(s), 1, 'first'); +l0 = l0(idx); +m0 = m0(idx); + +if -l0*L + m0*M ~= 1 + error('Something went wrong!'); +end + +end diff --git a/tune/src/src_generate.m b/tune/src/src_generate.m new file mode 100644 index 0000000..b01b29d --- /dev/null +++ b/tune/src/src_generate.m @@ -0,0 +1,311 @@ +function src_generate(fs_in, fs_out, ctype, fs_inout, profile, qc) + +% src_generate - export src conversions for given fs_in and fs_out +% +% src_generate(fs_in, fs_out <, ctype, fs_inout>>) +% +% fs_in - vector of input sample rates (M) +% fs_out - vector of output sample rates (N) +% ctype - coefficient type, use 'int16','int24', 'int32', or 'float' +% fs_inout - matrix of supported conversions (MxN), +% 0 = no support, 1 = supported +% % +% if ctype is omitted then ctype defaults to 'int16'. +% +% If fs_inout matrix is omitted this script will compute coefficients +% for all fs_in <-> fs_out combinations. +% +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +if (nargin == 1) || (nargin > 6) + error('Incorrect arguments for function!'); +end +if nargin == 0 + %% Default input and output rates + fs_in = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3 ... + 64e3 88.2e3 96e3 176400 192e3]; + + fs_out = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3]; + + fs_inout = [ 0 0 0 1 0 0 1 1 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 1 0 0 0 0 0 1 1 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 1 0 0 1 0 0 0 1 0 1 ; ... + 1 0 0 1 0 0 1 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 1 1 1 1 0 1 1 1 1 0 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ; ... + 0 0 0 0 0 0 0 0 0 1 ]; + + ctype = 'int32'; + profile = 'std'; + qc = 1.0; +else + if nargin < 3 + ctype = 'int16'; + end + if nargin < 4 + fs_inout = ones(length(fs_in), length(fs_out)); + end + if nargin < 5 + profile = ''; + end + if nargin < 6 + qc = 1.0; + end +end + +sio = size(fs_inout); +if (length(fs_in) ~= sio(1)) || (length(fs_out) ~= sio(2)) + error('Sample rates in/out matrix size mismatch!'); +end + +%% Exported coefficients type int16, int24, int32, float + +switch ctype + case 'int16' + coef_label = 'int16'; + coef_ctype = 'int16_t'; + coef_bits = 16; + coef_bytes = 2; + case 'int24' + coef_label = 'int24'; + coef_ctype = 'int32_t'; + coef_bits = 24; + coef_bytes = 4; + case 'int32' + coef_label = 'int32'; + coef_ctype = 'int32_t'; + coef_bits = 32; + coef_bytes = 4; + case 'float' + coef_label = 'float'; coef_ctype = 'float'; + coef_bits = 24; + coef_bytes = 4; + otherwise + error('Request for incorrect coefficient type'); +end +data_bytes = 4; + +hdir = mkdir_check('include'); +rdir = mkdir_check('reports'); + +%% Find fractional conversion factors +nfsi = length(fs_in); +nfso = length(fs_out); +l_2s = zeros(2, nfsi, nfso); +m_2s = zeros(2, nfsi, nfso); +mops_2s = zeros(2, nfsi, nfso); +pb_2s = zeros(2,nfsi, nfso); +sb_2s = zeros(2,nfsi, nfso); +taps_2s = zeros(2,nfsi, nfso); +defs.fir_delay_size = 0; +defs.out_delay_size = 0; +defs.blk_in = 0; +defs.blk_out = 0; +defs.num_in_fs = nfsi; +defs.num_out_fs = nfso; +defs.stage1_times_max = 0; +defs.stage2_times_max = 0; +defs.stage_buf_size = 0; +h = 1; +for b = 1:nfso + for a = 1:nfsi + fs1 = fs_in(a); + fs2 = fs_out(b); + [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2); + fs3 = fs1*l1/m1; + cnv1 = src_param(fs1, fs3, coef_bits, qc); + cnv2 = src_param(fs3, fs2, coef_bits, qc); + if (fs2 < fs1) + % When decimating 1st stage passband can be limited + % for wider transition band + f_pb = fs2*cnv2.c_pb; + cnv1.c_pb = f_pb/min(fs1,fs3); + end + if (fs2 > fs1) + % When interpolating 2nd stage passband can be limited + % for wider transition band + f_pb = fs1*cnv1.c_pb; + cnv2.c_pb = f_pb/min(fs2,fs3); + end + if fs_inout(a,b) > 0 || (a == b) + if cnv2.fs1-cnv2.fs2 > eps + % Allow half ripple for dual stage SRC parts + cnv1.rp = cnv1.rp/2; + cnv2.rp = cnv2.rp/2; + end + src1 = src_get(cnv1); + src2 = src_get(cnv2); + k = gcd(src1.blk_out, src2.blk_in); + stage1_times = src2.blk_in/k; + stage2_times = stage1_times*src1.blk_out/src2.blk_in; + defs.stage1_times_max = max(defs.stage1_times_max, stage1_times); + defs.stage2_times_max = max(defs.stage2_times_max, stage2_times); + l_2s(:,a,b) = [src1.L src2.L]; + m_2s(:,a,b) = [src1.M src2.M]; + mops_2s(:,a,b) = [src1.MOPS src2.MOPS]; + pb_2s(:,a,b) = [round(1e4*src1.c_pb) round(1e4*src2.c_pb)]; + sb_2s(:,a,b) = [round(1e4*src1.c_sb) round(1e4*src2.c_sb)]; + taps_2s(:,a,b) = [src1.filter_length src2.filter_length]; + defs.fir_delay_size = max(defs.fir_delay_size, src1.fir_delay_size); + defs.out_delay_size = max(defs.out_delay_size, src1.out_delay_size); + defs.blk_in = max(defs.blk_in, src1.blk_in); + defs.blk_out = max(defs.blk_out, src1.blk_out); + defs.fir_delay_size = max(defs.fir_delay_size, src2.fir_delay_size); + defs.out_delay_size = max(defs.out_delay_size, src2.out_delay_size); + defs.blk_in = max(defs.blk_in, src2.blk_in); + defs.blk_out = max(defs.blk_out, src2.blk_out); + defs.stage_buf_size = max(defs.stage_buf_size, src1.blk_out*stage1_times); + src_export_coef(src1, coef_label, coef_ctype, hdir, profile); + src_export_coef(src2, coef_label, coef_ctype, hdir, profile); + end + end +end + +%% Export modes table +defs.sum_filter_lengths = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ... + pb_2s, sb_2s, taps_2s, coef_label, coef_ctype, ... + 'sof/audio/coefficients/src/', hdir, profile); +src_export_defines(defs, coef_label, hdir, profile); + +%% Print 2 stage conversion factors +fn = sprintf('%s/src_2stage.txt', rdir); +fh = fopen(fn,'w'); +fprintf(fh,'\n'); +fprintf(fh,'Dual stage fractional SRC: Ratios\n'); +fprintf(fh,'%8s, ', 'in \ out'); +for b = 1:nfso + fprintf(fh,'%12.1f, ', fs_out(b)/1e3); +end +fprintf(fh,'\n'); +for a = 1:nfsi + fprintf(fh,'%8.1f, ', fs_in(a)/1e3); + for b = 1:nfso + cstr = print_ratios(l_2s, m_2s, a, b); + fprintf(fh,'%12s, ', cstr); + end + fprintf(fh,'\n'); +end +fprintf(fh,'\n'); + +%% Print 2 stage MOPS +fprintf(fh,'Dual stage fractional SRC: MOPS\n'); +fprintf(fh,'%8s, ', 'in \ out'); +for b = 1:nfso + fprintf(fh,'%8.1f, ', fs_out(b)/1e3); +end +fprintf(fh,'\n'); +for a = 1:nfsi + fprintf(fh,'%8.1f, ', fs_in(a)/1e3); + for b = 1:nfso + mops = sum(mops_2s(:,a,b)); + if sum(l_2s(:,a,b)) < eps + mops_str = 'x'; + else + mops_str = sprintf('%.2f', mops); + end + fprintf(fh,'%8s, ', mops_str); + end + fprintf(fh,'\n'); +end +fprintf(fh,'\n'); + +%% Print 2 stage MOPS per stage +fprintf(fh,'Dual stage fractional SRC: MOPS per stage\n'); +fprintf(fh,'%10s, ', 'in \ out'); +for b = 1:nfso + fprintf(fh,'%10.1f, ', fs_out(b)/1e3); +end +fprintf(fh,'\n'); +for a = 1:nfsi + fprintf(fh,'%10.1f, ', fs_in(a)/1e3); + for b = 1:nfso + mops = mops_2s(:,a,b); + if sum(l_2s(:,a,b)) < eps + mops_str = 'x'; + else + mops_str = sprintf('%.2f+%.2f', mops(1), mops(2)); + end + fprintf(fh,'%10s, ', mops_str); + end + fprintf(fh,'\n'); +end +fprintf(fh,'\n'); + +fprintf(fh,'Coefficient RAM %.1f kB\n', ... + defs.sum_filter_lengths*coef_bytes/1024); +fprintf(fh,'Max. data RAM %.1f kB\n', ... + (defs.fir_delay_size + defs.out_delay_size+defs.stage_buf_size) ... + * data_bytes/1024); + +fprintf(fh,'\n'); +fclose(fh); +type(fn); + +end + +function d = mkdir_check(d) +if exist(d) ~= 7 + mkdir(d); +end +end + +function cstr = print_ratios(l_2s, m_2s, a, b) +l1 = l_2s(1,a,b); +m1 = m_2s(1,a,b); +l2 = l_2s(2,a,b); +m2 = m_2s(2,a,b); +if l1+m2+l2+m2 == 0 + cstr = 'x'; +else + if m2 == 1 + if l2 == 1 + cstr2 = ''; + else + cstr2 = sprintf('*%d', l2); + end + else + cstr2 = sprintf('*%d/%d', l2, m2); + end + if m1 == 1 + cstr1 = sprintf('%d', l1); + else + cstr1 = sprintf('%d/%d', l1, m1); + end + cstr = sprintf('%s%s', cstr1, cstr2); +end +end diff --git a/tune/src/src_get.m b/tune/src/src_get.m new file mode 100644 index 0000000..4520af9 --- /dev/null +++ b/tune/src/src_get.m @@ -0,0 +1,254 @@ +function src = src_get(cnv) + +% src_get - calculate coefficients for a src +% +% src = src_get(cnv); +% +% cnv - src parameters +% src - src result +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +use_firpm = 0; +use_remez = 0; +use_kaiser = 0; +switch lower(cnv.design) + case 'firpm' + if exist('OCTAVE_VERSION', 'builtin') + use_remez = 1; + else + use_firpm = 1; + end + case 'kaiser' + use_kaiser = 1; + otherwise + error('Unknown FIR design request!'); +end + +if abs(cnv.fs1-cnv.fs2) < 1 + %% Return minimum needed for scripts to work + src.L=1; + src.M=1; + src.odm=1; + src.idm=1; + src.MOPS=0; + src.c_pb = 0; + src.c_sb = 0; + src.fir_delay_size = 0; + src.out_delay_size = 0; + src.blk_in = 1; + src.blk_out = 1; + src.gain = 1; + src.filter_length = 0; + return +end + +%% fractional SRC parameters +[L, M] = src_factor1_lm(cnv.fs1, cnv.fs2); +src.L = L; +src.M = M; +src.num_of_subfilters = L; +[src.idm src.odm] = src_find_l0m0(src.L, src.M); +min_fs = min(cnv.fs1,cnv.fs2); +src.f_pb = min_fs*cnv.c_pb; +src.f_sb = min_fs*cnv.c_sb; +src.c_pb = cnv.c_pb; +src.c_sb = cnv.c_sb; +src.fs1 = cnv.fs1; +src.fs2 = cnv.fs2; +src.rp = cnv.rp; +src.rs = cnv.rs; + +%% FIR PM design +fs3 = src.L*cnv.fs1; +f = [src.f_pb src.f_sb]; +a = [1 0]; + +% Kaiser fir is not equiripple, can allow more ripple in the passband +% lower freq. +dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)]; +[kn0, kw, kbeta, kftype] = kaiserord(f, a, dev, fs3); +if use_firpm + %dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)]; + [n0,fo,ao,w] = firpmord(f,a,dev,fs3); + n0 = round(n0*0.95); % Decrease order to 95% +end +if use_remez + n0 = round(kn0*0.60); % Decrease order to 70% + fo = [0 2*f/fs3 1]; + ao = [1 1 0 0]; + w = [1 dev(1)/dev(2)]; +end +if use_kaiser + n0 = round(kn0*0.70); % Decrease order to 70% +end + +% Constrain filter length to be a suitable multiple. Multiple of +% interpolation factor ensures that all subfilters are equal length. +% Make each sub-filter order multiple of N helps in making efficient +% implementation. +nfir_increment = src.num_of_subfilters * cnv.filter_length_mult; + +nsf0 = (n0+1)/nfir_increment; +if nsf0 > floor(nsf0) + n = (floor(nsf0)+1)*nfir_increment-1; +else + n = n0; +end + +src.subfilter_length = (n+1)/src.num_of_subfilters; +src.filter_length = n+1; +nfir = n; +f_sb = linspace(src.f_sb, fs3/2, 500); +stopband_ok = 0; +need_to_stop = 0; +delta = 100; +n_worse = 0; +n_worse_max = 20; +n = 1; +n_max = 100; +dn = ones(1, n_max)*1000; +fn = zeros(1, n_max); +while (stopband_ok) == 0 && (n < n_max) + if use_firpm || use_remez + if nfir > 1800 + b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta)); + else + if use_firpm + b = firpm(nfir,fo,ao,w); + else + b = remez(nfir,fo,ao,w); + end + end + else + b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta)); + end + m_b = max(abs(b)); + %sref = 2^(cnv.coef_bits-1); + %bq = round(b*sref/m_b)*m_b/sref; + bq = b; + h_sb = freqz(bq, 1, f_sb, fs3); + m_sb = 20*log10(abs(h_sb)); + delta_prev = delta; + delta = cnv.rs+max(m_sb); + fprintf('Step=%3d, Delta=%f dB, N=%d\n', n, delta, nfir); + dn(n) = delta; + fn(n) = nfir; + if delta < 0 + stopband_ok = 1; + else + if delta_prev < delta + n_worse = n_worse+1; + if n_worse > n_worse_max + need_to_stop = 1; % No improvement, reverse + idx = find(dn == min(dn), 1, 'first'); + nfir = fn(idx); + else + nfir = nfir + nfir_increment; + end + else + if need_to_stop == 0 + nfir = nfir + nfir_increment; + else + stopband_ok = 1; % Exit after reverse + fprintf('Warning: Filter stop band could not be '); + fprintf('reached.\n', cnv.coef_bits); + end + end + end + n = n + 1; +end + +f_p = linspace(0, fs3/2, 2000); +m_db = 20*log10(abs(freqz(bq, 1, f_p, fs3))); +i_pb = find(f_p < src.f_pb); +g_pb = max(m_db(i_pb)); +g_att_lin = 10^(-g_pb/20); + +if 1 + p_ymin = floor((-cnv.rs-50)/10)*10; + p_ymax = 10; + figure; + clf; + plot(f_p, m_db); + grid on; + xlabel('Frequency (Hz)'); + ylabel('Magnitude (dB)'); + axis([0 fs3/2 p_ymin p_ymax]); + hold on + plot([src.f_sb src.f_sb],[p_ymin p_ymax], 'r--'); + plot([0 fs3],[-cnv.rs -cnv.rs], 'r--'); + hold off + axes('Position', [ 0.58 0.7 0.3 0.2]); + box on; + plot(f_p(i_pb), m_db(i_pb)); + axis([0 src.f_pb -cnv.rp-0.01 cnv.rp+0.01]); + hold on + plot([0 src.f_pb], +0.5*cnv.rp*ones(1,2), 'r--'); + plot([0 src.f_pb], -0.5*cnv.rp*ones(1,2), 'r--'); + hold off + grid on; + box off; +end + +src.subfilter_length = ceil((nfir+1)/src.num_of_subfilters); +src.filter_length = src.subfilter_length*src.num_of_subfilters; +src.b = zeros(src.filter_length,1); +src.gain = 1; +src.b(1:nfir+1) = b*src.L*g_att_lin; +m = max(abs(src.b)); +gmax = (32767/32768)/m; +maxshift = floor(log(gmax)/log(2)); +src.b = src.b * 2^maxshift; +src.gain = 1/2^maxshift; +src.shift = maxshift; + +%% Reorder coefficients +if 1 + src.coefs = src.b; +else + src.coefs = zeros(src.filter_length,1); + for n = 1:src.num_of_subfilters + i11 = (n-1)*src.subfilter_length+1; + i12 = i11+src.subfilter_length-1; + src.coefs(i11:i12) = src.b(n:src.num_of_subfilters:end); + end +end + +src.halfband = 0; +src.blk_in = M; +src.blk_out = L; +src.MOPS = cnv.fs1/M*src.filter_length/1e6; +src.fir_delay_size = src.subfilter_length + ... + (src.num_of_subfilters-1)*src.idm + src.blk_in; +src.out_delay_size = (src.num_of_subfilters-1)*src.odm + 1; + +end diff --git a/tune/src/src_param.m b/tune/src/src_param.m new file mode 100644 index 0000000..49e935c --- /dev/null +++ b/tune/src/src_param.m @@ -0,0 +1,87 @@ +function cnv = src_param(fs1, fs2, coef_bits, q) + +% src_param - get converter parameters +% +% cnv = src_param(fs1, fs2, coef_bits, q) +% +% fs1 - input rate +% fs2 - output rate +% coef_bits - word length identifier +% q - quality scale filter bandwidth and stopband attenuation, +% 1 is default +% + +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +% Note: firpm design with rs 93 dB, or kaiser with 69 dB rs is fair quality. +% Both give about -80 dB THD+N with 24 bit coefficients. With 16 bit +% coefficients THD+N is limited to about -76 dB. + +if nargin < 4 + q = 1.0; +end + +%% Copy input parameters +cnv.fs1 = fs1; +cnv.fs2 = fs2; +cnv.coef_bits = coef_bits; + +%% FIR design +cnv.design = 'kaiser'; % Use firpm or kaiser + +%% Default SRC quality +cnv.c_pb = q * 22/48; % Gives 22 kHz BW @ 48 kHz +cnv.c_sb = 0.5; % Start stopband at Fs/2 +cnv.rs = 70; % Stopband attenuation in dB +cnv.rp = 0.1; % Passband ripple in dB +cnv.rp_tot = 0.1; % Max +/- passband ripple allowed, used in test script only + +%% Constrain sub-filter lengths. Make subfilters lengths multiple of four +% is a good assumption for processors. +cnv.filter_length_mult = 4; + +%% Exceptions for quality +if min(fs1, fs2) > 80e3 + cnv.c_pb = 30e3/min(fs1, fs2); % 30 kHz BW for > 80 kHz +end + +%% Sanity checks +if cnv.c_pb > 0.49 + error('Too wide passband'); +end +if cnv.c_pb < 0.15 + error('Too narrow passband'); +end +if cnv.rs > 160 + error('Too large stopband attenuation'); +end +if cnv.rs < 40 + error('Too low stopband attenuation'); +end diff --git a/tune/src/src_std_int32.m b/tune/src/src_std_int32.m new file mode 100644 index 0000000..125ae96 --- /dev/null +++ b/tune/src/src_std_int32.m @@ -0,0 +1,30 @@ +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +src_generate(); diff --git a/tune/src/src_tiny_int16.m b/tune/src/src_tiny_int16.m new file mode 100644 index 0000000..be310fb --- /dev/null +++ b/tune/src/src_tiny_int16.m @@ -0,0 +1,41 @@ +% Copyright (c) 2016, Intel Corporation +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% * Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% * Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% * Neither the name of the Intel Corporation nor the +% names of its contributors may be used to endorse or promote products +% derived from this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com +% + +fs1 = [8e3 16e3 24e3 32e3 44.1e3 48e3]; +fs2 = [8e3 16e3 24e3 32e3 44.1e3 48e3]; +fsm = [0 0 0 0 0 1; ... + 0 0 0 0 0 1; ... + 0 0 0 0 0 1; ... + 0 0 0 0 0 1; ... + 0 0 0 0 0 1; ... + 1 1 1 1 1 0; ... + ]; +fmt = 'int16'; profile = 'tiny'; q = 0.75; + +src_generate(fs1, fs2, fmt, fsm, profile, q);