comparison AudioDegradationToolbox/degradationUnits/degradationUnit_adaptiveEqualizer.m @ 28:76f45f5c9afd DoP tip

- added units * adaptiveEqualizer * applyMfccMeanAdaption - added corresponding data files for presets - modified applyImpulseReponse to use the estimated average group delay to adjust the output audio and keep the timestamps as is (was vice versa before) - added new units demos, incl one for applyLowpass
author SebastianEwert
date Tue, 21 Jan 2014 18:08:28 +0000
parents
children
comparison
equal deleted inserted replaced
27:5ab87a0152e7 28:76f45f5c9afd
1 function [f_audio_out,timepositions_afterDegr] = degradationUnit_adaptiveEqualizer(f_audio, samplingFreq, timepositions_beforeDegr, parameter)
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % Name: degradationUnit_adaptiveEqualizer
4 % Date of Revision: 2013-01-23
5 % Programmer: Sebastian Ewert
6 %
7 % Description:
8 % - designs a filter such that the mean spectrum of f_audio becomes similar
9 % to a given mean spectrum
10 % - mean spectra are specified using a decibel scale, i.e. if x is a magnitude
11 % spectrum, then apply x -> 20*log10(x)
12 % - there are four ways to specify the destination mean spectrum: 1. by
13 % loading example files provided with the toolbox, 2. by using specific
14 % noise "color" profiles, 3. by providing the destination mean spectrum
15 % using the parameter destMagFreqResp, 4. by providing audio data from
16 % which the destination mean spectrum is computed.
17 % - if mean spectra are computed, this is done by computing a magnitude
18 % spectrogram, deriving the corresponding values in dB, and then averaging
19 % over all time frames.
20 % - the same is done for f_audio and the two mean spectral vectors are
21 % compared
22 % - Then a filter is designed such that f_audio's mean spectral vector
23 % becomes similar to destMagFreqResp
24 % - filtering is done using a linear-phase FIR filter
25 % - this unit normalizes the output
26 %
27 % Notes:
28 % - note that the mean spectrum is often a good approximation of what is
29 % sometimes referred to as the mean spectral shape (however, this term is not
30 % defined for general sound recordings). In this sense, the function
31 % modifies the mean spectral shape to the desired one.
32 %
33 % Input:
34 % f_audio - audio signal \in [-1,1]^{NxC} with C being the number of
35 % channels
36 % samplingFreq - sampling frequency of f_audio
37 % timepositions_beforeDegr - some degradations delay the input signal. If
38 % some points in time are given via this
39 % parameter, timepositions_afterDegr will
40 % return the corresponding positions in the
41 % output. Set to [] if unavailable. Set f_audio
42 % and samplingFreq to [] to compute only
43 % timepositions_afterDegr.
44 %
45 % Input (optional): parameter
46 % .loadInternalMagFreqResp=1 - loads one of the destMagFreqResp provided
47 % by the toolbox
48 % .internalMagFreqResp='Beatles_NorwegianWood'
49 % .computeMagFreqRespFromAudio - computes destMagFreqResp from given
50 % audio data
51 % .computeMagFreqRespFromAudio_audioData
52 % - audio data for .computeMagFreqRespFromAudio
53 % .computeMagFreqRespFromAudio_sf - sampl freq for .computeMagFreqRespFromAudio
54 % .destMagFreqResp = [] - in db. See above.
55 % .destMagFreqResp_freqs = [] - must have same length as destMagFreqResp.
56 % In Hertz
57 % .fftLength = 2 ^ nextpow2(0.02 * samplingFreq); - fft length to
58 % calculate spectrogram of f_audio.
59 %
60 % Output:
61 % f_audio_out - audio signal \in [-1,1]^{NxC} with C being the number
62 % of channels
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 % Audio Degradation Toolbox
67 %
68 % Centre for Digital Music, Queen Mary University of London.
69 % This file copyright 2013 Sebastian Ewert, Matthias Mauch and QMUL.
70 %
71 % This program is free software; you can redistribute it and/or
72 % modify it under the terms of the GNU General Public License as
73 % published by the Free Software Foundation; either version 2 of the
74 % License, or (at your option) any later version. See the file
75 % COPYING included with this distribution for more information.
76 %
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 % Check parameters
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 if nargin<4
83 parameter=[];
84 end
85 if nargin<3
86 timepositions_beforeDegr=[];
87 end
88 if nargin<2
89 error('Please specify input data');
90 end
91
92 if isfield(parameter,'loadInternalMagFreqResp')==0
93 parameter.loadInternalMagFreqResp = 1;
94 end
95 if isfield(parameter,'loadNoiseColorPreset')==0
96 parameter.loadNoiseColorPreset = 0;
97 end
98 if isfield(parameter,'computeMagFreqRespFromAudio')==0
99 parameter.computeMagFreqRespFromAudio = 0;
100 end
101
102 if isfield(parameter,'internalMagFreqResp')==0
103 parameter.internalMagFreqResp = 'Beethoven_Appasionata_Rwc';
104 end
105 if isfield(parameter,'noiseColorPreset')==0
106 parameter.noiseColorPreset = 'pink';
107 end
108 if isfield(parameter,'computeMagFreqRespFromAudio_audioData')==0
109 parameter.computeMagFreqRespFromAudio_audioData = [];
110 end
111 if isfield(parameter,'computeMagFreqRespFromAudio_sf')==0
112 parameter.computeMagFreqRespFromAudio_sf = [];
113 end
114 if isfield(parameter,'destMagFreqResp')==0
115 parameter.destMagFreqResp = [];
116 end
117 if isfield(parameter,'destMagFreqResp_freqs')==0
118 parameter.destMagFreqResp_freqs = [];
119 end
120 if isfield(parameter,'fftLength')==0
121 parameter.fftLength = 2 ^ nextpow2(0.02 * samplingFreq);
122 end
123 if isfield(parameter,'filterOrder')==0
124 parameter.filterOrder = round(parameter.fftLength/2);
125 end
126 if isfield(parameter,'visualizations')==0
127 parameter.visualizations = 0;
128 end
129
130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 % Main program
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 if isempty(f_audio)
134 % we design a linear-phase filter. Such filters have the property that
135 % the group delay for every frequency is always equal to
136 % parameter.filterOrder/2. Therefore, although we built a signal
137 % adaptive filter, we can adjust for that delay. That means that the
138 % timepositions_beforeDegr don't require any adjustment.
139 timepositions_afterDegr = timepositions_beforeDegr;
140 return;
141 end
142
143 % load/compute destMagFreqResp
144 [destMagFreqResp,destMagFreqResp_freqs] = internal_getDestMagFreqResp(parameter);
145
146 % compute mean spectral vector for f_audio
147 [meanMagSpec,meanMagSpec_freqs] = internal_computeMeanSpectralVector(f_audio,samplingFreq,parameter.fftLength);
148 meanMagSpec = internal_standardizeMagFreqResp(meanMagSpec);
149
150 % compute magnitude response for the filter to be designed
151 destMagFreqResp_org = destMagFreqResp;
152 destMagFreqResp_freqs_org = destMagFreqResp_freqs;
153 if ~((length(destMagFreqResp_freqs)==length(meanMagSpec_freqs)) && (all(meanMagSpec_freqs(:) == destMagFreqResp_freqs(:))))
154 % in this case we interpolate the frequency response using a
155 % spline interpolation
156 destMagFreqResp = spline(destMagFreqResp,destMagFreqResp_freqs,meanMagSpec_freqs);
157 end
158 filter_magFreqResp = destMagFreqResp(:) - meanMagSpec(:);
159
160 % design filter (fir2 is linear phase)
161 filter_magFreqResp_linear = 10 .^ (filter_magFreqResp/20);
162 b = fir2(parameter.filterOrder,meanMagSpec_freqs/(samplingFreq/2),filter_magFreqResp_linear);
163
164 % apply filter
165 parameterApplyImpulseResponse.loadInternalIR = 0;
166 parameterApplyImpulseResponse.impulseResponse = b;
167 parameterApplyImpulseResponse.impulseResponseSampFreq = samplingFreq;
168 parameterApplyImpulseResponse.normalizeOutputAudio = 1;
169 parameterApplyImpulseResponse.averageGroupDelayOfFilter = round(parameter.filterOrder/2);
170 [f_audio_out,timepositions_afterDegr] = degradationUnit_applyImpulseResponse(f_audio, samplingFreq, timepositions_beforeDegr, parameterApplyImpulseResponse);
171
172 if parameter.visualizations
173 fvtool(b,1);
174
175 [meanMagSpecOut,meanMagSpecOut_freqs] = internal_computeMeanSpectralVector(f_audio_out,samplingFreq,parameter.fftLength);
176 meanMagSpecOut = internal_standardizeMagFreqResp(meanMagSpecOut);
177
178 figure;
179 plot(destMagFreqResp_freqs_org,destMagFreqResp_org,'y');
180 hold on;
181 plot(meanMagSpecOut_freqs,meanMagSpecOut,'k');
182 title('Comparison: destMagFreqResp(y) and mean spectral vector of output(k)')
183 end
184
185
186 end
187
188 function [f_meanmagspec_db,freqs] = internal_computeMeanSpectralVector(f_audio,fs,fftLength)
189
190 f_audio = mean(f_audio,2);
191
192 [f_spec,freqs,time] = spectrogram(f_audio,hanning(fftLength),fftLength/2,fftLength,fs);
193
194 f_magspec_db = 20 * log10(abs(f_spec));
195
196 f_magspec_db(:,isinf(sum(abs(f_magspec_db),1))) = []; % ignore columns with -inf/inf entries
197 f_magspec_db(:,isnan(sum(abs(f_magspec_db),1))) = [];
198
199 f_meanmagspec_db = mean(f_magspec_db,2);
200
201 end
202
203 function magFreqResp = internal_standardizeMagFreqResp(magFreqResp)
204
205 temp = magFreqResp(~isinf(magFreqResp));
206 temp = temp(~isnan(magFreqResp));
207 maxRobust = max(temp);
208
209 magFreqResp = magFreqResp - maxRobust;
210
211 magFreqResp(magFreqResp > 0) = 0; % remaining positive inf
212 magFreqResp(magFreqResp < -80) = -80; % remaining positive inf
213
214 end
215
216 function [destMagFreqResp,destMagFreqResp_freqs,fftLength] = internal_getDestMagFreqResp(parameter)
217 if parameter.loadInternalMagFreqResp
218 % load example included in toolbox
219
220 fullFilenameMfile = mfilename('fullpath');
221 [pathstr,name,ext] = fileparts(fullFilenameMfile);
222 dirRootIRs = fullfile(pathstr,'../degradationData');
223
224 names_internal = {'Beatles_NorwegianWood','Beethoven_Appasionata_Rwc'};
225 indexInternal = find(strcmpi(names_internal,parameter.internalMagFreqResp), 1);
226 if isempty(indexInternal)
227 error('Please specify a valid internal name')
228 end
229
230 switch indexInternal
231 case 1
232 file = fullfile(dirRootIRs,'SpecEnvelopes/Beatles_NorwegianWood.mat');
233 case 2
234 file = fullfile(dirRootIRs,'SpecEnvelopes/Beethoven_Appasionata_Rwc.mat');
235 end
236 load(file, 'destMagFreqResp', 'destMagFreqResp_freqs');
237
238 elseif parameter.loadNoiseColorPreset
239 switch(lower( parameter.noiseColorPreset))
240 case 'white'
241 freqExponent = 0;
242 case 'pink'
243 freqExponent = 0.5;
244 case 'brown'
245 freqExponent = 1;
246 case 'blue'
247 freqExponent = -0.5;
248 case 'violet'
249 freqExponent = -1;
250 end
251
252 lengthMagResp = parameter.fftLength/2+1;
253 destMagFreqResp_freqs = linspace(0,samplingFreq/2,lengthMagResp);
254 magResp = 1./destMagFreqResp_freqs.^freqExponent;
255 magResp(1) = 1;
256 destMagFreqResp = 20 * log10(magResp);
257
258 elseif parameter.computeMagFreqRespFromAudio
259 % compute destMagFreqResp as mean spectral vector from given audio data
260 [destMagFreqResp,destMagFreqResp_freqs] = internal_computeMeanSpectralVector(...
261 parameter.computeMagFreqRespFromAudio_audioData,parameter.computeMagFreqRespFromAudio_sf,parameter.fftLength);
262 else
263 destMagFreqResp = parameter.destMagFreqResp;
264 destMagFreqResp_freqs = parameter.destMagFreqResp_freqs;
265 end
266
267 % standardize destMagFreqResp
268 destMagFreqResp = internal_standardizeMagFreqResp(destMagFreqResp);
269 end
270
271
272
273
274
275