It is currently Thu Oct 17, 2019 11:46 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sat Feb 23, 2013 6:27 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Thu Mar 24, 2011 12:40 am
Posts: 534
Location: Iowa, USA
This was built using modified core procedures from my application, AudioPlayground

This include file will allow you to add sounds to your programs without any external sound files.
You will have a new command: CreateSound().

Syntax:
Result = CreateSound(#sound, [frequency.f], [duration.f], [amplitude], [sweepStop.f], [waveform], [fadeIn], [fadeOut])

#sound { The number to identify the new sound. #PB_Any can be used to auto-generate this number. }
frequency { The frequency in hertz of the new sound. Default = 440. Range = 20 to sample rate / 2 - 1 }
duration { The length of the new sound in seconds. Default = 1.0 seconds. Minimum = 0.1 seconds. }
amplitude { the peak waveform magnitude from 0 to 100 (full scale). Default = 25 }
sweepStop { Sets the final frequency of a frequency sweep. Default = 0 (sweep disabled). Range is same as frequency. }
waveform { Selects 1 of 9 different waveforms. Default = #WF_Sinewave. }
............ { possible waveforms are #WF_Sinewave, #WF_SawTooth, #WF_BuzzSaw, #WF_SquareWave, #WF_Triangle, #WF_Chunosta,
............ #WF_Organ, #WF_Noise, #WF_GuidedNoise }
fadeIn { turns the fadeIn effect on/off. Default (0) = off , (1) = on }
fadeOut { turns the fadeOut effect on/off. Default (0) = off , (1) = on }

Edit: SoundEasy.pbi version 2.0
.......... InitAudioBuffer() is no longer needed in your code.
.......... This is now automatically handled by the CreateSound() procedure.
.......... A new procedure: SetSoundParameters() has been added.
.......... You will not need this procedure unless you want to change the default wav sound settings: sample rate, resolution, channels.

Edit: made compatible with EnableExplicit.

Here is a demo and the 'SoundEasy' include file.

Code:
; Demo of SoundEasy.pbi include file.
; Demonstrates the CreateSound() command.
; Author: BasicallyPure
; Date:   2.24.2013

IncludeFile "SoundEasy.pbi"

flags.i = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(0, 0, 0, 225, 105, "CreateSound() Demo", flags) And InitSound()
   playButton_1.i = ButtonGadget(#PB_Any,10,10,100,25,"Play Sound 1")
   playButton_2.i = ButtonGadget(#PB_Any,10,40,100,25,"Play Sound 2")
   playButton_3.i = ButtonGadget(#PB_Any,10,70,100,25,"Play Sound 3")
   
   ; Refer to the comments in the SoundEasy.pbi file for the correct CreateSound() syntax.
   snd_1.i = CreateSound(#PB_Any, 500, 2.5, 45, 1500, #WF_Triangle, 0, 1)
   snd_2.i = CreateSound(#PB_Any, 1000) ; a simple sine wave 1000 Hz, 1 second
   snd_3.i = CreateSound(#PB_Any, 800, 0.5, 10, 100, #WF_BuzzSaw, 1, 0)
   
   Repeat
      event = WaitWindowEvent()
      If event = #PB_Event_Gadget
         Select EventGadget()
            Case playButton_1
               If IsSound(snd_1) : PlaySound(snd_1) : EndIf
            Case playButton_2
               If IsSound(snd_2) : PlaySound(snd_2) : EndIf
            Case playButton_3
               If IsSound(snd_3) : PlaySound(snd_3) : EndIf
         EndSelect
      EndIf
   Until event = #PB_Event_CloseWindow
   
EndIf


Here is the include file.
Code:
; Title:   SoundEasy.pbi
; Author:  BasicallyPure
; Date:    2.26.2013
; Date:    5.13.2016 edit: made EnableExplicit compatible
; Version: 2.1
; OS:      Windows, Linux, and Mac
; PB ver.  5.10
;
; Save this code with the filename "SoundEasy.pbi"
; Use IncludeFile "SoundEasy.pbi" in your code.
; You will have two new procedures you can use in your programs.
;
; 1. CreateSound(#sound, [frequency.f], [duration.f], [amplitude], [sweepStop.f], [waveform], [fadeIn], [fadeOut])
;    Refer to the comments in the CreateSound() procedure for a description of the syntax.
;
; 2. SetSoundParameters(sampleRate, resolution, channels)
;    You do not need to use this procedure unless you want to change the default sound parameters.
;    Refer to the comments in the SetSoundParameters() procedure for a description and syntax.
;

;{ waveform styles
Enumeration
   #WF_SineWave
   #WF_SawTooth
   #WF_BuzzSaw
   #WF_SquareWave
   #WF_Triangle
   #WF_Chunosta
   #WF_Organ
   #WF_Noise
   #WF_GuidedNoise
EndEnumeration
;}

Procedure SetSoundParameters(sampleRate = 44100, resolution = 2, channels = 1)
   ; use this procedure only if you need to change the default sound paramaters.
   ; sampleRate  { number of samples per second: 5512, 11025, 22050, 44100 only}
   ; resolution  { bytes per sample   (1 [8 bits] Or 2 [16 bits] only) }
   ; channels    { number of channels (1 [ mono ] Or 2 [ stereo] only) }
   
   Static sr = 44100, res = 2, ch = 1
   
   If sampleRate < 0
      Select sampleRate
         Case -1 ; return sampleRate
            ProcedureReturn sr
         Case -2 ; return resolution
            ProcedureReturn res
         Case -3 ; return number of channels
            ProcedureReturn ch
         Default
            ProcedureReturn 0
      EndSelect
   Else
      If     sampleRate <= 5512  : sr = 5512
      ElseIf sampleRate <= 11025 : sr = 11025
      ElseIf sampleRate <= 22050 : sr = 22050
      Else : sr = 44100          : EndIf
     
      If resolution <= 1 : res = 1 : Else : res = 2 : EndIf
      If channels   <= 1 : ch  = 1 : Else : ch  = 2 : EndIf
   EndIf
   
   ProcedureReturn 1
EndProcedure

Procedure.f InitAudioBuffer(duration.f = 10)
   
   ; purpose: create an empty PCM Wave format audio buffer in memory
   ; duration {sound buffer length in seconds}
   ; procedure returns a pointer that is the beginning of the wave sound header.
   ; this procedure is not intended to be used outside of this include file.
   
   Static *audBuff, length.f = 10
   Protected.i Fr, By, Nc
   
   If duration < 0
      Select duration
         Case -1 : ProcedureReturn *audBuff
         Case -2 : ProcedureReturn length
         Default : ProcedureReturn 0
      EndSelect
   Else
      length = duration
   EndIf
     
   If length < 0.1 : length = 0.1 : EndIf
   
   Fr = SetSoundParameters(-1) ; get samples per second
   By = SetSoundParameters(-2) ; get resolution { 1 byte or 2 byte }
   Nc = SetSoundParameters(-3) ; get number of channels
   
   ; calculations to complete the header info.
   Protected.l Av = Fr * By * Nc      ; average bytes per second
   Protected.w Ba = Nc *  By          ; block align
   Protected.w Bs = 08 *  By          ; bits per sample
   Protected.l Ns = Fr * length       ; total number of blocks
   Protected.l Nb = Ns * By * Nc      ; total number of audio bytes
   Protected.l Cs = 36 + By * Nc * Ns ; total chunk size (file size - 8)
   If Cs & 1 ; add pad byte if needed to make even number
      Cs + 1
   EndIf
   
   ; set a pointer to the first byte in the header DataSection
   Protected *waveHdr = ?wavHeader
   
   ; modify the default wave header as specified by the calculated parameters above
   PokeL(*waveHdr + 04, Cs) ; total size
   PokeW(*waveHdr + 22, Nc) ; number of channels
   PokeL(*waveHdr + 24, Fr) ; samples per second
   PokeL(*waveHdr + 28, Av) ; average bytes per second
   PokeW(*waveHdr + 32, Ba) ; block align
   PokeW(*waveHdr + 34, Bs) ; bits per sample
   PokeL(*waveHdr + 40, Nb) ; number of audio bytes
   
   If *audBuff : FreeMemory(*audBuff) : EndIf
   
   ; create space in memory for the audio data
   *audBuff = AllocateMemory(Cs + 8)
   
   If By = 1 ; 1 byte (8 bit) samples are unsigned so offset to 1/2 of full scale
      FillMemory(*audBuff, MemorySize(*audBuff), $80, #PB_Byte)
   ElseIf By = 2 ; 2 byte (16 bit) samples are signed so no offset is needed
      FillMemory(*audBuff, MemorySize(*audBuff), $0000, #PB_Word)
   EndIf
   
   ; put header information at the begining of sound buffer
   CopyMemory(*waveHdr,*audBuff,44)
   
   ProcedureReturn *audBuff ; return a pointer to the first byte
   
   DataSection ; don't change anything here
      wavHeader: ; placeholder values for header info.
      ; Master chunk (12 bytes) ;x xxxxx, offset
      Data.a 'R','I','F','F'    ;4 bytes, 0, chunk ID, "RIFF"
      Data.l $00000000          ;4 bytes, 4, (total file size - 8) = Cs
      Data.a 'W','A','V','E'    ;4 bytes, 8, wave ID, "WAVE"
     
      ; Format chunk (24 bytes)
      Data.a 'f','m','t',' '    ;4 bytes, 12, chunk ID "fmt "
      Data.l $00000010          ;4 bytes, 16, this chunk size = 16, (2+2+4+4+2+2)
      Data.w $0001              ;2 bytes, 20, Wave_Format_PCM
      Data.w $0000              ;2 bytes, 22, number fo channels, Nc
      Data.l $00000000          ;4 bytes, 24, samples per second, Fr
      Data.l $00000000          ;4 bytes, 28, avg bytes per second, Fr*By*Nc
      Data.w $0000              ;2 bytes, 32, block align, By*Nc
      Data.w $0000              ;2 bytes, 34, bits per sample, 8*By
     
      ; Begin data chunk (8 bytes)
      Data.a 'd','a','t','a'    ;4 bytes, 36, chunk ID, "data"
      Data.l $00000000          ;4 bytes, 40, number of audio bytes, By*Nc*Ns
   EndDataSection
   
EndProcedure

Procedure CreateSound(soundNum, frequency.f = 440, duration.f = 1.0, amplitude = 25, sweepStop.f = 0, waveform = #WF_SineWave, FadeIn = 0, FadeOut = 0)
   
   ; Syntax:
   ; Result = CreateSound(#sound, [frequency.f], [duration.f], [amplitude], [sweepStop.f], [waveform], [fadeIn], [fadeOut])
   ;
   ; #sound    { The number to identify the new sound. #PB_Any can be used to auto-generate this number. }
   ; frequency { The frequency in hertz of the new sound.  Default = 440.  Range = 20 to sample rate / 2 - 1
   ; duration  { The length of the new sound in seconds.  Default = 1.0 seconds. Minimum = 0.1 seconds.
   ; amplitude { the peak waveform magnitude from 0 to 100 (full scale).  Default = 25 }
   ; sweepStop { Sets the final frequency of a frequency sweep. Default = 0 (sweep disabled). Range is same as frequency.
   ; waveform  { Selects 1 of 9 different waveforms. Default = #WF_Sinewave. }
   ;           { possible waveforms are #WF_Sinewave, #WF_SawTooth, #WF_BuzzSaw, #WF_SquareWave, #WF_Triangle, #WF_Chunosta, #WF_Organ, #WF_Noise, #WF_GuidedNoise }
   ; fadeIn    { turns the fadeIn  effect on/off.  Default (0) = off , (1) = on }
   ; fadeOut   { turns the fadeOut effect on/off.  Default (0) = off , (1) = on }
   
   If duration < 0.1 : duration = 0.1 : EndIf
   If duration <> InitAudioBuffer(-2) : InitAudioBuffer(duration) : EndIf
   
   Protected *buffer = InitAudioBuffer(-1)
   
   If *buffer = 0 : ProcedureReturn 0 : EndIf
   
   Protected Nc.w = PeekW(*buffer + 22)   ; Nc {is number of channels}
   Protected Fr.l = PeekL(*buffer + 24)   ; Fr {is samples per second}
   Protected By.w = PeekW(*buffer + 34)/8 ; By {is bytes per sample (1 = 8 bits, 2 = 16 bits)}
   Protected Ba = Nc * By ; block align (bytes per block)
   
   Protected doSweep = #False : If sweepStop <> 0 : doSweep = #True : EndIf
   
   Static PIx2.f = #PI * 2
   Static HalfPI.f = #PI / 2
   
   If frequency >= Fr/2 ; maximum frequency is set by sample rate
      frequency = Fr/2 - 1
   ElseIf frequency < 20
      frequency = 20
   EndIf
   
   ; tweak frequency so waveform loops without glitches
   frequency = Round(frequency * duration,#PB_Round_Nearest)/duration
   
   If amplitude > 100 : amplitude = 100
   ElseIf amplitude < 0 : amplitude = 0
   EndIf
   
   If FadeIn  <> 0 : FadeIn  = 1 : EndIf
   If FadeOut <> 0 : FadeOut = 1 : EndIf
   Protected Fade = FadeIn | FadeOut << 1
   
   Protected *audioStart = *buffer + 44 ; pointer to the first audio data byte
   Protected *n = *audioStart
   Protected audBuffSize = MemorySize(*buffer) ; number of bytes in sound buffer
   Protected *audBuffEnd = *buffer + audBuffSize - 1 ; pointer to last byte in buffer
   
   If doSweep = #True
      Protected.f frequencyStep, frequencyThisInstant, frequencySpan, averageFrequency
     
      If sweepStop >= Fr/2
         sweepStop = Fr/2 - 1
      ElseIf sweepStop < 20
         sweepStop = 20
      EndIf
     
      ; linear sweep
      averageFrequency = (frequency + sweepStop) / 2
      averageFrequency = Round(averageFrequency * duration, #PB_Round_Nearest) / duration
      sweepStop = 2 * averageFrequency - frequency
     
      frequencySpan = sweepStop - frequency
   EndIf
   
   ; calculate the number of audio bytes
   Protected byteCount.l = duration * Fr * By * Nc
   If byteCount & 1 : byteCount + 1 : EndIf ; byteCount must be even number
   PokeL(*buffer + 40, byteCount)
   
   Protected.w value ; waveform magnitude at any instant in time
   Protected.f angStp = frequency / Fr * PIx2 ; angle step size in radians
   Protected.f ang = 0 ; starting angle (radians)
   Protected.i loops = byteCount / Ba ; number of loop iterations
   Protected.i loopCount = 0 ; loop counter
   Protected.f lastVal, bias ; used for guided noise
   
   If doSweep = #True : frequencyStep = frequencySpan / loops : EndIf
   
   ; if waveform formulas produce values from -1 to +1 use this scale factor
   Protected sf.f = (Pow(2,8*By)/2 - 1) * (amplitude / 100)
   
   ; adjustments for other waveforms
   Select waveform
      Case #WF_Chunosta
         sf * (1/(Sin(ACos(1/Sqr(3)))*Sin(2*ACos(1/Sqr(3)))))
         ang + HalfPI
      Case #WF_Organ
         sf / 2.25
      Case #WF_GuidedNoise
         sf / 2
      Case #WF_Triangle
         ang + HalfPI
      Case #WF_SawTooth, #WF_BuzzSaw
         ang + #PI
   EndSelect
   
   While loopCount < loops
      Select waveform
         Case #WF_SineWave
            value = Sin(ang) * sf
         Case #WF_SawTooth
            value = (ang-#PI) / #PI * sf
         Case #WF_BuzzSaw
            value = Pow(Abs((ang-#PI)/#PI), #PI) * Sign(ang-#PI) * sf
         Case #WF_SquareWave
            value = Sign(#PI-ang) * sf
         Case #WF_Triangle
            value = ((ang-#PI)/HalfPI * Sign(#PI-ang) + 1) * sf
         Case #WF_Chunosta
            value = Sin(ang) * Sin(2*ang) * sf
         Case #WF_Organ
            value = (Sin(ang) + Sin(2*ang) + Sin(4*ang)) * sf
         Case #WF_Noise
            value = sf * (((Random($7FFFFFFD)+1) / $40000000) - 1)
         Case #WF_GuidedNoise
            bias = (Sin(ang) - lastVal) * 0.5
            lastVal + ((Random($7FFFFFFD) / $40000000) - 1) + bias
            value = lastVal * sf
         Default
            ProcedureReturn 0 ; waveform was invalid
      EndSelect
     
      Select Fade
         Case %01 ; fade in
            value * (0.0 + loopCount / loops)
         Case %10 ; fade out
            value * (1.0 - loopCount / loops)
         Case %11 ; fade in & fade out
            value << 2 * (1.0 - loopCount / loops) * (loopCount / loops)
      EndSelect
     
      If By = 1 ; 8 bits/sample
         PokeA(*n, value+$80) ; left/mono
         If Nc = 2 ; stereo
            PokeA(*n+1, value+$80) ; right
         EndIf
      Else ; 16 bits/sample
         PokeW(*n, value) ; left/mono
         If Nc = 2 ; stereo
            PokeW(*n+2,value) ; right
         EndIf
      EndIf
      If doSweep
         frequencyThisInstant = loopCount * frequencyStep + frequency
         angStp = frequencyThisInstant / Fr * PIx2
      EndIf
      ang + angStp
      If ang > PIx2 : ang - PIx2  : EndIf
      *n + Ba ; point to the next audio sample
      If *n > *audBuffEnd : Break : EndIf
      loopCount + 1
   Wend
   
   ProcedureReturn CatchSound(soundNum, *buffer)
   
EndProcedure

_________________
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.


Last edited by BasicallyPure on Fri May 13, 2016 11:50 pm, edited 5 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sat Feb 23, 2013 6:37 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3479
Location: Netherlands
Quote:
Code:
; Title:   SoundEasy.pbi
; Author:  BasicallyPure
; Date:    2.22.2013
; Version: 1.0
; OS:      Windows, Linux, and probably Mac
; PB ver.  5.10

You can remove the probably part.
It works fine on Mac both x86 and x64. :)

It would be nice if PureBasic had some sort of Music Macro Language
http://en.wikipedia.org/wiki/Music_Macro_Language
The first computer I programmed on (a MSX system) had a very nice Play command that made it easy to play simple 3-channel tunes.

_________________
macOS 10.15 Catalina, PB 5.71 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sat Feb 23, 2013 7:12 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Thu Mar 24, 2011 12:40 am
Posts: 534
Location: Iowa, USA
wilbert wrote:
You can remove the probably part.

Done.

Here is another demo that shows how SetSoundFrequency() changes the pitch and duration of a sound.
SetSoundFrequency() is really changing the playback sample rate so the sound duration changes as well as the pitch.
To hear a sound at the same pitch as it was created you need to use the original sample rate with SetSoundFrequency()
Example: if the original sound sample rate was 44100 (the default for SoundEasy) you would use SetSoundFrequency(44100).

This demo requires PB 5.10 and windows OS.
For older versions of PB rename SetSoundFrequency() to SoundFrequency().

BP.

Code:
; Demo II of SoundEasy.pbi
; Demonstrates the CreateSound() command.
; This demo may ony work with windows because it uses the SetSoundFrequency() command.
; If your version of PureBasic is older than 5.10 you must rename SetSoundFrequency() to SoundFrequency().
; Author: BasicallyPure
; Date:   2.24.2013

IncludeFile "SoundEasy.pbi"

flags.i = #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget
If OpenWindow(0, 0, 0, 325, 105, "CreateSound() Demo II", flags) And InitSound()
   check_1.i = CheckBoxGadget(#PB_Any,10,10,100,25,"Play Sound 1")
   check_2.i = CheckBoxGadget(#PB_Any,10,40,100,25,"Play Sound 2")
   check_3.i = CheckBoxGadget(#PB_Any,10,70,100,25,"Play Sound 3")
   track_1.i = TrackBarGadget(#PB_Any,105,10,200,25,10,210) : SetGadgetState(track_1,100)
   track_2.i = TrackBarGadget(#PB_Any,105,40,200,25,10,210) : SetGadgetState(track_2,100)
   track_3.i = TrackBarGadget(#PB_Any,105,70,200,25,10,210) : SetGadgetState(track_3,100)
   
   ; Refer to the comments in the SoundEasy.pbi file for the correct CreateSound() syntax.
   snd_1.i = CreateSound(#PB_Any, 200, 2.5, 45, 1000, #WF_Organ, 0, 1)
   snd_2.i = CreateSound(#PB_Any, 1000) ; a simple sine wave 1000 Hz, 1 second
   snd_3.i = CreateSound(#PB_Any, 800, 0.5, 15, 100, #WF_BuzzSaw, 1, 0)
   
   Repeat
      event = WaitWindowEvent()
      If event = #PB_Event_Gadget
         Select EventGadget()
            Case check_1
               If GetGadgetState(check_1)
                  If IsSound(snd_1) : PlaySound(snd_1,#PB_Sound_Loop) : EndIf
               Else
                  StopSound(snd_1)
               EndIf
            Case check_2
               If GetGadgetState(check_2)
                  If IsSound(snd_2) : PlaySound(snd_2,#PB_Sound_Loop) : EndIf
               Else
                  StopSound(snd_2)
               EndIf
            Case check_3
               If GetGadgetState(check_3)
                  If IsSound(snd_3) : PlaySound(snd_3,#PB_Sound_Loop) : EndIf
               Else
                  StopSound(snd_3)
               EndIf
            Case track_1
               SetSoundFrequency(snd_1, 441 * GetGadgetState(track_1))
            Case track_2
               SetSoundFrequency(snd_2, 441 * GetGadgetState(track_2))
            Case track_3
               SetSoundFrequency(snd_3, 441 * GetGadgetState(track_3))
         EndSelect
      EndIf
   Until event = #PB_Event_CloseWindow
   
EndIf

_________________
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.


Last edited by BasicallyPure on Mon Feb 25, 2013 4:19 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sat Feb 23, 2013 9:35 pm 
Offline
Addict
Addict

Joined: Fri Nov 09, 2012 11:04 pm
Posts: 1681
Location: Uttoxeter, UK
BP:

Thanks for sharing.

Never tried music; always felt a bit daunted.
Thanks to you I'll now find it a whole lot easier. :D

_________________
DE AA EB


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sat Feb 23, 2013 9:40 pm 
Offline
Addict
Addict
User avatar

Joined: Fri Jan 21, 2011 8:25 am
Posts: 1021
Location: 'stralia!
Nice. :)

Play all three sounds at the same time on high and you got yourself
a really nasty ring tone for an alarm clock. :mrgreen:

_________________
Image
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sun Feb 24, 2013 9:13 am 
Offline
Enthusiast
Enthusiast

Joined: Fri Oct 16, 2009 10:12 am
Posts: 594
Location: BE
Thanks for sharing BasicallyPure.
Works great !
(after disabling the mute on my soundsystem...)

_________________
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sun Feb 24, 2013 12:02 pm 
Offline
Administrator
Administrator

Joined: Fri May 17, 2002 4:39 pm
Posts: 13622
Location: France
Cool stuff !


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Sun Feb 24, 2013 2:36 pm 
Offline
Addict
Addict
User avatar

Joined: Mon May 26, 2003 3:07 pm
Posts: 1477
Location: Nantes
Hi,
It's really a usefull function.

can you add a CreateMemorySound() function ?

_________________
Imagewin8.1 x64 5.31 | IDE | PB plugin | Tools | Sprite | JSON | visual tool


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 4:28 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Thu Mar 24, 2011 12:40 am
Posts: 534
Location: Iowa, USA
eddy wrote:
can you add a CreateMemorySound() function ?

I don't know. Can you describe what a 'CreateMemorySound' function is?

To everyone, if you have saved this previously, you might want to get the latest version.
I have made a major change in the include file code.
You no longer have to use InitAudioBuffer() in your program before you can use CreateSound().

BP.

_________________
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 9:48 am 
Offline
Enthusiast
Enthusiast

Joined: Fri Oct 16, 2009 10:12 am
Posts: 594
Location: BE
Noticed and done.

Thanks again BP, really great stuff.
(It's gonna be of great use here, but not right now...)

_________________
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 8:21 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Thu Jun 26, 2003 2:09 am
Posts: 744
Location: Spain (Galicia)
Hi BP:
Very good job!

Is there a way to change the sound frequency of a created sound?
I'm trying your SoundEasy code to obtain a sound to replace the base sound on this example,http://www.purebasic.fr/english/viewtopic.php?f=12&t=53676, but without success.
Cheers!


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 10:43 pm 
Offline
Addict
Addict
User avatar

Joined: Mon May 26, 2003 3:07 pm
Posts: 1477
Location: Nantes
BasicallyPure wrote:
eddy wrote:
can you add a CreateMemorySound() function ?

I don't know. Can you describe what a 'CreateMemorySound' function is?


I want to load custom wave data.
For example, you can design wave data in a canvas gadget right after you test your sound.

Code:
Procedure.f CreateDataSound(soundNum, Array waveData.f(2), amplitude = 25)
   
   ; Syntax:
   ; Result = CreateSound(#sound, waveData, [duration.f], [amplitude])
   ;
   ; #sound    { The number to identify the new sound. #PB_Any can be used to auto-generate this number. }
   ; wave data { The wave data. Array of floats [-1,+1] }
   ; amplitude { the peak waveform magnitude from 0 to 100 (full scale).  Default = 25 }
   
   InitAudioBuffer(1.111) ;<--- default init
   Protected _byteCount=ArraySize(waveData(),2)
   Protected *_buffer = InitAudioBuffer(-1)
   Protected _Nc.w = PeekW(*_buffer + 22)   ; Nc {is number of channels}
   Protected _Fr.l = PeekL(*_buffer + 24)   ; Fr {is samples per second}
   Protected _By.w = PeekW(*_buffer + 34)/8 ; By {is bytes per sample (1 = 8 bits, 2 = 16 bits)}
   Protected duration.f=_byteCount/_Fr
   
   If duration < 0.1 : duration = 0.1 : EndIf
   If duration <> InitAudioBuffer(-2) : InitAudioBuffer(duration) : EndIf
   
   Protected *buffer = InitAudioBuffer(-1)
   
   If *buffer = 0 : ProcedureReturn 0 : EndIf
   
   Protected Nc.w = PeekW(*buffer + 22)   ; Nc {is number of channels}
   Protected Fr.l = PeekL(*buffer + 24)   ; Fr {is samples per second}
   Protected By.w = PeekW(*buffer + 34)/8 ; By {is bytes per sample (1 = 8 bits, 2 = 16 bits)}
   Protected Ba = Nc * By ; block align (bytes per block)
   
   
   If amplitude > 100 : amplitude = 100
   ElseIf amplitude < 0 : amplitude = 0
   EndIf
   
   Protected *audioStart = *buffer + 44 ; pointer to the first audio data byte
   Protected *n = *audioStart
   Protected audBuffSize = MemorySize(*buffer) ; number of bytes in sound buffer
   Protected *audBuffEnd = *buffer + audBuffSize - 1 ; pointer to last byte in buffer
   
   ; calculate the number of audio bytes
   Protected byteCount.l = duration * Fr * By * Nc
   If byteCount & 1 : byteCount + 1 : EndIf ; byteCount must be even number
   PokeL(*buffer + 40, byteCount)
   
   Protected.w value ; waveform magnitude at any instant in time
   Protected.i loops = byteCount / Ba ; number of loop iterations
   Protected.i loopCount = 0 ; loop counter
   
   ; if waveform formulas produce values from -1 to +1 use this scale factor
   Protected sf.f = (Pow(2,8*By)/2 - 1) * (amplitude / 100)
   
   
   While loopCount < loops
     
      If By = 1 ; 8 bits/sample
         value=waveData(0,loopCount)*sf
         PokeA(*n, value+$80) ; left/mono
         If Nc = 2 ; stereo
            value=waveData(1,loopCount)*sf
            PokeA(*n+1, value+$80) ; right
         EndIf
      Else ; 16 bits/sample
         value=waveData(0,loopCount)*sf
         PokeW(*n, value) ; left/mono
         If Nc = 2 ; stereo
            value=waveData(1,loopCount)*sf
            PokeW(*n+2,value) ; right
         EndIf
      EndIf
     
      *n + Ba ; point to the next audio sample
      If *n > *audBuffEnd : Break : EndIf
      loopCount + 1
   Wend
   
   ProcedureReturn CatchSound(soundNum, *buffer)
   
EndProcedure


Code:
DisableExplicit
flags.i = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(0, 0, 0, 225, 105, "CreateSound() Demo", flags) And InitSound()
   playButton_3.i = ButtonGadget(#PB_Any,10,70,100,25,"Play Sound 3")
   
   ; generate my custom wave data
   Dim waveData.f(0,22050)
   fi=4000
   For i=0 To ArraySize(waveData(),2)
      fi-10
      a.f=#PI*2.0*fi / 44100.0
      b.f=#PI*2.0*2300.0 / 44100.0     
      waveData.f(0,i)=0.5*Sin(i*a)+0.5*Cos(i*b)
   Next
   snd_3.i = CreateDataSound(#PB_Any, waveData())
   
   Repeat
      event = WaitWindowEvent()
      If event = #PB_Event_Gadget
         Select EventGadget()
            Case playButton_3
               If IsSound(snd_3) : PlaySound(snd_3) : EndIf
         EndSelect
      EndIf
   Until event = #PB_Event_CloseWindow
   
EndIf

_________________
Imagewin8.1 x64 5.31 | IDE | PB plugin | Tools | Sprite | JSON | visual tool


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 11:26 pm 
Offline
Addict
Addict

Joined: Fri Apr 25, 2003 11:10 pm
Posts: 1199
I get an error when trying demo 2, SetSoundFrequency() is not a function, array, list, map or macro.


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Mon Feb 25, 2013 11:31 pm 
Offline
Addict
Addict
User avatar

Joined: Mon May 26, 2003 3:07 pm
Posts: 1477
Location: Nantes
jack wrote:
I get an error when trying demo 2, SetSoundFrequency() is not a function, array, list, map or macro.


It's a recent change:
History 5.10
Changed: renamed SoundFrequency() to SetSoundFrequency()

_________________
Imagewin8.1 x64 5.31 | IDE | PB plugin | Tools | Sprite | JSON | visual tool


Top
 Profile  
Reply with quote  
 Post subject: Re: SoundEasy.pbi include file adds CreateSound() command
PostPosted: Tue Feb 26, 2013 12:47 am 
Offline
Addict
Addict

Joined: Fri Apr 25, 2003 11:10 pm
Posts: 1199
OK thanks :)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye