MEMSOUND: Difference between revisions

From QB64 Phoenix Edition Wiki
Jump to navigation Jump to search
(Add notes to highlight miniaudio changes)
No edit summary
 
(7 intermediate revisions by one other user not shown)
Line 4: Line 4:


{{PageSyntax}}
{{PageSyntax}}
: {{Parameter|soundBlock}} = [[_MEMSOUND]]({{Parameter|soundHandle&}}, {{Parameter|channel%}})
: {{Parameter|soundBlock}} = [[_MEMSOUND]]({{Parameter|soundHandle&}}[, {{Parameter|channel&}}])




{{PageParameters}}
{{PageParameters}}
* The {{Parameter|soundBlock}} [[_MEM]] type variable holds the read-only elements .OFFSET, .SIZE, .ELEMENTSIZE, .TYPE and .SOUND.
* The {{Parameter|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.
** '''.OFFSET''' is the starting memory address of the sound sample data.
** .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 mono) or 8 (32-bit 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.
*** 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.
** '''.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 and up), 1 (left channel/mono) or 2 (right channel, for stereo files; only supported on the old OpenAL backend).
* The second parameter {{Parameter|channel&}} is optional and deprecated. This was used to specify the sound channel. In '''QB64-PE v3.1.0''' and above stereo data is always interleaved. You must use '''.ELEMENTSIZE''' and '''.TYPE''' to determine the type of audio data you are dealing with.




Line 23: Line 23:
* Even if the memory pointer obtained by this fuction was already freed again using [[_MEMFREE]], the respective Sound handle itself must still be freed using [[_SNDCLOSE]] when no longer required.
* Even if the memory pointer obtained by this fuction was already freed again using [[_MEMFREE]], the respective Sound handle itself 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 or the format simply does not support accessing raw PCM samples.
* 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 or the format simply does not support accessing raw PCM samples.
* {{Parameter|channel&}} - 1 (left channel/mono) or 2 (right channel; for stereo files) was supported on the old OpenAL backend. For the new miniaudio backend, this must be 0.
* '''_MEMSOUND''' does not work for sounds loaded with [[_SNDOPEN]] when using the '''STREAM''' or '''NODECODE''' flags.




{{PageAvailability}}
{{PageAvailability}}
* '''QB64 v1.5 and up'''
<!-- QB64 = a version or none, QBPE = a version or all, Platforms = yes or no -->
* '''QB64-PE all versions'''
<gallery widths="48px" heights="48px" mode="nolines">
File:Qb64.png|'''v1.5'''
File:Qbpe.png|'''all'''
File:Apix.png
File:Win.png|'''yes'''
File:Lnx.png|'''yes'''
File:Osx.png|'''yes'''
</gallery>
<!-- additional availability notes go below here -->




Line 33: Line 43:
;Example 1:Checking that a sound file is stereo.
;Example 1:Checking that a sound file is stereo.
{{CodeStart}}
{{CodeStart}}
{{Cl|OPTION _EXPLICIT}}
{{Cl|OPTION}} {{Cl|_EXPLICIT}}


{{Cl|PRINT}} "Loading...";
{{Cl|CONST}} FILE_FILTER = {{Text|<nowiki>"*.wav|*.aiff|*.aifc|*.flac|*.ogg|*.mp3|*.it|*.xm|*.s3m|*.mod|*.rad|*.ahx|*.hvl|*.mus|*.hmi|*.hmp|*.hmq|*.kar|*.lds|*.mds|*.mids|*.rcp|*.r36|*.g18|*.g36|*.rmi|*.mid|*.midi|*.xfm|*.xmi|*.qoa"</nowiki>|#FFB100}}
 
{{Cl|PRINT}} {{Text|<nowiki>"Loading..."</nowiki>|#FFB100}};
{{Cl|DIM}} Song {{Cl|AS}} {{Cl|LONG}}
{{Cl|DIM}} Song {{Cl|AS}} {{Cl|LONG}}
Song = {{Cl|_SNDOPEN}}("onward_ride1.flac") ' Replace file name with your sound file
Song = {{Cl|_SNDOPEN}}({{Cl|_OPENFILEDIALOG$}}({{Text|<nowiki>"Open audio file"</nowiki>|#FFB100}}, , FILE_FILTER))
{{Cl|IF}} Song < 1 {{Cl|THEN}}
{{Cl|IF}} Song < {{Text|1|#F580B1}} {{Cl|THEN}}
     {{Cl|PRINT}} "Failed to load sound!"
     {{Cl|PRINT}} {{Text|<nowiki>"Failed to load sound!"</nowiki>|#FFB100}}
     {{Cl|END}}
     {{Cl|END}}
{{Cl|END IF}}
{{Cl|END IF}}
{{Cl|PRINT}} "Done!"
{{Cl|PRINT}} {{Text|<nowiki>"Done!"</nowiki>|#FFB100}}


{{Cl|DIM}} Channels {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_BYTE}}
{{Cl|DIM}} channels {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_BYTE}}: channels = {{Text|SndChannels|#55FF55}}(Song)
Channels = SndChannels(Song)


{{Cl|IF}} Channels = 2 {{Cl|THEN}}
{{Cl|IF}} channels {{Cl|THEN}}
     {{Cl|PRINT}} "This file is STEREO"
     {{Cl|PRINT}} {{Text|<nowiki>"This sound data has"</nowiki>|#FFB100}}; channels; {{Text|<nowiki>"channels."</nowiki>|#FFB100}}
{{Cl|ELSEIF}} Channels = 1 {{Cl|THEN}}
    {{Cl|PRINT}} "This file is MONO"
{{Cl|ELSE}}
{{Cl|ELSE}}
     {{Cl|PRINT}} "An error occurred."
     {{Cl|PRINT}} {{Text|<nowiki>"An error occurred."</nowiki>|#FFB100}}
{{Cl|END IF}}
{{Cl|END IF}}


{{Cl|_SNDCLOSE}} Song 'closing the sound releases the mem blocks
{{Cl|_SNDCLOSE}} Song


{{Cl|END}}
{{Cl|END}}


{{Text|<nowiki>' This function returns the number of sound channels for a valid sound handle</nowiki>|#919191}}
{{Cl|FUNCTION}} {{Text|SndChannels~%%|#55FF55}} (handle {{Cl|AS}} {{Cl|LONG}})
    {{Cl|DECLARE LIBRARY}}
        {{Text|<nowiki>' This is needed to convert _OFFSET to LONG / _INTEGER64</nowiki>|#919191}}
        {{Cm|$IF}} {{Text|32BIT|#F580B1}} {{Cm|THEN}}
            {{Cl|FUNCTION}} {{Text|SndChannels.CLngPtr~&|#55FF55}} {{Cl|ALIAS}} {{Text|<nowiki>"uintptr_t"</nowiki>|#FFB100}} ({{Cl|BYVAL}} o {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_OFFSET (function)|_OFFSET}})
        {{Cm|$ELSE}}
            {{Cl|FUNCTION}} {{Text|SndChannels.CLngPtr~&&|#55FF55}} {{Cl|ALIAS}} {{Text|<nowiki>"uintptr_t"</nowiki>|#FFB100}} ({{Cl|BYVAL}} o {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_OFFSET (function)|_OFFSET}})
        {{Cm|$END IF}}
    {{Cl|END DECLARE}}
    {{Cl|DIM}} soundData {{Cl|AS}} {{Cl|_MEM}}: soundData = {{Cl|_MEMSOUND}}(handle)
    {{Cl|IF}} soundData.SIZE {{Cl|THEN}}
        {{Text|<nowiki>' See https://qb64phoenix.com/qb64wiki/index.php/MEM for details</nowiki>|#919191}}
        {{Cl|SELECT CASE}} soundData.TYPE
            {{Cl|CASE}} {{Text|260|#F580B1}} {{Text|<nowiki>' 32-bit floating point</nowiki>|#919191}}
                {{Text|SndChannels|#55FF55}} = {{Text|SndChannels.CLngPtr|#55FF55}}(soundData.ELEMENTSIZE) \ _SIZE_OF_SINGLE
            {{Cl|CASE}} {{Text|132|#F580B1}} {{Text|<nowiki>' 32-bit signed integer</nowiki>|#919191}}
                {{Text|SndChannels|#55FF55}} = {{Text|SndChannels.CLngPtr|#55FF55}}(soundData.ELEMENTSIZE) \ _SIZE_OF_LONG


' This function returns the number of sound channels for a valid sound "handle"
            {{Cl|CASE}} {{Text|130|#F580B1}} {{Text|<nowiki>' 16-bit signed integer</nowiki>|#919191}}
' 2 = stereo, 1 = mono, 0 = error
                {{Text|SndChannels|#55FF55}} = {{Text|SndChannels.CLngPtr|#55FF55}}(soundData.ELEMENTSIZE) \ _SIZE_OF_INTEGER
{{Cl|FUNCTION}} SndChannels~%% (handle {{Cl|AS}} {{Cl|LONG}})
    {{Cl|DIM}} SampleData {{Cl|AS}} {{Cl|_MEM}}


    SndChannels = 0 ' Assume failure
            {{Cl|CASE}} {{Text|1153|#F580B1}} {{Text|<nowiki>' 8-bit unsigned integer</nowiki>|#919191}}
                {{Text|SndChannels|#55FF55}} = {{Text|SndChannels.CLngPtr|#55FF55}}(soundData.ELEMENTSIZE) \ _SIZE_OF_BYTE


    ' Check if the sound is valid
            {{Cl|CASE ELSE}} {{Text|<nowiki>' unknown format</nowiki>|#919191}}
    SampleData = {{Cl|_MEMSOUND}}(handle, 0)
                {{Text|SndChannels|#55FF55}} = {{Text|1|#F580B1}}
    {{Cl|IF}} SampleData.SIZE = 0 {{Cl|THEN}}
         {{Cl|END SELECT}}
         {{Cl|EXIT FUNCTION}}
     {{Cl|END IF}}
     {{Cl|END IF}}


    ' Check the data type and then decide if the sound is stereo or mono
     {{Cl|IF}} soundData.SOUND = handle {{Cl|THEN}} {{Cl|_MEMFREE}} soundData
     {{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}}
{{Cl|END FUNCTION}}
{{CodeEnd}}
{{CodeEnd}}
Line 114: Line 109:
;Example 2:Plotting a sound's waves.
;Example 2:Plotting a sound's waves.
{{CodeStart}}
{{CodeStart}}
{{Cl|DEFLNG}} A-Z
{{Cl|OPTION}} {{Cl|_EXPLICIT}}
{{Cl|OPTION _EXPLICIT}}
 
{{Cl|CONST}} FILE_FILTER = {{Text|<nowiki>"*.wav|*.aiff|*.aifc|*.flac|*.ogg|*.mp3|*.it|*.xm|*.s3m|*.mod|*.rad|*.ahx|*.hvl|*.mus|*.hmi|*.hmp|*.hmq|*.kar|*.lds|*.mds|*.mids|*.rcp|*.r36|*.g18|*.g36|*.rmi|*.mid|*.midi|*.xfm|*.xmi|*.qoa"</nowiki>|#FFB100}}
 
{{Cl|DECLARE LIBRARY}}
    {{Text|<nowiki>' This is needed to convert _OFFSET to LONG / _INTEGER64</nowiki>|#919191}}
    {{Cm|$IF}} {{Text|32BIT|#F580B1}} {{Cm|THEN}}
        {{Cl|FUNCTION}} {{Text|CLngPtr~&|#55FF55}} {{Cl|ALIAS}} {{Text|<nowiki>"uintptr_t"</nowiki>|#FFB100}} ({{Cl|BYVAL}} o {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_OFFSET (function)|_OFFSET}})
    {{Cm|$ELSE}}
        {{Cl|FUNCTION}} {{Text|CLngPtr~&&|#55FF55}} {{Cl|ALIAS}} {{Text|<nowiki>"uintptr_t"</nowiki>|#FFB100}} ({{Cl|BYVAL}} o {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_OFFSET (function)|_OFFSET}})
    {{Cm|$END IF}}
{{Cl|END DECLARE}}


{{Cl|SCREEN}} {{Cl|_NEWIMAGE}}(800, 327, 32)
{{Cl|SCREEN}} {{Cl|_NEWIMAGE}}({{Text|800|#F580B1}}, {{Text|327|#F580B1}}, {{Text|32|#F580B1}})


{{Cl|PRINT}} "Loading...";
{{Cl|PRINT}} {{Text|<nowiki>"Loading..."</nowiki>|#FFB100}};
{{Cl|DIM}} Song {{Cl|AS}} {{Cl|LONG}}
{{Cl|DIM}} Song {{Cl|AS}} {{Cl|LONG}}
Song = {{Cl|_SNDOPEN}}("OPL3 Groove.rad") ' Replace this with your (rad, mid, it, xm, s3m, mod, mp3, flac, ogg, wav) sound file
Song = {{Cl|_SNDOPEN}}({{Cl|_OPENFILEDIALOG$}}({{Text|<nowiki>"Open audio file"</nowiki>|#FFB100}}, , FILE_FILTER))
{{Cl|IF}} Song < 1 {{Cl|THEN}}
{{Cl|IF}} Song < {{Text|1|#F580B1}} {{Cl|THEN}}
     {{Cl|PRINT}} "Failed to load song!"
     {{Cl|PRINT}} {{Text|<nowiki>"Failed to load sound!"</nowiki>|#FFB100}}
     {{Cl|END}}
     {{Cl|END}}
{{Cl|END}} {{Cl|IF}}
{{Cl|END IF}}
{{Cl|PRINT}} "Done!"
{{Cl|PRINT}} {{Text|<nowiki>"Done!"</nowiki>|#FFB100}}


{{Cl|_SNDPLAY}} Song
{{Cl|_SNDPLAY}} Song


{{Cl|DIM}} SampleData {{Cl|AS}} {{Cl|_MEM}}
{{Cl|DIM}} soundData {{Cl|AS}} {{Cl|_MEM}}: soundData = {{Cl|_MEMSOUND}}(Song, {{Text|0|#F580B1}})
SampleData = {{Cl|_MEMSOUND}}(Song, 0) ' This can now be 0 or 1
 
{{Cl|IF}} SampleData.SIZE = 0 {{Cl|THEN}}
{{Cl|IF}} soundData.SIZE = {{Text|0|#F580B1}} {{Cl|THEN}}
     {{Cl|PRINT}} "Failed to access sound sample data."
     {{Cl|PRINT}} {{Text|<nowiki>"Failed to access sound sample data."</nowiki>|#FFB100}}
     {{Cl|END}}
     {{Cl|END}}
{{Cl|END}} {{Cl|IF}}
{{Cl|END IF}}
 
{{Cl|DIM}} sz {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_INTEGER64}}: sz = {{Text|CLngPtr|#55FF55}}(soundData.ELEMENTSIZE)
{{Cl|DIM}} x {{Cl|AS}} {{Cl|LONG}}, i {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_INTEGER64}}


{{Cl|DIM}} x {{Cl|AS}} {{Cl|LONG}}, i {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_INTEGER64}}, sf {{Cl|AS}} {{Cl|SINGLE}}, si {{Cl|AS}} {{Cl|INTEGER}}
{{Cl|DO...LOOP|DO UNTIL}} {{Cl|_KEYHIT}} = {{Text|27|#F580B1}} {{Cl|OR (boolean)|OR}} {{Cl|NOT}} {{Cl|_SNDPLAYING}}(Song) {{Cl|OR (boolean)|OR}} i + ({{Cl|_WIDTH (function)|_WIDTH}} * sz) > soundData.SIZE
{{Cl|DIM}} sz {{Cl|AS}} {{Cl|_UNSIGNED}} {{Cl|_INTEGER64}}
    {{Cl|CLS}}
    {{Cl|LOCATE}} {{Text|1|#F580B1}}, {{Text|1|#F580B1}}: {{Cl|PRINT}} i; {{Text|<nowiki>"/"</nowiki>|#FFB100}}; soundData.SIZE, {{Text|<nowiki>"Frame Size ="</nowiki>|#FFB100}}; sz, {{Text|<nowiki>"Data Type ="</nowiki>|#FFB100}}; soundData.TYPE


sz = {{Cl|_CV}}({{Cl|_UNSIGNED}} {{Cl|_INTEGER64}}, {{Cl|_MK$}}({{Cl|_OFFSET}}, SampleData.ELEMENTSIZE)) ' sz is the total size of the sound in bytes
    {{Text|<nowiki>' See https://qb64phoenix.com/qb64wiki/index.php/MEM for details</nowiki>|#919191}}
    {{Cl|SELECT CASE}} soundData.TYPE
        {{Cl|CASE}} {{Text|130|#F580B1}} {{Text|<nowiki>' integer stereo or mono</nowiki>|#919191}}
            {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} {{Cl|_WIDTH (function)|_WIDTH}} - {{Text|1|#F580B1}}
                {{Cl|DIM}} si {{Cl|AS}} {{Cl|INTEGER}}: si = {{Cl|_MEMGET (function)|_MEMGET}}(soundData, soundData.OFFSET + i + x * sz, {{Cl|INTEGER}}) {{Text|<nowiki>' get sound data</nowiki>|#919191}}
                {{Cl|LINE}} (x, {{Cl|_HEIGHT}} \ {{Text|2|#F580B1}})-{{Cl|STEP}}({{Text|0|#F580B1}}, {{Text|300!|#F580B1}} * si / {{Text|32768!|#F580B1}}), {{Cl|_RGB32}}({{Text|0|#F580B1}}, {{Text|111|#F580B1}}, {{Text|0|#F580B1}}) {{Text|<nowiki>'plot wave</nowiki>|#919191}}
            {{Cl|NEXT}}


{{Cl|DO}} {{Cl|UNTIL}} {{Cl|_KEYHIT}} = 27 {{Cl|OR}} {{Cl|NOT}} {{Cl|_SNDPLAYING}}(Song) {{Cl|OR}} i + ({{Cl|_WIDTH}} * sz) > SampleData.SIZE
        {{Cl|CASE}} {{Text|132|#F580B1}} {{Text|<nowiki>' long stereo or mono</nowiki>|#919191}}
    {{Cl|CLS}}
            {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} {{Cl|_WIDTH (function)|_WIDTH}} - {{Text|1|#F580B1}}
    {{Cl|LOCATE}} 1, 1: {{Cl|PRINT}} i; "/"; SampleData.SIZE, "Frame Size ="; sz, "Data Type ="; SampleData.TYPE
                {{Cl|DIM}} sl {{Cl|AS}} {{Cl|LONG}}: sl = {{Cl|_MEMGET (function)|_MEMGET}}(soundData, soundData.OFFSET + i + x * sz, {{Cl|LONG}}) {{Text|<nowiki>' get sound data</nowiki>|#919191}}
                {{Cl|LINE}} (x, {{Cl|_HEIGHT}} \ {{Text|2|#F580B1}})-{{Cl|STEP}}({{Text|0|#F580B1}}, {{Text|300!|#F580B1}} * sl / {{Text|2147483648!|#F580B1}}), {{Cl|_RGB32}}({{Text|0|#F580B1}}, {{Text|111|#F580B1}}, {{Text|0|#F580B1}}) {{Text|<nowiki>'plot wave</nowiki>|#919191}}
            {{Cl|NEXT}}
 
        {{Cl|CASE}} {{Text|260|#F580B1}} {{Text|<nowiki>' floating point stereo or mono</nowiki>|#919191}}
            {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} {{Cl|_WIDTH (function)|_WIDTH}} - {{Text|1|#F580B1}}
                {{Cl|DIM}} sf {{Cl|AS}} {{Cl|SINGLE}}: sf = {{Cl|_MEMGET (function)|_MEMGET}}(soundData, soundData.OFFSET + i + x * sz, {{Cl|SINGLE}}) {{Text|<nowiki>' get sound data</nowiki>|#919191}}
                {{Cl|LINE}} (x, {{Cl|_HEIGHT}} \ {{Text|2|#F580B1}})-{{Cl|STEP}}({{Text|0|#F580B1}}, sf * {{Text|300!|#F580B1}}), {{Cl|_RGB32}}({{Text|0|#F580B1}}, {{Text|111|#F580B1}}, {{Text|0|#F580B1}}) {{Text|<nowiki>'plot wave</nowiki>|#919191}}
            {{Cl|NEXT}}


    {{Cl|$CHECKING}}:OFF
        {{Cl|CASE}} {{Text|1153|#F580B1}} {{Text|<nowiki>' unsigned byte stereo or mono</nowiki>|#919191}}
    {{Cl|IF}} SampleData.TYPE = 130 {{Cl|THEN}} ' integer stereo or mono
             {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} {{Cl|_WIDTH (function)|_WIDTH}} - {{Text|1|#F580B1}}
        {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
                {{Cl|DIM}} sb {{Cl|AS}} {{Cl|_BYTE}}: sb = {{Cl|_MEMGET (function)|_MEMGET}}(soundData, soundData.OFFSET + i + x * sz, {{Cl|_UNSIGNED}} {{Cl|_BYTE}}) {{Cl|XOR}} {{Text|&H80|#F580B1}} {{Text|<nowiki>' get sound data and convert to signed</nowiki>|#919191}}
             si = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|INTEGER}}) 'get sound data
                {{Cl|LINE}} (x, {{Cl|_HEIGHT}} \ {{Text|2|#F580B1}})-{{Cl|STEP}}({{Text|0|#F580B1}}, {{Text|300!|#F580B1}} * sb / {{Text|128!|#F580B1}}), {{Cl|_RGB32}}({{Text|0|#F580B1}}, {{Text|111|#F580B1}}, {{Text|0|#F580B1}}) {{Text|<nowiki>' plot wave</nowiki>|#919191}}
            {{Cl|LINE}} (x, {{Cl|_HEIGHT}} / 2)-{{Cl|STEP}}(0, 300 * si / 32768), {{Cl|_RGB32}}(0, 111, 0) 'plot wave
            {{Cl|NEXT}}
        {{Cl|NEXT}}
     {{Cl|END SELECT}}
    {{Cl|ELSEIF}} SampleData.TYPE = 260 {{Cl|THEN}} ' floating point stereo or mono
        {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
            sf = {{Cl|_MEMGET}}(SampleData, SampleData.OFFSET + i + x * sz, {{Cl|SINGLE}}) 'get sound data
            {{Cl|LINE}} (x, {{Cl|_HEIGHT}} / 2)-{{Cl|STEP}}(0, sf * 300), {{Cl|_RGB32}}(0, 111, 0) 'plot wave
        {{Cl|NEXT}}
    {{Cl|ELSEIF}} sz = 2 {{Cl|AND}} SampleData.TYPE = 0 {{Cl|THEN}} ' integer mono (QB64 OpenAL stuff)
        {{Cl|FOR}} x = 0 {{Cl|TO}} {{Cl|_WIDTH}} - 1
            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|NEXT}}
    {{Cl|END}} {{Cl|IF}}
     {{Cl|$CHECKING}}:ON


     {{Cl|_DISPLAY}}
     {{Cl|_DISPLAY}}
    {{Cl|_LIMIT}} 60


     i = {{Cl|FIX}}({{Cl|_SNDGETPOS}}(Song) * {{Cl|_SNDRATE}}) * sz ' Calculate the new sample frame position
    {{Cl|_LIMIT}} {{Text|60|#F580B1}}
 
     i = {{Cl|FIX}}({{Cl|_SNDGETPOS}}(Song) * {{Cl|_SNDRATE}}) * sz {{Text|<nowiki>' calculate the new sample frame position</nowiki>|#919191}}
{{Cl|LOOP}}
{{Cl|LOOP}}


{{Cl|_SNDCLOSE}} Song 'closing the sound releases the mem blocks
{{Cl|_SNDCLOSE}} Song
{{Cl|_AUTODISPLAY}}
{{Cl|_AUTODISPLAY}}
{{Cl|END}}
{{Cl|END}}

Latest revision as of 14:57, 21 November 2024

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 or _SNDNEW 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& is optional and deprecated. This was used to specify the sound channel. In QB64-PE v3.1.0 and above stereo data is always interleaved. You must use .ELEMENTSIZE and .TYPE to determine the type of audio data you are dealing with.


Description

  • Use this function to obtain a pointer to the raw sound data in memory for direct access.
  • Even if the memory pointer obtained by this fuction was already freed again using _MEMFREE, the respective Sound handle itself 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 or the format simply does not support accessing raw PCM samples.
  • channel& - 1 (left channel/mono) or 2 (right channel; for stereo files) was supported on the old OpenAL backend. For the new miniaudio backend, this must be 0.
  • _MEMSOUND does not work for sounds loaded with _SNDOPEN when using the STREAM or NODECODE flags.


Availability


Examples

Example 1
Checking that a sound file is stereo.
OPTION _EXPLICIT

CONST FILE_FILTER = "*.wav|*.aiff|*.aifc|*.flac|*.ogg|*.mp3|*.it|*.xm|*.s3m|*.mod|*.rad|*.ahx|*.hvl|*.mus|*.hmi|*.hmp|*.hmq|*.kar|*.lds|*.mds|*.mids|*.rcp|*.r36|*.g18|*.g36|*.rmi|*.mid|*.midi|*.xfm|*.xmi|*.qoa"

PRINT "Loading...";
DIM Song AS LONG
Song = _SNDOPEN(_OPENFILEDIALOG$("Open audio file", , FILE_FILTER))
IF Song < 1 THEN
    PRINT "Failed to load sound!"
    END
END IF
PRINT "Done!"

DIM channels AS _UNSIGNED _BYTE: channels = SndChannels(Song)

IF channels THEN
    PRINT "This sound data has"; channels; "channels."
ELSE
    PRINT "An error occurred."
END IF

_SNDCLOSE Song

END

' This function returns the number of sound channels for a valid sound handle
FUNCTION SndChannels~%% (handle AS LONG)
    DECLARE LIBRARY
        ' This is needed to convert _OFFSET to LONG / _INTEGER64
        $IF 32BIT THEN
            FUNCTION SndChannels.CLngPtr~& ALIAS "uintptr_t" (BYVAL o AS _UNSIGNED _OFFSET)
        $ELSE
            FUNCTION SndChannels.CLngPtr~&& ALIAS "uintptr_t" (BYVAL o AS _UNSIGNED _OFFSET)
        $END IF 
    END DECLARE

    DIM soundData AS _MEM: soundData = _MEMSOUND(handle)

    IF soundData.SIZE THEN
        ' See https://qb64phoenix.com/qb64wiki/index.php/MEM for details
        SELECT CASE soundData.TYPE
            CASE 260 ' 32-bit floating point
                SndChannels = SndChannels.CLngPtr(soundData.ELEMENTSIZE) \ _SIZE_OF_SINGLE

            CASE 132 ' 32-bit signed integer
                SndChannels = SndChannels.CLngPtr(soundData.ELEMENTSIZE) \ _SIZE_OF_LONG

            CASE 130 ' 16-bit signed integer
                SndChannels = SndChannels.CLngPtr(soundData.ELEMENTSIZE) \ _SIZE_OF_INTEGER

            CASE 1153 ' 8-bit unsigned integer
                SndChannels = SndChannels.CLngPtr(soundData.ELEMENTSIZE) \ _SIZE_OF_BYTE

            CASE ELSE ' unknown format
                SndChannels = 1
        END SELECT
    END IF

    IF soundData.SOUND = handle THEN _MEMFREE soundData
END FUNCTION

Example 2
Plotting a sound's waves.
OPTION _EXPLICIT

CONST FILE_FILTER = "*.wav|*.aiff|*.aifc|*.flac|*.ogg|*.mp3|*.it|*.xm|*.s3m|*.mod|*.rad|*.ahx|*.hvl|*.mus|*.hmi|*.hmp|*.hmq|*.kar|*.lds|*.mds|*.mids|*.rcp|*.r36|*.g18|*.g36|*.rmi|*.mid|*.midi|*.xfm|*.xmi|*.qoa"

DECLARE LIBRARY
    ' This is needed to convert _OFFSET to LONG / _INTEGER64
    $IF 32BIT THEN
        FUNCTION CLngPtr~& ALIAS "uintptr_t" (BYVAL o AS _UNSIGNED _OFFSET)
    $ELSE
        FUNCTION CLngPtr~&& ALIAS "uintptr_t" (BYVAL o AS _UNSIGNED _OFFSET)
    $END IF 
END DECLARE

SCREEN _NEWIMAGE(800, 327, 32)

PRINT "Loading...";
DIM Song AS LONG
Song = _SNDOPEN(_OPENFILEDIALOG$("Open audio file", , FILE_FILTER))
IF Song < 1 THEN
    PRINT "Failed to load sound!"
    END
END IF
PRINT "Done!"

_SNDPLAY Song

DIM soundData AS _MEM: soundData = _MEMSOUND(Song, 0)

IF soundData.SIZE = 0 THEN
    PRINT "Failed to access sound sample data."
    END
END IF

DIM sz AS _UNSIGNED _INTEGER64: sz = CLngPtr(soundData.ELEMENTSIZE)
DIM x AS LONG, i AS _UNSIGNED _INTEGER64

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

    ' See https://qb64phoenix.com/qb64wiki/index.php/MEM for details
    SELECT CASE soundData.TYPE
        CASE 130 ' integer stereo or mono
            FOR x = 0 TO _WIDTH - 1
                DIM si AS INTEGER: si = _MEMGET(soundData, soundData.OFFSET + i + x * sz, INTEGER) ' get sound data
                LINE (x, _HEIGHT \ 2)-STEP(0, 300! * si / 32768!), _RGB32(0, 111, 0) 'plot wave
            NEXT

        CASE 132 ' long stereo or mono
            FOR x = 0 TO _WIDTH - 1
                DIM sl AS LONG: sl = _MEMGET(soundData, soundData.OFFSET + i + x * sz, LONG) ' get sound data
                LINE (x, _HEIGHT \ 2)-STEP(0, 300! * sl / 2147483648!), _RGB32(0, 111, 0) 'plot wave
            NEXT

        CASE 260 ' floating point stereo or mono
            FOR x = 0 TO _WIDTH - 1
                DIM sf AS SINGLE: sf = _MEMGET(soundData, soundData.OFFSET + i + x * sz, SINGLE) ' get sound data
                LINE (x, _HEIGHT \ 2)-STEP(0, sf * 300!), _RGB32(0, 111, 0) 'plot wave
            NEXT

        CASE 1153 ' unsigned byte stereo or mono
            FOR x = 0 TO _WIDTH - 1
                DIM sb AS _BYTE: sb = _MEMGET(soundData, soundData.OFFSET + i + x * sz, _UNSIGNED _BYTE) XOR &H80 ' get sound data and convert to signed
                LINE (x, _HEIGHT \ 2)-STEP(0, 300! * sb / 128!), _RGB32(0, 111, 0) ' plot wave
            NEXT
    END SELECT

    _DISPLAY

    _LIMIT 60

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

_SNDCLOSE Song
_AUTODISPLAY
END


See also



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