Awesome Audio Generator

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Awesome Audio Generator

Post by BasicallyPure »

Generate a continuous audio stream calculated in real time.
Blend up to four waveforms with independent frequency, amplitude, and balance control.
Choose between sine wave, or square wave with duty cycle adjustment.
Choose between mono or stereo output.

When 'hop' mode is selected F1 and F4 set upper and lower boundaries of random frequencies.
F2 and F3 values have no effect in this mode.

Image

Code: Select all

;====================================
; Title   : Awesome Audio Generator |
; Author  : BasicallyPure           |
; Date    : 8/29/2015               |
; Version : 1.0                     |
; OS      : Windows                 |
; License : Free and risky          |
; Compiler: PureBasic 5.31          |
;====================================

EnableExplicit

#Version  = "1.0"
#WinMain  = 0
#PIx2     = 2*#PI
#Mono     = 1
#Stereo   = 2
#Menu_1   = 0
#BuffSize = 8192 ; determines BlockSize per channel

#Input_Finished = #PB_EventType_FirstCustomValue

;{ gadgets
Enumeration
  #Spin_F1       : #Spin_F2       : #Spin_F3       : #Spin_F4
  #Track_Vol_F1  : #Track_Vol_F2  : #Track_Vol_F3  : #Track_Vol_F4
  #Track_Bal_F1  : #Track_Bal_F2  : #Track_Bal_F3  : #Track_Bal_F4
  #Track_Duty_F1 : #Track_Duty_F2 : #Track_Duty_F3 : #Track_Duty_F4
  #Check_Sq_F1   : #Check_Sq_F2   : #Check_Sq_F3   : #Check_Sq_F4
  #Check_Hop     : #Button_Run    : #Option_Mono   : #Option_Stereo
  #Text_Duty_F1  : #Text_Duty_F2  : #Text_Duty_F3  : #Text_Duty_F4
  #Text_Vol_F1   : #Text_Vol_F2   : #Text_Vol_F3   : #Text_Vol_F4
  #Text_Bal_F1   : #Text_Bal_F2   : #Text_Bal_F3   : #Text_Bal_F4
  #Canvas_Scope_L: #Canvas_Scope_R: #Text_Scope    : #Track_Scope
EndEnumeration : ;}

;menu items
#MenuItem_EnterKey  = 0
#MenuItem_OnTop     = 1
#MenuItem_ScopeAuto = 2
#Last_Menu_Item     = 3

