Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Custom SoundStream  (Read 9200 times)

0 Members and 1 Guest are viewing this topic.

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Custom SoundStream
« on: November 17, 2015, 10:03:33 pm »
Hi All,

I'm trying to write my own sf::SoundStream but the application crashes with a floating point exception after onGetData is called 3 times.

I'm initializing the sound stream to 2 chanels at 22050 Hz, and filling the data chunk with 735 samples of silence. The rationale is:

22050 / 60 = 367.5 frames
367.5 * 2 channels = 735 samples

However, I'm receiving warnings and then the application crashes:

An internal OpenAL call failed in SoundStream.cpp (327) : AL_INVALID_VALUE, a numeric argument is out of range
An internal OpenAL call failed in SoundStream.cpp (327) : AL_INVALID_VALUE, a numeric argument is out of range
An internal OpenAL call failed in SoundStream.cpp (327) : AL_INVALID_VALUE, a numeric argument is out of range
Floating point exception

My methods are:

void initialize( unsigned sample_rate )
{
  SoundStream::initialize( 2, sample_rate );
}

bool onGetData( Chunk& data )
{
  static int16_t buffer[ 735 ] = { 0 };
  data.samples = buffer;
  data.sampleCount = sizeof( buffer ) / sizeof( buffer[ 0 ] );
  return true;
}

I'm not sure my numbers are correct. In fact, I find it odd that there are 735 samples in a chunk since the number of channels is 2, so I think the number of samples should be even...

Any thoughts? What size the buffer array should be? In SFML terminology, on a stereo stream, a sample is really just one sample, or it's two samples?

My SFML version is 2.1.

Thanks,

Andre

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Custom SoundStream
« Reply #1 on: November 17, 2015, 10:41:00 pm »
Code: [Select]
  static int16_t buffer[ 735 ] = { 0 };
unless I really need to get more morning coffee to be able to read code, this is initializing the first element of the array to zero - not the entire array. IIRC {0} does not equal memset of the entire array to 0.
Someone correct me if I got this wrong...
« Last Edit: November 17, 2015, 10:57:03 pm by Jesper Juhl »

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #2 on: November 17, 2015, 11:19:25 pm »
Quote
unless I really need to get more morning coffee to be able to read code, this is initializing the first element of the array to zero - not the entire array. IIRC {0} does not equal memset of the entire array to 0.
Someone correct me if I got this wrong...

Hm, I always thought it did. If I change the code to create the buffer on the stack and compile with -O0, the generated code is:

0000000000000000 <_ZN2SS9onGetDataERN2sf11SoundStream5ChunkE>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 58 05 00 00    sub    $0x558,%rsp
   b:   48 89 bd 38 fa ff ff    mov    %rdi,-0x5c8(%rbp)
  12:   48 89 b5 30 fa ff ff    mov    %rsi,-0x5d0(%rbp)
  19:   48 8d 95 40 fa ff ff    lea    -0x5c0(%rbp),%rdx
  20:   b8 00 00 00 00          mov    $0x0,%eax
  25:   b9 b7 00 00 00          mov    $0xb7,%ecx
  2a:   48 89 d7                mov    %rdx,%rdi
  2d:   f3 48 ab                rep stos %rax,%es:(%rdi)

I looked for a formal specification on variable initialization and the C specification corroborates the above code: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf, section 6.7.8 :)

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #3 on: November 17, 2015, 11:20:54 pm »
I looked for a formal specification on variable initialization and the C specification corroborates the above code: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf, section 6.7.8 :)

Ah, the original code initializes the entire array to zero according to the specification, so = { 0 } isn't needed.

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Custom SoundStream
« Reply #4 on: November 17, 2015, 11:29:53 pm »
= { 0 } isn't needed.
According to this, all the remaining elements after the one you gave the zero for, "are set to their default values (which for fundamental types, means they are filled with zeroes)". If you used just "= { }", it does so for all elements. However, if you leave this section off, they "are left uninitialized".

As for "735", you were correct to realise that this isn't acceptable as stereo samples are stored in pairs.
"22050 / 60 = 367.5 frames"
22050 is how many samples per second. What is 60? Your frame rate? 22050/60 would then be samples per frame, not "frames". Obviously half of a sample isn't much use.
« Last Edit: November 17, 2015, 11:37:18 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #5 on: November 17, 2015, 11:44:19 pm »
As for "735", you were correct to realise that this isn't acceptable as stereo samples are stored in pairs.
"22050 / 60 = 367.5 frames"
22050 is how many samples per second. What is 60? Your frame rate? 22050/60 would then be samples per frame, not "frames". Obviously half of a sample isn't much use.

Yes, 60 frames/second.

