QB64 Phoenix Edition
neat _SndRaw example, but how do you stop _SndRaw from playing? - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Help Me! (https://qb64phoenix.com/forum/forumdisplay.php?fid=10)
+---- Thread: neat _SndRaw example, but how do you stop _SndRaw from playing? (/showthread.php?tid=774)

Pages: 1 2


neat _SndRaw example, but how do you stop _SndRaw from playing? - madscijr - 08-16-2022

I was searching through various QB64 examples I had saved,
looking for examples of _SndRaw, and found this interesting one by angros47
(are they still around?) from way back in 2013 (when QB64 was at qb64.net!)

The first sound starts off okay but almost immediately becomes noise,
and I'm not sure why or how to turn it off.

The second sound is really really cool sounding, like sci fi sounds done on the early Moog synths.
I let it play for a while and it eventually starts sounding like noise, and again, I don't know how to turn it off.

Any input would be appreciated!

Code: (Select All)
' FM (Frequency modulation) sound with _SNDRAW
' http://www.qb64.net/forum/index.php?topic=11395.0

Const FALSE = 0
Const TRUE = Not FALSE

'FM_Sound_Test1
FM_Sound_Test2

End

' /////////////////////////////////////////////////////////////////////////////
' Plays 2 sounds based on angros47's parameters:
'
' 1. sounds okay for about a second, then just plays harsh noise without
'    stopping -  how do you turn it off without killing the program?
'
' 2. sounds pretty cool! But it goes on forever, does it ever stop?
'    (how do you stop _SNDRAW sounds once they start playing?)

Sub FM_Sound_Test2
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Input "Press ENTER to play sound #1, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 500
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0
            sngCarrierDecay = 0.1
            sngCarrierSustain = 0.01
            sngCarrierRelease = 0.5
            iModulatorFrequency = 500
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 30
            sngSoundAttack = 0
            sngSoundDecay = 0.1
            sngSoundSustain = 0.5
            sngSoundRelease = 0.6

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If

        Input "Press ENTER to play sound #2, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 3000
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0.5
            sngCarrierDecay = 0.2
            sngCarrierSustain = 1
            sngCarrierRelease = 0.1
            iModulatorFrequency = 10
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 1000
            sngSoundAttack = 0.6
            sngSoundDecay = 0.2
            sngSoundSustain = 0.7
            sngSoundRelease = 0.2

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If
    Loop
End Sub ' FM_Sound_Test2

' /////////////////////////////////////////////////////////////////////////////
' This version prompts for parameters.
' TODO: simple mouse or keyboard interface for realtime input?

Sub FM_Sound_Test1
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Print "--- Sound ---"
        Input "Frequency"; iSoundFrequency
        Input "Duration"; iSoundDuration
        Input "Maximum Volume"; iSoundMaxVolume

        Print "--- Carrier ---"
        Input "Attack"; sngCarrierAttack
        Input "Decay"; sngCarrierDecay
        Input "Sustain"; sngCarrierSustain
        Input "Release"; sngCarrierRelease

        Print "--- Modulator ---"
        Input "Frequency"; iModulatorFrequency
        Input "Phase"; sngModulatorPhase
        Input "Maximum level"; iModulatorMaxLevel

        Print "--- ADSR ---"
        Input "Attack"; sngSoundAttack
        Input "Decay"; sngSoundDecay
        Input "Sustain"; sngSoundSustain
        Input "Release"; sngSoundRelease

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
       
        Input "Type 'q' to quit or any key to continue"; in$
        If in$ = "q" Then Exit Do
    Loop
End Sub ' FM_Sound_Test1

' /////////////////////////////////////////////////////////////////////////////
' Version 2 of angros47's function, modified by madscijr:
' - more descriptive variable names,
' - user can press ESC to quit.

' TODO: if user presses ESC, stop playing the sound. How??

Sub FM_Sound( _
    iSoundFrequency as integer, _
    iSoundDuration as integer, _
    iSoundMaxVolume as integer, _
    sngCarrierAttack as single, _
    sngCarrierDecay as single, _
    sngCarrierSustain as single, _
    sngCarrierRelease as single, _
    iModulatorFrequency as integer, _
    sngModulatorPhase as single, _
    iModulatorMaxLevel as integer, _
    sngSoundAttack as single, _
    sngSoundDecay as single, _
    sngSoundSustain as single, _
    sngSoundRelease as single)
   
    Dim nSamples As Long
    Dim CS As Single
    Dim MS As Single
    Dim CEnvelopeInc As Double
    Dim CEnvelopeDecD As Double
    Dim CEnvelopeDecR As Double
    Dim MEnvelopeInc As Double
    Dim MEnvelopeDecD As Double
    Dim MEnvelopeDecR As Double
    Dim iLoop As Integer


    nSamples = _SndRate * Int(iSoundDuration / 18.2) ' seconds

    CS = 1 - sngCarrierAttack - sngCarrierDecay - sngCarrierRelease
    MS = 1 - sngSoundAttack - sngSoundDecay - sngSoundRelease

    CEnvelopeInc = 100 * iSoundMaxVolume / (nSamples * sngCarrierAttack + 1)
    CEnvelopeDecD = 100 * iSoundMaxVolume * (1 - sngCarrierSustain) / (nSamples * sngCarrierDecay + 1)
    CEnvelopeDecR = 100 * iSoundMaxVolume * sngCarrierSustain / (nSamples * sngCarrierRelease + 1)

    sngCarrierDecay = sngCarrierDecay + sngCarrierAttack
    CS = CS + sngCarrierDecay
    sngCarrierRelease = sngCarrierRelease + CS

    MEnvelopeInc = iModulatorMaxLevel / (nSamples * sngSoundAttack + 1)
    MEnvelopeDecD = iModulatorMaxLevel * (1 - sngSoundSustain) / (nSamples * sngSoundDecay + 1)
    MEnvelopeDecR = iModulatorMaxLevel * sngSoundSustain / (nSamples * sngSoundRelease + 1)

    sngSoundDecay = sngSoundDecay + sngSoundAttack
    MS = MS + sngSoundDecay
    sngSoundRelease = sngSoundRelease + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For iLoop = 0 To nSamples

        If iLoop <= sngCarrierAttack * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf iLoop < sngCarrierDecay * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf iLoop < CS * nSamples Then
        ElseIf iLoop < sngCarrierRelease * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If iLoop <= sngSoundAttack * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf iLoop < sngSoundDecay * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf iLoop < MS * nSamples Then
        ElseIf iLoop < sngSoundRelease * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * iLoop * iModulatorFrequency + sngModulatorPhase) * Mamp
        Waveform = Sin(Pi2 / _SndRate * iLoop * iSoundFrequency + Modulator) * Volume

        _SndRaw Amplitude * Waveform

        If InKey$ = Chr$(27) Then Exit For ' GIVE THE USER A WAY TO EXIT
    Next iLoop

    Do
        If InKey$ = Chr$(27) Then Exit Do ' GIVE THE USER A WAY TO EXIT
    Loop While _SndRawLen

