123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- classdef CAudio < handle
- % a class managing audio interface
- % last modified by Strongway: genNoise with randn, normalize noise
- properties
- freq;
- channels;
- pins;
- latency;
- pHandle;
- hwName;
- hwType;
- end
-
- methods
- function obj = CAudio(varargin)
- %constructor: frequency, channels, latency
- p = inputParser;
- p.addParamValue('freq',96000,@isnumeric);
- p.addParamValue('channels',2,@isnumeric);
- p.addParamValue('latency', 0.001, @(x) x>0);
- p.addParamValue('pins',[1 2],@isnumeric); %define the pin number of the channels
- p.addParamValue('hardware','sndCard', @(x) any(strcmpi(x,{'sndCard','Aout','Ain'})));
- p.parse(varargin{:});
-
- obj.freq = p.Results.freq;
- obj.channels = p.Results.channels;
- obj.latency = p.Results.latency;
- obj.hwName = p.Results.hardware;
- obj.pins = p.Results.pins;
- switch obj.hwName
- case {'sndCard'}
- obj.hwType = 1;
- try
- InitializePsychSound(1);
- obj.pHandle = PsychPortAudio('Open', [],[],2,obj.freq,obj.channels);
- PsychPortAudio('LatencyBias', obj.pHandle, obj.latency);
- obj.latency = PsychPortAudio('LatencyBias', obj.pHandle);
- catch ME
- disp(ME.message);
- end
- case {'Aout','Ain'}
- obj.hwType = 2;
- obj.pHandle = analogoutput('nidaq',obj.hwName);
- achan = addchannel(obj.pHandle,obj.pins);
- obj.channels = size(achan,1);
- set(obj.pHandle,'SampleRate',obj.freq);
- set(obj.pHandle,'TriggerType','manual');
- otherwise
- obj.hwType = 1;
- end
- end
-
- function prepare(obj, data)
- switch obj.hwType
- case 1
- PsychPortAudio('FillBuffer', obj.pHandle, data);
- case 2
- putdata(obj.pHandle,data');
- start(obj.pHandle);
- end
-
- end
-
- function onsetTime = present(obj,startTime)
- if nargin < 2
- startTime = 0;
- end
- switch obj.hwType
- case 1
- PsychPortAudio('Start', obj.pHandle, 1, startTime, 0);
- active = 0;
- while active == 0
- s = PsychPortAudio('GetStatus',obj.pHandle);
- active = s.Active;
- end
- onsetTime = s.StartTime; %get true onset time
- case 2
- if startTime > 0
- waitTime = max(0,startTime - GetSecs);
- WaitSecs(waitTime);
- end
- trigger(obj.pHandle);
- onsetTime = getSecs;
- end
- end
-
- function stop(obj,afterFinish)
- if nargin < 2
- afterFinish = 0; %immediately stop
- end
- switch obj.hwType
- case 1
- PsychPortAudio('Stop', obj.pHandle, afterFinish);
- case 2
- stop(obj.pHandle);
- end
- end
- function open(obj)
- obj.pHandle = PsychPortAudio('Open', [],[],2,obj.freq,obj.channels);
- PsychPortAudio('LatencyBias', obj.pHandle, obj.latency);
- obj.latency = PsychPortAudio('LatencyBias', obj.pHandle);
- end
- function close(obj)
- switch obj.hwType
- case 1
- PsychPortAudio('Stop', obj.pHandle);
- % Close the audio device:
- PsychPortAudio('Close', obj.pHandle);
- end
- end
-
- function tone = genTone(obj, freq, duration)
- t = MakeBeep(freq, duration, obj.freq);
- tone = repmat(t(1:end-1),obj.channels(1),1);
- end
-
- function tone = genNoise(obj,duration)
- % change to randn (normal distribution) - Oct.14. 2013
- num_samp = obj.freq*duration;
- t = randn(1,num_samp);
- tone = repmat(t,obj.channels(1),1);
- % rescale
- tone = tone./3; % 3 sigma
- end
-
- function [tone, pn] = genPinkNoise(obj, f0, duration, dbc_per_hz, num_taps)
- % based on code phase_noise by Jeff Schenck 11/21/95
- % f0 reference frequency (must be in Hz.)
- % dbc_per_hz power per hertz relative to carrier at ref. freq.
- % num_taps number of filter taps in AR 1/f filter
- % (optional; default = 100)
- % pn phase-modulated 1/f process
- % theta 1/f process (before phase modulation)
- % Check input.
- if dbc_per_hz >= 0
- error('Power per Hz. must be negative.');
- elseif f0 <= 0
- error('Reference frequency must be positive.');
- end
- if nargin < 5
- num_taps = 100;
- end
- num_samp = obj.freq * duration;
- % Generate white noise. Apply gain for desired dBc/Hz. Warn user
- % if gain is too large (gain thresholds have been chosen somewhat
- % arbitrarily -- needs work).
- gain = sqrt(2*pi * f0 * 10^(dbc_per_hz/10));
- wn = gain * randn(1,num_samp);
- fprintf('Gain applied to white noise = %f.\n', gain);
- if gain >= 1
- fprintf('WARNING: Narrowband approximation no longer valid.\n');
- elseif gain >= .5
- fprintf('WARNING: Narrowband approximation on the verge of collapse.\n');
- end
- % Generate 1/f AR filter and apply to white noise to produce 1/f
- % noise.
- a = zeros(1,num_taps);
- a(1) = 1;
- for ii = 2:num_taps
- a(ii) = (ii - 2.5) * a(ii-1) / (ii-1);
- end
- theta = filter(1,a,wn);
- tone = repmat(theta,obj.channels(1),1);
- % Phase modulate.
- pn = exp(i*theta);
- % normalize
- sd3 = std(tone(1,:))*3; % 3 sigma
- tone = tone./sd3;
- end
-
- end
- end
|