Phoenix 3.5.0 bug? - Solved, just diference!
#1
Hello. I found a MemSound bug (see attached test program) that makes Phoenix 3.5.0 MemSound unable to be used properly and causing my programs to crash, unlike QB64 2.02. The attached program exactly shows the occurrence of the error.

Code: (Select All)
$NoPrefix
s = SndOpen("0.mp3")
Dim As MEM l, r
l = MemSound(s, 1)
r = MemSound(s, 2)
Print "MemSound bug"
Print

Print "Value returned for left audio channel:"; l.SIZE
Print "Value returned for right audio channel:"; r.SIZE
chan& = SndLen(s) * 2 * SndRate

If l.SIZE = r.SIZE And r.SIZE = chan& Then Print "All ok!": End

Print "the size of the ONE audio track channel, that is expected:"; chan&
Print "Value returned with SndOpen:"; s;
If s > 0 Then Print "[correct audio file]" Else Print "[unsupported audio file]"
Print
Print "press key for try play this file"
Sleep
SndPlay s
If SndPlaying(s) Then Print "Both channels playing, bug is not in SndOpen." Else Print "Bug is in SndOpen"

'wroted in Phoenix IDE 3.5.0


Reply
#2
(02-19-2023, 04:25 PM)Petr Wrote: Hello. I found a MemSound bug (see attached test program) that makes Phoenix 3.5.0 MemSound unable to be used properly and causing my programs to crash, unlike QB64 2.02. The attached program exactly shows the occurrence of the error.

Code: (Select All)
$NoPrefix
s = SndOpen("0.mp3")
Dim As MEM l, r
l = MemSound(s, 1)
r = MemSound(s, 2)
Print "MemSound bug"
Print

Print "Value returned for left audio channel:"; l.SIZE
Print "Value returned for right audio channel:"; r.SIZE
chan& = SndLen(s) * 2 * SndRate

If l.SIZE = r.SIZE And r.SIZE = chan& Then Print "All ok!": End

Print "the size of the ONE audio track channel, that is expected:"; chan&
Print "Value returned with SndOpen:"; s;
If s > 0 Then Print "[correct audio file]" Else Print "[unsupported audio file]"
Print
Print "press key for try play this file"
Sleep
SndPlay s
If SndPlaying(s) Then Print "Both channels playing, bug is not in SndOpen." Else Print "Bug is in SndOpen"

'wroted in Phoenix IDE 3.5.0

This is working for me @Petr.

[Image: Screenshot-20230219-101403.png]

However, there has been a slight change in the behavior of _MemSound since we moved to the miniaudio backend. The wiki link has all the details and new examples. But to put this briefly, line "r.SIZE" will always return 0 since miniaudio internally uses interleaved audio for multi-channel sounds. Hence, the "All ok!" text will never print.
Reply
#3
Ok then write me how to get the audio data for the right channel. Also try to play the acquired music data for the left channel. It caused the program to crash. Don't tell me you've made changes to MemSound that would cause incompatibility. I couldn't find any such change on Wiki.


[Image: so-its-correct.png]

then try this:

Code: (Select All)
$NoPrefix
s = SndOpen("0.mp3")
Dim As MEM l, r
Dim done As Long, m As Integer
l = MemSound(s, 1)


Do Until done = l.SIZE
    MemGet l, l.OFFSET + done, m
    done = done + 2
    SndRaw m / 32768
Loop

It's entirely possible that I've missed something, so I'll ask you for a valid link to a real working use of memsound. Thank you.

In the attached screenshot, look at the numeric values returned. Even if you got it right, I absolutely do not understand the difference between the correctly calculated expected data size and what it returns for the left channel. And try playing the audio for the left channel.


Reply
#4
Good. I kicked it now. Phoenix seems to have a much better level of oversampling. So I want to confirm only one thing, but it is essential. Are the samples in the MEM array organized in order Left, Right, Left, Right...? So MemSound with a parameter of 1 will return the entire sound array for both channels?

