MEMSOUND: Difference between revisions

From QB64 Phoenix Edition Wiki
Jump to navigation Jump to search
(Updated all new miniaudio _MEMSOUND behavior and features. Updated example 2 that works for both OpenAL and miniaudio backends)
(Fixed issues per https://github.com/QB64-Phoenix-Edition/QB64pe/pull/157)
Line 12: Line 12:
** .SIZE is the size of the sample data in '''bytes'''
** .SIZE is the size of the sample data in '''bytes'''
** .ELEMENTSIZE will contain the number of '''bytes-per-sample''' the audio contains.
** .ELEMENTSIZE will contain the number of '''bytes-per-sample''' the audio contains.
*** Can return 1 (8-bit mono), 2 (8-bit stereo), 2 (16-bit mono), 4 (16-bit stereo), 4 (32-bit floating point mono) or 8 (32-bit floating point stereo).
*** Can return 1 (8-bit mono), 2 (8-bit stereo), 2 (16-bit mono), 4 (16-bit stereo), 4 (32-bit mono) or 8 (32-bit stereo).
*** Use .TYPE to determine the data type of the sample data ([[UNSIGNED]] [[_BYTE]], [[INTEGER]] or [[SINGLE]]).
*** Use .TYPE to determine the data type of the sample data.
** .TYPE will contain the data type of the sample data. This can be 0 ([[INTEGER]]), 1 ([[INTEGER]]), 2 ([[_UNSIGNED]] [[BYTE]]) or 4 ([[SINGLE]])
** .TYPE will contain the data type of the sample data. See [[_MEM]] for details.
** .SOUND will contain the same handle value as returned by the [[_SNDOPEN]] function.
** .SOUND will contain the same handle value as returned by the [[_SNDOPEN]] function.
* The second parameter {{Parameter| channel%}} must be 0 (interleaved/mono; version 3.1.0 and up), 1 (left channel/mono) or 2 (right channel, for stereo files).
* The second parameter {{Parameter| channel%}} must be 0 (interleaved/mono; version 3.1.0 and up), 1 (left channel/mono) or 2 (right channel, for stereo files).
Line 33: Line 33:
''Example 1:'' Checking that a sound file is stereo.
''Example 1:'' Checking that a sound file is stereo.
{{CodeStart}}
{{CodeStart}}
song& = {{Cl|_SNDOPEN}}("song.wav") 'replace song.wav with a sound file you have
{{Cl|OPTION _EXPLICIT}}
{{Cl|IF}} song& = 0 {{Cl|THEN}} {{Cl|PRINT}} "Load failed.": {{Cl|END}}
 
{{Cl|PRINT}} "Loading...";
{{Cl|DIM}} Song {{Cl|AS}} {{Cl|LONG}}
Song = {{Cl|_SNDOPEN}}("onward_ride1.flac") ' Replace file name with your sound file
{{Cl|IF}} Song < 1 {{Cl|THEN}}
    {{Cl|PRINT}} "Failed to load sound!"
    {{Cl|END}}
{{Cl|END IF}}
{{Cl|PRINT}} "Done!"


{{Cl|DIM}} leftchannel {{Cl|AS}} {{Cl|_MEM}}, rightchannel {{Cl|AS}} {{Cl|_MEM}}
{{Cl|DIM}} Channels {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_BYTE}}
leftchannel = {{Cl|_MEMSOUND}}(song&, 1)
Channels = SndChannels(Song)
rightchannel = {{Cl|_MEMSOUND}}(song&, 2)


{{Cl|IF}} rightchannel.SIZE > 0 {{Cl|THEN}} {{Cl|PRINT}} "This file is STEREO"
{{Cl|IF}} Channels = 2 {{Cl|THEN}}
{{Cl|IF}} rightchannel.SIZE = 0 {{Cl|AND}} leftchannel.SIZE > 0 {{Cl|THEN}}
    {{Cl|PRINT}} "This file is STEREO"
{{Cl|ELSEIF}} Channels = 1 {{Cl|THEN}}
     {{Cl|PRINT}} "This file is MONO"
     {{Cl|PRINT}} "This file is MONO"
{{Cl|ELSEIF}} rightchannel.SIZE = 0 {{Cl|AND}} leftchannel.SIZE = 0 {{Cl|THEN}}
{{Cl|ELSE}}
     {{Cl|PRINT}} "An error occurred."
     {{Cl|PRINT}} "An error occurred."
{{Cl|END IF}}
{{Cl|END IF}}


{{Cl|_SNDCLOSE}} song& 'closing the sound releases the mem blocks  
{{Cl|_SNDCLOSE}} Song 'closing the sound releases the mem blocks
 
