To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at git://github.com/rmeddis/MAP.git .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / userProgramsASRforDummies / cJob.m @ 38:c2204b18f4a2

History | View | Annotate | Download (41.1 KB)

1 38:c2204b18f4a2 rmeddis
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
%   This program is free software; you can redistribute it and/or modify
3
%   it under the terms of the GNU General Public License as published by
4
%   the Free Software Foundation; either version 2 of the License, or
5
%   (at your option) any later version.
6
%
7
%   This program is distributed in the hope that it will be useful,
8
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
%   GNU General Public License for more details.
11
%
12
%   You can obtain a copy of the GNU General Public License from
13
%   http://www.gnu.org/copyleft/gpl.html or by writing to
14
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
15
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16
17
classdef cJob
18
    %CJOB Responsible for conversion of wav files into recogniser features
19
    %   Please see the documentation located in a separate file for further
20
    %   information.
21
22
    %%  *********************************************************
23
    %  properties                      _   _
24
    %                                 | | (_)
25
    %  _ __  _ __ ___  _ __   ___ _ __| |_ _  ___  ___
26
    % | '_ \| '__/ _ \| '_ \ / _ \ '__| __| |/ _ \/ __|
27
    % | |_) | | | (_) | |_) |  __/ |  | |_| |  __/\__ \
28
    % | .__/|_|  \___/| .__/ \___|_|   \__|_|\___||___/
29
    % | |             | |
30
    % |_|             |_|
31
    %************************************************************
32
33
    %% **********************************************************
34
    % Public properties - can be set by user
35
    %************************************************************
36
    properties(Access = public)
37
        wavFolder
38
        opFolder
39
        noiseFolder
40
41
        wavList
42
        todoStatus
43
44
45
        participant        = 'Normal';%'DEMO2_multiSpont';
46
        noiseName          = '8TalkerBabble';
47
        numWavs            =  5;
48
        noiseLevToUse      = -200;
49
        speechLevToUse     =  50;
50
51
        speechLevStd       = 0;
52
        noiseLevStd        = 0;
53
        freezeNoise        = 0;
54
        meanSNR            = 20;
55
        speechDist         = 'None';
56
        noiseDist          = 'None';
57
58
        noisePreDur        = 0.0;
59
        noisePostDur       = 0.0;
60
        truncateDur        = 0.0; %Dr. RF used 0.550
61
62
        currentSpeechLevel
63
        currentNoiseLevel
64
65
66
        useSpectrogram = false;
67
        numCoeff = 9;
68
69
        %************************************************************
70
        % plotting handles
71
        %************************************************************
72
        probHaxes   = [];
73
        probHaxesSM = [];
74
        sacfHaxes   = [];
75
        sacfHaxesSM = [];
76
        featHaxes   = [];
77
        reconHaxes  = [];
78
79
        %************************************************************
80
        % SACF params
81
        %************************************************************
82
        useSACF             = false;
83
        SACFacfTau          = 2; % > 1 = Wiegrebe mode
84
        SACFnBins           = 128;
85
        SACFminLag          = 1 / 4000;
86
        SACFmaxLag          = 1 / 50;
87
        SACFlambda          = 10e-3;
88
89
        %************************************************************
90
        % MAP params
91
        %************************************************************
92
        MAProot                 = fullfile('..');
93
        MAPplotGraphs           = 0;
94
        MAPDRNLSave             = 0;
95
96
        MAPopLSR                = 0;
97
        MAPopMSR                = 0;
98
        MAPopHSR                = 1;
99
100
        MAPparamChanges = {};
101
102
        %************************************************************
103
        % HTK stuff - writing to HTK recogniser format
104
        %************************************************************
105
        frameshift              = 10;       % shift between frames (ms)
106
        sampPeriodFromMsFactor  = 10000;    % appropriate for 10ms frame rate
107
        paramKind               = 9;        % HTK USER format for user-defined features (p73 of HTK book)
108
109
        removeEnergyStatic      = false;
110
        doCMN                   = false; % Cepstral mean normalisation
111
112
        %************************************************************
113
        % Portable EssexAid params
114
        %************************************************************
115
        bwOct = 1/1;
116
        filterOrder  = 2;
117
118
        mainGain = [ 1;    1;    1;    1;    1];     % gain in linear units
119
        TCdBO    = [40;   40;   40;   40;   40];      %Compression thresholds (in dB OUTPUT from 2nd filt)
120
        TMdBO    = [10;   10;   10;   10;   10];      %MOC thresholds (in dB OUTPUT from 2nd filt)
121
        DRNLc    = [ 0.2;  0.2;  0.2;  0.2;  0.2;]
122
123
        ARtau  = 0.03;            % decay time constant
124
        ARthresholddB = 85;       % dB SPL (input signal level) =>200 to disable
125
        MOCtau = 0.3;
126
        MOCfactor = 0.5;   %dB per dB OUTPUT
127
128
        numSamples = 1024; %MAX=6912
129
        useAid = 0;
130
    end
131
132
    %%  *********************************************************
133
    % Protected properties - inter/ra class communication
134
    %************************************************************
135
    properties(Access = protected)
136
        jobLockFid % File identifier for mutex
