LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Continuous sound output buffer issue(s)

I need to better understand how the buffering for Sound Output VIs work.
 
I'm working on a LabVIEW application which receives a continuous demodulated RF signal from a custom board and sends it to a PC speaker. Every 50 ms, a lower level application sends packets of the demodulated audio, which the LabVIEW app takes and writes to the speaker via Sound Output Write.vi. The speaker sample rate is set to 48 ks/s using Sound Output Configure.vi, so with the 50 ms period, an average of 2400 samples should be received from the low level application every period to meet the desired sample rate.
 
In developing the code for these requirements, some question marks have risen about the workings of Sound Output Configure.vi and Sound Output Write.vi in regards to generating smooth audio output, that is, audio without jitter or glitches. When configuring the number of samples/channel input to Sound Output Configure.vi and/or the #s input to Sound Output Write.vi, values for either input which do not equally divide into the sample rate invariably cause the audio output to glitch. For example, if number of samples/channel is set to 4096 and #s is set to 2400, the audio output glitches. The same is true if the values are set to 4096 and 4096, respectively. If, however, number of samples/channel is set to 4800 and #s is set to 2400, the sound output works well with no discernible jitter.
 
I want to keep the sound output buffer as full as possible (without overflow, of course) to ensure smooth audio output, but also need to keep the total sound output buffer size < 100 ms to reduce noticeable sound output latency. As long as the #s * period >= sample rate (for instance, 4096(#s) * 20 times/second (50 ms)  = 81920 samples), this should be sufficient for the desired audio. However, as can be observed from the sample code attached, increasing the number of samples/channel and #s input values to meet this criteria at any combination other than such as equally divides into the sample rate generally results in poor audio quality. For example, try inputting the values mentioned in the previous paragraph into the attached code and listen to the result.
 
Why does this glitching occur with the indicated configuration? Do the LabVIEW sound output VIs use a multi-buffering system internally which requires configuration parameters evenly divisible into the sample rate?
 
How is buffer overflow handled? If Sound Output Write.vi cannot accept the number of samples being written to it because it hasn't yet consumed existing buffered samples at the configured sample rate, does it wait until it can hold the incoming samples before continuing execution? Or are older samples in the sound output buffer allowed to be overwritten by new incoming samples (overflow)?
 
Any feedback, comments, questions and/or answers are appreciated.
 
The attached sample code generalizes the method for writing to the speaker via Sound Output Write.vi, with Sine Waveform.vi simulating the signal from the low level application. The number of samples/channel input to Sound Output Configure.vi and/or the #s input to Sound Output Write.vi can be modified with the above values to hear their effects.
0 Kudos
Message 1 of 17
(9,964 Views)
The referenced example VI is attached here.

Message Edited by Mark M. on 04-07-2008 05:13 PM

Message Edited by Mark M. on 04-07-2008 05:14 PM
0 Kudos
Message 2 of 17
(9,957 Views)
Here is a slightly improved version of the previous VI, with corrections to the unincluded State control type definition and also exiting the Run state if an error is detected.
0 Kudos
Message 3 of 17
(9,933 Views)

Mark M.

After experimenting with your code I came to the following conclusions.  The only thing you are really interested in is the frequency content of the signal.  As long as this concept is preserved you will be able to extract a smooth tone to your sound cards output.

In order to accomplish the sample rate needs to be at least twice the rate of the waveform.  I would still sample a little faster than that to make sure you are guaranteed the frequency content of your tone.  The link I provided talks about analog input, but the same rules apply in your application.

To handle the “spurs” you are hearing you will need to have the number of samples be a multiple of your sample rate because otherwise you will have discontinuities between each sample set.  The reason is because we need to have enough samples to reconstruct your waveform.  However, if the multiple number of samples you choose is too small then you will still here the same effects as before.  To better explain refer to the screenshots below. 

 

The Yellow signal is your 1kHz sine wave sampled at 4000 S/s taking 4000 samples.  You can see that this doesn’t give you a nice smooth waveform, but the frequency content is still there, which will produce a nice smooth tone. 

As far as the number of samples is concerned, if you perform your test with the sample rate at 48k with 1200 samples then you will still hear spurs in your sound.  Even though this is a multiple of 48k, 1200 samples is not enough samples to complete the waveform. 

Because I am not sampling enough points the next pass of this experiment the waveform looked like this.

 

You can see that the two white signals do not line up like the yellow signal which will cause spurs in your tone.   If you have decided that 4096 is the optimal number of samples to get a smooth tone then just make sure your sample rate is a multiple like 40960 and you will get your desired waveform.

I hope this helps!



Message Edited by Ryan N. on 04-08-2008 05:26 PM
Ryan N
National Instruments
Application Engineer
ni.com/support
Download All
0 Kudos
Message 4 of 17
(9,905 Views)

Ryan N.,

Thanks for your response. The 48000 S/s output sample rate is a requirement from the hardware team, so the number of samples/ch and #s will need to divide into that value. I'll experiment further with your input in mind. Since the samples retrieved from the lower level application are variable, it appears as if we'll need to develop a method for feeding this variable stream at a steady rate into Sound Output Write.vi.

Any thoughts on my second question about how Sound Output Write.vi handles buffer overflow? What does Sound Output Write.vi do when its buffer, as configured by the number of samples/ch input to Sound Output Configure.vi, cannot contain the samples being written to it? For example, if in the example SoundOutputTester.vi the number of samples/ch input  to Sound Output Configure.vi is set to 4800 and the #s input to Sound Output Write.vi is set to 4000, what does Sound Output Write.vi do when, on the second pass, the output buffer has 1600 samples left in it (it consumes 2400 samples every 50 ms period) but the code is attempting to write another 4000 samples into the buffer, which will exceed the buffer size? Does Sound Output Write.vi wait until enough room is available in the buffer or does it overwrite (old) data in the buffer with the new samples?

