Sound-Editing like StartDrawing()

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
jamirokwai
Enthusiast
Enthusiast
Posts: 798
Joined: Tue May 20, 2008 2:12 am
Location: Cologne, Germany
Contact:

Sound-Editing like StartDrawing()

Post by jamirokwai »

Hi there,

I'd like to propose new options for working with sound. Since PB switched to the miniaudio-lib, it might be possible :-)

What, if we could edit audio like images? I mean, do something like (with a better named command than StartSounding():

Code: Select all

define mySound = CreateSound(#pb_any, 2000, 16, 2, 48000) ; 2000 msecs, 16 Bits, Stereo, 48000 Hz

if StartSounding(SoundOutput(mySound)) 
debug SoundBuffer() ; directly access sound-data
debug SoundBufferBitFormat() ; display bits per sample
debug SoundBufferPitch() ; display size of one sample
debug SoundBufferChannels() ; 2 = stereo
debug SoundBufferRate() ; e.g. 48000
StopSounding()
endif
I already wished for some things, as I hit some walls while coding...
Expose more MiniAudio-Functions
Audio-Filter - please try, comment, optimise, notify bugs
pl_mpeg.h and decoding question

Posting the structure of a PB-sound would be a great start.

Addition (2025-02-08) (after some thoughts and the comment by infratec):

Possible functions:

Code: Select all

define mySound = CreateSound(#pb_any, 2000, 16, 2, 48000) ; creates an empty buffer, 2000 msecs, 16 Bits, Stereo, 48000 Hz
ResizeSound(SoundID, newlength_in_msecs) ; make changing bits, channels, samplerate also possible?
SaveSound(SoundID, "export.wav", #pb_soundformat_wav) ; save as .wav as minimum, .ogg, etc. possible?
StartRingBuffer(SoundID) ; prepare a ring buffer
SetRingbufferCallback(@FilterCallback()) ; is called, when a part of the ring buffer has finished playing, so you can fill it again 
CustomSoundFilterCallback(@SoundFilterCallback()) ; like CustomFilterCallback
Last edited by jamirokwai on Sat Feb 08, 2025 10:37 am, edited 2 times in total.
Regards,
JamiroKwai
Quin
Addict
Addict
Posts: 1133
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Sound-Editing like StartDrawing()

Post by Quin »

Massive +1. Being able to generate and play songs entirely from within PB for example all with tones would be great!
threedslider
Enthusiast
Enthusiast
Posts: 397
Joined: Sat Feb 12, 2022 7:15 pm

Re: Sound-Editing like StartDrawing()

Post by threedslider »

Great ! +100
infratec
Always Here
Always Here
Posts: 7618
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Sound-Editing like StartDrawing()

Post by infratec »

And how sounds your CreateSound :?:

What should be inside of the sound?
How you want to specify the sound curve?

At the moment your CreateSound() can create an empty sound which returns silence.

To make something lke that universal, you need a lot of stuff around.
This would result in a synthesizer where you can draw your waves.
But this is not doable inside of a program.

Tools for this:
https://vital.audio/
https://tal-software.com/products/tal-noisemaker

Also OpenMPT can draw own 'samples'
Create new opnempt file, go to samples, press the pencil button, insert siolence, then you can modify the curve.

Or you are restricted to sine, square and saw curves.

I already posted examples how to create such sounds via code.
Last edited by infratec on Sat Feb 08, 2025 10:34 am, edited 1 time in total.
jamirokwai
Enthusiast
Enthusiast
Posts: 798
Joined: Tue May 20, 2008 2:12 am
Location: Cologne, Germany
Contact:

Re: Sound-Editing like StartDrawing()

Post by jamirokwai »

infratec wrote: Sat Feb 08, 2025 10:20 am And how sounds your CreateSound :?:

What should be inside of the sound?
How you want to specify the sound curve?

At the moment your CreateSound() can create an empty sound which returns silence.

To make something lke that universal, you need a lot of stuff around.
This would result in a synthesizer where you can draw your waves.
But this is not doable inside of a program.

A good tool for this:
https://vital.audio/

Or you are restricted to sine, square and saw curves.

I already posted examples how to create such sounds via code.
Yes, create an empty sound, like CreateImage. That sound should be resizable in length and may be exported as a .wav.
I totally agree: Purebasic should only lay the foundation. The coder or user has to be responsible for putting viable sound-data into the buffer, adding effects, filtering, exporting as .ogg, you name it.

I added some function-ideas in the first post.
Regards,
JamiroKwai
infratec
Always Here
Always Here
Posts: 7618
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Sound-Editing like StartDrawing()

Post by infratec »

Your first wish is done.

CreateSound:

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Structure RIFFStructure
  Riff.a[4]
  Length.l
  Wave.a[4]
EndStructure


Structure fmtStructure
  fmt.a[4]
  Length.l
  Format.u
  Channels.u
  SampleRate.l
  BytesPerSecond.l
  BlockAlign.u
  BitsPerSample.u
EndStructure


Structure dataStructure
  Signature.a[4]
  Length.l
EndStructure



Procedure.i CreateSound(Sound.i, Duration.i, Bits.i=16, Channels.i=2, SamplingRate.i=48000)
  
  Protected.i Result, HeaderSize, DataSize
  Protected *WAVBuffer, *RiffPtr.RIFFStructure, *fmtPtr.fmtStructure, *dataPtr.dataStructure, *audioPtr
  
  
  
  HeaderSize = SizeOf(RIFFStructure)
  HeaderSize + SizeOf(fmtStructure)
  HeaderSize + SizeOf(dataStructure)
  
  DataSize = (Bits / 8) * SamplingRate * Duration * Channels / 1000
  
  *WAVBuffer = AllocateMemory(HeaderSize + DataSize, #PB_Memory_NoClear)
  If *WAVBuffer
    
    *RiffPtr = *WAVBuffer
    PokeS(@*RiffPtr\Riff, "RIFF", 4, #PB_Ascii|#PB_String_NoZero)
    *RiffPtr\Length = HeaderSize + DataSize - 8
    PokeS(@*RiffPtr\Wave, "WAVE", 4, #PB_Ascii|#PB_String_NoZero)
    
    *fmtPtr = *WAVBuffer + SizeOf(RIFFStructure)
    PokeS(@*fmtPtr\fmt, "fmt ", 4, #PB_Ascii|#PB_String_NoZero)
    *fmtPtr\Length = SizeOf(fmtStructure) - 8
    *fmtPtr\Format = 1
    *fmtPtr\Channels = Channels
    *fmtPtr\SampleRate = SamplingRate
    *fmtPtr\BitsPerSample = Bits
    *fmtPtr\BlockAlign = *fmtPtr\Channels * ((*fmtPtr\BitsPerSample + 7) / 8)
    *fmtPtr\BytesPerSecond = *fmtPtr\SampleRate * *fmtPtr\BlockAlign
    
    *dataPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure)
    PokeS(@*dataPtr\Signature, "data", 4, #PB_Ascii|#PB_String_NoZero)
    *dataPtr\Length = DataSize
    
    *audioPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure) ; just behind the wav header
    
;     If CreateFile(0, "test.wav")
;       WriteData(0, *WAVBuffer, MemorySize(*WAVBuffer))
;       CloseFile(0)
;     EndIf
    
    Result = CatchSound(Sound, *WAVBuffer)
    FreeMemory(*WAVBuffer)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  
  Define Sound.i, Start.q
  
  InitSound()
  
  Sound = CreateSound(#PB_Any, 2000, 16, 2, 48000) ; 2000 msecs, 16 Bits, Stereo, 48000 Hz
  If Sound
    Debug "Sound Created and playing"
    PlaySound(Sound)
    Start = ElapsedMilliseconds()
    
    While SoundStatus(Sound) = #PB_Sound_Playing
      Delay(1)
    Wend
    Debug "Duration: " + Str(ElapsedMilliseconds() - Start) + "ms"
    
    FreeSound(Sound)
  Else
    Debug "Was not able to create sound."
  EndIf
  
CompilerEndIf
You can check the result by comment out the writing to file and open it with AudaCity.
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: Sound-Editing like StartDrawing()

Post by Mijikai »

+1
Post Reply