Author Topic: WASAPI Output (Exclusive mode + Enable event-driven buffering)  (Read 276 times)

Gabriel

  • Posts: 38
Hi,

I'm having trouble getting a correct output using WASAPI Output (Exclusive mode + Enable event-driven buffering).

Right now I'm just testing a sine wave. But the resulting sound is like part of the wave is being skipped, it doesn't sound like a small pause because the buffer is not filled fast enough.

The code is basically

Init bass wasapi
Code: [Select]
        r = BASS_WASAPI_Init(wOutputDeviceIndex, SampleRate, 2, _
                             BASS_WASAPI_AUTOFORMAT Or BASS_WASAPI_EXCLUSIVE Or BASS_WASAPI_EVENT, _
                             BufferSize / SampleRate, 0, wCallBackAddress, wOutputDeviceIndex)

Start:
Code: [Select]
BASS_WASAPI_Start()
Callback
 
Code: [Select]
  Private dbg_SampleNumber As Long = 0
    Private LockObj As New Object

    Private Function BufferCallback(ByVal bufferAddress As IntPtr, ByVal length As Integer, ByVal user As Integer) As Integer

        Static firstcall As Boolean = True

        SyncLock LockObj
            Debug.Print(System.Environment.TickCount & " length: " & length & " address: " & bufferAddress.ToInt64)

            Dim buffer(length / 4) As Single

            Dim WaveFreq As Double = 440

            Dim divValue As Double = SampleRate / WaveFreq
            Dim mulFactor As Double = 360 / divValue

            For i = 0 To length \ 4 - 1 Step 2
                Dim wSample As Double = (i \ 2 + dbg_SampleNumber) Mod divValue

                buffer(i) = Math.Sin(wSample * mulFactor * Math.PI / 180)
                buffer(i + 1) = Math.Sin(wSample * mulFactor * Math.PI / 180)

                dbg_SampleNumber += 1
            Next

            Marshal.Copy(buffer, 0, bufferAddress, length \ 4)
            Return length
        End SyncLock
    End Function

From the console:
Quote
15412352 length: 134272 address: 15628528
15412742 length: 134272 address: 15628528
15413132 length: 134272 address: 15628528
15413522 length: 134272 address: 15628528
15413928 length: 134272 address: 15628528
15414318 length: 134272 address: 15628528
15414708 length: 134272 address: 15628528

Sorry I can't provide a code so you can try it directly in C.
One of my questions is if the buffer address should be always the same. Theoretically it is a double buffer, but as you can see the callback always get the same buffer address.

Thanks

Ian @ un4seen

  • Administrator
  • Posts: 20437
Receiving the same buffer in the WASAPIPROC each time is normal, as BASSWASAPI converts the sample data from there to the device's format.

Regarding the problem, please see if you can reproduce it when you try to play a WAV file containing a sinewave with the pre-compiled CONTEST.EXE example in the BASSWASAPI package (C\BIN folder). You can use the "-e" parameter for event-driven buffering. If that's fine, you could try changing the "Sin" calls in the code above to this:

Code: [Select]
                buffer(i) = Math.Sin(dbg_SampleNumber * 2 * Math.PI * WaveFreq / SampleRate)
                buffer(i + 1) = Math.Sin(dbg_SampleNumber * 2 * Math.PI * WaveFreq / SampleRate)

If the problem persists, are you only having it with event-driven exclusive mode, and not without event-driven buffering or with shared mode?

Gabriel

  • Posts: 38
CONTEST.EXE is working correctly. So it must be something related to my code, or probably the .NET CLR

I did the same on my code (load a stream and use getdata to fill the buffer in the callback). And still got the problem. So, I'll dig a little more.

One more question, regarding BASS_WASAPI_PutData

"If successful, the amount of data used is returned.
As much data as possible will be placed in the device's buffer; this function will have to be called again for any remainder. "

Trying with a thread to fill the buffer. I get 0 most of the calls, and then a bigger number.
Is the bigger number the number of bytes that didn't fit the buffer ?
When I call again BASS_WASAPI_PutData to feed the remaining data, should I provide a buffer, or will it use the last one.

Ian @ un4seen

  • Administrator
  • Posts: 20437
CONTEST.EXE is working correctly. So it must be something related to my code, or probably the .NET CLR

I did the same on my code (load a stream and use getdata to fill the buffer in the callback). And still got the problem. So, I'll dig a little more.

What buffer size are you requesting in your BASS_WASAPI_Init call? The CONTEST example uses a 10ms (0.01s) buffer with event-driven output, so you could give that a try in your code.

One more question, regarding BASS_WASAPI_PutData

"If successful, the amount of data used is returned.
As much data as possible will be placed in the device's buffer; this function will have to be called again for any remainder. "

Trying with a thread to fill the buffer. I get 0 most of the calls, and then a bigger number.
Is the bigger number the number of bytes that didn't fit the buffer ?
When I call again BASS_WASAPI_PutData to feed the remaining data, should I provide a buffer, or will it use the last one.

The BASS_WASAPI_PutData return value is the number of bytes that were accepted. So the 0 return values mean that no data was accepted, ie. the buffer was full.

When calling BASS_WASAPI_PutData again, you should provide the data that wasn't accepted in the previous call. If no data was accepted, then you can pass exactly the same parameters as last time. If some data was accepted, then you can pass an offset into the same buffer and lower the "length" parameter accordingly.