changeset 2:5e72201496c8

Bug fixes, added stripzeros function, added new loudness function, moved general documentation to top level, MATLAB_R2014b compatibility
author Brecht De Man <b.deman@qmul.ac.uk>
date Mon, 17 Nov 2014 19:43:43 +0000
parents b64c9fb34bd0
children 1f7b986dab05
files CITATION.txt COPYING.txt MANUAL.txt README.txt aux/autoalign.m aux/batchResample.m aux/finddouble.m aux/getLoudness.m aux/stripzeros.m listeningTest/CITATION.txt listeningTest/COPYING.txt listeningTest/MANUAL.txt listeningTest/README.txt listeningTest/_oneEight.txt listeningTest/_oneThree.txt listeningTest/_sevenNine.txt listeningTest/multiComp/MpushIc.m listeningTest/multiComp/multiComp.m listeningTest/pairComp/PCpush.m listeningTest/pairComp/endPairComp.m listeningTest/pairComp/pairComp.m listeningTest/pairComp/readPairComp.m listeningTest/reportTest.m
diffstat 23 files changed, 600 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CITATION.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,7 @@
+
+@conference{deman2014b,
+	Author = {Brecht De Man and Joshua D. Reiss},
+	Booktitle = {136th Convention of the Audio Engineering Society},
+	Month = {April},
+	Title = {APE: Audio Perceptual Evaluation toolbox for MATLAB},
+	Year = {2014}}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,7 @@
+When using any part of this toolbox, please acknowledge by referencing:
+B. De Man and J. D. Reiss, "APE: Audio Perceptual Evaluation toolbox for MATLAB," 136th Convention of the Audio Engineering Society, 2014.
+
+<Here comes the full licence text for the code.>
+"If you have code and datasets in the same repository, include
+both the code licence and the relevant Creative Commons link and make
+it clear which things they apply to."
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MANUAL.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,74 @@
+Manual to go with the APE Perceptual Evaluation toolbox
+by Brecht De Man <b.deman@qmul.ac.uk>
+
+When using any part of this toolbox, please acknowledge by referencing:
+B. De Man and J. D. Reiss, "APE: Audio Perceptual Evaluation toolbox for MATLAB," 136th Convention of the Audio Engineering Society, 2014.
+
+INTERRUPT SESSION
+To end the test and close the window without finishing the test, type
+>> close all force;
+in the console. 
+
+
+SESSION SCRIPTS, TEST CONFIGURATION AND SOUND LISTS
+To start session, type ‘launch’. 
+Select a session script (e.g. ‘_DEMOSCRIPT.txt’) and type your ID. 
+The session script references the sound list, and subsequently the method of testing and the test configuration to be used, e.g.:
+
+sndList _oneEight.txt 		% loads the sounds specified in _oneEight.txt
+multiComp _multiComp.txt	% loads the configuration specified in _multiComp.txt
+
+<to be completed>
+
+
+INITIAL ORDER OF SAMPLES
+Option A: random positions
+<to be completed>
+
+Option B: initial positions
+<to be completed>
+
+
+FIXED REFERENCE AND ANCHOR SAMPLES
+In the sound list, add a reference and/or anchor sample. If the reference/anchor sample should also be 'hidden', i.e. part of the samples that aren't marked as 'reference', then this sample should be featured in the sound list twice:ß
+DIRECTORY: /Users/John/Music/TestAudio/
+HQreference.wav
+anchor.wav
+variation1.wav
+variation2.wav
+variation3.wav
+HQreference.wav
+anchor.wav
+
+Then, in the configuration file you can add the initial position on the scale(s), like so: 
+COMBINATIONS
+1 position
+2 position
+3 position
+4 position
+5 position
+6 reference position 100
+7 reference position 0
+
+Typically, the reference samples should receive the highest possible rating, and the anchors are very low quality.
+
+
+LOUDNESS EQUALISATION
+Use the  function ‘prepare2listen.m’ (which uses ‘loudness_match.m’ and ‘loudness_itu.m’) to equalise loudness of all files in a folder. Alternatively, use another loudness standard, or 
+
+
+PROBLEMS
+Since the interface was originally inspired by V. Rioux’s interface (2000) but heavily deviated, some code will be redundant or not structured properly. 
+The toolbox is a work in progress and is the result of the design of a number of listening tests related to audio engineering and music production. It is by no means finished or bug-free, but will be continually updated.
+Comments and corrections of any kind are most welcome. 
+
+
+TO ADD
+The following features will be added over time, but haven't been added yet. 
+- Reference/anchor check: only allow submitting the rating when at least one sample is rated minimum/maximum/below a certain value/above a certain value. 
+- Markers outside of the scale when they haven't been used yet
+- Add arbitrary percentage marks on scale (e.g. 20%, 40%, 40%, 80%) in the form of vertical lines
+- Make directory in sound list a relative path
+- Some sort of results sneak peak: for every test, save results to a .mat file, and provide methods for quick box plot and other analysis (for all results thus far/selection of results)
+- Auto-check if a marker was even moved at all
+- Modify loudness scripts: P. D. Pestana, J. D. Reiss, and A. Barbosa, “Loudness Measurement of Multitrack Audio Content Using Modifications of ITU-R BS.1770,” Audio Engineering Society Convention 134, 2013.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,10 @@
+APE Perceptual Evaluation
+Listening test toolbox
+
+See MANUAL.txt for notes on how to use. 
+See CITATION.txt for referencing if you use this toolbox for your work. 
+
+to be added:
+"describes the project, includes authorship credits,
+copyrights, etc and tells people to look at the COPYING and CITATION
+files if they want more details."
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aux/autoalign.m	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,48 @@
+function autoalign(folderName, masterIndex)
+% AUTOALIGN aligns audio in folder with selected file (index 'masterIndex')
+% by inserting zeros at the start of the other files. 
+%
+% by Brecht De Man at Centre for Digital Music on 17 November 2014
+
+    error('Work in progress, function not finished');
+    
+    tic;                                % start measuring time
+    list = dir([foldername '\*.wav']);  % get names of files
+    
+    % remove hidden files from list
+    % see http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/258220
+    for k = length(list):-1:1
+        fname = list(k).name;
+        if fname(1) == '.'
+            list(k) = [ ];
+        end
+    end
+
+    % load master file
+    masterAudioChannels = audioread([foldername '/' list(masterIndex).name]); 
+    masterAudio         = sum(masterAudioChannels, 2); % sum to mono
+    disp(['Aligning audio files with ' list(masterIndex).name '...']);
+    
+    % for each other file:
+    for i = 1:length(list)
+        
+        slaveAudioChannels = audioread([foldername '/' list(i).name]); % read file
+        slaveAudio         = sum(slaveAudioChannels, 2); % sum to mono
+        
+        % check sampling rate is the same
+        % ... 
+
+        % crosscorrelation function
+        xcorr(masterAudio, slaveAudio); 
+        
+        % add zeros to beginning 
+        
+        % monitoring/debugging
+        
+    end
+
+    elapsedTime = toc;  % stop measuring time
+    disp(['autoalign took ' elapsedTime ' seconds to align the files in folder ' ...
+        folderName ' with master file ' list(masterIndex).name]);
+
+end
\ No newline at end of file
--- a/aux/batchResample.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/aux/batchResample.m	Mon Nov 17 19:43:43 2014 +0000
@@ -1,12 +1,14 @@
-function [] = batchResample(foldername, fsnew, bitDepth)
-% BATCH RESAMPLE converts sample rate of all files in folder. 
-%
+function [] = batchresample(foldername, fsnew, bitdepthnew)
+% BATCHRESAMPLE converts sample rate of all files in folder. 
+% 
 % by Brecht De Man at Centre for Digital Music on 13 April 2014
 