;{ Global variables

Global WinColor = GetSysColor_(#COLOR_BTNFACE) ;use for default system color
;Global WinColor  = $BAB5A1 ; use for modified color scheme

Global SampleClock     = 44100   ; Sampling frequency in 'samples per second'
Global BytesPerSample  = 2       ; Number of bytes needed for each sample, don't change this
Global Channels        = #Stereo ; Number of channels, 1 for mono, 2 for stereo.
Global nBuf            = 8       ; Number of buffers
Global DevOut          = 1       ; default audio output device
Global Freq_F1   = 220 ; initial frequencies
Global Freq_F2   = 330
Global Freq_F3   = 440
Global Freq_F4   = 550
Global Vol_F1.f  = 0.20 ; initial volumes
Global Vol_F2.f  = 0.20
Global Vol_F3.f  = 0.20
Global Vol_F4.f  = 0.20
Global Bal_F1.f  = 0.50 ; initial balance settings
Global Bal_F2.f  = 0.50
Global Bal_F3.f  = 0.50
Global Bal_F4.f  = 0.50
Global hWaveOut ;Pointer to a buffer that receives a handle identifying the open waveform-audio output device
Global NumOutDevs
Global BlockSize ; determined by #BuffSize and Channels
Global OutDev_1  ; the first available audio output device
Global Hop       = #False
Global Pause     = #True
Global Trig      = #True
Global Square_F1 = #False
Global Square_F2 = #False
Global Square_F3 = #False
Global Square_F4 = #False
Global Duty_F1.f = #PI * 0.02 * 50 ;50% duty
Global Duty_F2.f = #PI * 0.02 * 50 ;50% duty
Global Duty_F3.f = #PI * 0.02 * 50 ;50% duty
Global Duty_F4.f = #PI * 0.02 * 50 ;50% duty
Global Hscale.i  = 15 ;scope horizontal scale, 1...|...20
Global stickyState = 0
Global autoTrig    = 1
Global.d Vol_L1,Vol_L2,Vol_L3,Vol_L4,Vol_R1,Vol_R2,Vol_R3,Vol_R4
Global imgID_L, imgID_R ;scope bkgnd images
Global *ScopeBuff
Global PlayFormat.WAVEFORMATEX
Global MyOutDevs.WAVEOUTCAPS
Global Dim outHdr.WAVEHDR(nBuf)
;}

Procedure SCOPE()
   Static sf.d = 50.0/32767.0 ;scale factor
   Protected a,x,y, Lx, Ly, aMax, stp
   
   If *ScopeBuff = 0 : ProcedureReturn : EndIf
   
   Trig = #False
   aMax = *ScopeBuff + (200 * Hscale * Channels * BytesPerSample)
   stp = BytesPerSample * Channels * Hscale
   
   StartDrawing(CanvasOutput(#Canvas_Scope_L))
      DrawImage(imgID_L,0,0)
      a = *ScopeBuff
      Ly = 50 + PeekW(a) * sf
      While a < aMax
         y = 50 + PeekW(a) * sf
         LineXY(Lx,Ly,x,y,$00FFFF)
         a + stp
         Lx = x : Ly = y
         x + 1
      Wend
   StopDrawing()
   
   StartDrawing(CanvasOutput(#Canvas_Scope_R))
      DrawImage(imgID_R,0,0)
      a = *ScopeBuff
      If Channels = #Stereo : a + BytesPerSample : EndIf
      x = 0 : Lx = 0
      Ly = 50 + PeekW(a) * sf
      While a < aMax
         y = 50 + PeekW(a) * sf
         LineXY(Lx,Ly,x,y,$00FFFF)
         a + stp
         Lx = x : Ly = y
         x + 1
      Wend
   StopDrawing()
   
EndProcedure

Procedure MAKE_WAVES(*SBuf)
   Static.d A1,A2,A3,A4,S1,S2,S3,S4,LL,UL,K1,K2,K3,K4
   Static.l value_L, value_R, sample
   
   *ScopeBuff = *SBuf
   
   If Hop
      LL = GetGadgetState(#Spin_F1)
      UL = GetGadgetState(#Spin_F4)
      If LL > UL : Swap LL,UL : EndIf
      Freq_F1 = Random(UL,LL)
      Freq_F2 = Random(UL,LL)
      Freq_F3 = Random(UL,LL)
      Freq_F4 = Random(UL,LL)
      Trig = #True
   EndIf
   
   ; calculate angel increments
   K1 = #PIx2 * Freq_F1 / SampleClock
   K2 = #PIx2 * Freq_F2 / SampleClock
   K3 = #PIx2 * Freq_F3 / SampleClock
   K4 = #PIx2 * Freq_F4 / SampleClock
   
   sample = 1
   Repeat ; Generate waveform data
      
      If Square_F1 : S1 = Sign(Duty_F1-A1) : Else : S1 = Sin(A1) : EndIf
      If Square_F2 : S2 = Sign(Duty_F2-A2) : Else : S2 = Sin(A2) : EndIf
      If Square_F3 : S3 = Sign(Duty_F3-A3) : Else : S3 = Sin(A3) : EndIf
      If Square_F4 : S4 = Sign(Duty_F4-A4) : Else : S4 = Sin(A4) : EndIf
      
      value_L = S1 * Vol_L1 + S2 * Vol_L2 + S3 * Vol_L3 + S4 * Vol_L4
      PokeW(*SBuf,value_L)        ; Put data point in buffer
      *SBuf + BytesPerSample      ; move buffer pointer to next sample
      
      If Channels = #Stereo
         value_R = S1 * Vol_R1 + S2 * Vol_R2 + S3 * Vol_R3 + S4 * Vol_R4
         PokeW(*SBuf,value_R)
         *SBuf + BytesPerSample
      EndIf
      
      ; calculate angle for next time
      A1 + K1 : If A1 > #PIx2 : A1 - #PIx2 : EndIf
      A2 + K2 : If A2 > #PIx2 : A2 - #PIx2 : EndIf
      A3 + K3 : If A3 > #PIx2 : A3 - #PIx2 : EndIf
      A4 + K4 : If A4 > #PIx2 : A4 - #PIx2 : EndIf
      
      sample + PlayFormat\nBlockAlign
   Until sample > BlockSize
   
   If autoTrig : SCOPE() : ElseIf Trig : SCOPE() : EndIf
   
EndProcedure

Procedure WIN_CALLBACK(hwnd, uMsg, wParam, lParam)
   ; Window callback to service sound output message
   ; also generate LostFocus events for spin gadgets
   Static *hWaveO.WAVEHDR
   Protected gadget
   
   Select uMsg
      Case #MM_WOM_DONE                      ; Sound output, a play buffer has been returned.
         *hWaveO.WAVEHDR = lParam                        ; lParam has the address of WAVEHDR
         MAKE_WAVES(*hWaveO\lpData)                      ; send pointer where to write NEW data
         *hWaveO\dwBytesRecorded = BlockSize             ; Number of bytes written into buffer
         waveOutWrite_(hWaveOut,lParam, SizeOf(WAVEHDR)) ; Send to sound device => jack socket => cable =>
      Case #WM_COMMAND
         Select wParam >> 16 ; get HiWord
            Case #EN_KILLFOCUS
               gadget = wParam & $FFFF ; get LoWord
               If GadgetType(gadget) = #PB_GadgetType_Spin
                  PostEvent(#PB_Event_Gadget, #WinMain, gadget, #PB_EventType_LostFocus)
               EndIf
            ;Case #EN_SETFOCUS
               ;PostEvent(#PB_Event_Gadget, #WinMain, gadget, #PB_EventType_Focus)
         EndSelect
   EndSelect
    
   ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure BUILD_GUI(x = 0, y = 0, width = 710, height = 320)
   Protected hWinMain, n, result
   Protected flags = #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
   hWinMain = OpenWindow(#WinMain, x, y, width, height, "Awesome Audio Generator "+#Version, flags)
   If hWinMain
      result = hWinMain
      SetWindowColor(#WinMain,WinColor)
      StickyWindow(#WinMain,stickyState)
      
      CreateMenu(#Menu_1, hWinMain)
      MenuTitle("Sound Output Devices")
      OutDev_1 = #Last_Menu_Item
      NumOutDevs = waveOutGetNumDevs_()
      
      If NumOutDevs <> 0 : NumOutDevs - 1
         For n = OutDev_1 To OutDev_1 + NumOutDevs
            If waveOutGetDevCaps_(n-OutDev_1,@MyOutDevs,SizeOf(WAVEOUTCAPS)) = 0
                  MenuItem(n ,PeekS(@MyOutDevs\szPname))
            EndIf
         Next
         SetMenuItemState(#Menu_1,OutDev_1,#True)
         SetWindowCallback(@WIN_CALLBACK()) ; Handle Sound Output callback
      Else
         MessageRequester("Error!","No audio output device found.")
         result = 0
      EndIf
      
      MenuTitle("Options")
         MenuItem(#MenuItem_ScopeAuto,"Scope Continuous")
         SetMenuItemState(#Menu_1,#MenuItem_ScopeAuto,autoTrig)
         MenuItem(#MenuItem_OnTop,"Always on top")
      
      AddKeyboardShortcut(#WinMain,#PB_Shortcut_Return,#MenuItem_EnterKey)
      
      ; ================= the scopes ======================
      CanvasGadget(#Canvas_Scope_L,290,5,200,101)
      CanvasGadget(#Canvas_Scope_R,500,5,200,101)
      
      imgID_L = CreateImage(0,200,101,24,$1A6A0F)
      imgID_R = CreateImage(1,200,101,24,$1A6A0F)
      For n = 0 To 1 ; draw graticules
         StartDrawing(ImageOutput(n))
            For x = 0 To 200 Step 25 : LineXY(x,0,x,101,0) : Next x
            For y = 0 To 100 Step 25 : LineXY(0,y,200,y,0) : Next y
            If n =0 
               DrawText(5,5,"Left",$00FF00,$1A6A0F)
            Else
               DrawText(5,5,"Right",$00FF00,$1A6A0F)
            EndIf
         StopDrawing()
      Next n
      StartDrawing(CanvasOutput(#Canvas_Scope_L)) : DrawImage(imgID_L,0,0) : StopDrawing()
      StartDrawing(CanvasOutput(#Canvas_Scope_R)) : DrawImage(imgID_R,0,0) : StopDrawing()
      ; =====================================================
      
      ButtonGadget(#Button_Run, 10, 05, 65, 95, "R U N", #PB_Button_Toggle)
      SetGadgetState(#Button_Run,Pause)
      
      SpinGadget(#Spin_F1, 45, 140, 65, 20, 10, 10000, #PB_Spin_Numeric)
      SpinGadget(#Spin_F2, 45, 180, 65, 20, 10, 10000, #PB_Spin_Numeric)
      SpinGadget(#Spin_F3, 45, 220, 65, 20, 10, 10000, #PB_Spin_Numeric)
      SpinGadget(#Spin_F4, 45, 260, 65, 20, 10, 10000, #PB_Spin_Numeric)
     
      FrameGadget(#PB_Any, 80, 0, 200, 50, "Mode")
      FrameGadget(#PB_Any, 130, 110, 150, 180, "Amplitude")
      FrameGadget(#PB_Any, 10, 110, 110, 180, "Frequency")
      FrameGadget(#PB_Any, 290, 110, 200, 180, "Balance")
      FrameGadget(#PB_Any, 500, 110, 200, 180, "SquareWave option")
   
      TrackBarGadget(#Track_Vol_F1, 140, 140, 100, 20, 0, 100)
      TrackBarGadget(#Track_Vol_F2, 140, 180, 100, 20, 0, 100)
      TrackBarGadget(#Track_Vol_F3, 140, 220, 100, 20, 0, 100)
      TrackBarGadget(#Track_Vol_F4, 140, 260, 100, 20, 0, 100)
     
      TrackBarGadget(#Track_Bal_F1, 325, 140, 100, 20, 0, 100)
      TrackBarGadget(#Track_Bal_F2, 325, 180, 100, 20, 0, 100)
      TrackBarGadget(#Track_Bal_F3, 325, 220, 100, 20, 0, 100)
      TrackBarGadget(#Track_Bal_F4, 325, 260, 100, 20, 0, 100)
  
      CheckBoxGadget(#Check_Sq_F1, 510, 140, 20, 20, "  ")
      TrackBarGadget(#Track_Duty_F1, 565, 140, 100, 20, 1, 99)
      CheckBoxGadget(#Check_Sq_F2, 510, 180, 20, 20, "  ")
      TrackBarGadget(#Track_Duty_F2, 565, 180, 100, 20, 1, 99)
      CheckBoxGadget(#Check_Sq_F3, 510, 220, 20, 20, "  ")
      TrackBarGadget(#Track_Duty_F3, 565, 220, 100, 20, 1, 99)
      CheckBoxGadget(#Check_Sq_F4, 510, 260, 20, 20, "  ")
      TrackBarGadget(#Track_Duty_F4, 565, 260, 100, 20, 1, 99)
      
      TrackBarGadget(#Track_Scope, 140, 80, 100, 20, 1, 20)
      
      CheckBoxGadget(#Check_Hop  , 230, 020, 40, 20, "Hop")
      
      OptionGadget(#Option_Mono  , 090, 20, 60, 20, "Mono")
      OptionGadget(#Option_Stereo, 160, 20, 60, 20, "Stereo")
      
      
      SetGadgetColor(TextGadget(#PB_Any, 20, 143, 20, 20, "F1", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 20, 183, 20, 20, "F2", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 20, 223, 20, 20, "F3", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 20, 263, 20, 20, "F4", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
   
      SetGadgetColor(TextGadget(#PB_Any, 300, 143, 20, 20, "L", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 300, 183, 20, 20, "L", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 300, 223, 20, 20, "L", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 300, 263, 20, 20, "L", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 430, 143, 20, 20, "R"),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 430, 183, 20, 20, "R"),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 430, 223, 20, 20, "R"),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 430, 263, 20, 20, "R"),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 535, 143, 25, 20, "Duty", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 535, 183, 25, 20, "Duty", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 535, 223, 25, 20, "Duty", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      SetGadgetColor(TextGadget(#PB_Any, 535, 263, 25, 20, "Duty", #PB_Text_Right),
                     #PB_Gadget_BackColor,WinColor)
      
      SetGadgetColor(TextGadget(#PB_Any, 140, 60, 140, 15, "Scope Horizontal Scale"),
                     #PB_Gadget_BackColor,WinColor)
      
      TextGadget(#Text_Duty_F1, 675, 143, 20, 20, Str(Duty_F1*50/#PI))
         SetGadgetColor(#Text_Duty_F1,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Duty_F2, 675, 183, 20, 20, Str(Duty_F2*50/#PI))
         SetGadgetColor(#Text_Duty_F2,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Duty_F3, 675, 223, 20, 20, Str(Duty_F3*50/#PI))
         SetGadgetColor(#Text_Duty_F3,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Duty_F4, 675, 263, 20, 20, Str(Duty_F4*50/#PI))
         SetGadgetColor(#Text_Duty_F4,#PB_Gadget_BackColor,WinColor)
      
      TextGadget(#Text_Vol_F1, 250, 143, 20, 20, Str(Vol_F1*100))
         SetGadgetColor(#Text_Vol_F1,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Vol_F2, 250, 183, 20, 20, Str(Vol_F2*100))
         SetGadgetColor(#Text_Vol_F2,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Vol_F3, 250, 223, 20, 20, Str(Vol_F3*100))
         SetGadgetColor(#Text_Vol_F3,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Vol_F4, 250, 263, 20, 20, Str(Vol_F4*100))
         SetGadgetColor(#Text_Vol_F4,#PB_Gadget_BackColor,WinColor)
         
      TextGadget(#Text_Bal_F1, 450, 143, 20, 20, Str(Bal_F1*100),#PB_Text_Center)
         SetGadgetColor(#Text_Bal_F1,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Bal_F2, 450, 183, 20, 20, Str(Bal_F2*100),#PB_Text_Center)
         SetGadgetColor(#Text_Bal_F2,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Bal_F3, 450, 223, 20, 20, Str(Bal_F3*100),#PB_Text_Center)
         SetGadgetColor(#Text_Bal_F3,#PB_Gadget_BackColor,WinColor)
      TextGadget(#Text_Bal_F4, 450, 263, 20, 20, Str(Bal_F4*100),#PB_Text_Center)
         SetGadgetColor(#Text_Bal_F4,#PB_Gadget_BackColor,WinColor)
         
      TextGadget(#Text_Scope, 250, 83, 20, 20, Str(Hscale))
         SetGadgetColor(#Text_Scope,#PB_Gadget_BackColor,WinColor)

   EndIf
   
   ProcedureReturn result
EndProcedure

Procedure SCALE_VOLUME()
   Protected.d adj, m
   
   ; wave 1
   m = 32767 / Abs(Bool(Bal_F1<0.5) - Bal_F1)
   adj = m / (4 - (1-Vol_F2) - (1-Vol_F3) - (1-Vol_F4))
   Vol_L1 =  Vol_F1 * adj * (1.0 - Bal_F1)
   Vol_R1 =  Vol_F1 * adj * Bal_F1
   
   ;wave 2
   m = 32767 / Abs(Bool(Bal_F2<0.5) - Bal_F2)
   adj = m / (4 - (1-Vol_F1) - (1-Vol_F3) - (1-Vol_F4))
   Vol_L2 = Vol_F2 * adj * (1.0 - Bal_F2)
   Vol_R2 = Vol_F2 * adj * Bal_F2
   
   ; wave 3
   m = 32767 / Abs(Bool(Bal_F3<0.5) - Bal_F3)
   adj = m / (4 - (1-Vol_F1) - (1-Vol_F2) - (1-Vol_F4))
   Vol_L3 = Vol_F3 * adj * (1.0 - Bal_F3)
   Vol_R3 = Vol_F3 * adj * Bal_F3 
   
   ; wave 4
   m = 32767 / Abs(Bool(Bal_F4<0.5) - Bal_F4)
   adj = m / (4 - (1-Vol_F1) - (1-Vol_F2) - (1-Vol_F3))
   Vol_L4 = Vol_F4 * adj * (1.0 - Bal_F4)
   Vol_R4 = Vol_F4 * adj * Bal_F4
   
   Trig = #True
   
   If pause And *ScopeBuff : MAKE_WAVES(*ScopeBuff) : EndIf
EndProcedure

Procedure INIT_GADGETS()
   SetGadgetState(#Option_Stereo,1)
   SetGadgetState(#Spin_F1,Freq_F1) : SetGadgetText(#Spin_F1,Str(Freq_F1))
   SetGadgetState(#Spin_F2,Freq_F2) : SetGadgetText(#Spin_F2,Str(Freq_F2))
   SetGadgetState(#Spin_F3,Freq_F3) : SetGadgetText(#Spin_F3,Str(Freq_F3))
   SetGadgetState(#Spin_F4,Freq_F4) : SetGadgetText(#Spin_F4,Str(Freq_F4))
   SetGadgetState(#Track_Vol_F1,Vol_F1*100)
   SetGadgetState(#Track_Vol_F2,Vol_F2*100)
   SetGadgetState(#Track_Vol_F3,Vol_F3*100)
   SetGadgetState(#Track_Vol_F4,Vol_F4*100)
   SetGadgetState(#Track_Bal_F1,Bal_F1*100)
   SetGadgetState(#Track_Bal_F2,Bal_F2*100)
   SetGadgetState(#Track_Bal_F3,Bal_F3*100)
   SetGadgetState(#Track_Bal_F4,Bal_F4*100)
   SetGadgetState(#Track_Duty_F1,50) : DisableGadget(#Track_Duty_F1,1)
   SetGadgetState(#Track_Duty_F2,50) : DisableGadget(#Track_Duty_F2,1)
   SetGadgetState(#Track_Duty_F3,50) : DisableGadget(#Track_Duty_F3,1)
   SetGadgetState(#Track_Duty_F4,50) : DisableGadget(#Track_Duty_F4,1)
   SetGadgetState(#Track_Scope,Hscale) : Hscale = 21-Hscale
   
   SetActiveGadget(#Button_Run)
   SCALE_VOLUME()
EndProcedure

Procedure START_SOUND_OUTPUT()
   Protected T,i, *P
   Static *OutBufMem
   
   With PlayFormat
      \wFormatTag      = #WAVE_FORMAT_PCM
      \nChannels       = Channels
      \wBitsPerSample  = BytesPerSample * 8
      \nSamplesPerSec  = SampleClock
      \nBlockAlign     = Channels * BytesPerSample
      \nAvgBytesPerSec = \nSamplesPerSec * \nBlockAlign
   EndWith
   
   BlockSize = #BuffSize * Channels
   
   If *OutBufMem : FreeMemory(*OutBufMem) : EndIf   ; Free a prior assignement
   *OutBufMem = AllocateMemory(BlockSize * nBuf)    ; Reserve memory for all the buffers
   
   T =  waveOutOpen_(@hWaveOut, #WAVE_MAPPER+DevOut, @PlayFormat, WindowID(#WinMain), #True, #CALLBACK_WINDOW | #WAVE_FORMAT_DIRECT)
   If T = #MMSYSERR_NOERROR
      
      *P = *OutBufMem                               ; Pointer to start of memory
      For i = 0 To nBuf-1                           ; For each buffer
         outHdr(i)\lpData         = *P              ; start of buffer
         outHdr(i)\dwBufferLength = BlockSize       ; size of buffer
         outHdr(i)\dwFlags        = 0
         outHdr(i)\dwLoops        = 0
         T | waveOutPrepareHeader_(hWaveOut, outHdr(i), SizeOf(WAVEHDR))
         *P + BlockSize
      Next
      
      For i = 0 To nBuf-1
         PostMessage_(WindowID(#WinMain),#MM_WOM_DONE,0,outHdr(i))
      Next 
      
   EndIf
   
   If T = #MMSYSERR_NOERROR
      If Pause : waveOutPause_(hWaveOut) : EndIf
      ProcedureReturn 1
   Else : ProcedureReturn 0
   EndIf
   
EndProcedure

Procedure STOP_SOUND_OUTPUT()
   Protected i
   waveOutReset_(hWaveOut)
   For i = 0 To nBuf - 1
      waveOutUnprepareHeader_(hWaveOut, outHdr(i), SizeOf(WAVEHDR))
   Next
   waveOutClose_(hWaveOut)
EndProcedure

Procedure PROCESS_RUN_PAUSE()
   ; handle 'Run' button event
   Pause = GetGadgetState(#Button_Run)
   
   If Pause
      waveOutPause_(hWaveOut)
      SetGadgetText(#Button_Run,"R U N")
   Else
      waveOutRestart_(hWaveOut)
      SetGadgetText(#Button_Run,"PAUSE")
   EndIf
EndProcedure

Procedure PROCESS_SPIN(nGad,*Freq)
   Select EventType()
      Case #PB_EventType_Up, #PB_EventType_Down
         PokeI(*Freq, GetGadgetState(nGad))
      Case #Input_Finished, #PB_EventType_LostFocus
         SetGadgetState(nGad,Val(GetGadgetText(nGad)))
         PokeI(*Freq, GetGadgetState(nGad))
   EndSelect
EndProcedure

Procedure PROCESS_FREQUENCY_CHANGE()
   ; handle frequency spin gadget events
   Select EventGadget()
      Case #Spin_F1    : PROCESS_SPIN(#Spin_F1, @Freq_F1)
      Case #Spin_F2    : PROCESS_SPIN(#Spin_F2, @Freq_F2)
      Case #Spin_F3    : PROCESS_SPIN(#Spin_F3, @Freq_F3)
      Case #Spin_F4    : PROCESS_SPIN(#Spin_F4, @Freq_F4)
   EndSelect
   Trig = #True
EndProcedure

Procedure PROCESS_VOLUME_CHANGE()
   Protected gadget = EventGadget(), vol = GetGadgetState(gadget)
   
   Select gadget
      Case #Track_Vol_F1 : SetGadgetText(#Text_Vol_F1,Str(vol)) : Vol_F1 = vol/100
      Case #Track_Vol_F2 : SetGadgetText(#Text_Vol_F2,Str(vol)) : Vol_F2 = vol/100
      Case #Track_Vol_F3 : SetGadgetText(#Text_Vol_F3,Str(vol)) : Vol_F3 = vol/100
      Case #Track_Vol_F4 : SetGadgetText(#Text_Vol_F4,Str(vol)) : Vol_F4 = vol/100
   EndSelect
   SCALE_VOLUME()
EndProcedure

Procedure PROCESS_BALANCE_CHANGE()
   Protected gadget = EventGadget()
   Protected bal = GetGadgetState(gadget)
   Select gadget
      Case #Track_Bal_F1 : SetGadgetText(#Text_Bal_F1,Str(bal)) : Bal_F1 = bal/100
      Case #Track_Bal_F2 : SetGadgetText(#Text_Bal_F2,Str(bal)) : Bal_F2 = bal/100
      Case #Track_Bal_F3 : SetGadgetText(#Text_Bal_F3,Str(bal)) : Bal_F3 = bal/100
      Case #Track_Bal_F4 : SetGadgetText(#Text_Bal_F4,Str(bal)) : Bal_F4 = bal/100
   EndSelect
   SCALE_VOLUME()
EndProcedure

Procedure PROCESS_DUTY_CHANGE()
   Select EventGadget()
      Case #Track_Duty_F1 : Duty_F1  = #PI * 0.02 * GetGadgetState(#Track_Duty_F1)
         SetGadgetText(#Text_Duty_F1,Str(GetGadgetState(#Track_Duty_F1)))
      Case #Track_Duty_F2 : Duty_F2  = #PI * 0.02 * GetGadgetState(#Track_Duty_F2)
         SetGadgetText(#Text_Duty_F2,Str(GetGadgetState(#Track_Duty_F2)))
      Case #Track_Duty_F3 : Duty_F3  = #PI * 0.02 * GetGadgetState(#Track_Duty_F3)
         SetGadgetText(#Text_Duty_F3,Str(GetGadgetState(#Track_Duty_F3)))
      Case #Track_Duty_F4 : Duty_F4  = #PI * 0.02 * GetGadgetState(#Track_Duty_F4)
         SetGadgetText(#Text_Duty_F4,Str(GetGadgetState(#Track_Duty_F4)))
   EndSelect
   SCALE_VOLUME()
EndProcedure

Procedure PROCESS_SQUARE_OPTION()
   Select  EventGadget()
      Case #Check_Sq_F1 : Square_F1 = GetGadgetState(#Check_Sq_F1)
         DisableGadget(#Track_Duty_F1, Square_F1 ! 1)
         Case #Check_Sq_F2 : Square_F2 = GetGadgetState(#Check_Sq_F2)
         DisableGadget(#Track_Duty_F2, Square_F2 ! 1)
         Case #Check_Sq_F3 : Square_F3 = GetGadgetState(#Check_Sq_F3)
         DisableGadget(#Track_Duty_F3, Square_F3 ! 1)
         Case #Check_Sq_F4 : Square_F4 = GetGadgetState(#Check_Sq_F4)
         DisableGadget(#Track_Duty_F4, Square_F4 ! 1)
   EndSelect
   SCALE_VOLUME()
EndProcedure

Procedure PROCESS_HOP_OPTION()
   hop = GetGadgetState(#Check_Hop)
   If Not hop
      Freq_F1 = GetGadgetState(#Spin_F1)
      Freq_F2 = GetGadgetState(#Spin_F2)
      Freq_F3 = GetGadgetState(#Spin_F3)
      Freq_F4 = GetGadgetState(#Spin_F4)
      Trig = #True
   EndIf
EndProcedure

Procedure SWITCH_MODE(mode)
   Static Dim LB(3)
   Protected gadget
   
   If Channels = mode : ProcedureReturn : EndIf
   
   Select mode
      Case #Mono
         STOP_SOUND_OUTPUT() : Channels = #Mono : START_SOUND_OUTPUT()
         For gadget = #Track_Bal_F1 To #Track_Bal_F4
            DisableGadget(gadget,1)
            LB(gadget - #Track_Bal_F1) = GetGadgetState(gadget)
            SetGadgetState(gadget,0)
            PostEvent(#PB_Event_Gadget,#WinMain,gadget)
         Next gadget
      Case #Stereo
         STOP_SOUND_OUTPUT() : Channels = #Stereo : START_SOUND_OUTPUT()
         For gadget = #Track_Bal_F1 To #Track_Bal_F4
            DisableGadget(gadget,0)
            SetGadgetState(gadget,LB(gadget - #Track_Bal_F1))
            PostEvent(#PB_Event_Gadget,#WinMain,gadget)
         Next gadget
   EndSelect
   
   SCALE_VOLUME()
EndProcedure

Procedure CHANGE_SCOPE_SCALE()
   Hscale = 21 - GetGadgetState(#Track_Scope)
   SetGadgetText(#Text_Scope,Str(21-Hscale))
   SCOPE()
EndProcedure

Procedure SET_SCOPE_MODE()
   autoTrig = GetMenuItemState(#Menu_1,#MenuItem_ScopeAuto) ! 1
   SetMenuItemState(#Menu_1,#MenuItem_ScopeAuto,autoTrig)
EndProcedure

Procedure ACTIVATE_STICKY_WINDOW()
   stickyState = GetMenuItemState(#Menu_1,#MenuItem_OnTop) ! 1
   SetMenuItemState(#Menu_1,#MenuItem_OnTop,stickyState)
   StickyWindow(#WinMain,stickyState)
EndProcedure

Procedure PROCESS_OUTPUT_SELECTION()
   Static LastMenuSelection = #Last_Menu_Item
   Protected menuSelection = EventMenu()
   
   If GetMenuItemState(#Menu_1,menuSelection) = #False
      SetMenuItemState(#Menu_1,LastMenuSelection,#False)
      SetMenuItemState(#Menu_1,menuSelection,#True)
      LastMenuSelection = menuSelection
      DevOut = menuSelection - OutDev_1 + 1
      STOP_SOUND_OUTPUT()
      START_SOUND_OUTPUT()
   EndIf
EndProcedure

Procedure PROCESS_ENTER_KEY()
   Protected ActiveGadget = GetActiveGadget()
   Select ActiveGadget
      Case #Spin_F1 To #Spin_F4
         PostEvent(#PB_Event_Gadget,#WinMain,ActiveGadget,#Input_Finished)
   EndSelect
EndProcedure

Procedure EVENT_LOOP()
   Protected event
   
   Repeat
      event = WaitWindowEvent()
      Select event
         Case #PB_Event_Gadget
            Select EventGadget()
               Case #Button_Run : PROCESS_RUN_PAUSE()
               Case #Check_Hop  : PROCESS_HOP_OPTION()
               Case #Spin_F1       To #Spin_F4       : PROCESS_FREQUENCY_CHANGE()
               Case #Track_Vol_F1  To #Track_Vol_F4  : PROCESS_VOLUME_CHANGE()
               Case #Track_Bal_F1  To #Track_Bal_F4  : PROCESS_BALANCE_CHANGE()
               Case #Track_Duty_F1 To #Track_Duty_F4 : PROCESS_DUTY_CHANGE()
               Case #Check_Sq_F1   To #Check_Sq_F4   : PROCESS_SQUARE_OPTION()
               Case #Option_Mono   : SWITCH_MODE(#Mono)
               Case #Option_Stereo : SWITCH_MODE(#Stereo)
               Case #Track_Scope   : CHANGE_SCOPE_SCALE()
            EndSelect
         Case #PB_Event_Menu
            Select EventMenu()
               Case OutDev_1 To OutDev_1 + NumOutDevs : PROCESS_OUTPUT_SELECTION()
               Case #MenuItem_ScopeAuto : SET_SCOPE_MODE()
               Case #MenuItem_OnTop     : ACTIVATE_STICKY_WINDOW()
               Case #MenuItem_EnterKey  : PROCESS_ENTER_KEY()
            EndSelect
      EndSelect

   Until event = #PB_Event_CloseWindow
EndProcedure

If BUILD_GUI()
   INIT_GADGETS()
   If START_SOUND_OUTPUT()
      EVENT_LOOP()
   Else
      MessageRequester("Error!","Unable to activate sound output.")
   EndIf
   STOP_SOUND_OUTPUT()
EndIf
Last edited by BasicallyPure on Sun Sep 13, 2015 3:37 pm, edited 1 time in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Awsome Audio Generator

Post by Joris »

Very nice.

In fact awsome.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Re: Awsome Audio Generator

Post by yrreti »

Really Really Awsome Audio Generator!
Lab worthy work.

Great job BasicallyPure
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Awsome Audio Generator

Post by Kwai chang caine »

Works great on W7
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: Awsome Audio Generator

Post by electrochrisso »

Good stuff BP, thanks for sharing. :)
Any chance you can show how to save some of the generated audio to a WAV file. :?:
PureBasic! Purely the best 8)
Simo_na
Enthusiast
Enthusiast
Posts: 177
Joined: Sun Mar 03, 2013 9:01 am

Re: Awsome Audio Generator

Post by Simo_na »

I had a way to analyze the result of sinewave produced by your new generator, very good work.
Thank you
For what concerns the squarewave, you can be taken reference from the squarewave generated by ARTA by Artalabs

Thanks for sharing 8)
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Awsome Audio Generator

Post by BasicallyPure »

electrochrisso wrote:Any chance you can show how to save some of the generated audio to a WAV file.
Right now I want to spend all of my coding time on another project I am working on.
I will be happy to offer the following suggestions.
1. Try AudioPlayground It allows the creation of wave files.
2. use PureAudioRecorder to record the audio generator sound then save it.

If you want to try and get the audio data from Awesome Audio Generator directly take a look at the WIN_CALLBACK() procedure.
Right after the call to procedure MAKE_WAVES() a global pointer '*ScopeBuff' will point to the current block of audio data and
the variable 'BlockSize' gives the size.
You would need to create a wave header in memory then copy the blocks of audio data after the header.
The code for PureAudioRecorder gives an example of how to create a header, add audio data dynamically following the header, then when
audio capture is done modify the header info to reflect the length of the captured audio data.
Last edited by BasicallyPure on Sun Sep 13, 2015 8:56 pm, edited 1 time in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: Awsome Audio Generator

Post by electrochrisso »

Thanks for the tips BP, looks complicated but I will have a go and see what I can do. :)
PureBasic! Purely the best 8)
Simo_na
Enthusiast
Enthusiast
Posts: 177
Joined: Sun Mar 03, 2013 9:01 am

Re: Awsome Audio Generator

Post by Simo_na »

It is a few days I use your code, good and stable, thanks again.
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Awsome Audio Generator

Post by Stephane Fonteyne »

Hi,

Very nice program.
I like that

I want to see how I can developed an function generator that creates visual and sounds sinewave, trianglewave, puls, squarewave, sawtooth pos and negative slope and that the user can setting the parameters with each waveform like dc offset, amplitude, time, duty cycle, slope, slope time, puls width.

I look know to the examples and the possiblities of PureBasic.

Kind regards
Stephane
Post Reply