Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Minor Issue with Audio
#1
Hello

I sorry to keep bothering you guys with issues. I'm writing a game that has background music that is looping. I fade the music in and fade it out, so that it doesn't sound abrupt when starting to play or when I want it to end. So, this somewhat depends on the length of the sound clip.

So, I use _SNDLEN (handle) get the length of the sound clip. With version 3.14, _SNDLEN() no longer reports the length of a sound file that has the *.ogg extention. It returns 0 length. It has a handle and it will play it, just _SNDLEN() returns 0. 

I checked with *.mp3 and they report the correct length.

Version 3.13 works correctly with either extension .

Sample code and couple of .ogg files.

I'm running Linux.

Code: (Select All)

DIM AS STRING sndFile
DIM AS LONG sndH
DIM AS DOUBLE sndL

sndFile = _OPENFILEDIALOG$("Open Sound File", "", "*.mp3|*.ogg|*.wav|*.flac", "Audio files", -1)

IF sndFile <> "" THEN
sndH = _SNDOPEN(sndFile)
IF sndH > 0 THEN
  _SNDVOL sndH, .25
  sndL = _SNDLEN(sndH)
  _SNDPLAY sndH
  PRINT "File:"; sndFile
  PRINT "Sound Handle:"; sndH
  PRINT "Sound Length:"; sndL
END IF
END IF

END IF


.ogg   fx_drop_004.ogg (Size: 9.09 KB / Downloads: 32)

.ogg   fx_question_003.ogg (Size: 10.09 KB / Downloads: 41)
Reply
#2
Don't be sorry, this improves QB64pe for everyone!
b = b + ...
Reply
#3
I'll take a look at it when I get some time. It looks like this may be due to the changes in miniaudio v0.11.21.
Reply
#4
@justsomeguy QB64-PE v3.14.0 loads and decodes the audio files asynchronously on another thread after a call to _SNDOPEN. This means _SNDOPEN does not block the caller for extended period of time and almost instantaneously returns control. Not doing this would be problematic especially for large files and files that needs to render samples using some kind of instructions like MIDI, MOD etc. We had folks complain about the long load times in the past.

To work around your issue, just use the "noasync" flag with _SNDOPEN. This flag will force QB64-PE to completely render the audio in memory and then return control.

Code: (Select All)
_DEFINE A-Z AS LONG
OPTION _EXPLICIT


DIM sndFile AS STRING: sndFile = _OPENFILEDIALOG$("Open Sound File", , "*.mp3|*.ogg|*.wav|*.flac", "Audio files")

IF LEN(sndFile) THEN
    DIM sndH AS LONG: sndH = _SNDOPEN(sndFile, "noasync")

    IF sndH > 0 THEN
        DIM sndL AS DOUBLE: sndL = _SNDLEN(sndH)
        _SNDVOL sndH, .25
        _SNDPLAY sndH

        PRINT "File:"; sndFile
        PRINT "Sound Handle:"; sndH
        PRINT "Sound Length:"; sndL
    END IF
END IF

See https://qb64phoenix.com/qb64wiki/index.php/SNDOPEN for more fun stuff.

Now, a question may arise - why the hell does MP3 and formats report the correct length even when "noasync" is not used? Well, the answer to that questions is in the way miniaudio internally uses stb_vorbis unfortunately. It's the same reason why _MEMSOUND never works with Ogg Vorbis sounds. Fortunately though, the issue is limited to just Ogg Vorbis and does not impact other formats supported by _SNDOPEN.

Hope this helps.
Reply
#5
Thank you sir! I really appreciate you looking into it, and of course, it works now.

Using what you said, I found that this also works.

Code: (Select All)
DIM AS STRING sndFile
DIM AS LONG sndH
DIM AS DOUBLE sndL

sndFile = _OPENFILEDIALOG$("Open Sound File", "", "*.mp3|*.ogg|*.wav|*.flac", "Audio files", -1)

