Hello Guest

STB Vorbis streaming - PointerBuffer usage

  • 5 Replies
  • 2887 Views
STB Vorbis streaming - PointerBuffer usage
« on: August 07, 2016, 13:23:35 »
I've been unable to figure out the intended usage of PointerBuffer in the following method:
Code: [Select]
stb_vorbis_decode_frame_pushdata(long f, ByteBuffer datablock, int[] channels, PointerBuffer output, int[] samples)
The documentation for this method isn't very understandable given how it's accessed through LWJGL.
Quote
*output will contain an array of float* buffers, one per channel. In other words, (*output)[0][0] contains the first sample from the first channel, and (*output)[1][0] contains the first sample from the second channel.
Quote
output - place to write float ** array of float * buffers

I've tried using the getFloatBuffer method of PointerBuffer with the size specified by samples, but the resulting buffer does not contain any data, even when the number of samples produced is greater than zero. I have been unable to find any examples of this method being used through LWJGL. A little example of proper PointerBuffer usage in this context would be very helpful.
« Last Edit: August 07, 2016, 13:26:18 by xsupermetroidx »

*

Offline spasi

  • *****
  • 2163
    • WebHotelier
Re: STB Vorbis streaming - PointerBuffer usage
« Reply #1 on: August 07, 2016, 18:25:20 »
The native signature is: float ***output. This means that the output argument receives a pointer (a single value) that points to an array of pointers (float**) that each point to a float array (float*). The following code should help:

Code: [Select]
try ( MemoryStack stack = stackPush() ) {
IntBuffer channels_p = stack.mallocInt(1); // int*
IntBuffer samples_p = stack.mallocInt(1); // int*

PointerBuffer output_ppp = stack.mallocPointer(1); // float***

stb_vorbis_decode_frame_pushdata(f, datablock, channels_p, output_ppp, samples_p);

int channels = channels_p.get(0);
int samples = samples_p.get(0);

PointerBuffer output_pp = output_ppp.getPointerBuffer(channels); // float**
for ( int c = 0; c < channels; c++ ) {
FloatBuffer channel = output_pp.getFloatBuffer(c, samples); // float*
for ( int s = 0; s < samples; s++ ) {
float sample = channel.get(s);
// ...
}
}
}


Re: STB Vorbis streaming - PointerBuffer usage
« Reply #2 on: August 07, 2016, 23:21:44 »
Thanks for the explanation- I was able to get it working, but the playback result is nothing but noise. I've gotten streaming OGG playback working with both JOrbis and J-Ogg, so I know that the streaming code itself isn't the issue. I've also gotten non-streaming playback working by using stb_vorbis to load the entire file at once.

What I don't understand is that OpenAL seems to expect input data in the form of shorts, yet the pushdata methods are only able to return float buffers. I assume that supplying floats where shorts are expected is the reason I'm getting noise. How can I incrementally decode and recieve short data from stb_vorbis? The get_frame_short functions seem to require the file to be fully loaded rather than streamed. Alternatively, how can I feed float data to OpenAL when it only seems to have constants defined for 8 and 16 bit formats?

Just a nudge in the right direction should be all I need... thanks for your time.
« Last Edit: August 07, 2016, 23:30:19 by xsupermetroidx »

*

Offline CoDi

  • *
  • 49
Re: STB Vorbis streaming - PointerBuffer usage
« Reply #3 on: August 08, 2016, 09:04:24 »
What I don't understand is that OpenAL seems to expect input data in the form of shorts, yet the pushdata methods are only able to return float buffers. I assume that supplying floats where shorts are expected is the reason I'm getting noise. How can I incrementally decode and recieve short data from stb_vorbis?

The stb_vorbis API seemingly does not do float->short conversions with its push API. Performance concerns aside, I'd try to convert sample data manually to verify your assumption, e.g. short_sample = (short)(float_sample * 32767.0f).

*

Offline spasi

  • *****
  • 2163
    • WebHotelier
Re: STB Vorbis streaming - PointerBuffer usage
« Reply #4 on: August 08, 2016, 09:20:48 »
I have not used the pushdata API, but I'm guessing a float-to-short conversion should work indeed.

For a working stream decoding solution, see the Vorbis sample. It plays some music by decoding the file in 4kb batches (using stb_vorbis_get_samples_short_interleaved) and double buffering the audio playback with OpenAL.

Re: STB Vorbis streaming - PointerBuffer usage
« Reply #5 on: August 08, 2016, 12:55:18 »
Float-to-short conversion did work. I encountered some popping noises during the playback until I noticed that the float output from decode_frame_pushdata isn't normalized to the range 0 to 1. For the sake of anyone trying to get this working I'll leave the simple clamped conversion code here:
Code: [Select]
short shortSample = clamp((short) (floatSample * Short.MAX_VALUE), Short.MIN_VALUE, Short.MAX_VALUE);

Thanks for the assistance spasi and CoDi.
« Last Edit: August 08, 2016, 13:09:04 by xsupermetroidx »