End Sub ' FM_Sound

' /////////////////////////////////////////////////////////////////////////////
' Original version of the code by angros47

' -----------------------------------------------------------------------------
' angros47
' « on: September 15, 2013, 12:19:04 pm »
' http://www.qb64.net/forum/index.php?topic=11395.0
'
' Years ago, I made a program to generate sound effects in FreeBasic...
' just for fun, I tried to port it to QB64, too (the _SNDRAW helped, of course).
' Have fun!
' -----------------------------------------------------------------------------
' LeChuck
' « Reply #1 on: September 15, 2013, 02:27:54 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97452#msg97452
'
' Hey angros47,
' Can you add some demo values as well because I can't seem to generate any
' sound.
' Thanks
' No disaster occurs for any single reason.
' -----------------------------------------------------------------------------
' angros47
' « Reply #2 on: September 16, 2013, 08:03:22 am »
' http://www.qb64.net/forum/index.php?topic=11395.msg97464#msg97464
'
' Frequency 500
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0
' Decay 0.1
' Sustain 0.01
' Release 0.5
'
' Modulator
' Frequency 500
' Phase 0.5
' Maximum level 30
'
' Attack 0
' Decay 0.1
' Sustain 0.5
' Release 0.6
'
' Or
'
' Frequency 3000
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0.5
' Decay 0.2
' Sustain 1
' Release 0.1
'
' Modulator
' Frequency 10
' Phase 0.5
' Maximum level 1000
'
' Attack 0.6
' Decay 0.2
' Sustain 0.7
' Release 0.2
' -----------------------------------------------------------------------------
' OlDosLover
' « Reply #3 on: September 16, 2013, 06:54:06 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97469#msg97469
'
' Hi all,
' Wow! Very impressive. I think this might be QB64's first sound generator.
' Thank you for sharing this valuable tool.
' OlDosLover.
' -----------------------------------------------------------------------------

Sub FM_Sound_v1
    Input "Frequency"; Frequency
    Input "Duration"; Duration
    Input "Maximum Volume"; MaxVol
    Print "--- Carrier ---"
    Input "Attack"; ca
    Input "Decay"; cd
    Input "Sustain"; csl
    Input "Release"; cr

    Print "--- Modulator ---"
    Input "Frequency"; MFrequency
    Input "Phase"; ModStart
    Input "Maximum level"; MaxModulator

    Input "Attack"; Ma
    Input "Decay"; md
    Input "Sustain"; msl
    Input "Release"; mr

    Dim nSamples As Long

    Dim CS As Single, MS As Single

    nSamples = _SndRate * Int(Duration / 18.2) ' seconds

    CS = 1 - ca - cd - cr
    MS = 1 - Ma - md - mr

    Dim CEnvelopeInc As Double, CEnvelopeDecD As Double, CEnvelopeDecR As Double
    CEnvelopeInc = 100 * MaxVol / (nSamples * ca + 1)
    CEnvelopeDecD = 100 * MaxVol * (1 - csl) / (nSamples * cd + 1)
    CEnvelopeDecR = 100 * MaxVol * csl / (nSamples * cr + 1)

    cd = cd + ca
    CS = CS + cd
    cr = cr + CS

    Dim MEnvelopeInc As Double, MEnvelopeDecD As Double, MEnvelopeDecR As Double
    MEnvelopeInc = MaxModulator / (nSamples * Ma + 1)
    MEnvelopeDecD = MaxModulator * (1 - msl) / (nSamples * md + 1)
    MEnvelopeDecR = MaxModulator * msl / (nSamples * mr + 1)

    md = md + Ma
    MS = MS + md
    mr = mr + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For i = 0 To nSamples

        If i <= ca * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf i < cd * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf i < CS * nSamples Then
        ElseIf i < cr * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If i <= Ma * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf i < md * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf i < MS * nSamples Then
        ElseIf i < mr * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * i * MFrequency + ModStart) * Mamp
        Waveform = Sin(Pi2 / _SndRate * i * Frequency + Modulator) * Volume

        _SndRaw Amplitude * Waveform
    Next
    Do: Loop While _SndRawLen