IF sndFile <> "" THEN
sndH = _SNDOPEN(sndFile)
IF sndH > 0 THEN
  _SNDVOL sndH, .25
  PRINT "Waiting for sound to render";
  DO
  sndL = _SNDLEN(sndH)
  PRINT ".";
  _DELAY .001
  LOOP WHILE sndL = 0
  PRINT
  _SNDPLAY sndH
  PRINT "File:"; sndFile
  PRINT "Sound Handle:"; sndH
  PRINT "Sound Length:"; sndL
END IF
END IF

This has the advantage of allowing it to "bake" and the program can do other things, and periodically check if the audio is ready.

Is this going to be normal behavior moving forward? I don't want to build a work around and have it patched out later.
Reply
#6
Hey @justsomeguy. I'm wondering why you want the length of the sound file to control fading in and out. I just used _SNDVOL to control fading an array of sounds in my recent game and it worked fine. What's your approach?
Reply
#7
(08-15-2024, 06:15 PM)NakedApe Wrote: Hey @justsomeguy. I'm wondering why you want the length of the sound file to control fading in and out. I just used _SNDVOL to control fading an array of sounds in my recent game and it worked fine. What's your approach?
I have several looping background music files. Some have no real intro, they just abruptly start and stop. I use the 5% of both ends to LERP the volume from 0 to 1.0 and 1.0 to 0.

For example, if a piece of music is 100 seconds. I raise the volume from 0-1.0 over 5 seconds and at 95 seconds I lower the volume from 1.0-0 over the last 5 seconds.
Reply
#8
Ahh, I see. So they aren't event-driven changes in volume, more like auto-fade in & out. Gotcha.
Reply
#9
(08-15-2024, 03:19 PM)justsomeguy Wrote: Thank you sir! I really appreciate you looking into it, and of course, it works now.

Using what you said, I found that this also works.

Code: (Select All)
DIM AS STRING sndFile
DIM AS LONG sndH
DIM AS DOUBLE sndL

sndFile = _OPENFILEDIALOG$("Open Sound File", "", "*.mp3|*.ogg|*.wav|*.flac", "Audio files", -1)

IF sndFile <> "" THEN
sndH = _SNDOPEN(sndFile)
IF sndH > 0 THEN
  _SNDVOL sndH, .25
  PRINT "Waiting for sound to render";
  DO
  sndL = _SNDLEN(sndH)
  PRINT ".";
  _DELAY .001
  LOOP WHILE sndL = 0
  PRINT
  _SNDPLAY sndH
  PRINT "File:"; sndFile
  PRINT "Sound Handle:"; sndH
  PRINT "Sound Length:"; sndL
END IF
END IF

This has the advantage of allowing it to "bake" and the program can do other things, and periodically check if the audio is ready.

Is this going to be normal behavior moving forward? I don't want to build a work around and have it patched out later.
No problem. You are welcome.

Well, the issue is only with the .ogg format. The asynchronous loading does not impact anything else other than .ogg. It may get patched out later but that fully depends on miniaudio and stb_vorbis. See:
Allow ma_decoder_get_length_in_pcm_frames() to work for OGG files · Issue #179 · mackron/miniaudio (github.com)
Better OGG support (and perhaps opus as well) · Issue #255 · mackron/miniaudio (github.com)

You solution has an issue. It might take a while for _SNDLEN to report the correct length if the audio is really long. In that case your loop will exit early because _DELAY .001 may be shorter than the time it takes to decode the complete audio. sndL in that case with report something shorter than the real length of the audio.

My recommendation would be to use:

Code: (Select All)
_SNDOPEN("foo.ogg", "noasync") ' to pre-render the complete audio to PCM in memory and then return < takes longer to return but is easier on the CPU during playback

Or

Code: (Select All)
_SNDOPEN("foo.ogg", "nodecode") ' to load the whole file in memory without decoding; decoding happens on-the-fly during playback < takes less time to return control but may place a tiny load on the CPU

Both workarounds will have zero impact if the program is compiled with an older version of QB64-PE. I personally would use "noasync" for short sounds like sound effects and "nodecode" for longer sounds like background music. But then, all of this only matter when using _SNDLEN and .ogg.
Reply




Users browsing this thread: 2 Guest(s)