Distortion Plugin with variable Oversampling

4 views (last 30 days)
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

Accepted Answer

jibrahim
jibrahim on 2 Feb 2021
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
  15 Comments
Adrian Alexander
Adrian Alexander on 7 Feb 2021
thank u both works.
i have a lot more code in this plugin.
this solved it.
is there documentation on how and when something like this is needed ?
it fixes the problem but it doesnt realy do anything. the out array is in this format anyway
filterOut = plugin.dcblker(out(:,1:2));
jibrahim
jibrahim on 7 Feb 2021
Hi Adrian,
You are right that the indexing 1:2 does not change the dimensions of the input to the DC blocker. The reason it makes things work is that it helps code generation understand that the number of channels is not variable, but fixed at 2. The decimator outputs a signal that is interpreted as having a variable number of channels (though technically it does not), so we need to workaround this with this extra specification.
This is not documented, but we are aware of this issue and understand that it makes life hard in certain situations. We're working on addressing it.

Sign in to comment.

More Answers (0)

Categories

Find more on Audio Plugin Creation and Hosting in Help Center and File Exchange

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!