Page 1 of 1

Generating Live Audio

Posted: Fri Dec 27, 2024 6:40 pm
by matalog
I have asked a similar question before, just asking to see if anyone has a little example of Purebasic being used to generate an audio output live - and not saving to an audio file first.

To be honest I really just want to play a sine/square/triangle wave out of the PC speakers with the hope of making some type of PCM later.

I know idle mentioned that they had 97% completed something working after a full day of trying.

Does anyone have anything like this?

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 7:11 pm
by wilbert
Years ago I have used PortAudio for generating audio.
"miniaudio" can also used for something like this.
I hope Fred will add a PB command in the future for generating audio with a callback to supply the audio samples.
Especially since newer versions of PureBasic already use "miniaudio" internally.

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 8:05 pm
by idle
Portaudio is the easiest I will post links later.

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 8:32 pm
by Sicro
https://github.com/Dadido3/Audio
German forum thread: https://www.purebasic.fr/german/viewtopic.php?t=28447
There is no thread in this English forum.

I also have it in my code archive:
PB-CodeArchiv-Rebirth/Sound/AudioIN_OUT[Win]/

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 8:33 pm
by dfw1417
:wink: Great Example Located:

Type "Awesome Audio Generator" into the Search.

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 9:08 pm
by matalog
dfw1417 wrote: Fri Dec 27, 2024 8:33 pm :wink: Great Example Located:

Type "Awesome Audio Generator" into the Search.
That actually is Awesome! Thanks for sharing it.

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 9:12 pm
by matalog
Sicro wrote: Fri Dec 27, 2024 8:32 pm https://github.com/Dadido3/Audio
German forum thread: https://www.purebasic.fr/german/viewtopic.php?t=28447
There is no thread in this English forum.

I also have it in my code archive:
PB-CodeArchiv-Rebirth/Sound/AudioIN_OUT[Win]/
Hi Sicro, I have downloaded your Sound folder and the sine example is pretty awesome too! Thanks for sharing your work.

Re: Generating Live Audio

Posted: Fri Dec 27, 2024 10:48 pm
by matalog
matalog wrote: Fri Dec 27, 2024 9:12 pm
Sicro wrote: Fri Dec 27, 2024 8:32 pm https://github.com/Dadido3/Audio
German forum thread: https://www.purebasic.fr/german/viewtopic.php?t=28447
There is no thread in this English forum.

I also have it in my code archive:
PB-CodeArchiv-Rebirth/Sound/AudioIN_OUT[Win]/
Hi Sicro, I have downloaded your Sound folder and the sine example is pretty awesome too! Thanks for sharing your work.
Sicro, I have been amending your Sine example to become an LFO, when I set it to change frequency+1 each step it is smooth but slow. If I Set it to frequency+10 at each step it is faster and smoothish, and when I set it to frequency+100 it is fast but obviously low resolution.

I'm sure that PB can be fast enough to change the frequency speed fast enough, because I'm sure I have got a 16MHz Arduino to do it. What would I need to amend to make an LFO program run correctly to change the Frequency and update the change of Frequency faster?

This is what I have amended your Sine Example to as an example of fast enough, but not enough resolution:

The variable I change is called 'add' and it can be positive or negative to add or take away. It's as if the program will always only change the variable Frequency once every Frame or something, unlike graphics, audio could be required to be update faster.

Code: Select all

EnableExplicit

; ##################################################### Includes ####################################################

XIncludeFile "Includes/AudioOut.pbi"

; ##################################################### Prototypes ##################################################

; ##################################################### Structures ##################################################

; ##################################################### Constants ###################################################

#Samplerate = 44100
Global add=100
; ##################################################### Structures ##################################################

Structure Main
  *AudioOut
  
  Quit.i
EndStructure
Global Main.Main

Structure Main_Window
  ID.i
  
  TrackBar.i [10]
  TextG.i [10]
  Timer.i
EndStructure
Global Main_Window.Main_Window

; ##################################################### Variables ###################################################

Global Frequency.d = 1000
Global Amplitude.d = 0.25

; ##################################################### Procedures ##################################################

Procedure Main_Window_Open()
  Main_Window\ID = OpenWindow(#PB_Any, 0, 0, 800, 200, "AudioOut Example", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
  AddWindowTimer(Main_Window\ID,Main_Window\Timer,1)
  If Main_Window\ID
    
    Main_Window\TrackBar[0] = TrackBarGadget(#PB_Any, 10, 10, 780, 30, 0, 2000)
    Main_Window\TextG[0] = TextGadget(#PB_Any,10,40,780,30,"Freq = "+Str(Frequency))
    SetGadgetState(Main_Window\TrackBar[0], Frequency)
    
    Main_Window\TrackBar[1] = TrackBarGadget(#PB_Any, 10, 70, 780, 30, 0, 1000)
    SetGadgetState(Main_Window\TrackBar[1], Amplitude*1000)
    
  EndIf
EndProcedure

Procedure Notifier_CallBack(*AudioOut)
  Protected *Temp, Temp_Size.i
  Static Rotation.d
  
  While AudioOut::GetQueuedBlocks(*AudioOut) <= 3
    
    Temp_Size = AudioOut::GetBufferBlocksize(*AudioOut)
    If Temp_Size > 0
      *Temp = AllocateMemory(Temp_Size)
      
      Define Left.d, Right.d, i
      For i = 0 To Temp_Size / 4 - 1
        Left = Sin(Rotation) * Amplitude
        Right = Sin(Rotation) * Amplitude
        
        PokeW(*Temp + i*4    , Left*32767)
        PokeW(*Temp + i*4 + 2, Right*32767)
        
        Rotation + 2.0*#PI / #Samplerate * Frequency
      Next
      
      AudioOut::Write_Data(Main\AudioOut, *Temp, Temp_Size)
      
      FreeMemory(*Temp)
    EndIf
    
  Wend
EndProcedure

Procedure changefreq()
  Frequency=Frequency+add
  If Frequency>2000 Or Frequency<=0
    add=-add
  EndIf
  EndProcedure

; ##################################################### Initialisation ##############################################

Main_Window_Open()

AudioOut::GetDevices()

ForEach AudioOut::Device()
 ; Debug PeekS(AudioOut::@Device()\szPname)
Next

Main\AudioOut = AudioOut::Initialize(#WAVE_MAPPER, #Samplerate, 2, 16, @Notifier_CallBack())

If Not Main\AudioOut
 ; Debug AudioOut::GetError()
  End
EndIf

Notifier_CallBack(Main\AudioOut)

; ##################################################### Main ########################################################

Repeat
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_Timer
        changefreq()
      Case #PB_Event_Gadget
        Select EventGadget()
          Case Main_Window\TrackBar[0]
            Frequency = GetGadgetState(Main_Window\TrackBar[0])
            SetGadgetText(Main_Window\TextG[0],"Freq = "+Str(Frequency))
            
          Case Main_Window\TrackBar[1]
            Amplitude = GetGadgetState(Main_Window\TrackBar[1]) / 1000
            

            
            
        EndSelect
        
      Case #PB_Event_CloseWindow
        Main\Quit = #True
        
      Case 0
        Break
    EndSelect
  ForEver
  
Until Main\Quit

; ##################################################### End #########################################################

AudioOut::Deinitialize(Main\AudioOut)

Re: Generating Live Audio

Posted: Sat Dec 28, 2024 9:51 am
by pjay
It's not recommended to use event-based timers for any realtime work as they're low priority - Your 1ms timeout request could be only firing every 20ms or so.

Try placing your frequency change code directly into the main callback.