public void Init(OpenGL gl)
        {
            // Init location source
            _emitterLocation.Init(0.0f, -15.0f, 0.0f, 30.0f, 30.0f, 0.0f, 0.6f, 0.6f, 0.0f);

            // Init colors
            setColors();
            _colorRotateStopwatch.Start();

            float adjustedThickness = BandThickness * 100.0f;

            // Particle system init
            _particleSystem.AfterParticleInit = ((particle, audioModifier) =>
            {
                // Which spectrum bar this particle belongs to
                int bandIndex = particle.ParticleId % BandCount;

                // The x offset of this particle
                float offsetX = bandIndex * (BandThickness + BandSpacing);
                offsetX = 0.0f;

                int color = _colorIndices[0];

                // Color
                particle.R = Constants.Colors[color, 0];
                particle.G = Constants.Colors[color, 1];
                particle.B = Constants.Colors[color, 2];

                // Start location
                particle.X = offsetX + _emitterLocation.X + ((_random.Next((int)(adjustedThickness * 2.0f)) - adjustedThickness) / adjustedThickness);
                particle.Y = _emitterLocation.Y + ((_random.Next(200) - 0.0f) / 600.0f);
                particle.Z = (_random.Next(200) - 100.0f) / 400.0f;
                particle.DieRate = ((_random.Next(100)) + 100.0f) / 4000.0f;
                particle.Size = 0.4f + (audioModifier * 0.2f);
                particle.Chaos = (_random.Next(200) - 100.0f) * ParticleChaos;
                particle.Drag = 0.0f;
                particle.Attribute1 = NoiseIntensity + (audioModifier * 0.4f);
                particle.Lift = ((_random.Next(200) + 100.0f) / 800.0f) + FixedVelocityModifier + (audioModifier * 0.2f);
                //particle.Lift = (particle.ParticleId % 2 == 0 ? 1.0f : -1.0f) * (FixedVelocityModifier + (audioModifier * 0.2f));

                // Speed
                particle.Xi = 0.0f;
                particle.Yi = 0.0f;
                particle.Zi = 0.0f;
            });
            _particleSystem.OverrideParticleUpdate = ((particle, audioModifier) =>
            {
                if (particle.ParticleId < 0)
                {
                    // Put particle in its place
                    vec2 potentialFieldLocation = _potentialFieldLocations[particle.ParticleId];
                    particle.X = potentialFieldLocation.x;
                    particle.Y = potentialFieldLocation.y;
                    particle.Z = 0.0f;

                    // Get noise at location
                    float noiseValue = _perlinNoise.Noise(particle.X * NoiseSampleScale, particle.Y * NoiseSampleScale, _time) * NoiseIntensity;

                    particle.Size = noiseValue;
                    particle.R = noiseValue;
                    particle.G = noiseValue;
                    particle.B = noiseValue;
                }
                else
                {
                    // Which spectrum bar this particle belongs to
                    int bandIndex = particle.ParticleId % BandCount;
                    //particle.Size = 0.2f + (_scaledAudioData[bandIndex] * 2.0f);

                    vec3 curl1 = _perlinNoise.ComputeCurl(particle.X * NoiseSampleScale, particle.Y * NoiseSampleScale, _time, CurlEpsilon, particle.Attribute1);

                    particle.Xi = (curl1.x * particle.Chaos);
                    particle.Yi = (curl1.y * particle.Chaos);
                    particle.Zi = 0.0f;

                    particle.Yi += particle.Lift;

                    // Move by speed
                    particle.X += particle.Xi;
                    particle.Y += particle.Yi;
                    particle.Z += particle.Zi;

                    // Reduce life (opacity)
                    particle.Life -= particle.DieRate;
                }
            });

            _particleSystem.Init(gl, OpenGL.GL_SRC_ALPHA, ParticleCount, true, false);
        }