Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
sound file playback (and record) - manipulating speed + pitch in realtime?
#1
Question 
Back in the olden days before digital audio, when sound was recorded using analog formats like records and tapes, the pitch of the audio was affected by playback speed (e.g., 33 1/4 vs 45 vs 78 rpm for records, 3.75 vs 7.5 vs 15 vs 30 ips for audio tape). Or you could record at a very high speed, and playing back the recording at normal speed would result in a very slow and low sound. Playing back audio recorded at a very low speed would sound like chipmunks. Professional and even consumer tape machines often included a knob to vary the speed of the tape or turntable motor and thus the pitch & speed, where adjusting it a small amount allowed fine-tuning. DJs can accomplish this when playing records by lightly pressing their finger down on the record as it plays (the harder they press, the more it slows down).

I'm wondering how we might use modern QB64PE with its extensive audio capability to replicate this function? Perhaps the playback speed (or speed while recording) could be manipulated using a mouse or other analog or continuous type input device like an analog joystick, or a little at a time by pressing +/- keys.

Any ideas how this might be done?
Reply
#2
the easiest and dirtiest way.  playback with _sndraw while making computations on sample playback.  load a wave file and play back each sample frame with that procedure.  normal playback is rate of 1.  a higher rate produces a higher pitch and faster playback.  a lower rate, with a better chance one frame is played twice or more.  has issues with sound quality but it's the only way to get a lower frequency than root.  interpolation for lower pitches would only increase cpu usage.

a really fast computer would be needed to do it in realtime and to keep up with gui controls and that sort of thing.
Reply
#3
Here is an equalizer program where you can change the sound frequency by pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2  

Speed change - try this....

Code: (Select All)

f$ = "slunce.mp3" 'must be mp3 (use single array)
Dim As Long s, t, Sze, i, Block
Dim As _MEM m

If _FileExists(f$) Then
    s = _SndOpen(f$)
    _Delay .5
Else
    Print f$; " not found."
    End
End If

If s < 1 Then Print "Error opening sound file "; f$: End
Sze = _SndRate * _SndLen(s)
m = _MemSound(s, 0)

Dim As Single Left(Sze), Right(Sze) 'load Audio do Ram
Do Until t = m.SIZE
    Left(i) = _MemGet(m, m.OFFSET + t, Single)
    Right(i) = _MemGet(m, m.OFFSET + t + 4, Single)
    t = t + 8
    i = i + 1
Loop
i = 0
speed = 1 'basic speed
Block = _SndRate \ 4 'data window - 0.25 sec

Print "Press + or - for setting music speed..."
Do Until i >= Sze - Block
    X = i
    Do Until X = Block
        If X + i >= Sze Then Exit Do
        _SndRaw Left(i + X), Right(i + X)
        X = X + speed

        Do Until _SndRawLen < .1
        Loop
        i$ = InKey$
        Select Case i$
            Case "+": speed = speed + .1
            Case "-": speed = speed - .1
        End Select
        Locate 2: Print "Speed: "; CInt(speed * 100); " percent              "
        If speed < 0 Then speed = 0

    Loop
    i = i + Block
Loop

_MemFree m
_SndClose s
Print "End."


Reply
#4
(02-04-2025, 05:28 PM)hsiangch_ong Wrote: the easiest and dirtiest way.  playback with _sndraw while making computations on sample playback.  load a wave file and play back each sample frame with that procedure.  normal playback is rate of 1.  a higher rate produces a higher pitch and faster playback.  a lower rate, with a better chance one frame is played twice or more.  has issues with sound quality but it's the only way to get a lower frequency than root.  interpolation for lower pitches would only increase cpu usage.

a really fast computer would be needed to do it in realtime and to keep up with gui controls and that sort of thing.
I don't need a fancy GUI, just reading basic mouse input and displaying a number on screen in plain text will be enough. I have not done any _sndraw, are there any simple examples you would recommend that I can build off of? 

UPDATE: I just saw Petr's reply, will try playing with that... 


(02-04-2025, 09:14 PM)Petr Wrote: Here is an equalizer program where you can change the sound frequency by pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2  

Speed change - try this....

Code: (Select All)

f$ = "slunce.mp3" 'must be mp3 (use single array)
...
Print "End."

Oh cool - thanks!!
I'll give these a look and see if I can combine the functionality,
and post the results when I have something.
Reply
#5
(02-04-2025, 09:14 PM)Petr Wrote: Here is an equalizer program where you can change the sound frequency by pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2  

Speed change - try this....

Code: (Select All)

f$ = "slunce.mp3" 'must be mp3 (use single array)
...
Print "End."
It works great! Thanks! 
I want to play with it some more and hear how it sounds with different types of audio files, but it does exactly what I was looking for. 
Thanks again!
Reply
#6
(02-04-2025, 09:14 PM)Petr Wrote:
Code: (Select All)

f$ = "slunce.mp3" 'must be mp3 (use single array)

Question: How might we get it to work with WAV files?

(02-04-2025, 09:14 PM)Petr Wrote: Speed change - try this....

I added to your code to allow using the mouse to speed up / slow down the audio file. Also, +/- now increases/decreases speed by one percent at a time to allow finer tuning.

The code is kind of bloated (apologies in advance to Steve and bplus for the headache it will give you!) and uses a hi-res screen, so not as efficient as a text-only display. Just a proof of concept for using mouse input.