137
138
        %Nick C comment on this:
139
        %OK. The big-endian thing used to work because in the config file
140
        %'config_tr_zcpa12' there was a flag called NATURALREADORDER that was set to
141
        %FALSE and thus appeared to override x86 standard:
142
        %little-endian. Endianess has **!nothing!** to do with win vs *nix
143
        byteOrder = 'le';  % byte order is big endian
144
    end
145
    properties(Dependent = true)
146
        jobLockTxtFile
147
    end
148
149
    %%  *********************************************************
150
    % methods        _   _               _
151
    %               | | | |             | |
152
    % _ __ ___   ___| |_| |__   ___   __| |___
153
    %| '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
154
    %| | | | | |  __/ |_| | | | (_) | (_| \__ \
155
    %|_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
156
    %************************************************************
157
158
    methods
159
        %% **********************************************************
160
        % Constructor
161
        %************************************************************
162
        function obj = cJob(LearnOrRecWavs, jobFolder)
163
            if nargin < 1
164
                warning('job:ambiguouscorpus',...
165
                    'We need to know whether the (L)earning or (R)ecognition corpus is being used, assuming ''L''');
166
                LearnOrRecWavs = 'L';
167
            end
168
            if nargin > 1
169
                obj.opFolder = jobFolder;
170
            else
171
                if isunix
172
                    if ismac
173
                        obj.opFolder = '~/ASR/exps/_foo';
174
                    else
175
                        obj.opFolder = '/scratch/nrclark/exps/_foo';
176
                    end
177
                else
178
                    obj.opFolder = 'D:\exps\_foo';
179
                end
180
            end
181
182
            obj = obj.assignWavPaths(LearnOrRecWavs);
183
            obj = obj.initMAP;
184
185
186
        end % ------ OF CONSTRUCTOR
187
188
        %% **********************************************************
189
        % Set Wav Paths
190
        %************************************************************
191
        function obj = assignWavPaths(obj, LearnOrRecWavs)
192
            if isunix
193
                if ismac
194
                    lWAVpath = fullfile('demo_wavs', 'TrainingData-Clean');
195
                    rWAVpath = fullfile('demo_wavs', 'TripletTestData');
196
                    obj.noiseFolder = fullfile('demo_wavs', 'noises');
197
                else
198
                    lWAVpath = fullfile('demo_wavs', 'TrainingData-Clean');
199
                    rWAVpath = fullfile('demo_wavs', 'TripletTestData');
200
                    obj.noiseFolder = fullfile('demo_wavs', 'noises');
201
                end
202
            else
203
                lWAVpath = 'D:\AURORA digits (wav)\TrainingData-Clean';
204
                rWAVpath = 'D:\AURORA digits (wav)\TripletTestData';
205
                obj.noiseFolder = 'D:\AURORA digits (wav)\noises';
206
            end
207
208
            if strcmpi(LearnOrRecWavs, 'l')
209
                obj.wavFolder = lWAVpath;
210
            elseif strcmpi(LearnOrRecWavs, 'r')
211
                obj.wavFolder = rWAVpath;
212
            else
213
                error('First argument to constructor must be ''L'' or ''R''');
214
            end
215
        end
216
217
        %% **********************************************************
218
        % mutex related    _
219
        %                 | |
220
        %  _ __ ___  _   _| |_ _____  __
221
        % | '_ ` _ \| | | | __/ _ \ \/ /
222
        % | | | | | | |_| | ||  __/>  <
223
        % |_| |_| |_|\__,_|\__\___/_/\_\
224
        %************************************************************
225
226
        %% **********************************************************
227
        % lockJobList - File mutex protecting from race conditions
228
        %************************************************************
229
        function obj = lockJobList(obj)
230
            lockON = false;
231
            while (~lockON)
232
                if numel(dir(obj.jobLockTxtFile)) %Check to see if lock already in place
233
                    wTime = randi(750)+250; %3,000-10,000 ms
234
                    disp(['File mutex in place. Retrying in ' num2str(wTime) ' ms'])
235
                    pause(wTime/1000);
236
                else
237
                    obj.jobLockFid = fopen(obj.jobLockTxtFile,'w');
238
                    disp('Job locked');
239
                    pause(50/1000);
240
                    lockON = true;
241
                end
242
            end
243
            fclose(obj.jobLockFid);
244
        end% ------ OF LOCKJOBLIST
245
246
        %% **********************************************************
247
        % unlockJobList - unlocks for other workers
248
        %************************************************************
249
        function obj = unlockJobList(obj)
250
            lockON = logical(numel(dir(obj.jobLockTxtFile)));
251
            while(lockON)
252
                try
253
                    delete(obj.jobLockTxtFile);
254
                    disp('Job unlocked');
255
                    pause(50/1000);
256
                    lockON = false;
257
                catch %#ok<CTCH>
258
                    disp('Unjamming lock - retrying immediately')
259
                    pause(200/1000)
260
                end
261
            end
262
        end% ------ OF UNLOCKJOBLIST
263
264
        %% **********************************************************
265
        % storeSelf - save a copy of this object in opFolder
266
        %************************************************************
267
        function storeSelf(obj)
268
            doneSaving = false;
269
            while(~doneSaving)
270
                try
271
                    save(fullfile(obj.opFolder, 'jobObject'), 'obj');
272
                    doneSaving = true;
273
                catch  %#ok<CTCH>
274
                    wTime = randi(3800)+200; %200-4000 ms
275
                    disp(['Save collision (THIS IS VERY VERY BAD - have you not used the mutex?). Retrying in ' num2str(wTime) ' ms']);
276
                    pause(wTime/1000);
277
                end
278
            end
279
        end % ------ OF STORESELF
280
281
        %% **********************************************************
282
        % loadSelf - load a copy of this object from opFolder
283
        %************************************************************
284
        function obj = loadSelf(obj)
285
            doneLoading = false;
286
            while(~doneLoading)
287
                try
288
                    load(fullfile(obj.opFolder,'jobObject'));
289
                    doneLoading = true;
290
                catch  %#ok<CTCH>
291
                    wTime = randi(3800)+200; %200-4000 ms
292
                    disp(['Load collision (THIS IS VERY VERY BAD - have you not used the mutex?). Retrying in ' num2str(wTime) ' ms'])
293
                    pause(wTime/1000);
294
                end
295
            end
296
        end% ------ OF LOADSELF
297
298
299
        %%  *********************************************************
300
        %  _                          _                   _
301
        % | |                        | |                 (_)
302
        % | |__   ___  _   _ ___  ___| | _____  ___ _ __  _ _ __   __ _
303
        % | '_ \ / _ \| | | / __|/ _ \ |/ / _ \/ _ \ '_ \| | '_ \ / _` |
304
        % | | | | (_) | |_| \__ \  __/   <  __/  __/ |_) | | | | | (_| |
305
        % |_| |_|\___/ \__,_|___/\___|_|\_\___|\___| .__/|_|_| |_|\__, |
306
        %                                          | |             __/ |
307
        %                                          |_|            |___/
308
        %************************************************************
309
310
        %% **********************************************************
311
        % get method for dependtent var jobLockTxtFile
312
        %************************************************************
313
        function value = get.jobLockTxtFile(obj)
314
            %Name the MUTEX file here
315
            value = [fullfile(obj.opFolder, 'jobLock') '.txt'];
316
        end
317
318
        %% **********************************************************
319
        % checkStatus - see how much of the current job is complete
320
        %************************************************************
321
        function checkStatus(obj)
322
            NOWopen = sum(obj.todoStatus==0); %Starting from R2010b, Matlab supports enumerations. For now, we resort to integers for compatibility.
323
            NOWpend = sum(obj.todoStatus==1);
324
            NOWdone = sum(obj.todoStatus==2);
325
326
            zz = clock;
327
            disp([num2str(zz(3)) '-' num2str(zz(2)) '-' num2str(zz(1)) '   ' num2str(zz(4)) ':' num2str(zz(5))])
328
            disp(['CURRENT JOB:' obj.opFolder]);
329
            disp(' ')
330
            disp(['open - ' num2str(NOWopen) ' || pending - ' num2str(NOWpend) ' || complete - ' num2str(NOWdone)])
331
332
            % ---- PROGRESS BAR ----
333
            pcDone = 100*NOWdone/obj.numWavs;
334
            progBarLength = 40;
335
            charBars = repmat('=',1,floor(pcDone/100 * progBarLength));
336
            charWhiteSpace = repmat(' ',1, progBarLength - numel(charBars));
337
            disp(' ')
338
            disp([' -[' charBars charWhiteSpace ']-  ' num2str(pcDone, '%0.1f') '%'])
339
            disp(' ')
340
            disp(' ')
341
            % -- END PROGRESS BAR ---
342
        end% ------ OF CHECKSTATUS
343
344
        %% **********************************************************
345
        % initMAP - add MAP stuff to path
346
        %************************************************************
347
        function obj = initMAP(obj)
348
            addpath(...fullfile(obj.MAProot, 'modules'),...
349
                fullfile(obj.MAProot, 'utilities'),...
350
                fullfile(obj.MAProot, 'MAP'),...
351
                fullfile(obj.MAProot, 'parameterStore'));
352
        end % ------ OF INIT MAP
353
354
        %% **********************************************************
355
        % assign files to testing and training sets
356
        %************************************************************
357
        function obj = assignFiles(obj)
358
            speechWavs  = dir(fullfile(obj.wavFolder, '*.wav'));
359
            assert(obj.numWavs <= size(speechWavs, 1) ,...
360
                'not enough files available in the corpus');  % make sure we have enough wavs
361
362
            randomWavs = rand(1, size(speechWavs, 1));
363
            [~,b] = sort(randomWavs);
364
            trainFileIdx = b(1:obj.numWavs);
365
366
            obj.wavList  = speechWavs(trainFileIdx); %This is a record of all of the wavs that should be done
367
368
            %Starting from R2010b, Matlab should support enumerated types. For now we
369
            %use integers for compatibility.
370
            %0=open, 1=processing, 2=done
371
            obj.todoStatus = zeros(numel(obj.wavList), 1);
372
373
        end % ------ OF ASSIGN FILES
374
375
        %% **********************************************************
376
        % generate  feature
377
        %************************************************************
378
        function obj = genFeat(obj, currentWav)
379
            fprintf(1,'Processing: %s \n', currentWav);
380
            if strcmpi(obj.speechDist,'Gaussian')
381
                tempSpeechLev = obj.speechLevToUse + obj.speechLevStd*randn;
382
            elseif strcmpi(obj.speechDist,'Uniform')
383
                % for a uniform distribution, the standard deviation is
384
                % range/sqrt(12)
385
                % http://mathforum.org/library/drmath/view/52066.html
386
                tempSpeechLev = obj.speechLevToUse - obj.speechLevStd*sqrt(12)/2 + obj.speechLevStd*sqrt(12)*rand;
387
            elseif strcmpi(obj.speechDist,'None')
388
                tempSpeechLev = obj.speechLevToUse;
389
            end
390
391
            if strcmpi(obj.noiseDist,'Gaussian')
392
                tempNoiseLev  = speechLev - obj.meanSNR  + obj.noiseLevStd*randn;
393
            elseif strcmpi(obj.noiseDist,'Uniform')
394
                tempNoiseLev  = tempSpeechLev - obj.meanSNR - obj.noiseLevStd*sqrt(12)/2 + obj.noiseLevStd*sqrt(12)*rand;
395
            elseif strcmpi(obj.noiseDist,'None')
396
                tempNoiseLev  = obj.noiseLevToUse;
397
            end
398
399
            disp(['Current speech level = ' num2str(tempSpeechLev)]);
400
            disp(['Current noise level  = ' num2str(tempNoiseLev)]);
401
402
            obj.currentSpeechLevel = tempSpeechLev;
403
            obj.currentNoiseLevel = tempNoiseLev;
404
            [finalFeatures, ~] = processWavs(obj, currentWav); %discard the output from ANprobabilityResponse and method using ~
405
            opForHTK(obj, currentWav, finalFeatures);
406
        end % ------ OF GENFEAT
407
408
        %% **********************************************************
409
        % write o/p in HTK friendly format
410
        %************************************************************
411
        function obj = opForHTK(obj, currentWav, featureData)
412
413
            featureName = strrep(currentWav, '.wav','.map');
414
            targetFilename = fullfile(obj.opFolder, featureName);
415
416
            % write in a format HTK compliant for the recogniser to use
417
            obj.writeHTK(...
418
                targetFilename,...
419
                featureData,...
420
                size(featureData,2),...
421
                obj.frameshift*obj.sampPeriodFromMsFactor,...
422
                size(featureData,1)*4,...
423
                obj.paramKind,...
424
                obj.byteOrder);
425
        end % ------ OF opForHTK
426
427
428
        %% **********************************************************
429
        %      _                   _                                     _
430
        %     (_)                 | |                                   (_)
431
        %  ___ _  __ _ _ __   __ _| |  _ __  _ __ ___   ___ ___  ___ ___ _ _ __   __ _
432
        % / __| |/ _` | '_ \ / _` | | | '_ \| '__/ _ \ / __/ _ \/ __/ __| | '_ \ / _` |
433
        % \__ \ | (_| | | | | (_| | | | |_) | | | (_) | (_|  __/\__ \__ \ | | | | (_| |
434
        % |___/_|\__, |_| |_|\__,_|_| | .__/|_|  \___/ \___\___||___/___/_|_| |_|\__, |
435
        %         __/ |               | |                                         __/ |
436
        %        |___/                |_|                                        |___/
437
        %************************************************************
438
439
        %% **********************************************************
440
        % getStimulus - what it says on the tin
441
        %************************************************************
442
        function [stimulus, sampleRate] = getStimulus(obj, currentWav)
443
444
            % getStimulus.m - NC Aug 2010
445
            % Modified version of Rob's script to include:
446
            %
447
            % 1)Signal and noise samples with different sample rate. The component with
448
            % lower sample rate is upsampled to the rate of that with the
449
            % higher rate.
450
            % 2) Clearer level setting
451
            % 3) Parameter to change noise intro duration
452
            % 4) Noise padding at end of stimulus