End Sub ' FM_Sound_v1



RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - mnrvovrfc - 08-17-2022

https://qb64phoenix.com/forum/showthread.php?tid=757
If you checked out my code from that thread, you would know how to fix this already. :tu:

You need to check the value of "_SNDRAWLEN" so it doesn't exceed three seconds or some other short period of time to your liking. Do not generate any more sound until the threshold of the sound buffer falls below the expectation. Then when sound generation is finished, it would be a good idea to keep checking the value of "_SNDRAWLEN" until it hits zero and, in the meantime, fade out the sound.


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - madscijr - 08-17-2022

(08-17-2022, 09:48 AM)mnrvovrfc Wrote: https://qb64phoenix.com/forum/showthread.php?tid=757
If you checked out my code from that thread, you would know how to fix this already. :tu:

You need to check the value of "_SNDRAWLEN" so it doesn't exceed three seconds or some other short period of time to your liking. Do not generate any more sound until the threshold of the sound buffer falls below the expectation. Then when sound generation is finished, it would be a good idea to keep checking the value of "_SNDRAWLEN" until it hits zero and, in the meantime, fade out the sound.

Hey, thanks, mnrvovrfc! I did try out your granular synth code, but haven't yet fully digested how it works.

BTW, how should one pronounce "mnrvovrfc" out loud?  Tongue

UPDATE: I tried checking the _SNDRAWLEN like you do in your Granular Synth example (code below). 

After adding the DO loop at the end (lines 79-81, 120-122), the sounds now end right away, when the user presses ESC to stop playing. 

However, checking that _SNDRAWLEN doesn't go over 3 seconds (lines 258-261) doesn't seem to be stopping sound #1 from degenerating into harsh noise. 

Any ideas? 

Thanks again! 

Code: (Select All)
' FM (Frequency modulation) sound with _SNDRAW
' http://www.qb64.net/forum/index.php?topic=11395.0

Const FALSE = 0
Const TRUE = Not FALSE

'FM_Sound_Test1
FM_Sound_Test2

End

' /////////////////////////////////////////////////////////////////////////////
' Plays 2 sounds based on angros47's parameters:
'
' 1. sounds okay for about a second, then just plays harsh noise without
'    stopping -  how do you turn it off without killing the program?
'
' 2. sounds pretty cool! But it goes on forever, does it ever stop?
'    (how do you stop _SNDRAW sounds once they start playing?)

' TODO: check the value of _SNDRAWLEN and make sure it doesn't exceed
'       3 seconds, and don't add any more sounds until the value
'       falls below that threshold.

Sub FM_Sound_Test2
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Input "Press ENTER to play sound #1, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 500
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0
            sngCarrierDecay = 0.1
            sngCarrierSustain = 0.01
            sngCarrierRelease = 0.5
            iModulatorFrequency = 500
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 30
            sngSoundAttack = 0
            sngSoundDecay = 0.1
            sngSoundSustain = 0.5
            sngSoundRelease = 0.6

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If

        Do
            _Limit 3000
        Loop While _SndRawLen > 0


        Input "Press ENTER to play sound #2, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 3000
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0.5
            sngCarrierDecay = 0.2
            sngCarrierSustain = 1
            sngCarrierRelease = 0.1
            iModulatorFrequency = 10
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 1000
            sngSoundAttack = 0.6
            sngSoundDecay = 0.2
            sngSoundSustain = 0.7
            sngSoundRelease = 0.2

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If

        Do
            _Limit 3000
        Loop While _SndRawLen > 0

    Loop
End Sub ' FM_Sound_Test2

' /////////////////////////////////////////////////////////////////////////////
' This version prompts for parameters.
' TODO: simple mouse or keyboard interface for realtime input?

Sub FM_Sound_Test1
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Print "--- Sound ---"
        Input "Frequency"; iSoundFrequency
        Input "Duration"; iSoundDuration
        Input "Maximum Volume"; iSoundMaxVolume

        Print "--- Carrier ---"
        Input "Attack"; sngCarrierAttack
        Input "Decay"; sngCarrierDecay
        Input "Sustain"; sngCarrierSustain
        Input "Release"; sngCarrierRelease

        Print "--- Modulator ---"
        Input "Frequency"; iModulatorFrequency
        Input "Phase"; sngModulatorPhase
        Input "Maximum level"; iModulatorMaxLevel

        Print "--- ADSR ---"
        Input "Attack"; sngSoundAttack
        Input "Decay"; sngSoundDecay
        Input "Sustain"; sngSoundSustain
        Input "Release"; sngSoundRelease

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
       
        Input "Type 'q' to quit or any key to continue"; in$
        If in$ = "q" Then Exit Do
    Loop
End Sub ' FM_Sound_Test1

' /////////////////////////////////////////////////////////////////////////////
' Version 2 of angros47's function, modified by madscijr:
' - more descriptive variable names,
' - user can press ESC to quit.

