def sendFreq(self, duration, freqhz, duration_is_cycles=False): """ Sends a train of pulses at a given frequency on TTL2 NOTE: MUST CALL configFreq FIRST TO GET ACCURATE RESULTS INPUT ARGS: duration - Duration of the train (defaults to seconds, can override with 3rd argument) freqhz - Frequency at which to stimulate in Hz duration_is_cycles - Whether duration provided is in seconds or number of pulses (default: False) """ if not self.labjack: raise (Exception('CAN ONLY USE THIS FUNCTION ON LABJACK')) # Time at which to send the pulse trainTime = timing.now() (timeInterval, returnValue) = timing.timedCall(\ trainTime,\ self.labjack.pulseTrain,\ duration,\ freqhz,\ duration_is_cycles) if duration_is_cycles: self.logMessage( 'STIM_TRAIN\t%d\t%d' % (int(round(float(duration) / freqhz)), freqhz), timeInterval) else: self.logMessage('STIM_TRAIN\t%d\t%d' % (duration, freqhz), timeInterval) return timeInterval
def scalpCallback(self): """ Callback to make logs using the real-time scalp interface. """ # is it time to do another alignment? if timing.now() >= self.last_align + self.align_interval: # query for offset (timeInterval, offset) = timing.timedCall(None, EEGGetOffset) # get info for log message self.logMessage("%s\t%s" % (self.dat_filename, offset), timeInterval) # update last_align self.last_align = timeInterval[0]
def clientLowNow(self, clk=None): """ Do a non-blocking low on channel 2 """ if self.labjack == None: raise EPLPulseEEGException( "Client pulse methods are only callable with multiple outputs." ) if clk is None: # no clock, so use time clk = timing.now() (timeInterval, returnValue) = timing.timedCall(clk, self.labjack.setChannel2Low) pulsePrefix = "CHANNEL_2_" self.logMessage("%s" % pulsePrefix + "DN", timeInterval)
def startRecording(self, basename=None, t=None, **sfargs): """ Starts recording and returns a tuple of the AudioClip and the time of recording onset. INPUT ARGS: t- optional PresentationClock for timing. sfargs- keyword arguments for FileAudioClip constructor OUTPUT ARGS: recClip- The AudioClip object that will contain the recorded data. timestamp- time and latency when sound recording began. """ if not self.recording: # get a new audio clip to record to if not basename is None: # send output to file self.recClip = FileAudioClip(self.archive, basename, **sfargs) else: # record in memory if len(sfargs) > 0: raise SoundException( "Cannot pass sfargs to AudioClip constructor; you must be recording to file." ) self.recClip = AudioClip() # start recording if isinstance(t, exputils.PresentationClock): t = t.get() (timeInterval, val) = timing.timedCall(t, self.eplsound.recstart) # Add the callback to continue recording self.recording = True self.last_rec = timeInterval[0] addPollCallback(self.__recCallback__) # log message if basename: shortName = self.recClip.filename else: shortName = "NOFILE" self.logMessage("%s\t%s" % ("RB", shortName), timeInterval) return (self.recClip, timeInterval)
def stopRecording(self, t=None): """ Stops recording and returns the resulting audio clip and the time recording ended. INPUT ARGS: t- optional PresentationClock for timing. OUTPUT ARGS: recClip- The AudioClip object that contains the recorded data. timestamp- time and latency when sound recording ended. """ if self.recording: # stop recording if isinstance(t, exputils.PresentationClock): t = t.get() (timeInterval, val) = timing.timedCall(t, self.eplsound.recstop) # Remove the recording callback self.recording = False removePollCallback(self.__recCallback__) # get the rest of the data from recbuffer newstuff = self.getBuffData() if len(newstuff) > 0: # append the data to the clip self.recClip.append(newstuff, self.eplsound.getRecChans()) # log message if isinstance(self.recClip, FileAudioClip): shortName = self.recClip.filename else: shortName = "NOFILE" self.logMessage("%s\t%s" % ("RE", shortName), timeInterval) r = self.recClip del self.recClip return (r, timeInterval)
def configFreq(self, frequency): """ Configures stimulation so that stimulation trains can happen more quickly NOTE: ONLY FUNCTIONS ON TTL2 INPUT ARGS: frequency - the frequency (Hz) at which to configure """ # Log the frequency self.logMessage("CONFIG\t%d" % frequency) # Set the time at which to configure configTime = timing.now() if not self.labjack: raise (Exception('CAN ONLY CONFIGURE FREQUENCY ON LABJACK')) (timeInterval, returnValue)=timing.timedCall(configTime,\ self.labjack.configFreq,\ frequency) return timeInterval
def pulseTrain(self, numPulses, trainName=""): """ Send a train of pulses. INPUT ARGS: numPulses- Number of pulses in train. trainName- Name to use in the log. """ #trainLen denotes the number of pulses in this train pulseLen = 10 #in milliseconds interPulseInterval = 5 self.logMessage(trainName + "TRAIN") # set the desired pulsetime pulseTime = timing.now() for i in range(numPulses): # send a pulse (timeInterval, returnValue) = timing.timedCall(pulseTime, self.timedPulse, pulseLen, 'TRAIN_') # pause for the next pulse pulseTime += interPulseInterval
def timedStim(self, duration, freq, doRelay=False): ''' Start a sync box controlled train of pulses to trigger a stimulator. INPUT ARGS: duration - duration of stimulation (s) freq - frequency to send pulse (Hz) ''' # use the current time clk = timing.now() # only labjack boxes support stimulation if self.labjack: (timeInterval, returnValue) = timing.timedCall(clk, self.labjack.StartStim, duration, freq, doRelay) # log start of stimulation self.logMessage("STIM_ON", timeInterval) return timeInterval else: raise EPLPulseEEGException( "timedStim only functions with labjack autostim boards.")
def timedPulse(self, pulseTime, pulsePrefix='', signal='', clk=None, output_channel=0): """ Send a pulse and log it. INPUT ARGS: pulseTime- Duration of pulse. pulsePrefix- Name to log the pulse. """ # see if using clock usingClock = True if clk is None: # no clock, so use time clk = timing.now() usingClock = False if self.awCard: if len(signal) > 0: (timeInterval, returnValue) = timing.timedCall(clk, self.awCard.write, signal) else: (timeInterval, returnValue) = timing.timedCall(clk, self.awCard.allOn) elif self.labjack: (timeInterval, returnValue) = timing.timedCall(clk, self.labjack.setFIOState, output_channel, 0 if output_channel == 4 else 1) pulsePrefix = "CHANNEL_" + str(output_channel) + "_" else: if len(signal) > 0: (timeInterval, returnValue) = timing.timedCall(clk, self.parallel.setSignal, True, signal) else: (timeInterval, returnValue) = timing.timedCall(clk, self.parallel.setState, True) self.logMessage("%s" % pulsePrefix + "UP", timeInterval) # wait for the pulse time if usingClock: clk.delay(pulseTime) else: clk = clk + pulseTime if self.awCard: (timeInterval, returnValue) = timing.timedCall(clk, self.awCard.allOff) elif self.labjack: (timeInterval, returnValue) = timing.timedCall(clk, self.labjack.setFIOState, output_channel, 1 if output_channel == 4 else 0) else: (timeInterval, returnValue) = timing.timedCall(clk, self.parallel.setState, False) self.logMessage("%s" % pulsePrefix + "DN", timeInterval) # I'm not sure when if you want this to be the start or end of the pulse return timeInterval
def playLoop(self, soundClip, t=None, ampFactor=1.0, doDelay=True): """ Play an AudioClip and return the time and latency of when the sound played. INPUT ARGS: soundClip- AudioClip object of the sound to be played t- Optional PresentationClock for timing. ampFactor- Optional amplification of sound. (default value is 1) doDelay- Optionally do not tare and move the presentation clock forward. Defaults to True (moving the clock forward) OUTPUT ARGS: timestamp- time and latency when sound playing began. """ # Must be sure to not get multiple callbacks at once, so # playing a soundclip while another is running causes that # other one to stop immediately, even if it is not done playing. # self.playStop() # handle special case: if it's a FileAudioClip and needs loading, # load it. self.currentClip = soundClip if isinstance(soundClip, FileAudioClip): if not soundClip.isLoaded(): # load and append the sound soundClip.load() # for logging shortName = soundClip.filename else: shortName = "NOFILE" if isinstance(t, exputils.PresentationClock): clk = t else: clk = exputils.PresentationClock() t = clk.get() if not soundClip.snd is None: # first, compute how many bytes our initial chunk # to append is. ASSUMPTION: always starting from byte 0. firstbytes = min(self.bytes_per_append, len(soundClip.snd)) self.total_samples = int( math.floor(len(soundClip.snd) / self.eplsound.FORMAT_SIZE)) if self.playing: # stop the playing sound 5ms prior to the new time timing.timedCall(t - 5, self.playStop, False) self.playing = True self.eplsound.resetSamplesPlayed() (timeInterval, appended) = timing.timedCall( t, self.eplsound.append, soundClip.snd[0:firstbytes], len(soundClip.snd[0:firstbytes]) / self.eplsound.FORMAT_SIZE, 0, ampFactor) if doDelay: # accumulate the error clk.accumulatedTimingError += timeInterval[0] - t # tare the clock and delay the proper amount clk.tare(timeInterval[0]) clk.delay(soundClip.getDuration()) # it would be great if the soundClip knew the formatsize... # mark the offset into the sound clip self.startInd = appended * self.eplsound.FORMAT_SIZE self.endInd = len( soundClip.snd) #self.total_samples*self.eplsound.FORMAT_SIZE # Add the callback to continue playing self.last_play = timeInterval[0] #addPollCallback(self.__playLoopCallback__, soundClip.snd, 0, ampFactor) addPollCallback(self.__playLoopCallback__, 0, ampFactor) dur = soundClip.getDuration() else: dur = 0 # log message self.logMessage("%s\t%s\t%s" % ("P", shortName, dur), timeInterval) return timeInterval