Onboard Device Memory UnderFlow

I am using SndLoadWave operation to load a .WAV file of birdsong to be played (through a NIDAQ board ADC channel) while I am recording in current clamp (via MultiClamp700B). When I load and play an entire song (~30-60 seconds), the following two commands work correctly:
DAQmx_Scan/DEV="NI6259"/TRIG={"/NI6259/ao/starttrigger"}/BKG WAVES= "datawav, 1" //datawav receives the voltage trace recorded via DAC
DAQmx_WaveformGen/DEV="NI6259"/NPRD=1 "playwav, 0;" //playwav is the normalized and scaled version of the wave loaded by SndLoadWave
These commands are within a "for" loop that repeats the scan and playback however many times I specify.
The sample rate of the song is 44100Hz and both the datawav and playwav are scaled with a delta (SetScale operation) of 2.26757e-005

HOWEVER when I load and try to play .WAV files of short motifs that have been cut out of the song (~1 second duration) the waveform DOES NOT play reliably on each repetition.

IF I include the /BKG=-1 flag on the DAQmx_WaveformGen operation, then I get the following error (returned by fDAQmx_ErrorString()):
"NI-DAQmx driver error while calling function DAQmxWaitUntilTaskDone; device NI6259:-200016: Measurements: Onboard device memory underflow. Because of system and/or bus-bandwidth limitations, the driver could not write data to the device fast enough to keep up with the device output rate. Reduce your sample rate, alter the data transfer method (from interrupts to DMA), use a product with more onboard memory, or reduce the number of programs your computer is executing concurrently.
Extended info:
Measurements: Onboard device memory underflow. Because of system and/or bus-bandwidth limitations, the driver could not write data to the device fast enough to keep up with the device output rate. Reduce your sample rate, alter the data transfer method (from interrupts to DMA), use a product with more onboard memory, or reduce the number of programs your computer is executing concurrently.
Task Name: NI6259AO
Status Code: -200016"

If I play these short motifs (~1 second song segments) at half the sample rate (22050) so SetScale sets the delta of the waves to 4.53515e-005, but the number of samples remains the same (so it plays the sound file in slow motion) the playback using DAQmx_Scan followed by DAQmx_WaveformGen DOES work reliably every time.

adding neither fDAQmx_WF_WaitUntilFinished("NI6259",-1) nor fDAQmx_ScanWait("NI6259") after the DAQmx_WaveformGen operation helps.

I do not want to change the sample rate of my song playback.
And it seems that my NIDAQ device is set to use DMA transfer method if it is possible, but how can I make sure that I am making use of that method as opposed to "interrupts" in IGOR?

Is there any other advice/answers that anyone can provide who has had experience with problems like this?

Thank You in advance for your help!

(and below I have pasted the procedure I am using to accomplish my goals so it can be referenced if necessary... I apologize for my novice coding skills)

