Re: SpotFX Lib - Retro Sound Generator
Posted: Tue Dec 15, 2009 4:46 am
I would also like to see the source, 'cause DLLs don't work in Linux. Wondering if it's using any windows API in it, that prevent it from compiling under Linux.
http://www.purebasic.com
https://www.purebasic.fr/english/
Well, I just realized that the lib for 4.31 also works for 4.40 - maybe you should mention it in your first post or so.pjay wrote:I'm working away from home at the moment and haven't got the source on me, will try to post next weekend.
Sure, his code is really good for adjusting every setting to generate the sound. The only bad thing is that it's way more complicated than yours where I just have to use CreateSpotFX() and I have my sound.pjay wrote:I think this is redundant now anyway, as Demivec had released his source.
I would be interested in your sourcecode, if you don't mind to release it open.pjay wrote:Thanks for the info c4s, still haven't got around to testing it myself.![]()
I think this is redundant now anyway, as Demivec had released his source.
Code: Select all
EnableExplicit
Structure SpotFX_WAVE_Header
wFormatTag.w
nChannels.w
nSamplesPerSec.l
nAvgBytesPerSec.l
nBlockAlign.w
wBitsPerSample.w
cbSize.w
EndStructure
Structure SpotFX_SFXRWave
Sound_playing.i: wave_type.i: p_base_freq.d: p_freq_limit.d: p_freq_ramp.d: p_freq_dramp.d: p_duty.d
p_duty_ramp.d: p_vib_strength.d: p_vib_speed.d: p_vib_delay.d: p_env_attack.d: p_env_sustain.d
p_env_decay.d: p_env_punch.d: filter_on.b: p_lpf_resonance.d: p_lpf_freq.d: p_lpf_ramp.d
p_hpf_freq.d: p_hpf_ramp.d: p_pha_offset.d: p_pha_ramp.d: p_repeat_speed.d: p_arp_speed.d: p_arp_mod.d
phase.i: playing_sample.i : env_time.i
fperiod.d: rfperiod.d : fmaxperiod.d : fslide.d : fdslide.d : period.i : square_duty.d : square_slide.d : env_stage.i
env_vol.d: fphase.d: fdphase.d: iphase.i: ipp.i: fltp.d: fltdp.d: fltw.d: fltw_d.d: fltdmp.d: fltphp.d: flthp.d
flthp_d.d: vib_phase.d: vib_speed.d: vib_amp.d: rep_time.i: rep_limit.i: arp_time.i: arp_limit.i: arp_mod.d
SFX_env_length.i[5] : SFX_phaser_buffer.d[1025] : SFX_noise_buffer.d[33]
SFX_WaveFormatEx.SpotFX_WAVE_Header
EndStructure
Global SFX_Wave.SpotFX_SFXRWave
Macro SpotFX_Rnd(range)
(Random(1000000.0)/1000000.0)*range;
EndMacro
Procedure SpotFX_ResetSample(restart.b)
Protected tmp.d, Loop.i, Alength.i
With SFX_Wave
If Not restart : \phase=0 : EndIf
\fperiod= 100.0/((\p_base_freq * \p_base_freq)+0.001)
\period=Int(\fperiod)
\fmaxperiod=100.0/((\p_freq_limit*\p_freq_limit)+0.001);
\fslide= 1.0-Pow(\p_freq_ramp,3)*0.01;
\fdslide= -Pow(\p_freq_dramp,3)*0.000001;
\square_duty=0.5-\p_duty*0.5;
\square_slide=-\p_duty_ramp*0.00005;
If \p_arp_mod >= 0
\arp_mod=1.0 - Pow(\p_arp_mod,2.0)*0.9
Else
\arp_mod=1.0 + Pow(\p_arp_mod,2.0) * 10.0
EndIf
\arp_time = 0
\arp_limit = Int(Pow(1.0 - \p_arp_speed, 2.0) * 20000 + 32)
If \p_arp_speed=1.0
\arp_limit=0;
EndIf
If Not restart
; Alength = 0
;// reset filter
\fltp=0
\fltdp=0
\fltw=Pow(\p_lpf_freq,3)*0.1;
\fltw_d=1.0+\p_lpf_ramp*0.0001;
\fltdmp=5.0/(1.0+Pow(\p_lpf_resonance,2)*20.0)*(0.01+\fltw);
If \fltdmp>0.8 : \fltdmp=0.8 : EndIf
\fltphp=0.0;
\flthp=Pow(\p_hpf_freq,2)*0.1;
\flthp_d=1.0+\p_hpf_ramp*0.0003;
;// reset vibrato
\vib_phase=0.0;
\vib_speed=Pow(\p_vib_speed,2)*0.01;
\vib_amp=\p_vib_strength*0.5;
;// reset envelope
\env_vol=0.0;
\env_stage=0;
\env_time=0;
\SFX_env_length[0]=Int(\p_env_attack*\p_env_attack*100000.0)
\SFX_env_length[1]=Int(\p_env_sustain*\p_env_sustain*100000.0)
\SFX_env_length[2]=Int(\p_env_decay*\p_env_decay*100000.0)
\fphase=Pow(\p_pha_offset,2.0)*1020.0;
If \p_pha_offset<0.0 : \fphase=-\fphase : EndIf
\fdphase=Pow(\p_pha_ramp,2.0)*1.0;
If \p_pha_ramp<0.0 : \fdphase=-\fdphase : EndIf
\iphase=Abs(Int(\fphase))
\ipp=0
For Loop = 0 To 1024 : \SFX_phaser_buffer[Loop]=0.0 : Next
For Loop = 0 To 32 : \SFX_noise_buffer[Loop]= SpotFX_Rnd(2)-1 : Next
\rep_time=0;
\rep_limit= Int(Pow(1.0 - \p_repeat_speed, 2.0) * 20000 + 32)
If \p_repeat_speed=0.0 : \rep_limit=0 : EndIf
EndIf
EndWith
EndProcedure
Procedure SpotFX_Create(seed.i, mutations.i, Sample_Number.i, *memcopy = 0)
Protected Mutate.i, *Sample_Memory_Alloc, *ms, RiffCount.i, i.i, rfperiod.d, ssample.d, si.i, sample.d, T.i, fp.d, pp.d, SLength.i, Alength.i, PowTmp.d
Protected Sample_Min.d, Sample_Max.d, Sample_Div.d, MyLoop.i, SuperSample.d
With SFX_Wave
\playing_sample = #True
RandomSeed(seed)
;{/ Randomize()
\wave_type = Random(3)
\p_base_freq=Pow(SpotFX_Rnd(2.0)-1.0, 2.0);
If Random(1)
\p_base_freq=Pow(SpotFX_Rnd(2.0)-1.0, 3.0)+0.5
EndIf
\p_freq_limit=0.0
\p_freq_ramp=Pow(SpotFX_Rnd(2.0)-1.0, 5.0);
If \p_base_freq>0.7 And \p_freq_ramp>0.2
\p_freq_ramp=-\p_freq_ramp;
EndIf
If \p_base_freq<0.2 And \p_freq_ramp<-0.05
\p_freq_ramp=-\p_freq_ramp;
EndIf
\p_freq_dramp=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_duty=SpotFX_Rnd(2.0)-1.0
\p_duty_ramp=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_vib_strength=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_vib_speed=SpotFX_Rnd(2.0)-1.0
\p_vib_delay=SpotFX_Rnd(2.0)-1.0
\p_env_attack=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_env_sustain=Pow(SpotFX_Rnd(2.0)-1.0, 2.0);
\p_env_decay=SpotFX_Rnd(2.0)-1.0
\p_env_punch=Pow(SpotFX_Rnd(0.8), 2.0);
If \p_env_attack+\p_env_sustain+\p_env_decay<0.2
\p_env_sustain+ (0.2+SpotFX_Rnd(0.3));
\p_env_decay+ (0.2+SpotFX_Rnd(0.3));
EndIf
\p_lpf_resonance=SpotFX_Rnd(2.0)-1.0
\p_lpf_freq=1.0-Pow(SpotFX_Rnd(1.0), 3.0);
\p_lpf_ramp=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
If \p_lpf_freq<0.1 And \p_lpf_ramp<-0.05
\p_lpf_ramp=-\p_lpf_ramp;
EndIf
\p_hpf_freq=Pow(SpotFX_Rnd(1.0), 5.0);
\p_hpf_ramp=Pow(SpotFX_Rnd(2.0)-1.0, 5.0);
\p_pha_offset=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_pha_ramp=Pow(SpotFX_Rnd(2.0)-1.0, 3.0);
\p_repeat_speed=SpotFX_Rnd(2.0)-1.0
\p_arp_speed=SpotFX_Rnd(2.0)-1.0
\p_arp_mod=SpotFX_Rnd(2.0)-1.0
;}
;{/ Mutate
If mutations > 0
For Mutate = 1 To mutations
If Random(1)=1 : \p_base_freq+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_freq_ramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_freq_dramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_duty+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_duty_ramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_vib_strength+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_vib_speed+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_vib_delay+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_env_attack+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_env_sustain+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_env_decay+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_env_punch+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_lpf_resonance+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_lpf_freq+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_lpf_ramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_hpf_freq+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_hpf_ramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_pha_offset+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_pha_ramp+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_repeat_speed+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_arp_speed+SpotFX_Rnd(0.1)-0.05 : EndIf
If Random(1)=1 : \p_arp_mod+SpotFX_Rnd(0.1)-0.05 : EndIf
Next
EndIf
SuperSample = Random(14)+2
;}
\arp_time = 0
SpotFX_ResetSample(#False);
*Sample_Memory_Alloc = AllocateMemory(768000)
*ms = *Sample_Memory_Alloc
Dim Temp.d(768000)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
\SFX_WaveFormatEx\wFormatTag = 1
CompilerElse
\SFX_WaveFormatEx\wFormatTag = #WAVE_FORMAT_PCM;
CompilerEndIf
\SFX_WaveFormatEx\nChannels =$0001;
\SFX_WaveFormatEx\nSamplesPerSec = 44100 ;
\SFX_WaveFormatEx\wBitsPerSample = $0010;
\SFX_WaveFormatEx\nBlockAlign = (\SFX_WaveFormatEx\nChannels * \SFX_WaveFormatEx\wBitsPerSample) /8
\SFX_WaveFormatEx\nAvgBytesPerSec = \SFX_WaveFormatEx\nSamplesPerSec * \SFX_WaveFormatEx\nBlockAlign;
\SFX_WaveFormatEx\cbSize = 0
PokeS(*ms,"RIFF",4,#PB_Ascii):*ms+4 ;'RIFF'
PokeL(*ms,RiffCount):*ms+4 ;file Data size
PokeS(*ms,"WAVE",4,#PB_Ascii):*ms+4 ;'WAVE'
PokeS(*ms,"fmt ",4,#PB_Ascii):*ms+4 ;'fmt '
PokeL(*ms,SizeOf(SpotFX_WAVE_Header)):*ms+4 ;TWaveFormat data size
PokeW(*ms,\SFX_WaveFormatEx\wFormatTag):*ms+2; SFX_WaveFormatEx record
PokeW(*ms,\SFX_WaveFormatEx\nChannels):*ms+2
PokeL(*ms,\SFX_WaveFormatEx\nSamplesPerSec):*ms+4
PokeL(*ms,\SFX_WaveFormatEx\nAvgBytesPerSec):*ms+4
PokeW(*ms,\SFX_WaveFormatEx\nBlockAlign):*ms+2
PokeW(*ms,\SFX_WaveFormatEx\wBitsPerSample):*ms+2
PokeW(*ms,\SFX_WaveFormatEx\cbSize):*ms+2
PokeS(*ms,"data",4,#PB_Ascii):*ms+4 ;'data'
Sample_Min.d = 999999 : Sample_Max.d = -999999 ;/ for normalizing
Repeat
If Not \playing_sample
Break
EndIf
\rep_time + 1;
If \rep_limit <> 0 And \rep_time >= \rep_limit
\rep_time = 0;
SpotFX_ResetSample(#True);
EndIf
;/ frequency envelopes/arpeggios
\arp_time+1
If \arp_limit <> 0 And \arp_time>=\arp_limit
\arp_limit=0;
\fperiod* \arp_mod;
EndIf
\fslide+\fdslide;
\fperiod*\fslide;
If \fperiod>\fmaxperiod
\fperiod=\fmaxperiod;
If \p_freq_limit>0
\playing_sample=#False;
Break
EndIf
EndIf
\rfperiod=\fperiod
If \vib_amp>0
\vib_phase+\vib_speed;
\rfperiod=\fperiod*(1.0+Sin(\vib_phase)*\vib_amp);
EndIf
\period=\rfperiod
If \period<8 : \period=8 : EndIf
\square_duty+\square_slide;
If \square_duty<0 : \square_duty=0 : EndIf
If \square_duty>0.5 : \square_duty=0.5 : EndIf
;// volume envelope
\env_time+1;
If \env_time>\SFX_env_length[\env_stage]
\env_time=0;
\env_stage+1;
If \env_stage=3
\playing_sample=#False;
Break
EndIf
EndIf
If \env_stage=0
\env_vol=(\env_time/\SFX_env_length[0]);
EndIf
If \env_stage=1
\env_vol=1.0+(Pow(1.0-\env_time/\SFX_env_length[1], 1.0)*2.0*\p_env_punch);
EndIf
If \env_stage=2
\env_vol=1.0-(\env_time/\SFX_env_length[2]);
EndIf
;// phaser step
\fphase+\fdphase;
\iphase=Abs(\fphase);
If \iphase>1023 : \iphase=1023 : EndIf
If \flthp_d <> 0
\flthp*\flthp_d;
If \flthp<0.00001 : \flthp=0.00001 : EndIf
If \flthp>0.1 : \flthp=0.1 : EndIf
EndIf
ssample=0.0 : sample=0.0
For si=0 To SuperSample ;// 8x supersampling X now randomized
\phase+1;
If \phase>=\period
\phase % \period;
If \wave_type=3
For i=0 To 31 : \SFX_noise_buffer[i]=SpotFX_Rnd(2.0)-1.0 : Next
EndIf
EndIf
;// base waveform
fp=\phase / \period
Select \wave_type
Case 0: ;// square
If fp<\square_duty
sample=0.5
Else
sample=-0.5
EndIf
Case 1: ;// sawtooth
sample=1.0-fp*2.0;
Case 2: ;// sine
sample=Sin(fp*2.0*#PI);
Case 3: ;// noise
sample=\SFX_noise_buffer[\phase*32 / \period];
EndSelect
;// lp filter
pp=\fltp
\fltw*\fltw_d;
If \fltw<0.0 : \fltw=0.0 : EndIf
If \fltw>0.1 : \fltw=0.1 : EndIf
If \p_lpf_freq <> 1.0
\fltdp+((sample-\fltp)*\fltw);
\fltdp-(\fltdp*\fltdmp);
Else
\fltp=sample;
\fltdp=0.0
EndIf
\fltp+\fltdp;
;// hp filter
\fltphp+(\fltp-pp);
\fltphp-(\fltphp*\flthp);
sample=\fltphp;
;// phaser
\SFX_phaser_buffer[\ipp&1023]=sample;
sample+\SFX_phaser_buffer[(\ipp-\iphase+1024)&1023];
\ipp=(\ipp+1)&1023;
;// final accumulation and envelope application
ssample + sample*\env_vol;
Next
ssample / (SuperSample+1)
SLength + 1 : Alength+2
Temp(SLength) = ssample
If ssample > Sample_Max : Sample_Max = ssample : EndIf
If ssample < Sample_Min : Sample_Min = ssample : EndIf
ForEver
;/ Normalize & store final sample data
Sample_Div.d = Abs(Sample_Max)
If Abs(Sample_Min) > Sample_Div : Sample_Div = Abs(Sample_Min) : EndIf
*ms+2
For MyLoop.i = 1 To SLength
*ms+2
PokeW(*ms,(Temp(MyLoop) / Sample_Div) * 32000)
Next
PokeL(*Sample_Memory_Alloc+42,Alength) ;/sound data size
;/ Store
CatchSound(Sample_Number,*Sample_Memory_Alloc,Alength)
;/ for visual waveform routine
If *memcopy > 0
PokeL(*memcopy,Alength) ;/ store waveform length in the first 4 bytes
CopyMemory(*Sample_Memory_Alloc+46,*memcopy+4,Alength)
EndIf
FreeMemory(*Sample_Memory_Alloc) : Dim Temp(0)
EndWith
EndProcedure
;{- SpotFX Test app
Enumeration
#Random
#Seed
#Minus
#Plus
#Play
#Mutate
#String
#FList
#LList
#Message
EndEnumeration
If OpenWindow(1,0,0,260,52,"PB-SpotFX - PJames 08",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StickyWindow(1,1)
ButtonGadget(#Random,2,2,50,18,"Random")
StringGadget(#Seed,54,2,70,18,"0",#PB_String_Numeric)
ButtonGadget(#Minus,126,2,16,18,"-")
ButtonGadget(#Plus,144,2,16,18,"+")
ButtonGadget(#Play,162,2,30,18,"Play")
ButtonGadget(#Mutate,194,2,64,18,"Mutate:0")
StringGadget(#String,2,24,250,20,"CreateSpotFX(0,0,1)")
If InitSound()
;/ generate intro sound
Global EventID.i, MySeed.i = 9837320, Mutate = 0, Update.i = 1
Repeat
EventID.i = WaitWindowEvent(1)
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case #Random
RandomSeed(ElapsedMilliseconds())
MySeed.i = Random(2147483647)
Mutate = Random(10) : Update = 1
Case #Seed
If EventType() = #PB_EventType_Change
MySeed = Val(GetGadgetText(#Seed))
Mutate = 0 : Update = 2
EndIf
Case #Minus
MySeed = Val(GetGadgetText(#Seed))-1
Mutate = 0 : Update = 1
Case #Plus
MySeed = Val(GetGadgetText(#Seed))+1
Mutate = 0 : Update = 1
Case #Play
PlaySound(1)
Case #Mutate
Mutate+1 : Update=1
EndSelect
EndSelect
If Update > 0
SpotFX_Create(MySeed,Mutate,1)
If Update < 2 : SetGadgetText(#Seed,Str(MySeed)) : EndIf
SetGadgetText(#Mutate,"Mutate: "+Str(Mutate))
SetGadgetText(#String,"SpotFX_Create("+Str(MySeed)+","+Str(Mutate)+",1)")
SoundVolume(1, 60) : PlaySound(1)
Update = 0
EndIf
Until EventID=#PB_Event_CloseWindow
End
EndIf
EndIf
;}