MATLAB: Distortion Plugin with variable Oversampling

audioAudio ToolboxdistortionDSP System ToolboxMATLABoversamplingpluginvariable

Hello i run into a problem here.
i got inspired for this way of aproatching oversampling by another question.
it is oversampling an Distortion Algorithm.
All i wanted to do is use the Code from the Question and let the user Pick the Amount of Oversampling desired ." oFactor = [1 2 4 8 16]"
Initialy i wanted to use enum mapping but as it didnt work i simplified the code . the int slider pickes one number of the oFator Array. That way i change the oversampling multiplicator.
The code works with a Constant property but not with one that can be changed. I dont know why.
thank u in advance 😉
Thats the Error i get:
Index in position 1 exceeds array bounds (must not exceed 4).
Error in PickOversampling2/stepImpl (line 70)
xin = disto(plugin.oFactor(plugin.oF)*ii-(plugin.oFactor(plugin.oF)-1):plugin.oFactor(plugin.oF)*endIdx,:);
Error in testbench_PickOversampling2 (line 69)
o1 = step(plugin, in(:,1:2));
Error in validateAudioPlugin
classdef (StrictDefaults)PickOversampling2 < matlab.System & audioPlugin
properties (Constant)
oFactor = [1 2 4 6 16] ;
end
properties (Constant, Hidden)
PluginInterface = audioPluginInterface(...
audioPluginParameter('oF',...
'DisplayName','oF',...
'Label','dB',...
'Mapping',{'int',1,5},...
'Style', 'rotaryknob','Layout', [1 2]))
end
properties
oF = 1
end
properties (Access = private)
Up16;
Down16;
end
methods
% Constructor
function plugin = PickOversampling2
plugin.Up16=dsp.SampleRateConverter;
plugin.Down16=dsp.SampleRateConverter;
calculateSampleRates(plugin);
end
end
methods(Access = protected)
function out = stepImpl(plugin, in)
x = step(plugin.Up16,in);
%Distortion
Drive_lin = 100
x = x * Drive_lin ;
x(x>1)=1 ;
x(x<(-1))=-1 ;
disto=x;
out = zeros(size(in));
for ii = 1:4096:size(in,1)
endIdx = min(ii+4095,size(in,1));
xin = disto(plugin.oFactor(plugin.oF)*ii-(plugin.oFactor(plugin.oF)-1):plugin.oFactor(plugin.oF)*endIdx,:);
assert(size(xin,1)<=plugin.oFactor(plugin.oF)*4096);
out(ii:endIdx,:) = step(plugin.Down16,xin);
end
end
function resetImpl(plugin)
reset(plugin.Up16);
reset(plugin.Down16);
end
function calculateSampleRates(plugin)
sampleRate = 44100;
plugin.Up16.InputSampleRate=sampleRate;
plugin.Up16.OutputSampleRate=plugin.oFactor(plugin.oF)*sampleRate;
plugin.Down16.InputSampleRate=plugin.oFactor(plugin.oF)*sampleRate;
plugin.Down16.OutputSampleRate=sampleRate;
end
end
end

Best Answer

Hi Adrian,
There are multiple issues here.
First, to reproduce the error, execute this:
h = PickOversampling2
h.oF = 3
h(randn(4,2))
I haven't taken a close look at the code, but there seems to be an indexing error in the for loop. Note that plugins cannot make assumption on the input frame size or sample rate, so we test the plugin with different combinations of inputs sizes and sample rates when we validate it. You validate a plugin with validateAudioPlugin. You can use the -keeptestbench option to preserve a testbench MATLAB file you can run to reproduce and debug issues.
After you resolve this issue in your for loop, you will still have a problerm with your sample rate converters. These objects will not allow their input/output sample rates to be tunable. They must be contants for you to be able to generate a plugin. One solution is to instead use pairs of FIRInterpolator and FIRDecimator objects. Since you can't tune the decimation or interpolation factors, you need to predefine the objects and use the right one depending on the current value of your upsample factor.
This code should work. Note that I skipped the distortion part since it has issues to be resolved.
classdef (StrictDefaults)PickOversampling2 < matlab.System & audioPlugin
properties
OversampleFactor {mustBeMember(OversampleFactor,{'1','2','4','6','16'})} = '1'
end
properties (Access = protected)
poF = 1;
end
properties (Constant, Hidden)
PluginInterface = audioPluginInterface(...
audioPluginParameter('OversampleFactor',...
'DisplayName','Oversample Fsctor','Mapping',{'enum','1','2','4','6','16'}))
end
properties (Access = private)
Up2;
Down2;
Up4;
Down4;
Up6;
Down6;
Up16;
Down16;
pBuff
end
methods
% Constructor
function plugin = PickOversampling2
plugin.Up2 = dsp.FIRInterpolator(2,designMultirateFIR(2,1));
plugin.Up4 = dsp.FIRInterpolator(4,designMultirateFIR(4,1));
plugin.Up6 = dsp.FIRInterpolator(6,designMultirateFIR(6,1));
plugin.Up16 = dsp.FIRInterpolator(16,designMultirateFIR(16,1));
plugin.Down2 = dsp.FIRDecimator(2,designMultirateFIR(1,2));
plugin.Down4 = dsp.FIRDecimator(4,designMultirateFIR(1,4));
plugin.Down6 = dsp.FIRDecimator(6,designMultirateFIR(1,6));
plugin.Down16 = dsp.FIRDecimator(16,designMultirateFIR(1,16));
plugin.pBuff = dsp.AsyncBuffer('Capacity', 192000-1);
end
function set.OversampleFactor(plugin,val)
plugin.OversampleFactor = val;
switch val
case {'2'}
plugin.poF = 2; %#ok




case {'4'}
plugin.poF = 4; %#ok
case {'6'}
plugin.poF = 6; %#ok
case{'16'}
plugin.poF = 16; %#ok
otherwise
plugin.poF = 1; %#ok
end
end
end
methods(Access = protected)
function out = stepImpl(plugin, in)
o = plugin.poF;
switch o
case {2}
x = plugin.Up2(in);
case {4}
x = plugin.Up4(in);
case {6}
x = plugin.Up6(in);
case{16}
x = plugin.Up16(in);
otherwise
x = in;
end
%Distortion
% TO BE ADDED HERE
% workaround the limitation of FIRDecimator (no unbounded
% inputs allowed)
write(plugin.pBuff, x(:,1:size(in,2)));
FrameLength = size(in,1);
z = read(plugin.pBuff, o*FrameLength);
switch o
case {2}
out = plugin.Down2(z);
case {4}
out = plugin.Down4(z);
case {6}
out = plugin.Down6(z);
case{16}
out = plugin.Down16(z);
otherwise
out = x;
end
end
function resetImpl(plugin)
reset(plugin.Up2);
reset(plugin.Down2);
reset(plugin.Up4);
reset(plugin.Down4);
reset(plugin.Up6);
reset(plugin.Down6);
reset(plugin.Up16);
reset(plugin.Down16);
reset(plugin.pBuff);
end
end
end
Related Question