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