annotate utilities/stimulusCreate.m @ 38:c2204b18f4a2 tip

End nov big change
author Ray Meddis <rmeddis@essex.ac.uk>
date Mon, 28 Nov 2011 13:34:28 +0000
parents 25d53244d5c8
children
rev   line source
rmeddis@0 1 function [audio, msg, time]=stimulusCreate(globalStimParams,...
rmeddis@0 2 stimComponents, doPlot)
rmeddis@0 3 % updated June 2007
rmeddis@0 4 % the only authorised version of stimulus create is the version to be found
rmeddis@0 5 % in MAP1_6. Other versions are copies!!
rmeddis@0 6 %
rmeddis@0 7 % for a simple tone you need
rmeddis@0 8 %
rmeddis@0 9 % % Mandatory structure fields
rmeddis@0 10 % globalStimParams.FS=100000;
rmeddis@0 11 % globalStimParams.overallDuration=.1; % s
rmeddis@0 12 % doPlot=1;
rmeddis@0 13 %
rmeddis@0 14 % stim.type='tone';
rmeddis@0 15 % stim.phases='sin';
rmeddis@0 16 % stim.toneDuration=.05;;
rmeddis@0 17 % stim.frequencies=500;
rmeddis@0 18 % stim.amplitudesdB=50;
rmeddis@0 19 % stim.beginSilence=.01;
rmeddis@0 20 % stim.endSilence=-1;
rmeddis@0 21 % stim.rampOnDur=.002;
rmeddis@0 22 % stim.rampOffDur=-1;
rmeddis@0 23 % [audio, msg]=stimulusCreate(globalStimParams, stim, doPlot);
rmeddis@0 24 %
rmeddis@0 25 % % or for multi-component stimuli
rmeddis@0 26 % % Mandatory structure fields
rmeddis@0 27 % globalStimParams.FS=100000;
rmeddis@0 28 % globalStimParams.overallDuration=.1; % s
rmeddis@0 29 % ear=1;
rmeddis@0 30 % componentNo=1;
rmeddis@0 31 %
rmeddis@0 32 % stimComponents(ear, componentNo).type='tone';
rmeddis@0 33 % stimComponents(ear, componentNo).phases='sin';
rmeddis@0 34 % stimComponents(ear, componentNo).toneDuration=.05;;
rmeddis@0 35 % stimComponents(ear, componentNo).frequencies=500;
rmeddis@0 36 % stimComponents(ear, componentNo).amplitudesdB=50;
rmeddis@0 37 % stimComponents(ear, componentNo).beginSilence=.01;
rmeddis@0 38 % stimComponents(ear, componentNo).endSilence=-1;
rmeddis@0 39 % stimComponents(ear, componentNo).rampOnDur=.002;
rmeddis@0 40 % stimComponents(ear, componentNo).rampOffDur=-1;
rmeddis@0 41 %
rmeddis@0 42 % % All components are forced to have the same overall duration and sample rate
rmeddis@0 43 %
rmeddis@0 44 %
rmeddis@0 45 % [audio, msg]=stimulusCreate(globalStimParams, stimComponents);
rmeddis@0 46 %
rmeddis@0 47 % Optional fields
rmeddis@0 48 % .ears overides ear setting by component
rmeddis@0 49 % globalStimParams.ears='monoticL'; % 'monoticL', 'monoticR', 'diotic', 'dichotic'
rmeddis@0 50 %
rmeddis@0 51 % globalStimParams.filter = [leftfl leftfu rightfl right fu]
rmeddis@0 52 % filter is applied separately to left and right combined sounds
rmeddis@0 53 %
rmeddis@0 54 % correction factor is applied to all signals to compensate for differences in output devices.
rmeddis@0 55 % audioOutCorrection is a scalar
rmeddis@0 56 % globalStimParams.audioOutCorrection=2;
rmeddis@0 57 %
rmeddis@0 58 % globalStimParams.FFT= 1; % {0, 1}
rmeddis@0 59 % globalStimParams.doPlot=1; % {0, 1}
rmeddis@0 60 % globalStimParams.doPlay=1; % {0, 1}
rmeddis@0 61 %
rmeddis@0 62 % stimComponents(ear, componentNo).filter=[100 10000 2] % [lower, upper, order] applies to an
rmeddis@0 63 % individual component
rmeddis@0 64 %
rmeddis@0 65 % Output arguments:
rmeddis@0 66 % audio is a stereo signal, a 2-column vector
rmeddis@0 67 %
rmeddis@0 68 %
rmeddis@0 69 % stim.type='noise'; % {'IRN', 'irn', 'noise', 'pinkNoise'}
rmeddis@0 70 % stim.toneDuration=.05;;
rmeddis@0 71 % stim.amplitudesdB=50;
rmeddis@0 72 % stim.beginSilence=.01;
rmeddis@0 73 % stim.endSilence=-1;
rmeddis@0 74 % stim.rampOnDur=.002;
rmeddis@0 75 % stim.rampOffDur=-1;
rmeddis@0 76 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 77 %
rmeddis@0 78 % % for IRN only
rmeddis@0 79 % stim.type='IRN';
rmeddis@0 80 % stim.toneDuration=.05;;
rmeddis@0 81 % stim.amplitudesdB=50;
rmeddis@0 82 % stim.beginSilence=.01;
rmeddis@0 83 % stim.endSilence=-1;
rmeddis@0 84 % stim.rampOnDur=.002;
rmeddis@0 85 % stim.rampOffDur=-1;
rmeddis@0 86 % stim.niterations = 8; %0 for white noise
rmeddis@0 87 % stim.delay = 1/150;
rmeddis@0 88 % stim.irnGain = 1;
rmeddis@0 89 % [audio, msg]=stimulusCreate(globalStimParams, stim);stimComponents.clickWidth;
rmeddis@0 90 %
rmeddis@0 91 % stim.type='clicks'; % uses frequencies for duty cycle
rmeddis@0 92 % stim.toneDuration=.05;;
rmeddis@0 93 % stim.frequencies=500;
rmeddis@0 94 % stim.amplitudesdB=50;
rmeddis@0 95 % stim.beginSilence=.01;
rmeddis@0 96 % stim.endSilence=-1;
rmeddis@0 97 % stim.rampOnDur=.002;
rmeddis@0 98 % stim.rampOffDur=-1;
rmeddis@0 99 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 100 % stimComponents.clickWidth=.0001; % default= dt
rmeddis@0 101 % stimComponents.clickHeight= 20e-6; % default= 28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 102 % stim.clickTimes=[.4 .6]; % times in cylce when clicks occur, default = 1
rmeddis@0 103 %
rmeddis@0 104 %
rmeddis@0 105
rmeddis@0 106 msg=''; %error messages; no message is a good message
rmeddis@0 107
rmeddis@0 108 % plotting can be set as a separate argument or as a globalstimParams
rmeddis@0 109 % variable. this is for backwards compatibility only
rmeddis@0 110 if nargin>2,
rmeddis@0 111 globalStimParams.doPlot=doPlot;
rmeddis@0 112 end
rmeddis@0 113
rmeddis@0 114 % stimComponents(1,1).endSilence=-1; % end silence is always computed
rmeddis@0 115
rmeddis@0 116 % perform checks and set defaults
rmeddis@0 117 [globalStimParams, stimComponents]=checkDescriptors(globalStimParams, stimComponents);
rmeddis@0 118
rmeddis@0 119
rmeddis@0 120 % create empty stereo audio of appropriate length
rmeddis@0 121 audio=zeros(globalStimParams.nSignalPoints, 2);
rmeddis@0 122 % signal=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 123 dt=globalStimParams.dt;
rmeddis@0 124
rmeddis@0 125 [Nears nComponentSounds]=size(stimComponents);
rmeddis@0 126 for ear=1:Nears % left/ right
rmeddis@0 127 % combinedSignal is the sum of all sounds in one ear
rmeddis@0 128 % it is a column vector
rmeddis@0 129 combinedSignal=zeros(globalStimParams.nSignalPoints,1);
rmeddis@0 130
rmeddis@0 131 % find valid components
rmeddis@0 132 % if a component is empty, it is not a validComponent and is ignored
rmeddis@0 133 validStimComponents=[];
rmeddis@0 134 for i=1:nComponentSounds
rmeddis@0 135 if ~isempty(stimComponents(ear,i).type)
rmeddis@0 136 validStimComponents=[validStimComponents i];
rmeddis@0 137 end
rmeddis@0 138 end
rmeddis@0 139
rmeddis@0 140 for componentNo=validStimComponents
rmeddis@0 141 % compute individual components before adding
rmeddis@0 142 stim=stimComponents(ear,componentNo);
rmeddis@0 143 switch stim.type
rmeddis@0 144 case 'tone'
rmeddis@0 145 stimulus=maketone(globalStimParams, stim);
rmeddis@0 146
rmeddis@0 147 case 'fmTone'
rmeddis@0 148 stimulus=makeFMtone(globalStimParams, stim);
rmeddis@0 149
rmeddis@0 150 case 'OHIO'
rmeddis@0 151 stim.beginSilence=0;
rmeddis@0 152 stimulus=makeOHIOtones(globalStimParams, stim);
rmeddis@0 153
rmeddis@0 154 case 'transposedStimulus'
rmeddis@0 155 stim.beginSilence=0; % necessary because of recursion
rmeddis@0 156 stimulus=makeTransposedStimulus(globalStimParams, stim);
rmeddis@0 157
rmeddis@0 158 case { 'noise', 'pinkNoise'}
rmeddis@0 159 stimulus=makeNoise(globalStimParams, stim);
rmeddis@0 160
rmeddis@0 161 case { 'whiteNoise'}
rmeddis@0 162 stimulus=makeWhiteNoise(globalStimParams, stim);
rmeddis@0 163
rmeddis@0 164 case {'IRN', 'irn'}
rmeddis@0 165 stimulus=makeIRN(globalStimParams, stim);
rmeddis@0 166
rmeddis@0 167 case {'RPN'}
rmeddis@0 168 stimulus=makeRPN(globalStimParams, stim);
rmeddis@0 169
rmeddis@0 170 case 'clicks'
rmeddis@0 171 stimulus=makeClicks(globalStimParams, stim);
rmeddis@0 172
rmeddis@0 173 case 'PressnitzerClicks'
rmeddis@0 174 % kxx clicks
rmeddis@0 175 % k is 1/clickRepeatFrequency
rmeddis@0 176 stimulus=makePressnitzerClicks(globalStimParams, stimComponents);
rmeddis@0 177
rmeddis@0 178 case 'PressnitzerABxClicks'
rmeddis@0 179 % kxx clicks
rmeddis@0 180 % k is 1/clickRepeatFrequency
rmeddis@0 181 stimulus=makePressnitzerABxClicks(globalStimParams, stimComponents);
rmeddis@0 182
rmeddis@0 183 case 'ABxClicks'
rmeddis@0 184 % A=rand*k, B=k-A, x=rand*k.
rmeddis@0 185 stimulus=makeABxClicks(globalStimParams, stimComponents);
rmeddis@0 186
rmeddis@0 187 case 'YostClicks'
rmeddis@0 188 % kxx clicks
rmeddis@0 189 % k is 1/clickRepeatFrequency
rmeddis@0 190 stimulus=makeYostClicks(globalStimParams, stimComponents);
rmeddis@0 191
rmeddis@0 192 case 'kxxClicks'
rmeddis@0 193 % kxx clicks
rmeddis@0 194 % k is 1/clickRepeatFrequency
rmeddis@0 195 stimulus=makeKxxClicks(globalStimParams, stimComponents);
rmeddis@0 196
rmeddis@0 197
rmeddis@0 198 % case 'babble'
rmeddis@0 199 % % NB random start in a long file
rmeddis@0 200 % [stimulus sampleRate]= wavread('babble');
rmeddis@0 201 % nPoints=round(sampleRate*...
rmeddis@0 202 % stimComponents(ear,componentNo).toneDuration);
rmeddis@0 203 % start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 204 % stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 205 % rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 206 % dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 207 % gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 208 % stimulus=stimulus'*gain;
rmeddis@0 209
rmeddis@0 210 case 'speech'
rmeddis@0 211 [stimulus sampleRate]= wavread('speech');
rmeddis@0 212 stimulus=stimulus';
rmeddis@0 213 nPoints=sampleRate*stimComponents(ear,componentNo).toneDuration;
rmeddis@0 214 if nPoints > length(stimulus)
rmeddis@0 215 initialSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 216 else
rmeddis@0 217 initialSilence=[];
rmeddis@0 218 start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 219 stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 220 end
rmeddis@0 221 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 222 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 223 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 224 stimulus=stimulus*gain;
rmeddis@0 225 stimulus=[stimulus initialSilence ];
rmeddis@0 226
rmeddis@0 227
rmeddis@0 228 case 'file'
rmeddis@0 229 % component already read from file and stored in stimulus. Insert it here
rmeddis@0 230 % additional code for establishing signal rms level
rmeddis@0 231 % NB signal is always mono at this stage
rmeddis@0 232
rmeddis@0 233 stimulus=stim.stimulus;
rmeddis@0 234 dBSPL=stim.amplitudesdB;
rmeddis@0 235
rmeddis@0 236 nPoints=round(stim.toneDuration/dt);
rmeddis@0 237 [r c]=size(stimulus);
rmeddis@0 238 if r>c, stimulus=stimulus'; end % secure horizontal vector
rmeddis@0 239 stimulus=stimulus(1,1:nPoints); % only mono taken from file
rmeddis@0 240
rmeddis@0 241 try
rmeddis@0 242 % dB rms
rmeddis@0 243 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 244 % special request to set fixed rms for stimulus
rmeddis@0 245 dBSPLrms=stimComponents(ear,componentNo).amplitudesdBrms;
rmeddis@0 246 if ~(dBSPLrms==-1)
rmeddis@0 247 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 248 stimulus=stimulus*gain;
rmeddis@0 249 end
rmeddis@0 250 catch
rmeddis@0 251 % If no request for rms level is made
rmeddis@0 252 % set dB as peak amp
rmeddis@0 253 [stimulus gain]= normalize(stimulus);
rmeddis@0 254 dBSPL=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 255 if ~(dBSPL==-1)
rmeddis@0 256 amplitude=28e-6*10.^(dBSPL/20);
rmeddis@0 257 stimulus=stimulus*amplitude;
rmeddis@0 258 end
rmeddis@0 259 end
rmeddis@0 260
rmeddis@0 261 case 'none'
rmeddis@0 262 % no stimulus
rmeddis@0 263 stimulus=zeros(1,round(stim.toneDuration/dt));
rmeddis@0 264
rmeddis@0 265 case 'digitStrings'
rmeddis@0 266 % select a digit string at random anduse as target
rmeddis@0 267 files=dir(['..' filesep '..' filesep 'multithresholdResources\digitStrings']);
rmeddis@0 268 files=files(3:end);
rmeddis@0 269 nFiles=length(files);
rmeddis@0 270 fileNo=ceil(nFiles*rand);
rmeddis@0 271 fileData=files(fileNo);
rmeddis@0 272 fileName=['..\..\multithresholdResources\digitStrings\' fileData.name];
rmeddis@0 273 [stimulus sampleRate]=wavread(fileName);
rmeddis@0 274 stimulus=stimulus(:,1)'; % make into a row vector
rmeddis@0 275 % estimate the extend of endsilence padding
rmeddis@0 276 nPoints=sampleRate*...
rmeddis@0 277 stimComponents(ear,componentNo).toneDuration;
rmeddis@0 278 if nPoints > length(stimulus)
rmeddis@0 279 endSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 280 else
rmeddis@0 281 % or truncate the file
rmeddis@0 282 endSilence=[];
rmeddis@0 283 stimulus=stimulus(1:nPoints);
rmeddis@0 284 end
rmeddis@0 285 % compute rms before adding silence
rmeddis@0 286 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 287 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 288 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 289 stimulus=stimulus*gain;
rmeddis@0 290 stimulus=[stimulus endSilence];
rmeddis@0 291 global stimulusParameters
rmeddis@0 292 stimulusParameters.digitString=fileName(end-7:end-5);
rmeddis@0 293
rmeddis@0 294 otherwise
rmeddis@0 295 switch stim.type(end-5:end)
rmeddis@0 296 % any file name with 'Babble' at the end is a
rmeddis@0 297 % multiThreshold file
rmeddis@0 298 case 'Babble'
rmeddis@0 299 % one of the many babbles is selected.
rmeddis@0 300 % NB random start in a long file
rmeddis@0 301 % stim.type should contain the name of the babble file
rmeddis@0 302 fileName=['..' filesep '..' filesep ...
rmeddis@0 303 'multithresholdResources' filesep ...
rmeddis@0 304 'backgrounds and maskers'...
rmeddis@0 305 filesep stim.type];
rmeddis@0 306
rmeddis@0 307 [stimulus sampleRate]= wavread(fileName);
rmeddis@0 308 if ~isequal(sampleRate, globalStimParams.FS)
rmeddis@0 309 % NB the file will read but will disagree with
rmeddis@0 310 % tone stimuli or other files read
rmeddis@0 311 msg= ['error: file sample rate disagrees ' ...
rmeddis@0 312 'with sample rate requested in paradigm'...
rmeddis@0 313 ' file (' ...
rmeddis@0 314 num2str(globalStimParams.FS) ').'];
rmeddis@0 315 error(msg);
rmeddis@0 316 end
rmeddis@0 317 nPoints=round(sampleRate*...
rmeddis@0 318 stimComponents(ear,componentNo).toneDuration);
rmeddis@0 319 start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 320 stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 321 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 322 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 323 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 324 stimulus=stimulus'*gain;
rmeddis@0 325
rmeddis@0 326 otherwise
rmeddis@0 327 % stim.type may be the name of a file to be read
rmeddis@0 328 % play from beginning for stimulus duration
rmeddis@0 329 try
rmeddis@0 330 [stimulus sampleRate]= wavread([stim.type '.wav']);
rmeddis@0 331 catch
rmeddis@0 332 error(['stimulusCreate: unrecognised stimulus type -> '...
rmeddis@0 333 stim.type])
rmeddis@0 334 end
rmeddis@0 335 if ~isequal(sampleRate, globalStimParams.FS)
rmeddis@0 336 % NB the file will read but will disagree with
rmeddis@0 337 % tone stimuli or other files read
rmeddis@0 338 msg= ['error: file sample rate disagrees ' ...
rmeddis@0 339 'with sample rate requested in paradigm'...
rmeddis@0 340 ' file (' ...
rmeddis@0 341 num2str(globalStimParams.FS) ').'];
rmeddis@0 342 error(msg);
rmeddis@0 343 end
rmeddis@0 344 stimulus=stimulus'; % make into a row vector
rmeddis@0 345 % estimate the extend of endsilence padding
rmeddis@0 346 nPoints=sampleRate*...
rmeddis@0 347 stimComponents(ear,componentNo).toneDuration;
rmeddis@0 348 if nPoints > length(stimulus)
rmeddis@0 349 endSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 350 else
rmeddis@0 351 % or truncate the file
rmeddis@0 352 endSilence=[];
rmeddis@0 353 stimulus=stimulus(1:nPoints);
rmeddis@0 354 end
rmeddis@0 355 % compute rms before adding silence
rmeddis@0 356 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 357 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 358 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 359 stimulus=stimulus*gain;
rmeddis@0 360 stimulus=[stimulus endSilence];
rmeddis@0 361 end
rmeddis@0 362 end
rmeddis@0 363
rmeddis@0 364 % NB stimulus is a row vector now!
rmeddis@0 365 % audio and combinedSignal were column vectors
rmeddis@0 366 % signal will be a row vector
rmeddis@0 367
rmeddis@0 368 % filter stimulus
rmeddis@0 369 try
rmeddis@0 370 % if filter field is present, [lower upper order]
rmeddis@0 371 if stim.filter(1)>0 % 0 means don't filter
rmeddis@0 372 stimulus=Butterworth (stimulus, dt, stim.filter(1), ...
rmeddis@0 373 stim.filter(2), stim.filter(3));
rmeddis@0 374
rmeddis@0 375 end
rmeddis@0 376 catch
rmeddis@0 377 end
rmeddis@0 378
rmeddis@0 379
rmeddis@0 380 % apply amplitude modulation
rmeddis@0 381 if isfield(stim,'AMfrequency') & isfield(stim,'AMdepth')
rmeddis@0 382 if stim.AMfrequency>0 & stim.AMdepth>0
rmeddis@0 383 time=dt:dt:dt*length(stimulus);
rmeddis@0 384 modulator=sin(2*pi*stim.AMfrequency*time);
rmeddis@0 385 modulator=modulator*stim.AMdepth/100 + 1; % depth is percent
rmeddis@0 386 stimulus=stimulus.*modulator/2;
rmeddis@0 387 end
rmeddis@0 388 end
rmeddis@0 389
rmeddis@0 390 % Basic stimulus is now created.
rmeddis@0 391 % Add trappings, ramps, silences to main stimulus
rmeddis@0 392 rampOnTime=0; %ramp starts at the beginning of the stimulus
rmeddis@0 393 rampOffTime=stim.toneDuration-stim.rampOffDur;
rmeddis@0 394 if stim.rampOnDur>0.0001
rmeddis@0 395 stimulus=applyRampOn(stimulus, stim.rampOnDur, rampOnTime, 1/dt);
rmeddis@0 396 stimulus=applyRampOff(stimulus, stim.rampOffDur, rampOffTime, 1/dt);
rmeddis@0 397 end
rmeddis@0 398 if stim.rampOnDur<-0.0001 % apply Gaussian ramp
rmeddis@0 399 stimulus=applyGaussianRamps(stimulus, -stim.rampOnDur, 1/dt);
rmeddis@0 400 end
rmeddis@0 401
rmeddis@38 402 % begin silence
rmeddis@0 403 % start with a signal of the right length consisting of zeros
rmeddis@0 404 signal=zeros(1, globalStimParams.nSignalPoints);
rmeddis@0 405 % identify start of stimulus
rmeddis@0 406 insertStimulusAt=round(stim.beginSilence/dt)+1;
rmeddis@0 407 % add stimulus
rmeddis@0 408 endOfStimulus=insertStimulusAt+length(stimulus)-1;
rmeddis@0 409 if endOfStimulus<=globalStimParams.nSignalPoints
rmeddis@0 410 signal(1, insertStimulusAt: endOfStimulus)=stimulus;
rmeddis@0 411 else
rmeddis@0 412 error('stimulusCreate: tone too long to fit into the overall duration')
rmeddis@0 413 end
rmeddis@0 414
rmeddis@0 415 % time signature
rmeddis@0 416 time=dt:dt:dt*length(signal);
rmeddis@38 417 % figure(22), plot(signal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1)
rmeddis@0 418
rmeddis@0 419 try
rmeddis@0 420 % create a column vector and trap if no signal has been created
rmeddis@0 421 signal=signal';
rmeddis@0 422 % also traps if signals are not the same length
rmeddis@0 423 combinedSignal=combinedSignal+signal;
rmeddis@0 424 % figure(21), plot(combinedSignal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1)
rmeddis@0 425 catch
rmeddis@0 426 % dump everything because there is a problem
rmeddis@0 427 globalStimParams
rmeddis@0 428 [ear componentNo]
rmeddis@0 429 stim
rmeddis@0 430 size(combinedSignal)
rmeddis@0 431 size(signal)
rmeddis@0 432 [ size(initialSilence) size(signal) size(endSilence)]
rmeddis@0 433 [ ear componentNo...
rmeddis@0 434 round(globalStimParams.overallDuration*globalStimParams.FS)...
rmeddis@0 435 round(stim.beginSilence*globalStimParams.FS)...
rmeddis@0 436 round(stim.toneDuration*globalStimParams.FS) ...
rmeddis@0 437 round(stim.endSilence*globalStimParams.FS)...
rmeddis@0 438 ( round(globalStimParams.overallDuration*globalStimParams.FS)...
rmeddis@0 439 -round(stim.beginSilence*globalStimParams.FS)...
rmeddis@0 440 -round(stim.toneDuration*globalStimParams.FS) ...
rmeddis@0 441 -round(stim.endSilence*globalStimParams.FS))...
rmeddis@0 442 ]
rmeddis@0 443 error(' trouble in stimulusCreate: signals are the wrong length ')
rmeddis@0 444 end
rmeddis@0 445
rmeddis@0 446 end % component no
rmeddis@0 447
rmeddis@0 448 audio(:,ear)= combinedSignal;
rmeddis@0 449
rmeddis@0 450 % FFT
rmeddis@0 451 try
rmeddis@0 452 if globalStimParams.FFT
rmeddis@0 453 showFFT (audio, dt)
rmeddis@0 454 end
rmeddis@0 455 catch
rmeddis@0 456 end
rmeddis@0 457
rmeddis@0 458
rmeddis@0 459 end % ear
rmeddis@0 460
rmeddis@0 461 switch globalStimParams.ears
rmeddis@0 462 % normally the signals are created in appropriate ears but .ears can
rmeddis@0 463 % overide this to produce a mono signal.
rmeddis@0 464 case 'monoticL';
rmeddis@0 465 % combine left and right ears to make a mono signal in the left ear
rmeddis@0 466 audio(:,1)=audio(:,1)+audio(:,2);
rmeddis@0 467 audio(:,2)=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 468
rmeddis@0 469 case 'monoticR';
rmeddis@0 470 % combine left and right ears to make a mono signal in the right ear
rmeddis@0 471 audio(:,2)=audio(:,1)+audio(:,2);
rmeddis@0 472 audio(:,1)=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 473
rmeddis@0 474 case 'diotic';
rmeddis@0 475 % combine left and right ears to make a mono signal in both ears
rmeddis@0 476 bothEarsCombined=audio(:,1)+audio(:,2);
rmeddis@0 477 audio(:,2)=bothEarsCombined;
rmeddis@0 478 audio(:,1)=bothEarsCombined;
rmeddis@0 479
rmeddis@0 480 otherwise
rmeddis@0 481 % Any other denomination produces no effect here
rmeddis@0 482 end
rmeddis@0 483
rmeddis@0 484 % Plotting as required
rmeddis@0 485 if globalStimParams.doPlot
rmeddis@0 486 figure(9), clf
rmeddis@0 487 plot(time,audio(:,1)'), hold on,
rmeddis@0 488 if Nears>1
rmeddis@0 489 offSet=(max(audio(:,1))+max(audio(:,2)))/10;
rmeddis@0 490 offSet=2*offSet+max(audio(:,1))+max(audio(:,2));
rmeddis@0 491 plot(time,audio(:,2)'+offSet,'r'), hold off
rmeddis@0 492 end
rmeddis@0 493 ylabel('left right')
rmeddis@0 494 end
rmeddis@0 495
rmeddis@0 496 % Calibration
rmeddis@0 497 % all signals are divided by this correction factor
rmeddis@0 498 % peakAmp=globalStimParams.audioOutCorrection; % microPascals = 100 dB SPL
rmeddis@0 499
rmeddis@0 500 audio=audio/globalStimParams.audioOutCorrection;
rmeddis@0 501
rmeddis@0 502 if globalStimParams.doPlay
rmeddis@35 503 if ispc
rmeddis@35 504 wavplay(audio,globalStimParams.FS)
rmeddis@35 505 else
rmeddis@35 506 sound(audio,globalStimParams.FS)
rmeddis@35 507 end
rmeddis@35 508
rmeddis@0 509 wavplay(audio,globalStimParams.FS)
rmeddis@0 510 end
rmeddis@0 511 % all Done
rmeddis@0 512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rmeddis@0 513
rmeddis@0 514
rmeddis@0 515
rmeddis@0 516 %---------------------------------------------------- maketone
rmeddis@0 517 function tone=maketone(globalStimParams, stimComponents)
rmeddis@0 518 % maketone generates a stimComponents tone
rmeddis@0 519 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 520 % tone is returned in Pascals
rmeddis@0 521 % frequencies is a list of frequencies
rmeddis@0 522 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 523 %
rmeddis@0 524 % defaults:
rmeddis@0 525 % phase = sin
rmeddis@0 526 % dBSPL=56 dB SPL
rmeddis@0 527
rmeddis@0 528 dt=globalStimParams.dt;
rmeddis@0 529 frequencies=stimComponents.frequencies;
rmeddis@0 530 toneDuration=stimComponents.toneDuration;
rmeddis@0 531 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 532 phases=stimComponents.phases;
rmeddis@0 533
rmeddis@0 534 if ischar(phases)
rmeddis@0 535 switch phases
rmeddis@0 536 case 'sin'
rmeddis@0 537 phases= zeros(1,length(frequencies));
rmeddis@0 538 case 'cos'
rmeddis@0 539 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 540 case 'alt'
rmeddis@0 541 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 542 if length(phases)<length(frequencies)
rmeddis@0 543 phases=[phases 0];
rmeddis@0 544 end
rmeddis@0 545 case {'ran', 'rand'}
rmeddis@0 546 phases= 2*pi*rand(1,length(frequencies));
rmeddis@0 547 end
rmeddis@0 548 end
rmeddis@0 549
rmeddis@0 550 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 551 if length(phases)<length(frequencies)
rmeddis@0 552 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 553 end
rmeddis@0 554
rmeddis@0 555 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 556 if length(dBSPL)<length(dBSPL)
rmeddis@0 557 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 558 end
rmeddis@0 559
rmeddis@0 560 time=dt:dt:toneDuration;
rmeddis@0 561 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 562
rmeddis@0 563 tone=zeros(size(time));
rmeddis@0 564 for i=1:length(frequencies)
rmeddis@0 565 frequency=frequencies(i);
rmeddis@0 566 phase=phases(i);
rmeddis@0 567 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase);
rmeddis@0 568 end
rmeddis@0 569
rmeddis@0 570 % figure(1), plot(time, signal)
rmeddis@0 571
rmeddis@0 572
rmeddis@0 573 %---------------------------------------------------- makeOHIOtones
rmeddis@0 574 function stimulus=makeOHIOtones(globalStimParams, stimComponents)
rmeddis@0 575
rmeddis@0 576 % Generates a stimulus consisting of one or more 10-ms tones
rmeddis@38 577 % The length of the list of frequencies determines the numberof tones
rmeddis@38 578 % Tones are either presented at 10-ms intervals or simultaneously
rmeddis@38 579 % all tones are individually ramped
rmeddis@0 580 % Each tone has its own amplitude and its own ramp.
rmeddis@0 581
rmeddis@0 582 frequencies=stimComponents.frequencies;
rmeddis@0 583 amplitudesdB=stimComponents.amplitudesdB;
rmeddis@0 584 nFrequencies=length(frequencies);
rmeddis@0 585
rmeddis@38 586 if amplitudesdB==-100
rmeddis@38 587 % catch trial
rmeddis@38 588 amplitudesdB=repmat(-100,1,nFrequencies);
rmeddis@38 589 end
rmeddis@38 590
rmeddis@0 591 dt=globalStimParams.dt;
rmeddis@38 592
rmeddis@0 593 toneDuration=.010;
rmeddis@0 594 time=dt:dt:toneDuration;
rmeddis@0 595
rmeddis@38 596 % fixed ramp, silenceDuration, toneDuration
rmeddis@38 597 rampDuration=0.005;
rmeddis@0 598 rampTime=dt:dt:rampDuration;
rmeddis@38 599 ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ...
rmeddis@38 600 ones(1,length(time)-length(rampTime))];
rmeddis@0 601 ramp=ramp.*fliplr(ramp);
rmeddis@0 602
rmeddis@38 603 silenceDuration=0.010;
rmeddis@38 604 silenceDurationLength=round(silenceDuration/dt);
rmeddis@38 605 initialSilence=zeros(1,silenceDurationLength);
rmeddis@38 606
rmeddis@38 607 silenceToneDuration=toneDuration + silenceDuration;
rmeddis@38 608 silenceToneDurationLength=round(silenceToneDuration/dt);
rmeddis@38 609
rmeddis@38 610 % OHIO spect produces simultaneous tones
rmeddis@38 611 if strcmp(stimComponents.OHIOtype,'OHIOspect')
rmeddis@38 612 totalDuration=silenceToneDuration;
rmeddis@38 613 else
rmeddis@38 614 totalDuration=silenceToneDuration*nFrequencies;
rmeddis@38 615 end
rmeddis@38 616
rmeddis@38 617 totalDurationLength=round(totalDuration/dt);
rmeddis@38 618 stimulus=zeros(1,totalDurationLength);
rmeddis@38 619 toneBeginPTR=1;
rmeddis@0 620
rmeddis@0 621 for i=1:nFrequencies
rmeddis@0 622 frequency=frequencies(i);
rmeddis@0 623 dBSPL=amplitudesdB(i);
rmeddis@0 624 amplitude=28e-6* 10.^(dBSPL/20);
rmeddis@0 625 tone=amplitude*sin(2*pi*frequency*time);
rmeddis@0 626 tone=tone.*ramp;
rmeddis@38 627 % stimulus is normally zeros except for OHIOspect
rmeddis@38 628 stimulus(toneBeginPTR:toneBeginPTR+silenceToneDurationLength-1)=...
rmeddis@38 629 [initialSilence tone]+...
rmeddis@38 630 stimulus(toneBeginPTR:toneBeginPTR+silenceToneDurationLength-1);
rmeddis@38 631 if ~strcmp(stimComponents.OHIOtype,'OHIOspect')
rmeddis@38 632 toneBeginPTR=toneBeginPTR+silenceToneDurationLength;
rmeddis@38 633 end
rmeddis@0 634 end
rmeddis@0 635 % figure(2), plot( stimulus')
rmeddis@0 636
rmeddis@0 637
rmeddis@0 638 %---------------------------------------------------- makeFMtone
rmeddis@0 639 function tone=makeFMtone(globalStimParams, stimComponents)
rmeddis@0 640 % maketone generates a stimComponents tone
rmeddis@0 641 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 642 % tone is returned in Pascals
rmeddis@0 643 % frequencies is a list of frequencies
rmeddis@0 644 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 645 %
rmeddis@0 646 % defaults:
rmeddis@0 647 % phase = sin
rmeddis@0 648 % dBSPL=56 dB SPL
rmeddis@0 649
rmeddis@0 650 dt=globalStimParams.dt;
rmeddis@0 651 frequencies=stimComponents.frequencies;
rmeddis@0 652 toneDuration=stimComponents.toneDuration;
rmeddis@0 653 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 654 phases=stimComponents.phases;
rmeddis@0 655 fmDepth=stimComponents.fmDepth;
rmeddis@0 656 fmFrequency=stimComponents.fmFrequency;
rmeddis@0 657
rmeddis@0 658 if ischar(phases)
rmeddis@0 659 switch phases
rmeddis@0 660 case 'sin'
rmeddis@0 661 phases= zeros(1,length(frequencies));
rmeddis@0 662 case 'cos'
rmeddis@0 663 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 664 case 'alt'
rmeddis@0 665 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 666 if length(phases)<length(frequencies)
rmeddis@0 667 phases=[phases 0];
rmeddis@0 668 end
rmeddis@0 669 end
rmeddis@0 670 end
rmeddis@0 671
rmeddis@0 672 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 673 if length(phases)<length(frequencies)
rmeddis@0 674 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 675 end
rmeddis@0 676
rmeddis@0 677 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 678 if length(dBSPL)<length(dBSPL)
rmeddis@0 679 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 680 end
rmeddis@0 681
rmeddis@0 682 time=dt:dt:toneDuration;
rmeddis@0 683 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 684
rmeddis@0 685 tone=zeros(size(time));
rmeddis@0 686 for i=1:length(frequencies)
rmeddis@0 687 frequency=frequencies(i);
rmeddis@0 688 phase=phases(i);
rmeddis@0 689 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase + fmDepth*sin(2*pi*fmFrequency*time));
rmeddis@0 690 end
rmeddis@0 691
rmeddis@0 692 % figure(1), plot(time, signal)
rmeddis@0 693
rmeddis@0 694 %----------------------------------------------------makeTransposedStimulus
rmeddis@0 695 function [transposedStimulus]=makeTransposedStimulus(globalStimParams, stim)
rmeddis@0 696 % globalStimParams.FS=100000;
rmeddis@0 697 % globalStimParams.overallDuration=.1; % s
rmeddis@0 698 % globalStimParams.doPlot=1;
rmeddis@0 699 %
rmeddis@0 700 % stim.type='transposedStimulus';
rmeddis@0 701 % stim.phases='sin';
rmeddis@0 702 % stim.toneDuration=.05;;
rmeddis@0 703 % stim.frequencies=500;
rmeddis@0 704 % stim.amplitudesdB=50;
rmeddis@0 705 % stim.beginSilence=.01;
rmeddis@0 706 % stim.endSilence=-1;
rmeddis@0 707 % stim.rampOnDur=.002;
rmeddis@0 708 % stim.rampOffDur=-1;
rmeddis@0 709 %
rmeddis@0 710 % stim.transCarrierFreq=4000;
rmeddis@0 711 % stim.transModFreq=100;
rmeddis@0 712
rmeddis@0 713 transposedStimulus=[];
rmeddis@0 714 % make envelope of transposed tone
rmeddis@0 715 for i=1:length(stim.transModFreq)
rmeddis@0 716 stim.type='tone';
rmeddis@0 717 stim.frequencies=stim.transModFreq(i);
rmeddis@0 718 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 719 [envelope, msg]=stimulusCreate(globalStimParams, stim); % NB recursive
rmeddis@0 720 envelope=envelope(:,1); % mono
rmeddis@0 721 % HW rectify
rmeddis@0 722 envelope(find(envelope<0))=0;
rmeddis@0 723 % LP filter
rmeddis@0 724 maxEnvelope=max(envelope);
rmeddis@0 725 envelope=UTIL_Butterworth (envelope, globalStimParams.dt, 10, .2*stim.transModFreq(i), 2);
rmeddis@0 726 envelope=envelope*maxEnvelope/max(envelope);
rmeddis@0 727
rmeddis@0 728 % make the carrier
rmeddis@0 729 stim.frequencies=stim.transCarrierFreq(i);
rmeddis@0 730 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 731 [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 732 carrier=audio(:,1);
rmeddis@0 733 x= (carrier.*envelope)';
rmeddis@0 734 % base amplitude on peak of unmodulated carrier
rmeddis@0 735 x=x/max(carrier);
rmeddis@0 736 transposedStimulus=[transposedStimulus; x];
rmeddis@0 737 end
rmeddis@0 738 transposedStimulus=sum(transposedStimulus,1);
rmeddis@0 739 % clf,plot(transposedStimulus)
rmeddis@0 740
rmeddis@0 741 %--------------------------------------------------------------------makeClicks
rmeddis@0 742 function clickTrain=makeClicks(globalStimParams, stimComponents)
rmeddis@0 743 % makeClicks(F0, clickTimes, duration, FS);
rmeddis@0 744 % F0 specifies the repetition rate of the click sequence
rmeddis@0 745 % If F0=-1, a single click is generated at the start of the duration of the signal
rmeddis@0 746 %
rmeddis@0 747 % clickTimes a are fractions of the period
rmeddis@0 748 % and specify when the click appears in the period
rmeddis@0 749 % A click time of 1 is reset to zero.
rmeddis@0 750 % if the clicktime plus the click width is greater than the period, no click is generated
rmeddis@0 751 % clicks are treated as 20 microPascal high before amplification
rmeddis@0 752 % unless otherwise specified in stimComponents.clickHeight
rmeddis@0 753 % click width is dt unless specified in stimComponents.clickWidth
rmeddis@0 754 %
rmeddis@0 755 % for regular pulse train set clicktimes=1 or zero;
rmeddis@0 756 % FS is the sampling interval;
rmeddis@0 757 % CarlyonClickTrain(100, [.4 1], 40, 441000);
rmeddis@0 758
rmeddis@0 759 FS=globalStimParams.FS; % sample rate
rmeddis@0 760 dt=1/FS;
rmeddis@0 761
rmeddis@0 762 try,clickWidth=stimComponents.clickWidth;catch, clickWidth=dt; end
rmeddis@0 763 try,clickHeight=stimComponents.clickHeight; catch, clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20); end
rmeddis@0 764 try, clickTimes=stimComponents.clickTimes; catch, clickTimes=1; end
rmeddis@0 765
rmeddis@0 766 % clickTimes are the times in a cycle that the click
rmeddis@0 767 % occurs
rmeddis@0 768 checkClickTimes=clickTimes-1;
rmeddis@0 769 if max(checkClickTimes)>1
rmeddis@0 770 msg= 'click times must be <= than 1 (period)';
rmeddis@0 771 return
rmeddis@0 772 end
rmeddis@0 773
rmeddis@0 774 if clickWidth>=1/stimComponents.clickRepeatFrequency
rmeddis@0 775 msg= 'click width is too great for frequency';
rmeddis@0 776 return
rmeddis@0 777 end
rmeddis@0 778
rmeddis@0 779 duration=stimComponents.toneDuration;
rmeddis@0 780 totalLength=round(stimComponents.toneDuration/dt);
rmeddis@0 781 F0=stimComponents.clickRepeatFrequency;
rmeddis@0 782 F0=round(F0/dt)*dt;
rmeddis@0 783 if F0==-1 % single click required
rmeddis@0 784 F0=1/duration;
rmeddis@0 785 repetitions=1;
rmeddis@0 786 clickStartTimes=1; %clicktimes are fractions of a period
rmeddis@0 787 else
rmeddis@0 788 repetitions=round(F0*duration)-1;
rmeddis@0 789 duration=repetitions/F0;
rmeddis@0 790 clickStartTimes=clickTimes;
rmeddis@0 791 end
rmeddis@0 792 % if a clickTime=1 (end of duty period) set it to the beginning
rmeddis@0 793 clickStartTimes(clickStartTimes==1)=0;
rmeddis@0 794
rmeddis@0 795 period=1/F0;
rmeddis@0 796 time=dt:dt:period;
rmeddis@0 797 nPoints=length(time);
rmeddis@0 798 signal=zeros(1,nPoints);
rmeddis@0 799 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 800
rmeddis@0 801 % compute click train for a single cycle
rmeddis@0 802 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 803 for i=1:length(clickStartTimes)
rmeddis@0 804 % if clickStartTimes(i)<clickWidth
rmeddis@0 805 % clickStartTimes(i)=dt;
rmeddis@0 806 % end
rmeddis@0 807 clickTime=round(period*clickStartTimes(i)/dt -dt);
rmeddis@0 808 % clicks are treated as 20 microPascal high
rmeddis@0 809 if clickTime+clickWidthNpoints<length(signal)
rmeddis@0 810 signal(clickTime+1:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 811 end
rmeddis@0 812 end
rmeddis@0 813
rmeddis@0 814 clickTrain=repmat(signal, 1, repetitions);
rmeddis@0 815
rmeddis@0 816 if length(clickTrain)>totalLength
rmeddis@0 817 clickTrain=clickTrain(1:totalLength);
rmeddis@0 818 elseif length(clickTrain)<totalLength
rmeddis@0 819 timeToAdd=zeros(1,round((totalLength-length(clickTrain))));
rmeddis@0 820 clickTrain=[clickTrain timeToAdd];
rmeddis@0 821 % figure (1), plot(clickTrain)
rmeddis@0 822 end
rmeddis@0 823
rmeddis@0 824 %----------------------------------------------------------------makePressnitzerClicks
rmeddis@0 825 function signal=makePressnitzerClicks(globalStimParams, stimComponents)
rmeddis@0 826 % PressnitzerClicks(k,duration,dt)
rmeddis@0 827 % Generates a sequence of clicks with intervals kxx
rmeddis@0 828 % where x= rand*k/2
rmeddis@0 829 % This is not the same as Kaernbach and Demany clicks
rmeddis@0 830
rmeddis@0 831 FS=globalStimParams.FS; % sample rate
rmeddis@0 832 dt=1/FS;
rmeddis@0 833
rmeddis@0 834 % obligatory parameter
rmeddis@0 835 try
rmeddis@0 836 k=stimComponents.k;
rmeddis@0 837 catch
rmeddis@0 838 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 839 end
rmeddis@0 840
rmeddis@0 841 % optional parameters
rmeddis@0 842 if isfield(stimComponents,'clickWidth')
rmeddis@0 843 clickWidth=stimComponents.clickWidth;
rmeddis@0 844 else
rmeddis@0 845 clickWidth=dt;
rmeddis@0 846 end
rmeddis@0 847 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 848
rmeddis@0 849 if isfield(stimComponents,'clickHeight')
rmeddis@0 850 clickHeight=stimComponents.clickHeight;
rmeddis@0 851 else
rmeddis@0 852 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 853 end
rmeddis@0 854
rmeddis@0 855 duration=stimComponents.toneDuration;
rmeddis@0 856
rmeddis@0 857 signalLength=round(duration/dt);
rmeddis@0 858 signal=zeros(1,signalLength);
rmeddis@0 859 kInterval=round(k/dt);
rmeddis@0 860 halfk=k/2;
rmeddis@0 861 signal(1)=clickHeight;
rmeddis@0 862 timeIdx=0;
rmeddis@0 863 while timeIdx<signalLength
rmeddis@0 864 % first interval = k
rmeddis@0 865 clickTime=timeIdx+kInterval;
rmeddis@0 866 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 867 timeIdx=timeIdx+kInterval;
rmeddis@0 868
rmeddis@0 869 % second interval = 0 : k/2
rmeddis@0 870 intervalx1=round(rand*halfk/dt);
rmeddis@0 871 clickTime=timeIdx+intervalx1;
rmeddis@0 872 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 873 timeIdx=timeIdx+intervalx1;
rmeddis@0 874
rmeddis@0 875 % third interval = 0 : k/2
rmeddis@0 876 intervalx1=round(rand*halfk/dt);
rmeddis@0 877 clickTime=timeIdx+intervalx1;
rmeddis@0 878 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 879 timeIdx=timeIdx+intervalx1;
rmeddis@0 880 end
rmeddis@0 881
rmeddis@0 882 signal=signal(1:signalLength);
rmeddis@0 883 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 884
rmeddis@0 885 %----------------------------------------------------------------makePressnitzerABXClicks
rmeddis@0 886 function signal=makePressnitzerABxClicks(globalStimParams, stimComponents)
rmeddis@0 887 % Generates a sequence of clicks with intervals ABx
rmeddis@0 888 % AB interval is 2*k
rmeddis@0 889 % where A= rand* k
rmeddis@0 890 % B= k-A
rmeddis@0 891 % x= k/2
rmeddis@0 892 % These are second order clicks
rmeddis@0 893
rmeddis@0 894 FS=globalStimParams.FS; % sample rate
rmeddis@0 895 dt=1/FS;
rmeddis@0 896
rmeddis@0 897 % obligatory parameter
rmeddis@0 898 try
rmeddis@0 899 k=stimComponents.k;
rmeddis@0 900 catch
rmeddis@0 901 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 902 end
rmeddis@0 903
rmeddis@0 904 % optional parameters
rmeddis@0 905 if isfield(stimComponents,'clickWidth')
rmeddis@0 906 clickWidth=stimComponents.clickWidth;
rmeddis@0 907 else
rmeddis@0 908 clickWidth=dt;
rmeddis@0 909 end
rmeddis@0 910 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 911
rmeddis@0 912 if isfield(stimComponents,'clickHeight')
rmeddis@0 913 clickHeight=stimComponents.clickHeight;
rmeddis@0 914 else
rmeddis@0 915 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 916 end
rmeddis@0 917
rmeddis@0 918 duration=stimComponents.toneDuration;
rmeddis@0 919
rmeddis@0 920 signalLength=round(duration/dt);
rmeddis@0 921 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 922 ABinterval=k/dt; % i.e. the number of dt steps
rmeddis@0 923 randomInterval=ABinterval/2;
rmeddis@0 924 signal(1)=clickHeight;
rmeddis@0 925 time=0;
rmeddis@0 926 while time<signalLength
rmeddis@0 927 % first interval = A
rmeddis@0 928 intervalA=rand*ABinterval;
rmeddis@0 929 clickTime=round(time+intervalA)+1; % +1 avoids zero index
rmeddis@0 930 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 931 time=time+intervalA;
rmeddis@0 932
rmeddis@0 933 % second interval = B
rmeddis@0 934 intervalB=ABinterval-intervalA;
rmeddis@0 935 clickTime=round(time+intervalB)+1;
rmeddis@0 936 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 937 time=time+intervalB;
rmeddis@0 938
rmeddis@0 939 % third interval = 0 : k/2
rmeddis@0 940 intervalx1=rand*randomInterval; % mean random interval=k
rmeddis@0 941 clickTime=round(time+intervalx1)+1;
rmeddis@0 942 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 943 time=time+intervalx1;
rmeddis@0 944 end
rmeddis@0 945
rmeddis@0 946 signal=signal(1:signalLength);
rmeddis@0 947 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 948
rmeddis@0 949 %-----------------------------------------------------makeABxClicks
rmeddis@0 950 function signal=makeABxClicks(globalStimParams, stimComponents)
rmeddis@0 951 % Generates a sequence of clicks with intervals ABx
rmeddis@0 952 % AB interval is 2*k
rmeddis@0 953 % where A= rand* k
rmeddis@0 954 % B= k-A
rmeddis@0 955 % x= rand*2*k
rmeddis@0 956 % These are second order clicks
rmeddis@0 957
rmeddis@0 958 FS=globalStimParams.FS; % sample rate
rmeddis@0 959 dt=1/FS;
rmeddis@0 960
rmeddis@0 961 % obligatory parameter
rmeddis@0 962 try
rmeddis@0 963 k=stimComponents.k;
rmeddis@0 964 catch
rmeddis@0 965 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 966 end
rmeddis@0 967
rmeddis@0 968 % optional parameters
rmeddis@0 969 if isfield(stimComponents,'clickWidth')
rmeddis@0 970 clickWidth=stimComponents.clickWidth;
rmeddis@0 971 else
rmeddis@0 972 clickWidth=dt;
rmeddis@0 973 end
rmeddis@0 974 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 975
rmeddis@0 976 if isfield(stimComponents,'clickHeight')
rmeddis@0 977 clickHeight=stimComponents.clickHeight;
rmeddis@0 978 else
rmeddis@0 979 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 980 end
rmeddis@0 981
rmeddis@0 982 duration=stimComponents.toneDuration;
rmeddis@0 983
rmeddis@0 984 signalLength=round(duration/dt);
rmeddis@0 985 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 986 ABinterval=2*k/dt;
rmeddis@0 987 randomInterval=ABinterval;
rmeddis@0 988 signal(1)=clickHeight;
rmeddis@0 989 timeIdx=0;
rmeddis@0 990 while timeIdx<signalLength
rmeddis@0 991 % first interval = A
rmeddis@0 992 intervalA=round(rand*ABinterval);
rmeddis@0 993 clickTime=timeIdx+intervalA+1;
rmeddis@0 994 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 995 timeIdx=timeIdx+intervalA;
rmeddis@0 996
rmeddis@0 997 % second interval = B
rmeddis@0 998 intervalB=round(ABinterval-intervalA);
rmeddis@0 999 clickTime=timeIdx+intervalB;
rmeddis@0 1000 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 1001 timeIdx=timeIdx+intervalB;
rmeddis@0 1002
rmeddis@0 1003 % third interval = 0 : k
rmeddis@0 1004 intervalx1=round(rand*randomInterval); % mean random interval=k
rmeddis@0 1005 clickTime=timeIdx+intervalx1;
rmeddis@0 1006 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 1007 timeIdx=timeIdx+intervalx1;
rmeddis@0 1008 end
rmeddis@0 1009
rmeddis@0 1010 signal=signal(1:signalLength);
rmeddis@0 1011 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 1012
rmeddis@0 1013 %----------------------------------------------------------------makeYostClicks
rmeddis@0 1014 function signal=makeYostClicks(globalStimParams, stimComponents)
rmeddis@0 1015 % Generates a shuffled sequence of clicks with intervals kxxxx
rmeddis@0 1016 % where max(x)= 2*k
rmeddis@0 1017 % and there are n occurrences of x
rmeddis@0 1018 % this section requires:
rmeddis@0 1019 % stimComponents.k
rmeddis@0 1020 % stimComponents.nXs
rmeddis@0 1021 % stimComponents.toneDuration
rmeddis@0 1022 % optional:
rmeddis@0 1023 % stimComponents.clickWidth %useful because width depends on dt
rmeddis@0 1024 % stimComponents.clickHeight %best left to amplitude rescaling later
rmeddis@0 1025
rmeddis@0 1026 FS=globalStimParams.FS; % sample rate
rmeddis@0 1027 dt=1/FS;
rmeddis@0 1028
rmeddis@0 1029 % obligatory parameters
rmeddis@0 1030 try
rmeddis@0 1031 k=stimComponents.k;
rmeddis@0 1032 catch
rmeddis@0 1033 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 1034 end
rmeddis@0 1035
rmeddis@0 1036 try
rmeddis@0 1037 nXs=stimComponents.nXs;
rmeddis@0 1038 catch
rmeddis@0 1039 error('makeYostClicks: field ''nXs'' is missing from stimComponents')
rmeddis@0 1040 end
rmeddis@0 1041
rmeddis@0 1042 try
rmeddis@0 1043 shuffled=stimComponents.shuffled;
rmeddis@0 1044 catch
rmeddis@0 1045 error('makeYostClicks: field ''shuffled'' is missing from stimComponents')
rmeddis@0 1046 end
rmeddis@0 1047
rmeddis@0 1048 try
rmeddis@0 1049 duration=stimComponents.toneDuration;
rmeddis@0 1050 catch
rmeddis@0 1051 error('makeYostClicks: field ''toneDuration'' is missing from stimComponents')
rmeddis@0 1052 end
rmeddis@0 1053
rmeddis@0 1054 % optional parameters
rmeddis@0 1055 if isfield(stimComponents,'clickWidth')
rmeddis@0 1056 clickWidth=stimComponents.clickWidth;
rmeddis@0 1057 else
rmeddis@0 1058 clickWidth=dt;
rmeddis@0 1059 end
rmeddis@0 1060 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 1061
rmeddis@0 1062 if isfield(stimComponents,'clickHeight')
rmeddis@0 1063 clickHeight=stimComponents.clickHeight;
rmeddis@0 1064 else
rmeddis@0 1065 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1066 end
rmeddis@0 1067
rmeddis@0 1068 kInterval=round(k/dt);
rmeddis@0 1069 twoK=k*2; % max width of x interval
rmeddis@0 1070
rmeddis@0 1071 signalLength=round(duration/dt);
rmeddis@0 1072 signal=zeros(1,signalLength);
rmeddis@0 1073
rmeddis@0 1074 timeIdx=0;
rmeddis@0 1075 intervalCount=0;
rmeddis@0 1076 while timeIdx<signalLength
rmeddis@0 1077 timeIdx=timeIdx+kInterval;
rmeddis@0 1078 if timeIdx>signalLength, break,end
rmeddis@0 1079 intervalCount=intervalCount+1;
rmeddis@0 1080 intervals(intervalCount)=kInterval;
rmeddis@0 1081
rmeddis@0 1082 % repeat x intervals as required
rmeddis@0 1083 if nXs>0
rmeddis@0 1084 for nX=1:nXs
rmeddis@0 1085 xInterval=round(rand*twoK/dt);
rmeddis@0 1086 timeIdx=timeIdx+xInterval;
rmeddis@0 1087 if timeIdx>signalLength, break,end
rmeddis@0 1088 intervalCount=intervalCount+1;
rmeddis@0 1089 intervals(intervalCount)=xInterval;
rmeddis@0 1090 end
rmeddis@0 1091 end
rmeddis@0 1092 if timeIdx>signalLength, break,end
rmeddis@0 1093 end
rmeddis@0 1094
rmeddis@0 1095 % shuffle intervals
rmeddis@0 1096 if shuffled
rmeddis@0 1097 randomNumbers=rand(1,length(intervals));
rmeddis@0 1098 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1099 intervals=intervals(idx);
rmeddis@0 1100 idx=intervals>0;
rmeddis@0 1101 intervals=intervals(idx);
rmeddis@0 1102 end
rmeddis@0 1103
rmeddis@0 1104 intervalCount=length(intervals);
rmeddis@0 1105 signal(1)=clickHeight;
rmeddis@0 1106 clickTime=0;
rmeddis@0 1107 for i=1:intervalCount
rmeddis@0 1108 clickTime=clickTime+intervals(i);
rmeddis@0 1109 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 1110 end
rmeddis@0 1111 signal=signal(1:signalLength);
rmeddis@0 1112 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 1113
rmeddis@0 1114 %--------------------------------------------------------------------makeKxxClicks
rmeddis@0 1115 function signal=makeKxxClicks(globalStimParams, stimComponents)
rmeddis@0 1116 % Click train consists of kkxxx.. sequences
rmeddis@0 1117 % k is the duration of a fixed interval (seconds)
rmeddis@0 1118 % random intervals are distributed 0 : 2* k (NB not like Pressnitzer clicks)
rmeddis@0 1119 % nKs is the number of successive 'k' intervals
rmeddis@0 1120 % nXs is the number of random intervals between k sequences
rmeddis@0 1121 % sequences of 3 x intervals > k are replaced with new sequences
rmeddis@0 1122 % shuffled causes all intervals to be reordered randomly
rmeddis@0 1123 % NB 1/k is the mean click rate
rmeddis@0 1124
rmeddis@0 1125 FS=globalStimParams.FS; % sample rate
rmeddis@0 1126 dt=1/FS;
rmeddis@0 1127
rmeddis@0 1128 try
rmeddis@0 1129 k=stimComponents.k; % duration (s) of fixed intervals
rmeddis@0 1130 catch
rmeddis@0 1131 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 1132 end
rmeddis@0 1133
rmeddis@0 1134 try
rmeddis@0 1135 duration=stimComponents.toneDuration;
rmeddis@0 1136 catch
rmeddis@0 1137 error('makeYostClicks: field ''duration'' is missing from stimComponents')
rmeddis@0 1138 end
rmeddis@0 1139
rmeddis@0 1140 if isfield(stimComponents,'clickWidth')
rmeddis@0 1141 clickWidth=stimComponents.clickWidth;
rmeddis@0 1142 else
rmeddis@0 1143 clickWidth=dt;
rmeddis@0 1144 end
rmeddis@0 1145
rmeddis@0 1146 if isfield(stimComponents,'clickHeight')
rmeddis@0 1147 clickHeight=stimComponents.clickHeight;
rmeddis@0 1148 else
rmeddis@0 1149 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1150 end
rmeddis@0 1151
rmeddis@0 1152
rmeddis@0 1153 if isfield(stimComponents,'order')
rmeddis@0 1154 order=stimComponents.order;
rmeddis@0 1155 else
rmeddis@0 1156 order=1;
rmeddis@0 1157 end
rmeddis@0 1158
rmeddis@0 1159 if isfield(stimComponents,'nKs')
rmeddis@0 1160 nKs=stimComponents.nKs;
rmeddis@0 1161 else
rmeddis@0 1162 nKs=1;
rmeddis@0 1163 end
rmeddis@0 1164
rmeddis@0 1165 if isfield(stimComponents,'nXs')
rmeddis@0 1166 nXs=stimComponents.nXs;
rmeddis@0 1167 else
rmeddis@0 1168 nXs=1;
rmeddis@0 1169 end
rmeddis@0 1170
rmeddis@0 1171 if isfield(stimComponents,'shuffled')
rmeddis@0 1172 shuffled=stimComponents.shuffled;
rmeddis@0 1173 else
rmeddis@0 1174 shuffled=1;
rmeddis@0 1175 end
rmeddis@0 1176
rmeddis@0 1177 kLength=round(k/dt); % fixed interval
rmeddis@0 1178 xLength=2*kLength; % maximum random interval
rmeddis@0 1179 requiredSignalLength=round(duration/dt);
rmeddis@0 1180 intervalsPerCycle=(nKs+nXs);
rmeddis@0 1181 cycleLength=nKs*kLength+nXs*xLength;
rmeddis@0 1182 % more cycles to allow for uncertainty
rmeddis@0 1183 nCycles=5*round(requiredSignalLength/cycleLength);
rmeddis@0 1184 nIntervals=nCycles*intervalsPerCycle;
rmeddis@0 1185
rmeddis@0 1186 % random intervals
rmeddis@0 1187 if nXs>0
rmeddis@0 1188 xIntervals=floor(rand(1,nIntervals)*2*kLength);
rmeddis@0 1189 % weed out triple intervals > 2*k
rmeddis@0 1190 rogues=1;
rmeddis@0 1191 while sum(rogues)
rmeddis@0 1192 y=(xIntervals>kLength);
rmeddis@0 1193 rogues=(sum([y(1:end-2)' y(2:end-1)' y(3:end)'],2)>2);
rmeddis@0 1194 xIntervals(rogues)=floor(rand*2*kLength);
rmeddis@0 1195 end
rmeddis@0 1196 xIntervals=reshape(xIntervals,nCycles,intervalsPerCycle);
rmeddis@0 1197 else
rmeddis@0 1198 xIntervals=[];
rmeddis@0 1199 end
rmeddis@0 1200
rmeddis@0 1201 % insert constrained (k) intervals
rmeddis@0 1202 if nKs>0
rmeddis@0 1203 switch order
rmeddis@0 1204 case 1
rmeddis@0 1205 kIntervals=floor(ones(nCycles,nKs)*kLength);
rmeddis@0 1206 case 2
rmeddis@0 1207 nKs=1; % force this
rmeddis@0 1208 kIntervals=floor(rand(nCycles,1)*kLength);
rmeddis@0 1209 kIntervals=[kIntervals kLength-kIntervals];
rmeddis@0 1210 end
rmeddis@0 1211 else
rmeddis@0 1212 kIntervals=[];
rmeddis@0 1213 end
rmeddis@0 1214
rmeddis@0 1215 % combine fixed and random
rmeddis@0 1216 intervals=[kIntervals xIntervals(:,nKs+1:end)];
rmeddis@0 1217 % make a single array;
rmeddis@0 1218 [r c]=size(intervals);
rmeddis@0 1219 intervals=reshape(intervals',1,r*c);
rmeddis@0 1220
rmeddis@0 1221 % shuffle intervals
rmeddis@0 1222 if shuffled
rmeddis@0 1223 randomNumbers=rand(1,length(intervals));
rmeddis@0 1224 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1225 intervals=intervals(idx);
rmeddis@0 1226 idx=intervals>0;
rmeddis@0 1227 intervals=intervals(idx);
rmeddis@0 1228 end
rmeddis@0 1229
rmeddis@0 1230 % convert intervals to clicks
rmeddis@0 1231 clickTimes=cumsum(intervals);
rmeddis@0 1232 signal(clickTimes)=clickHeight;
rmeddis@0 1233 signal=signal(1:requiredSignalLength);
rmeddis@0 1234 % figure(1), clf, plot(signal)
rmeddis@0 1235
rmeddis@0 1236
rmeddis@0 1237
rmeddis@0 1238 %--------------------------------------------------------------------makeNoise
rmeddis@0 1239 function noise=makeNoise(globalStimParams, stimComponents)
rmeddis@0 1240 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1241 % noise is returned with overall level dB(rms) = amplitudesdB
rmeddis@0 1242 %
rmeddis@0 1243 % % You need
rmeddis@0 1244 %
rmeddis@0 1245 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1246 % stim.toneDuration=.05;
rmeddis@0 1247 % stim.amplitudesdB=50;
rmeddis@0 1248 % stim.beginSilence=.01;
rmeddis@0 1249 % stim.endSilence=-1;
rmeddis@0 1250 % stim.rampOnDur=.002;
rmeddis@0 1251 % stim.rampOffDur=-1;
rmeddis@0 1252 %
rmeddis@0 1253 % % Mandatory structure fields
rmeddis@0 1254 % globalStimParams.FS=100000;
rmeddis@0 1255 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1256 % globalStimParams.doPlot=1;
rmeddis@0 1257 % globalStimParams.doPlay=1;
rmeddis@0 1258 %
rmeddis@0 1259 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1260 %
rmeddis@0 1261 % % local
rmeddis@0 1262 % stim.type='noise'; % or 'IRN'
rmeddis@0 1263 %
rmeddis@0 1264 FS=globalStimParams.FS;
rmeddis@0 1265 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1266 npts=round(noiseDuration*FS);
rmeddis@0 1267 noise=randn(1,npts); % NB randn (normally distributed)
rmeddis@0 1268
rmeddis@0 1269 switch stimComponents.type
rmeddis@0 1270 case 'pinkNoise'
rmeddis@0 1271 % noise=UTIL_lowpassFilterFreq(noise, 100, 1/FS);
rmeddis@0 1272 noise=UTIL_bandPassFilter(noise, 1, 100, 200, 1/FS,[]);
rmeddis@0 1273 end
rmeddis@0 1274
rmeddis@0 1275 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1276 adjust=20e-6/rms;
rmeddis@0 1277 noise=noise*adjust;
rmeddis@0 1278 rms=(mean(noise.^2)^.5);
rmeddis@0 1279 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1280 noise=amplitude*noise;
rmeddis@0 1281 % rms=(mean(noise.^2)^.5);
rmeddis@0 1282 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1283
rmeddis@0 1284
rmeddis@0 1285 %--------------------------------------------------------------------makeWhiteNoise
rmeddis@0 1286 function noise=makeWhiteNoise(globalStimParams, stimComponents)
rmeddis@0 1287 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1288 % noise is bandpass filtered between 100 and 10000 Hz
rmeddis@0 1289 % spectrum level (dB/Hz) is 40 dB below nominal level.
rmeddis@0 1290 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1291 %
rmeddis@0 1292 % % You need
rmeddis@0 1293 %
rmeddis@0 1294 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1295 % stim.toneDuration=.05;
rmeddis@0 1296 % stim.amplitudesdB=50;
rmeddis@0 1297 % stim.beginSilence=.01;
rmeddis@0 1298 % stim.endSilence=-1;
rmeddis@0 1299 % stim.rampOnDur=.002;
rmeddis@0 1300 % stim.rampOffDur=-1;
rmeddis@0 1301 %
rmeddis@0 1302 % % Mandatory structure fields
rmeddis@0 1303 % globalStimParams.FS=100000;
rmeddis@0 1304 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1305 % globalStimParams.doPlot=1;
rmeddis@0 1306 % globalStimParams.doPlay=1;
rmeddis@0 1307 %
rmeddis@0 1308 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1309 %
rmeddis@0 1310 % % local
rmeddis@0 1311 % stim.type='noise'; % or 'IRN'
rmeddis@0 1312 %
rmeddis@0 1313 FS=globalStimParams.FS;
rmeddis@0 1314 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1315 npts=round(noiseDuration*FS);
rmeddis@0 1316 noise=randn(1,npts);
rmeddis@0 1317
rmeddis@0 1318 noise=UTIL_bandPassFilter (noise, 6, 100, 10000, 1/FS, []);
rmeddis@0 1319
rmeddis@0 1320 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1321 adjust=20e-6/rms;
rmeddis@0 1322 noise=noise*adjust;
rmeddis@0 1323 rms=(mean(noise.^2)^.5);
rmeddis@0 1324 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1325 noise=amplitude*noise;
rmeddis@0 1326 % rms=(mean(noise.^2)^.5);
rmeddis@0 1327 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1328
rmeddis@0 1329
rmeddis@0 1330 %-----------------------------------------------------------------makeIRN
rmeddis@0 1331 function noise=makeIRN(globalStimParams, stimComponents)
rmeddis@0 1332 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1333 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1334 %
rmeddis@0 1335 % % You need
rmeddis@0 1336 %
rmeddis@0 1337 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1338 % stim.toneDuration=.05;
rmeddis@0 1339 % stim.amplitudesdB=50;
rmeddis@0 1340 % stim.beginSilence=.01;
rmeddis@0 1341 % stim.endSilence=-1;
rmeddis@0 1342 % stim.rampOnDur=.002;
rmeddis@0 1343 % stim.rampOffDur=-1;
rmeddis@0 1344 %
rmeddis@0 1345 % % Mandatory structure fields
rmeddis@0 1346 % globalStimParams.FS=100000;
rmeddis@0 1347 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1348 % globalStimParams.doPlot=1;
rmeddis@0 1349 % globalStimParams.doPlay=1;
rmeddis@0 1350 %
rmeddis@0 1351 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1352 %
rmeddis@0 1353 % % local
rmeddis@0 1354 % stim.type='noise'; % or 'IRN'
rmeddis@0 1355 % % for IRN only
rmeddis@0 1356 % stim.niterations = 8; %0 for white noise
rmeddis@0 1357 % stim.delay = 1/150;
rmeddis@0 1358 % stim.irnGain = 1;
rmeddis@0 1359 %
rmeddis@0 1360 FS=globalStimParams.FS;
rmeddis@0 1361 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1362
rmeddis@0 1363 nIterations=stimComponents.niterations;
rmeddis@0 1364 if nIterations==0
rmeddis@0 1365 % white noise is specified as nIterations=1
rmeddis@0 1366 nIterations=1;
rmeddis@0 1367 IRNgain=0;
rmeddis@0 1368 delay=0.01; % dummy
rmeddis@0 1369 else
rmeddis@0 1370 % IRN
rmeddis@0 1371 delay=stimComponents.delay;
rmeddis@0 1372 IRNgain=stimComponents.irnGain;
rmeddis@0 1373 end
rmeddis@0 1374
rmeddis@0 1375 npts=round(noiseDuration*FS);
rmeddis@0 1376 dels=round(delay*FS);
rmeddis@0 1377 noise=randn(1,npts);
rmeddis@0 1378
rmeddis@0 1379 %fringe=nIterations*dels;
rmeddis@0 1380 %npts=npts+fringe;
rmeddis@0 1381
rmeddis@0 1382 for i=1:nIterations,
rmeddis@0 1383 dnoise=[noise(dels+1:npts) noise(1:dels)];
rmeddis@0 1384 dnoise=dnoise.*IRNgain;
rmeddis@0 1385 noise=noise+dnoise;
rmeddis@0 1386 end;
rmeddis@0 1387
rmeddis@0 1388 switch stimComponents.type
rmeddis@0 1389 case 'pinkNoise'
rmeddis@0 1390 noise=UTIL_lowpassFilterFreq(noise, 10000, 1/FS);
rmeddis@0 1391 end
rmeddis@0 1392
rmeddis@0 1393 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1394 adjust=20e-6/rms;
rmeddis@0 1395 noise=noise*adjust;
rmeddis@0 1396 rms=(mean(noise.^2)^.5);
rmeddis@0 1397 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1398 noise=amplitude*noise;
rmeddis@0 1399 % rms=(mean(noise.^2)^.5);
rmeddis@0 1400 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1401
rmeddis@0 1402 %------------------------------------------------------------------ makeRPN
rmeddis@0 1403 function RPN=makeRPN(globalStimParams, stim)
rmeddis@0 1404 % 'period' is a collection of samples - AAABCD
rmeddis@0 1405 % you need
rmeddis@0 1406 %
rmeddis@0 1407 % stim.type='RPN';
rmeddis@0 1408 % stim.toneDuration=.2;
rmeddis@0 1409 % stim.amplitudesdB=50;
rmeddis@0 1410 % stim.beginSilence=.01;
rmeddis@0 1411 % stim.rampOnDur=.002;
rmeddis@0 1412 % stim.rampOffDur=-1;
rmeddis@0 1413 %
rmeddis@0 1414 % stim.sampleDuration=.005; %200 Hz pitch
rmeddis@0 1415 % stim.nSimilarSamples=5; % pitch strength
rmeddis@0 1416 % stim.nIndependentSamples=1% dilutes strength
rmeddis@0 1417 %
rmeddis@0 1418 % % Mandatory structure fields
rmeddis@0 1419 % globalStimParams.FS=44100;
rmeddis@0 1420 % globalStimParams.overallDuration=.21; % s
rmeddis@0 1421 %
rmeddis@0 1422 % globalStimParams.doPlot=1;
rmeddis@0 1423 % globalStimParams.doPlay=1;
rmeddis@0 1424 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 1425
rmeddis@0 1426 FS=globalStimParams.FS;
rmeddis@0 1427 ptsPerSample=floor(stim.sampleDuration*FS);
rmeddis@0 1428
rmeddis@0 1429 samplesPerPeriod=stim.nSimilarSamples+stim.nIndependentSamples;
rmeddis@0 1430 periodDuration=samplesPerPeriod*stim.sampleDuration;
rmeddis@0 1431
rmeddis@0 1432 totalNumPeriods=2*floor(stim.toneDuration/periodDuration); % longer than necessary
rmeddis@0 1433 if totalNumPeriods<1
rmeddis@0 1434 error('stimulusCreate: RPN, stimulus duration needs to be longer')
rmeddis@0 1435 end
rmeddis@0 1436
rmeddis@0 1437 RPN=[];
rmeddis@0 1438 for j=1:totalNumPeriods
rmeddis@0 1439 noise=randn(1,ptsPerSample);
rmeddis@0 1440 for i=1:stim.nSimilarSamples
rmeddis@0 1441 RPN=[RPN noise];
rmeddis@0 1442 end
rmeddis@0 1443
rmeddis@0 1444 for i=1:stim.nIndependentSamples
rmeddis@0 1445 noise=randn(1,ptsPerSample);
rmeddis@0 1446 RPN=[RPN noise];
rmeddis@0 1447 end
rmeddis@0 1448 end
rmeddis@0 1449
rmeddis@0 1450 targetStimulusLength=round(stim.toneDuration/FS);
rmeddis@0 1451 RPN=RPN(1:floor(stim.toneDuration*FS)); % take enough for stimulus
rmeddis@0 1452
rmeddis@0 1453 rms=(mean(RPN.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1454 adjust=20e-6/rms;
rmeddis@0 1455 RPN=RPN*adjust;
rmeddis@0 1456 rms=(mean(RPN.^2)^.5);
rmeddis@0 1457 amplitude=10.^(stim.amplitudesdB/20);
rmeddis@0 1458 RPN=amplitude*RPN;
rmeddis@0 1459 % rms=(mean(noise.^2)^.5);
rmeddis@0 1460 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1461
rmeddis@0 1462 %--------------------------------------------------------------------applyRampOn
rmeddis@0 1463 function signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1464 %applyRampOn applies raised cosine ramp
rmeddis@0 1465 %rampOntime is the time at which the ramp begins
rmeddis@0 1466 %At all other times the mask has a value of 1
rmeddis@0 1467 %signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1468
rmeddis@0 1469 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1470 rampOn= (1+cos(pi:pi/(rampDurPoints-1): 2*pi))/2';
rmeddis@0 1471
rmeddis@0 1472 sigDurPoints=length(signal);
rmeddis@0 1473 mask(1:sigDurPoints)=1;
rmeddis@0 1474 rampOnStartIndex=round(rampOnTime*sampleRate+1);
rmeddis@0 1475 mask(rampOnStartIndex: rampOnStartIndex+ rampDurPoints-1)=rampOn;
rmeddis@0 1476 signal=signal.*mask;
rmeddis@0 1477 %plot(mask)
rmeddis@0 1478
rmeddis@0 1479 %--------------------------------------------------------------------applyRampOff
rmeddis@0 1480 function signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1481 %applyRampOn applies raised cosine squared ramp
rmeddis@0 1482 %rampOffTime is the time at which the ramp begins
rmeddis@0 1483 %At all other times the mask has a value of 1
rmeddis@0 1484 % signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1485
rmeddis@0 1486 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1487 rampOff= (1+cos(0:pi/(rampDurPoints-1): pi))/2';
rmeddis@0 1488
rmeddis@0 1489 sigDurPoints=length(signal);
rmeddis@0 1490 mask=ones(1,sigDurPoints);
rmeddis@0 1491 rampOffStartIndex=round(rampOffTime*sampleRate+1);
rmeddis@0 1492 mask(rampOffStartIndex: round(rampOffStartIndex+ rampDurPoints-1))=rampOff;
rmeddis@0 1493 if length(mask)>sigDurPoints, mask=mask(1:sigDurPoints); end
rmeddis@0 1494 signal=signal.*mask;
rmeddis@0 1495 %plot(mask)
rmeddis@0 1496
rmeddis@0 1497 function signal=applyGaussianRamps(signal, sigma, sampleRate)
rmeddis@0 1498 dt=1/sampleRate;
rmeddis@0 1499 time=dt:dt:dt*length(signal);
rmeddis@0 1500 ramp=1-exp(-time.^2/(2*sigma^2));
rmeddis@0 1501 % apply onset ramp
rmeddis@0 1502 signal=signal.*ramp;
rmeddis@0 1503 % apply offset ramp
rmeddis@0 1504 ramp=fliplr(ramp);
rmeddis@0 1505 signal=signal.*ramp;
rmeddis@0 1506
rmeddis@0 1507
rmeddis@0 1508
rmeddis@0 1509 %--------------------------------------------------------------------checkDescriptors
rmeddis@30 1510 function [globalStimParams, stimComponents]=...
rmeddis@30 1511 checkDescriptors(globalStimParams, stimComponents)
rmeddis@0 1512
rmeddis@0 1513 try
rmeddis@0 1514 % if FS exists, it takes priority
rmeddis@0 1515 globalStimParams.dt=1/globalStimParams.FS;
rmeddis@0 1516 catch
rmeddis@0 1517 % otherwise set FS using dt
rmeddis@0 1518 globalStimParams.FS=1/globalStimParams.dt;
rmeddis@0 1519 end
rmeddis@0 1520
rmeddis@30 1521 sampleRate=globalStimParams.FS;
rmeddis@30 1522
rmeddis@30 1523 globalStimParams.nSignalPoints=...
rmeddis@30 1524 round(globalStimParams.overallDuration* sampleRate);
rmeddis@0 1525
rmeddis@0 1526 % optional field (ears)
rmeddis@0 1527 try
rmeddis@0 1528 globalStimParams.ears;
rmeddis@0 1529 catch
rmeddis@0 1530 % default: dichotic.
rmeddis@0 1531 globalStimParams.ears='dichotic';
rmeddis@0 1532 end
rmeddis@0 1533
rmeddis@0 1534 % audioOutCorrection is optional
rmeddis@0 1535 % audioOutCorrection is a scalar for reducing the sound
rmeddis@0 1536 try
rmeddis@0 1537 globalStimParams.audioOutCorrection;
rmeddis@0 1538 catch
rmeddis@0 1539 % set to 1 if omitted
rmeddis@0 1540 globalStimParams.audioOutCorrection=1;
rmeddis@0 1541 end
rmeddis@0 1542
rmeddis@0 1543 try
rmeddis@0 1544 globalStimParams.doPlay;
rmeddis@0 1545 catch
rmeddis@0 1546 % default plays sound only if explicitly requested
rmeddis@0 1547 globalStimParams.doPlay=0;
rmeddis@0 1548 end
rmeddis@0 1549
rmeddis@0 1550 try
rmeddis@0 1551 globalStimParams.doPlot;
rmeddis@0 1552 catch
rmeddis@0 1553 % no plotting unless explicitly requested
rmeddis@0 1554 globalStimParams.doPlot=0;
rmeddis@0 1555 end
rmeddis@0 1556
rmeddis@0 1557 [ears nComponentSounds]=size(stimComponents);
rmeddis@0 1558
rmeddis@0 1559 for ear=1:2 % 1=left/ 2=right
rmeddis@0 1560
rmeddis@0 1561 % create a list of components whose type is specified
rmeddis@0 1562 % if no type is specified assume that it is an empty specification
rmeddis@0 1563 % this is allowed
rmeddis@0 1564 validStimComponents=[];
rmeddis@0 1565 for i=1:nComponentSounds
rmeddis@0 1566 try
rmeddis@0 1567 if ~isempty(stimComponents(ear,i).type)
rmeddis@0 1568 validStimComponents=[validStimComponents i];
rmeddis@0 1569 end
rmeddis@0 1570 catch
rmeddis@0 1571 end
rmeddis@0 1572 end
rmeddis@0 1573
rmeddis@0 1574 for componentNo=validStimComponents
rmeddis@0 1575 % If no AM filed is present, create it for completeness
rmeddis@0 1576 if ~isfield(stimComponents(ear,componentNo),'AMfrequency') |...
rmeddis@0 1577 ~isfield(stimComponents(ear,componentNo),'AMdepth')
rmeddis@0 1578 stimComponents(ear,componentNo).AMfrequency=0;
rmeddis@0 1579 stimComponents(ear,componentNo).AMdepth=0;
rmeddis@0 1580 end
rmeddis@0 1581
rmeddis@0 1582 % all signals must have durations, amplitudes and ramps
rmeddis@0 1583 if ...
rmeddis@0 1584 isempty(stimComponents(ear,componentNo).type) |...
rmeddis@0 1585 isempty(stimComponents(ear,componentNo).toneDuration) |...
rmeddis@0 1586 isempty(stimComponents(ear,componentNo).amplitudesdB) |...
rmeddis@0 1587 isempty(stimComponents(ear,componentNo).rampOnDur)
rmeddis@0 1588 descriptorError( 'missing stimComponent descriptor', stimComponents, ear, componentNo)
rmeddis@0 1589 end
rmeddis@0 1590
rmeddis@0 1591 try, stimComponents(ear,componentNo).endSilence; catch, stimComponents(ear,componentNo).endSilence=-1; end
rmeddis@0 1592
rmeddis@0 1593 % ramp checks do not apply to file input
rmeddis@0 1594 if ~strcmp(stimComponents(ear,componentNo).type, 'file')
rmeddis@0 1595 % match offset ramp to onset if not explicitly specified
rmeddis@0 1596 if stimComponents(ear,componentNo).rampOffDur==-1,
rmeddis@0 1597 stimComponents(ear,componentNo).rampOffDur=stimComponents(ear,componentNo).rampOnDur;
rmeddis@0 1598 end
rmeddis@0 1599 % ramps must be shorter than the stimulus
rmeddis@0 1600 if stimComponents(ear,componentNo).rampOffDur> stimComponents(ear,componentNo).toneDuration | ...
rmeddis@0 1601 stimComponents(ear,componentNo).rampOnDur> stimComponents(ear,componentNo).toneDuration
rmeddis@0 1602 descriptorError( 'ramp longer than sound component', stimComponents, ear, componentNo)
rmeddis@0 1603 end
rmeddis@0 1604 end
rmeddis@0 1605
rmeddis@0 1606 % end silence is measured to fit into the global duration
rmeddis@0 1607 if stimComponents(ear,componentNo).endSilence==-1,
rmeddis@30 1608 stimComponents(ear,componentNo).endSilence=...
rmeddis@30 1609 globalStimParams.overallDuration-...
rmeddis@30 1610 stimComponents(ear,componentNo).beginSilence -...
rmeddis@30 1611 stimComponents(ear,componentNo).toneDuration;
rmeddis@30 1612
rmeddis@30 1613 endSilenceNpoints=stimComponents(ear,componentNo).endSilence...
rmeddis@30 1614 *sampleRate;
rmeddis@30 1615 end
rmeddis@30 1616 if stimComponents(ear,componentNo).endSilence<0
rmeddis@30 1617 globalStimParams
rmeddis@30 1618 descriptorError( 'component durations greater than overallDuration', stimComponents, ear, componentNo)
rmeddis@0 1619 end
rmeddis@0 1620
rmeddis@0 1621 % check overall duration of this component against global duration
rmeddis@0 1622 totalDuration= ...
rmeddis@0 1623 stimComponents(ear,componentNo).beginSilence+...
rmeddis@0 1624 stimComponents(ear,componentNo).toneDuration+...
rmeddis@0 1625 stimComponents(ear,componentNo).endSilence;
rmeddis@0 1626
rmeddis@0 1627 % avoid annoying error message for single stimulus component
rmeddis@0 1628 if ears==1 && nComponentSounds==1
rmeddis@0 1629 globalStimParams.overallDuration= totalDuration;
rmeddis@0 1630 end
rmeddis@0 1631
rmeddis@0 1632 % check total duration
rmeddis@30 1633 totalSignalPoints= round(totalDuration* sampleRate);
rmeddis@0 1634 if totalSignalPoints >globalStimParams.nSignalPoints
rmeddis@0 1635 descriptorError( 'Signal component duration does not match overall duration ', stimComponents, ear, componentNo)
rmeddis@0 1636 end
rmeddis@0 1637
rmeddis@0 1638 if isfield(stimComponents(ear,componentNo), 'filter')
rmeddis@0 1639 if ~isequal(length(stimComponents(ear,componentNo).filter), 3)
rmeddis@0 1640 descriptorError( 'Filter parameter must have three elements ', stimComponents, ear, componentNo)
rmeddis@0 1641 end
rmeddis@0 1642 end
rmeddis@0 1643 end % component
rmeddis@0 1644 % ??
rmeddis@0 1645 if strcmp(globalStimParams.ears,'monoticL') | strcmp(globalStimParams.ears, 'monoticR'), break, end
rmeddis@0 1646 end % ear
rmeddis@0 1647
rmeddis@0 1648
rmeddis@0 1649 %-------------------------------------------------------------------- descriptorError
rmeddis@0 1650 function descriptorError( msg, stimComponents, ear, componentNo)
rmeddis@0 1651 stimComponents(ear, componentNo)
rmeddis@0 1652
rmeddis@0 1653 disp(' *********** **************** ************')
rmeddis@0 1654 disp([ '...Error in stimComponents description: '])
rmeddis@0 1655 disp([msg ])
rmeddis@0 1656 disp(['Ear = ' num2str(ear) ' component No ' num2str(componentNo)])
rmeddis@0 1657 disp(' *********** **************** ************')
rmeddis@0 1658 error('myError ')
rmeddis@0 1659
rmeddis@0 1660
rmeddis@0 1661 %-------------------------------------------------------------------- normalize
rmeddis@0 1662 function [normalizedSignal, gain]= normalize(signal)
rmeddis@0 1663 % normalize (signal)
rmeddis@0 1664 maxSignal=max(max(signal));
rmeddis@0 1665 minSignal=min(min(signal));
rmeddis@0 1666 if -minSignal>maxSignal, normalizingFactor=-minSignal; else normalizingFactor=maxSignal; end
rmeddis@0 1667 normalizingFactor=1.01*normalizingFactor;
rmeddis@0 1668 gain= 20*log10(normalizingFactor);
rmeddis@0 1669 normalizedSignal=signal/normalizingFactor;
rmeddis@0 1670
rmeddis@0 1671
rmeddis@0 1672 %--------------------------------------------------------------------Butterworth
rmeddis@0 1673 function y=Butterworth (x, dt, fl, fu, order)
rmeddis@0 1674 % Butterworth (x, dt, fu, fl, order)
rmeddis@0 1675 % Taken from Yuel and beauchamp page 261
rmeddis@0 1676 % NB error in their table for K (see their text)
rmeddis@0 1677 % x is original signal
rmeddis@0 1678 % fu, fl upper and lower cutoff
rmeddis@0 1679 % order is the number of times the filter is applied
rmeddis@0 1680
rmeddis@0 1681 q=(pi*dt*(fu-fl));
rmeddis@0 1682 J=1/(1+ cot(q));
rmeddis@0 1683 K= (2*cos(pi*dt*(fu+fl)))/(1+tan(q)*cos(q));
rmeddis@0 1684 L= (tan(q)-1)/(tan(q)+1);
rmeddis@0 1685 b=[J -J];
rmeddis@0 1686 a=[1 -K -L];
rmeddis@0 1687 for i=1:order
rmeddis@0 1688 y=filter(b, a, x);
rmeddis@0 1689 x=y;
rmeddis@0 1690 end
rmeddis@0 1691
rmeddis@0 1692
rmeddis@0 1693 % -------------------------------------------------------- UTIL_amp2dB
rmeddis@0 1694 function [y] = UTIL_amp2dB (x, ref)
rmeddis@0 1695 % Calculates a dB (ref. ref) value 'y' from a peak amplitude number 'x'.
rmeddis@0 1696 % if ref omitted treat as dB
rmeddis@0 1697 % Check the number of arguments that are passed in.
rmeddis@0 1698 if (nargin < 2)
rmeddis@0 1699 ref=1;
rmeddis@0 1700 end
rmeddis@0 1701 if (nargin > 2)
rmeddis@0 1702 error ('Too many arguments');
rmeddis@0 1703 end
rmeddis@0 1704
rmeddis@0 1705 % Check arguments.
rmeddis@0 1706 if x < 0.0
rmeddis@0 1707 error ('Can not calculate the log10 of a negative number');
rmeddis@0 1708 elseif x == 0.0
rmeddis@0 1709 warning ('log10 of zero. The result is set to -1000.0');
rmeddis@0 1710 y = -1000.0;
rmeddis@0 1711 else
rmeddis@0 1712 % Do calculations.
rmeddis@0 1713 y = 20.0 * log10(x/(sqrt(2)*ref));
rmeddis@0 1714
rmeddis@0 1715 end
rmeddis@0 1716
rmeddis@0 1717 %-------------------------------------------------------------------- FFT
rmeddis@0 1718 function showFFT (getFFTsignal, dt)
rmeddis@0 1719 color='r';
rmeddis@0 1720 figure(2), clf,
rmeddis@0 1721 hold off
rmeddis@0 1722
rmeddis@0 1723 % trim initial silence
rmeddis@0 1724 idx=find(getFFTsignal>0);
rmeddis@0 1725 if ~isempty(idx)
rmeddis@0 1726 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1727 end
rmeddis@0 1728 %trim final silence
rmeddis@0 1729 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1730 idx=find(getFFTsignal>0);
rmeddis@0 1731 if ~isempty(idx)
rmeddis@0 1732 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1733 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1734 end
rmeddis@0 1735
rmeddis@0 1736 % Analyse make stimComponents length a power of 2
rmeddis@0 1737 x=length(getFFTsignal);
rmeddis@0 1738 squareLength=2;
rmeddis@0 1739 while squareLength<=x
rmeddis@0 1740 squareLength=squareLength*2;
rmeddis@0 1741 end
rmeddis@0 1742 squareLength=round(squareLength/2);
rmeddis@0 1743 getFFTsignal=getFFTsignal(1:squareLength);
rmeddis@0 1744 n=length(getFFTsignal);
rmeddis@0 1745
rmeddis@0 1746 minf=100; maxf=20000;
rmeddis@0 1747
rmeddis@0 1748 fft_result = fft(getFFTsignal, n); % Compute FFT of the input signal.
rmeddis@0 1749 fft_power = fft_result .* conj(fft_result);% / n; % Compute power spectrum. Dividing by 'n' we get the power spectral density.
rmeddis@0 1750 fft_phase = angle(fft_result); % Compute the phase spectrum.
rmeddis@0 1751
rmeddis@0 1752 frequencies = (1/dt)*(1:n/2)/n;
rmeddis@0 1753 fft_power=fft_power(1:length(fft_power)/2); % remove mirror frequencies
rmeddis@0 1754 fft_phase=fft_phase(1:length(fft_phase)/2); % remove mirror frequencies
rmeddis@0 1755 fft_powerdB = UTIL_amp2dB (fft_power, max(fft_power)); % convert to dB
rmeddis@0 1756 % jags=find(diff(fft_phase)>0); % unwrap phase
rmeddis@0 1757 % for i=jags, fft_phase(i+1:end)=fft_phase(i+1:end)-2*pi; end
rmeddis@0 1758
rmeddis@0 1759 xlim([minf maxf])
rmeddis@0 1760 semilogx(frequencies, fft_powerdB-max(fft_powerdB), color)
rmeddis@0 1761 ylim([ -20 5])
rmeddis@0 1762
rmeddis@0 1763
rmeddis@0 1764
rmeddis@0 1765 function y=UTIL_lowpassFilterFreq(x, cutOffFrequency, dt)
rmeddis@0 1766 % UTIL_lowpassFilterFreq multi-channel filter
rmeddis@0 1767 %
rmeddis@0 1768 % Usage:
rmeddis@0 1769 % output=UTIL_lowpassFilterFreq(input, cutOffFrequency, dt)
rmeddis@0 1770 %
rmeddis@0 1771 % cutoff should be around 100 Hz for audio work
rmeddis@0 1772 % dt should be <1/50000 s for audio work
rmeddis@0 1773 %
rmeddis@0 1774 % Attenuation is - 6 dB per octave above cutoff.
rmeddis@0 1775
rmeddis@0 1776
rmeddis@0 1777 sampleRate=1/dt;
rmeddis@0 1778
rmeddis@0 1779 if 4*cutOffFrequency>sampleRate
rmeddis@0 1780 warning(['UTIL_lowpassFilterFreq: sample rate ' num2str(1/dt) ' is too low for this BF. Sampling rate should be >' num2str(4*cutOffFrequency) 'or cutoff (' num2str(4*cutOffFrequency) ') should be lower' ])
rmeddis@0 1781 cutOffFrequency=sampleRate/4;
rmeddis@0 1782 end
rmeddis@0 1783
rmeddis@0 1784 tau=1/(2*pi*cutOffFrequency);
rmeddis@0 1785
rmeddis@0 1786 y=zeros(size(x));
rmeddis@0 1787 [numChannels numPoints]=size(x);
rmeddis@0 1788 for i=1:numChannels
rmeddis@0 1789 y(i,:)=filter([dt/tau], [1 -(1-dt/tau)], x(i,:));
rmeddis@0 1790 end
rmeddis@0 1791
rmeddis@0 1792