I also found out, and I'm thrilled and thank you very much, that SndRaw is now fixed in Phoenix and actually plays in stereo! Here is a test program that opened my eyes.


Code: (Select All)
$NoPrefix
Dim s As Long
s = SndOpen("0.mp3")
Dim As MEM l, r
Dim done As Long
Dim m2 As Single '4 byte long, so 32bit sound!
Dim m As Single

l = MemSound(s, 1)
If l.ELEMENTSIZE <> 8 Then Print "This program play just 32 bit songs.": End

Do Until done = l.SIZE - 8
    MemGet l, l.OFFSET + done, m
    MemGet l, l.OFFSET + done + 4, m2
    done = done + 8
    SndRaw m, m2
Loop
'wroted in Phoenix 3.5.0

I will change the name of the thread.


Reply
#5
Code: (Select All)
OPTION _EXPLICIT

PRINT "Loading...";
DIM Song AS LONG
Song = _SNDOPEN("STARDUST.MOD") ' Replace file name with your sound file
IF Song < 1 THEN
    PRINT "Failed to load sound!"
    END
END IF
PRINT "Done!"

DIM Channels AS _UNSIGNED _BYTE
Channels = SndChannels(Song)

IF Channels > 0 THEN
    PRINT "The sound has"; Channels; "channels."
ELSE
    PRINT "An error occurred."
    END
END IF

DIM AS LONG i, rawSnd

rawSnd = _SNDOPENRAW
IF rawSnd < 1 THEN
    PRINT "Failed to open sound pipe!"
    END
END IF

FOR i = 0 TO Channels - 1
    PRINT "Queueing channel"; i; "...";
    PlaySoundChannel Song, i, rawSnd
    PRINT "Done!"

    PRINT "Waiting for playback to finish...";
    DO WHILE _SNDRAWLEN(rawSnd) > 0 'Finish any left over queued sound!
        SLEEP 1
    LOOP
    PRINT "Done!"
NEXT

_SNDCLOSE rawSnd
_SNDCLOSE Song 'closing the sound releases the mem blocks

END

' Here chan starts from 0
' So, chan 0 is the first channel, 1 the next one and so on
' rs is the raw sound handle
SUB PlaySoundChannel (handle AS LONG, chan AS _UNSIGNED _BYTE, rs AS LONG)
    DIM AS _UNSIGNED _INTEGER64 i, sz, es, ofs
    DIM SampleData AS _MEM
    DIM channels AS _UNSIGNED _BYTE
    DIM samp AS SINGLE

    channels = SndChannels(handle)

    SampleData = _MEMSOUND(handle, 0)
    IF SampleData.SIZE = 0 THEN
        EXIT SUB
    END IF

    $IF 64BIT THEN
        sz = _CV(_UNSIGNED _INTEGER64, _MK$(_OFFSET, SampleData.SIZE)) ' sz is the total size of the sound in bytes
        es = _CV(_UNSIGNED _INTEGER64, _MK$(_OFFSET, SampleData.ELEMENTSIZE))
    $ELSE
            sz = _CV(_Unsigned long, _MK$(_Offset, SampleData.SIZE)) ' sz is the total size of the sound in bytes
            es = _CV(_Unsigned long, _MK$(_Offset, SampleData.ELEMENTSIZE))
    $END IF

    ofs = es \ channels

    FOR i = 0 TO sz - es STEP es
        IF SampleData.TYPE = 260 THEN ' 32-bit floating point
            samp = _MEMGET(SampleData, SampleData.OFFSET + i + (chan * ofs), SINGLE)
        ELSEIF SampleData.TYPE = 132 THEN ' 32-bit integer
            samp = _MEMGET(SampleData, SampleData.OFFSET + i + (chan * ofs), LONG) / 2147483648
        ELSEIF SampleData.TYPE = 130 THEN ' 16-bit integer
            samp = _MEMGET(SampleData, SampleData.OFFSET + i + (chan * ofs), INTEGER) / 32768
        ELSEIF SampleData.TYPE = 1153 THEN ' 8-bit unsigned integer
            samp = (_MEMGET(SampleData, SampleData.OFFSET + i + (chan * ofs), _UNSIGNED _BYTE) - 128) / 128
        END IF

        IF chan MOD 2 = 0 THEN
            _SNDRAW samp, 0, rs
        ELSE
            _SNDRAW 0, samp, rs
        END IF
    NEXT
