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

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

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
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
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.