{{Cl|END}}
 
 
' This function returns the number of sound channels for a valid sound "handle"
' 2 = stereo, 1 = mono, 0 = error
{{Cl|FUNCTION}} SndChannels~%% (handle {{Cl|AS}} {{Cl|LONG}})
    {{Cl|DIM}} SampleData {{Cl|AS}} {{Cl|_MEM}}
 
    SndChannels = 0 ' Assume failure
 
    ' Check if the sound is valid
    SampleData = {{Cl|_MEMSOUND}}(handle, 1)
    {{Cl|IF}} SampleData.SIZE = 0 {{Cl|THEN}}
        {{Cl|EXIT FUNCTION}}
    {{Cl|END IF}}
 
    ' Check the data type and then decide if the sound is stereo or mono
    {{Cl|IF}} SampleData.TYPE = 260 {{Cl|THEN}} ' 32-bit floating point
        {{Cl|IF}} SampleData.ELEMENTSIZE = 4 {{Cl|THEN}}
            SndChannels = 1
        {{Cl|ELSEIF}} SampleData.ELEMENTSIZE = 8 {{Cl|THEN}}
            SndChannels = 2
        {{Cl|END IF}}
    {{Cl|ELSEIF}} SampleData.TYPE = 132 {{Cl|THEN}} ' 32-bit integer
        {{Cl|IF}} SampleData.ELEMENTSIZE = 4 {{Cl|THEN}}
            SndChannels = 1
        {{Cl|ELSEIF}} SampleData.ELEMENTSIZE = 8 {{Cl|THEN}}
            SndChannels = 2
        {{Cl|END IF}}
    {{Cl|ELSEIF}} SampleData.TYPE = 130 {{Cl|THEN}} ' 16-bit integer
        {{Cl|IF}} SampleData.ELEMENTSIZE = 2 {{Cl|THEN}}
            SndChannels = 1
        {{Cl|ELSEIF}} SampleData.ELEMENTSIZE = 4 {{Cl|THEN}}
            SndChannels = 2
        {{Cl|END IF}}
    {{Cl|ELSEIF}} SampleData.TYPE = 1153 {{Cl|THEN}} ' 8-bit unsigned integer
        {{Cl|IF}} SampleData.ELEMENTSIZE = 1 {{Cl|THEN}}
            SndChannels = 1
        {{Cl|ELSEIF}} SampleData.ELEMENTSIZE = 2 {{Cl|THEN}}
            SndChannels = 2
        {{Cl|END IF}}
    {{Cl|ELSEIF}} SampleData.TYPE = 0 {{Cl|THEN}} ' This means this is an OpenAL sound handle
        {{Cl|DIM}} RightChannel {{Cl|AS}} {{Cl|_MEM}}
        RightChannel = {{Cl|_MEMSOUND}}(handle, 2)
        {{Cl|IF}} RightChannel.SIZE > 0 {{Cl|THEN}}
            SndChannels = 2
        {{Cl|ELSE}}
            SndChannels = 1
        {{Cl|END IF}}
    {{Cl|END IF}}
{{Cl|END FUNCTION}}
{{CodeEnd}}
{{CodeEnd}}


Line 87: Line 147:


     {{Cl|$CHECKING}}:OFF
     {{Cl|$CHECKING}}:OFF
     {{Cl|IF}} (sz = 4 {{Cl|OR}} sz = 2) {{Cl|AND}} SampleData.TYPE = 1 {{Cl|THEN}} ' integer stereo or mono
     {{Cl|IF}} SampleData.TYPE = 130 {{Cl|THEN}} ' integer stereo or mono
         {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
         {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
             si = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|INTEGER}}) 'get sound data
             si = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|INTEGER}}) 'get sound data
             {{Cl|LINE}} (x, {{Cl|_HEIGHT}} / 2)-{{Cl|STEP}}(0, 300 * si / 32768), {{Cl|_RGB32}}(0, 111, 0) 'plot wave
             {{Cl|LINE}} (x, {{Cl|_HEIGHT}} / 2)-{{Cl|STEP}}(0, 300 * si / 32768), {{Cl|_RGB32}}(0, 111, 0) 'plot wave
         {{Cl|NEXT}}
         {{Cl|NEXT}}
     {{Cl|ELSEIF}} (sz = 8 {{Cl|OR}} sz = 4) {{Cl|AND}} SampleData.TYPE = 4 {{Cl|THEN}} ' floating point stereo or mono
     {{Cl|ELSEIF}} SampleData.TYPE = 260 {{Cl|THEN}} ' floating point stereo or mono
         {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
         {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
             sf = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|SINGLE}}) 'get sound data
             sf = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|SINGLE}}) 'get sound data

Revision as of 01:06, 4 September 2022

The _MEMSOUND function returns a _MEM value referring to a sound's raw data in memory using a designated sound handle created by the _SNDOPEN function.


Syntax

soundBlock = _MEMSOUND[(soundHandle&, channel%)]


Parameters

  • The soundBlock _MEM type variable holds the read-only elements .OFFSET, .SIZE, .ELEMENTSIZE, .TYPE and .SOUND.
    • .OFFSET is the starting memory address of the sound sample data.
    • .SIZE is the size of the sample data in bytes
    • .ELEMENTSIZE will contain the number of bytes-per-sample the audio contains.
      • Can return 1 (8-bit mono), 2 (8-bit stereo), 2 (16-bit mono), 4 (16-bit stereo), 4 (32-bit mono) or 8 (32-bit stereo).
      • Use .TYPE to determine the data type of the sample data.
    • .TYPE will contain the data type of the sample data. See _MEM for details.
    • .SOUND will contain the same handle value as returned by the _SNDOPEN function.
  • The second parameter channel% must be 0 (interleaved/mono; version 3.1.0 and up), 1 (left channel/mono) or 2 (right channel, for stereo files).