END SUB

' This function returns the number of sound channels for a valid sound "handle"
' Note that we are assuming that the sound can have at most 2 channels
' In reality miniaudio can handle sounds with more than 2 channels
' 2 = stereo, 1 = mono, 0 = error
FUNCTION SndChannels~%% (handle AS LONG)
    DIM SampleData AS _MEM

    ' Check if the sound is valid
    SampleData = _MEMSOUND(handle, 0)
    IF SampleData.SIZE = 0 THEN
        EXIT FUNCTION
    END IF

    ' Check the data type and then decide if the sound is stereo or mono
    IF SampleData.TYPE = 260 THEN ' 32-bit floating point
        IF SampleData.ELEMENTSIZE = 4 THEN
            SndChannels = 1
        ELSEIF SampleData.ELEMENTSIZE = 8 THEN
            SndChannels = 2
        END IF
    ELSEIF SampleData.TYPE = 132 THEN ' 32-bit integer
        IF SampleData.ELEMENTSIZE = 4 THEN
            SndChannels = 1
        ELSEIF SampleData.ELEMENTSIZE = 8 THEN
            SndChannels = 2
        END IF
    ELSEIF SampleData.TYPE = 130 THEN ' 16-bit integer
        IF SampleData.ELEMENTSIZE = 2 THEN
            SndChannels = 1
        ELSEIF SampleData.ELEMENTSIZE = 4 THEN
            SndChannels = 2
        END IF
    ELSEIF SampleData.TYPE = 1153 THEN ' 8-bit unsigned integer
        IF SampleData.ELEMENTSIZE = 1 THEN
            SndChannels = 1
        ELSEIF SampleData.ELEMENTSIZE = 2 THEN
            SndChannels = 2
        END IF
    END IF
END FUNCTION

Here you go @Petr. Hope this will help.
Reply
#6
I tried it and it ended up with an error.


[Image: ifc.png]


Reply
#7
Quote:Good. I kicked it now. Phoenix seems to have a much better level of oversampling. So I want to confirm only one thing, but it is essential. Are the samples in the MEM array organized in order Left, Right, Left, Right...? So MemSound with a parameter of 1 will return the entire sound array for both channels?

Yes. They are interleaved. LRLR... for stereo sounds.


Quote:I also found out, and I'm thrilled and thank you very much, that SndRaw is now fixed in Phoenix and actually plays in stereo! Here is a test program that opened my eyes.


Yes. That bug was really annoying. But it is fixed now. I discovered it while writing my MOD re-player using _SNDRAW and then I discovered your posts about it in the old forums.

You've been away from the scene for a while. Nice to see you are back.
Reply
#8
You are using the 32-bit version of QB64-PE. Sorry, I did not pay much attention to what it would do when compiled with the 32-bit version of QB64-PE.

The code should run correctly if you compile with the 64-bit version of QB64-PE though.

Update: I fixed my code above for 32-bit QB64-PE. It should work correctly now.
Reply
#9
It works now. I will study it. Thank you.


Reply
#10
(02-19-2023, 07:06 PM)Petr Wrote: I tried it and it ended up with an error.


[Image: ifc.png]

(02-19-2023, 07:43 PM)Petr Wrote: It works now. I will study it. Thank you.

@Petr there was a bug. More like a typo Big Grin inside the PlaySoundChannel FOR loop that I corrected. The updated code is in the same post.
Reply




Users browsing this thread: 2 Guest(s)