' TODO: check the value of _SNDRAWLEN and make sure it doesn't exceed
'       3 seconds, and don't add any more sounds until the value
'       falls below that threshold.
'       https://github.com/QB64Official/qb64/wiki/_SNDRAWLEN

' TODO: if user presses ESC, stop playing the sound. How??

Sub FM_Sound( _
    iSoundFrequency as integer, _
    iSoundDuration as integer, _
    iSoundMaxVolume as integer, _
    sngCarrierAttack as single, _
    sngCarrierDecay as single, _
    sngCarrierSustain as single, _
    sngCarrierRelease as single, _
    iModulatorFrequency as integer, _
    sngModulatorPhase as single, _
    iModulatorMaxLevel as integer, _
    sngSoundAttack as single, _
    sngSoundDecay as single, _
    sngSoundSustain as single, _
    sngSoundRelease as single)
   
    Dim nSamples As Long
    Dim CS As Single
    Dim MS As Single
    Dim CEnvelopeInc As Double
    Dim CEnvelopeDecD As Double
    Dim CEnvelopeDecR As Double
    Dim MEnvelopeInc As Double
    Dim MEnvelopeDecD As Double
    Dim MEnvelopeDecR As Double
    Dim iLoop As Integer


    nSamples = _SndRate * Int(iSoundDuration / 18.2) ' seconds

    CS = 1 - sngCarrierAttack - sngCarrierDecay - sngCarrierRelease
    MS = 1 - sngSoundAttack - sngSoundDecay - sngSoundRelease

    CEnvelopeInc = 100 * iSoundMaxVolume / (nSamples * sngCarrierAttack + 1)
    CEnvelopeDecD = 100 * iSoundMaxVolume * (1 - sngCarrierSustain) / (nSamples * sngCarrierDecay + 1)
    CEnvelopeDecR = 100 * iSoundMaxVolume * sngCarrierSustain / (nSamples * sngCarrierRelease + 1)

    sngCarrierDecay = sngCarrierDecay + sngCarrierAttack
    CS = CS + sngCarrierDecay
    sngCarrierRelease = sngCarrierRelease + CS

    MEnvelopeInc = iModulatorMaxLevel / (nSamples * sngSoundAttack + 1)
    MEnvelopeDecD = iModulatorMaxLevel * (1 - sngSoundSustain) / (nSamples * sngSoundDecay + 1)
    MEnvelopeDecR = iModulatorMaxLevel * sngSoundSustain / (nSamples * sngSoundRelease + 1)

    sngSoundDecay = sngSoundDecay + sngSoundAttack
    MS = MS + sngSoundDecay
    sngSoundRelease = sngSoundRelease + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For iLoop = 0 To nSamples

        Do While _SndRawLen > 3.0
            _Limit 3000
            If _KeyDown(27) Then Exit Do
        Loop

        If iLoop <= sngCarrierAttack * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf iLoop < sngCarrierDecay * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf iLoop < CS * nSamples Then
        ElseIf iLoop < sngCarrierRelease * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If iLoop <= sngSoundAttack * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf iLoop < sngSoundDecay * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf iLoop < MS * nSamples Then
        ElseIf iLoop < sngSoundRelease * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * iLoop * iModulatorFrequency + sngModulatorPhase) * Mamp
        Waveform = Sin(Pi2 / _SndRate * iLoop * iSoundFrequency + Modulator) * Volume

        _SndRaw Amplitude * Waveform

        If InKey$ = Chr$(27) Then Exit For ' GIVE THE USER A WAY TO EXIT
    Next iLoop

    Do
        If InKey$ = Chr$(27) Then Exit Do ' GIVE THE USER A WAY TO EXIT
    Loop While _SndRawLen

End Sub ' FM_Sound

' /////////////////////////////////////////////////////////////////////////////
' Original version of the code by angros47

' -----------------------------------------------------------------------------
' angros47
' « on: September 15, 2013, 12:19:04 pm »
' http://www.qb64.net/forum/index.php?topic=11395.0
'
' Years ago, I made a program to generate sound effects in FreeBasic...
' just for fun, I tried to port it to QB64, too (the _SNDRAW helped, of course).
' Have fun!
' -----------------------------------------------------------------------------
' LeChuck
' « Reply #1 on: September 15, 2013, 02:27:54 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97452#msg97452
'
' Hey angros47,
' Can you add some demo values as well because I can't seem to generate any
' sound.
' Thanks
' No disaster occurs for any single reason.
' -----------------------------------------------------------------------------
' angros47
' « Reply #2 on: September 16, 2013, 08:03:22 am »
' http://www.qb64.net/forum/index.php?topic=11395.msg97464#msg97464
'
' Frequency 500
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0
' Decay 0.1
' Sustain 0.01
' Release 0.5
'
' Modulator
' Frequency 500
' Phase 0.5
' Maximum level 30
'
' Attack 0
' Decay 0.1
' Sustain 0.5
' Release 0.6
'
' Or
'
' Frequency 3000
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0.5
' Decay 0.2
' Sustain 1
' Release 0.1
'
' Modulator
' Frequency 10
' Phase 0.5
' Maximum level 1000
'
' Attack 0.6
' Decay 0.2
' Sustain 0.7
' Release 0.2
' -----------------------------------------------------------------------------
' OlDosLover
' « Reply #3 on: September 16, 2013, 06:54:06 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97469#msg97469
'
' Hi all,
' Wow! Very impressive. I think this might be QB64's first sound generator.
' Thank you for sharing this valuable tool.
' OlDosLover.
' -----------------------------------------------------------------------------