Regards,

Mark M. 

0 Kudos
Message 5 of 17
(9,889 Views)

Mark M.

I’d like to clarify a few things.  When you say:

For example, if in the example SoundOutputTester.vi the number of samples/ch input  to Sound Output Configure.vi is set to 4800 and the #s input to Sound Output Write.vi is set to 4000, what does Sound Output Write.vi do when, on the second pass, the output buffer has 1600 samples left in it (it consumes 2400 samples every 50 ms period) but the code is attempting to write another 4000 samples into the buffer, which will exceed the buffer size?”

I do not see an input on “Sound Output Write.vi” that takes in the input “#’s”.  I am going to assume you are speaking about the”#’s input for the Sine Wave.vi.

 

These parameters are strictly used in creating the 1KHz sine wave in your application.  This creates a Sine Wave (digitally) with 4096 points sampled at 48 kS/s.  The Sound VI’s then interprets the sine wave using its own parameters and converts it to an analog signal.

The parameters used in the picture below takes the digital sine wave and samples it yet again then converts it to an analog signal. 

 

Every interation through the while loop the “Sound Output.vi” will sample the Sine Wave we have just created and write that to the sound card.  So every pass through the while loop we are overwriting the previous data with new samples.  The sound card then interprets these new samples and outputs them.  If you create a control instead of a constant for the frequency input on the Sine Wave.vi you can change this frequency on the fly and hear the effects through your speakers.  This is because we are overwriting the samples in memory with new data.

 

I hope this helps!



Message Edited by Ryan N. on 04-09-2008 03:33 PM

Message Edited by Ryan N. on 04-09-2008 03:34 PM
Ryan N
National Instruments
Application Engineer
ni.com/support
0 Kudos
Message 6 of 17
(9,874 Views)

Ryan N.,

Thanks for the correction. You're right; my reference to #s was to the cluster element input to Sine Waveform.vi as you assumed.



Ryan N. wrote:

Every iteration through the while loop the “Sound Output.vi” will sample the Sine Wave we have just created and write that to the sound card.  So every pass through the while loop we are overwriting the previous data with new samples.  The sound card then interprets these new samples and outputs them.  If you create a control instead of a constant for the frequency input on the Sine Wave.vi you can change this frequency on the fly and hear the effects through your speakers.  This is because we are overwriting the samples in memory with new data.


If I understand correctly, you indicate that new samples overwrite old samples in the sound output buffer. For example, if the sound output buffer (number of samples/ch) is set to 4800 and there are 2000 samples in the buffer when a new call to Sound Output Write.vi is made passing in 4000 samples, enough of the 2000 samples in the buffer are overwritten to make room for the 4000 samples being passed in. 
 
I've attached a revised edition of the original VI below which illustrates my question about your response. If the VI is run and you place a probe on the Iteration Duration wire running through the Timed Loop, you'll notice that the loop duration exceeds its 50 ms period regularly. Since Sine Waveform.vi generates its samples in a very short time, Sound Output Write.vi must be causing this excessive duration. If Sound Output Write.vi overwrites existing samples in the buffer with the 4000 incoming samples, why is this delay present? I understand why the audio sounds poor based on your previous response. However, if the sound output buffer operation is as you describe, I would expect the buffer write to occur with little or no execution time difference than if the new samples fit in the buffer with no overwrite of existing samples. Rather, what I see appears to be the Sound Output Write.vi waiting until enough room is available in the buffer for the new samples before writing them and continuing execution.
 
Thanks for your assistance.
0 Kudos
Message 7 of 17
(9,863 Views)

Ryan,

I am having similar problems with the SO Write.vi.  From what I can tell, the VI completely ignores the Timeout value input - I have tried setting verious timeouts that are shorter than the time it would take to play the clip, and it makes no difference in the VI execution time.  According to NI's documentation, if I enter a timeout of 0, the VI should return immediately and continue to play. I thought maybe it was just adding the data to a buffer, but I only get an immediate return the first time the VI is called.  The second time it takes two seconds to complete, and the remaining times it takes 1 second.  What I am trying to do is stream 16-bit PCM samples via UDP to a program that will play the sound in near real-time.  I had planned on just queuing the waveforms in on loop, and dequeuing them and playing them in anopther loop once I had a sufficient buffer built up.  The way SO Write vi is behaving does not permit that, because it is taking too long to complete.  Can you please answer Mark's (and my) question - how does the vi do its buffering?  I figured it would let you call it with a 0 timeout as many times as you could until the buffer was full, at which time there would be an error.  This does not seem to be how it works.

Download All
0 Kudos
Message 8 of 17
(9,803 Views)

wired,

An NI applications engineer confirmed to me that there is indeed a bug in Sound Output Write.vi which ignores the Timeout value input. This problem is a known issue and is scheduled to be fixed in the LabVIEW 8.6 release.

Regards,

Mark M.

0 Kudos
Message 9 of 17
(9,793 Views)
Mark M. and wired,

Myself and that same Engineer Mark M. referred to are working on this issue.  I will post the information we come up with on this forum as soon as we have it. 
Ryan N
National Instruments
Application Engineer
ni.com/support
0 Kudos
Message 10 of 17
(9,788 Views)