Lösung

Transcription

Lösung
Audiotechnik II
Digitale Audiotechnik: 12. Übung
Prof. Dr. Stefan Weinzierl
22.01.2015
Musterlösung: 21. Januar 2015, 16:40
Digitale Audioeekte in Matlab - Limiter
Ein Limiter ist ein Eekt, der gewährleisten soll, dass ein festgelegter Pegelschwellwert (Threshold)
nicht überschritten wird. Dabei wird, wie in Abb. 1 dargestellt, das verzögerte Eingangssignal x(n −
D) mit einem Steuersignal g(n) gewichtet1 .
Abbildung 1: Blockschaltbild eines Limiters (Siehe 1)
Das Steuersignal xP EAK (n) ergibt sich aus dem geglätteten momentanen Amplitudenbetrag des
Eingangssignales. xP EAK (n) steuert die Limiter-Kennlinie an, die durch Threshold LT in dB und
Steilheit (Slope) LS beschrieben ist, um die notwendige Dämpfung (also das Gewicht g(n)) des
Eingangssignals zu bestimmen. Die Dämpfung wird anschlieÿend geglättet, um zu abrupte Änderungen des Eingangssignals zu vermeiden. Nehmen Sie an, dass die Pegelkennlinie oberhalb des
Schwellwertes horizontal verläuft (LS = 0 dB bzw. LS = 1).
Peakmessung
Abbildung 2: Peakmessung (Siehe 1)
1 Aus:
Zölzer, Udo (2005): Digitale
Audiosignalverarbeitung. 3. Auage. Teubner, Stuttgart
1
(
ATP EAK |x(n)| + (1 − ATP EAK )xpeak (n − 1) , wenn |x(n)| ≥ xpeak (n − 1)
xpeak (n) =
(1 − RTP EAK )xpeak (n − 1)
sonst.
Die Koezienten ATP EAK und RTP EAK sind gegeben durch:
−2.2
RTP EAK , ATP EAK = 1 − e f s·t
, mit t: Attack- bzw. Release-Zeit in Sekunden.
Glättung
Abbildung 3: Glättung der Steuerkurve (Siehe 1)
(
RTg f (n) + (1 − RTg ) g(n − 1)
g(n) =
ATg f (n) + (1 − ATg ) g(n − 1)
, wenn
sonst.
f (n) ≥ f (n − 1)
Die Verzögerung des Eingangssignals kann dabei durch eine Delayline implementiert
werden.
x[n − 1]
x[n − 2]
x[n − 3]
x[n − 4]
...
x[n − L]
Abbildung 4: Delayline der Länge L Samples
Programmieren Sie in Matlab einen Limiter, der die angegeben Gleichungen sampleweise auf ein Eingangssignal anwendet. (Als Testsignal können Sie die Datei
drums.wav aus dem Downloadbereich benutzen.)
a)
[y, data] = limitBlock(x, fs, at, rt, lt, gain, data)
Dabei sind at und rt die Attack- bzw. Release-Zeit in ms für die Glättung des Steuersignals xP EAK . lt und gain sind der Pegelschwellwert und die zusätzliche Verstärkung,
2
die auf das Ausgangssignal angewendet wird, beide in dB. Die Attack- bzw. ReleaseZeit für die Glättung der angewendeten Dämpfung können Sie hard-coded auf 3
bzw. 5 ms setzen. Die zur Berechnung des Steuersignals benötigten Zwischenschritte
können Sie in der Variablen data abspeichern (z.B. data.peak, data.f, data.g). Dies
ermöglicht eine einfachere Kontrolle der Funktion. Verwenden Sie anders als in Abb. 1
angegeben den Logarithmus mit der Basis 10 (dB-Skala). Auf die Hysterese in Abb. 3
können Sie verzichten.
b)
Modizieren Sie die Funktion so, dass sie Blöcke der Länge N verarbeitet.
Matlab-Funktionen: audioread,
audiowrite, round, exp, for, if
Lösung:
clear;
% load wave file
[x, fs] = audioread('drums.wav');
x = x(1:44100, :); % 1 sec
%%
N
L
at
rt
lt
gain
=
=
=
=
=
=
512;
ceil(size(x, 1)/N);
5;
100;
-15;
0;
%
%
%
%
%
%
blocksize in samples
number of blocks in audio
attack time in ms
release time in ms
threshold in dB
gain in dB
if mod(size(x,1),N)~= 0
numNull = N-mod(size(x,1),N);
x_padded = [x;zeros(numNull,size(x,2))];
else
x_padded = x;
end
% allocate memory
y
= zeros( size(
f
= zeros( size(
g
= zeros( size(
xPeak = zeros( size(
x_padded ) );
x_padded, 1 ), 1 );
x_padded, 1 ), 1 );
x_padded ) );
% process audio block by block
for idx = 1:L
% cut block from audio
xBlock = x_padded((idx-1)*N+1:idx*N, :);
% call limiter function
if idx == 1
[yBlock, data] = limitBlock(xBlock, fs, at, rt, lt, gain);
else
[yBlock, data] = limitBlock(xBlock, fs, at, rt, lt, gain, data);
end
% write result block to output vector
3
y((idx-1)*N+1:idx*N, :)
= yBlock;
% write control signals to output vector (for plotting)
xPeak((idx-1)*N+1:idx*N, :) = data.xPeak;
f((idx-1)*N+1:idx*N, :)
= data.f;
g((idx-1)*N+1:idx*N, :)
= data.g;
end
% remove padded zeros and overhanging signal parts
y
= y(1:end-numNull,:);
f
= f(1:end-numNull,:);
g
= g(1:end-numNull,:);
xPeak = xPeak(1:end-numNull,:);
% check old and new maxima
maxX = 20*log10( max(abs(x(:))) );
maxY = 20*log10( max(abs(y(:))) );
disp( [ maxX, maxY ] );
%% ------------------------- save signal -------------------------- %%
audiowrite('drums_lt.wav',y,fs);
%% ---------------- plot audio and control signals----------------- %%
tx = (0:1/fs:(length(x)-1)/fs) + ((at+3)/1000);
tf = 0:1/fs:(length(f)-1)/fs;
fWidth
= 25;
fHeight
= 20;
hFigureHandle = figure;
set(hFigureHandle,'PaperUnits', 'centimeters')
set(hFigureHandle,'PaperPosition', [0 0 fWidth fHeight])
set(hFigureHandle,'Units', 'centimeters')
set(hFigureHandle,'Position', [5 5 fWidth fHeight])
hold on
plot(tx, abs(x), 'linewidth', 2, 'color', [0 1 1])
plot(tf, abs(y), 'linewidth', 2, 'color', 'g')
plot(tf, xPeak, 'linewidth', 1, 'color', 'm')
plot(tf, f, 'linewidth', 1, 'color', 'b')
plot(tf, g, 'linewidth', 1, 'color', 'r')
plot([tf(1) tf(end)], [1 1]*10^(lt/20), 'k--')
hold off
legend('x Left', 'x Right', 'y Left', 'y Right', 'Peak Left', 'Peak Right', ...
'f', 'g', sprintf('lt = %d dB',lt), 'location', 'northeast');
xlabel( 't (s)' )
ylabel( '|.|' )
axis('tight')
box on;
% [y, data] = limitBlock(x, fs, at, rt, lt, gain, data)
%
% is a peak limiter that can proces audio block by block. pretends to be
% realtime...
4
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
input:
x
fs
at
rt
lt
gain data -
n channel audio input
sampling rate
attack time in ms
release time in ms
threshold in dB (e.g. -20)
gain applied to x in db
additional data needed for block by block processing
output:
y
- n channel output audio signal
data - additional data needed for block by block processing
call:
if firstBlock
[yBlock, data] = limitBlock(xBlock, fs, at, rt, lt, gain);
else
[yBlock, data] = limitBlock(xBlock, fs, at, rt, lt, gain, data);
end
function [y, data] = limitBlock(x, fs, at, rt, lt, gain, data)
% allocate memory
xPeak = zeros(size(x));
f
= zeros(size(x, 1), 1);
g
= zeros(size(x, 1), 1);
y
= zeros(size(x));
% at, rt for peak calculation
AT = 1-exp(-2.2/fs/at*1000);
RT = 1-exp(-2.2/fs/rt*1000);
% at, rt
atSmooth
rtSmooth
ATSmooth
RTSmooth
for control signal smoothing
= 3;
= 5;
= 1-exp(-2.2/fs/atSmooth*1000);
= 1-exp(-2.2/fs/rtSmooth*1000);
% initalize data that is needed for block by block processing
if nargin == 6
data.xPeakPrev
= zeros(1, size(x, 2));
data.fPrev
= 1;
data.gSmoothPrev = 1;
data.delayline
= zeros(round(fs*((at+atSmooth)/1000)), size(x, 2));
end
% process (loop over all samples)
for idx = 1:size(x, 1)
% ------------------------- calculate peak signal ----------------------- %
% loop over channels of audio
for cIdx = 1:size(x, 2)
if abs(x(idx, cIdx)) >= data.xPeakPrev(cIdx)
5
% attack
xPeak(idx, cIdx) = AT*abs(x(idx, cIdx)) + (1-AT)*data.xPeakPrev(cIdx);
else
% release
xPeak(idx, cIdx) = (1-RT)*data.xPeakPrev(cIdx);
end
end
data.xPeakPrev(1, :) = xPeak(idx, :);
% ---------------------- apply characteristic curve --------------------- %
% use highest channel as reference
f(idx) = 20*log10(max(data.xPeakPrev)+eps) - lt; % "+eps" to avoid log of zero
if f(idx) > 0
f(idx) = -f(idx);
else
f(idx) = 0;
end
f(idx) = 10^((f(idx)+gain)/20); % gain may also be added after smoothing
% ------------------------- smooth control signal ----------------------- %
if f(idx) >= data.fPrev
% release
g(idx) = RTSmooth*f(idx) + (1-RTSmooth)*data.gSmoothPrev;
else
% attack
g(idx) = ATSmooth*f(idx) + (1-ATSmooth)*data.gSmoothPrev;
end
data.fPrev
= f(idx);
data.gSmoothPrev = g(idx);
% -------------------- apply control signal to audio ------------------- %
data.delayline
= [x(idx, :); data.delayline(1:size(data.delayline, 1)-1, :)];
y(idx, 1:size(x, 2)) = g(idx) * data.delayline(size(data.delayline, 1), :);
end
% save additional data (for debugging, parameter adjustment, plotting ...)
data.xPeak = xPeak;
data.f
= f;
data.g
= g;
end
6
1
x Left
x Right
y Left
y Right
Peak Left
Peak Right
f
g
lt = −15 dB
0.9
0.8
0.7
|x|
0.6
0.5
0.4
0.3
0.2
0.1
0
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
t (s)
Abbildung 5: Ergebnisse für die erste Sekunde der Stereodatei drums.wav
7