Skip to main content
Skip table of contents

Play audio on a digital input

This demo presents a white square onscreen and waits for an input on a specified digital input channel.
When the channel detects activity, the time is recorded and a tone plays.

PY

from pypixxlib import _libdpx as dp 
from psychopy import core, visual
import numpy as np

### HELPER FUNCTIONS

def convertDinValuesToList():
    ''' Some nice formatting of DinValues as a list that aligns bit position with VPixx dout vals
    eg. [1,1,1 .... 1] corresponds to [statusDin0, statusDin1, statusDin2 ... statusDin25]
    Makes it easy to query individual bits to see their current state'''
    
    #get the activity of all channels as a binary string
    dinString = bin(dp.DPxGetDinValue())
    
    #convert binary to a list of values for indexing
    dinList = list(map(int, list(dinString[2:])))
    
    #reverse list so it runs from least to most sig, thus aligning with VPixx dout labelling (e.g., position 0 corresponds with dout0, etc)
    dinList.reverse()
    
    return dinList


def getTriggerDefaultValue(channel=0):
    '''Call at the beginning of experiment to get nonactive trigger value.
    Some systems have a default of 1, while others are 0, so it is best to check'''
    
    #get latest status of box
    dp.DPxUpdateRegCache()
    
    #get list of default port values
    noActivityList = convertDinValuesToList()   
    
    #check the specific channel
    result = noActivityList[channel]
    
    return result

    
def listenForTrigger(channel=0, noActivity=0):
    '''Listens for a trigger on the digital input channel specified by channel
    and returns when the trigger is detected'''

    while True:
        #get latest status of box
        dp.DPxUpdateRegCache() 
        
        #get current list of port values
        currentActivity = convertDinValuesToList()
        
        #get box time
        time = dp.DPxGetTime()
        
        #if channel value is not "off" as specified by noActivity, break out of listener
        if currentActivity[channel] != noActivity:
            break
        
    return time


def generateBeep(frequency=400, duration=2):
    '''Make a little beep for testing'''
    
    # Audio settings
    sample_rate = 44100  # Samples per second
    
    # Generate time values from 0 to duration
    t = np.arange(0, duration, 1/sample_rate)
    
    # Generate a 400Hz sine wave
    audio_data = np.sin(2 * np.pi * frequency * t)
    
    # Normalize the audio data to be in the range of [-1, 1]
    audio_data_normalized = audio_data / np.max(np.abs(audio_data))
        
    return audio_data_normalized
    

def setupBoxAudio(myAudio):
    ''' Does all the fiddly audio setup'''
    
    dp.DPxSetAudVolume(0.5) #between 0 and 1
    
    #Some audio parameters
    audBufferAddress = int(16e6)
    audioSize=len(myAudio)
    onset = 0.0 #no delay
    
    #setup the box audio with a few writing/formatting calls
    dp.DPxWriteAudioBuffer(myAudio, audBufferAddress)
    dp.DPxSetAudioSchedule(onset, 44100, audioSize, 'mono', audBufferAddress)
    
    #push updates to the box
    dp.DPxWriteRegCache()
     
    
def playBoxAudio():
    dp.DPxStartAudSched()
    dp.DPxWriteRegCache()
    
    
def stopBoxAudio():
    dp.DPxStopAudSched()
    dp.DPxWriteRegCache()



### EXPERIMENT START ###
#connect to VPixx hardware
dp.DPxOpen()

#set the dout channel where you expect the trigger to appear. 
#Here it's 0. Get the default value for that channel
triggerChannel = 0 
noTrigger = getTriggerDefaultValue(triggerChannel)

#create and prepare audio for playback on box
myAudio = generateBeep(400,2)
setupBoxAudio(myAudio)

#Present a stimulus onscreen:
win = visual.Window(screen=1, fullscr=True, color='black', units='pix')    
stimulus = visual.Rect(win, width=100, height=100, fillColor=[1,1,1], pos=(0, 0))
stimulus.draw()

#Get a box timestamp on next video flip, save this as startTime
dp.DPxUpdateRegCacheAfterVideoSync()
win.flip()
startTime = dp.DPxGetTime()

#Wait for our trigger and log the time the trigger was recorded 
trigTime = listenForTrigger(triggerChannel, noTrigger)

#Play tone and flip display
playBoxAudio()
win.flip()

#Wait 2 seconds and stop playback
core.wait(2)
stopBoxAudio()

#Print some results and shut down
print('Trigger time: ', trigTime-startTime, ' seconds.')
win.close()
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.