Sub FM_Sound_v1
    Input "Frequency"; Frequency
    Input "Duration"; Duration
    Input "Maximum Volume"; MaxVol
    Print "--- Carrier ---"
    Input "Attack"; ca
    Input "Decay"; cd
    Input "Sustain"; csl
    Input "Release"; cr

    Print "--- Modulator ---"
    Input "Frequency"; MFrequency
    Input "Phase"; ModStart
    Input "Maximum level"; MaxModulator

    Input "Attack"; Ma
    Input "Decay"; md
    Input "Sustain"; msl
    Input "Release"; mr

    Dim nSamples As Long

    Dim CS As Single, MS As Single

    nSamples = _SndRate * Int(Duration / 18.2) ' seconds

    CS = 1 - ca - cd - cr
    MS = 1 - Ma - md - mr

    Dim CEnvelopeInc As Double, CEnvelopeDecD As Double, CEnvelopeDecR As Double
    CEnvelopeInc = 100 * MaxVol / (nSamples * ca + 1)
    CEnvelopeDecD = 100 * MaxVol * (1 - csl) / (nSamples * cd + 1)
    CEnvelopeDecR = 100 * MaxVol * csl / (nSamples * cr + 1)

    cd = cd + ca
    CS = CS + cd
    cr = cr + CS

    Dim MEnvelopeInc As Double, MEnvelopeDecD As Double, MEnvelopeDecR As Double
    MEnvelopeInc = MaxModulator / (nSamples * Ma + 1)
    MEnvelopeDecD = MaxModulator * (1 - msl) / (nSamples * md + 1)
    MEnvelopeDecR = MaxModulator * msl / (nSamples * mr + 1)

    md = md + Ma
    MS = MS + md
    mr = mr + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For i = 0 To nSamples

        If i <= ca * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf i < cd * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf i < CS * nSamples Then
        ElseIf i < cr * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If i <= Ma * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf i < md * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf i < MS * nSamples Then
        ElseIf i < mr * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * i * MFrequency + ModStart) * Mamp
        Waveform = Sin(Pi2 / _SndRate * i * Frequency + Modulator) * Volume

        _SndRaw Amplitude * Waveform
    Next
    Do: Loop While _SndRawLen
End Sub ' FM_Sound_v1



RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - SMcNeill - 08-17-2022

(08-17-2022, 11:36 AM)madscijr Wrote: BTW, how should one pronounce "mnrvovrfc" out loud?  :P

Mobile Network Resource Visitation of Virtual Reality Finance Corporation...   it's where he used to work.  It's a finance company that sets up mobile vans with virtual reality headsets and goggles, then drives around to large businesses so the corporate bigwigs can come out to their van and do a virtual tour of various parcels of land and resources for sale and lease.

The nickname for mn was simply "V-van man".  Feel free to call him that.  ;)


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - madscijr - 08-17-2022

(08-17-2022, 01:04 PM)SMcNeill Wrote:
(08-17-2022, 11:36 AM)madscijr Wrote: BTW, how should one pronounce "mnrvovrfc" out loud?  Tongue

Mobile Network Resource Visitation of Virtual Reality Finance Corporation...   it's where he used to work.  It's a finance company that sets up mobile vans with virtual reality headsets and goggles, then drives around to large businesses so the corporate bigwigs can come out to their van and do a virtual tour of various parcels of land and resources for sale and lease.

The nickname for mn was simply "V-van man".  Feel free to call him that.  Wink

Wow, who knew? Sounds like an interesting gig! Thanks for explaining!


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - SMcNeill - 08-17-2022

(08-17-2022, 01:13 PM)madscijr Wrote:
(08-17-2022, 01:04 PM)SMcNeill Wrote:
(08-17-2022, 11:36 AM)madscijr Wrote: BTW, how should one pronounce "mnrvovrfc" out loud?  Tongue

Mobile Network Resource Visitation of Virtual Reality Finance Corporation...   it's where he used to work.  It's a finance company that sets up mobile vans with virtual reality headsets and goggles, then drives around to large businesses so the corporate bigwigs can come out to their van and do a virtual tour of various parcels of land and resources for sale and lease.

The nickname for mn was simply "V-van man".  Feel free to call him that.  Wink

Wow, who knew? Sounds like an interesting gig! Thanks for explaining!

It was a secret gig!  I don't even know if mnrvovrfc knew about it himself, or not.  I'm just special and those little voices whispering in my ears tells me these things.  Just like they told me the secret about how your father was a Mad Scientist, and you were Mad Scientist, Junior...


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - madscijr - 08-17-2022

(08-17-2022, 01:18 PM)SMcNeill Wrote:
(08-17-2022, 01:13 PM)madscijr Wrote:
(08-17-2022, 01:04 PM)SMcNeill Wrote: Mobile Network Resource Visitation of Virtual Reality Finance Corporation...   it's where he used to work.  It's a finance company that sets up mobile vans with virtual reality headsets and goggles, then drives around to large businesses so the corporate bigwigs can come out to their van and do a virtual tour of various parcels of land and resources for sale and lease.

The nickname for mn was simply "V-van man".  Feel free to call him that.  Wink

Wow, who knew? Sounds like an interesting gig! Thanks for explaining!

