+ }
+}
+
+class SoundRain extends SCPattern {
+
+ private FFT fft = null;
+ private LinearEnvelope[] bandVals = null;
+ private float[] lightVals = null;
+ private int avgSize;
+ private float gain = 25;
+ SawLFO pos = new SawLFO(0, 9, 8000);
+ SinLFO col1 = new SinLFO(0, model.xMax, 5000);
+ BasicParameter gainParameter = new BasicParameter("GAIN", 0.5);
+
+ public SoundRain(LX lx) {
+ super(lx);
+ addModulator(pos).trigger();
+ addModulator(col1).trigger();
+ addParameter(gainParameter);
+ }
+
+ public void onParameterChanged(LXParameter parameter) {
+ if (parameter == gainParameter) {
+ gain = 50*parameter.getValuef();
+ }
+ }
+ void onActive() {
+ if (this.fft == null) {
+ this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
+ this.fft.window(FFT.HAMMING);
+ this.fft.logAverages(40, 1);
+ this.avgSize = this.fft.avgSize();
+ this.bandVals = new LinearEnvelope[this.avgSize];
+ for (int i = 0; i < this.bandVals.length; ++i) {
+ this.addModulator(this.bandVals[i] = (new LinearEnvelope(0, 0, 700+i*4))).trigger();
+ }
+ lightVals = new float[avgSize];
+ }
+ }
+
+ public void run(double deltaMs) {
+ this.fft.forward(this.lx.audioInput().mix);
+ for (int i = 0; i < avgSize; ++i) {
+ float value = this.fft.getAvg(i);
+ this.bandVals[i].setEndVal(value,40).trigger();
+ float lv = min(value*gain,100);
+ if (lv>lightVals[i]) {
+ lightVals[i]=min(lightVals[i]+15,lv,100);
+ } else {
+ lightVals[i]=max(lv,lightVals[i]-5,0);
+ }
+ }
+ for (Cube c : model.cubes) {
+ for (int j=0; j<c.strips.size(); j++) {
+ Strip s = c.strips.get(j);
+ if (j%4!=0 && j%4!=2) {
+ for (LXPoint p : s.points) {
+ int seq = int(p.y*avgSize/model.yMax+pos.getValuef()+sin(p.x+p.z)*2)%avgSize;
+ seq=min(abs(seq-(avgSize/2)),avgSize-1);
+ colors[p.index] = lx.hsb(200,max(0,100-abs(p.x-col1.getValuef())/2),lightVals[seq]);
+ }
+ }
+ }
+ }
+ }
+}
+
+class FaceSync extends SCPattern {
+ SinLFO xosc = new SinLFO(-10, 10, 3000);
+ SinLFO zosc = new SinLFO(-10, 10, 3000);
+ SinLFO col1 = new SinLFO(0, model.xMax, 5000);
+ SinLFO col2 = new SinLFO(0, model.xMax, 4000);
+
+ public FaceSync(LX lx) {
+ super(lx);
+ addModulator(xosc).trigger();
+ addModulator(zosc).trigger();
+ zosc.setValue(0);
+ addModulator(col1).trigger();
+ addModulator(col2).trigger();
+ col2.setValue(model.xMax);
+ }
+
+ public void run(double deltaMs) {
+ int i=0;
+ for (Strip s : model.strips) {
+ i++;
+ for (LXPoint p : s.points) {
+ float dx, dz;
+ if (i%32 < 16) {
+ dx = p.x - (s.cx+xosc.getValuef());
+ dz = p.z - (s.cz+zosc.getValuef());
+ } else {
+ dx = p.x - (s.cx+zosc.getValuef());
+ dz = p.z - (s.cz+xosc.getValuef());
+ }
+ //println(dx);
+ float a1=max(0,100-abs(p.x-col1.getValuef()));
+ float a2=max(0,100-abs(p.x-col2.getValuef()));
+ float sat = max(a1,a2);
+ float h = (359*a1+200*a2) / (a1+a2);
+ colors[p.index] = lx.hsb(h,sat,100-abs(dx*5)-abs(dz*5));
+ }
+ }
+ }
+}
+
+class SoundSpikes extends SCPattern {
+ private FFT fft = null;
+ private LinearEnvelope[] bandVals = null;
+ private float[] lightVals = null;
+ private int avgSize;
+ private float gain = 25;
+ BasicParameter gainParameter = new BasicParameter("GAIN", 0.5);
+ SawLFO pos = new SawLFO(0, model.xMax, 8000);
+
+ public SoundSpikes(LX lx) {
+ super(lx);
+ addParameter(gainParameter);
+ addModulator(pos).trigger();
+ }
+
+ public void onParameterChanged(LXParameter parameter) {
+ if (parameter == gainParameter) {
+ gain = 50*parameter.getValuef();
+ }
+ }
+ void onActive() {
+ if (this.fft == null) {
+ this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
+ this.fft.window(FFT.HAMMING);
+ this.fft.logAverages(40, 1);
+ this.avgSize = this.fft.avgSize();
+ this.bandVals = new LinearEnvelope[this.avgSize];
+ for (int i = 0; i < this.bandVals.length; ++i) {
+ this.addModulator(this.bandVals[i] = (new LinearEnvelope(0, 0, 700+i*4))).trigger();