453
            %
454
            % ORIGINAL HEADER:
455
            % getStimulus.m
456
            %
457
            % Robert T. Ferry
458
            % 13th May 2009
459
460
            % Set levels
461
            [speech speechSampleRate] = wavread(fullfile(obj.wavFolder, currentWav ));
462
            speech = speech./sqrt(mean(speech.^2)); %Normalize RMS to 1
463
            speech = speech * 20e-6 * 10^(obj.currentSpeechLevel/20); %Convert RMS to pascals at desired level
464
            %disp(20*log10(sqrt(mean(speech.^2))/20e-6))
465
466
            [noise noiseSampleRate] = wavread(fullfile(obj.noiseFolder, obj.noiseName ));
467
            noise = noise./sqrt(mean(noise.^2)); %Normalize RMS to 1
468
            noise = noise * 20e-6*10^(obj.currentNoiseLevel/20); %Convert RMS to pascals at desired level
469
            %disp(20*log10(sqrt(mean(noise.^2))/20e-6))
470
471
            % Do sample rate conversion if needed
472
            % Will always convert stimulus component with lower rate up to that with
473
            % higher rate.
474
            if speechSampleRate > noiseSampleRate
475
                %     disp('S>N')
476
                [p,q] = rat(speechSampleRate/noiseSampleRate,0.0001);