-% TODO read sampling rate without reading whole file
+    if nargin < 2
+        fsnew = 96000; 
+    end
 
-    if nargin <3
-        bitDepth = 24;
+    if nargin < 3
+        bitdepthnew = 24;
     end
 
     currentfolder = pwd;
@@ -19,22 +21,28 @@
     for k = length(files):-1:1
         fname = files(k).name;
         if fname(1) == '.'
-            files(k) = [ ];
+            files(k) = [];
         end
     end
 
     for k=1:length(files)
-            disp(['Reading ' files(k).name '...']);
-
-            [audio,fs] = audioread(files(k).name); % read audio
+            info     = audioinfo(files(k).name); 
+            bitdepth = info.BitsPerSample; 
+            fs       = info.SampleRate; 
             
-            if fs==fsnew
-                warning('Sampling rate of original audio file is equal to current sampling rate');
+            if fs==fsnew && bitdepth == bitdepthnew
+                disp([files(k).name ' already at ' num2str(fs) ' Hz, ' num2str(bitdepth) ' bit.']);
             else
-                resampledAudio = resample(audio, fsnew, fs);
-                audiowrite([files(k).name],resampledAudio, fsnew, 'BitsPerSample', bitDepth);
+                [audio,fs] = audioread(files(k).name); % read audio
+                disp([files(k).name ' was ' num2str(fs) ' Hz, ' num2str(bitdepth) ' bit.']);
+                if fs ~= fsnew
+                    audio = resample(audio, fsnew, fs);
+                end
+                audiowrite([files(k).name], audio, fsnew, ...
+                    'BitsPerSample', bitdepthnew);
             end
     end
+    
     cd(currentfolder); % go back to original folder
 
 end
\ No newline at end of file
--- a/aux/finddouble.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/aux/finddouble.m	Mon Nov 17 19:43:43 2014 +0000
@@ -3,13 +3,13 @@
 % 
 % by Brecht De Man at Centre for Digital Music on 15 July 2013
 
