Mercurial > hg > audio-degradation-toolbox
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 |