Mercurial > hg > audio-degradation-toolbox
view 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 |
line wrap: on
line source
function [f_audio_out,timepositions_afterDegr] = degradationUnit_applyDynamicRangeCompression(f_audio, samplingFreq, timepositions_beforeDegr, parameter) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Name: degradation_applyDynamicRangeCompression % Version: 1 % Date: 2013-01-23 % Programmer: Matthias Mauch, Sebastian Ewert % % Description: % - applies dynamic range compression to a signal % - f_audio_out is the compressed audio % % Input: % f_audio - audio signal \in [-1,1]^{NxC} with C being the number of % channels % samplingFreq - sampling frequency of f_audio % timepositions_beforeDegr - some degradations delay the input signal. If % some points in time are given via this % parameter, timepositions_afterDegr will % return the corresponding positions in the % output. Set to [] if unavailable. Set f_audio % and samplingFreq to [] to compute only % timepositions_afterDegr. % % Input (optional): parameter % .preNormalization = 0; % db for 95% RMS quantile / 0 means "off" % .forgettingTime = 0.1; % seconds % .compressorThreshold = -40; % dB % .compressorSlope = 0.9; % .attackTime = 0.01; % seconds % .releaseTime = 0.01; % seconds % .delayTime = 0.01; % seconds % .normalizeOutputAudio = 1; % % Output: % f_audio_out - audio output signal % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Audio Degradation Toolbox % % Centre for Digital Music, Queen Mary University of London. % This file copyright 2013 Sebastian Ewert, Matthias Mauch and QMUL. % % This program is free software; you can redistribute it and/or % modify it under the terms of the GNU General Public License as % published by the Free Software Foundation; either version 2 of the % License, or (at your option) any later version. See the file % COPYING included with this distribution for more information. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Check parameters %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if nargin<4 parameter=[]; end if nargin<3 timepositions_beforeDegr=[]; end if nargin<2 error('Please specify input data'); end if isfield(parameter,'preNormalization')==0 parameter.preNormalization = 0; % db for 95% RMS quantile / 0 means "off" end if isfield(parameter,'forgettingTime')==0 parameter.forgettingTime = 0.1; % seconds end if isfield(parameter,'compressorThreshold')==0 parameter.compressorThreshold = -40; % dB end if isfield(parameter,'compressorSlope')==0 parameter.compressorSlope = 0.9; end if isfield(parameter,'attackTime')==0 parameter.attackTime = 0.01; % seconds end if isfield(parameter,'releaseTime')==0 parameter.releaseTime = 0.01; % seconds end if isfield(parameter,'delayTime')==0 parameter.delayTime = 0.01; % seconds end if isfield(parameter,'normalizeOutputAudio')==0 parameter.normalizeOutputAudio = 1; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Main program %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% f_audio_out = []; if ~isempty(f_audio) %% secondary parameters AT = 1 - exp(-2.2/(samplingFreq*parameter.attackTime)); % attack parameter RT = 1 - exp(-2.2/(samplingFreq*parameter.releaseTime)); % release parameter FT = 1 - exp(-2.2/(samplingFreq*parameter.forgettingTime)); % forgetting parameter delay = floor(parameter.delayTime * samplingFreq); mono_audio = mean(f_audio, 2); if parameter.preNormalization < 0 quantMeasured = max(quantile(abs(mono_audio), 0.95),eps); quantWanted = db2mag(parameter.preNormalization); f_audio = f_audio * quantWanted / quantMeasured; mono_audio = mono_audio * quantWanted / quantMeasured; end %% nSample = size(f_audio, 1); nChannel = size(f_audio, 2); if AT == RT % Vectorized version %% runningMS_all = filter(FT,[1 -(1-FT)],mono_audio.^2); runningRMSdB_all = 10 * log10(runningMS_all); gainDB_all = min([zeros(1,length(runningRMSdB_all));... parameter.compressorSlope * (parameter.compressorThreshold - runningRMSdB_all(:)')]); preGain_all = 10.^(gainDB_all/20); gain_all = filter(AT,[1 -(1-AT)],[1/AT,preGain_all(2:end)]); % The next line is equivalent to the behaviour of the serial version. Is that a bug? %f_audio_out = repmat(gain_all(:),1,nChannel) .* [zeros(delay+1,nChannel);f_audio(1:end-(delay+1),:)]; f_audio_out = repmat(gain_all(:),1,nChannel) .* [zeros(delay,nChannel);f_audio(1:end-delay,:)]; else % Serial version (The non-linearity 'if preGain < gain' does not seem to allow for a vectorization in all cases) %% runningMS = mono_audio(1)^2 * FT; gain = 1; buffer = zeros(delay + 1, nChannel); f_audio_out = zeros(size(f_audio)); for iSample = 2:nSample runningMS = ... runningMS * (1-FT) +... mono_audio(iSample)^2 * FT; runningRMSdB = 10 * log10(runningMS); gainDB = min([0, ... parameter.compressorSlope * (parameter.compressorThreshold - runningRMSdB)]); preGain = 10^(gainDB/20); if preGain < gain % "gain" being old gain coeff = AT; % we're in the attack phase else coeff = RT; % we're in the release phase end % calculate new gain as mix of current gain (preGain) and old gain gain = (1-coeff) * gain + coeff * preGain; f_audio_out(iSample, :) = gain * buffer(end,:); if delay > 1 buffer = [f_audio(iSample, :); buffer(1:end-1,:)]; else buffer = f_audio(iSample, :); end end end if parameter.normalizeOutputAudio f_audio_out = adthelper_normalizeAudio(f_audio_out, samplingFreq); end end % This degradation does impose a temporal distortion timepositions_afterDegr = timepositions_beforeDegr + parameter.delayTime; end