[Sound-open-firmware] [PATCH] SOFT: Add SRC coefficients generate tool
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);
On Mon, 2018-06-04 at 11:02 +0300, Seppo Ingalsuo wrote:
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.
Thanks I've applied, but some minor comments.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
tune/src/README | 36 +++++
This will need moved to doc/ and converted to our markup format (more on that later).
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
We should also add a check for GNU octave in configure.ac and a simple script that runs octave and outputs a C file with the new coefficients (by default it should just emit the same coefficients we use today).
Thanks
Liam
On 04.06.2018 12:13, Liam Girdwood wrote:
On Mon, 2018-06-04 at 11:02 +0300, Seppo Ingalsuo wrote:
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.
Thanks I've applied, but some minor comments.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
tune/src/README | 36 +++++
This will need moved to doc/ and converted to our markup format (more on that later).
OK, I will study it.
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
We should also add a check for GNU octave in configure.ac and a simple script that runs octave and outputs a C file with the new coefficients (by default it should just emit the same coefficients we use today).
That will be run of "octave --no-gui src_std_int32.m" and "octave --no-gui src_tiny_int16.m". I'll add that. With Kaiser filters the design is quite fast and the run won't take much more time than topologies compile. So it should be acceptable
That option will still open Gnuplot windows to desktop to show the filter responses but they are closed when the script completes. By adding option --no-window-system the plots appear as coarse ASCII to console. What would be preferred?
The "std" coefficients set output matches with current git while "tiny" doesn't. I'll see if it's best to update tiny again to achieve that. Tiny set had and also what is generated now still has a number of fails in audio quality tests so I've been trying to alter it to minimize the number of fails. There's no bugs but just the limitation that FIR filters can't have strong stop-band with short type.
Thank, Seppo
Thanks
Liam _______________________________________________ Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
On Mon, 2018-06-04 at 12:48 +0300, Seppo Ingalsuo wrote:
We should also add a check for GNU octave in configure.ac and a simple script that runs octave and outputs a C file with the new coefficients (by default it should just emit the same coefficients we use today).
That will be run of "octave --no-gui src_std_int32.m" and "octave --no-gui src_tiny_int16.m". I'll add that. With Kaiser filters the design is quite fast and the run won't take much more time than topologies compile. So it should be acceptable
That option will still open Gnuplot windows to desktop to show the filter responses but they are closed when the script completes. By adding option --no-window-system the plots appear as coarse ASCII to console. What would be preferred?
ASCII, but I would comment the script so that users know how to enable the windows. Can it dumpt the plot to bmp, png, pdf files ?
The "std" coefficients set output matches with current git while "tiny" doesn't. I'll see if it's best to update tiny again to achieve that. Tiny set had and also what is generated now still has a number of fails in audio quality tests so I've been trying to alter it to minimize the number of fails. There's no bugs but just the limitation that FIR filters can't have strong stop-band with short type.
Liam
participants (2)
-
Liam Girdwood
-
Seppo Ingalsuo