Do you know how much it should be for one video frame? 735 (since a stereo sound frame is 2 samples) causes the crash.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10815
    • View Profile
    • development blog
    • Email
Re: Custom SoundStream
« Reply #6 on: November 18, 2015, 12:10:52 am »
Take a look at the example in the official tutorial, it uses class member std::vector, so there's no need for scary sizeof() calls and static buffers.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Custom SoundStream
« Reply #7 on: November 18, 2015, 12:11:07 am »
60 frames/second.
Do you know how much it should be for one video frame? 735 (since a stereo sound frame is 2 samples) causes the crash.
At sample rate of 22050, you would need 368 samples (per channel) for one frame. Since 22050 is not divisible by 60 exactly, this may be not be exact but a 368th of a frame should not be too noticable.
You could alternate between using 368 and 367 samples for a frame, or you could consider using higher sample rate (44100 is divisible by 60).

It might also be worth noting that it's highly unlikely that your frame rate is ever exactly 60 frames per second.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Custom SoundStream
« Reply #8 on: November 18, 2015, 12:13:05 am »
...it uses...std::vector...
This solves a lot of problems including the initialisation of all of the elements discussed above  ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #9 on: November 18, 2015, 12:22:25 am »
Take a look at the example in the official tutorial, it uses class member std::vector, so there's no need for scary sizeof() calls and static buffers.

I'm more scared of the standard library than of those things ;)

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #10 on: November 18, 2015, 12:24:06 am »
This solves a lot of problems including the initialisation of all of the elements discussed above  ;)

Actually my buffer is filled on every onGetData call, that code was just the bare minimum that reproduces the problem.

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Custom SoundStream
« Reply #11 on: November 18, 2015, 12:33:32 am »
Take a look at the example in the official tutorial, it uses class member std::vector, so there's no need for scary sizeof() calls and static buffers.

I'm more scared of the standard library than of those things ;)
Don't be scared. std::vector is very simple to use, generally a lot safer than standard arrays, and probably the standard go-to container for most cases.
It was just the "class member" bit that removes the need for the static buffer, by the way.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #12 on: November 18, 2015, 12:52:48 am »
At sample rate of 22050, you would need 368 samples (per channel) for one frame. Since 22050 is not divisible by 60 exactly, this may be not be exact but a 368th of a frame should not be too noticable.

Hm, it could work but my actual sound source is more complicated than that...

You could alternate between using 368 and 367 samples for a frame, or you could consider using higher sample rate (44100 is divisible by 60).

I was already trying with 44100 too, but the sound is not right.

It might also be worth noting that it's highly unlikely that your frame rate is ever exactly 60 frames per second.

Some more details: my sound source is a libretro core. I'm actually testing with the snes9x-next core and Super Mario Kart.

I can render the video just fine, and I can see the game demo going on at an accelerated rate. I then went on to render the audio. I initialize the sound stream to 44100 Hz, and in onGetData, I render one SNES frame. I've turned the video off to make it easier to get the audio right.

Each SNES frame renders 1024 or 1026 samples per video frame at 32040,5 Hz (the video refresh rate is 60.098812.) I'm using an audio resampler to go from 32040,5 to 44100 (I'm actually varying the source frequency a bit to get a constant number of 1470 samples at 44100), and then I return the converted buffer in the sf::SoundStream::Chunk structure.

But the audio sounds wrong, it seems to go slower or faster at times, and it stutters a lot. I'm not sure what I'm doing wrong yet.

Don't be scared. std::vector is very simple to use, generally a lot safer than standard arrays, and probably the standard go-to container for most cases.
It was just the "class member" bit that removes the need for the static buffer, by the way.

I know it and its interface is easy to use. I'm scared of what you can't see, like how it manages memory. The thing I dislike about SFML is its use of the standard library. I tried to use SDL2 before going to SFML because of that, but SDL2 don't seem to allow me to render the audio (it imposes a power-of-two audio buffer and libretro cores can send audio frames of any length.)

leiradel

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Custom SoundStream
« Reply #13 on: November 18, 2015, 01:24:53 am »
I have to apologize... I was developing on a Linux virtual machine, and even RetroArch had a terrible sound there. So I moved to the host Windows OS and my custom SoundStream is working just fine now without any changes.

Now on to render the video together with the audio. I'd love if SFML had more thread primitives, conditions and semaphores are really *not* advanced features, and SFML should really provide them in a cross-platform way.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Custom SoundStream
« Reply #14 on: November 18, 2015, 07:46:26 am »
Quote
I'd love if SFML had more thread primitives, conditions and semaphores are really *not* advanced features, and SFML should really provide them in a cross-platform way.
What's wrong with using the C++ standard library for that?
Laurent Gomila - SFML developer