Code: (Select All)
' Question: sound file playback (and record) - manipulating speed + pitch in realtime?
' https://qb64phoenix.com/forum/showthread.php?tid=3440
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Post #1
' From: madscijr
' Date: 02-04-2025, 07:57 AM (This post was last modified: Yesterday, 08:04 AM by madscijr.)
'
' Back in the olden days before digital audio, when sound was recorded using
' analog formats like records and tapes, the pitch of the audio was affected by
' playback speed (e.g., 33 1/4 vs 45 vs 78 rpm for records, 3.75 vs 7.5 vs 15 vs
' 30 ips for audio tape). Or you could record at a very high speed, and playing
' back the recording at normal speed would result in a very slow and low sound.
' Playing back audio recorded at a very low speed would sound like chipmunks.
' Professional and even consumer tape machines often included a knob to vary the
' speed of the tape or turntable motor and thus the pitch & speed, where
' adjusting it a small amount allowed fine-tuning. DJs can accomplish this when
' playing records by lightly pressing their finger down on the record as it plays
' (the harder they press, the more it slows down).
'
' I'm wondering how we might use modern QB64PE with its extensive audio
' capability to replicate this function? Perhaps the playback speed (or speed
' while recording) could be manipulated using a mouse or other analog or
' continuous type input device like an analog joystick, or a little at a time by
' pressing +/- keys.
'
' Any ideas how this might be done?
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #2
' From: hsiangch_ong Offline
' Date: 02-04-2025, 12:28 PM
'
' the easiest and dirtiest way.  playback with _sndraw while making computations
' on sample playback.  load a wave file and play back each sample frame with that
' procedure.  normal playback is rate of 1.  a higher rate produces a higher
' pitch and faster playback.  a lower rate, with a better chance one frame is
' played twice or more.  has issues with sound quality but it's the only way to
' get a lower frequency than root.  interpolation for lower pitches would only
' increase cpu usage.
'
' a really fast computer would be needed to do it in realtime and to keep up with
' gui controls and that sort of thing.
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #3
' From : Petr
' Date: 02-04-2025, 04:14 PM (This post was last modified: Yesterday, 04:20 PM by Petr.)
'
' Here is an equalizer program where you can change the sound frequency by
' pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2
'
' Speed change - try this....
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #4
' From: madscijr
' Date: 02-04-2025, 06:30 PM (This post was last modified: Yesterday, 06:36 PM by madscijr.)
'
' (02-04-2025, 12:28 PM) hsiangch_ong Wrote:
' >the easiest and dirtiest way.  playback with _sndraw while making computations
' >on sample playback.  load a wave file and play back each sample frame with that
' >procedure.  normal playback is rate of 1.  a higher rate produces a higher
' >pitch and faster playback.  a lower rate, with a better chance one frame is
' >played twice or more.  has issues with sound quality but it's the only way to
' >get a lower frequency than root.  interpolation for lower pitches would only
' >increase cpu usage.
' >
' >a really fast computer would be needed to do it in realtime and to keep up with
' >gui controls and that sort of thing.
'
' I don't need a fancy GUI, just reading basic mouse input and displaying a
' number on screen in plain text will be enough. I have not done any _sndraw, are
' there any simple examples you would recommend that I can build off of?
'
' UPDATE: I just saw Petr's reply, will try playing with that...
'
' Petr Wrote:
' >Here is an equalizer program where you can change the sound frequency by
' >pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2
' >
' >Speed change - try this....
' >Code: (Select All)
' >f$ = "slunce.mp3" 'must be mp3 (use single array)
' >...
' >Print "End."
'
' Oh cool - thanks!!
' I'll give these a look and see if I can combine the functionality,
' and post the results when I have something.
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
Const FALSE = 0
Const TRUE = Not FALSE ' -1

' CONSTANTS FOR QUICKMOUSE
Const Drift = 5 ' change the drift value for how lenient you want to be for your directional wandering of the mouse movement

' GLOBAL VARIABLES FOR QUICKMOUSE
Dim Shared As Long MB1, MB2, MB3, MMX, MMY, MW, MX, MY
Dim Shared As Integer oMB1, oMB2, oMB3 ' old mouse buttons

Dim f$
Dim As Long s
Dim t
Dim Sze
Dim i
Dim Block
Dim As _MEM m
ReDim As Single Left(-1)
ReDim As Single Right(-1)
Dim xPos As Integer
Dim xMax As Integer
Dim bMoved As Integer
Dim bExit As Integer
Dim RowNum As Integer

f$ = "sound1.mp3" ' must be mp3 (use single array)
If _FileExists(f$) Then
    s = _SndOpen(f$)
    _Delay .5
Else
    Print f$; " not found."
    End
End If

If s < 1 Then Print "Error opening sound file "; f$: End

Sze = _SndRate * _SndLen(s)
m = _MemSound(s, 0)

ReDim As Single Left(Sze) ' load Audio do Ram
ReDim As Single Right(Sze) ' load Audio do Ram

Do Until t = m.SIZE
    Left(i) = _MemGet(m, m.OFFSET + t, Single)
    Right(i) = _MemGet(m, m.OFFSET + t + 4, Single)
    t = t + 8
    i = i + 1
Loop ' Until t = m.SIZE

' Init screen
Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0 ' Screen set at top of program, before main menu.
Cls , cBlack~& ' makes the background opaque black

' SHOW INSTRUCTIONS
RowNum = 0
RowNum = RowNum + 1: Color cWhite~&, cBlue~&: PrintString0 RowNum, 1, "Tape Speed Simulator v2.0"
RowNum = RowNum + 1: Color cRed~&, cBlack~&: PrintString0 RowNum, 1, "by Petr"
RowNum = RowNum + 1: Color cLime~&, cBlack~&: PrintString0 RowNum, 1, "mods by madscijr"
RowNum = RowNum + 1
RowNum = RowNum + 1: Color cPurple~&, cBlack~&: PrintString0 RowNum, 1, "MOUSE:"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Left/right/wheel: decrease/increase sound speed and pitch"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Left   click    : decrease sound speed/pitch by 100%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Middle click    : reset    sound speed/pitch to 100%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Right  click    : increase sound speed/pitch by 100%"
RowNum = RowNum + 1
RowNum = RowNum + 1: Color cPurple~&, cBlack~&: PrintString0 RowNum, 1, "KEYS:"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "- or +: decrease/increase sound speed and pitch by 1%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Esc   : Quit program"
RowNum = RowNum + 1
RowNum = RowNum + 1

_MouseHide

' INITIALIZE
i = 0
speed = 1 ' basic speed
xPos = _Width * speed
xMax = _Width
Block = _SndRate \ 4 ' data window - 0.25 sec
bMoved = _FALSE
bExit = _FALSE