Description

  • Use the function to access raw sound data in memory for direct access.
  • Sound handle values and the memory used must still be freed using _SNDCLOSE when no longer required.
  • If .SIZE returns 0, that means the data could not be accessed. It may happen if you try to access the right channel in a mono file, for example.


Availability

  • QB64 1.5 and up (QB64 Team)
  • QBPE 0.5 and up (QB64 Phoenix Edition)


Examples

Example 1: Checking that a sound file is stereo.

OPTION _EXPLICIT

PRINT "Loading...";
DIM Song AS LONG
Song = _SNDOPEN("onward_ride1.flac") ' 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 = 2 THEN
    PRINT "This file is STEREO"
ELSEIF Channels = 1 THEN
    PRINT "This file is MONO"
ELSE
    PRINT "An error occurred."
END IF

_SNDCLOSE Song 'closing the sound releases the mem blocks

END


' This function returns the number of sound channels for a valid sound "handle"
' 2 = stereo, 1 = mono, 0 = error
FUNCTION SndChannels~%% (handle AS LONG)
    DIM SampleData AS _MEM

    SndChannels = 0 ' Assume failure

    ' Check if the sound is valid
    SampleData = _MEMSOUND(handle, 1)
    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
    ELSEIF SampleData.TYPE = 0 THEN ' This means this is an OpenAL sound handle
        DIM RightChannel AS _MEM
        RightChannel = _MEMSOUND(handle, 2)
        IF RightChannel.SIZE > 0 THEN
            SndChannels = 2
        ELSE
            SndChannels = 1
        END IF
    END IF
END FUNCTION


Example 2: Plotting a sound's waves.

DEFLNG A-Z
OPTION _EXPLICIT
OPTION _EXPLICITARRAY

SCREEN _NEWIMAGE(800, 327, 32)

PRINT "Loading...";
DIM Song AS LONG
Song = _SNDOPEN("OPL3 Groove.rad") ' Replace this with your (rad, mid, it, xm, s3m, mod, mp3, flac, ogg, wav) sound file
IF Song < 1 THEN
    PRINT "Failed to load song!"
    END
END IF
PRINT "Done!"

_SNDPLAY Song

DIM SampleData AS _MEM
SampleData = _MEMSOUND(Song, 1) ' This can now be 0 or 1
IF SampleData.SIZE = 0 THEN
    PRINT "Failed to access sound sample data."
    END
END IF

DIM x AS LONG, i AS _UNSIGNED _INTEGER64, sf AS SINGLE, si AS INTEGER
DIM sz AS _UNSIGNED _INTEGER64

sz = _CV(_UNSIGNED _INTEGER64, _MK$(_OFFSET, SampleData.ELEMENTSIZE)) ' sz is the total size of the sound in bytes

DO UNTIL _KEYHIT = 27 OR NOT _SNDPLAYING(Song) OR i + (_WIDTH * sz) > SampleData.SIZE
    CLS
    LOCATE 1, 1: PRINT i; "/"; SampleData.SIZE, "Frame Size ="; sz, "Data Type ="; SampleData.TYPE

    $CHECKING:OFF
    IF SampleData.TYPE = 130 THEN ' integer stereo or mono
        FOR x = 0 TO _WIDTH - 1
            si = _MEMGET(SampleData, SampleData.OFFSET + i + x * sz, INTEGER) 'get sound data
            LINE (x, _HEIGHT / 2)-STEP(0, 300 * si / 32768), _RGB32(0, 111, 0) 'plot wave
        NEXT
    ELSEIF SampleData.TYPE = 260 THEN ' floating point stereo or mono
        FOR x = 0 TO _WIDTH - 1
            sf = _MEMGET(SampleData, SampleData.OFFSET + i + x * sz, SINGLE) 'get sound data
            LINE (x, _HEIGHT / 2)-STEP(0, sf * 300), _RGB32(0, 111, 0) 'plot wave
        NEXT
    ELSEIF sz = 2 AND SampleData.TYPE = 0 THEN ' integer mono (QB64 OpenAL stuff)
        FOR x = 0 TO _WIDTH - 1
            si = _MEMGET(SampleData, SampleData.OFFSET + i + x * sz, INTEGER) 'get sound data
            LINE (x, _HEIGHT / 2)-STEP(0, 300 * si / 32768), _RGB32(0, 111, 0) 'plot wave
        NEXT
    END IF
    $CHECKING:ON

    _DISPLAY
    _LIMIT 60

    i = FIX(_SNDGETPOS(Song) * _SNDRATE) * sz ' Calculate the new sample frame position
LOOP

_SNDCLOSE Song 'closing the sound releases the mem blocks
_AUTODISPLAY
END


See also


Navigation:
Main Page with Articles and Tutorials
Keyword Reference - Alphabetical
Keyword Reference - By usage
Report a broken link