annotate AudioDegradationToolbox/degradationUnit_applyImpulseResponse.m @ 11:2d0ed50c547f version 0.11

Removed tag version 0.11
author matthiasm
date Wed, 21 Aug 2013 19:18:43 +0100
parents 9d682f5e3927
children
rev   line source
matthiasm@0 1 function [f_audio_out,timepositions_afterDegr] = degradationUnit_applyImpulseResponse(f_audio, samplingFreq, timepositions_beforeDegr, parameter)
matthiasm@0 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 3 % Name: degradation_applyImpulseResponse
matthiasm@0 4 % Date of Revision: 2013-04
matthiasm@0 5 % Programmer: Sebastian Ewert
matthiasm@0 6 %
matthiasm@0 7 % Description:
matthiasm@0 8 % - applies an FIR filter
matthiasm@0 9 % - takes care that f_audio and firfilter use same sampling frequency
matthiasm@0 10 % - set samplingFreqFilter = samplingFreq if you do not which to resample
matthiasm@0 11 % the filter
matthiasm@0 12 % - predefines IR: 'GreatHall1','Classroom1','Octagon1',
matthiasm@0 13 % 'GoogleNexusOneFrontSpeaker','GoogleNexusOneFrontMic'
matthiasm@0 14 % 'VinylPlayer1960'
matthiasm@0 15 %
matthiasm@0 16 % Input:
matthiasm@0 17 % f_audio - audio signal \in [-1,1]^{NxC} with C being the number of
matthiasm@0 18 % channels
matthiasm@0 19 % samplingFreq - sampling frequency of f_audio
matthiasm@0 20 % timepositions_beforeDegr - some degradations delay the input signal. If
matthiasm@0 21 % some points in time are given via this
matthiasm@0 22 % parameter, timepositions_afterDegr will
matthiasm@0 23 % return the corresponding positions in the
matthiasm@0 24 % output. Set to [] if unavailable. Set f_audio
matthiasm@0 25 % and samplingFreq to [] to compute only
matthiasm@0 26 % timepositions_afterDegr.
matthiasm@0 27 %
matthiasm@0 28 % Input (optional): parameter
matthiasm@0 29 % .presetIR = 'GreatHall1'; - load IR from a ADT preset
matthiasm@0 30 % .impulseResponse = []; - IR to apply
matthiasm@0 31 % .impulseResponseSampFreq = 0; - sampling rate of IR
matthiasm@0 32 % .normalizeOutputAudio = 1 - normalize output
matthiasm@0 33 % .normalizeImpulseResponse = 0 - l1-normalize firfilter before
matthiasm@0 34 % application
matthiasm@0 35 %
matthiasm@0 36 % Output:
matthiasm@0 37 % f_audio_out - audio signal \in [-1,1]^{NxC} with C being the number of
matthiasm@0 38 % channels
matthiasm@0 39 % timepositions_afterDegr - time positions corresponding to timepositions_beforeDegr
matthiasm@0 40 %
matthiasm@0 41 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 42
matthiasm@0 43 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 44 % Audio Degradation Toolbox
matthiasm@0 45 %
matthiasm@0 46 % Centre for Digital Music, Queen Mary University of London.
matthiasm@0 47 % This file copyright 2013 Sebastian Ewert, Matthias Mauch and QMUL.
matthiasm@0 48 %
matthiasm@0 49 % This program is free software; you can redistribute it and/or
matthiasm@0 50 % modify it under the terms of the GNU General Public License as
matthiasm@0 51 % published by the Free Software Foundation; either version 2 of the
matthiasm@0 52 % License, or (at your option) any later version. See the file
matthiasm@0 53 % COPYING included with this distribution for more information.
matthiasm@0 54 %
matthiasm@0 55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 56
matthiasm@0 57 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 58 % Check parameters
matthiasm@0 59 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 60 if nargin<4
matthiasm@0 61 parameter=[];
matthiasm@0 62 end
matthiasm@0 63 if nargin<3
matthiasm@0 64 timepositions_beforeDegr=[];
matthiasm@0 65 end
matthiasm@0 66 if nargin<2
matthiasm@0 67 error('Please specify input data');
matthiasm@0 68 end
matthiasm@0 69 if isfield(parameter,'loadInternalIR')==0
matthiasm@0 70 parameter.loadInternalIR = 1;
matthiasm@0 71 end
matthiasm@0 72 if isfield(parameter,'internalIR')==0
matthiasm@0 73 parameter.internalIR = 'GreatHall1';
matthiasm@0 74 end
matthiasm@0 75 if isfield(parameter,'normalizeOutputAudio')==0
matthiasm@0 76 parameter.normalizeOutputAudio = 1;
matthiasm@0 77 end
matthiasm@0 78 if isfield(parameter,'normalizeImpulseResponse')==0
matthiasm@0 79 parameter.normalizeImpulseResponse = 0;
matthiasm@0 80 end
matthiasm@0 81 if isfield(parameter,'impulseResponse')==0
matthiasm@0 82 parameter.impulseResponse = [];
matthiasm@0 83 end
matthiasm@0 84 if isfield(parameter,'impulseResponseSampFreq')==0
matthiasm@0 85 parameter.impulseResponseSampFreq = 0;
matthiasm@0 86 end
matthiasm@0 87
matthiasm@0 88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 89 % Main program
matthiasm@0 90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 91
matthiasm@0 92 if parameter.loadInternalIR
matthiasm@0 93 % load IR included in toolbox
matthiasm@0 94
matthiasm@0 95 fullFilenameMfile = mfilename('fullpath');
matthiasm@0 96 [pathstr,name,ext] = fileparts(fullFilenameMfile);
matthiasm@0 97 dirRootIRs = fullfile(pathstr,'degradationData');
matthiasm@0 98
matthiasm@0 99 names_internalIR = {'GreatHall1','Classroom1','Octagon1','GoogleNexusOneFrontSpeaker','GoogleNexusOneFrontMic','VinylPlayer1960'};
matthiasm@0 100 indexIR = find(strcmpi(names_internalIR,parameter.internalIR), 1);
matthiasm@0 101 if isempty(indexIR)
matthiasm@0 102 error('Please specify a valid preset')
matthiasm@0 103 end
matthiasm@0 104
matthiasm@0 105 switch indexIR
matthiasm@0 106 case 1
matthiasm@0 107 file = fullfile(dirRootIRs,'RoomResponses/GreatHall_Omni_x06y06.wav');
matthiasm@0 108 case 2
matthiasm@0 109 file = fullfile(dirRootIRs,'RoomResponses/Classroom_Omni_30x20y.wav');
matthiasm@0 110 case 3
matthiasm@0 111 file = fullfile(dirRootIRs,'RoomResponses/Octagon_Omni_x06y06.wav');
matthiasm@0 112 case 4
matthiasm@0 113 file = fullfile(dirRootIRs,'PhoneResponses/IR_GoogleNexusOneFrontSpeaker.wav');
matthiasm@0 114 case 5
matthiasm@0 115 file = fullfile(dirRootIRs,'PhoneResponses/IR_GoogleNexusOneFrontMic.wav');
matthiasm@0 116 case 6
matthiasm@0 117 file = fullfile(dirRootIRs,'VinylSim/ImpulseReponseVinylPlayer1960_smoothed.wav');
matthiasm@0 118 end
matthiasm@0 119 [parameter.impulseResponse,parameter.impulseResponseSampFreq] = wavread(file);
matthiasm@0 120 end
matthiasm@0 121
matthiasm@0 122 fs = samplingFreq;
matthiasm@0 123 h = parameter.impulseResponse;
matthiasm@0 124 fs_h = parameter.impulseResponseSampFreq;
matthiasm@0 125 h_org = h;
matthiasm@0 126
matthiasm@0 127 f_audio_out = [];
matthiasm@0 128 if ~isempty(f_audio)
matthiasm@0 129
matthiasm@0 130 if (size(h,2) > 1) && (size(h,1) ~= 1)
matthiasm@0 131 error('Multichannel impulse responses are not supported');
matthiasm@0 132 end
matthiasm@0 133
matthiasm@0 134 if fs ~= fs_h
matthiasm@0 135 h = resample(h,fs,fs_h);
matthiasm@0 136 end
matthiasm@0 137
matthiasm@0 138 if parameter.normalizeImpulseResponse
matthiasm@0 139 h = h / max(abs(h));
matthiasm@0 140 end
matthiasm@0 141
matthiasm@0 142 f_audio_out = fftfilt(h,f_audio);
matthiasm@0 143
matthiasm@0 144 if parameter.normalizeOutputAudio
matthiasm@0 145 f_audio_out = adthelper_normalizeAudio(f_audio_out, samplingFreq);
matthiasm@0 146 end
matthiasm@0 147 end
matthiasm@0 148
matthiasm@0 149 % This degradation does impose a delay
matthiasm@0 150 timepositions_afterDegr = [];
matthiasm@0 151 if ~isempty(timepositions_beforeDegr)
matthiasm@0 152 % approximation via group delay
matthiasm@0 153
matthiasm@0 154 [Gd,W] = mygrpdelay(h_org,1,fs_h,2048);
matthiasm@0 155 %[Gd,W] = grpdelay(h_org,1,1024); % Matlab's own group delay function. Failt for some filters considerably.
matthiasm@0 156
matthiasm@0 157 %figure;
matthiasm@0 158 %plot(W,Gd/samplingFreqFilter)
matthiasm@0 159
matthiasm@0 160 averageOfGroupDelays = mean(Gd);
matthiasm@0 161 timeOffset_sec = averageOfGroupDelays / fs_h;
matthiasm@0 162
matthiasm@0 163 timepositions_afterDegr = timepositions_beforeDegr + timeOffset_sec;
matthiasm@0 164 end
matthiasm@0 165
matthiasm@0 166 end
matthiasm@0 167
matthiasm@0 168 function [gd,w] = mygrpdelay(b,a,Fs,nfft)
matthiasm@0 169 % see also https://ccrma.stanford.edu/~jos/fp/Group_Delay_Computation_grpdelay_m.html
matthiasm@0 170
matthiasm@0 171 b = b(:);
matthiasm@0 172 a = a(:);
matthiasm@0 173
matthiasm@0 174 w=Fs*[0:nfft-1]/nfft;
matthiasm@0 175 oa = length(a)-1; % order of a(z)
matthiasm@0 176 oc = oa + length(b)-1; % order of c(z)
matthiasm@0 177 c = conv(b,fliplr(a)); % c(z) = b(z)*a(1/z)*z^(-oa)
matthiasm@0 178 cr = c.*[0:oc]'; % derivative of c wrt 1/z
matthiasm@0 179 num = fft(cr,nfft);
matthiasm@0 180 den = fft(c,nfft);
matthiasm@0 181 minmag = 10*eps;
matthiasm@0 182 polebins = find(abs(den)<minmag);
matthiasm@0 183 num(polebins) = 0;
matthiasm@0 184 den(polebins) = 1;
matthiasm@0 185 gd = real(num ./ den) - oa;
matthiasm@0 186
matthiasm@0 187 ns = nfft/2; % Matlab convention - should be nfft/2 + 1
matthiasm@0 188 gd = gd(1:ns);
matthiasm@0 189 w = w(1:ns);
matthiasm@0 190
matthiasm@0 191 w = w(:); % Matlab returns column vectors
matthiasm@0 192 gd = gd(:);
matthiasm@0 193
matthiasm@0 194 end
matthiasm@0 195
matthiasm@0 196
matthiasm@0 197