Do Until i >= Sze - Block
    X = i
    Do Until X = Block
        If X + i >= Sze Then Exit Do
       
        _SndRaw Left(i + X), Right(i + X)
        X = X + speed
       
        Do Until _SndRawLen < .1
        Loop
       
        ' LET USER CHANGE SPEED WITH KEYBOARD
        i$ = InKey$
        Select Case i$
            Case "-": speed = speed - .01
            Case "+": speed = speed + .01
        End Select
       
        ' LET USER CHANGE SPEED WITH MOUSE
        quickmouse
       
        ' LEFT/RIGHT
        If MMX < -Drift Then speed = speed - .01 ' Print "LEFT"
        If MMX > Drift Then speed = speed + .01 ' Print "RIGHT"
       
        ' MOUSE WHEEL
        If MW > 0 Then speed = speed - .01: bMoved = _TRUE ' Print "LEFT"
        If MW < 0 Then speed = speed + .01: bMoved = _TRUE ' Print "RIGHT"
       
        ' UP/DOWN
        'If MMY < -Drift Then Print "UP"
        'If MMY > Drift Then Print "DOWN"
       
        ' MOUSE BUTTONS
        If MB1 Then speed = speed - 1: bMoved = _TRUE ' Print "PEW PEW"
        If MB2 Then speed = speed + 1: bMoved = _TRUE ' Print "BYE BYE": System
        If MB3 Then speed = 1: bMoved = _TRUE
       
        ' CHECK BOUDARIES
        If speed < 0 Then speed = 0: bMoved = _TRUE
       
        ' PLACE MOUSE POINTER
        'if bMoved = _TRUE then _MOUSEMOVE (speed * 100), MY
       
        ' SHOW VALUES
        Color cHotPink~&, cBlack~&: PrintString0 RowNum, 1, "Speed: " + _Trim$(Str$(speed * 100)) + "%                    "
       
        ' SHOW GRAPH
        DrawRectSolid 0, ((RowNum + 1) * _FontHeight), _Width, _FontHeight, cGray~&
        DrawRectSolid 0, ((RowNum + 1) * _FontHeight), (speed * 100), _FontHeight, cWhite~&
       
        ' DID USER HIT ESCAPE?
        If _KeyDown(27) Then bExit = _TRUE: Exit Do
       
    Loop ' Until X = Block
   
    ' DID USER HIT ESCAPE?
    If bExit = _TRUE Then Exit Do
   
    i = i + Block
Loop ' Until i >= Sze - Block

_MemFree m
_SndClose s

If _MouseHidden = TRUE Then _MouseShow "DEFAULT"

Print "End."

' /////////////////////////////////////////////////////////////////////////////
' QuickMouse
' https://qb64phoenix.com/forum/showthread.php?tid=3442

' From: SMcNeill
' Date: 02-05-2025 04:30 PM
' I was talking to someone on Discord earlier today,
' and they were looking for a simple little routine
' to add directional movement and pew-pews to a game,
' using a mouse.  They had a routine,
' but it was rather laggy and didn't work quite right for me,
' so I wrote this little demo for them and thought
' I'd share it here in case anyone else might need
' something really simple like this:

Sub quickmouse
    ' mouse buttons
    MB1 = _FALSE
    MB2 = _FALSE
    MB3 = _FALSE
   
    ' track x/y
    MMX = 0
    MMY = 0
   
    ' track mouse wheel
    MW = 0
   
    While _MouseInput
        MMX = MMX + _MouseMovementX
        MMY = MMY + _MouseMovementY
        MW = MW + _MouseWheel
        MX = _MouseX
        MY = _MouseY
    Wend
   
   
    ' mouse buttons
    If _MouseButton(1) And Not oMB1 Then MB1 = _TRUE
    If _MouseButton(2) And Not oMB2 Then MB2 = _TRUE
    If _MouseButton(3) And Not oMB3 Then MB3 = _TRUE
   
    ' old mouse buttons
    oMB1 = _MouseButton(1)
    oMB2 = _MouseButton(2)
    oMB3 = _MouseButton(3)
End Sub ' quickmouse

' /////////////////////////////////////////////////////////////////////////////
' Convert integer to string and trim it (because normal Str$ adds spaces)

Function istr$ (MyValue%)
    istr$ = _Trim$(Str$(MyValue%))
End Function ' istr$

' /////////////////////////////////////////////////////////////////////////////
' Convert long to string and trim it (because normal Str$ adds spaces)

Function lstr$ (MyValue&)
    lstr$ = _Trim$(Str$(MyValue&))
End Function ' lstr$

' /////////////////////////////////////////////////////////////////////////////
' Use to pretty print TRUE and FALSE values.

Function TrueFalse$ (myValue)
    If myValue = TRUE Then
        TrueFalse$ = "TRUE"
    Else
        TrueFalse$ = "FALSE"
    End If
End Function ' TrueFalse$

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.
' iRow and iCol are 0-based.
' See also: PrintString1