Function SongStim_IClamp()
   
    DoOpenMultiFileDialog()
   
    NVAR nlist = root:numFilesSelected
    WAVE/T stimlist = root:stimlist
   
    variable inval = nlist
   
    variable basedur, nreps
    Prompt nreps, "number reps song list"
    Prompt basedur, "baseline time in sec"
    DoPrompt "birdsong trial", nreps, basedur
   
    variable rep
    for(rep=0;rep<nreps;rep+=1)
        permute(inval)
        WAVE outseq=root:outseq
       
        variable item, pick
        for(item=0;item<nlist;item+=1)  // Initialize variables;continue test
            variable  sampfreq, songsample, tdur, normval, scaley, sampdelta, basesample, datasample, delta, beginwav, endwav
            string pathfromopen, sampfreqst, tit
       
            pick=outseq[item]
            pathfromopen = stimlist[item]       //get the stim file path returned in outputPaths list of DoOpenMultiFileDialog() function using the randomized index generated by purmute(inval)           
   
            SndLoadWave/M=1/O anywav, (pathfromopen)  //load the .WAV file from the stim file path determined by outputPaths list of DoOpenMultiFileDialog()
            wavestats/Q anywav
            sampfreqst=stringbykey("RATE", S_info)  //gets the sample frequency of the original .WAV file from the info strings returned by SndLoadWave
            //sampfreq=str2num(sampfreqst)
            sampfreq=22050
            tit=S_fileName
       
            songsample = V_npnts
            basesample =(basedur)*(sampfreq)
       
            tdur=songsample/sampfreq
            delta=1/sampfreq
       
            Make/D/N=(songsample) datawav, playwav
            WAVE anywav=root:anywav
            playwav=anywav
            InsertPoints 0,(basesample), playwav      //insert x zeros to the beginning of the .WAV to be played so that there is a baseline measurement of the cell's activity
            InsertPoints 0,(basesample), datawav
            //I may want to figure out how to add points after as well

            setscale/P x, 0, (delta), datawav, playwav
            normval = max(V_max, abs(V_min))
            playwav /=normval
            scaley = 6
            playwav *= scaley
           
            DAQmx_Scan/DEV="NI6259"/TRIG={"/NI6259/ao/starttrigger"}/BKG WAVES= "datawav, 1"
            DAQmx_WaveformGen/DEV="NI6259"/NPRD=1 "playwav, 0;"
            //fDAQmx_WF_WaitUntilFinished("NI6259",-1)
            fDAQmx_ScanWait("NI6259")
            //fDAQmx_ScanStop("NI6259")
            //fDAQmx_WaveformStop("NI6259")
       
            string datawavst, basewavst
            datawavst= (tit)+(num2str(rep))
           
            rename datawav, $(datawavst)
            rename playwav, $(datawavst) + "play"
           
            KillWaves anywav
            //, playwav
        endfor                                             
    endfor
 End
 
 Function/S DoOpenMultiFileDialog()
    Variable refNum
    String message = "Select one or more files"
    String outputPaths
    String fileFilters = "Data Files (*.txt,*.dat,*.csv,*.wav):.txt,.dat,.csv,.wav;"
    fileFilters += "All Files:.*;"

    Open/D/R/MULT=1/F=fileFilters/M=message refNum
    outputPaths = S_fileName
   
    if (strlen(outputPaths) == 0)
        Print "Cancelled"
    else
        Variable/G numFilesSelected = ItemsInList(outputPaths, "\r")
        Make/T/N=(numFilesSelected)/O stimlist
        Variable i
        for(i=0; i<numFilesSelected; i+=1)
            String path = StringFromList(i, outputPaths, "\r")
            Printf "%d: %s\r", i, path 
            stimlist[i]=path
        endfor
    endif
   
    return outputPaths      // Will be empty if user canceled
End

Function/WAVE permute(inval)
    variable inval
    Make/O/N=(inval) outseq
    variable i, j, val, fail, test, emax=(inval)/2
    for (i=1; i<=inval; i+=1)
        fail=0
        do
        val=  floor(emax + enoise(emax))
        fail=0
            for(j=0; j<(i-1); j+=1)
                if (val==outseq[j])
                    fail+=1
                endif
            print j, fail
            endfor 
       
       
        while(fail!=0)
               
        outseq[i-1]=val
     print outseq
    endfor
End



kperks wrote:
it looks like my code at the bottom is inaccessible...

You need to surround any code with <igor></igor> tags so that the text rendering engine doesn't treat stuff within angle brackets as (invalid) HTML tags.

I just edited your original post to add the tags.
Thank you.

Do you have any insight on my problem of not being able to play short (~1sec) songs with a high sample rate (although I can play long songs with a high sample frequency just fine)?
You have a pretty sophisticated use of NIDAQ Tools there!

I did a little bit of searching on the NI support site about this issue. It seems like generating short sequences of waveform generation is paradoxically difficult for the hardware. One suggestion in a response to a similar problem was to apply a short delay after triggering the waveform generation. You might be able to try that out by using /STRT=0 on the call to DAQmx_WaveformGen, then calling fDAQmx_WaveformStart() afterward. I don't know if the small delay that would occur just due to the speed (or lack thereof) of Igor's function execution would be enough. So your code would change to something like this:
            DAQmx_Scan/DEV="NI6259"/TRIG={"/NI6259/ao/starttrigger"}/BKG WAVES= "datawav, 1"
            DAQmx_WaveformGen/DEV="NI6259"/NPRD=1/STRT=0 "playwav, 0;"
            // maybe here insert a delay using the Sleep operation
            fDAQmx_WaveformStart("NI6259", 1)

