SFXR
Moderator: Moderators
SFXR
Port of DrPetter's sfxr for use with the Sample Component.
This library is meant as a replacement to exporting / importing a .wav file from sfxr into ZGE, not as real-time synthesizer!
Instructions
- Load a .sfs file using FileAction.
- Call SampleLength() and set your Sample accordingly.
- Call ResetSample() to initialize the Synthesizer.
- Call SynthSample() to render the sample to the buffer*
- Use a SampleExpression to copy the buffer to a Sample.
Attached file contains the library plus a demo scene which loads + renders Sample.sfs when pressing "R" and plays the sample when pressing "S".
*The quality argument of SynthSample has to be in the 0-3 range ( 0 being lowest, 3 be highest ).
K
- Attachments
-
- SFXR.zip
- (3.82 KiB) Downloaded 1105 times
- jph_wacheski
- Posts: 1005
- Joined: Sat Feb 16, 2008 8:10 pm
- Location: Canada
- Contact:
Thanks jph. Ville will try to debug the script in order to see how we can speed it up some more. Let me know when you come across any problems* Anyway, the Base Note is around 148.7656.
*Other then some of the delta parameters not working at low values ( this is because ZGE doesn't support doubles ).
K
Bumping with the notion, or at least the tip of the hat, that another project that takes this a tad further than the base one has come into being, bfxr.
http://www.bfxr.net/
Handy/potential for further/renewed doings?
http://www.bfxr.net/
Handy/potential for further/renewed doings?
Champion of Roguelikes, living voraciously, trying to wrap my head around game creation.
Re: SFXR
I quickly updated Kjell's example, as ZGE isn't happy anymore with names being the same as components File:File, Sound:Sound and Sample:Sample. Weirdly enough, KeyPress:KeyPress isn't an issue.
And I'm already happy, as sfxr/jsfxr is simpler to use for me than the ZGE sound interface, as I understand how to make other sounds than "brrrrrr" and "piiiiii'
But now I'm wondering if sfxr could be wrapped to work as an external library (dll and so), just like ZGEBullet, so that we could synthesize sounds in real time. Therefore, I'm trying to compile it, for starters. Sourcecode on original website is missing a lot of files. So I'm trying to compile one of the many clones over github, but it is using SDL1.2 and 32bits, so I'm still navigating around that.
Do you think making such a library for ZGE is doable?
(named zsfxr, to stay in the trend)
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="SFXR" CustomScreenWidth="320" CustomScreenHeight="240" MouseVisible="255" FileVersion="2">
<OnLoaded>
<ZLibrary Comment="SFXR">
<Source>
<![CDATA[//
float SampleLength()
{
return (p_env_attack*p_env_attack+
p_env_sustain*p_env_sustain+
p_env_decay*p_env_decay)*100000;
}
//
void ResetSample(int restart)
{
// Base
if(!restart)phase = 0;
period = 100/(p_base_freq*p_base_freq+0.001);
fperiod = period;
fmaxperiod = 100/(p_freq_limit*p_freq_limit+0.001);
fslide = 1-pow(p_freq_ramp,3)*0.01;
fdslide = pow(p_freq_dramp,3)*-0.000001;
// Square
square_duty = 0.5-p_duty*0.5;
square_slide = p_duty_ramp*-0.00005;
// Arpeggio
arp_time = 0;
arp_limit = p_arp_speed != 1 ? pow(1-p_arp_speed,2)*20000+32 : 0;
arp_mod = p_arp_mod >= 0 ? 1-pow(p_arp_mod,2)*0.9 : 1+pow(p_arp_mod,2)*10;
if(!restart)
{
sampling = 1;
// Filter
fltp = 0;
fltdp = 0;
fltw = pow(p_lpf_freq,3)*0.1;
fltw_d = 1+p_lpf_ramp*0.0001;
fltdmp = 5/(1+pow(p_lpf_resonance,2)*20)*(0.01+fltw);
if(fltdmp > 0.8)fltdmp = 0.8;
fltphp = 0;
flthp = pow(p_hpf_freq,2)*0.1;
flthp_d = 1+p_hpf_ramp*0.0003;
// Vibrato
vib_phase = 0;
vib_speed = pow(p_vib_speed,2)*0.01;
vib_amp = p_vib_strength*0.5;
// Envelope
env_stage = 0;
env_time = 0;
env_length[0] = p_env_attack*p_env_attack*100000;
env_length[1] = p_env_sustain*p_env_sustain*100000;
env_length[2] = p_env_decay*p_env_decay*100000;
// Phaser
fphase = pow(p_pha_offset,2)*1020;
if(p_pha_offset < 0)fphase *= -1;
fdphase = pow(p_pha_ramp,2);
if(p_pha_ramp < 0)fdphase *= -1;
iphase = fphase;
ipp = 0;
// Noise
fnoise = rnd()*2-1;
ppnoise = 0;
// Repeat
rep_time = 0;
rep_limit = p_repeat_speed ? pow(1-p_repeat_speed,2)*20000+32 : 0;
}
}
//
void SynthSample(int start, int end, int quality)
{
// Repeat
float l_rep_time = rep_time;
float l_rep_limit = rep_limit;
// Arpeggio
float l_arp_time = arp_time;
float l_arp_mod = arp_mod;
float l_arp_limit = arp_limit;
// Base
int l_wave_type = wave_type;
float l_phase = phase;
float l_period = period;
float l_fperiod = fperiod;
float l_fmaxperiod = fmaxperiod;
float l_fslide = fslide;
float l_fdslide = fdslide;
// Square
float l_square_duty = square_duty;
float l_square_slide = square_slide;
// Vibrato
float l_vib_phase = vib_phase;
float l_vib_speed = vib_speed;
float l_vib_amp = vib_amp;
// Envelope
float l_env_vol;
float l_env_length;
float l_env_stage = env_stage;
float l_env_time = env_time;
float l_env_punch = p_env_punch;
float l_env_length_0 = env_length[0];
float l_env_length_1 = env_length[1];
float l_env_length_2 = env_length[2];
// Noise
float l_fnoise = fnoise;
int l_ppnoise = ppnoise;
// Phaser
float l_fphase = fphase;
float l_fdphase = fdphase;
int l_iphase = iphase;
int l_ipp = ipp;
// Filter
float l_lpf_freq = p_lpf_freq;
float l_fltp = fltp;
float l_fltdp = fltdp;
float l_fltdmp = fltdmp;
float l_flthp = flthp;
float l_flthp_d = flthp_d;
float l_fltw = fltw;
float l_fltw_d = fltw_d;
float l_fltphp = fltphp;
// Supersampler
float sp = pow(2,quality);
float ss = 8/sp;
// Synth
int l_sampling = sampling;
for(int i=start; i<end; i++)
{
if(!l_sampling)
{
buffer[i] = 0;
continue;
}
// Repeat
if(l_rep_limit)
{
l_rep_time++;
if(l_rep_time >= l_rep_limit)
{
l_rep_time = 0;
ResetSample(1);
// Local
l_period = period;
l_fperiod = fperiod;
l_fslide = fslide;
l_square_duty = square_duty;
l_arp_time = arp_time;
l_arp_limit = arp_limit;
}
}
// Arpeggio
l_arp_time++;
if(l_arp_limit != 0 && l_arp_time >= l_arp_limit)
{
l_arp_limit = 0;
l_fperiod *= l_arp_mod;
}
// Base
l_fslide += l_fdslide;
l_fperiod *= l_fslide;
if(l_fperiod > l_fmaxperiod)
{
l_fperiod = l_fmaxperiod;
l_sampling = 0;
}
// Square
if(l_wave_type == 0)
{
l_square_duty += l_square_slide;
if(l_square_duty < 0)l_square_duty = 0;
if(l_square_duty > 0.5)l_square_duty = 0.5;
}
// Vibrato
float rfperiod = l_fperiod;
if(l_vib_amp > 0)
{
l_vib_phase += l_vib_speed;
rfperiod = l_fperiod*(1+sin(l_vib_phase)*l_vib_amp);
}
l_period = rfperiod;
if(l_period < 8)l_period = 8;
// Envelope
l_env_time++;
switch(l_env_stage)
{
case 0: l_env_length = l_env_length_0; break;
case 1: l_env_length = l_env_length_1; break;
case 2: l_env_length = l_env_length_2; break;
}
if(l_env_time > l_env_length)
{
l_env_time = 0;
l_env_stage++;
}
float tl = l_env_time ? l_env_time/l_env_length : 0;
switch(l_env_stage)
{
case 0: l_env_vol = tl; break;
case 1: l_env_vol = 1+(1-tl)*2*l_env_punch; break;
case 2: l_env_vol = 1-tl; break;
}
// Phaser
if(l_fphase || l_fdphase)
{
l_fphase += l_fdphase;
l_iphase = abs(l_fphase);
if(l_iphase > 1023)l_iphase = 1023;
}
// Filter
if(l_flthp_d != 0)
{
l_flthp *= l_flthp_d;
if(l_flthp < 0.00001)l_flthp = 0.00001;
if(l_flthp > 0.1)l_flthp = 0.1;
}
// Supersampler
float ssample = 0;
for(int si=0; si<sp; si++)
{
float sample = 0;
l_phase += ss;
if(l_phase >= l_period)l_phase = l_phase-floor(l_phase/l_period)*l_period;
float fp = l_phase/l_period;
switch(l_wave_type)
{
case 0: sample = fp < l_square_duty ? -0.5 : 0.5; break;
case 1: sample = 1-fp*2; break;
case 2: sample = sin(fp*PI*2); break;
case 3: int pnoise = fp*32;
if(pnoise != l_ppnoise){l_fnoise = rnd()*2-1; l_ppnoise = pnoise;}
sample = l_fnoise; break;
}
// Filter
float pp = l_fltp;
l_fltw *= l_fltw_d;
if(l_fltw < 0)l_fltw = 0;
if(l_fltw > 0.1)l_fltw = 0.1;
if(l_lpf_freq != 1)
{
l_fltdp += (sample-l_fltp)*l_fltw;
l_fltdp -= l_fltdp*l_fltdmp;
}
else
{
l_fltp = sample;
l_fltdp = 0;
}
l_fltp += l_fltdp;
l_fltphp += l_fltp-pp;
l_fltphp -= l_fltphp*l_flthp;
sample = l_fltphp;
// Phaser
if(l_fphase || l_fdphase)
{
phaser_buffer[l_ipp&1023] = sample;
sample += phaser_buffer[(l_ipp-l_iphase+1024)&1023];
l_ipp = (l_ipp+1)&1023;
}
// Accumulate
ssample += sample;
}
buffer[i] = ssample*l_env_vol*sound_vol*2/sp;
}
// Repeat
rep_time = l_rep_time;
// Arpeggio
arp_time = l_arp_time;
arp_limit = l_arp_limit;
// Base
phase = l_phase;
period = l_period;
fperiod = l_fperiod;
fslide = l_fslide;
// Square
square_duty = l_square_duty;
// Vibrato
vib_phase = l_vib_phase;
// Envelope
env_time = l_env_time;
env_stage = l_env_stage;
// Noise
fnoise = l_fnoise;
ppnoise = l_ppnoise;
// Phaser
fphase = l_fphase;
iphase = l_iphase;
ipp = l_ipp;
// Filter
fltw = l_fltw;
flthp = l_flthp;
fltp = l_fltp;
fltdp = l_fltdp;
fltphp = l_fltphp;
// Synth
sampling = l_sampling;
}]]>
</Source>
</ZLibrary>
<SetAppState State="Demo"/>
</OnLoaded>
<States>
<AppState Name="Demo">
<Definitions>
<Sample Name="MySample" Length="0.5084">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[this.Time*44100];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sound Name="MySound" Length="0.5" Volume="0.29" Mod0Active="1" Mod0Destination="1" Mod0Amount="1" Env0Active="1" Env0ReleaseTime="0.2" Sample="MySample" SampleRepeatPosition="-1" UseSampleHz="255"/>
<Array Name="Key" Type="1" Dimensions="1" SizeDim1="2" SizeDim2="3"/>
</Definitions>
<OnUpdate>
<Repeat Name="KeyRepeat" Count="2">
<OnIteration>
<ZExpression>
<Expression>
<![CDATA[//
int K = KeyRepeat.Iteration;
//
Key[K,1] = Key[K,0];
Key[K,0] = 0;
//
KeyPress.CharCode = 82+K;]]>
</Expression>
</ZExpression>
<KeyPress Name="KeyPress" CharCode="83">
<OnPressed>
<ZExpression>
<Expression>
<![CDATA[//
Key[KeyRepeat.Iteration,0] = 1;]]>
</Expression>
</ZExpression>
</OnPressed>
</KeyPress>
<ZExpression>
<Expression>
<![CDATA[//
int K = KeyRepeat.Iteration;
//
Key[K,2] = Key[K,0] && !Key[K,1];]]>
</Expression>
</ZExpression>
</OnIteration>
</Repeat>
<Condition>
<Expression>
<![CDATA[//
return Key[0,2];]]>
</Expression>
<OnTrue>
<FileAction File="MyFile"/>
<ZExpression>
<Expression>
<![CDATA[//
float S = SampleLength(); // Get the sample length
float L = S/44100; // Get the sample length in seconds
//
MySound.Length = L; // Set the Sound component length
MySample.Length = L; // Set the Sample component length
//
ResetSample(0); // Reset the synthesizer
SynthSample(0,S,3); // Synthesize the entire sample]]>
</Expression>
</ZExpression>
<RefreshContent Component="MySample"/>
</OnTrue>
</Condition>
<Condition>
<Expression>
<![CDATA[//
return Key[1,2];]]>
</Expression>
<OnTrue>
<PlaySound Sound="MySound"/>
</OnTrue>
</Condition>
</OnUpdate>
</AppState>
</States>
<Content>
<Group Comment="SFXR">
<Children>
<Group Comment="File">
<Children>
<File Name="MyFile" FileName="Sample.sfs">
<OnRead>
<Repeat Name="FileRead" Count="33">
<OnIteration>
<FileMoveData Property="Data"/>
<ZExpression>
<Expression>
<![CDATA[//
switch(FileRead.Iteration)
{
case 4: wave_type = Data; break;
case 7: MyFile.Encoding = 1; break;
case 8: sound_vol = Data; break;
case 9: p_base_freq = Data; break;
case 10: p_freq_limit = Data; break;
case 11: p_freq_ramp = Data; break;
case 12: p_freq_dramp = Data; break;
case 13: p_duty = Data; break;
case 14: p_duty_ramp = Data; break;
case 15: p_vib_strength = Data; break;
case 16: p_vib_speed = Data; break;
case 18: p_env_attack = Data; break;
case 19: p_env_sustain = Data; break;
case 20: p_env_decay = Data; break;
case 21: p_env_punch = Data; MyFile.Encoding = 0; break;
case 22: MyFile.Encoding = 1; break;
case 23: p_lpf_resonance = Data; break;
case 24: p_lpf_freq = Data; break;
case 25: p_lpf_ramp = Data; break;
case 26: p_hpf_freq = Data; break;
case 27: p_hpf_ramp = Data; break;
case 28: p_pha_offset = Data; break;
case 29: p_pha_ramp = Data; break;
case 30: p_repeat_speed = Data; break;
case 31: p_arp_speed = Data; break;
case 32: p_arp_mod = Data; MyFile.Encoding = 0; break;
}]]>
</Expression>
</ZExpression>
</OnIteration>
</Repeat>
</OnRead>
</File>
<Variable Name="Data"/>
</Children>
</Group>
<Group Comment="Sample">
<Children>
<Group Comment="Synth">
<Children>
<Variable Name="sampling" Type="1"/>
<Array Name="buffer" SizeDim1="132300"/>
</Children>
</Group>
<Group Comment="Base">
<Children>
<Variable Name="phase"/>
<Variable Name="period"/>
<Variable Name="fperiod"/>
<Variable Name="fmaxperiod"/>
<Variable Name="fslide"/>
<Variable Name="fdslide"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="square_duty"/>
<Variable Name="square_slide"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="vib_phase"/>
<Variable Name="vib_speed"/>
<Variable Name="vib_amp"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="env_stage"/>
<Variable Name="env_time"/>
<Array Name="env_length" SizeDim1="3"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="fltp"/>
<Variable Name="fltdp"/>
<Variable Name="fltw"/>
<Variable Name="fltw_d"/>
<Variable Name="fltdmp"/>
<Variable Name="fltphp"/>
<Variable Name="flthp"/>
<Variable Name="flthp_d"/>
</Children>
</Group>
<Group Comment="Noise">
<Children>
<Variable Name="fnoise"/>
<Variable Name="ppnoise" Type="1"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="fphase"/>
<Variable Name="fdphase"/>
<Variable Name="iphase" Type="1"/>
<Variable Name="ipp" Type="1"/>
<Array Name="phaser_buffer" SizeDim1="1024"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="rep_time"/>
<Variable Name="rep_limit"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="arp_time"/>
<Variable Name="arp_mod"/>
<Variable Name="arp_limit"/>
</Children>
</Group>
</Children>
</Group>
<Group Comment="Parameters">
<Children>
<Group Comment="Base">
<Children>
<Variable Name="wave_type" Type="1"/>
<Variable Name="sound_vol"/>
<Variable Name="p_base_freq"/>
<Variable Name="p_freq_limit"/>
<Variable Name="p_freq_ramp"/>
<Variable Name="p_freq_dramp"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="p_duty"/>
<Variable Name="p_duty_ramp"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="p_vib_speed"/>
<Variable Name="p_vib_strength"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="p_env_attack"/>
<Variable Name="p_env_sustain"/>
<Variable Name="p_env_decay"/>
<Variable Name="p_env_punch"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="p_lpf_freq"/>
<Variable Name="p_lpf_ramp"/>
<Variable Name="p_lpf_resonance"/>
<Variable Name="p_hpf_freq"/>
<Variable Name="p_hpf_ramp"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="p_pha_offset"/>
<Variable Name="p_pha_ramp"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="p_repeat_speed"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="p_arp_speed"/>
<Variable Name="p_arp_mod"/>
</Children>
</Group>
</Children>
</Group>
</Children>
</Group>
</Content>
</ZApplication>
But now I'm wondering if sfxr could be wrapped to work as an external library (dll and so), just like ZGEBullet, so that we could synthesize sounds in real time. Therefore, I'm trying to compile it, for starters. Sourcecode on original website is missing a lot of files. So I'm trying to compile one of the many clones over github, but it is using SDL1.2 and 32bits, so I'm still navigating around that.
Do you think making such a library for ZGE is doable?
(named zsfxr, to stay in the trend)
Last edited by Ats on Wed May 01, 2024 5:27 pm, edited 1 time in total.
Re: SFXR
Hi Ats,
K
You can't use KeyPress as variable type in the scripting language .. while you can use File / Sample / Sound.
Sure .. although it would have been nice if ZGE exposed the audio interface ( DirectSound on Windows ) so you don't have to run a second interface
K
Re: SFXR
Oh, ok, I get it.Kjell wrote:it would have been nice if ZGE exposed the audio interface ( DirectSound on Windows ) so you don't have to run a second interface
Alternatively, how could I import several sfx sounds without having to loop on each file to read their data? Maybe I could simply copy/paste the serialization of the sound generated by jsfxr. But I'm wondering if it's even possible to play several different sounds at the same time...?
Re: SFXR
Following Kjell's concerns about the amount of time the generation of the sound can take, I made an example that runs all the sounds presets of jsfxr.
Edit:
I modified my example so that we can chose which sound to play using numbers 0 to 9, and R for random. This way, it is easier to discover what kind of sound crashes the program while holding the mouse click and enjoying the blip-blops.
Here are the results so far:
- 0 key = pickupCoin
- 1 key = laserShoot
- 2 key = explosion
- 3 key = powerUp
- 4 key = hitHurt
- 5 key = jump
- 6 key = blipSelect
- 7 key = synth
- 8 key = tone
- 9 key = click
- R key = random
- Left click to play a sound
- Right click to mutate the current sound
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZSFXR" CustomScreenWidth="320" CustomScreenHeight="240" MouseVisible="255" FileVersion="2" AndroidPackageName="org.zgameeditor.zsfxr" AndroidPortrait="2">
<OnLoaded>
<ZLibrary Comment="Math">
<Source>
<![CDATA[int irnd(int i) { return round(rnd() * i); }
float frnd(float f) { return rnd() * f; }
float sqr(float x) { return x * x; }
float cube(float x) { return x * x * x; }
int sign(float x) { return x < 0 ? -1 : 1; }
float rndr(float from, float to) { return rnd() * (to - from) + from; }]]>
</Source>
</ZLibrary>
<ZLibrary Comment="SFXR">
<Source>
<![CDATA[//
float SampleLength()
{
return (p_env_attack*p_env_attack+
p_env_sustain*p_env_sustain+
p_env_decay*p_env_decay)*100000;
}
//
void ResetSample(int restart)
{
// Base
if(!restart)phase = 0;
period = 100/(p_base_freq*p_base_freq+0.001);
fperiod = period;
fmaxperiod = 100/(p_freq_limit*p_freq_limit+0.001);
fslide = 1-pow(p_freq_ramp,3)*0.01;
fdslide = pow(p_freq_dramp,3)*-0.000001;
// Square
square_duty = 0.5-p_duty*0.5;
square_slide = p_duty_ramp*-0.00005;
// Arpeggio
arp_time = 0;
arp_limit = p_arp_speed != 1 ? pow(1-p_arp_speed,2)*20000+32 : 0;
arp_mod = p_arp_mod >= 0 ? 1-pow(p_arp_mod,2)*0.9 : 1+pow(p_arp_mod,2)*10;
if(!restart)
{
sampling = 1;
// Filter
fltp = 0;
fltdp = 0;
fltw = pow(p_lpf_freq,3)*0.1;
fltw_d = 1+p_lpf_ramp*0.0001;
fltdmp = 5/(1+pow(p_lpf_resonance,2)*20)*(0.01+fltw);
if(fltdmp > 0.8)fltdmp = 0.8;
fltphp = 0;
flthp = pow(p_hpf_freq,2)*0.1;
flthp_d = 1+p_hpf_ramp*0.0003;
// Vibrato
vib_phase = 0;
vib_speed = pow(p_vib_speed,2)*0.01;
vib_amp = p_vib_strength*0.5;
// Envelope
env_stage = 0;
env_time = 0;
env_length[0] = p_env_attack*p_env_attack*100000;
env_length[1] = p_env_sustain*p_env_sustain*100000;
env_length[2] = p_env_decay*p_env_decay*100000;
// Phaser
fphase = pow(p_pha_offset,2)*1020;
if(p_pha_offset < 0)fphase *= -1;
fdphase = pow(p_pha_ramp,2);
if(p_pha_ramp < 0)fdphase *= -1;
iphase = fphase;
ipp = 0;
// Noise
fnoise = rnd()*2-1;
ppnoise = 0;
// Repeat
rep_time = 0;
rep_limit = p_repeat_speed ? pow(1-p_repeat_speed,2)*20000+32 : 0;
}
}
//
void SynthSample(int start, int end, int quality)
{
// Repeat
float l_rep_time = rep_time;
float l_rep_limit = rep_limit;
// Arpeggio
float l_arp_time = arp_time;
float l_arp_mod = arp_mod;
float l_arp_limit = arp_limit;
// Base
int l_wave_type = wave_type;
float l_phase = phase;
float l_period = period;
float l_fperiod = fperiod;
float l_fmaxperiod = fmaxperiod;
float l_fslide = fslide;
float l_fdslide = fdslide;
// Square
float l_square_duty = square_duty;
float l_square_slide = square_slide;
// Vibrato
float l_vib_phase = vib_phase;
float l_vib_speed = vib_speed;
float l_vib_amp = vib_amp;
// Envelope
float l_env_vol;
float l_env_length;
float l_env_stage = env_stage;
float l_env_time = env_time;
float l_env_punch = p_env_punch;
float l_env_length_0 = env_length[0];
float l_env_length_1 = env_length[1];
float l_env_length_2 = env_length[2];
// Noise
float l_fnoise = fnoise;
int l_ppnoise = ppnoise;
// Phaser
float l_fphase = fphase;
float l_fdphase = fdphase;
int l_iphase = iphase;
int l_ipp = ipp;
// Filter
float l_lpf_freq = p_lpf_freq;
float l_fltp = fltp;
float l_fltdp = fltdp;
float l_fltdmp = fltdmp;
float l_flthp = flthp;
float l_flthp_d = flthp_d;
float l_fltw = fltw;
float l_fltw_d = fltw_d;
float l_fltphp = fltphp;
// Supersampler
float sp = pow(2,quality);
float ss = 8/sp;
// Synth
int l_sampling = sampling;
for(int i=start; i<end; i++)
{
if(!l_sampling)
{
buffer[i] = 0;
continue;
}
// Repeat
if(l_rep_limit)
{
l_rep_time++;
if(l_rep_time >= l_rep_limit)
{
l_rep_time = 0;
ResetSample(1);
// Local
l_period = period;
l_fperiod = fperiod;
l_fslide = fslide;
l_square_duty = square_duty;
l_arp_time = arp_time;
l_arp_limit = arp_limit;
}
}
// Arpeggio
l_arp_time++;
if(l_arp_limit != 0 && l_arp_time >= l_arp_limit)
{
l_arp_limit = 0;
l_fperiod *= l_arp_mod;
}
// Base
l_fslide += l_fdslide;
l_fperiod *= l_fslide;
if(l_fperiod > l_fmaxperiod)
{
l_fperiod = l_fmaxperiod;
l_sampling = 0;
}
// Square
if(l_wave_type == 0)
{
l_square_duty += l_square_slide;
if(l_square_duty < 0)l_square_duty = 0;
if(l_square_duty > 0.5)l_square_duty = 0.5;
}
// Vibrato
float rfperiod = l_fperiod;
if(l_vib_amp > 0)
{
l_vib_phase += l_vib_speed;
rfperiod = l_fperiod*(1+sin(l_vib_phase)*l_vib_amp);
}
l_period = rfperiod;
if(l_period < 8)l_period = 8;
// Envelope
l_env_time++;
switch(l_env_stage)
{
case 0: l_env_length = l_env_length_0; break;
case 1: l_env_length = l_env_length_1; break;
case 2: l_env_length = l_env_length_2; break;
}
if(l_env_time > l_env_length)
{
l_env_time = 0;
l_env_stage++;
}
float tl = l_env_time ? l_env_time/l_env_length : 0;
switch(l_env_stage)
{
case 0: l_env_vol = tl; break;
case 1: l_env_vol = 1+(1-tl)*2*l_env_punch; break;
case 2: l_env_vol = 1-tl; break;
}
// Phaser
if(l_fphase || l_fdphase)
{
l_fphase += l_fdphase;
l_iphase = abs(l_fphase);
if(l_iphase > 1023)l_iphase = 1023;
}
// Filter
if(l_flthp_d != 0)
{
l_flthp *= l_flthp_d;
if(l_flthp < 0.00001)l_flthp = 0.00001;
if(l_flthp > 0.1)l_flthp = 0.1;
}
// Supersampler
float ssample = 0;
for(int si=0; si<sp; si++)
{
float sample = 0;
l_phase += ss;
if(l_phase >= l_period)l_phase = l_phase-floor(l_phase/l_period)*l_period;
float fp = l_phase/l_period;
switch(l_wave_type)
{
case 0: sample = fp < l_square_duty ? -0.5 : 0.5; break;
case 1: sample = 1-fp*2; break;
case 2: sample = sin(fp*PI*2); break;
case 3: int pnoise = fp*32;
if(pnoise != l_ppnoise){l_fnoise = rnd()*2-1; l_ppnoise = pnoise;}
sample = l_fnoise; break;
}
// Filter
float pp = l_fltp;
l_fltw *= l_fltw_d;
if(l_fltw < 0)l_fltw = 0;
if(l_fltw > 0.1)l_fltw = 0.1;
if(l_lpf_freq != 1)
{
l_fltdp += (sample-l_fltp)*l_fltw;
l_fltdp -= l_fltdp*l_fltdmp;
}
else
{
l_fltp = sample;
l_fltdp = 0;
}
l_fltp += l_fltdp;
l_fltphp += l_fltp-pp;
l_fltphp -= l_fltphp*l_flthp;
sample = l_fltphp;
// Phaser
if(l_fphase || l_fdphase)
{
phaser_buffer[l_ipp&1023] = sample;
sample += phaser_buffer[(l_ipp-l_iphase+1024)&1023];
l_ipp = (l_ipp+1)&1023;
}
// Accumulate
ssample += sample;
}
buffer[i] = ssample*l_env_vol*sound_vol*2/sp;
}
// Repeat
rep_time = l_rep_time;
// Arpeggio
arp_time = l_arp_time;
arp_limit = l_arp_limit;
// Base
phase = l_phase;
period = l_period;
fperiod = l_fperiod;
fslide = l_fslide;
// Square
square_duty = l_square_duty;
// Vibrato
vib_phase = l_vib_phase;
// Envelope
env_time = l_env_time;
env_stage = l_env_stage;
// Noise
fnoise = l_fnoise;
ppnoise = l_ppnoise;
// Phaser
fphase = l_fphase;
iphase = l_iphase;
ipp = l_ipp;
// Filter
fltw = l_fltw;
flthp = l_flthp;
fltp = l_fltp;
fltdp = l_fltdp;
fltphp = l_fltphp;
// Synth
sampling = l_sampling;
}]]>
</Source>
</ZLibrary>
<ZLibrary Comment="SFXR Samples" HasInitializer="1">
<Source>
<![CDATA[// Wave shapes
byte SQUARE = 0;
byte SAWTOOTH = 1;
byte SINE = 2;
byte NOISE = 3;
void setcurrentSound(int i)
{
currentSound = i;
switch (currentSound)
{
case 0: text.Text = "PICKUP COIN"; break;
case 1: text.Text = "LASER SHOOT"; break;
case 2: text.Text = "EXPLOSION"; break;
case 3: text.Text = "POWERUP"; break;
case 4: text.Text = "HIT HURT"; break;
case 5: text.Text = "JUMP"; break;
case 6: text.Text = "BLIP SELECT"; break;
case 7: text.Text = "SYNTH"; break;
case 8: text.Text = "TONE"; break;
case 9: text.Text = "CLICK"; break;
case 10: text.Text = "RANDOM"; break;
}
}
void initSound()
{
// Wave shape
wave_type = SQUARE;
// Envelope
p_env_attack = 0; // Attack time
p_env_sustain = 0.3; // Sustain time
p_env_punch = 0; // Sustain punch
p_env_decay = 0.4; // Decay time
// Tone
p_base_freq = 0.3; // Start frequency
p_freq_limit = 0; // Min frequency cutoff
p_freq_ramp = 0; // Slide (SIGNED)
p_freq_dramp = 0; // Delta slide (SIGNED)
// Vibrato
p_vib_strength = 0; // Vibrato depth
p_vib_speed = 0; // Vibrato speed
// Tonal change
p_arp_mod = 0; // Change amount (SIGNED)
p_arp_speed = 0; // Change speed
// Square wave duty (proportion of time signal is high vs. low)
p_duty = 0; // Square duty
p_duty_ramp = 0; // Duty sweep (SIGNED)
// Repeat
p_repeat_speed = 0; // Repeat speed
// Flanger
p_pha_offset = 0; // Flanger offset (SIGNED)
p_pha_ramp = 0; // Flanger sweep (SIGNED)
// Low-pass filter
p_lpf_freq = 1; // Low-pass filter cutoff
p_lpf_ramp = 0; // Low-pass filter cutoff sweep (SIGNED)
p_lpf_resonance = 0;// Low-pass filter resonance
// High-pass filter
p_hpf_freq = 0; // High-pass filter cutoff
p_hpf_ramp = 0; // High-pass filter cutoff sweep (SIGNED)
// Sample parameters
sound_vol = 0.5;
// sample_rate = 44100;
// sample_size = 8;
}
void pickupCoin() {
wave_type = SAWTOOTH;
p_base_freq = 0.4 + frnd(0.5);
p_env_attack = 0;
p_env_sustain = frnd(0.1);
p_env_decay = 0.1 + frnd(0.4);
p_env_punch = 0.3 + frnd(0.3);
if (irnd(1)) {
p_arp_speed = 0.5 + frnd(0.2);
p_arp_mod = 0.2 + frnd(0.4);
}
}
void laserShoot() {
wave_type = irnd(2);
if(wave_type == SINE && irnd(1))
wave_type = irnd(1);
if (irnd(2) == 0) {
p_base_freq = 0.3 + frnd(0.6);
p_freq_limit = frnd(0.1);
p_freq_ramp = -0.35 - frnd(0.3);
} else {
p_base_freq = 0.5 + frnd(0.5);
p_freq_limit = p_base_freq - 0.2 - frnd(0.6);
if (p_freq_limit < 0.2) p_freq_limit = 0.2;
p_freq_ramp = -0.15 - frnd(0.2);
}
if (wave_type == SAWTOOTH)
p_duty = 1;
if (irnd(1)) {
p_duty = frnd(0.5);
p_duty_ramp = frnd(0.2);
} else {
p_duty = 0.4 + frnd(0.5);
p_duty_ramp = -frnd(0.7);
}
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.2);
p_env_decay = frnd(0.4);
if (irnd(1))
p_env_punch = frnd(0.3);
if (irnd(2) == 0) {
p_pha_offset = frnd(0.2);
p_pha_ramp = -frnd(0.2);
}
//if (irnd(1))
p_hpf_freq = frnd(0.3);
}
void explosion() {
wave_type = NOISE;
if (irnd(1)) {
p_base_freq = sqr(0.1 + frnd(0.4));
p_freq_ramp = -0.1 + frnd(0.4);
} else {
p_base_freq = sqr(0.2 + frnd(0.7));
p_freq_ramp = -0.2 - frnd(0.2);
}
if (irnd(4) == 0)
p_freq_ramp = 0;
if (irnd(2) == 0)
p_repeat_speed = 0.3 + frnd(0.5);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.3);
p_env_decay = frnd(0.5);
if (irnd(1)) {
p_pha_offset = -0.3 + frnd(0.9);
p_pha_ramp = -frnd(0.3);
}
p_env_punch = 0.2 + frnd(0.6);
if (irnd(1)) {
p_vib_strength = frnd(0.7);
p_vib_speed = frnd(0.6);
}
if (irnd(2) == 0) {
p_arp_speed = 0.6 + frnd(0.3);
p_arp_mod = 0.8 - frnd(1.6);
}
}
void powerUp() {
if (irnd(1)) {
wave_type = SAWTOOTH;
p_duty = 1;
} else {
p_duty = frnd(0.6);
}
p_base_freq = 0.2 + frnd(0.3);
if (irnd(1)) {
p_freq_ramp = 0.1 + frnd(0.4);
p_repeat_speed = 0.4 + frnd(0.4);
} else {
p_freq_ramp = 0.05 + frnd(0.2);
if (irnd(1)) {
p_vib_strength = frnd(0.7);
p_vib_speed = frnd(0.6);
}
}
p_env_attack = 0;
p_env_sustain = frnd(0.4);
p_env_decay = 0.1 + frnd(0.4);
}
void hitHurt() {
wave_type = irnd(2);
if (wave_type == SINE)
wave_type = NOISE;
if (wave_type == SQUARE)
p_duty = frnd(0.6);
if (wave_type == SAWTOOTH)
p_duty = 1;
p_base_freq = 0.2 + frnd(0.6);
p_freq_ramp = -0.3 - frnd(0.4);
p_env_attack = 0;
p_env_sustain = frnd(0.1);
p_env_decay = 0.1 + frnd(0.2);
if (irnd(1))
p_hpf_freq = frnd(0.3);
}
void jump() {
wave_type = SQUARE;
p_duty = frnd(0.6);
p_base_freq = 0.3 + frnd(0.3);
p_freq_ramp = 0.1 + frnd(0.2);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.3);
p_env_decay = 0.1 + frnd(0.2);
if (irnd(1))
p_hpf_freq = frnd(0.3);
if (irnd(1))
p_lpf_freq = 1 - frnd(0.6);
}
void blipSelect() {
wave_type = irnd(1);
if (wave_type == SQUARE)
p_duty = frnd(0.6);
else
p_duty = 1;
p_base_freq = 0.2 + frnd(0.4);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.1);
p_env_decay = frnd(0.2);
p_hpf_freq = 0.1;
}
void synth() {
wave_type = irnd(1);
// p_base_freq = [0.2723171360931539, 0.19255692561524382, 0.13615778746815113][];
int bf = irnd(2);
if (bf == 0) p_base_freq = 0.27231713;
else if (bf == 1) p_base_freq = 0.19255692;
else p_base_freq = 0.13615778;
p_env_attack = irnd(4) > 3 ? frnd(0.5) : 0;
p_env_sustain = frnd(1);
p_env_punch = frnd(1);
p_env_decay = frnd(0.9) + 0.1;
// p_arp_mod = [0, 0, 0, 0, -0.3162, 0.7454, 0.7454][irnd(6)];
int am = irnd(2);
if (am == 4) p_arp_mod = -0.3162;
else if (am == 5) p_arp_mod = 0.7454;
else if (am == 6) p_arp_mod = 0.7454;
else p_arp_mod = 0;
p_arp_mod = 0.7454;
p_arp_speed = frnd(0.5) + 0.4;
p_duty = frnd(1);
p_duty_ramp = irnd(2) == 2 ? frnd(1) : 0;
// p_lpf_freq = [1, 0.9 * frnd(1) * frnd(1) + 0.1][irnd(1)];
p_lpf_freq = irnd(1) ? 0.9 * frnd(1) * frnd(1) + 0.1 : 1;
p_lpf_ramp = rndr(-1, 1);
p_lpf_resonance = frnd(1);
p_hpf_freq = irnd(3) == 3 ? frnd(1) : 0;
p_hpf_ramp = irnd(3) == 3 ? frnd(1) : 0;
}
void tone() {
wave_type = SINE;
p_base_freq = 0.35173364; // 440 Hz
p_env_attack = 0;
p_env_sustain = 0.6641; // 1 sec
p_env_decay = 0;
p_env_punch = 0;
}
void click() {
//const base = ["explosion", "hitHurt"][irnd(1)];
//this[base]();
if (irnd(1)) {
p_freq_ramp = -0.5 + frnd(1.0);
}
if (irnd(1)) {
p_env_sustain = (frnd(0.4) + 0.2) * p_env_sustain;
p_env_decay = (frnd(0.4) + 0.2) * p_env_decay;
}
if (irnd(3) == 0) {
p_env_attack = frnd(0.3);
}
p_base_freq = 1 - frnd(0.25);
p_hpf_freq = 1 - frnd(0.1);
}
void random() {
wave_type = irnd(3);
if (irnd(1))
p_base_freq = cube(frnd(2) - 1) + 0.5;
else
p_base_freq = sqr(frnd(1));
p_freq_limit = 0;
p_freq_ramp = pow(frnd(2) - 1, 5);
if (p_base_freq > 0.7 && p_freq_ramp > 0.2)
p_freq_ramp = -p_freq_ramp;
if (p_base_freq < 0.2 && p_freq_ramp < -0.05)
p_freq_ramp = -p_freq_ramp;
p_freq_dramp = pow(frnd(2) - 1, 3);
p_duty = frnd(2) - 1;
p_duty_ramp = pow(frnd(2) - 1, 3);
p_vib_strength = pow(frnd(2) - 1, 3);
p_vib_speed = rndr(-1, 1);
p_env_attack = cube(rndr(-1, 1));
p_env_sustain = sqr(rndr(-1, 1));
p_env_decay = rndr(-1, 1);
p_env_punch = pow(frnd(0.8), 2);
if (p_env_attack + p_env_sustain + p_env_decay < 0.2) {
p_env_sustain += 0.2 + frnd(0.3);
p_env_decay += 0.2 + frnd(0.3);
}
p_lpf_resonance = rndr(-1, 1);
p_lpf_freq = 1 - pow(frnd(1), 3);
p_lpf_ramp = pow(frnd(2) - 1, 3);
if (p_lpf_freq < 0.1 && p_lpf_ramp < -0.05)
p_lpf_ramp = -p_lpf_ramp;
p_hpf_freq = pow(frnd(1), 5);
p_hpf_ramp = pow(frnd(2) - 1, 5);
p_pha_offset = pow(frnd(2) - 1, 3);
p_pha_ramp = pow(frnd(2) - 1, 3);
p_repeat_speed = frnd(2) - 1;
p_arp_speed = frnd(2) - 1;
p_arp_mod = frnd(2) - 1;
}
void mutate() {
if (irnd(1)) p_base_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_freq_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_freq_dramp += frnd(0.1) - 0.05;
if (irnd(1)) p_duty += frnd(0.1) - 0.05;
if (irnd(1)) p_duty_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_vib_strength += frnd(0.1) - 0.05;
if (irnd(1)) p_vib_speed += frnd(0.1) - 0.05;
//if (irnd(1)) p_vib_delay += frnd(0.1) - 0.05;
if (irnd(1)) p_env_attack += frnd(0.1) - 0.05;
if (irnd(1)) p_env_sustain += frnd(0.1) - 0.05;
if (irnd(1)) p_env_decay += frnd(0.1) - 0.05;
if (irnd(1)) p_env_punch += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_resonance += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_hpf_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_hpf_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_pha_offset += frnd(0.1) - 0.05;
if (irnd(1)) p_pha_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_repeat_speed += frnd(0.1) - 0.05;
if (irnd(1)) p_arp_speed += frnd(0.1) - 0.05;
if (irnd(1)) p_arp_mod += frnd(0.1) - 0.05;
}]]>
</Source>
</ZLibrary>
<SetAppState State="Demo"/>
</OnLoaded>
<States>
<AppState Name="Demo">
<Definitions>
<Sample Name="MySample" Length="1.5812">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sound Name="MySound" Length="1.5812" Volume="0.29" Mod0Active="1" Mod0Destination="1" Mod0Amount="1" Env0Active="1" Env0ReleaseTime="0.2" Sample="MySample" SampleRepeatPosition="-1" UseSampleHz="255"/>
<Variable Name="MySampleIndex" Type="1"/>
</Definitions>
<OnStart>
<ZExpression Expression="setcurrentSound(irnd(9));"/>
</OnStart>
<OnUpdate>
<KeyPress Comment="0 - pickupCoin" Keys="0">
<OnPressed>
<ZExpression Expression="setcurrentSound(0);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="1 - laserShoot" Keys="1">
<OnPressed>
<ZExpression Expression="setcurrentSound(1);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="2 - explosion" Keys="2">
<OnPressed>
<ZExpression Expression="setcurrentSound(2);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="3 - powerUp" Keys="3">
<OnPressed>
<ZExpression Expression="setcurrentSound(3);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="4 - hitHurt" Keys="4">
<OnPressed>
<ZExpression Expression="setcurrentSound(4);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="5 - jump" Keys="5">
<OnPressed>
<ZExpression Expression="setcurrentSound(5);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="6 - blipSelect" Keys="6">
<OnPressed>
<ZExpression Expression="setcurrentSound(6);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="7 - synth" Keys="7">
<OnPressed>
<ZExpression Expression="setcurrentSound(7);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="8 - tone" Keys="8">
<OnPressed>
<ZExpression Expression="setcurrentSound(8);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="9 - click" Keys="9">
<OnPressed>
<ZExpression Expression="setcurrentSound(9);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="R - random" Keys="R">
<OnPressed>
<ZExpression Expression="setcurrentSound(10);"/>
</OnPressed>
</KeyPress>
<KeyPress Comment="left click play sound" Keys="{" RepeatDelay="0.2">
<OnPressed>
<ZExpression Comment="Sound library">
<Expression>
<![CDATA[if (App.MousePosition.Y > 0.7)
{
// Normalize the mouse_x position from the range (-1, 1) to the range (0, 1)
float normalized_x = (App.MousePosition.X + 1) / 2;
// Calculate the index in the range of the buttons (0-9)
setCurrentSound(floor(normalized_x * 10));
}
sound_vol = 0.5;
initSound();
switch(currentSound)
{
case 0: pickupCoin(); break;
case 1: laserShoot(); break;
case 2: explosion(); break;
case 3: powerUp(); break;
case 4: hitHurt(); break;
case 5: jump(); break;
case 6: blipSelect(); break;
case 7: synth(); break;
case 8: tone(); break;
case 9: click(); break;
case 10: random(); break; // !!! Can trigger an infinite loop in SynthSample()
}
playSound = 1;]]>
</Expression>
</ZExpression>
</OnPressed>
</KeyPress>
<KeyPress Comment="right click mutate sound" Keys="}" RepeatDelay="0.2">
<OnPressed>
<ZExpression Comment="Sound library">
<Expression>
<![CDATA[mutate();
playSound = 1;]]>
</Expression>
</ZExpression>
</OnPressed>
</KeyPress>
<Condition Comment="playSound?" Expression="return playSound;">
<OnTrue>
<ZExpression>
<Expression>
<![CDATA[playSound = 0;
//
float S = SampleLength(); // Get the sample length
float L = S/44100; // Get the sample length in seconds
//
MySound.Length = L; // Set the Sound component length
MySample.Length = L; // Set the Sample component length
//
buffer.SizeDim1 = S + 1; // Set buffer size
MySampleIndex = 0;
ResetSample(0); // Reset the synthesizer
SynthSample(0,S,2); // Synthesize the entire sample]]>
</Expression>
</ZExpression>
<RefreshContent Component="MySample"/>
<PlaySound Sound="MySound"/>
</OnTrue>
</Condition>
</OnUpdate>
<OnRender>
<UseMaterial Material="FontMaterial4"/>
<RenderText Name="text" Text="SYNTH"/>
<RenderText Text="0" X="-0.9" Y="0.8"/>
<RenderText Text="1" X="-0.7" Y="0.8"/>
<RenderText Text="2" X="-0.5" Y="0.8"/>
<RenderText Text="3" X="-0.3" Y="0.8"/>
<RenderText Text="4" X="-0.1" Y="0.8"/>
<RenderText Text="5" X="0.1" Y="0.8"/>
<RenderText Text="6" X="0.3" Y="0.8"/>
<RenderText Text="7" X="0.5" Y="0.8"/>
<RenderText Text="8" X="0.7" Y="0.8"/>
<RenderText Text="9" X="0.9" Y="0.8"/>
</OnRender>
</AppState>
</States>
<Content>
<Variable Name="CurrentSound" Type="4"/>
<Variable Name="playSound" Type="4"/>
<Group Comment="SFXR">
<Children>
<Group Comment="Sample">
<Children>
<Group Comment="Synth">
<Children>
<Variable Name="sampling" Type="1"/>
<Array Name="buffer" SizeDim1="69729"/>
</Children>
</Group>
<Group Comment="Base">
<Children>
<Variable Name="phase"/>
<Variable Name="period"/>
<Variable Name="fperiod"/>
<Variable Name="fmaxperiod"/>
<Variable Name="fslide"/>
<Variable Name="fdslide"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="square_duty"/>
<Variable Name="square_slide"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="vib_phase"/>
<Variable Name="vib_speed"/>
<Variable Name="vib_amp"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="env_stage"/>
<Variable Name="env_time"/>
<Array Name="env_length" SizeDim1="3"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="fltp"/>
<Variable Name="fltdp"/>
<Variable Name="fltw"/>
<Variable Name="fltw_d"/>
<Variable Name="fltdmp"/>
<Variable Name="fltphp"/>
<Variable Name="flthp"/>
<Variable Name="flthp_d"/>
</Children>
</Group>
<Group Comment="Noise">
<Children>
<Variable Name="fnoise"/>
<Variable Name="ppnoise" Type="1"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="fphase"/>
<Variable Name="fdphase"/>
<Variable Name="iphase" Type="1"/>
<Variable Name="ipp" Type="1"/>
<Array Name="phaser_buffer" SizeDim1="1024"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="rep_time"/>
<Variable Name="rep_limit"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="arp_time"/>
<Variable Name="arp_mod"/>
<Variable Name="arp_limit"/>
</Children>
</Group>
</Children>
</Group>
<Group Comment="Parameters">
<Children>
<Group Comment="Base">
<Children>
<Variable Name="wave_type" Type="1"/>
<Variable Name="sound_vol"/>
<Variable Name="p_base_freq"/>
<Variable Name="p_freq_limit"/>
<Variable Name="p_freq_ramp"/>
<Variable Name="p_freq_dramp"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="p_duty"/>
<Variable Name="p_duty_ramp"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="p_vib_speed"/>
<Variable Name="p_vib_strength"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="p_env_attack"/>
<Variable Name="p_env_sustain"/>
<Variable Name="p_env_decay"/>
<Variable Name="p_env_punch"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="p_lpf_freq"/>
<Variable Name="p_lpf_ramp"/>
<Variable Name="p_lpf_resonance"/>
<Variable Name="p_hpf_freq"/>
<Variable Name="p_hpf_ramp"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="p_pha_offset"/>
<Variable Name="p_pha_ramp"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="p_repeat_speed"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="p_arp_speed"/>
<Variable Name="p_arp_mod"/>
</Children>
</Group>
</Children>
</Group>
</Children>
</Group>
<Group Name="Font4Group">
<Children>
<Bitmap Name="FontBitmap4" Width="512" Height="128">
<Producers>
<BitmapFromFile Transparency="1" DataWidth="512" DataHeight="128">
<BitmapFile>
<![CDATA[789CED5D8195E32A0C743129C6CDA498349362D24CFEEE618F074960094876B39F793CBFBBB52D84908410982CCBC4C4C4C4C4C48175BDDEEF8FAF72BBDDBFCAF57A4BFF487F7C3C9EDFE5B9977FFF15CF7F9544E77259BFCAD73FBE4AFA7BBAE541A9463C60DC2D30C30C186DF9F7FAD70351412552A8051545E9082456B92DB2A5D5662699D7E90B222552CDFC0FA12F5A94FE1DE5AAA4A8CED72176D104CFBB45ABD909FA553749804D29248489090FBE2D77D743E1D96C652E2B6DA2A68700BFE9956AE407C60C01E42242E24A5508E75FF7BDA7D83CBF6A8B73D83DE521EA73A22EB7817E4514FAE1A8EB2B71E27C3D49DE0C6F3CEF8E1D0258874342989838857438F75B5B81C748AACBB7FCA607479D117F48FF2F1F682ED476BFC4B4A04E63EFD3561FDEA0B52D251ED2B4CE4F9F1D8E6708184E5F2B4083EBDBF8C995D04FE4AB45428743FEBFC78E4A25C4FFC484074760D9AD9F883F93A508D5753A5804D519F1DC3F2743186859C8543885A60DBC39FEFF6AC81125F6B5C20CAAB32834428D674C15FE5F415F8FEFA1F963C21660AB1A9DAFA711AAEDF52DC21FA79F30A2A81026262AE098ED4BC12BD7D307BEAE883F937FCEEEFABC2B32BD82B2783D59E2293FA16B322E67C603EE0E14DAD2E65FAF6C898211ADD03C609DA29926DCBBC9FF8BE86F7F54BD1392ADEE23E774065D2374CCDFC5187AC6AA6868FD6262A28E23E77FBB0E29883FE1138EE25EC44C81B4249E6B7E7A7814DBA98416F8B4DC42BE851B929CCC902292E4C818F752FED777BA75AFA3BF4DC7F2DE490919A760B19341C8C74F41372DE0FF9F23CD8A0515CA524E4C5490ECEE4BAFBFED4B5CC93987167F9381A4BF3341FF22669A44F0BB3A4B60AE8B9DAEB81D2D329B7C0BACAF25E26DEF722BBED9B698716EBBFA6E5199874D2C4EFA1091F5BC587FF1D3670A7EFADBDAAB5248FF323D5AC71585727449A39887FA9A3523F55449CDBE19B1763739D5D8C9FFC444056C205CA06C7098D15D28CB1EBF09CA6DC5DC3B6AEE8BF30F01705CBAAEA8811F25B83607CE4BEDF58CBC42C89C248FD217DD2DB5629764887FA683AD651EFAA999C633D634440359354121B446AF29F85F474FD515DBDC2677AAC64EFE27264A80817C29F5B72AEE5756B39E0D8DC9D805F1C6EB3E0719D87C0C55A2AE5882F79FFF177CFA79D8F6345A0CF0485A011C94E6E1D83319A19FB4026EC7D08DDDFD62F255A10F3F9FEE6EFED0473F89D756CEB3EF35D88B3285E81EDDC4AAA0E07F1D237549B1BF4BF0BB9889892180757041A4E1F43C7AF73B26C88994A0DF56100B8D95C0E6A9F2BAFC06AE1B185A9B4BB2BAFE4B2AA04477DDEB4E84A05243DAE8635548F720E2CF3AFD2443C400C7BBCFA79FFEF7F0AA55348F4F34E7592E45756E6881268D53FD140411591C3BAC2626C662F3DB97E55BABF76B6999CF0486003D875DF6F92F13EFB926236A585DAD60F3C0795DFE09FE262B7A37B436B7B9A9BC9908AA9D44742782874EFAC9FD7E47025647D4E983C8E6A5F7BB227D54A78F07D210C08FD5D79E8E444AFE96734AC5C024E5A0135FE2079315F57E5184333151C2E6BABF6C762F88559C14F03C13C1FE1358374A2DAB99A7B533827B199BF93C06ACBC16BFFBD5AC86D6E692A084E8A2E1A5268215D27EFAE81726C2F38B53FAE2F5AFFFB27CEAF4173A4AC2D48792F3D77D0A07DBF2F9D843EA7043AEE68894AC86B459DFC4440F109324C04642FE27793C26020381E58A5BFEDD447837BD8E87351B226BED5CA44EE16B466777624E018AB687462884EE2C9F06FFCFAD601EFAE9234BA395A4423F8BFFF718203D20F26375FA1B85BDFB444FF901D7DA9060D972A1397B6DB9FA23535A6808C6EEB9BC3BF106601B4C32D22D937CBD85167CB7142E11C104B972AB0E76D1783D5130D7FE30A64437A9A67F33FD508A000433F622FE5FBCDE105BE2549C83877D881C427F4BE0E744E0FF4FE96F6BB8FF9E49CBC1C20957E827A43142E8AABF5CE9243D67938FB509A578227A89268258F1EADC9A41CEC4C4406CAE3257BFB07F78E6C1F63FE70CFF2FE84783CF144C9A96C28FC169449D8369807E21942A75363079127EB121B64CE90E938721F42B4AE2A12F1CA95EE5F428E1BA5E317C37F6B26F50AECD22A9880742F2AC6B7503CF13136D38FCF31E2A37AC6D4157714506E030EDFD6E68EFDC423B18B32A68828C84B3E0A1F98AE56C0F7BDBF4812944CC36B91A517B344771381396CFEEFFFBE927C72B3A11FEFF94BEF8AC40FBF60A7DDDD2630808F6ACA7434572129A96CD259FEA8F4F2F7D001FAD9C733E87808997416AF823169F6F449ED228B07F66336DEB9613D8C8C144787D731B1D5443DA0A824C277B2B1DD4CFC5F97A164612037EF92C38A0CCE26108FDC3DF2A25F1D0C79A2627DF9CF419EC9CDB7AB69EFFC9F28121E22A26F1C0546C93E7B91C3CF12224D54584F6D8E373BF8B3E224FA223CFFF21FAA19D8D09C92A99088C82E328F140DB356A6E306141C7F97A8987907CD26C45931A453F396DB3135F4D1F58E96BB2E6FEAD8CECEC8DDB8837B4FD580838D3C9F95DC0C42BC0C94CAC67855CF44ABF17C344E0FFAFFB17A0E2961F307C8E24EFF47D13DFE212FDA03EE4BA13127D5DB5F3752DBA061EB47CC0C38BE823427835FD8435FF94B8B994327B88223AE943C3A36DAF370D29AF905427264E01FF9FBC62DAF91972D1B07A50482690E6F8D06DA61F5A7F84C716D7640E89557D17AD080D01D18169D95D07D77E8F446BA976E63C9A4658689065E11CFEBF9B3EE6172CDEC3FFBF92FE922FEE6B4D909DF8CC32275A67CC95FDA41EA69A55E8979E8F3A6AB175ADA4ED0D1B332626EAE0353B94AB7B8B385B8DA000FFCF6B760D6ACCB6CC446EFBFE4341FF46DB3B9BC5E247F254828180FFA72D3137EC6C89FB7FB38CA20FF78872ECEF7A31FD852264B38D7208C89DBF2E5A374C156AA68F5A421260E75FA1F936AD9EF89F808319ECE546A92BDBBAFF982FBF0B0A378ACFC5DD987BFCC7A1A6CFF38B52ED6F007C97E0C1F93AF65CE1DDE451433C88EE63210FA1BFEE87FC30FDC3FFBF923E07FF662FDFAC6F15E1CFCD7779860BFAA68239E99BEC8524B0E4F36893E02D3E379F98A803B96B76FB224922766CA6748AD07FFD2EEC6B3B1F2CBF7BCA184FBA057DB60293070E805F8DEBFE859A28CED731BAA134C4CF660F261E86D03F0EA97B3B7D53CD20704F7C62F60EEF4FD07743F4C590C14442425896E3CB5FD3AC4036BA836E62A2024E30B2C9DCCCE4679EFFD46F21919B88C3B471379B539773B66C0B4C9F0F175DF2D3E7CC5AEA93771E50F4EF082C64922556D963B0DFF02C3D2CF4E92B2834E4CF3511F03F843EBE2F66F1BE873E84CC4DF387C1ECFC8516ADB43F4DD41EA25FA1B0E4E35749CDB4623CF62F20CCEBF4FF13630113D3051B63B4F72B3DCF5B20A0E728994F2EE7544BF485FF17ABBDBAAEBAF7D6B6C956B988FDED05564DD1796C1CF4B50043DD078FA1DDE310FA9A32A657EFA72F14E014579A906AF9684D8BD2E769B2A0B3E4C15549CDB462E083B24A09497862A202A8229FDCDE70C55652A6DC4C4D5FB5F2C36A06D692D67339FE1C48395D938D9BF485003D480393AE6814FD95626610817F7E29FD077D4E021D88EE4F8693673A3CBE9BDDE4A7AF99BCD0F78FFA56FFB52DBF34315182887F1A0A02634116C34A6731D3AAEB3E431952050AE2CFF48FB1C42FFBC12F26FD860D84899AAE65147D8E0D402475F4ABE9EBCE6D887EE184852E2D7B7EAF93BEA9812B9D7F355C7FC0FFC4C428882160F997BDF15C11846B9D8469FBA9E92BCFA035DB982F77D6225A04FFDFCFBFBE22FED7F41B56AE11FF8308F20F43E8A71C05134192E7D5F475D31A425FACB680CE15FBA3F6441CDF0AFB7F4BFEF0FFE2D6906BDB16A389893A300438030C4E5D9ACFC3D0DAC099F68A55726EBFB92E5DEFB28F5F436832C0AAA6DF60DABAE1F03F43E86B973E96FF0A7DBD9BB4A147B47C502306E22EFA8A49E4971A764379F0B6ED6D13FF37F01060AF4C596BA0256AA0505F87D58B5F582076E693F1967F7B4F65E90DF127EFB870BD585E6236F7FF94E887BAACD4EA51F44B227A03FD52B786E89BBB176EF47D5C2FFD82E22D7964324A331F4D87F84D4C3871A11DFEA72EAE3E59BE39F661DA55EC8F4557E2FCDB7BEA26F6D8CF1765233D7FBDCC807EAB423FD45FA54A47D12F75D01BE8EB48A0313F66A9EE52F6CF31FA168799FF0F6E3C3B75FE0D8BEC131313131313131309D17C8E89520CBF98A19D632EDC9C49C89A16AC48075D4B7E267C6D42546E571BF397FD4CB91EE92DFC83B34D9BDB9BB1CDC5DCD1AFD917E05FE74942CC40AB05B5255FC072E6F142FA53938FBB8A0A9D21F229A52BEBFCF7674417F5DB707832C47FC5FF34748D86D9E91521AFFBC7471ECD3925A5356DE08AA4D9350DFEDFEC82A59CDA0D5956DB7A5CBF092FF4FD9A7F625E7235FDF26C183A6FF4791A3F10E2270A7F4EACDE0BE05FE74942FCDCF6A3D544A50B7D1D368A672652E2C7133688F6969A3C443E260FA7FEAD3F23BA88EFEB23EB7D420866BD8B75782C4CDB0FB3EB4B4E69A52CB45F734AD236DF1AB8F4B329E1FD86D2E06F134B4C04F24FADCB6E450A779C47AB57F1C1726BBD081292E49BE944BDEE65DFDADD2937E49F359D8AEAF66315CB46ADFCC3090CE15F3383203949BB5D4F4A45ED08827C0EFD7C9CEBE7691434443EDA584AEA0A66D2033D7601FF2FBAE6DEF4FB7452D9F2F9BB79CB0FEDDF4ADD2146318F9DC2584C812751EB5742FC57B031DCA73F8611ED4236868678612955D8C802804EFBDDE3B7E4C03BA92184AB0B9687F821125BF0FB9B0ED5ED07DC547F8F23481BC2FFA615AA4716CBBEC6142BFEC7BA6D746414393141B35F3E3A083427AD1CCDF65BC4857F1FD652DD50FF6AFF7FDF7F1FD0F0FFC1F369F5206B06E1C79CAE49DBCD81494B1B53E321D846ABDBB788D2B561FE985C161381FCC13FDF6DBC96BF325878A3E988BAC4FE96F4F79EC2565C9221747588ACE0FF854CC6CE1F850E083568BFEEB6B0394CBADBC0BFA9E457DA1F3546E6B9FE3FAC2F0EBE55B495AC1902F5CB67C54A0DD585FC98A8A8877F933E5C2B37B3797C0711080AF3F78381C2D4AC02ED58F4207524697B74467D2D92A4A1DD6088FF0AB6A90A79AA86F5A36DBD833D1EED6F4CFC0F298FC28E50A4C54656F43CF6B78F225BCAF55DF6735D465504F9EBFE1D3B7F6405182828C87F08FF891A1341903C58EC247F36E461FAA9D2D7FDF2B9EE3F76CF44841358F7338E46C907F4E1DF74D7C4FA37E71FF18FEEDF86F81F832C0BF99E9F7266F0D0A0F64F3904206610AAE559A54248E969DAEDBAA66B740B019E67222C7F79EB76B24BFF4823D02BB8A6860BF62ACFF72CE1817222958AEC82F242DEA12DF9BB7AF84E5C99FC47D71CF983A665378D8CE6D0F96382D9CBDC5ECD9E56804C439E87FF4F6685BB0DFC276A42AA493F9D5265DEFC5A0406588BFCB650791EFADF2F9FDBFE7926D7C24980DBFE9B9E263FCD8BBFBCFE22C4DBB27EFD944ACEFE470B30445FCB87FB77DDCF190EF99F92BD27A141029873650ED0B74BCDB3F2B8BDB53BA806FF8F8A9808E4BF7D4A76CDEE9E2A066B947C97361781812DBECA9F841E360F01CB1E9F68CAD2A7952B2ABD0BFE4B4FB68D59FCC1D482DFF7540C84F4FF5401A0CF5CA23E41F7F228FEE11F4AFA793AA48A779D9D02F9E8067AAC2011AFEB7FBF7CB024C14478AD0A1A2E38C13698D350A4D4C685221FAE3AECFF0B7D64D217D6E7A2FF3084FCD8D797D170A37F9FE7CE595AFD753B4873A5F571FD8CB3B05A9A52DDB85A2FDF06BB5FA17EA79281AEF2EB2CFFD44C41DF9382638D325F4FEC1DA6973FC3DAD8A051828D443395DBF5FC88CB9576F6261366F63884BBEC677909FE85CE34F30FD360CA51FDAFB7D45400E119EAFCC3488F2EE6F1EBF964CACDF62BF4D3E9243176B06AF9132C25F9C03D9624235C847E77A5DF5FEE914F1285503F2461AED79B56A1D4BF9E9DF04EF908E713DD2FADFB88F94F23AFB0AC4EFAD0CF15BF8468F9A84ABE3A8B190AB6BFE0F79584730B5ED9120527703E5C563AFCA7D4B962381314447E55DCF5A7E0104EF0EBDB84F479ECCF94B5EF467AF7ED1AAD33903A57133F7D974DB82401288F7EE05EDE15E607FC4356F538FF6FF63EDC82D33960044781134B46D4C97FA226E807FCBF7AD7EFFF2BBDEF31017611C7EB4F39BF6B96CF6D5F95D61A7EC5F759B9FE24EB5E1DB9650FB47FD04BCFA7D07D849049FBB7E6FCA169BFC94F1AFD6BA5A975DBE1990505F6FFB269AD454C4B13B664FB97CD5E96ECBA33E69ABC5BAFAFFBEFFF26FDE707422ABA4952BDFEA0FDF925E6FBF51313902FB2A9B0759C023E504A20FF3E4EF05F891CA2D8D289427ABEB9B907A6FE443F44DD9C0951807F86FE1FC2695DBF6322FE20196307BFEB7720D04F2EA1CE35257CF8FF56F9F0972642FDA00C267D78D77EE55C2CFB6D1856B6693EB762676F0B62E95668FA9660B8A0FCFB622D4067FF62FA20281CF27F1AF26FBEEA9072EBCA5C3F514E137AA517217F937E688ABACD762DAE16E47F54ED98807462CBC5E5F443C48FFC1B7B805D7F4C31EA6D003DFC27D390C41D6B731E6CE92925FF5014C7DF548AFCB9967FF3FE3DED813DEFEA0E7A440E28A864C89D148E99B865410DF211AB1525AB5FE9F76BF82EF4C4C97F1D86FDC64716C388F2EF0B84F1B6F87F6D44B43EA8A5E7D7103CAF85BC58DECFBFDA627A66A17B5B807A09C9E3042C7FE818DF0DC9071248EF8AC48EE61F2A34243E41D733FD5084CC86060A08D210BA30FD53E72CD61CEBFC274DF0727B594201185C135388CA9F33C92257094D0671CFE0A5BF976726D7C824026347F6AEDB7BEB4645D37A1C2282075890219FB4D9D521196DF8681D1AA8E97B1674FC106C20780B11D17D84F043F3DF30780923651DD05D1395CF8ADF4CB798C4FC5DDCB28700CB28A46FD91F46ED6926788C20DDE5BAFF96DF42E793F0DDD8EA1B8D6E4857DED5E60A107F3C9F4332931B0369FE95F31F1D5C9210322989F93BEEA67F07B72D55AABEEF1FCD35F49D07F7FD5C1DA6D0B3605DA7BFFD23289F2DC52A88B8FDBFC9C090D639A185001330E4F370C947AB04BF5BA93AB4FC710A6DBF0DFE59F7113C409203DF6A185F8411254195E4EF4F0E03C209B005556E559062063C2CCCF391EF9FB95CD647C11B3417FEBEE37BB936BFEB4CC11DA39BF2FF78460C2EA83DBA845482D9BA35B845410B81E7EF3D723E9DCC26FD0CD10CB56EEB23C5D5A8FC80A93F038A3BFE4F12D61486B4CE092D6458C12BE4C3559BAA1B5D3FAD40DB6F437E46F7112234991E79B6EC064CA3AD2904DD350DCA0F8534F917F4FDFC639657F2F00BCEC7E019C4882B983CFC0FDDF57431E27CE64D0F1C5BD7E70C44FD73051BD99C7E747CD14238D637738F14BD9E8EA49BFD46C8860C64D3CF9C42430854E1FF88F9C75E7D31FCE6A0F8DDE7BBE37F2D6458D070F988AA0DFAF1F3992BD0F6AB555AE7D0B413107D84205FB7B12139A08DE89EEFCF64FA0D935FED0178FD42D00F39379E0E8B4E7CF0F9788FE38FBC79A3B27A95392EE8E75E20FFEC95BD7886C84331A8E8D8E3E89ABCF661F99F9C324414A2AF85C0EB9BDC23D1729A49DBEC57BCF834BAEFDEF4B94189AB512982C3B48716FF0E846DFAAC280C699D13BA7658D070F9DCADFD81AF6BBEB65FADD2DA178907741F65F9F3DCBE1A9203DA1741C3B5641A9C4F85C92D74ECE01FD233F51FA24B7FF9BA5EF6B368FC9F9A62091B740EF9E32854AAC2938243F24ABC2B8600CC1144ED03FDBFA61FED622D04A13FBA0AE7F574320EFBE5171F8F9AF30F4D60450080EB40FFAF75A0FFEA4F62C076048521AD73420B1916345C3EA2EF34FDB1D31F6DBFBA6B922FAA3CA0FB08F3234CB7D9781BFCBF30A21BEFCFE9A6AFFB57E4CF997E34F8840FD77246D320D5A45A51E779A79FF1BDEF6B25C2BF355481152BF13A2B80796B60FED9A41F5A425AF35F2516F2115ACDF2F14CBEEE67712CEC97CB635C0807364C29F5D3D70AC0CD2F8D5FE6423013F1EF4048144AEAF71E6821C382B47C6A6A93CBCAEC358831556DC87F4F1D0F81C98350CED4959507304088562C96FF89FA37537FC4FC42D08F9E9F536132F54527FFDAC943FF319FC215B6E3A78FA41CD311E32FDFF5CB673B5988DE8536627DE1B1CF19F9DAB08A64828D05D77084AC84000AA247209FE8393F2524224C7CAC0743C25F34E174607202B60FE20F6BEE79EAFCB59E3BD5436BE07DE806180F920A9916A4E553511B212BF87653BD4BF487FB7F611AE85F3C23F8143A8FBED64AB8E43F6D89D635F87F6144C7FE9CDDFF0BF9FBAB40EF082FC7F93D413F14DC6AF7C5FA0FD78DB23A761532AEFB962741E74EEB9BE2963F85953A57BC8EBA161CCDA45A81B6F80565C224EB1F5CB6651725017422778716513FFFA600D13BFD28C9FFB1E7423BE9C3B499F3E8C8A2F533D483A6009B5AD3080CB2DA82B47C3C6A031B876713CA090FA6E98FCDFF98FA238698C467A65A6A74D0EA7DA7FD39A2EB4393F7244F53448BD535371A5B3DF44D0FC0EB3BA2F628FF62DC17FA7FA36191CDC459CB4A5BAC9902E49FBA926F5DF7C3439CFCAFFB5E566DC50B8E66CA1F601E3A5D9049D9E90156DA58C514583DB83BF8CA1FE9F4F08FCDDE25017682D3A17C4596A69FFF75FF864BA8961F42ED436B1CA6068ECA2E3A0127A92D48CB271A5C41439CF407260FD1346120629395702F3C3AC09A0487ECFF4DE7E694CF4A9F4B301DFEBE409B004A5DF9C1B6D62EF867CCE6C4334EFE314DD6F439FFC03C8B6963A909C2F38B82202D75AEB8EB716BEC2A35F1A4E70B05D8260F7AB61885D9BADB59FCCC29D3C743F2C6167AB9AC426784943C8A54071FADA04B33D904E889A6CC29FA66FE59084EE16B705A8395CAF3AEA981EFF7FF42C2B0202D9F68F256536015D577C72E7F97EC97739BA2EF10FF73A45A79573CE3897CC4FC481B264FB21A5C2842FA927BB9EDB98B75FF3E37CA3F2F1456DC2F1CD4BA1F597CA519C75D2D389A4957F12EBA60F9A7BAFA19ED9F357D3193C2BB3A7DCD4EC664A36DB9F04AF32F41F9E0BCBA9112BDCFEFA22EF0CF1E495FB53A658DAAB608CA50225E6A78B1BABC52A81034D6947F2845CFF50A4B64CDACEBBF40A923A0FF1525D1BD13E27F08E06144134CF944E78C9AC295E25B7DB761FE5507C45E521EE1677407C9B768E2A97B1039F0BB5A4AD38A6A9ABFB0DF9227B4FD67C1C5690E57CABF09FD37FC4FCE3FB74EF72C0F5EF09C66399552E94531468BBB988F57E8DF691B8CA07C57BBBF1EFBA638FB9526E7CFF32F2D16C41815E76FBE0BCB154DA89436E76F0E31A5121802A8D2441CF9E18A163538FF07FDFE9A1060D4FF6BF580099C6A38072151898598AC000E818570A5F5C15305AB0022D56D34E9DF472F7FAFEBF1A366A6FF11CDAFBB08917534F9AF479E75E70682DC849292ACBCEB5ED5527A9EA70C9C0766FE33B296D296E88BF42018C3B6FFFE2B682E7B7E6014718C685A8520D2217521C81C4570A5799C36013C30B02EEEE5751F4490EFEDA42F923068DAA856207EB8D26A0827B2421E06EE858573A1EF6B068A9D4D20C46405E83B963FFC7FBF7CE0EE041D937EC3FCEB14EC12FBFD038FBCD0C92157D3F92F344BEA547E3873A63C90FF751FD60FC93F0FFF3FAA60605AF6F86A0CD97C55480003DF90BAE0DF068A05C1A4C93F6B4E7F4974B47C46F5857602977D963AA4091C3F883EADC8B084C7FEE1BF96CF409D31F91F02530837DABFD7291FAD18184486D0F700B16BB3CCCD69D72885BCD0262893FF350FB05B7486C266268B61A5B398839718342FFBA27FF31559AF95F2AB9D64397B7629AF6DDDF2A5ED9E4A91DFB8FCF31543A89D4E9CD77C6ADF53A31EE8973CD7D149DF4CC25CF218A3873EE70F936BC2AD86F81366053A60F2B66FE7E864586AECE8F85F0801BA34443EACEDCB3E940FA4EF0427094DA90A4E70E5CC9BA0C973E17E13BEEDDB4E4CAC2AC7E2BC5672861569F8AF2C58CDB6C8BA9FF552119C0245433A13A16221A322FC049EA3690718AA17EB8F3D74383BE7A103D3130996284A49E0353F06A4877E3D91D52BB79D3DAD930DF9671D56413E0DD912578DA3F3FF5A0877DADF2E6E35F87FC12D9CFC10FA7E9416B016DA692698E1BCB7260857DC8694EFF2DB2F8600A75EF1C865D26F58ED6288E58C12CFECFF4F97452AAB78BA2DF5E5759388B99416EA443F59D14CF1DFA5FAFB4DA5CD3FE69A69C8197AD65EEBDD54573F1E02E4FA94BBB32AF4F99953998B752B7E7811FB73D4D2B3138FA7DDA285F2C35155D1D4F45B21262BB817367B0C934F61257114FD10B49A41B06BBEADD1135CB575AB36BA28FF35E5B7D4BEC43F47D415252CB1EDEFAFD55C198FFBEDD2FA42F310D01C4606ECDA1C0B68FF897F4B8C7EA68DFF0B9651CA034D5DA3EAE187980834F478BD5D4E99EB8AC45CBEA4F621610A5B60F988397B33DBE65B21263DFCB3723EE8F78306C8C752B051F41BC06A268219218ABA1E3674ABB8D5363D5C2BDBF6D42EA00A1D50A828613D28ED99864F4C4C4C4CFC5534CC73FDF1528DFE4EBC1E48EB1AB9D285BECF0A4CE1F35ADE303E724C2ED29B9ED904BF556CDAC3B5E0F86AFA6D30BBEF74FE52D24641E70DFD0B860533AFAE77E2D7E25354A2619EEB77B64B7E7EE69021404C091BB8326B79A9906FF9D9832BED1070B277EEA269D43679F08FEC6DF47B505A4B321FBED0E7F0A6F33787929E45C053E89E3DCD8F4DFC6D7C8A4A24EB78DC4797E7E1FFBF1DC868FAC8DF2647D14387BDDF8B84AC8580602031304CE685F46C36BEBC807E2792F075BFE827D7FC6BE2539E872C249D4277E25A5D1F9FF8F3D8B4EE7645F99D2AA14D6F4CD9E3FF2DC21F4D1FFE6188FFBC16B69C8DC2E67E73FFB0D2FEF38192C16A116A3FE659AFA1DF0F1D84DCD4F6576C936EE8719ECBBCA28B135742A37EA1B14FBC0D9BA25E5794DFA912C9117DDBF56DE455EE4F184DFF9E7FFF328426F24BC385BC79E0BC2ECE5F8D158E089EB7B8FD65F4FB910641D1BFC2FF2361D5A333F7A1DB3201CD58257FA5F129B9E2093F924A5CD7CB51FA76F2BF0849DF789E32A6E0FCE7E7E6FA86D3BFD3F72FA3C8BE284D9766435C11AF5F7CE734860A87F737226FFF22FA43A027CBC25163B76A27E7FE1D71BCD8E4DD3AA844E46FFE47E48A27FC482AB15E169437AC3336C0B966FA357FF9D6EA7F57FF92EB82DFFFA2D7718571AD6A63B973F576297F1AE359B62E71357C9A060F8C5A100C98EBDAFE656BB3093CBE60FC15CF8CA23F04DB3666AA02F3C70507803C6C2D12C133FE5BEADFD4D87A164868CB49A7EC72CB2A8A7CBEFD29B9E2093F588113422AF136383D0F27B2FC7B8116DA709851D80BDE6ADBC0B3589FC644F72C69968667EA3086B20C6F74BE68F3CE25383A51B09C6D0A7F20FD21D8AA23FABCDD148C49360A3B97EAFD8B969A9C3091AF622AADA78496483E25573CE1C7664ACFECB3B25F18FF9F02BEEBBA5EB66B702203979211C1D5B1D97B2CC4193B294DC75C5DAD0F997B9024C0B58C0A060E8F97370109842479297677F6E694FE106826E1A257FC3E54CE008FF262E1FE42C7149BFD9B086AFE7940311435720D2D347C4AAE78C20F9D91F89DF99F53C077A1340C6418013325DFCBF07CB2077CEC5E89A55175E95A066EA1D942DF9CFF35FFBEACA77575FA43A0750CFE3F5990A81D36551F8356FAA51E83423E0538E68C968A468B9EFED79BFF11B9E289FF21E0BBBED4325DDB7CD79D7F2293A8A5EB36557FBBCE23F521F8193B59831366FAA336A2A4DC911029BE2FDBD238F9DD50EBEAF43D70A6D0B90ADE3F0C077EDC7D06967175FF82263F96B8126AD07CD5E34B05DBAAF46567E6F24B73C5134E5432BA3FCD5A18B00B9447EB174088F3991ACA2B36969FE2B2FFB880C9CCA85AB6EF8F72190EF1FFC7BA46CEBFF8BEACB975A7F49D443C4380291FA44FB3BBE504BE8626AE3782C20397D4D25CF0152B4D5D1CFE895CF144427D47C74F7317037C5742A7EF3A766B5CE4ADB14340744D99F9E1310E2C9D6E95A96D34DA9D30D37FD0EF1B5EF7A3B3EB3B4C4AD509617EBBA0FCFB32D1BA81F43DD8CC41F578F1799A1FADF4C16FA2D0ECFF973DB4BEE59F03A3F9424AE71B3E85ACACFEF573F80772C5130925AB39B5BB5FB8E9171ABE2DC35D6F9D87C0F06E8D430EB940FA6363FF26D52DBD40CC7CFF7BE7013EB9D9F9A34629C3DDFF9F0F0175E78C1FB847204D3F020E06F881AFFFFAE9EB6EC25D675F5CF69F9F33BADB2A893D8401E00A3244078955E07AE71E3B8228BB72AC2FE70AC0D44E5B8A87B5FE4CFC0F01FD3115BB6277EF5F063D4532016DA43D34E1276D0F306208607FDB58E8FCD22E3AA536EEFE5F3BF0CEC25BAA5E4DDF830B7EDBDA5DD8455FE8A757598032FDE238BC0E74B07861D6EEFC8D03408FC203D777263E0E50C2A8CE4723AB37600B6C3060916FEC01964832CAA2968E51E6701725FAF5EB5EFB318EB4D1A95CE9F725C752E628E2D5F43DD87808562112205B8776732EC822D8C0636BFC04866D802322A134E691149DE73FFC159CA86B594B4381C71BB04D64602683F2330B7D7AA689F70F012932B4297BCA3EC61DC3DFD0C2F9ED0BFFD4D708CAECE55E4DDF035E04B157379EB216BD013E7BB183F9BB75AC103F0327EC6FE011C9EC25B48187E72FF3FC87BF01A9EA91B2BEEC20B206C045A7B6E03A907872B0823E0BA481322FDAB65D1F8F233FD343C7BCC211257B7F05E58457D3F7801741EC2180C6C474E5FC12BED410BD534AF8F012067B7EE61FEE5D2B095CB1BF81186441243444DEE6F90F7F1142E5841256AC0CB9919F6EC137D2488456B479800AE01C74153C0A44C96EC27C4A0F732F2CA1EA7A531BF5DDC36B9D91150BC14C04F1617ACC6C7B7253A17321F4D0FC6AFAFD6019A2B0033439AFF32CFAC2A400E2783795861CAC56123D7FA9E03ECF7FF8A3806E979C43C5307F49FC9FF8145B5342D37FD1643DAE898D19E2DA96083AA60F3E2F2DEA858B80FF3CF88990156E8AE9DCE8FC37DD6A0C4C2117ADE5F06AFAFDD0C322D85BF8CBACBC159E24395AC76D67820BFD3EA9D93B4EA44E670A2107BE0D19F3FC873F8ABA73109A032DFD25FE3F710BFF8CE27C5D84D9A5DC269BA12EFDCBC126301EE91A31C6E907EEF1AD1DB77D7B270A0C1CAE43DC1DB50DE0D5F4FB6176BAF87E4D488F1FA8C3D45E505BACAEC1C0E7970F8F9B37DA8CEA7CFD31CF7FF8BF42045D6DFA3310A568166682AB93209A86174B4D83DDE9BA6EB4923BB0B11892CC1AE1FFB17C89183E9A03119E47ECCF8402F0DD51E6FF6AFA9DD06E39B18779A2F9C08DE62F15E21C5F899E45FF9AF2C1ACC7390468FD09C56F5AB16FF3FC87FF0DD824B57F78272A090DB014E58DE9D42920B4C6F29F28A38680CBFE03E29CF410E5B67FF5A39F69B0CD3B9DA5CC225DA8F74515A322C057D3EF8129F9241C2409313BD6CF889E62C0E79BDA8B14131ED6CFF0AAC7A927D74A1ECADFF20E404E85456439F19110537261A46F66060E76DD3F2035AFD748EA80A733C2CA2A39E752ED62F16E719E2D5318D7EA6D047DF16483E7E4354D5C457E43DC4543B2B638561C3899FF06FA52D4F16571F3CA0AC68BAAFC00F7B8E86EAE575464AA10BE50E627452B0CBD7A660FF0BBA1FD1B5A6EBF61749EF0A0621D458FF49003BD36819F5200E836E6CEA5E22428561BD9184B52AAD72BEC37B47D853D92B375ECB8D8ED44A58A351D684BAAC5940F37563B9CBA6B6569BC87BE73B4D5CEDF2C3CF82680CFBA3E8007FCC57C3EF1269C73852B5E9E300D198D152FFE92FD7B132F45C53A8ABE886CA464053F980004936891797552BBD376A651571E1C61B943AE7ADA9EFA911FD30EEA5CA4F9671DBC0FEA15F2C18AC642FEF975F46FFB2FB0744A1E0BB5AB95CFD1326CB856F239ECB7875CCD5A26FE18B47FE8BF22A2F8A94661088061EAE225F5CFE22A741A0A67478503E929A0C3FCDFF6DD26ECA3C2FEFF2985803114E1E8D8C243E42BBA00F4B57C3ABBD59C5B5D2EC7EF3636D3AFEF62C5C83EA42DA11CE9C4E762A0FE1F8AEA5B757A2978CBE5E59FA7C2F51259DB5AF773B1349DB6ABC8FF20D0EA21CB9338C17F9A88F1C30DA9392D01D405E73C4A3E9052E6FF77CF399C3E46C31E829C4529C9F0929F1618AA42BF6882A7ED9DF26998244E7C22B47FE8BCBEF45B9B104A9C44E7B6A35AC4E95666A6C7D0C442A1F980704A0D7B33F4C70BA8EE457D2DD8E6ACE358FA9D8E0E7DEA0C7890C3714E9039FBEAA4CF695B571B2C344C12273E11031335BC463084603F2ACB79313AC18D25F5955CA68C87EBEB2CA76B9425CE4B0BF70D62346518DD36E397926052EF571942FFBA6FD7F4BEA88E7A8B8E4A9820971A62D65E09FB3532B60B3A53D7B7B981E77F823B1F08D36FBFBFC9F927884D0ECD8ACDEB1AA71B4B4ADE43877057DACD6E6ECFB0ED94BC503D2C2C1978A8EDA60C0DFF1FDC7E53DFEC643AD5E1F479D9D4F5BAF2FC6D79CE9576E608E72F6A6FA65FD299E210A0F6F535D43BF159A8070951FB9A6B461313131313BF0788A944A4F7D37C4DFCDFB1EEFBFF3107141157949A88CD38429B0AEFC40709EA433DDB4A5FBED43FB1693304811B7D47C9C447356762220A5E088609687388D21413F3ABFAC478AA7D1D9FE5193ED1B3999A5F72FE50E09E466D26307F9F62E277402EEEDC6FBA34C7FF263591EA7F51BB3E1A9FE23F191FE7D93C9ACF65C804F63E7F9F62E2D7E0588DAD6A3EBEB0F323B9AF139B7AFEC64D1A3F0BDE03F0599EE1B33C9B53F3CDE8A561A31D709FBF4F31F13B706CB4B87FDB6DE59AC2D110F1F4CA29E5DFF385CE8F43E7CF3FEBC3E70FF26C7ECD2FEAEDA3516F1FF3F729267E018ECC274DD84BA561212F79300FF1B91690C0F9F3146A7E96FFFF14CF16D2FC9ADE36852E9BB65F76662EF3F729267E00691AFB3549FFD264792DEC8508D12FEDCD366B6CF80CE4EFE1E3F2E7023A25F20B3DDBBA9F7F6BEA7C49F3BFBF6437F5F6190E5DB64587E7FCBC65E2C7C0DE984BFDBBE65015F5AF3245BDD30A964FCB9F6BFC7ECFB6D24F75080D843337351FCBF1C65BFBD1D34E1EE6E7ED133F8B753F96E7BA5EBE9DCC7E65B57C45DA417C052C6AEFDF59F7E9F8A0FCB989DFEFD94A9A8FABA9F9F25BE3FCAD5F38CC4D4C5490BC4AE667BE9CFFEE995FED81D77486EDBFEA040FB7FFF7396F9F923FFF5C989AAF95D09439CF67C52B21FF7FDF7F7D9509FEB62CD9C41FC6A67E97E54B7571BDEFBF6BF30606707A95E0E1B3D21DC3F111F9F38F86D6FC34E1127A581902B659AAEF7913F7FCD757918F1ADAD0898922B67D261467225BFB361E5023B3F159E98EE1E8CF9F1B6733E647A871E489F8D379E4E0EB1AFE3694349FFFC27FD7144CBD0DCD5BF12DFC9605DD7F1A7B684327268A400C938000E69DB9770EA5041B6FE3E1B7A13F7F5E3943551FE8C49B5B3CE7CDBEAEE16F4345F3F147DC3287009EBAE2C9D0BC35D5A84F2AEE68D6C4440008051181A4FF46BFF0EA41FAB849B33127C23D483D2B7D4B7FF92BC77494341F031FB7BA14996F4B574424B43B2E55AA853CBAAD131336B6A02E57F5F727DE53A5CCC64C8476E2882D1FCF91D7BFE2A02A9ABF7D76678E7DF91020C492B64C84FCFF36B2309D19FF4F04D19CAE491358B6F11FF9CE748BB8C810FE4C9EF9A7B005B7D64FC2F5963FE1FFEB9ABF9D585218010F224F7937743AD6A1F67919DFDA89BF8B9E9321B5EEFDC839935BC4350D611C526C9986D1B1D7BFD12FA79ABF0D018541702342F3825442A76341ED8590C7B776E22FA2FF6460EC30C1B5E178CF7E6C07840A3FF327E2CC9F82F858B5B2985BDA208405E23FB9FFC7A3F9EBFE73307A044C4260A1A56BE874ACF4301F3731D39E131E8C3A199893EDF7FD30F337FF54136A6436FE4C9EF9A710DACF5371FEE65B3FDDB801706A3E8600B3B0D04024E4FFBF4A92EA7118C5FF78DBDBC429C69E0C0C2B8012C26F8C65BB82E3582D3284E9FF275E0ABFE62393C6FAC90328FF25744C5FB25F6CC74519DDD689BF83B12703A7C04FA85FDB219F6D405C2A7898F99F899722A4F93C03E2C21F53F0A4C9C903C21EEC3EFD9F1F7B32718ADBD09381318165F5E329C658E605905B384E53D977FEFF9975C689DF89A8E6C3BDD7AFA1EFD639BDC665745B27FE0EEE434F06466E536820277B5F74FEA7B9CE88B9F68BEA9D9800A29A6FEAAA7E37BAFF5F1FC1F182B64EFC11DC479F0CCC4E985591E370BD3FA48167939459EFFCF877E20D08687EAEB4E2795CB18EE06480334E5C5EDAEA898FC663F4C9C06905CAD4C3954FE927E71FCDCCF08B4CCDAC3119E0FBF7A04EFC0F71AEF956F0837D3EE2F9E8A415F385B4EF08D7D7B577E2D3A113E3FDD132E69ED82B58B936ACCC26F339A58CBDAC33049A780F429A5FB99AA7439C22CD1752D55C5ED4D8893F00FEDE1CD148E79E31EC0F871FAE94869D99E99553CACC434F732626FCF06B7ED122D4B9104E20959A147EC6FF13A7D0D9C8217B86B5FB2D5D9BE3FF0ACDE9FC277E10620858AA8ACA57CE6A36D4AB4F7B98F9FF899F023BE1CA63CDF97FF39648A24EE73FF123E0E527CF6EBA211BE4CC6FAEA7FF9FF8418875D8D22130219A95236578F5ED452D9A98F0406BFEE91119A1DD3E1AA5D39606366A62228A3411A81F021322583F526686FD13BF07D07C63D3723E04D43DFF7FE3CA631F]]>
</BitmapFile>
</BitmapFromFile>
</Producers>
</Bitmap>
<Font Name="Font4" Bitmap="FontBitmap4" FirstChar="33" CharPixelWidth="31" CharPixelHeight="31" BorderPixels="1"/>
<Material Name="FontMaterial4" Blend="1" Font="Font4"/>
</Children>
</Group> <!-- Font4Group -->
</Content>
</ZApplication>
Edit:
I modified my example so that we can chose which sound to play using numbers 0 to 9, and R for random. This way, it is easier to discover what kind of sound crashes the program while holding the mouse click and enjoying the blip-blops.
Here are the results so far:
- Power up can crash in preview
- Explosions can crash in preview
- Synth has high chance to crash
- Tone can crash in preview
- Random has high chance to enter an ugly infinite loop
Last edited by Ats on Thu May 02, 2024 9:44 pm, edited 4 times in total.
Re: SFXR
Hi Ats,
The only "crashes" / errors i'm seeing on my end are "array access out of range" errors. You need to make sure your buffer array is large enough to fit the sound you're generating. But perhaps you're getting different errors?
K
The only "crashes" / errors i'm seeing on my end are "array access out of range" errors. You need to make sure your buffer array is large enough to fit the sound you're generating. But perhaps you're getting different errors?
K
Re: SFXR
Hahaha, I've fallen into a new loophole.
All right. So from what I understand, the buffer size should be equal to the sample lenght, right?
mmm... Nope, this is still crashing. But buffer.SizeDim1 = S + 4; works fine
I didn't manage to obtain that bug when reducing the SynthSample quality to 2.
All right. So from what I understand, the buffer size should be equal to the sample lenght, right?
Code: Select all
float S = SampleLength(); // Get the sample length
float L = S/44100; // Get the sample length in seconds
//
MySound.Length = L; // Set the Sound component length
MySample.Length = L; // Set the Sample component length
buffer.SizeDim1 = S; // Set buffer size
//
ResetSample(0); // Reset the synthesizer
SynthSample(0,S,3); // Synthesize the entire sample
With the Random and Synth sounds, I can easily get this error:Kjell wrote:But perhaps you're getting different errors?
Code: Select all
Callstack:
SynthSample
ZExpression
Infinite loop?
Re: SFXR
Hi Ats,
- Add a MySampleIndex ( type = int ) variable
- Change the SampleExpression to "this.Sample = buffer[MySampleIndex++];"
- Make sure to set MySampleIndex to 0 every time prior to using CallComponent(MySample)
Edit: My bad .. it's been a while since i looked at the SFXR source ( 10+ years ) I double-checked and there isn't anything that could cause a infinite loop. However at quality=3 the super-sampling loop runs 8 times per sample, which could end up tripping the GuardLimit in ZGE if a sound is long enough.
K
Ah .. in that case it's probably a rounding-error caused by the SampleExpression. Try the following:
- Add a MySampleIndex ( type = int ) variable
- Change the SampleExpression to "this.Sample = buffer[MySampleIndex++];"
- Make sure to set MySampleIndex to 0 every time prior to using CallComponent(MySample)
That's because SFXR uses doubles ( 64-bit floating point ) for some variables, which is something ZGE doesn't support.Kjell wrote:I didn't manage to obtain that bug when reducing the SynthSample quality to 2.
Edit: My bad .. it's been a while since i looked at the SFXR source ( 10+ years ) I double-checked and there isn't anything that could cause a infinite loop. However at quality=3 the super-sampling loop runs 8 times per sample, which could end up tripping the GuardLimit in ZGE if a sound is long enough.
K
Re: SFXR
With the new method, I still had to add a little +1 to prevent crashing. But it's running just fine
But I've yet to find which line is producing the error in the SynthSample function, for(int si=0; si<sp; si++) loop, just to try to prevent the problem.
I updated the entire project code in my previous post to include onscreen buttons, and here's the android APK - 243 KB - I love how small it is when compared to the size of an apk generated by any other engine!
And... Yeah, we can clearly feel the sound generation lag
Since I can't manage to create cool sounds using the classic ZGE interface, I'm considering a different approach. Maybe I can generate multiple sfxr variations of each sound type (laser, explosion, beeps) at the start of my game and save them as separate samples. This way, the sounds should play smoothly during the game. Am I right?
Code: Select all
buffer.SizeDim1 = S + 1; // Set buffer size
MySampleIndex = 0;
So I trimmed the extremely precise numbers jsfxr is giving, just in case: 0.023714355139274713 -> 0.02371435Kjell wrote:That's because SFXR uses doubles ( 64-bit floating point ) for some variables, which is something ZGE doesn't support.
But I've yet to find which line is producing the error in the SynthSample function, for(int si=0; si<sp; si++) loop, just to try to prevent the problem.
I updated the entire project code in my previous post to include onscreen buttons, and here's the android APK - 243 KB - I love how small it is when compared to the size of an apk generated by any other engine!
And... Yeah, we can clearly feel the sound generation lag
Since I can't manage to create cool sounds using the classic ZGE interface, I'm considering a different approach. Maybe I can generate multiple sfxr variations of each sound type (laser, explosion, beeps) at the start of my game and save them as separate samples. This way, the sounds should play smoothly during the game. Am I right?
- Attachments
-
- ZSFXR.0.1.0.apk
- (243.14 KiB) Downloaded 187 times
Re: SFXR
So I tried to initialize a bunch of sounds when starting the app, but there's something wrong with it and I don't know where...
So I'm wondering if I can really pass a Sample as a variable in a function, then do a RefreshContent on that variable, or if I messed up somewhere else with the calculation of the buffers. Or maybe I need a Sound object per Sample? I don't know...
So I'm wondering if I can really pass a Sample as a variable in a function, then do a RefreshContent on that variable, or if I messed up somewhere else with the calculation of the buffers. Or maybe I need a Sound object per Sample? I don't know...
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZSFXR" CustomScreenWidth="320" CustomScreenHeight="240" MouseVisible="255" FileVersion="2" AndroidPackageName="org.zgameeditor.zsfxr" AndroidPortrait="2">
<OnLoaded>
<ZLibrary Comment="Math">
<Source>
<![CDATA[int irnd(int i) { return round(rnd() * i); }
float frnd(float f) { return rnd() * f; }
float sqr(float x) { return x * x; }
float cube(float x) { return x * x * x; }
int sign(float x) { return x < 0 ? -1 : 1; }
float rndr(float from, float to) { return rnd() * (to - from) + from; }]]>
</Source>
</ZLibrary>
<ZLibrary Comment="SFXR">
<Source>
<![CDATA[//
float SampleLength()
{
return (p_env_attack*p_env_attack+
p_env_sustain*p_env_sustain+
p_env_decay*p_env_decay)*100000;
}
//
void ResetSample(int restart)
{
// Base
if(!restart)phase = 0;
period = 100/(p_base_freq*p_base_freq+0.001);
fperiod = period;
fmaxperiod = 100/(p_freq_limit*p_freq_limit+0.001);
fslide = 1-pow(p_freq_ramp,3)*0.01;
fdslide = pow(p_freq_dramp,3)*-0.000001;
// Square
square_duty = 0.5-p_duty*0.5;
square_slide = p_duty_ramp*-0.00005;
// Arpeggio
arp_time = 0;
arp_limit = p_arp_speed != 1 ? pow(1-p_arp_speed,2)*20000+32 : 0;
arp_mod = p_arp_mod >= 0 ? 1-pow(p_arp_mod,2)*0.9 : 1+pow(p_arp_mod,2)*10;
if(!restart)
{
sampling = 1;
// Filter
fltp = 0;
fltdp = 0;
fltw = pow(p_lpf_freq,3)*0.1;
fltw_d = 1+p_lpf_ramp*0.0001;
fltdmp = 5/(1+pow(p_lpf_resonance,2)*20)*(0.01+fltw);
if(fltdmp > 0.8)fltdmp = 0.8;
fltphp = 0;
flthp = pow(p_hpf_freq,2)*0.1;
flthp_d = 1+p_hpf_ramp*0.0003;
// Vibrato
vib_phase = 0;
vib_speed = pow(p_vib_speed,2)*0.01;
vib_amp = p_vib_strength*0.5;
// Envelope
env_stage = 0;
env_time = 0;
env_length[0] = p_env_attack*p_env_attack*100000;
env_length[1] = p_env_sustain*p_env_sustain*100000;
env_length[2] = p_env_decay*p_env_decay*100000;
// Phaser
fphase = pow(p_pha_offset,2)*1020;
if(p_pha_offset < 0)fphase *= -1;
fdphase = pow(p_pha_ramp,2);
if(p_pha_ramp < 0)fdphase *= -1;
iphase = fphase;
ipp = 0;
// Noise
fnoise = rnd()*2-1;
ppnoise = 0;
// Repeat
rep_time = 0;
rep_limit = p_repeat_speed ? pow(1-p_repeat_speed,2)*20000+32 : 0;
}
}
//
void SynthSample(int start, int end, int quality)
{
// Repeat
float l_rep_time = rep_time;
float l_rep_limit = rep_limit;
// Arpeggio
float l_arp_time = arp_time;
float l_arp_mod = arp_mod;
float l_arp_limit = arp_limit;
// Base
int l_wave_type = wave_type;
float l_phase = phase;
float l_period = period;
float l_fperiod = fperiod;
float l_fmaxperiod = fmaxperiod;
float l_fslide = fslide;
float l_fdslide = fdslide;
// Square
float l_square_duty = square_duty;
float l_square_slide = square_slide;
// Vibrato
float l_vib_phase = vib_phase;
float l_vib_speed = vib_speed;
float l_vib_amp = vib_amp;
// Envelope
float l_env_vol;
float l_env_length;
float l_env_stage = env_stage;
float l_env_time = env_time;
float l_env_punch = p_env_punch;
float l_env_length_0 = env_length[0];
float l_env_length_1 = env_length[1];
float l_env_length_2 = env_length[2];
// Noise
float l_fnoise = fnoise;
int l_ppnoise = ppnoise;
// Phaser
float l_fphase = fphase;
float l_fdphase = fdphase;
int l_iphase = iphase;
int l_ipp = ipp;
// Filter
float l_lpf_freq = p_lpf_freq;
float l_fltp = fltp;
float l_fltdp = fltdp;
float l_fltdmp = fltdmp;
float l_flthp = flthp;
float l_flthp_d = flthp_d;
float l_fltw = fltw;
float l_fltw_d = fltw_d;
float l_fltphp = fltphp;
// Supersampler
float sp = pow(2,quality);
float ss = 8/sp;
// Synth
int l_sampling = sampling;
for(int i=start; i<end; i++)
{
if(!l_sampling)
{
buffer[i] = 0;
continue;
}
// Repeat
if(l_rep_limit)
{
l_rep_time++;
if(l_rep_time >= l_rep_limit)
{
l_rep_time = 0;
ResetSample(1);
// Local
l_period = period;
l_fperiod = fperiod;
l_fslide = fslide;
l_square_duty = square_duty;
l_arp_time = arp_time;
l_arp_limit = arp_limit;
}
}
// Arpeggio
l_arp_time++;
if(l_arp_limit != 0 && l_arp_time >= l_arp_limit)
{
l_arp_limit = 0;
l_fperiod *= l_arp_mod;
}
// Base
l_fslide += l_fdslide;
l_fperiod *= l_fslide;
if(l_fperiod > l_fmaxperiod)
{
l_fperiod = l_fmaxperiod;
l_sampling = 0;
}
// Square
if(l_wave_type == 0)
{
l_square_duty += l_square_slide;
if(l_square_duty < 0)l_square_duty = 0;
if(l_square_duty > 0.5)l_square_duty = 0.5;
}
// Vibrato
float rfperiod = l_fperiod;
if(l_vib_amp > 0)
{
l_vib_phase += l_vib_speed;
rfperiod = l_fperiod*(1+sin(l_vib_phase)*l_vib_amp);
}
l_period = rfperiod;
if(l_period < 8)l_period = 8;
// Envelope
l_env_time++;
switch(l_env_stage)
{
case 0: l_env_length = l_env_length_0; break;
case 1: l_env_length = l_env_length_1; break;
case 2: l_env_length = l_env_length_2; break;
}
if(l_env_time > l_env_length)
{
l_env_time = 0;
l_env_stage++;
}
float tl = l_env_time ? l_env_time/l_env_length : 0;
switch(l_env_stage)
{
case 0: l_env_vol = tl; break;
case 1: l_env_vol = 1+(1-tl)*2*l_env_punch; break;
case 2: l_env_vol = 1-tl; break;
}
// Phaser
if(l_fphase || l_fdphase)
{
l_fphase += l_fdphase;
l_iphase = abs(l_fphase);
if(l_iphase > 1023)l_iphase = 1023;
}
// Filter
if(l_flthp_d != 0)
{
l_flthp *= l_flthp_d;
if(l_flthp < 0.00001)l_flthp = 0.00001;
if(l_flthp > 0.1)l_flthp = 0.1;
}
// Supersampler
float ssample = 0;
for(int si=0; si<sp; si++)
{
float sample = 0;
l_phase += ss;
if(l_phase >= l_period)l_phase = l_phase-floor(l_phase/l_period)*l_period;
float fp = l_phase/l_period;
switch(l_wave_type)
{
case 0: sample = fp < l_square_duty ? -0.5 : 0.5; break;
case 1: sample = 1-fp*2; break;
case 2: sample = sin(fp*PI*2); break;
case 3: int pnoise = fp*32;
if(pnoise != l_ppnoise){l_fnoise = rnd()*2-1; l_ppnoise = pnoise;}
sample = l_fnoise; break;
}
// Filter
float pp = l_fltp;
l_fltw *= l_fltw_d;
if(l_fltw < 0)l_fltw = 0;
if(l_fltw > 0.1)l_fltw = 0.1;
if(l_lpf_freq != 1)
{
l_fltdp += (sample-l_fltp)*l_fltw;
l_fltdp -= l_fltdp*l_fltdmp;
}
else
{
l_fltp = sample;
l_fltdp = 0;
}
l_fltp += l_fltdp;
l_fltphp += l_fltp-pp;
l_fltphp -= l_fltphp*l_flthp;
sample = l_fltphp;
// Phaser
if(l_fphase || l_fdphase)
{
phaser_buffer[l_ipp&1023] = sample;
sample += phaser_buffer[(l_ipp-l_iphase+1024)&1023];
l_ipp = (l_ipp+1)&1023;
}
// Accumulate
ssample += sample;
}
buffer[i] = ssample*l_env_vol*sound_vol*2/sp;
}
// Repeat
rep_time = l_rep_time;
// Arpeggio
arp_time = l_arp_time;
arp_limit = l_arp_limit;
// Base
phase = l_phase;
period = l_period;
fperiod = l_fperiod;
fslide = l_fslide;
// Square
square_duty = l_square_duty;
// Vibrato
vib_phase = l_vib_phase;
// Envelope
env_time = l_env_time;
env_stage = l_env_stage;
// Noise
fnoise = l_fnoise;
ppnoise = l_ppnoise;
// Phaser
fphase = l_fphase;
iphase = l_iphase;
ipp = l_ipp;
// Filter
fltw = l_fltw;
flthp = l_flthp;
fltp = l_fltp;
fltdp = l_fltdp;
fltphp = l_fltphp;
// Synth
sampling = l_sampling;
}]]>
</Source>
</ZLibrary>
<ZLibrary Comment="SFXR Samples" HasInitializer="1">
<Source>
<![CDATA[// Wave shapes
byte SQUARE = 0;
byte SAWTOOTH = 1;
byte SINE = 2;
byte NOISE = 3;
void setcurrentSound(int i)
{
CurrentSoundType = i;
switch (CurrentSoundType)
{
case 0: text.Text = "PICKUP COIN"; break;
case 1: text.Text = "LASER SHOOT"; break;
case 2: text.Text = "EXPLOSION"; break;
case 3: text.Text = "POWERUP"; break;
case 4: text.Text = "HIT HURT"; break;
case 5: text.Text = "JUMP"; break;
case 6: text.Text = "BLIP SELECT"; break;
case 7: text.Text = "SYNTH"; break;
case 8: text.Text = "TONE"; break;
case 9: text.Text = "CLICK"; break;
case 10: text.Text = "RANDOM"; break;
}
}
void initSound()
{
// Wave shape
wave_type = SQUARE;
// Envelope
p_env_attack = 0; // Attack time
p_env_sustain = 0.3; // Sustain time
p_env_punch = 0; // Sustain punch
p_env_decay = 0.4; // Decay time
// Tone
p_base_freq = 0.3; // Start frequency
p_freq_limit = 0; // Min frequency cutoff
p_freq_ramp = 0; // Slide (SIGNED)
p_freq_dramp = 0; // Delta slide (SIGNED)
// Vibrato
p_vib_strength = 0; // Vibrato depth
p_vib_speed = 0; // Vibrato speed
// Tonal change
p_arp_mod = 0; // Change amount (SIGNED)
p_arp_speed = 0; // Change speed
// Square wave duty (proportion of time signal is high vs. low)
p_duty = 0; // Square duty
p_duty_ramp = 0; // Duty sweep (SIGNED)
// Repeat
p_repeat_speed = 0; // Repeat speed
// Flanger
p_pha_offset = 0; // Flanger offset (SIGNED)
p_pha_ramp = 0; // Flanger sweep (SIGNED)
// Low-pass filter
p_lpf_freq = 1; // Low-pass filter cutoff
p_lpf_ramp = 0; // Low-pass filter cutoff sweep (SIGNED)
p_lpf_resonance = 0;// Low-pass filter resonance
// High-pass filter
p_hpf_freq = 0; // High-pass filter cutoff
p_hpf_ramp = 0; // High-pass filter cutoff sweep (SIGNED)
// Sample parameters
sound_vol = 0.5;
// sample_rate = 44100;
// sample_size = 8;
}
void pickupCoin() {
wave_type = SAWTOOTH;
p_base_freq = 0.4 + frnd(0.5);
p_env_attack = 0;
p_env_sustain = frnd(0.1);
p_env_decay = 0.1 + frnd(0.4);
p_env_punch = 0.3 + frnd(0.3);
if (irnd(1)) {
p_arp_speed = 0.5 + frnd(0.2);
p_arp_mod = 0.2 + frnd(0.4);
}
}
void laserShoot() {
wave_type = irnd(2);
if(wave_type == SINE && irnd(1))
wave_type = irnd(1);
if (irnd(2) == 0) {
p_base_freq = 0.3 + frnd(0.6);
p_freq_limit = frnd(0.1);
p_freq_ramp = -0.35 - frnd(0.3);
} else {
p_base_freq = 0.5 + frnd(0.5);
p_freq_limit = p_base_freq - 0.2 - frnd(0.6);
if (p_freq_limit < 0.2) p_freq_limit = 0.2;
p_freq_ramp = -0.15 - frnd(0.2);
}
if (wave_type == SAWTOOTH)
p_duty = 1;
if (irnd(1)) {
p_duty = frnd(0.5);
p_duty_ramp = frnd(0.2);
} else {
p_duty = 0.4 + frnd(0.5);
p_duty_ramp = -frnd(0.7);
}
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.2);
p_env_decay = frnd(0.4);
if (irnd(1))
p_env_punch = frnd(0.3);
if (irnd(2) == 0) {
p_pha_offset = frnd(0.2);
p_pha_ramp = -frnd(0.2);
}
//if (irnd(1))
p_hpf_freq = frnd(0.3);
}
void explosion() {
wave_type = NOISE;
if (irnd(1)) {
p_base_freq = sqr(0.1 + frnd(0.4));
p_freq_ramp = -0.1 + frnd(0.4);
} else {
p_base_freq = sqr(0.2 + frnd(0.7));
p_freq_ramp = -0.2 - frnd(0.2);
}
if (irnd(4) == 0)
p_freq_ramp = 0;
if (irnd(2) == 0)
p_repeat_speed = 0.3 + frnd(0.5);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.3);
p_env_decay = frnd(0.5);
if (irnd(1)) {
p_pha_offset = -0.3 + frnd(0.9);
p_pha_ramp = -frnd(0.3);
}
p_env_punch = 0.2 + frnd(0.6);
if (irnd(1)) {
p_vib_strength = frnd(0.7);
p_vib_speed = frnd(0.6);
}
if (irnd(2) == 0) {
p_arp_speed = 0.6 + frnd(0.3);
p_arp_mod = 0.8 - frnd(1.6);
}
}
void powerUp() {
if (irnd(1)) {
wave_type = SAWTOOTH;
p_duty = 1;
} else {
p_duty = frnd(0.6);
}
p_base_freq = 0.2 + frnd(0.3);
if (irnd(1)) {
p_freq_ramp = 0.1 + frnd(0.4);
p_repeat_speed = 0.4 + frnd(0.4);
} else {
p_freq_ramp = 0.05 + frnd(0.2);
if (irnd(1)) {
p_vib_strength = frnd(0.7);
p_vib_speed = frnd(0.6);
}
}
p_env_attack = 0;
p_env_sustain = frnd(0.4);
p_env_decay = 0.1 + frnd(0.4);
}
void hitHurt() {
wave_type = irnd(2);
if (wave_type == SINE)
wave_type = NOISE;
if (wave_type == SQUARE)
p_duty = frnd(0.6);
if (wave_type == SAWTOOTH)
p_duty = 1;
p_base_freq = 0.2 + frnd(0.6);
p_freq_ramp = -0.3 - frnd(0.4);
p_env_attack = 0;
p_env_sustain = frnd(0.1);
p_env_decay = 0.1 + frnd(0.2);
if (irnd(1))
p_hpf_freq = frnd(0.3);
}
void jump() {
wave_type = SQUARE;
p_duty = frnd(0.6);
p_base_freq = 0.3 + frnd(0.3);
p_freq_ramp = 0.1 + frnd(0.2);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.3);
p_env_decay = 0.1 + frnd(0.2);
if (irnd(1))
p_hpf_freq = frnd(0.3);
if (irnd(1))
p_lpf_freq = 1 - frnd(0.6);
}
void blipSelect() {
wave_type = irnd(1);
if (wave_type == SQUARE)
p_duty = frnd(0.6);
else
p_duty = 1;
p_base_freq = 0.2 + frnd(0.4);
p_env_attack = 0;
p_env_sustain = 0.1 + frnd(0.1);
p_env_decay = frnd(0.2);
p_hpf_freq = 0.1;
}
void synth() {
wave_type = irnd(1);
// p_base_freq = [0.2723171360931539, 0.19255692561524382, 0.13615778746815113][];
int bf = irnd(2);
if (bf == 0) p_base_freq = 0.27231713;
else if (bf == 1) p_base_freq = 0.19255692;
else p_base_freq = 0.13615778;
p_env_attack = irnd(4) > 3 ? frnd(0.5) : 0;
p_env_sustain = frnd(1);
p_env_punch = frnd(1);
p_env_decay = frnd(0.9) + 0.1;
// p_arp_mod = [0, 0, 0, 0, -0.3162, 0.7454, 0.7454][irnd(6)];
int am = irnd(2);
if (am == 4) p_arp_mod = -0.3162;
else if (am == 5) p_arp_mod = 0.7454;
else if (am == 6) p_arp_mod = 0.7454;
else p_arp_mod = 0;
p_arp_mod = 0.7454;
p_arp_speed = frnd(0.5) + 0.4;
p_duty = frnd(1);
p_duty_ramp = irnd(2) == 2 ? frnd(1) : 0;
// p_lpf_freq = [1, 0.9 * frnd(1) * frnd(1) + 0.1][irnd(1)];
p_lpf_freq = irnd(1) ? 0.9 * frnd(1) * frnd(1) + 0.1 : 1;
p_lpf_ramp = rndr(-1, 1);
p_lpf_resonance = frnd(1);
p_hpf_freq = irnd(3) == 3 ? frnd(1) : 0;
p_hpf_ramp = irnd(3) == 3 ? frnd(1) : 0;
}
void tone() {
wave_type = SINE;
p_base_freq = 0.35173364; // 440 Hz
p_env_attack = 0;
p_env_sustain = 0.6641; // 1 sec
p_env_decay = 0;
p_env_punch = 0;
}
void click() {
//const base = ["explosion", "hitHurt"][irnd(1)];
//this[base]();
if (irnd(1)) {
p_freq_ramp = -0.5 + frnd(1.0);
}
if (irnd(1)) {
p_env_sustain = (frnd(0.4) + 0.2) * p_env_sustain;
p_env_decay = (frnd(0.4) + 0.2) * p_env_decay;
}
if (irnd(3) == 0) {
p_env_attack = frnd(0.3);
}
p_base_freq = 1 - frnd(0.25);
p_hpf_freq = 1 - frnd(0.1);
}
void random() {
wave_type = irnd(3);
if (irnd(1))
p_base_freq = cube(frnd(2) - 1) + 0.5;
else
p_base_freq = sqr(frnd(1));
p_freq_limit = 0;
p_freq_ramp = pow(frnd(2) - 1, 5);
if (p_base_freq > 0.7 && p_freq_ramp > 0.2)
p_freq_ramp = -p_freq_ramp;
if (p_base_freq < 0.2 && p_freq_ramp < -0.05)
p_freq_ramp = -p_freq_ramp;
p_freq_dramp = pow(frnd(2) - 1, 3);
p_duty = frnd(2) - 1;
p_duty_ramp = pow(frnd(2) - 1, 3);
p_vib_strength = pow(frnd(2) - 1, 3);
p_vib_speed = rndr(-1, 1);
p_env_attack = cube(rndr(-1, 1));
p_env_sustain = sqr(rndr(-1, 1));
p_env_decay = rndr(-1, 1);
p_env_punch = pow(frnd(0.8), 2);
if (p_env_attack + p_env_sustain + p_env_decay < 0.2) {
p_env_sustain += 0.2 + frnd(0.3);
p_env_decay += 0.2 + frnd(0.3);
}
p_lpf_resonance = rndr(-1, 1);
p_lpf_freq = 1 - pow(frnd(1), 3);
p_lpf_ramp = pow(frnd(2) - 1, 3);
if (p_lpf_freq < 0.1 && p_lpf_ramp < -0.05)
p_lpf_ramp = -p_lpf_ramp;
p_hpf_freq = pow(frnd(1), 5);
p_hpf_ramp = pow(frnd(2) - 1, 5);
p_pha_offset = pow(frnd(2) - 1, 3);
p_pha_ramp = pow(frnd(2) - 1, 3);
p_repeat_speed = frnd(2) - 1;
p_arp_speed = frnd(2) - 1;
p_arp_mod = frnd(2) - 1;
}
void mutate() {
if (irnd(1)) p_base_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_freq_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_freq_dramp += frnd(0.1) - 0.05;
if (irnd(1)) p_duty += frnd(0.1) - 0.05;
if (irnd(1)) p_duty_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_vib_strength += frnd(0.1) - 0.05;
if (irnd(1)) p_vib_speed += frnd(0.1) - 0.05;
//if (irnd(1)) p_vib_delay += frnd(0.1) - 0.05;
if (irnd(1)) p_env_attack += frnd(0.1) - 0.05;
if (irnd(1)) p_env_sustain += frnd(0.1) - 0.05;
if (irnd(1)) p_env_decay += frnd(0.1) - 0.05;
if (irnd(1)) p_env_punch += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_resonance += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_lpf_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_hpf_freq += frnd(0.1) - 0.05;
if (irnd(1)) p_hpf_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_pha_offset += frnd(0.1) - 0.05;
if (irnd(1)) p_pha_ramp += frnd(0.1) - 0.05;
if (irnd(1)) p_repeat_speed += frnd(0.1) - 0.05;
if (irnd(1)) p_arp_speed += frnd(0.1) - 0.05;
if (irnd(1)) p_arp_mod += frnd(0.1) - 0.05;
}]]>
</Source>
</ZLibrary>
<ZLibrary Comment="Init Sound Sample">
<Source>
<![CDATA[void initSoundSample(Sample sample)
{
// Init sfxr parameters for the sound type
initSound();
switch(CurrentSoundType)
{
case 0: pickupCoin(); break;
case 1: laserShoot(); break;
case 2: explosion(); break;
case 3: powerUp(); break;
case 4: hitHurt(); break;
case 5: jump(); break;
case 6: blipSelect(); break;
case 7: synth(); break;
case 8: tone(); break;
case 9: click(); break;
case 10: random(); break; // !!! Can trigger an infinite loop in SynthSample()
}
float S = SampleLength(); // Get the sample length
float L = S / 44100; // Get the sample length in seconds
buffer.SizeDim1 = S + 1; // Set buffer size
MySampleIndex = 0;
sample.Length = L;
ResetSample(0); // Reset the synthesizer
SynthSample(0,S,2); // Synthesize the entire sample in buffer
@RefreshContent(Component:sample);
}
void attachSampleToSound(Sample sample)
{
MySound.Sample = sample;
MySound.Length = sample.Length; // Set the Sound component length
}]]>
</Source>
</ZLibrary>
<SetAppState State="Initialization"/>
</OnLoaded>
<States>
<AppState Name="Initialization">
<OnStart>
<ZExpression Expression="CurrentSoundType = -1;
setRandomSeed(getSystemTime());"/>
</OnStart>
<OnUpdate>
<Condition Comment="Init over?" Expression="return CurrentSoundType == 1;">
<OnTrue>
<SetAppState State="Demo"/>
</OnTrue>
<OnFalse>
<ZExpression>
<Expression>
<![CDATA[// Display text one turn before init sound
int currentInit = CurrentSoundType + 1;
switch(currentInit)
{
case 0: textInit.Text = "INIT PICKUPCOIN"; break;
case 1: textInit.Text = "INIT LASERSHOT"; break;
case 2: textInit.Text = "INIT EXPLOSION"; break;
}
if (CurrentSoundType > -1)
{
for (int n = 0; n < 10; n ++)
{
trace("Init "+intToStr(CurrentSoundType)+" "+intToStr(n));
// Set the Sample component length
switch(CurrentSoundType)
{
case 0:
switch(n)
{
case 0: initSoundSample(Sample_PickupCoin_0); break;
case 1: initSoundSample(Sample_PickupCoin_1); break;
case 2: initSoundSample(Sample_PickupCoin_2); break;
case 3: initSoundSample(Sample_PickupCoin_3); break;
case 4: initSoundSample(Sample_PickupCoin_4); break;
case 5: initSoundSample(Sample_PickupCoin_5); break;
case 6: initSoundSample(Sample_PickupCoin_6); break;
case 7: initSoundSample(Sample_PickupCoin_7); break;
case 8: initSoundSample(Sample_PickupCoin_8); break;
case 9: initSoundSample(Sample_PickupCoin_9); break;
}
break;
}
}
}
CurrentSoundType ++;]]>
</Expression>
</ZExpression>
</OnFalse>
</Condition>
</OnUpdate>
<OnRender>
<RenderText Name="textInit" Text="INIT LASERSHOT"/>
</OnRender>
</AppState>
<AppState Name="Demo">
<Definitions>
<Sound Name="MySound" Length="0.5252" Volume="0.29" Mod0Active="1" Mod0Destination="1" Mod0Amount="1" Env0Active="1" Env0ReleaseTime="0.2" SampleRepeatPosition="-1" UseSampleHz="255"/>
<Variable Name="MySampleIndex" Type="1"/>
</Definitions>
<OnStart>
<ZExpression>
<Expression>
<![CDATA[setcurrentSound(0);
CurrentSoundNumber = 0;]]>
</Expression>
</ZExpression>
</OnStart>
<OnUpdate>
<KeyPress Comment="left click play sound" Keys="{" RepeatDelay="0.2">
<OnPressed>
<ZExpression Comment="Sound library">
<Expression>
<![CDATA[sound_vol = 0.5;
playSound = 1;]]>
</Expression>
</ZExpression>
</OnPressed>
</KeyPress>
<KeyPress Comment="right click mutate sound" Keys="}" RepeatDelay="0.2">
<OnPressed>
<ZExpression Comment="Sound library">
<Expression>
<![CDATA[mutate();
playSound = 1;]]>
</Expression>
</ZExpression>
</OnPressed>
</KeyPress>
<Condition Comment="playSound?" Expression="return playSound;">
<OnTrue>
<ZExpression>
<Expression>
<![CDATA[playSound = 0;
trace("Play "+intToStr(CurrentSoundType)+" "+intToStr(CurrentSoundNumber));
switch(CurrentSoundType)
{
case 0:
switch(CurrentSoundNumber)
{
case 0: attachSampleToSound(Sample_PickupCoin_0); break;
case 1: attachSampleToSound(Sample_PickupCoin_1); break;
case 2: attachSampleToSound(Sample_PickupCoin_2); break;
case 3: attachSampleToSound(Sample_PickupCoin_3); break;
case 4: attachSampleToSound(Sample_PickupCoin_4); break;
case 5: attachSampleToSound(Sample_PickupCoin_5); break;
case 6: attachSampleToSound(Sample_PickupCoin_6); break;
case 7: attachSampleToSound(Sample_PickupCoin_7); break;
case 8: attachSampleToSound(Sample_PickupCoin_8); break;
case 9: attachSampleToSound(Sample_PickupCoin_9); break;
}
break;
}
CurrentSoundNumber ++;
if (CurrentSoundNumber == 10) CurrentSoundNumber = 0;]]>
</Expression>
</ZExpression>
<PlaySound Sound="MySound"/>
</OnTrue>
</Condition>
</OnUpdate>
<OnRender>
<RenderText Name="text" Text="PICKUP COIN"/>
</OnRender>
</AppState>
</States>
<Content>
<Variable Name="CurrentSoundType" Type="1"/>
<Variable Name="CurrentSoundNumber" Type="1"/>
<Variable Name="playSound" Type="4"/>
<Group Comment="SFXR">
<Children>
<Group Comment="Sample">
<Children>
<Group Comment="Synth">
<Children>
<Variable Name="sampling" Type="1"/>
<Array Name="buffer" SizeDim1="1364"/>
</Children>
</Group>
<Group Comment="Base">
<Children>
<Variable Name="phase"/>
<Variable Name="period"/>
<Variable Name="fperiod"/>
<Variable Name="fmaxperiod"/>
<Variable Name="fslide"/>
<Variable Name="fdslide"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="square_duty"/>
<Variable Name="square_slide"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="vib_phase"/>
<Variable Name="vib_speed"/>
<Variable Name="vib_amp"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="env_stage"/>
<Variable Name="env_time"/>
<Array Name="env_length" SizeDim1="3"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="fltp"/>
<Variable Name="fltdp"/>
<Variable Name="fltw"/>
<Variable Name="fltw_d"/>
<Variable Name="fltdmp"/>
<Variable Name="fltphp"/>
<Variable Name="flthp"/>
<Variable Name="flthp_d"/>
</Children>
</Group>
<Group Comment="Noise">
<Children>
<Variable Name="fnoise"/>
<Variable Name="ppnoise" Type="1"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="fphase"/>
<Variable Name="fdphase"/>
<Variable Name="iphase" Type="1"/>
<Variable Name="ipp" Type="1"/>
<Array Name="phaser_buffer" SizeDim1="1024"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="rep_time"/>
<Variable Name="rep_limit"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="arp_time"/>
<Variable Name="arp_mod"/>
<Variable Name="arp_limit"/>
</Children>
</Group>
</Children>
</Group>
<Group Comment="Parameters">
<Children>
<Group Comment="Base">
<Children>
<Variable Name="wave_type" Type="1"/>
<Variable Name="sound_vol"/>
<Variable Name="p_base_freq"/>
<Variable Name="p_freq_limit"/>
<Variable Name="p_freq_ramp"/>
<Variable Name="p_freq_dramp"/>
</Children>
</Group>
<Group Comment="Square">
<Children>
<Variable Name="p_duty"/>
<Variable Name="p_duty_ramp"/>
</Children>
</Group>
<Group Comment="Vibrato">
<Children>
<Variable Name="p_vib_speed"/>
<Variable Name="p_vib_strength"/>
</Children>
</Group>
<Group Comment="Envelope">
<Children>
<Variable Name="p_env_attack"/>
<Variable Name="p_env_sustain"/>
<Variable Name="p_env_decay"/>
<Variable Name="p_env_punch"/>
</Children>
</Group>
<Group Comment="Filter">
<Children>
<Variable Name="p_lpf_freq"/>
<Variable Name="p_lpf_ramp"/>
<Variable Name="p_lpf_resonance"/>
<Variable Name="p_hpf_freq"/>
<Variable Name="p_hpf_ramp"/>
</Children>
</Group>
<Group Comment="Phaser">
<Children>
<Variable Name="p_pha_offset"/>
<Variable Name="p_pha_ramp"/>
</Children>
</Group>
<Group Comment="Repeat">
<Children>
<Variable Name="p_repeat_speed"/>
</Children>
</Group>
<Group Comment="Arpeggio">
<Children>
<Variable Name="p_arp_speed"/>
<Variable Name="p_arp_mod"/>
</Children>
</Group>
</Children>
</Group>
</Children>
</Group>
<Group Comment="Samples">
<Children>
<Group Comment="0 - Pickup Coin">
<Children>
<Sample Name="Sample_PickupCoin_0" Length="0.2419">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_1" Length="0.0957">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_2" Length="0.5112">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_3" Length="0.5689">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_4" Length="0.3633">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_5" Length="0.1103">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_6" Length="0.4319">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_7" Length="0.2736">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_8" Length="0.5705">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
<Sample Name="Sample_PickupCoin_9" Length="0.0309">
<Producers>
<SampleExpression>
<Expression>
<![CDATA[//
this.Sample = buffer[MySampleIndex++];]]>
</Expression>
</SampleExpression>
</Producers>
</Sample>
</Children>
</Group>
</Children>
</Group>
</Content>
</ZApplication>
Last edited by Ats on Fri May 03, 2024 9:49 am, edited 3 times in total.
Re: SFXR
I tried the project and got a crash which turned out to be a problem in ZGEs code that shows the callstack. I've fixed that bug and now it shows array access error.
Code: Select all
Callstack:
SampleExpression
Array access outside range: buffer 0 0 4571
Re: SFXR
Thanks Ville. I think I'm getting pretty good at randomly finding bugs in ZGE
So, setting the buffer.SizeDim1 before the sample.Length seems to fix the crash that could occur during the initialization.
(I update the project above)
Edit:
Nope. My fix didn't last long
But setting buffer.SizeDim1 = (insert big number here) at the start of the project's initialization is working. That's weird because there are no access to that array before initSoundSample function sets its size, depending on the SampleLength.
But I've yet to find the quirk with that same buffer when playing the sound.
Is it possible that all the Samples are affected by the last buffer modification when a single SampleExpression is refreshed, maybe?
this.Sample = buffer[MySampleIndex++];
Because initializing only one sound is working well.
So, setting the buffer.SizeDim1 before the sample.Length seems to fix the crash that could occur during the initialization.
(I update the project above)
Code: Select all
buffer.SizeDim1 = S + 1; // Set buffer size
MySampleIndex = 0;
sample.Length = L;
Nope. My fix didn't last long
But setting buffer.SizeDim1 = (insert big number here) at the start of the project's initialization is working. That's weird because there are no access to that array before initSoundSample function sets its size, depending on the SampleLength.
But I've yet to find the quirk with that same buffer when playing the sound.
Is it possible that all the Samples are affected by the last buffer modification when a single SampleExpression is refreshed, maybe?
this.Sample = buffer[MySampleIndex++];
Because initializing only one sound is working well.