It was a secret gig!  I don't even know if mnrvovrfc knew about it himself, or not.  I'm just special and those little voices whispering in my ears tells me these things.  Just like they told me the secret about how your father was a Mad Scientist, and you were Mad Scientist, Junior...

You're a silly guy, McNeill! 
It's five o'clock somewhere  Big Grin


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - mnrvovrfc - 08-17-2022

Do you guys know anything about Greek/Roman mythology? Have you read "The Oddysey" English translation?

Kidding aside...

The sound has to be faded away after the user presses escape. If you decided to sound longer for three seconds before closing the program, then you have to figure out for three seconds how to make the sound silent. This means make the code just like the regular loop but, only for the length of time chosen (three seconds in this case), make a multiplication on the sample frame.

The following line could produce trouble:

_SndRaw Amplitude * Waveform

If that is computed to an absolute value greater than one, it's going to cause digital distortion. Check the code to make sure that value doesn't run out of control away from the range of -1.0 to 1.0.


RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - madscijr - 08-17-2022

(08-17-2022, 02:19 PM)mnrvovrfc Wrote: The following line could produce trouble:

_SndRaw Amplitude * Waveform

If that is computed to an absolute value greater than one, it's going to cause digital distortion. Check the code to make sure that value doesn't run out of control away from the range of -1.0 to 1.0.

Thanks for your reply. I tried your suggestion, replacing _SndRaw Amplitude * Waveform with 

Code: (Select All)
    Dim sngSoundRaw As Single
    ...
        sngSoundRaw = Amplitude * Waveform
        If sngSoundRaw < -1 Then
            sngSoundRaw = -1
        ElseIf sngSoundRaw > 1 Then
            sngSoundRaw = 1
        End If
        _SndRaw sngSoundRaw

(line 230, 284-290 in the below code) but it's still making that noise. 

How is it possible I can mess this up?  Huh

Code: (Select All)
' FM (Frequency modulation) sound with _SNDRAW
' http://www.qb64.net/forum/index.php?topic=11395.0

Const FALSE = 0
Const TRUE = Not FALSE

'FM_Sound_Test1
FM_Sound_Test2

End

' /////////////////////////////////////////////////////////////////////////////
' Plays 2 sounds based on angros47's parameters:
'
' 1. sounds okay for about a second, then just plays harsh noise without
'    stopping -  how do you turn it off without killing the program?
'
' 2. sounds pretty cool! But it goes on forever, does it ever stop?
'    (how do you stop _SNDRAW sounds once they start playing?)

' TODO: check the value of _SNDRAWLEN and make sure it doesn't exceed
'       3 seconds, and don't add any more sounds until the value
'       falls below that threshold.

Sub FM_Sound_Test2
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Input "Press ENTER to play sound #1, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 500
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0
            sngCarrierDecay = 0.1
            sngCarrierSustain = 0.01
            sngCarrierRelease = 0.5
            iModulatorFrequency = 500
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 30
            sngSoundAttack = 0
            sngSoundDecay = 0.1
            sngSoundSustain = 0.5
            sngSoundRelease = 0.6

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If

        Do
            _Limit 3000
        Loop While _SndRawLen > 0


        Input "Press ENTER to play sound #2, 's' to skip, or 'q' to quit"; in$
        If in$ = "q" Then Exit Do

        If in$ <> "s" Then
            iSoundFrequency = 3000
            iSoundDuration = 182
            iSoundMaxVolume = 256
            sngCarrierAttack = 0.5
            sngCarrierDecay = 0.2
            sngCarrierSustain = 1
            sngCarrierRelease = 0.1
            iModulatorFrequency = 10
            sngModulatorPhase = 0.5
            iModulatorMaxLevel = 1000
            sngSoundAttack = 0.6
            sngSoundDecay = 0.2
            sngSoundSustain = 0.7
            sngSoundRelease = 0.2

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
        End If

        Do
            _Limit 3000
        Loop While _SndRawLen > 0

    Loop
End Sub ' FM_Sound_Test2

' /////////////////////////////////////////////////////////////////////////////
' This version prompts for parameters.
' TODO: simple mouse or keyboard interface for realtime input?

Sub FM_Sound_Test1
    Dim iSoundFrequency As Integer
    Dim iSoundDuration As Integer
    Dim iSoundMaxVolume As Integer
    Dim sngCarrierAttack As Single
    Dim sngCarrierDecay As Single
    Dim sngCarrierSustain As Single
    Dim sngCarrierRelease As Single
    Dim iModulatorFrequency As Integer
    Dim sngModulatorPhase As Single
    Dim iModulatorMaxLevel As Integer
    Dim sngSoundAttack As Single
    Dim sngSoundDecay As Single
    Dim sngSoundSustain As Single
    Dim sngSoundRelease As Single
    Dim in$

    Do
        Print "--- Sound ---"
        Input "Frequency"; iSoundFrequency
        Input "Duration"; iSoundDuration
        Input "Maximum Volume"; iSoundMaxVolume

        Print "--- Carrier ---"
        Input "Attack"; sngCarrierAttack
        Input "Decay"; sngCarrierDecay
        Input "Sustain"; sngCarrierSustain
        Input "Release"; sngCarrierRelease

        Print "--- Modulator ---"
        Input "Frequency"; iModulatorFrequency
        Input "Phase"; sngModulatorPhase
        Input "Maximum level"; iModulatorMaxLevel

        Print "--- ADSR ---"
        Input "Attack"; sngSoundAttack
        Input "Decay"; sngSoundDecay
        Input "Sustain"; sngSoundSustain
        Input "Release"; sngSoundRelease

        FM_Sound _
            iSoundFrequency, _
            iSoundDuration, _
            iSoundMaxVolume, _
            sngCarrierAttack, _
            sngCarrierDecay, _
            sngCarrierSustain, _
            sngCarrierRelease, _
            iModulatorFrequency, _
            sngModulatorPhase, _
            iModulatorMaxLevel, _
            sngSoundAttack, _
            sngSoundDecay, _
            sngSoundSustain, _
            sngSoundRelease
       
        Input "Type 'q' to quit or any key to continue"; in$
        If in$ = "q" Then Exit Do
    Loop