477
                noise = resample(noise, p, q);
478
                noiseSampleRate = speechSampleRate;
479
            elseif noiseSampleRate > speechSampleRate
480
                %     disp('N>S')
481
                [p,q] = rat(noiseSampleRate/speechSampleRate,0.0001);
482
                speech = resample(speech, p, q);
483
                speechSampleRate = noiseSampleRate; %#ok<NASGU>
484
            else
485
                %DO NOTHING BUT ASSERT
486
                assert(speechSampleRate == noiseSampleRate);
487
            end
488
            sampleRate = noiseSampleRate;
489
            dt = 1/sampleRate;
490
491
            % mix stimuli
492
            % Everything from here down (mostly) is RTF's original
493
            silenceStart = floor(obj.noisePreDur*sampleRate);
494
            silenceEnd = floor(obj.noisePostDur*sampleRate);
495
496
            silencePointsStart = zeros(silenceStart,1);
497
            silencePointsEnd = zeros(silenceEnd,1);
498
499
            speech = [silencePointsStart; speech; silencePointsEnd];
500
501
            stimLength = length(speech);
502
            noiseLength = length(noise);
503
            if obj.freezeNoise
504
                idx = 1;
505
            else
506
                idx = ceil(rand*(noiseLength-stimLength));
507
            end
