Mercurial > hg > ape
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);