SFXR

Post screenshots, binaries and projectfiles of the projects you have made with ZGE that you want to share!

Moderator: Moderators

Post Reply
User avatar
Kjell
Posts: 1886
Joined: Sat Feb 23, 2008 11:15 pm

SFXR

Post by Kjell »

8)

Port of DrPetter's sfxr for use with the Sample Component.

Image

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 881 times
User avatar
jph_wacheski
Posts: 1005
Joined: Sat Feb 16, 2008 8:10 pm
Location: Canada
Contact:

Post by jph_wacheski »

Wow, nice one!

This is quite cool,.

what is the noteNr to use if i want to pitch the sounds in playback, I cant seem to find the base note?
iterationGAMES.com
User avatar
Kjell
Posts: 1886
Joined: Sat Feb 23, 2008 11:15 pm

Post by Kjell »

:)

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
getter77
Posts: 5
Joined: Wed Apr 06, 2011 9:40 pm
Location: GA,USA

Post by getter77 »

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?
Champion of Roguelikes, living voraciously, trying to wrap my head around game creation.
User avatar
Ats
Posts: 623
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: SFXR

Post by Ats »

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.

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>
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' :lol:

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.
User avatar
Kjell
Posts: 1886
Joined: Sat Feb 23, 2008 11:15 pm

Re: SFXR

Post by Kjell »

Hi Ats,
Ats wrote: Wed May 01, 2024 5:03 pmWeirdly enough, KeyPress:KeyPress isn't an issue.
You can't use KeyPress as variable type in the scripting language .. while you can use File / Sample / Sound.
Ats wrote: Wed May 01, 2024 5:03 pmBut 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.
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
User avatar
Ats
Posts: 623
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: SFXR

Post by Ats »

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
Oh, ok, I get it.

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...?
User avatar
Ats
Posts: 623
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: SFXR

Post by Ats »

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.
  • Left click to play a sound
  • Right click to mutate the current sound
And yes, while it's holding better in release than in preview, this can definitely crash :lol:

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="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 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][irnd(2)];
  p_base_freq = 0.2723171360931539;
  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)];
  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 = 0.9 * frnd(1) * frnd(1) + 0.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="0.0295">
          <Producers>
            <SampleExpression>
              <Expression>
<![CDATA[//

this.Sample = buffer[this.Time*44100];]]>
              </Expression>
            </SampleExpression>
          </Producers>
        </Sample>
        <Sound Name="MySound" Length="0.0295" 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>
      <OnStart>
        <ZExpression Expression="initSound();"/>
      </OnStart>
      <OnUpdate>
        <KeyPress Comment="left click play sound" Keys="{" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression Comment="Sound library">
              <Expression>
<![CDATA[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()
}

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;
}

currentSound++;
if (currentSound == 10) currentSound = 0;

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

//

ResetSample(0); // Reset the synthesizer
SynthSample(0,S,3); // Synthesize the entire sample]]>
              </Expression>
            </ZExpression>
            <RefreshContent Component="MySample"/>
            <PlaySound Sound="MySound"/>
          </OnTrue>
        </Condition>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="FontMaterial4"/>
        <RenderText Name="text" Text="BLIP SELECT"/>
      </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="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>
    <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>
Post Reply