508
            noise = noise(idx:idx+stimLength-1);
509
510
            stimulus = speech+noise;
511
512
            % add ramps to noise
513
            stimInNoiseTime = dt:dt:dt*length(stimulus);
514
            rampDuration = 0.100;
515
            rampTime = dt : dt : rampDuration;
516
            ramp = [0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ones(1,length(stimInNoiseTime)-length(rampTime))];
517
            stimulus = stimulus'.*ramp;
518
            ramp = fliplr(ramp);
519
            stimulus = stimulus.*ramp;
520
            stimulus = stimulus';
521
            %disp(20*log10(sqrt(mean(stimulus.^2))/20e-6))
522
523
            % add additional silent period to start of stimulus for model to 'settle down'
524
            additionalSilenceLength = round(0.050*sampleRate);
525
            additionalSilencePoints = zeros(additionalSilenceLength,1);
526
            stimulus = [additionalSilencePoints; stimulus]'; %now rotated.
527
            %disp(20*log10(sqrt(mean(stimulus.^2))/20e-6))
528
        end% ------ OF GETSTIMULUS
529
530
531
        %% **********************************************************
532
        % processWavs - do all of the MAP signal processing
533
        %************************************************************
534
        function [finalFeatures, ANprobabilityResponse] = processWavs(obj, currentWav)
535
536
            %**********************************************************
537
            % FIRST GET THE STIMULUS
538
            %**********************************************************
539
            [stimulus, sampleRate] = obj.getStimulus(currentWav);
540
541
            %**********************************************************
542
            % NOW TO LOAD IN THE HEARING AID
543
            %**********************************************************
544
            if obj.useAid
545
                stimulus = [stimulus; stimulus]'; %EsxAid requires stereo stim
546
                stimulus = EssexAid_guiEmulatorWrapper(stimulus, sampleRate, obj);
547
                stimulus = stimulus(1,:); %convert back to mono
548
            end
549
550
            AN_spikesOrProbability = 'probability';
551
552
            if obj.useSpectrogram
553
                lowestBF=100; 	highestBF= 4500; 	numChannels=30;
554
                F=round(logspace(log10(lowestBF),log10(highestBF),numChannels));
555
556
                nfft = 1024;
557
                hopSamples = 64;
558
                noverlap = nfft - hopSamples;
559
                dt = hopSamples/sampleRate;
560
                [~,~,~,P] = spectrogram(stimulus,nfft,noverlap,F,sampleRate);
561
562
                ANprobabilityResponse = 10*log10(  abs(P) /  ((20e-6)^2)  ); %now correct [(a^2)/(b^2) = (a/b)^2]
563
564
            else
565
                [ANprobabilityResponse, dt, myBFlist] = MAPwrap(stimulus, sampleRate, -1, obj.participant, AN_spikesOrProbability, obj.MAPparamChanges);
566
            end
567
            nChannels = numel(myBFlist);
568
569
570
            time_ANresponse = dt:dt:dt*size(ANprobabilityResponse,2);
571
            idx = time_ANresponse > obj.truncateDur; %RTF had this @ 0.550
572
            ANprobabilityResponse = ANprobabilityResponse(:, idx);
573
574
575
            if ~obj.useSpectrogram
576
                if obj.MAPopLSR && ~obj.MAPopHSR
577
                    ANprobabilityResponse = ANprobabilityResponse(1:nChannels, :); %use LSR
578
                end
579
                if ~obj.MAPopLSR && obj.MAPopHSR
580
                    ANprobabilityResponse = ANprobabilityResponse(end-nChannels+1:end, :); %or use HSR
581
                end
582
                if obj.MAPopMSR
583
                    assert(0,'Not working with MSR at the mo')
584
                end
585
            end
586
587
            % OPTIONAL PLOTTING
