annotate AudioDegradationToolbox/degradationUnit_applyDynamicRangeCompression.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_applyDynamicRangeCompression(f_audio, samplingFreq, timepositions_beforeDegr, parameter)
matthiasm@0 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 3 % Name: degradation_applyDynamicRangeCompression
matthiasm@0 4 % Version: 1
matthiasm@0 5 % Date: 2013-01-23
matthiasm@0 6 % Programmer: Matthias Mauch, Sebastian Ewert
matthiasm@0 7 %
matthiasm@0 8 % Description:
matthiasm@0 9 % - applies dynamic range compression to a signal
matthiasm@0 10 % - f_audio_out is the compressed audio
matthiasm@0 11 %
matthiasm@0 12 % Input:
matthiasm@0 13 % f_audio - audio signal \in [-1,1]^{NxC} with C being the number of
matthiasm@0 14 % channels
matthiasm@0 15 % samplingFreq - sampling frequency of f_audio
matthiasm@0 16 % timepositions_beforeDegr - some degradations delay the input signal. If
matthiasm@0 17 % some points in time are given via this
matthiasm@0 18 % parameter, timepositions_afterDegr will
matthiasm@0 19 % return the corresponding positions in the
matthiasm@0 20 % output. Set to [] if unavailable. Set f_audio
matthiasm@0 21 % and samplingFreq to [] to compute only
matthiasm@0 22 % timepositions_afterDegr.
matthiasm@0 23 %
matthiasm@0 24 % Input (optional): parameter
matthiasm@0 25 % .preNormalization = 0; % db for 95% RMS quantile / 0 means "off"
matthiasm@0 26 % .forgettingTime = 0.1; % seconds
matthiasm@0 27 % .compressorThreshold = -40; % dB
matthiasm@0 28 % .compressorSlope = 0.9;
matthiasm@0 29 % .attackTime = 0.01; % seconds
matthiasm@0 30 % .releaseTime = 0.01; % seconds
matthiasm@0 31 % .delayTime = 0.01; % seconds
matthiasm@0 32 % .normalizeOutputAudio = 1;
matthiasm@0 33 %
matthiasm@0 34 % Output:
matthiasm@0 35 % f_audio_out - audio output signal
matthiasm@0 36 %
matthiasm@0 37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 38
matthiasm@0 39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 40 % Audio Degradation Toolbox
matthiasm@0 41 %
matthiasm@0 42 % Centre for Digital Music, Queen Mary University of London.
matthiasm@0 43 % This file copyright 2013 Sebastian Ewert, Matthias Mauch and QMUL.
matthiasm@0 44 %
matthiasm@0 45 % This program is free software; you can redistribute it and/or
matthiasm@0 46 % modify it under the terms of the GNU General Public License as
matthiasm@0 47 % published by the Free Software Foundation; either version 2 of the
matthiasm@0 48 % License, or (at your option) any later version. See the file
matthiasm@0 49 % COPYING included with this distribution for more information.
matthiasm@0 50 %
matthiasm@0 51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 52
matthiasm@0 53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 54 % Check parameters
matthiasm@0 55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 56 if nargin<4
matthiasm@0 57 parameter=[];
matthiasm@0 58 end
matthiasm@0 59 if nargin<3
matthiasm@0 60 timepositions_beforeDegr=[];
matthiasm@0 61 end
matthiasm@0 62 if nargin<2
matthiasm@0 63 error('Please specify input data');
matthiasm@0 64 end
matthiasm@0 65
matthiasm@0 66 if isfield(parameter,'preNormalization')==0
matthiasm@0 67 parameter.preNormalization = 0; % db for 95% RMS quantile / 0 means "off"
matthiasm@0 68 end
matthiasm@0 69 if isfield(parameter,'forgettingTime')==0
matthiasm@0 70 parameter.forgettingTime = 0.1; % seconds
matthiasm@0 71 end
matthiasm@0 72 if isfield(parameter,'compressorThreshold')==0
matthiasm@0 73 parameter.compressorThreshold = -40; % dB
matthiasm@0 74 end
matthiasm@0 75 if isfield(parameter,'compressorSlope')==0
matthiasm@0 76 parameter.compressorSlope = 0.9;
matthiasm@0 77 end
matthiasm@0 78 if isfield(parameter,'attackTime')==0
matthiasm@0 79 parameter.attackTime = 0.01; % seconds
matthiasm@0 80 end
matthiasm@0 81 if isfield(parameter,'releaseTime')==0
matthiasm@0 82 parameter.releaseTime = 0.01; % seconds
matthiasm@0 83 end
matthiasm@0 84 if isfield(parameter,'delayTime')==0
matthiasm@0 85 parameter.delayTime = 0.01; % seconds
matthiasm@0 86 end
matthiasm@0 87 if isfield(parameter,'normalizeOutputAudio')==0
matthiasm@0 88 parameter.normalizeOutputAudio = 1;
matthiasm@0 89 end
matthiasm@0 90
matthiasm@0 91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 92 % Main program
matthiasm@0 93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
matthiasm@0 94
matthiasm@0 95 f_audio_out = [];
matthiasm@0 96 if ~isempty(f_audio)
matthiasm@0 97
matthiasm@0 98 %% secondary parameters
matthiasm@0 99
matthiasm@0 100 AT = 1 - exp(-2.2/(samplingFreq*parameter.attackTime)); % attack parameter
matthiasm@0 101 RT = 1 - exp(-2.2/(samplingFreq*parameter.releaseTime)); % release parameter
matthiasm@0 102 FT = 1 - exp(-2.2/(samplingFreq*parameter.forgettingTime)); % forgetting parameter
matthiasm@0 103
matthiasm@0 104 delay = floor(parameter.delayTime * samplingFreq);
matthiasm@0 105
matthiasm@0 106 mono_audio = mean(f_audio, 2);
matthiasm@0 107
matthiasm@0 108 if parameter.preNormalization < 0
matthiasm@0 109 quantMeasured = max(quantile(abs(mono_audio), 0.95),eps);
matthiasm@0 110 quantWanted = db2mag(parameter.preNormalization);
matthiasm@0 111 f_audio = f_audio * quantWanted / quantMeasured;
matthiasm@0 112 mono_audio = mono_audio * quantWanted / quantMeasured;
matthiasm@0 113 end
matthiasm@0 114
matthiasm@0 115 %%
matthiasm@0 116
matthiasm@0 117 nSample = size(f_audio, 1);
matthiasm@0 118 nChannel = size(f_audio, 2);
matthiasm@0 119
matthiasm@0 120 if AT == RT
matthiasm@0 121 % Vectorized version
matthiasm@0 122 %%
matthiasm@0 123 runningMS_all = filter(FT,[1 -(1-FT)],mono_audio.^2);
matthiasm@0 124 runningRMSdB_all = 10 * log10(runningMS_all);
matthiasm@0 125 gainDB_all = min([zeros(1,length(runningRMSdB_all));...
matthiasm@0 126 parameter.compressorSlope * (parameter.compressorThreshold - runningRMSdB_all(:)')]);
matthiasm@0 127 preGain_all = 10.^(gainDB_all/20);
matthiasm@0 128 gain_all = filter(AT,[1 -(1-AT)],[1/AT,preGain_all(2:end)]);
matthiasm@0 129 % The next line is equivalent to the behaviour of the serial version. Is that a bug?
matthiasm@0 130 %f_audio_out = repmat(gain_all(:),1,nChannel) .* [zeros(delay+1,nChannel);f_audio(1:end-(delay+1),:)];
matthiasm@0 131 f_audio_out = repmat(gain_all(:),1,nChannel) .* [zeros(delay,nChannel);f_audio(1:end-delay,:)];
matthiasm@0 132 else
matthiasm@0 133 % Serial version (The non-linearity 'if preGain < gain' does not seem to allow for a vectorization in all cases)
matthiasm@0 134 %%
matthiasm@0 135 runningMS = mono_audio(1)^2 * FT;
matthiasm@0 136 gain = 1;
matthiasm@0 137 buffer = zeros(delay + 1, nChannel);
matthiasm@0 138 f_audio_out = zeros(size(f_audio));
matthiasm@0 139
matthiasm@0 140 for iSample = 2:nSample
matthiasm@0 141 runningMS = ...
matthiasm@0 142 runningMS * (1-FT) +...
matthiasm@0 143 mono_audio(iSample)^2 * FT;
matthiasm@0 144 runningRMSdB = 10 * log10(runningMS);
matthiasm@0 145
matthiasm@0 146 gainDB = min([0, ...
matthiasm@0 147 parameter.compressorSlope * (parameter.compressorThreshold - runningRMSdB)]);
matthiasm@0 148 preGain = 10^(gainDB/20);
matthiasm@0 149
matthiasm@0 150 if preGain < gain % "gain" being old gain
matthiasm@0 151 coeff = AT; % we're in the attack phase
matthiasm@0 152 else
matthiasm@0 153 coeff = RT; % we're in the release phase
matthiasm@0 154 end
matthiasm@0 155
matthiasm@0 156 % calculate new gain as mix of current gain (preGain) and old gain
matthiasm@0 157 gain = (1-coeff) * gain + coeff * preGain;
matthiasm@0 158
matthiasm@0 159 f_audio_out(iSample, :) = gain * buffer(end,:);
matthiasm@0 160 if delay > 1
matthiasm@0 161 buffer = [f_audio(iSample, :); buffer(1:end-1,:)];
matthiasm@0 162 else
matthiasm@0 163 buffer = f_audio(iSample, :);
matthiasm@0 164 end
matthiasm@0 165 end
matthiasm@0 166 end
matthiasm@0 167
matthiasm@0 168 if parameter.normalizeOutputAudio
matthiasm@0 169 f_audio_out = adthelper_normalizeAudio(f_audio_out, samplingFreq);
matthiasm@0 170 end
matthiasm@0 171
matthiasm@0 172 end
matthiasm@0 173
matthiasm@0 174 % This degradation does impose a temporal distortion
matthiasm@0 175 timepositions_afterDegr = timepositions_beforeDegr + parameter.delayTime;
matthiasm@0 176
matthiasm@0 177 end
matthiasm@0 178
matthiasm@0 179
matthiasm@0 180
matthiasm@0 181