Sub PrintString0 (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * iCol
    iY = _FontHeight * iRow ' (iRow + 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString0

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (OUTLINE)

'DrawRectOutline iX, iY, iSizeW, iSizeH, fgColor

Sub DrawRectOutline (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, B ' Draw rectangle outline
End Sub ' DrawRectOutline

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (SOLID)

'DrawRectSolid iX, iY, iSizeW, iSizeH, fgColor

Sub DrawRectSolid (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, BF ' Draw a solid rectangle
End Sub ' DrawRectSolid

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN RGB COLOR FUNCTIONS #RGB
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function cRed~& ()
    cRed = _RGB32(255, 0, 0)
End Function

Function cOrangeRed~& ()
    cOrangeRed = _RGB32(255, 69, 0)
End Function ' cOrangeRed~&

Function cDarkOrange~& ()
    cDarkOrange = _RGB32(255, 140, 0)
End Function ' cDarkOrange~&

Function cOrange~& ()
    cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&

Function cGold~& ()
    cGold = _RGB32(255, 215, 0)
End Function ' cGold~&

Function cYellow~& ()
    cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&

' LONG-HAIRED FRIENDS OF JESUS OR NOT,
' THIS IS NOT YELLOW ENOUGH (TOO CLOSE TO LIME)
' TO USE FOR OUR COMPLEX RAINBOW SEQUENCE:
Function cChartreuse~& ()
    cChartreuse = _RGB32(127, 255, 0)
End Function ' cChartreuse~&

' WE SUBSTITUTE THIS CSS3 COLOR FOR INBETWEEN LIME AND YELLOW:
Function cOliveDrab1~& ()
    cOliveDrab1 = _RGB32(192, 255, 62)
End Function ' cOliveDrab1~&

Function cLime~& ()
    cLime = _RGB32(0, 255, 0)
End Function ' cLime~&

Function cMediumSpringGreen~& ()
    cMediumSpringGreen = _RGB32(0, 250, 154)
End Function ' cMediumSpringGreen~&

' ADDED THIS FOR THE GAUGE COLOR:
Function cSpringGreen~& ()
    cSpringGreen = _RGB32(0, 255, 160)
End Function ' cSpringGreen~&

Function cCyan~& ()
    cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&

Function cDeepSkyBlue~& ()
    cDeepSkyBlue = _RGB32(0, 191, 255)
End Function ' cDeepSkyBlue~&

Function cDodgerBlue~& ()
    cDodgerBlue = _RGB32(30, 144, 255)
End Function ' cDodgerBlue~&

Function cSeaBlue~& ()
    cSeaBlue = _RGB32(0, 64, 255)
End Function ' cSeaBlue~&

Function cBlue~& ()
    cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&

Function cBluePurple~& ()
    cBluePurple = _RGB32(64, 0, 255)
End Function ' cBluePurple~&

Function cDeepPurple~& ()
    cDeepPurple = _RGB32(96, 0, 255)
End Function ' cDeepPurple~&

Function cPurple~& ()
    cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&

Function cPurpleRed~& ()
    cPurpleRed = _RGB32(128, 0, 192)
End Function ' cPurpleRed~&

Function cDarkRed~& ()
    cDarkRed = _RGB32(160, 0, 64)
End Function ' cDarkRed~&

Function cBrickRed~& ()
    cBrickRed = _RGB32(192, 0, 32)
End Function ' cBrickRed~&

Function cDarkGreen~& ()
    cDarkGreen = _RGB32(0, 100, 0)
End Function ' cDarkGreen~&

Function cGreen~& ()
    cGreen = _RGB32(0, 128, 0)
End Function ' cGreen~&

Function cOliveDrab~& ()
    cOliveDrab = _RGB32(107, 142, 35)
End Function ' cOliveDrab~&

Function cLightPink~& ()
    cLightPink = _RGB32(255, 182, 193)
End Function ' cLightPink~&

Function cHotPink~& ()
    cHotPink = _RGB32(255, 105, 180)
End Function ' cHotPink~&

Function cDeepPink~& ()
    cDeepPink = _RGB32(255, 20, 147)
End Function ' cDeepPink~&

Function cMagenta~& ()
    cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&

Function cBlack~& ()
    cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&

Function cDimGray~& ()
    cDimGray = _RGB32(105, 105, 105)
End Function ' cDimGray~&

Function cGray~& ()
    cGray = _RGB32(128, 128, 128)
End Function ' cGray~&

Function cDarkGray~& ()
    cDarkGray = _RGB32(169, 169, 169)
End Function ' cDarkGray~&

Function cSilver~& ()
    cSilver = _RGB32(192, 192, 192)
End Function ' cSilver~&

Function cLightGray~& ()
    cLightGray = _RGB32(211, 211, 211)
End Function ' cLightGray~&

Function cGainsboro~& ()
    cGainsboro = _RGB32(220, 220, 220)
End Function ' cGainsboro~&

Function cWhiteSmoke~& ()
    cWhiteSmoke = _RGB32(245, 245, 245)
End Function ' cWhiteSmoke~&

Function cWhite~& ()
    cWhite = _RGB32(255, 255, 255)
    'cWhite = _RGB32(254, 254, 254)
End Function ' cWhite~&

Function cDarkBrown~& ()
    cDarkBrown = _RGB32(128, 64, 0)
End Function ' cDarkBrown~&

Function cLightBrown~& ()
    cLightBrown = _RGB32(196, 96, 0)
End Function ' cLightBrown~&

Function cKhaki~& ()
    cKhaki = _RGB32(240, 230, 140)
End Function ' cKhaki~&

Function cEmpty~& ()
    'cEmpty~& = -1
    cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END RGB COLOR FUNCTIONS @RGB
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' BEGIN RGB COLOR ARRAY FUNCTIONS #COLR
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub AddColor (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long)
    ReDim _Preserve arrColor(0 To UBound(arrColor) + 1) As _Unsigned Long
    arrColor(UBound(arrColor)) = ColorValue
End Sub ' AddColor

' /////////////////////////////////////////////////////////////////////////////

Sub AddColors (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long, HowMany As Long)
    Dim iLoop As Integer
    For iLoop = 1 To HowMany
        AddColor ColorValue, arrColor()
    Next iLoop
End Sub ' AddColors

' /////////////////////////////////////////////////////////////////////////////

Sub AddSpectrumColors (arrColor() As _Unsigned Long)
    Dim iNum As Integer
    iNum = 1
    AddColors cRed, arrColor(), iNum
    AddColors cOrangeRed, arrColor(), iNum
    AddColors cDarkOrange, arrColor(), iNum
    AddColors cOrange, arrColor(), iNum
    AddColors cGold, arrColor(), iNum
    AddColors cYellow, arrColor(), iNum
    AddColors cChartreuse, arrColor(), iNum
    AddColors cOliveDrab1, arrColor(), iNum
    AddColors cLime, arrColor(), iNum
    AddColors cMediumSpringGreen, arrColor(), iNum
    AddColors cSpringGreen, arrColor(), iNum
    AddColors cCyan, arrColor(), iNum
    AddColors cDeepSkyBlue, arrColor(), iNum
    AddColors cDodgerBlue, arrColor(), iNum
    AddColors cSeaBlue, arrColor(), iNum
    AddColors cBlue, arrColor(), iNum
    AddColors cBluePurple, arrColor(), iNum
    AddColors cDeepPurple, arrColor(), iNum
    AddColors cPurple, arrColor(), iNum
    AddColors cPurpleRed, arrColor(), iNum
End Sub ' AddSpectrumColors

' /////////////////////////////////////////////////////////////////////////////

Sub AddGrayscaleColors (arrColor() As _Unsigned Long)
    Dim iNum As Integer
    iNum = 1
    AddColors cDimGray, arrColor(), iNum
    AddColors cGray, arrColor(), iNum
    AddColors cDarkGray, arrColor(), iNum
    AddColors cSilver, arrColor(), iNum
    AddColors cLightGray, arrColor(), iNum
    AddColors cGainsboro, arrColor(), iNum
    AddColors cWhiteSmoke, arrColor(), iNum
    AddColors cWhite, arrColor(), iNum '* 2
    AddColors cWhiteSmoke, arrColor(), iNum
    AddColors cGainsboro, arrColor(), iNum
    AddColors cLightGray, arrColor(), iNum
    AddColors cSilver, arrColor(), iNum
    AddColors cDarkGray, arrColor(), iNum
    AddColors cGray, arrColor(), iNum
End Sub ' AddGrayscaleColors

' ################################################################################################################################################################
' END COLOR ARRAY FUNCTIONS @COLR
' ################################################################################################################################################################


Here is a slightly modified version, with just a couple lines added to show the progress of the file playing, However, now the sound quality is very poor. I probably need to go back and streamline the code to be more efficient, and simplify the display to be text only:

Code: (Select All)
' This version sounds really bad with just a couple extra lines...

' Question: sound file playback (and record) - manipulating speed + pitch in realtime?
' https://qb64phoenix.com/forum/showthread.php?tid=3440
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Post #1
' From: madscijr
' Date: 02-04-2025, 07:57 AM (This post was last modified: Yesterday, 08:04 AM by madscijr.)
'
' Back in the olden days before digital audio, when sound was recorded using
' analog formats like records and tapes, the pitch of the audio was affected by
' playback speed (e.g., 33 1/4 vs 45 vs 78 rpm for records, 3.75 vs 7.5 vs 15 vs
' 30 ips for audio tape). Or you could record at a very high speed, and playing
' back the recording at normal speed would result in a very slow and low sound.
' Playing back audio recorded at a very low speed would sound like chipmunks.
' Professional and even consumer tape machines often included a knob to vary the
' speed of the tape or turntable motor and thus the pitch & speed, where
' adjusting it a small amount allowed fine-tuning. DJs can accomplish this when
' playing records by lightly pressing their finger down on the record as it plays
' (the harder they press, the more it slows down).
'
' I'm wondering how we might use modern QB64PE with its extensive audio
' capability to replicate this function? Perhaps the playback speed (or speed
' while recording) could be manipulated using a mouse or other analog or
' continuous type input device like an analog joystick, or a little at a time by
' pressing +/- keys.
'
' Any ideas how this might be done?
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #2
' From: hsiangch_ong Offline
' Date: 02-04-2025, 12:28 PM
'
' the easiest and dirtiest way.  playback with _sndraw while making computations
' on sample playback.  load a wave file and play back each sample frame with that
' procedure.  normal playback is rate of 1.  a higher rate produces a higher
' pitch and faster playback.  a lower rate, with a better chance one frame is
' played twice or more.  has issues with sound quality but it's the only way to
' get a lower frequency than root.  interpolation for lower pitches would only
' increase cpu usage.
'
' a really fast computer would be needed to do it in realtime and to keep up with
' gui controls and that sort of thing.
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #3
' From : Petr
' Date: 02-04-2025, 04:14 PM (This post was last modified: Yesterday, 04:20 PM by Petr.)
'
' Here is an equalizer program where you can change the sound frequency by
' pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2
'
' Speed change - try this....
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Reply #4
' From: madscijr
' Date: 02-04-2025, 06:30 PM (This post was last modified: Yesterday, 06:36 PM by madscijr.)
'
' (02-04-2025, 12:28 PM) hsiangch_ong Wrote:
' >the easiest and dirtiest way.  playback with _sndraw while making computations
' >on sample playback.  load a wave file and play back each sample frame with that
' >procedure.  normal playback is rate of 1.  a higher rate produces a higher
' >pitch and faster playback.  a lower rate, with a better chance one frame is
' >played twice or more.  has issues with sound quality but it's the only way to
' >get a lower frequency than root.  interpolation for lower pitches would only
' >increase cpu usage.
' >
' >a really fast computer would be needed to do it in realtime and to keep up with
' >gui controls and that sort of thing.
'
' I don't need a fancy GUI, just reading basic mouse input and displaying a
' number on screen in plain text will be enough. I have not done any _sndraw, are
' there any simple examples you would recommend that I can build off of?
'
' UPDATE: I just saw Petr's reply, will try playing with that...
'
' Petr Wrote:
' >Here is an equalizer program where you can change the sound frequency by
' >pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2
' >
' >Speed change - try this....
' >Code: (Select All)
' >f$ = "slunce.mp3" 'must be mp3 (use single array)
' >...
' >Print "End."
'
' Oh cool - thanks!!
' I'll give these a look and see if I can combine the functionality,
' and post the results when I have something.
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
Const FALSE = 0
Const TRUE = Not FALSE ' -1

' CONSTANTS FOR QUICKMOUSE
Const Drift = 5 ' change the drift value for how lenient you want to be for your directional wandering of the mouse movement

' GLOBAL VARIABLES FOR QUICKMOUSE
Dim Shared As Long MB1, MB2, MB3, MMX, MMY, MW, MX, MY
Dim Shared As Integer oMB1, oMB2, oMB3 ' old mouse buttons

Dim f$
Dim As Long s
Dim t
Dim Sze
Dim i
Dim Block
Dim As _MEM m
ReDim As Single Left(-1)
ReDim As Single Right(-1)
Dim xPos As Integer
Dim xMax As Integer
Dim bMoved As Integer
Dim bExit As Integer
Dim RowNum As Integer

f$ = "sound1.mp3" ' must be mp3 (use single array)
If _FileExists(f$) Then
    s = _SndOpen(f$)
    _Delay .5
Else
    Print f$; " not found."
    End
End If

If s < 1 Then Print "Error opening sound file "; f$: End

Sze = _SndRate * _SndLen(s)
m = _MemSound(s, 0)

ReDim As Single Left(Sze) ' load Audio do Ram
ReDim As Single Right(Sze) ' load Audio do Ram

Do Until t = m.SIZE
    Left(i) = _MemGet(m, m.OFFSET + t, Single)
    Right(i) = _MemGet(m, m.OFFSET + t + 4, Single)
    t = t + 8
    i = i + 1
Loop ' Until t = m.SIZE

' Init screen
Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0 ' Screen set at top of program, before main menu.
Cls , cBlack~& ' makes the background opaque black

' SHOW INSTRUCTIONS
RowNum = 0
RowNum = RowNum + 1: Color cWhite~&, cBlue~&: PrintString0 RowNum, 1, "Tape Speed Simulator v2.0"
RowNum = RowNum + 1: Color cRed~&, cBlack~&: PrintString0 RowNum, 1, "by Petr"
RowNum = RowNum + 1: Color cLime~&, cBlack~&: PrintString0 RowNum, 1, "mods by madscijr"
RowNum = RowNum + 1
RowNum = RowNum + 1: Color cPurple~&, cBlack~&: PrintString0 RowNum, 1, "MOUSE:"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Left/right/wheel: decrease/increase sound speed and pitch"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Left   click    : decrease sound speed/pitch by 100%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Middle click    : reset    sound speed/pitch to 100%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Right  click    : increase sound speed/pitch by 100%"
RowNum = RowNum + 1
RowNum = RowNum + 1: Color cPurple~&, cBlack~&: PrintString0 RowNum, 1, "KEYS:"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "- or +: decrease/increase sound speed and pitch by 1%"
RowNum = RowNum + 1: Color cCyan~&, cBlack~&: PrintString0 RowNum, 1, "Esc   : Quit program"
RowNum = RowNum + 1
RowNum = RowNum + 1

_MouseHide

' INITIALIZE
i = 0
speed = 1 ' basic speed
xPos = _Width * speed
xMax = _Width
Block = _SndRate \ 4 ' data window - 0.25 sec
bMoved = _FALSE
bExit = _FALSE

Do Until i >= Sze - Block
    X = i
    Do Until X = Block
        If X + i >= Sze Then Exit Do
       
        _SndRaw Left(i + X), Right(i + X)
        X = X + speed
       
        Do Until _SndRawLen < .1
        Loop
       
        ' LET USER CHANGE SPEED WITH KEYBOARD
        i$ = InKey$
        Select Case i$
            Case "-": speed = speed - .01
            Case "+": speed = speed + .01
        End Select
       
        ' LET USER CHANGE SPEED WITH MOUSE
        quickmouse
       
        ' LEFT/RIGHT
        If MMX < -Drift Then speed = speed - .01 ' Print "LEFT"
        If MMX > Drift Then speed = speed + .01 ' Print "RIGHT"
       
        ' MOUSE WHEEL
        If MW > 0 Then speed = speed - .01: bMoved = _TRUE ' Print "LEFT"
        If MW < 0 Then speed = speed + .01: bMoved = _TRUE ' Print "RIGHT"
       
        ' UP/DOWN
        'If MMY < -Drift Then Print "UP"
        'If MMY > Drift Then Print "DOWN"
       
        ' MOUSE BUTTONS
        If MB1 Then speed = speed - 1: bMoved = _TRUE ' Print "PEW PEW"
        If MB2 Then speed = speed + 1: bMoved = _TRUE ' Print "BYE BYE": System
        If MB3 Then speed = 1: bMoved = _TRUE
       
        ' CHECK BOUDARIES
        If speed < 0 Then speed = 0: bMoved = _TRUE
       
        ' PLACE MOUSE POINTER
        'if bMoved = _TRUE then _MOUSEMOVE (speed * 100), MY
       
        ' SHOW VALUES
        Color cHotPink~&, cBlack~&: PrintString0 RowNum, 1, "Speed: " + _Trim$(Str$(speed * 100)) + "%                    "
       
        ' SHOW GRAPH
        DrawRectSolid 0, ((RowNum + 1) * _FontHeight), _Width, _FontHeight, cGray~&
        DrawRectSolid 0, ((RowNum + 1) * _FontHeight), (speed * 100), _FontHeight, cWhite~&
       
        ' SHOW PROGRESS (HOW DO YOU SHOW IT IN SECONDS?)
        Color cDodgerBlue~&, cBlack~&: PrintString0 RowNum + 3, 1, "Progress: " + _Trim$(Str$((i / (Sze - Block)) * 100)) + "%                    "
       
        ' SHOW PROGRESS GRAPH
        DrawRectSolid 0, ((RowNum + 4) * _FontHeight), 100, _FontHeight, cGray~&
        DrawRectSolid 0, ((RowNum + 4) * _FontHeight), (i / (Sze - Block)) * 100, _FontHeight, cWhite~&
       
        ' DID USER HIT ESCAPE?
        If _KeyDown(27) Then bExit = _TRUE: Exit Do
       
    Loop ' Until X = Block
   
    ' DID USER HIT ESCAPE?
    If bExit = _TRUE Then Exit Do
   
    i = i + Block
Loop ' Until i >= Sze - Block

_MemFree m
_SndClose s

If _MouseHidden = TRUE Then _MouseShow "DEFAULT"

Print "End."

' /////////////////////////////////////////////////////////////////////////////
' QuickMouse
' https://qb64phoenix.com/forum/showthread.php?tid=3442

' From: SMcNeill
' Date: 02-05-2025 04:30 PM
' I was talking to someone on Discord earlier today,
' and they were looking for a simple little routine
' to add directional movement and pew-pews to a game,
' using a mouse.  They had a routine,
' but it was rather laggy and didn't work quite right for me,
' so I wrote this little demo for them and thought
' I'd share it here in case anyone else might need
' something really simple like this:

Sub quickmouse
    ' mouse buttons
    MB1 = _FALSE
    MB2 = _FALSE
    MB3 = _FALSE
   
    ' track x/y
    MMX = 0
    MMY = 0
   
    ' track mouse wheel
    MW = 0
   
    While _MouseInput
        MMX = MMX + _MouseMovementX
        MMY = MMY + _MouseMovementY
        MW = MW + _MouseWheel
        MX = _MouseX
        MY = _MouseY
    Wend
   
   
    ' mouse buttons
    If _MouseButton(1) And Not oMB1 Then MB1 = _TRUE
    If _MouseButton(2) And Not oMB2 Then MB2 = _TRUE
    If _MouseButton(3) And Not oMB3 Then MB3 = _TRUE
   
    ' old mouse buttons
    oMB1 = _MouseButton(1)
    oMB2 = _MouseButton(2)
    oMB3 = _MouseButton(3)
End Sub ' quickmouse

' /////////////////////////////////////////////////////////////////////////////
' Convert integer to string and trim it (because normal Str$ adds spaces)

Function istr$ (MyValue%)
    istr$ = _Trim$(Str$(MyValue%))
End Function ' istr$

' /////////////////////////////////////////////////////////////////////////////
' Convert long to string and trim it (because normal Str$ adds spaces)

Function lstr$ (MyValue&)
    lstr$ = _Trim$(Str$(MyValue&))
End Function ' lstr$

' /////////////////////////////////////////////////////////////////////////////
' Use to pretty print TRUE and FALSE values.

Function TrueFalse$ (myValue)
    If myValue = TRUE Then
        TrueFalse$ = "TRUE"
    Else
        TrueFalse$ = "FALSE"
    End If
End Function ' TrueFalse$

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.
' iRow and iCol are 0-based.
' See also: PrintString1

Sub PrintString0 (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * iCol
    iY = _FontHeight * iRow ' (iRow + 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString0

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (OUTLINE)

'DrawRectOutline iX, iY, iSizeW, iSizeH, fgColor

Sub DrawRectOutline (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, B ' Draw rectangle outline
End Sub ' DrawRectOutline

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (SOLID)

'DrawRectSolid iX, iY, iSizeW, iSizeH, fgColor

Sub DrawRectSolid (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, BF ' Draw a solid rectangle
End Sub ' DrawRectSolid

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN RGB COLOR FUNCTIONS #RGB
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Function cRed~& ()
    cRed = _RGB32(255, 0, 0)
End Function

Function cOrangeRed~& ()
    cOrangeRed = _RGB32(255, 69, 0)
End Function ' cOrangeRed~&

Function cDarkOrange~& ()
    cDarkOrange = _RGB32(255, 140, 0)
End Function ' cDarkOrange~&

Function cOrange~& ()
    cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&

Function cGold~& ()
    cGold = _RGB32(255, 215, 0)
End Function ' cGold~&

Function cYellow~& ()
    cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&

' LONG-HAIRED FRIENDS OF JESUS OR NOT,
' THIS IS NOT YELLOW ENOUGH (TOO CLOSE TO LIME)
' TO USE FOR OUR COMPLEX RAINBOW SEQUENCE:
Function cChartreuse~& ()
    cChartreuse = _RGB32(127, 255, 0)
End Function ' cChartreuse~&

' WE SUBSTITUTE THIS CSS3 COLOR FOR INBETWEEN LIME AND YELLOW:
Function cOliveDrab1~& ()
    cOliveDrab1 = _RGB32(192, 255, 62)
End Function ' cOliveDrab1~&

Function cLime~& ()
    cLime = _RGB32(0, 255, 0)
End Function ' cLime~&

Function cMediumSpringGreen~& ()
    cMediumSpringGreen = _RGB32(0, 250, 154)
End Function ' cMediumSpringGreen~&

' ADDED THIS FOR THE GAUGE COLOR:
Function cSpringGreen~& ()
    cSpringGreen = _RGB32(0, 255, 160)
End Function ' cSpringGreen~&

Function cCyan~& ()
    cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&

Function cDeepSkyBlue~& ()
    cDeepSkyBlue = _RGB32(0, 191, 255)
End Function ' cDeepSkyBlue~&

Function cDodgerBlue~& ()
    cDodgerBlue = _RGB32(30, 144, 255)
End Function ' cDodgerBlue~&

Function cSeaBlue~& ()
    cSeaBlue = _RGB32(0, 64, 255)
End Function ' cSeaBlue~&

Function cBlue~& ()
    cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&

Function cBluePurple~& ()
    cBluePurple = _RGB32(64, 0, 255)
End Function ' cBluePurple~&

Function cDeepPurple~& ()
    cDeepPurple = _RGB32(96, 0, 255)
End Function ' cDeepPurple~&

Function cPurple~& ()
    cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&

Function cPurpleRed~& ()
    cPurpleRed = _RGB32(128, 0, 192)
End Function ' cPurpleRed~&

Function cDarkRed~& ()
    cDarkRed = _RGB32(160, 0, 64)
End Function ' cDarkRed~&

Function cBrickRed~& ()
    cBrickRed = _RGB32(192, 0, 32)
End Function ' cBrickRed~&

Function cDarkGreen~& ()
    cDarkGreen = _RGB32(0, 100, 0)
End Function ' cDarkGreen~&

Function cGreen~& ()
    cGreen = _RGB32(0, 128, 0)
End Function ' cGreen~&

Function cOliveDrab~& ()
    cOliveDrab = _RGB32(107, 142, 35)
End Function ' cOliveDrab~&

Function cLightPink~& ()
    cLightPink = _RGB32(255, 182, 193)
End Function ' cLightPink~&

Function cHotPink~& ()
    cHotPink = _RGB32(255, 105, 180)
End Function ' cHotPink~&

Function cDeepPink~& ()
    cDeepPink = _RGB32(255, 20, 147)
End Function ' cDeepPink~&

Function cMagenta~& ()
    cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&

Function cBlack~& ()
    cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&

Function cDimGray~& ()
    cDimGray = _RGB32(105, 105, 105)
End Function ' cDimGray~&

Function cGray~& ()
    cGray = _RGB32(128, 128, 128)
End Function ' cGray~&

Function cDarkGray~& ()
    cDarkGray = _RGB32(169, 169, 169)
End Function ' cDarkGray~&

Function cSilver~& ()
    cSilver = _RGB32(192, 192, 192)
End Function ' cSilver~&

Function cLightGray~& ()
    cLightGray = _RGB32(211, 211, 211)
End Function ' cLightGray~&

Function cGainsboro~& ()
    cGainsboro = _RGB32(220, 220, 220)
End Function ' cGainsboro~&

Function cWhiteSmoke~& ()
    cWhiteSmoke = _RGB32(245, 245, 245)
End Function ' cWhiteSmoke~&

Function cWhite~& ()
    cWhite = _RGB32(255, 255, 255)
    'cWhite = _RGB32(254, 254, 254)
End Function ' cWhite~&

Function cDarkBrown~& ()
    cDarkBrown = _RGB32(128, 64, 0)
End Function ' cDarkBrown~&

Function cLightBrown~& ()
    cLightBrown = _RGB32(196, 96, 0)
End Function ' cLightBrown~&

Function cKhaki~& ()
    cKhaki = _RGB32(240, 230, 140)
End Function ' cKhaki~&

Function cEmpty~& ()
    'cEmpty~& = -1
    cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END RGB COLOR FUNCTIONS @RGB
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' BEGIN RGB COLOR ARRAY FUNCTIONS #COLR
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub AddColor (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long)
    ReDim _Preserve arrColor(0 To UBound(arrColor) + 1) As _Unsigned Long
    arrColor(UBound(arrColor)) = ColorValue
End Sub ' AddColor

' /////////////////////////////////////////////////////////////////////////////

Sub AddColors (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long, HowMany As Long)
    Dim iLoop As Integer
    For iLoop = 1 To HowMany
        AddColor ColorValue, arrColor()
    Next iLoop
End Sub ' AddColors

' /////////////////////////////////////////////////////////////////////////////

Sub AddSpectrumColors (arrColor() As _Unsigned Long)
    Dim iNum As Integer
    iNum = 1
    AddColors cRed, arrColor(), iNum
    AddColors cOrangeRed, arrColor(), iNum
    AddColors cDarkOrange, arrColor(), iNum
    AddColors cOrange, arrColor(), iNum
    AddColors cGold, arrColor(), iNum
    AddColors cYellow, arrColor(), iNum
    AddColors cChartreuse, arrColor(), iNum
    AddColors cOliveDrab1, arrColor(), iNum
    AddColors cLime, arrColor(), iNum
    AddColors cMediumSpringGreen, arrColor(), iNum
    AddColors cSpringGreen, arrColor(), iNum
    AddColors cCyan, arrColor(), iNum
    AddColors cDeepSkyBlue, arrColor(), iNum
    AddColors cDodgerBlue, arrColor(), iNum
    AddColors cSeaBlue, arrColor(), iNum
    AddColors cBlue, arrColor(), iNum
    AddColors cBluePurple, arrColor(), iNum
    AddColors cDeepPurple, arrColor(), iNum
    AddColors cPurple, arrColor(), iNum
    AddColors cPurpleRed, arrColor(), iNum
End Sub ' AddSpectrumColors

' /////////////////////////////////////////////////////////////////////////////

Sub AddGrayscaleColors (arrColor() As _Unsigned Long)
    Dim iNum As Integer
    iNum = 1
    AddColors cDimGray, arrColor(), iNum
    AddColors cGray, arrColor(), iNum
    AddColors cDarkGray, arrColor(), iNum
    AddColors cSilver, arrColor(), iNum
    AddColors cLightGray, arrColor(), iNum
    AddColors cGainsboro, arrColor(), iNum
    AddColors cWhiteSmoke, arrColor(), iNum
    AddColors cWhite, arrColor(), iNum '* 2
    AddColors cWhiteSmoke, arrColor(), iNum
    AddColors cGainsboro, arrColor(), iNum
    AddColors cLightGray, arrColor(), iNum
    AddColors cSilver, arrColor(), iNum
    AddColors cDarkGray, arrColor(), iNum
    AddColors cGray, arrColor(), iNum
End Sub ' AddGrayscaleColors

' ################################################################################################################################################################
' END COLOR ARRAY FUNCTIONS @COLR
' ################################################################################################################################################################
Reply
#7
(02-04-2025, 09:14 PM)Petr Wrote: Here is an equalizer program where you can change the sound frequency by pressing + or minus:  https://qb64phoenix.com/forum/showthread...558&page=2  

Speed change - try this....

Hey Petr, that worked for playback.
Can you think of a way to _record_ at a different speed?
So if you record faster and then play it back at normal speed, it sounds slow, and if you record slow and play it back, it sounds fast?
Reply
#8
What code are you using for recording?
The noticing will continue
Reply
#9
(02-10-2025, 02:41 PM)SpriggsySpriggs Wrote: What code are you using for recording?
I'm not - haven't figured out how to record yet - but I think it would need to be low level processing one sample at a time in a loop, similar to the approach in Petr's playback example above.

PS: Over the weekend I collected my notes on this, didn't get around to reading through it all or running any code yet, but here's what I have:

From the wiki:
_SNDNEW (function) creates a raw empty sound in memory and returns a LONG handle value for later access.
_SNDOPENRAW (function) opens a new channel to shove _SNDRAW content into without mixing.
SNDRATE (function) returns the sound card sample rate to set _SNDRAW durations.
_SNDRAWLEN (function) returns a value until the _SNDRAW buffer is empty.
_MEMSOUND (function) returns a _MEM block referring to a designated sound handle's memory
SMFL Library - SFML is a sound library that allows users to record and play sounds.

Threads:
QB64PE - Help Me! - What options are there to get audio input? (10/25/2024)
QB64PE - General Discussion - WAV file splitter program? (4/20/2023)
QB64PE issues - Sound playback from embedded data #232 (KingMocker opened on Oct 31, 2022)
QB64PE - Help Me! - Building sounds with _SNDPLAYCOPY? (10/12/2022)
Reply
#10
You can record using MCISendString. I have code in my API Collection on my GitHub.

Spriggsy-s-API-Collection/WinAPI/mciSendStringA (WinAPI WINMM) Record and playback audio.bas at master · spriggsyspriggs/Spriggsy-s-API-Collection
The noticing will continue
Reply




Users browsing this thread: 11 Guest(s)