Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
need help playing sound using certain parameters
#1
For the attempt at formant speech synthesis (see post #1, post #2), 
I need to play a sound (in some cases square wave in others noise (whether white/pink/brown noise is TBD) 
for a given duration (# of milliseconds) 
at a given amplitude (input range is 0-32767) 
where the sound starts at frequency1 
and the frequency changes as the sound plays
so that at the end of duration it is at frequency2 
(input range for frequency is 160-3951, but needs to be converted so it is in human hearing range). 

I based the code on the _SndRaw example in the wiki, 

maybe _SndRaw isn't what I want, but whatever command is used, 
the end goal is to play a sound given the following parameters 
  • frequency1 = start frequency
  • frequency2 = end frequency
  • amplitude
  • duration = milliseconds
  • inflection = TBD
  • vowel = TBD
  • pitch = (offset for frequency)
  • filter
  • volume = offset for amplitude
  • rate = how long sound plays (faster or slower should not affect frequency)
  • stress = TBD

Anyway, the code below is making sound, but it isn't really working the way I expect:
  • frequency isn't matching the values (it resets to low even if nextFreq is higher)
  • frequency isn't changing as the sound plays
  • what's really weird is the sound does not play if I disable the call to SngToStr$ (used to display the value of freqDiff in non-scientific notation)
  • volume isn't getting gradually lower each iteration even though the value of amplitude is decreasing by even amounts

If someone could look at this and figure out why the frequency and amplitude aren't working as expected, and why you don't hear anything without SngToStr$ that would be a much appreciated, because I'm stuck! 



Code: (Select All)
Const Pi = 4 * Atn(1)
Const Pi2 = 8 * Atn(1)

' SOUND PARAMTER VALUES
Dim frequency1 As Integer
Dim frequency2 As Integer
Dim amplitude As Integer
Dim duration As Integer
Dim inflection As Integer
Dim vowel As Integer
Dim pitch As Integer
Dim filter As Integer
Dim volume As Integer
Dim rate As Integer
Dim stress As Integer

' CONVERT INPUT VALUES TO VALUES THAT CAN BE PLAYED
Dim amplitude1 As Single
Dim freqDiff As Single ' how much to increase frequency to get to frequency2 by duration
Dim nextFreq As Integer ' the current frequency we are playing

' OTHER SOUND VARIABLES
Dim SampleRate&
Dim FRate As Single
Dim SndLoop!

' OTHER VARIABLES
Dim in$

' INITIALIZE INPUT VALUES
' If frequency1 <> frequency2
' then start at frequency1 and over duration
' raise/lower pitch so that by end we are playing frequency2
' value range = 160-3951
' (not sure if we need to convert it for _SNDRAW)
frequency1 = 160
frequency2 = frequency1 + 100

' value range = 0-32767
amplitude = 32767

' value range = 5-9
' not sure what time this represents, probably a fraction of a second
' do we need to convert this to # of samples, ticks (1/18th second), etc.?
duration = 7

' TBD:
inflection = 0

' TBD:
vowel = 1

' TBD (probably offset for frequency1, frequency2)
' currently always 64
pitch = 64

' TBD (probably frequency to filter)
' currently always 0
filter = 0

' TBD (probalby offset for amplitude)
' currently always 63
volume = 63

' speed at which sound plays (without affecting pitch)
' currently always 10
rate = 10

' TBD:
stress = 0

' PLAY THE SOUND, CHANGING THE VALUES EACH ITERATION
Do
    ' -----------------------------------------------------------------------------
    ' CONVERT INPUT VALUES TO PLAYABLE RANGE

    ' convert amplitude to amplitude1 which must be from -1.0 to 1.0
    amplitude1 = (2 * (amplitude / 32767)) - 1

    SampleRate& = _SndRate ' sets the sample rate

    ' calculate how much to change frequency each step
    ' to get from frequency1 to frequency2 in SampleRate& steps
    freqDiff = (frequency2 - frequency1) / SampleRate&
    nextFreq = frequency1

    ' -----------------------------------------------------------------------------
    ' SHOW VALUES FOR SOUND THAT WILL PLAY NEXT
    Print "SOUND PARAMETERS TO PLAY NEXT:"
    Print "    frequency1  = " + _Trim$(Str$(frequency1))
    Print "    frequency2  = " + _Trim$(Str$(frequency2))
    Print "    amplitude   = " + _Trim$(Str$(amplitude))
    Print "    amplitude1  = " + SngToStr$(amplitude1)
    Print "    duration    = " + _Trim$(Str$(duration))
    Print "    SampleRate& = " + _Trim$(Str$(SampleRate&))
    Print "    freqDiff    = " + SngToStr$(freqDiff)
    Print

    ' -----------------------------------------------------------------------------
    ' PROMPT USER TO PLAY SOUND OR QUIT
    Input "Press Enter to play the sound or Q to quit"; in$
    in$ = Left$(UCase$(_Trim$(in$)), 1)
    If in$ = "Q" Then Exit Do

    ' -----------------------------------------------------------------------------
    ' PLAY SOUND FOR DURATION
    SndLoop! = 0 ' INIT COUNTER FOR DURATION
    Do While SndLoop! < SampleRate&
        FRate = nextFreq / SampleRate&

        '_SNDRAW SIN((2 * 4 * ATN(1) * SndLoop! / SampleRate&) * frq!) * EXP(-(SndLoop! / SampleRate&) * 3)
        '_SNDRAW amplitude1 * SIN(Pi2 * Duration * FRate) 'sine wave
        _SndRaw amplitude1 * Sgn(Sin(Pi2 * duration * FRate)) ' square wave

        ' INCREMENT FREQUENCY BY AMOUNT DETERMINED, SO FINAL FREQUENCY IS frequency2:
        nextFreq = nextFreq + freqDiff

        ' INCREMENT SAMPLE COUNTER
        SndLoop! = SndLoop! + 1
    Loop

    _SndRawDone

    Do: Loop While _SndRawLen ' flush the sound playing buffer

    _Delay 0.2 ' Add a short delay after speaking, important for some sound cards.

    ' -----------------------------------------------------------------------------
    ' NOW CHANGE THE INPUT VALUES FOR NEXT STEP

    ' value range = 160-3951
    frequency1 = frequency1 + 100
    frequency2 = frequency1 + 100
    If frequency1 > 3951 Then
        frequency1 = 160: frequency2 = frequency1 + 100
    End If

    ' value range = 5-9
    duration = duration + 1
    If duration > 9 Then duration = 5

    ' value range = 0-32767
    amplitude = amplitude - 2000
    If amplitude < 100 Then
        amplitude = 32767
    End If


Loop ' Until _KeyHit = 27

End

' /////////////////////////////////////////////////////////////////////////////
' TODO: verify this works

' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation

' Example: A string function that displays extremely small or large exponential decimal values.

Function SngToStr$ (n!)
    value$ = UCase$(LTrim$(Str$(n!)))
    Xpos% = InStr(value$, "D") + InStr(value$, "E") 'only D or E can be present
    If Xpos% Then
        expo% = Val(Mid$(value$, Xpos% + 1))
        If Val(value$) < 0 Then
            sign$ = "-": valu$ = Mid$(value$, 2, Xpos% - 2)
        Else valu$ = Mid$(value$, 1, Xpos% - 1)
        End If
        dot% = InStr(valu$, "."): L% = Len(valu$)
        If expo% > 0 Then add$ = String$(expo% - (L% - dot%), "0")
        If expo% < 0 Then min$ = String$(Abs(expo%) - (dot% - 1), "0"): DP$ = "."
        For n = 1 To L%
            If Mid$(valu$, n, 1) <> "." Then num$ = num$ + Mid$(valu$, n, 1)
        Next
    Else SngToStr$ = value$: Exit Function
    End If
    SngToStr$ = _Trim$(sign$ + DP$ + min$ + num$ + add$)
End Function ' SngToStr$
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question sound file playback (and record) - manipulating speed + pitch in realtime? madscijr 12 1,951 02-26-2025, 06:33 PM
Last Post: Petr
  List of file sound extensions eoredson 17 2,676 12-27-2024, 04:30 PM
Last Post: hsiangch_ong
Question APIs from QB64PE and parameters defined As Any and unions of types ? madscijr 23 4,352 06-06-2024, 07:09 PM
Last Post: SpriggsySpriggs
Question Last 2 parameters of Locate bplus 5 1,051 01-20-2024, 08:47 PM
Last Post: TerryRitchie
  _SndPlayFile not starting sound file eoredson 11 2,418 07-20-2023, 04:33 PM
Last Post: TerryRitchie

Forum Jump:


Users browsing this thread: 1 Guest(s)