588
            YTickIdx = 1:floor(numel(myBFlist)/6):numel(myBFlist);
589
            YTickIdxRev = numel(myBFlist)+1-YTickIdx;
590
            if ~isempty(obj.probHaxes)
591
                axes(obj.probHaxes);  %#ok<MAXES>
592
                imagesc(ANprobabilityResponse); colorbar('peer', obj.probHaxes)
593
                set(obj.probHaxes, 'YTick', YTickIdx);
594
                set(obj.probHaxes, 'YTickLabel', num2str(    myBFlist(YTickIdxRev)'     ));
595
                ylabel('cf in Hz')
596
            end
597
598
            % OPTIONAL PLOTTING SMOOTHED
599
            if ~isempty(obj.probHaxesSM)
600
                axes(obj.probHaxesSM); %#ok<MAXES>
601
                anSM=flipud(obj.makeANsmooth(ANprobabilityResponse, 1/dt));
602
                imagesc((1:size(anSM,2))./100,1:size(ANprobabilityResponse,1),anSM);
603
                set(obj.probHaxesSM, 'YTick', YTickIdx);
604
                set(obj.probHaxesSM, 'YTickLabel', num2str(    myBFlist(YTickIdxRev)'     ));
605
                shading(obj.probHaxesSM, 'flat'); colorbar('peer', obj.probHaxesSM)
606
                ylabel('cf (Hz)')
607
                xlabel('Time (s)')
608
            end
609
610
611
            %**********************************************************
612
            % optional SACF stage
613
            %**********************************************************
614
            if obj.useSACF
615
616
                % A slightly ugly copying is needed
617
                SACFparams.lambda = obj.SACFlambda;
618
                SACFparams.acfTau = obj.SACFacfTau;
619
                SACFparams.lags = logspace(log10(obj.SACFminLag),log10(obj.SACFmaxLag),obj.SACFnBins);
620
                SACFparams.lags = linspace(obj.SACFminLag, obj.SACFmaxLag,obj.SACFnBins );
621
622
                SACFmethod.dt = dt;
623
                SACFmethod.nonlinCF = myBFlist;
624
625
                %This is slightly misleading as the ANprob is now a SACF
626
                [ANprobabilityResponse, ~, ~, ~] = filteredSACF(ANprobabilityResponse, SACFmethod, SACFparams);
627
628
                % OPTIONAL PLOTTING
629
                YTickIdx = 1:floor(obj.SACFnBins/6):obj.SACFnBins;
630
                %YTickIdxRev = obj.SACFnBins+1-YTickIdx;
631
                if ~isempty(obj.sacfHaxes)
632
                    axes(obj.sacfHaxes);  %#ok<MAXES>
633
                    imagesc(flipud(ANprobabilityResponse)); shading(obj.sacfHaxes, 'flat'); colorbar('peer', obj.sacfHaxes)
634
                    set(obj.sacfHaxes, 'YTick', YTickIdx);
635
                    set(obj.sacfHaxes, 'YTickLabel', num2str(    1./SACFparams.lags(YTickIdx)'    ,'%0.1f' ));
636
                    ylabel('Pitch in Hz')
637
                end
638
639
                % OPTIONAL PLOTTING SMOOTHED
640
                if ~isempty(obj.sacfHaxesSM)
641
                    axes(obj.sacfHaxesSM);  %#ok<MAXES>
642
                    imagesc(flipud(obj.makeANsmooth(ANprobabilityResponse, 1/dt))); shading(obj.sacfHaxesSM, 'flat'); colorbar('peer', obj.sacfHaxesSM)
643
                    set(obj.sacfHaxesSM, 'YTick', YTickIdx);
644
                    set(obj.sacfHaxesSM, 'YTickLabel', num2str(    1./SACFparams.lags(YTickIdx)'    ,'%0.1f' ));
645
                    ylabel('Pitch in Hz')
646
                end
647
648
            end
649
650
651
            finalFeatures = obj.makeANfeatures(  ...
652
                obj.makeANsmooth(ANprobabilityResponse, 1/dt), obj.numCoeff  );
653
654
            if obj.removeEnergyStatic
655
                finalFeatures = finalFeatures(2:end,:);
656
                % disp(size(finalFeatures))
657
            end
658
659
            if obj.doCMN
660
                m = mean(finalFeatures,2);
661
                finalFeatures = finalFeatures - repmat(m,1,size(finalFeatures,2));
662
            end
663
664
            % OPTIONAL PLOTTING
665
            if ~isempty(obj.featHaxes)
666
                pcolor(obj.featHaxes, finalFeatures); shading(obj.featHaxes, 'flat'); colorbar('peer', obj.featHaxes)
667
            end
668
            if ~isempty(obj.reconHaxes)
669
                reconsData = idct(finalFeatures,obj.SACFnBins);
670
                axes(obj.reconHaxes);  %#ok<MAXES>
671
                imagesc(flipud( reconsData ));
672
            end
673
674
            opForHTK(obj, currentWav, finalFeatures);
675
        end % ------ OF PROCESSWAVS
676
677
    end % ------ OF METHODS
678
679
    %%  *********************************************************
680
    %      _        _   _                       _   _               _
681
    %     | |      | | (_)                     | | | |             | |
682
    %  ___| |_ __ _| |_ _  ___   _ __ ___   ___| |_| |__   ___   __| |___
683
    % / __| __/ _` | __| |/ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
684
    % \__ \ || (_| | |_| | (__  | | | | | |  __/ |_| | | | (_) | (_| \__ \
685
    % |___/\__\__,_|\__|_|\___| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
686
    %************************************************************
687
688
    methods(Static)
689
        %% ********************************************************
690
        % makeANsmooth - smooth the AN response into hanning windowed chunks
691
        %**********************************************************
692
        function ANsmooth = makeANsmooth(ANresponse, sampleRate, winSize, hopSize)
693
            if nargin < 3
694
                winSize = 25; %default 25 ms window
695
            end
696
            if nargin < 4
697
                hopSize = 10; %default 10 ms jump between windows
698
            end
699
700
            winSizeSamples = round(winSize*sampleRate/1000);
701
            hopSizeSamples = round(hopSize*sampleRate/1000);
702
703
            % smooth
704
            hann = cJob.NRC_hanning(winSizeSamples);
705
706
            ANsmooth = [];%Cannot pre-allocate a size as it is unknown until the enframing
707
            for chan = 1:size(ANresponse,1)
708
                f = cJob.enframe(ANresponse(chan,:), hann, hopSizeSamples);
709
                ANsmooth(chan,:) = mean(f,2)'; %#ok<AGROW> see above comment
710
            end
711
        end% ------ OF makeANsmooth
712
713
        %% ********************************************************
714
        % makeANfeatures - dct wizardry
715
        %**********************************************************
716
        function ANfeatures = makeANfeatures(ANrate, numCoeff)
717
            % make feature vectors
718
            features = cJob.GJB_dct(ANrate);
719
            ANfeatures = features(1:numCoeff,:);
720
        end % ------ OF makeANfeatures
721
722
        %% ************************************************************************
723
        % enframe - AVOID SIGNAL PROCESSING TOOLBOX buffer function
724
        %**************************************************************************
725
        function f=enframe(x,win,inc)
726
            %ENFRAME split signal up into (overlapping) frames: one per row. F=(X,WIN,INC)
727
            %
728
            %	F = ENFRAME(X,LEN) splits the vector X(:) up into
729
            %	frames. Each frame is of length LEN and occupies
730
            %	one row of the output matrix. The last few frames of X
731
            %	will be ignored if its length is not divisible by LEN.
732
            %	It is an error if X is shorter than LEN.
733
            %
734
            %	F = ENFRAME(X,LEN,INC) has frames beginning at increments of INC
735
            %	The centre of frame I is X((I-1)*INC+(LEN+1)/2) for I=1,2,...
736
            %	The number of frames is fix((length(X)-LEN+INC)/INC)
737
            %
738
            %	F = ENFRAME(X,WINDOW) or ENFRAME(X,WINDOW,INC) multiplies
739
            %	each frame by WINDOW(:)
740
741
            %	   Copyright (C) Mike Brookes 1997
742
            %      Version: $Id: enframe.m,v 1.4 2006/06/22 19:07:50 dmb Exp $
743
            %
744
            %   VOICEBOX is a MATLAB toolbox for speech processing.
745
            %   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
746
            %
747
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748
            %   This program is free software; you can redistribute it and/or modify
749
            %   it under the terms of the GNU General Public License as published by
750
            %   the Free Software Foundation; either version 2 of the License, or
751
            %   (at your option) any later version.
752
            %
753
            %   This program is distributed in the hope that it will be useful,
754
            %   but WITHOUT ANY WARRANTY; without even the implied warranty of
755
            %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
756
            %   GNU General Public License for more details.
757
            %
758
            %   You can obtain a copy of the GNU General Public License from
759
            %   http://www.gnu.org/copyleft/gpl.html or by writing to
760
            %   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
761
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762
763
            nx=length(x(:));
764
            nwin=length(win);
765
            if (nwin == 1)
766
                len = win;
767
            else
768
                len = nwin;
769
            end
770
            if (nargin < 3)
771
                inc = len;
772
            end
773
            nf = fix((nx-len+inc)/inc);
774
            f=zeros(nf,len);
775
            indf= inc*(0:(nf-1)).';
776
            inds = (1:len);
777
            f(:) = x(indf(:,ones(1,len))+inds(ones(nf,1),:));
778
            if (nwin > 1)
779
                w = win(:)';
780
                f = f .* w(ones(nf,1),:);
781
            end
782
        end % ------ OF ENFRAME
783
784
        %% ************************************************************************
785
        % GJB_dct - AVOID SIGNAL PROCESSING TOOLBOX
786
        %**************************************************************************
787
        function b=GJB_dct(a,n)
788
789
            if nargin == 0,
790
                error('Not enough input arguments.');
791
            end
792
793
            if isempty(a)
794
                b = [];
795
                return
796
            end
797
798
            % If input is a vector, make it a column:
799
            do_trans = (size(a,1) == 1);
800
            if do_trans, a = a(:); end
801
802
            if nargin==1,
803
                n = size(a,1);
804
            end
805
            m = size(a,2);
806
807
            % Pad or truncate input if necessary
808
            if size(a,1)<n,
809
                aa = zeros(n,m);
810
                aa(1:size(a,1),:) = a;
811
            else
812
                aa = a(1:n,:);
813
            end
814
815
            % Compute weights to multiply DFT coefficients
816
            ww = (exp(-1i*(0:n-1)*pi/(2*n))/sqrt(2*n)).';
817
            ww(1) = ww(1) / sqrt(2);
818
819
            if rem(n,2)==1 || ~isreal(a), % odd case
820
                % Form intermediate even-symmetric matrix
821
                y = zeros(2*n,m);
822
                y(1:n,:) = aa;
823
                y(n+1:2*n,:) = flipud(aa);
824
825
                % Compute the FFT and keep the appropriate portion:
826
                yy = fft(y);
827
                yy = yy(1:n,:);
828
829
            else % even case
830
                % Re-order the elements of the columns of x
831
                y = [ aa(1:2:n,:); aa(n:-2:2,:) ];
832
                yy = fft(y);
833
                ww = 2*ww;  % Double the weights for even-length case
834
            end
835
836
            % Multiply FFT by weights:
837
            b = ww(:,ones(1,m)) .* yy;
838
839
            if isreal(a), b = real(b); end
840
            if do_trans, b = b.'; end
841
        end % ----- of GJB_DCT
842
843
        %% ************************************************************************
844
        % NRC_hanning - AVOID SIGNAL PROCESSING TOOLBOX
845
        %**************************************************************************
846
        function w=NRC_hanning(n)
847
            calc_hanning = @(m,n)0.5*(1 - cos(2*pi*(1:m)'/(n+1))); %cheeky anonymous function - I <3 these
848
            if ~rem(n,2)
849
                % Even length window
850
                half = n/2;
851
                w = calc_hanning(half,n);
852
                w = [w; w(end:-1:1)];
853
            else
854
                % Odd length window
855
                half = (n+1)/2;
856
                w = calc_hanning(half,n);
857
                w = [w; w(end-1:-1:1)];
858
            end
859
        end % ------ of NRC_HANNING
860
861
        %% ************************************************************************
862
        % writeHTK - convert data to htk format -> by anonymous Sue (2001)
863
        %**************************************************************************
864
        function retcode = writeHTK(filename, htkdata, nFrames, sampPeriod, SampSize, ParamKind, byte_order)
865
            % Write an HTK format file.
866
            %
867
            % Input parameters:
868
            %    filename		HTK data file
869
            %    htkdata      HTK data read: an m x n matrix with
870
            %                    m = no. of channels
871
            %                    n = no. of frames
872
            %  The following are from the HTK header (see HTK manual):
873
            %    nFrames      no. of frames (samples)
874
            %    sampPeriod   sample period (in 100 ns units?)
875
            %    SampSize     sample size
876
            %    ParamKind    parameter kind code
877
            %
878
            %    byteorder    'be' for big-endian (typical for Unix) (default)
879
            %                 'le' for little-endian (typical for MSWindows)
880
            %
881
            % Output parameters:
882
            %    retcode      0 if successful
883
884
            % Written by Sue 17/12/01
885
886
            retcode=-1;	% initialise in case of error
887
            if nargin < 6
888
                fprintf('Usage: %s(filename, htkdata, nFrames, sampPeriod, SampSize, ParamKind [, byte_order])', mfilename);
889
            end;
890
891
            % Default to big-endian (HTK format)
892
            if nargin < 7
893
                byte_order = 'be';
894
            end;
895
896
            fid = fopen (filename, 'w', sprintf('ieee-%s', byte_order));
897
            if fid < 1
898
                fprintf('%s: can''t open output file %s\n', mfilename, filename);
899
                return
900
            end
901
902
            % Write header
903
            fwrite (fid, nFrames, 'int32'); %nSamples in HTK
904
            fwrite (fid, sampPeriod, 'int32');
905
            fwrite (fid, SampSize, 'int16');
906
            fwrite (fid, ParamKind, 'int16');
907
908
            % Write actual data
909
            fwrite(fid, htkdata, 'float32');
910
911
            fclose(fid);
912
913
            retcode=0;
914
        end% ------ OF WRITEHTK
915
916
        %% ************************************************************************
917
        % readHTK - just incase you ever want to go backwards
918
        %**************************************************************************
919
        function [htkdata,nframes,sampPeriod,sampSize,paramKind] = readHTK(filename,byte_order)
920
921
            if nargin<2
922
                byte_order = 'be';
923
            end
924
925
            fid = fopen(filename,'r',sprintf('ieee-%s',byte_order));
926
927
            nframes = fread(fid,1,'int32');
928
            sampPeriod = fread(fid,1,'int32');
929
            sampSize = fread(fid,1,'int16');
930
            paramKind = fread(fid,1,'int16');
931
932
            % read the data
933
934
            htkdata = fread(fid,nframes*(sampSize/4),'float32');
935
            htkdata = reshape(htkdata,sampSize/4,nframes);
936
            fclose(fid);
937
        end % ------ OF READHTK
938
939
    end % ------ OF STATIC METHODS
940
941
end % ------ OF CLASS