-list = dir([foldername '\*.wav']);
-sums = length(list)-1; 
+
+list = dir([foldername '\*.wav']);  % find wav file names in folder
+sums = zeros(length(list));       % array for every file (don't count '.')
+
 for i = 1:length(list)
     audio = audioread([foldername '\' list(i).name]); 
     sums(i) = sum(sum(audio.^2));
-    % find doubles in this list (method or manual)
-    % find corresponding audio files; print their names
 end
 
 for i = 1:length(list)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aux/getLoudness.m	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,344 @@
+function result = getLoudness( vector, Fs, timescale, plotBOOL )
+%GETLOUDNESS returns loudness levels according to EBU R 128 specification
+% Function getLoudness accepts an audio file vector (vector), a sampling
+% rate (Fs), a timescale ('M' - Momentary, 'S' - Short, 'I' - Integrated)
+% and a boolean of whether or not to plot the results, and returns either a
+% scalar for Integrated timescales, or a vector of loudnesses with a
+% refresh rate of 10 Hz.
+%
+% Calling sequence:
+%   result = getLoudness(vector, Fs, timescale, plotBOOL)
+
+% 	% Defining filter coefficients for the pre-filter, according to ITU-R BS.1770-1 
+%     % Modelling a spherical head
+%     prefilterBcoeffs = [1.53512485958697, -2.69169618940638, 1.19839281085285];
+%     prefilterAcoeffs = [1.0, -1.69065929318241, 0.73248077421585];
+%     
+%     % Defining filter coefficients for the RLB, according to ITU-R BS.1770-1
+%     rlbBcoeffs = [1.0, -2.0, 1.0];
+%     rlbAcoeffs = [1.0, -1.99004745483398, 0.99007225036621];
+    
+ % MY 44.1kHZ Coefficients   
+    
+%     prefilterBcoeffs = [1.53093728623786, -2.65120001232265, 1.16732946528280];
+%     prefilterAcoeffs = [1.0, -1.66410930225081, 0.711176041448821];
+
+% by Pedro Pestana; modified by Brecht De Man
+
+    rlbBcoeffs = [[0.994975383507587;], [-1.98995076701517;], [0.994975383507587;]];
+    rlbAcoeffs = [1, -1.98992552008493, 0.989976013945421];
+
+    % loudness prefilter function below this one (see Pestana 2013)
+    [prefilterBcoeffs, prefilterAcoeffs] = getLoudnessPreFilter(10, Fs);
+
+   
+    % Weighting coefficients with channel format [L, R, C, Ls, Rs]
+    nrChannels = size(vector,2);
+    switch nrChannels
+        case 1,
+            G = [1.0];
+        case 2,
+            G = [1.0 1.0];
+        case 5,
+            G = [1.0 1.0 1.0 1.41 1.41];
+        case 6,
+            G = [1.0 1.0 1.0 1.41 1.41]; % double check... AES is L,R,C,LFE,Ls,Rs
+        otherwise,
+            fprintf('Unsuported number of channels\n');
+    end
+    
+    pfVector = filter(prefilterBcoeffs, prefilterAcoeffs, vector); %Apply pre-filter
+	rlbVector = filter(rlbBcoeffs, rlbAcoeffs, pfVector);% Apply RLB filter
+    vectorSquared = rlbVector.^2;
+    
+    switch timescale
+        case 'M'
+            % MODE: MOMENTARY
+            winDur = 400; % window time in miliseconds
+            winSize = Fs*winDur/1000; % window duration in samples
+            olapSize = Fs*100/1000; % not specified
+            maxI = floor( length(vector)/olapSize - winSize/olapSize + 1); % number of iterations
+            for i = 1:maxI
+                blockEnergy(i,:) = sum( vectorSquared( (i-1)*olapSize+1 : (i-1)*olapSize+winSize ,:) )./winSize;
+                time(i) = (i*olapSize)/Fs;
+            end
+            gTimesZ = bsxfun(@times, blockEnergy, G);
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+            
+            if(plotBOOL)
+                plot(time, loudness, 'b-', 'LineWidth', 2);
+                axis([0 length(vector)/Fs -70 0]);
+                xlabel('Time (s)');
+                ylabel('Momentary Loudness (dB)')
+                grid on;
+            end
+            
+            result = loudness;
+            
+        case 'S'
+            % MODE: SHORT
+            winDur = 3000; % window time in miliseconds
+            winSize = Fs*winDur/1000; % window duration in samples
+            olapSize = Fs*100/1000; % 10 Hz refresh rate as per spec
+            maxI = floor( length(vector)/olapSize - winSize/olapSize + 1); % number of iterations
+            for i = 1:maxI
+                blockEnergy(i,:) = sum( vectorSquared( (i-1)*olapSize+1 : (i-1)*olapSize+winSize ,:) )./winSize;
+                time(i) = (i*olapSize)/Fs;
+            end
+            gTimesZ = bsxfun(@times, blockEnergy, G);
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+            
+            if(plotBOOL)
+                plot(time, loudness, 'r-.', 'LineWidth', 2);
+                axis([0 length(vector)/Fs -70 0]);
+                xlabel('Time (s)');
+                ylabel('Short Term Loudness (dB)')
+                grid on;
+            end
+            
+            result = loudness;
+        
+        case 'I' 
+
+            % MODE: INTEGRATED
+            
+            % Gating block interval duration
+            winDur = 400; % in miliseconds
+            winSize = Fs*winDur/1000; % in samples
+            overlap = 0.5; % overlap. Specs: 1/(1-n) must be a natural number exc. 1
+            olapSize = overlap*winSize; % block start interval
+            maxI = floor( length(vector)/olapSize - winSize/olapSize + 1 ); % number of iterations
+    
+            for i = 1:maxI
+                % equation 3
+                blockEnergy(i,:) = sum(vectorSquared( (i-1)*olapSize+1 : (i-1)*olapSize+winSize,:))./winSize;
+            end
+            
+            % equation 4 - loudness
+            gTimesZ = bsxfun(@times, blockEnergy, G);  %element-by-elemnt array multiple of G and blockEnergy
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+    
+            % applying the absolute gate
+            absGate = loudness >= -70;
+            absgatedLoudness = loudness(absGate);
+            absgatedEnergy = blockEnergy(absGate,:);
+            overallAbsLoudness = -0.691 + 10 .* log10( sum((sum(absgatedEnergy)./size(absgatedEnergy,1)).*G) );
+    
+            % applying the relative gate 8 dB down from overallAbsLoudness
+            relGateLevel = overallAbsLoudness - 8;
+            relGate = loudness >= relGateLevel;
+            relgatedLoudness = loudness(relGate);
+            relgateEnergy = blockEnergy(relGate,:);
+            overallRelLoudness = -0.691 + 10 .* log10( sum((sum(relgateEnergy)./size(relgateEnergy,1)).*G) );
+    
+            result = overallRelLoudness;
+           
+            
+        case 'ITU' 
+
+            % MODE: ITU (brecht)
+            
+            % Gating block interval duration
+            winDur = 400; % in miliseconds
+            winSize = Fs*winDur/1000; % in samples
+            overlap = 0.75; % overlap. Specs: 1/(1-n) must be a natural number exc. 1
+            olapSize = overlap*winSize; % block start interval
+            maxI = floor( length(vector)/olapSize - winSize/olapSize + 1 ); % number of iterations
+    
+            for i = 1:maxI
+                % equation 3
+                blockEnergy(i,:) = sum(vectorSquared( (i-1)*olapSize+1 : (i-1)*olapSize+winSize,:))./winSize;
+            end
+            
+            % equation 4 - loudness
+            gTimesZ = bsxfun(@times, blockEnergy, G);  %element-by-elemnt array multiple of G and blockEnergy
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+    
+            % applying the absolute gate
+            absGate = loudness >= -70;
+            absgatedLoudness = loudness(absGate);
+            absgatedEnergy = blockEnergy(absGate,:);
+            overallAbsLoudness = -0.691 + 10 .* log10( sum((sum(absgatedEnergy)./size(absgatedEnergy,1)).*G) );
+    
+            % applying the relative gate 10 dB down from overallAbsLoudness
+            relGateLevel = overallAbsLoudness - 10;
+            relGate = loudness >= relGateLevel;
+            relgatedLoudness = loudness(relGate);
+            relgateEnergy = blockEnergy(relGate,:);
+            overallRelLoudness = -0.691 + 10 .* log10( sum((sum(relgateEnergy)./size(relgateEnergy,1)).*G) );
+    
+            result = overallRelLoudness;
+            
+        case 'B' 
+
+            % MODE: INTEGRATED - modified by Brecht De Man to follow ITU-R BS.1770-3
+            % and Pestana 2013
+            
+            % GAIN???
+            
+            % Gating block interval duration
+            winDur = 280; % in miliseconds (see Pestana 2013)
+            winSize = Fs*winDur/1000; % in samples
+            overlap = 0.75; %! % overlap. Specs: 1/(1-n) must be a natural number exc. 1
+            olapSize = overlap*winSize; % block start interval
+            maxI = floor( length(vector)/olapSize - winSize/olapSize + 1 ); % number of iterations
+    
+            for i = 1:maxI
+                % equation 3
+                blockEnergy(i,:) = sum(vectorSquared( (i-1)*olapSize+1 : (i-1)*olapSize+winSize,:))./winSize;
+            end
+            
+            % equation 4 - loudness
+            gTimesZ = bsxfun(@times, blockEnergy, G);  %element-by-elemnt array multiple of G and blockEnergy
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+    
+            % applying the absolute gate
+            absGate = loudness >= -70;
+            absgatedLoudness = loudness(absGate);
+            absgatedEnergy = blockEnergy(absGate,:);
+            overallAbsLoudness = -0.691 + 10 .* log10( sum((sum(absgatedEnergy)./size(absgatedEnergy,1)).*G) );
+    
+            % applying the relative gate 10 dB (!) down from overallAbsLoudness
+            relGateLevel = overallAbsLoudness - 10; % !
+            relGate = loudness >= relGateLevel;
+            relgatedLoudness = loudness(relGate);
+            relgateEnergy = blockEnergy(relGate,:);
+            overallRelLoudness = -0.691 + 10 .* log10( sum((sum(relgateEnergy)./size(relgateEnergy,1)).*G) );
+    
+            result = overallRelLoudness;
+            
+        otherwise  
+           
+            % MODE: My short-time measure
+            
+            winDur = 3000; % window time in miliseconds
+            winSize = Fs*winDur/1000; % window duration in samples
+            blockEnergy = sum(vectorSquared(:))./winSize;
+
+            % equation 4 - loudness
+            gTimesZ = bsxfun(@times, blockEnergy, G);  %element-by-elemnt array multiple of G and blockEnergy
+            loudness = -0.691 + 10 .* log10(sum(gTimesZ,2));
+            
+            winSize=0;
+            olapSize=0;
+            
+            result = loudness; 
+            
+    end
+end
+
+
+
+function [prefilterBcoeffs, prefilterAcoeffs] = getLoudnessPreFilter(gainIndB, fs)
+% GET LOUDNESS calculates coefficients for prefilter with arbitrary gain as 
+% specified in EBU R 128 and the modification proposed in Pestana 2013. 
+% 
+% by Brecht De Man at Centre for Digital Music on 24 April 2014
+
+if nargin < 2
+    fs = 44100; % standard 44.1kHz
+    if nargin < 1
+        gainIndB = 4.0; % as recommended in EBU R 128 / ITU-R BS.1770-3
+    end
+end
+
+f0      = 1681.9;
+%Q = ?
+%BW = ?
+S       = 1;
+ 
+A       = sqrt(10^(gainIndB/20));
+w0      = 2*pi*f0/fs;
+alpha   = sin(w0/2) * sqrt( (A+1/A) * (1/S-1) + 2);
+ 
+b0      = A*((A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha);
+b1      = -2*A*((A-1) + (A+1)*cos(w0));
+b2      = A*((A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha);
+a0      = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
+a1      = 2*((A-1) - (A+1)*cos(w0));
+a2      = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
+ 
+% b0 =  (1 - cos(w0))/2;
+% b1 =   1 - cos(w0);
+% b2 =  (1 - cos(w0))/2;
+% a0 =   1 + alpha;
+% a1 =  -2*cos(w0);
+% a2 =   1 - alpha;
+ 
+% b0      = b0/a0;
+% b1      = b1/a0;
+% b2      = b2/a0;
+% a0      = a0/a0;
+% a1      = a1/a0;
+% a2      = a2/a0;
+ 
+prefilterBcoeffs    = [b0, b1, b2];
+prefilterAcoeffs    = [a0, a1, a2];
+
+
+% % DEBUG: comparison with ITU/EBU standard hard coded coefficients
+% [Hpf,Wpf] = freqz(prefilterBcoeffs, prefilterAcoeffs, 20000, fs); % response in radians per sample
+%  
+% subplot(2,1,1)
+% semilogx(20*log10(abs(Hpf)));
+% axis([0 20000 -10 15]);
+% grid on
+% set(gca, 'XTickMode','manual');
+% set(gca, 'XTickLabel',num2str(get(gca,'XTick')'));
+%  
+% 
+% % fs=48k, 4dB gain
+% prefilterBcoeffs = [1.53512485958697, -2.69169618940638, 1.19839281085285];
+% prefilterAcoeffs = [1.0, -1.69065929318241, 0.73248077421585];
+%  
+% [Hpf,Wpf] = freqz(prefilterBcoeffs, prefilterAcoeffs, 20000,48000); % response in radians per sample
+%  
+% subplot(2,1,2)
+% semilogx(20*log10(abs(Hpf)));
+% axis([0 20000 -10 10]);
+% grid on
+% set(gca, 'XTickMode','manual');
+% set(gca, 'XTickLabel',num2str(get(gca,'XTick')'));
+
+
+% see 
+% S. Mansbridge, S. Finn, and J. D. Reiss, "Implementation and Evaluation 
+% of Autonomous Multi-track Fader Control," 132nd Convention of the Audio 
+% Engineering Society, 2012. 
+% f_c = 1681.97;
+% Omega = tan(pi*f_c/fs);
+% V_H = 1.58; % probably gain (?+4dB)
+% V_L = 1.26; % switch with V_B?
+% V_B = 1; 
+% Q   = 0.71;
+% 
+% b(1) = V_L * Omega^2 + V_B*Omega/Q + V_H;
+% b(2) = 2*(V_L*Omega^2 - V_H);
+% b(3) = V_L*Omega^2 - V_B*Omega/Q + V_H;
+% a(1) = Omega^2 + Omega/Q + 1;
+% a(2) = 2*(Omega^2 - 1);
+% a(3) = Omega^2 - Omega/Q + 1;
+% 
+% b = b /a(1);
+% a = a /a(1);
+
+% f  = 1682; % Hz
+% S  = 1; % steep without noticeable notches/peaks
+% A  = 10^(gain/40);
+% w0 =2*pi*f/fs;
+% alpha = sin(w0)/2 * sqrt( (A+ 1/A)*(1/S - 1) + 2 );
+% 
+% % filter coefficients
+% b(1)=    A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha );
+% b(2) = -2*A*( (A-1) + (A+1)*cos(w0)                   );
+% b(3) =    A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha );
+% a(1) =        (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
+% a(2) =    2*( (A-1) - (A+1)*cos(w0)                   );
+% a(3) =        (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
+% 
+
+
+% DEBUG
+%fvtool(b,a,'Fs',fs);
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aux/stripzeros.m	Mon Nov 17 19:43:43 2014 +0000
@@ -0,0 +1,57 @@
+function stripzeros(foldername)
+% STRIPZEROS strips off an array of samples that equal zero at the 
+% beginning and end of an audio file. 
+%
+% by Brecht De Man at Centre for Digital Music on 17 November 2014
+
+    tic;                                % start measuring time
+    list = dir([foldername '/*.wav']);  % get names of files
+
+    % remove hidden files from list
+    % see http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/258220
+    for k = length(list):-1:1
+        fname = list(k).name;
+        if fname(1) == '.'
+            list(k) = [ ];
+        end
+    end
+
+    for i = 1:length(list) % go over each file in the folder
+        [audio, fs] = audioread([foldername '/' list(i).name]);
+
+        numSamples  = size(audio,1);
+        numChannels = size(audio,2);
+        bitDepth    = 24; % not automated here
+        startIndex  = zeros(numChannels, 1);
+        stopIndex   = zeros(numChannels, 1);
+
+        % first and last non-zero elements (for all channels)
+        for channel = 1:numChannels
+            % ? more efficient way to find first and last non-zero sample?
+            indexOfNonZeroSamples = find(audio(:,channel)); % returns indices non-zero elements
+            startIndex(channel) = min(indexOfNonZeroSamples);
+            stopIndex(channel)  = max(indexOfNonZeroSamples);
+        end
+
+        start = max(startIndex);
+        stop  = min(stopIndex);
+
+        % if startIndex and stopIndex are both equal to first and last sample: 
+        % do nothing.
+        % else: 
+        if start>1 || stop<numSamples
+            audiowrite([foldername '/' list(i).name], audio([start:stop], :), ...
+                fs, 'BitsPerSample', bitDepth);
+        end
+
+        % debugging/monitoring: 
+        startCrop = (start-1)/fs; %
+        stopCrop  = (size(audio,1)-stop)/fs;
+        disp([num2str(startCrop) 's (start) / ' num2str(stopCrop) 's (end) stripped off ' list(i).name]);
+    end
+
+    elapsedTime = toc;  % stop measuring time
+    disp(['stripzeros took ' num2str(elapsedTime) ' seconds to strip zeros off the files in folder ' ...
+    foldername]);
+
+end
\ No newline at end of file
--- a/listeningTest/CITATION.txt	Wed Jul 30 12:38:47 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-
-@conference{deman2014b,
-	Author = {Brecht De Man and Joshua D. Reiss},
-	Booktitle = {136th Convention of the Audio Engineering Society},
-	Month = {April},
-	Title = {APE: Audio Perceptual Evaluation toolbox for MATLAB},
-	Year = {2014}}
--- a/listeningTest/COPYING.txt	Wed Jul 30 12:38:47 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-When using any part of this toolbox, please acknowledge by referencing:
-B. De Man and J. D. Reiss, "APE: Audio Perceptual Evaluation toolbox for MATLAB," 136th Convention of the Audio Engineering Society, 2014.
-
-<Here comes the full licence text for the code.>
-"If you have code and datasets in the same repository, include
-both the code licence and the relevant Creative Commons link and make
-it clear which things they apply to."
\ No newline at end of file
--- a/listeningTest/MANUAL.txt	Wed Jul 30 12:38:47 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-Manual to go with the APE Perceptual Evaluation toolbox
-by Brecht De Man <b.deman@qmul.ac.uk>
-
-When using any part of this toolbox, please acknowledge by referencing:
-B. De Man and J. D. Reiss, "APE: Audio Perceptual Evaluation toolbox for MATLAB," 136th Convention of the Audio Engineering Society, 2014.
-
-INTERRUPT SESSION
-To end the test and close the window without finishing the test, type
->> close all force;
-in the console. 
-
-
-SESSION SCRIPTS, TEST CONFIGURATION AND SOUND LISTS
-To start session, type ‘launch’. 
-Select a session script (e.g. ‘_DEMOSCRIPT.txt’) and type your ID. 
-The session script references the sound list, and subsequently the method of testing and the test configuration to be used, e.g.:
-
-sndList _oneEight.txt 		% loads the sounds specified in _oneEight.txt
-multiComp _multiComp.txt	% loads the configuration specified in _multiComp.txt
-
-<to be completed>
-
-
-INITIAL ORDER OF SAMPLES
-Option A: random positions
-<to be completed>
-
-Option B: initial positions
-<to be completed>
-
-
-FIXED REFERENCE AND ANCHOR SAMPLES
-In the sound list, add a reference and/or anchor sample. If the reference/anchor sample should also be 'hidden', i.e. part of the samples that aren't marked as 'reference', then this sample should be featured in the sound list twice:ß
-DIRECTORY: /Users/John/Music/TestAudio/
-HQreference.wav
-anchor.wav
-variation1.wav
-variation2.wav
-variation3.wav
-HQreference.wav
-anchor.wav
-
-Then, in the configuration file you can add the initial position on the scale(s), like so: 
-COMBINATIONS
-1 position
-2 position
-3 position
-4 position
-5 position
-6 reference position 100
-7 reference position 0
-
-Typically, the reference samples should receive the highest possible rating, and the anchors are very low quality.
-
-
-LOUDNESS EQUALISATION
-Use the  function ‘prepare2listen.m’ (which uses ‘loudness_match.m’ and ‘loudness_itu.m’) to equalise loudness of all files in a folder. Alternatively, use another loudness standard, or 
-
-
-PROBLEMS
-Since the interface was originally inspired by V. Rioux’s interface (2000) but heavily deviated, some code will be redundant or not structured properly. 
-The toolbox is a work in progress and is the result of the design of a number of listening tests related to audio engineering and music production. It is by no means finished or bug-free, but will be continually updated.
-Comments and corrections of any kind are most welcome. 
-
-
-TO ADD
-The following features will be added over time, but haven't been added yet. 
-- Reference/anchor check: only allow submitting the rating when at least one sample is rated minimum/maximum/below a certain value/above a certain value. 
-- Markers outside of the scale when they haven't been used yet
-- Add arbitrary percentage marks on scale (e.g. 20%, 40%, 40%, 80%) in the form of vertical lines
-- Make directory in sound list a relative path
-- Some sort of results sneak peak: for every test, save results to a .mat file, and provide methods for quick box plot and other analysis (for all results thus far/selection of results)
-- Auto-check if a marker was even moved at all
-- Modify loudness scripts: P. D. Pestana, J. D. Reiss, and A. Barbosa, “Loudness Measurement of Multitrack Audio Content Using Modifications of ITU-R BS.1770,” Audio Engineering Society Convention 134, 2013.
\ No newline at end of file
--- a/listeningTest/README.txt	Wed Jul 30 12:38:47 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-APE Perceptual Evaluation
-Listening test toolbox
-
-See MANUAL.txt for notes on how to use. 
-See CITATION.txt for referencing if you use this toolbox for your work. 
-
-to be added:
-"describes the project, includes authorship credits,
-copyrights, etc and tells people to look at the COPYING and CITATION
-files if they want more details."
\ No newline at end of file
--- a/listeningTest/_oneEight.txt	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/_oneEight.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -1,4 +1,4 @@
-DIRECTORY: /Users/Brecht/Documents/MATLAB/APE/listeningTest/AUDIO/counting/
+DIRECTORY: ./AUDIO/counting/
 1.wav
 2.wav
 3.wav
--- a/listeningTest/_oneThree.txt	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/_oneThree.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -1,4 +1,4 @@
-DIRECTORY: /Users/Brecht/Documents/MATLAB/APE/listeningTest/AUDIO/counting/
+DIRECTORY: ./AUDIO/counting/
 1.wav
 2.wav
 3.wav
\ No newline at end of file
--- a/listeningTest/_sevenNine.txt	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/_sevenNine.txt	Mon Nov 17 19:43:43 2014 +0000
@@ -1,4 +1,4 @@
-DIRECTORY: /Users/Brecht/Documents/MATLAB/APE/listeningTest/AUDIO/counting/
+DIRECTORY: ./AUDIO/counting/
 7.wav
 8.wav
 9.wav
\ No newline at end of file
--- a/listeningTest/multiComp/MpushIc.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/multiComp/MpushIc.m	Mon Nov 17 19:43:43 2014 +0000
@@ -10,15 +10,16 @@
 switch sel
     
     case 'normal'
-        % BRECHT: log plays in response log
         fidInd=['responses/' dat.sesDat.id,'_',dat.sesDat.sesScript];
         fid=fopen(fidInd,'a');
-        fprintf(fid,'%i ', sndId);
-        dat.playVec(sndId,1) = 1; % check sample as 'played'
-        set(hf,'userdata',dat); % write dat away already here (avoid 'not all sounds played')
+        fprintf(fid,'%i ', sndId);  % log that this sound has been played
+        dat.playVec(sndId,1) = 1;   % check sample as 'played'
+        set(hf,'userdata',dat);     % write dat away already here (avoid 'not all sounds played')
         
         set(dat.hIcon,'backgroundcolor',[.6 .9 .6]); % all icons turn green
-        if(obj<=dat.nbScale*(dat.nbSnd+4)+1) % value depends on number of sounds (avoid 'Stop Audio' becoming red)
+        
+         % avoid 'Stop Audio' becoming red
+        if(str2double(obj.String)<=dat.nbScale*(dat.nbSnd+4)+1)
             set(obj,'backgroundcolor','r');
         end
         playSound(dat.sesDat.cuSndList(sndId));
--- a/listeningTest/multiComp/multiComp.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/multiComp/multiComp.m	Mon Nov 17 19:43:43 2014 +0000
@@ -47,8 +47,8 @@
 set(hp,'color',[.7 .7 .7]);	% gray background
 
 % Figure-event properties
-set(hf,'windowbuttonmotionfcn',sprintf('MmoveW(%d)',hf));
-set(hf,'keypressfcn',sprintf('TpushKey(%d)',hf));
+set(hf,'windowbuttonmotionfcn',sprintf('MmoveW(%d)',hf.Number));
+set(hf,'keypressfcn',sprintf('TpushKey(%d)',hf.Number));
 
 % Define Scales and SonIcons
 
@@ -127,7 +127,7 @@
       
       % set handles      
       hIc=uicontrol('style','text','string',num2str(permVec(noSnd)),'units','normalized','position',posIc); % changed by Brecht: randperm
-      set(hIc,'buttondownfcn',sprintf('MpushIc(%d)',hf));
+      set(hIc,'buttondownfcn',sprintf('MpushIc(%d)',hf.Number));
       set(hIc,'backgroundcolor', [.6 .9 .6]); % set colour to green
       
       %%%%%%%%%%%%%%%%%%% ENABLING
@@ -195,7 +195,7 @@
 
 posFin=[11/15 3*dY/2 3/15 3*(dY-small)/2]; % [left, bottom, width, height]
 hFin=uicontrol('style','pushbutton','string','Stop audio','units','normalized','position',posFin);
-set(hFin,'callback',sprintf('MpushIc(%d)',hf));
+set(hFin,'callback',sprintf('MpushIc(%d)',hf.Number));
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % "Finished" button
@@ -203,7 +203,7 @@
 
 posFin=[11/15 small 3/15 3*(dY-small)/2]; % [left, bottom, width, height]
 hFin=uicontrol('style','pushbutton','string','Finished','units','normalized','position',posFin);
-set(hFin,'callback',sprintf('endMultiComp(%d)',hf)); 
+set(hFin,'callback',sprintf('endMultiComp(%d)',hf.Number)); 
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--- a/listeningTest/pairComp/PCpush.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/pairComp/PCpush.m	Mon Nov 17 19:43:43 2014 +0000
@@ -11,16 +11,16 @@
 case 1 % A
    set(ha,'backgroundcolor','r');
    set(hb,'backgroundcolor',butCol);
-   fidInd=[dat.sesDat.id,'_',dat.sesDat.sesScript]; %print 'A'
+   fidInd=['responses/' dat.sesDat.id,'_',dat.sesDat.sesScript]; %print 'A'
    fid=fopen(fidInd,'a');
    fprintf(fid,'A');
    playSound(dat.sesDat.cuSndList(comb(noComb,1)));
-case 2 % Stop
-   wavplay(0);   
+case 2 % Stop ()
+   audioplayer(0,1);
 case 3 % B
    set(hb,'backgroundcolor','r');
    set(ha,'backgroundcolor',butCol);
-   fidInd=[dat.sesDat.id,'_',dat.sesDat.sesScript];%print 'B'
+   fidInd=['responses/' dat.sesDat.id,'_',dat.sesDat.sesScript];%print 'B'
    fid=fopen(fidInd,'a');
    fprintf(fid,'B');
    playSound(dat.sesDat.cuSndList(comb(noComb,2))); 
--- a/listeningTest/pairComp/endPairComp.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/pairComp/endPairComp.m	Mon Nov 17 19:43:43 2014 +0000
@@ -134,7 +134,7 @@
 end
 
 fprintf(fid,'------------- LIST OF RESULTS');eol(fid);eol(fid);
-%ADDED BY BRECHT
+
 for noComb=1:dat.nbComb
     if rsl.quest(noComb,1)
         fprintf(fid,'%d',dat.comb(noComb,1));eol(fid);
--- a/listeningTest/pairComp/pairComp.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/pairComp/pairComp.m	Mon Nov 17 19:43:43 2014 +0000
@@ -94,18 +94,18 @@
 
 ha=uicontrol('style','pushbutton','string','A','units','normalized','position',posA, 'FontSize', 56);
 set(ha,'backgroundcolor',butCol);
-set(ha,'callback',sprintf('PCpush(%d,1)',hf));
+set(ha,'callback',sprintf('PCpush(%d,1)',hf.Number));
 
 if strcmp(computer,'PCWIN')
    hStop=uicontrol('style','pushbutton','string','STOP','units','normalized','position',posStop, 'FontSize', 56);
-   set(hStop,'callback',sprintf('PCpush(%d,2)',hf));
+   set(hStop,'callback',sprintf('PCpush(%d,2)',hf.Number));
 else
    hStop='';
 end
 
 hb=uicontrol('style','pushbutton','string','B','units','normalized','position',posB, 'FontSize', 56);
 set(hb,'backgroundcolor',butCol);
-set(hb,'callback',sprintf('PCpush(%d,3)',hf));
+set(hb,'callback',sprintf('PCpush(%d,3)',hf.Number));
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % questions and scales
@@ -158,7 +158,7 @@
    noGUI=2*test.nbScale+noQuest;
    posG=[xx y2-(noGUI*h-hh) x-2*xx h];
    hQuest(noQuest)=uicontrol('style','checkbox','string',test.quest{noQuest},'units','normalized','position',posG,'min',0,'max',1);
-   set(hQuest(noQuest),'callback',sprintf('PCcheck(%d,%d)',hf,noQuest));   
+   set(hQuest(noQuest),'callback',sprintf('PCcheck(%d,%d)',hf.Number,noQuest));   
    if reREAD
       set(hQuest(noQuest),'value',rsl.quest(1,noQuest));
    end
@@ -188,7 +188,7 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 posFin=[x3 y4/3 1-x3 y4/3];
 hFin=uicontrol('style','pushbutton','string','Submit','units','normalized','position',posFin);
-set(hFin,'callback',sprintf('endPairComp(%d)',hf));
+set(hFin,'callback',sprintf('endPairComp(%d)',hf.Number));
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--- a/listeningTest/pairComp/readPairComp.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/pairComp/readPairComp.m	Mon Nov 17 19:43:43 2014 +0000
@@ -55,7 +55,7 @@
    lin=fgetl(fid);
    [word1,COUNT,ERRMSG,NEXTINDEX] = sscanf(lin,'%s',1);
    
-   if (~COUNT | ~strcmp(word1,'%'))      
+   if (~COUNT || ~strcmp(word1,'%'))      
       switch upper(word1)
       case 'NAME'
          tstDat.name=fgetl(fid);
--- a/listeningTest/reportTest.m	Wed Jul 30 12:38:47 2014 +0100
+++ b/listeningTest/reportTest.m	Mon Nov 17 19:43:43 2014 +0000
@@ -2,10 +2,10 @@
 % write report
 
 fidInd=['responses/' sesDat.id,'_',sesDat.sesScript];
-if (~sesDat.reREAD && (sesDat.noTst==1))
+if (~sesDat.reREAD && (sesDat.noTst==1)) % if first time, just write
    fid=fopen(fidInd,'w');
 else   
-   fid=fopen(fidInd,'a');
+   fid=fopen(fidInd,'a');                % if not first time, append
 end
 eol(fid);