Another possibility might be to request that the samples be stored on the device. That requires the (pretty new) /DBUF flag. If your version of NIDAQ Tools MX doesn't have that flag, let me know and I will send you the information you need to update NIDAQ Tools MX. That requires adding "/DBUF=1" to your call to DAQmx_WaveformGen. The 6259 device has an 8192-point buffer, so your samples have to be no longer than 8192 samples. Is that a problem?

The same posting that suggested a delay before starting the waveform also suggested that using interrupt transfers would paradoxically *help* the problem. Unfortunately, I have to add the necessary option of it is required (probably should anyway). Let me know how you get on with the suggestions above, and if it comes to it I can add the necessary option to waveform generation.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
John,
I do have the NIDAQ Tools version with the /DBUF flag and I had tried to include it yesterday when I was trouble-shooting. It always returned an error, but I did not know that it was because the device only had 8192-point buffer. My stimuli are indeed usually an order of magnitude larger than that buffer.
Adding the /STRT=0 flag and the sleep operation seemed to help a little bit, but the playback is still not reliable on every repetition, even when adding a 3 second pause and inserting 3 seconds worth of zeros onto the beginning of each song motif wave. Should that have been enough of a sleep (and lengthening of the stimulus) to help the problem using this type of solution?

Is the "interrupts transfers flag" on the waveform generation still an option?

Thanks again,
Krista


kperks wrote:
Is the "interrupts transfers flag" on the waveform generation still an option?

Sounds like you've done what you can. I will look into the transfer method flag in the next day or two.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Krista-

I was just reviewing that problem, when I noticed your statement about using /BKG=-1. Now I'm a bit confused, because the code you posted doesn't have that. I presume this is one of the things you tried- using either /BKG=-1 or fDAQmx_ScanWait or fDAQmx_WF_WaitUntilFinished.

Would it be possible for you to send me an Igor experiment that I can use to try it out? You would need to substitute pre-loaded waves for the SndLoadWave call to avoid sending me a whole bunch of sound files, etc. Naturally, the content of the waves doesn't matter. I just need to be able to run your code without having all your sound files, etc. Send it as an attachment to support@wavemetrics.com.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Krista-

Here's another thing to try-

Swap the order of DAQmx_Scan and DAQmx_WaveformGen. Move the trigger from DAQmx_Scan to DAQmx_WaveformGen, changing the trigger source to "/NI6259/ai/starttrigger". Some NI Forum posts suggest that using a hardware trigger for the waveform generation might help; it's not clear why, but it's easy to try. Your code would then look like
            DAQmx_WaveformGen/DEV="NI6259"/NPRD=1/TRIG={"/NI6259/ai/starttrigger"} "playwav, 0;"
            DAQmx_Scan/DEV="NI6259"/BKG WAVES= "datawav, 1"
            //fDAQmx_WF_WaitUntilFinished("NI6259",-1)
            fDAQmx_ScanWait("NI6259")


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
This seems to be a working solution! Thank you!

Let me know if you are still interested in the /interrupts flag. Seems like it could be useful in the future.



johnweeks wrote:
Krista-

Here's another thing to try-

Swap the order of DAQmx_Scan and DAQmx_WaveformGen. Move the trigger from DAQmx_Scan to DAQmx_WaveformGen, changing the trigger source to "/NI6259/ai/starttrigger". Some NI Forum posts suggest that using a hardware trigger for the waveform generation might help; it's not clear why, but it's easy to try. Your code would then look like
            DAQmx_WaveformGen/DEV="NI6259"/NPRD=1/TRIG={"/NI6259/ai/starttrigger"} "playwav, 0;"
            DAQmx_Scan/DEV="NI6259"/BKG WAVES= "datawav, 1"
            //fDAQmx_WF_WaitUntilFinished("NI6259",-1)
            fDAQmx_ScanWait("NI6259")


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com