End Sub ' FM_Sound_Test1

' /////////////////////////////////////////////////////////////////////////////
' Version 2 of angros47's function, modified by madscijr:
' - more descriptive variable names,
' - user can press ESC to quit.

' TODO: check the value of _SNDRAWLEN and make sure it doesn't exceed
'       3 seconds, and don't add any more sounds until the value
'       falls below that threshold.
'       https://github.com/QB64Official/qb64/wiki/_SNDRAWLEN

' TODO: if user presses ESC, stop playing the sound. How??

Sub FM_Sound( _
    iSoundFrequency as integer, _
    iSoundDuration as integer, _
    iSoundMaxVolume as integer, _
    sngCarrierAttack as single, _
    sngCarrierDecay as single, _
    sngCarrierSustain as single, _
    sngCarrierRelease as single, _
    iModulatorFrequency as integer, _
    sngModulatorPhase as single, _
    iModulatorMaxLevel as integer, _
    sngSoundAttack as single, _
    sngSoundDecay as single, _
    sngSoundSustain as single, _
    sngSoundRelease as single)
   
    Dim nSamples As Long
    Dim CS As Single
    Dim MS As Single
    Dim CEnvelopeInc As Double
    Dim CEnvelopeDecD As Double
    Dim CEnvelopeDecR As Double
    Dim MEnvelopeInc As Double
    Dim MEnvelopeDecD As Double
    Dim MEnvelopeDecR As Double
    Dim iLoop As Integer
    Dim sngSoundRaw As Single

    nSamples = _SndRate * Int(iSoundDuration / 18.2) ' seconds

    CS = 1 - sngCarrierAttack - sngCarrierDecay - sngCarrierRelease
    MS = 1 - sngSoundAttack - sngSoundDecay - sngSoundRelease

    CEnvelopeInc = 100 * iSoundMaxVolume / (nSamples * sngCarrierAttack + 1)
    CEnvelopeDecD = 100 * iSoundMaxVolume * (1 - sngCarrierSustain) / (nSamples * sngCarrierDecay + 1)
    CEnvelopeDecR = 100 * iSoundMaxVolume * sngCarrierSustain / (nSamples * sngCarrierRelease + 1)

    sngCarrierDecay = sngCarrierDecay + sngCarrierAttack
    CS = CS + sngCarrierDecay
    sngCarrierRelease = sngCarrierRelease + CS

    MEnvelopeInc = iModulatorMaxLevel / (nSamples * sngSoundAttack + 1)
    MEnvelopeDecD = iModulatorMaxLevel * (1 - sngSoundSustain) / (nSamples * sngSoundDecay + 1)
    MEnvelopeDecR = iModulatorMaxLevel * sngSoundSustain / (nSamples * sngSoundRelease + 1)

    sngSoundDecay = sngSoundDecay + sngSoundAttack
    MS = MS + sngSoundDecay
    sngSoundRelease = sngSoundRelease + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For iLoop = 0 To nSamples

        Do While _SndRawLen > 3.0
            _Limit 3000
            If _KeyDown(27) Then Exit Do
        Loop

        If iLoop <= sngCarrierAttack * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf iLoop < sngCarrierDecay * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf iLoop < CS * nSamples Then
        ElseIf iLoop < sngCarrierRelease * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If iLoop <= sngSoundAttack * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf iLoop < sngSoundDecay * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf iLoop < MS * nSamples Then
        ElseIf iLoop < sngSoundRelease * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * iLoop * iModulatorFrequency + sngModulatorPhase) * Mamp
        Waveform = Sin(Pi2 / _SndRate * iLoop * iSoundFrequency + Modulator) * Volume

        sngSoundRaw = Amplitude * Waveform
        If sngSoundRaw < -1 Then
            sngSoundRaw = -1
        ElseIf sngSoundRaw > 1 Then
            sngSoundRaw = 1
        End If
        _SndRaw sngSoundRaw

        If InKey$ = Chr$(27) Then Exit For ' GIVE THE USER A WAY TO EXIT
    Next iLoop

    Do
        If InKey$ = Chr$(27) Then Exit Do ' GIVE THE USER A WAY TO EXIT
    Loop While _SndRawLen

End Sub ' FM_Sound

' /////////////////////////////////////////////////////////////////////////////
' Original version of the code by angros47

' -----------------------------------------------------------------------------
' angros47
' « on: September 15, 2013, 12:19:04 pm »
' http://www.qb64.net/forum/index.php?topic=11395.0
'
' Years ago, I made a program to generate sound effects in FreeBasic...
' just for fun, I tried to port it to QB64, too (the _SNDRAW helped, of course).
' Have fun!
' -----------------------------------------------------------------------------
' LeChuck
' « Reply #1 on: September 15, 2013, 02:27:54 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97452#msg97452
'
' Hey angros47,
' Can you add some demo values as well because I can't seem to generate any
' sound.
' Thanks
' No disaster occurs for any single reason.
' -----------------------------------------------------------------------------
' angros47
' « Reply #2 on: September 16, 2013, 08:03:22 am »
' http://www.qb64.net/forum/index.php?topic=11395.msg97464#msg97464
'
' Frequency 500
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0
' Decay 0.1
' Sustain 0.01
' Release 0.5
'
' Modulator
' Frequency 500
' Phase 0.5
' Maximum level 30
'
' Attack 0
' Decay 0.1
' Sustain 0.5
' Release 0.6
'
' Or
'
' Frequency 3000
' Duration 182
' Maximum Volume 256
'
' Carrier
' Attack 0.5
' Decay 0.2
' Sustain 1
' Release 0.1
'
' Modulator
' Frequency 10
' Phase 0.5
' Maximum level 1000
'
' Attack 0.6
' Decay 0.2
' Sustain 0.7
' Release 0.2
' -----------------------------------------------------------------------------
' OlDosLover
' « Reply #3 on: September 16, 2013, 06:54:06 pm »
' http://www.qb64.net/forum/index.php?topic=11395.msg97469#msg97469
'
' Hi all,
' Wow! Very impressive. I think this might be QB64's first sound generator.
' Thank you for sharing this valuable tool.
' OlDosLover.
' -----------------------------------------------------------------------------

Sub FM_Sound_v1
    Input "Frequency"; Frequency
    Input "Duration"; Duration
    Input "Maximum Volume"; MaxVol
    Print "--- Carrier ---"
    Input "Attack"; ca
    Input "Decay"; cd
    Input "Sustain"; csl
    Input "Release"; cr

    Print "--- Modulator ---"
    Input "Frequency"; MFrequency
    Input "Phase"; ModStart
    Input "Maximum level"; MaxModulator

    Input "Attack"; Ma
    Input "Decay"; md
    Input "Sustain"; msl
    Input "Release"; mr

    Dim nSamples As Long

    Dim CS As Single, MS As Single

    nSamples = _SndRate * Int(Duration / 18.2) ' seconds

    CS = 1 - ca - cd - cr
    MS = 1 - Ma - md - mr

    Dim CEnvelopeInc As Double, CEnvelopeDecD As Double, CEnvelopeDecR As Double
    CEnvelopeInc = 100 * MaxVol / (nSamples * ca + 1)
    CEnvelopeDecD = 100 * MaxVol * (1 - csl) / (nSamples * cd + 1)
    CEnvelopeDecR = 100 * MaxVol * csl / (nSamples * cr + 1)

    cd = cd + ca
    CS = CS + cd
    cr = cr + CS

    Dim MEnvelopeInc As Double, MEnvelopeDecD As Double, MEnvelopeDecR As Double
    MEnvelopeInc = MaxModulator / (nSamples * Ma + 1)
    MEnvelopeDecD = MaxModulator * (1 - msl) / (nSamples * md + 1)
    MEnvelopeDecR = MaxModulator * msl / (nSamples * mr + 1)

    md = md + Ma
    MS = MS + md
    mr = mr + MS

    Pi2 = 8 * Atn(1) '2 * pi
    Amplitude = .000001

    For i = 0 To nSamples

        If i <= ca * nSamples Then
            Volume = Volume + CEnvelopeInc
        ElseIf i < cd * nSamples Then
            Volume = Volume - CEnvelopeDecD
        ElseIf i < CS * nSamples Then
        ElseIf i < cr * nSamples Then
            Volume = Volume - CEnvelopeDecR
        End If

        If i <= Ma * nSamples Then
            Mamp = Mamp + MEnvelopeInc
        ElseIf i < md * nSamples Then
            Mamp = Mamp - MEnvelopeDecD
        ElseIf i < MS * nSamples Then
        ElseIf i < mr * nSamples Then
            Mamp = Mamp - MEnvelopeDecR
        End If

        Modulator = Cos(Pi2 / _SndRate * i * MFrequency + ModStart) * Mamp
        Waveform = Sin(Pi2 / _SndRate * i * Frequency + Modulator) * Volume

        _SndRaw Amplitude * Waveform
    Next
    Do: Loop While _SndRawLen
End Sub ' FM_Sound_v1



RE: neat _SndRaw example, but how do you stop _SndRaw from playing? - mnrvovrfc - 08-17-2022

Setting "sngSoundRaw" variable to -1 or 1 just hard-clips the sound. You have to check the "Waveform" and "Amplitude" variables how they're being changed and find a way to reduce the absolute value of that multiplication. Try dividing "Amplitude" by 2 to see what happens.

"Hard-clip" is just rounding off a sound so that if the input sound is very very loud, it is transformed to be like silence, but it's annoying because when the audio was played back and then stopped, it causes a loud pop into headphones or speakers. It's not better cleaning DC offset. That's why sound engineers look to prevent it.

I took another look at the code. The problem with one of the functions is that "Modulator" is always going at full blast while "Waveform" has to experience some reduction. "Amplitude" is already being set very small, to one-over-million, so the culprit might be the modulation depth. Both "Modulator" and "Waveform" have to experience some sort of reduction.