Update
This commit is contained in:
parent
035405bfcc
commit
13baa93aff
@ -6,6 +6,8 @@ import { TestPattern } from '../patterns/test';
|
|||||||
import rust, { BeatTrackerHandle, MovingHeadState, OutputHandle, TrackerConfig } from 'rust_native_module';
|
import rust, { BeatTrackerHandle, MovingHeadState, OutputHandle, TrackerConfig } from 'rust_native_module';
|
||||||
import { ChaserPattern } from '../patterns/chaser';
|
import { ChaserPattern } from '../patterns/chaser';
|
||||||
import { HSLRandomMovementPattern } from '../patterns/hslRandom';
|
import { HSLRandomMovementPattern } from '../patterns/hslRandom';
|
||||||
|
import { HSLRandomMovementPairsPattern } from '../patterns/hslRandom2';
|
||||||
|
import { SnoopDoggPattern } from '../patterns/snoop';
|
||||||
|
|
||||||
export type AppState = {
|
export type AppState = {
|
||||||
patterns: { [key: string]: PatternOutput },
|
patterns: { [key: string]: PatternOutput },
|
||||||
@ -63,6 +65,8 @@ class Backend {
|
|||||||
this.patterns.set("test", new TestPattern());
|
this.patterns.set("test", new TestPattern());
|
||||||
this.patterns.set("chaser", new ChaserPattern());
|
this.patterns.set("chaser", new ChaserPattern());
|
||||||
this.patterns.set("hslRandom", new HSLRandomMovementPattern());
|
this.patterns.set("hslRandom", new HSLRandomMovementPattern());
|
||||||
|
this.patterns.set("snoop", new SnoopDoggPattern());
|
||||||
|
this.patterns.set("hslRandomPairs", new HSLRandomMovementPairsPattern());
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
patterns: {},
|
patterns: {},
|
||||||
|
105
boilerbloat/src/patterns/hslRandom2.ts
Normal file
105
boilerbloat/src/patterns/hslRandom2.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
import { panLeft, panRight, startAddresses, tiltDown, tiltUp } from './stage'
|
||||||
|
import { Pattern, PatternOutput, RenderUpdate } from './proto';
|
||||||
|
import { MovingHeadState } from 'rust_native_module';
|
||||||
|
import { Tuple4 } from './types';
|
||||||
|
import { hsl2rgb, clamp, rescale } from './util';
|
||||||
|
|
||||||
|
const HSL_CYCLE_LENGTH: number = 7; // seconds
|
||||||
|
const MOVEMENT_CYCLE_LENGTH: number = 0.5; // seconds?
|
||||||
|
const THRESHOLD: number = 1.5;
|
||||||
|
|
||||||
|
const panBounds: Tuple4<[number, number]> = [
|
||||||
|
[panLeft, panRight],
|
||||||
|
[panLeft, panRight],
|
||||||
|
[panLeft, panRight],
|
||||||
|
[panLeft, panRight],
|
||||||
|
];
|
||||||
|
|
||||||
|
const tiltBound: [number, number] = [tiltDown, tiltUp];
|
||||||
|
|
||||||
|
export class HSLRandomMovementPairsPattern implements Pattern {
|
||||||
|
|
||||||
|
brightness: number;
|
||||||
|
targets: [[number, number], [number, number]];
|
||||||
|
lastUpdate: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.brightness = 0;
|
||||||
|
this.targets = [
|
||||||
|
[panLeft, tiltUp],
|
||||||
|
[panRight, tiltUp],
|
||||||
|
]
|
||||||
|
this.lastUpdate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(update: RenderUpdate): PatternOutput {
|
||||||
|
|
||||||
|
// color
|
||||||
|
|
||||||
|
const t = update.absolute;
|
||||||
|
const h = 360 * ((t % HSL_CYCLE_LENGTH) / HSL_CYCLE_LENGTH);
|
||||||
|
const s = 1;
|
||||||
|
const v = 0.5;
|
||||||
|
|
||||||
|
const [r, g, b] = hsl2rgb(h, s, v);
|
||||||
|
const rgbw1: Tuple4<number> = [
|
||||||
|
Math.round(r * 255),
|
||||||
|
Math.round(g * 255),
|
||||||
|
Math.round(b * 255),
|
||||||
|
0
|
||||||
|
];
|
||||||
|
|
||||||
|
const [r2, g2, b2] = hsl2rgb((h + 90) % 360, s, v);
|
||||||
|
const rgbw2: Tuple4<number> = [
|
||||||
|
Math.round(r2 * 255),
|
||||||
|
Math.round(g2 * 255),
|
||||||
|
Math.round(b2 * 255),
|
||||||
|
0
|
||||||
|
];
|
||||||
|
|
||||||
|
// brightness
|
||||||
|
|
||||||
|
this.brightness = update.bassVolume > THRESHOLD
|
||||||
|
? 1
|
||||||
|
: 0.75 * this.brightness;
|
||||||
|
|
||||||
|
// movement
|
||||||
|
|
||||||
|
if (t - this.lastUpdate > MOVEMENT_CYCLE_LENGTH) {
|
||||||
|
|
||||||
|
this.lastUpdate = t;
|
||||||
|
|
||||||
|
for (let index in [0, 1]) {
|
||||||
|
|
||||||
|
const bound = panBounds[index];
|
||||||
|
|
||||||
|
const pan = rescale(Math.random(), { to: bound });
|
||||||
|
const tilt = clamp(Math.acos(Math.random()), tiltBound);
|
||||||
|
|
||||||
|
this.targets[index] = [pan, tilt];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return startAddresses.map((startAddress, index) => {
|
||||||
|
const [pan, tilt] = this.targets[index % 2];
|
||||||
|
const rgbw = [rgbw1, rgbw2][index % 2];
|
||||||
|
|
||||||
|
let state: MovingHeadState = {
|
||||||
|
startAddress: startAddress,
|
||||||
|
pan: pan,
|
||||||
|
tilt: tilt,
|
||||||
|
brightness: {
|
||||||
|
type: 'dimmer',
|
||||||
|
value: 0.2 + 0.8 * this.brightness,
|
||||||
|
},
|
||||||
|
rgbw: rgbw,
|
||||||
|
speed: 1,
|
||||||
|
reset: false
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
|
||||||
|
}) as PatternOutput;
|
||||||
|
}
|
||||||
|
}
|
55
boilerbloat/src/patterns/snoop.ts
Normal file
55
boilerbloat/src/patterns/snoop.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { MovingHeadState } from "rust_native_module";
|
||||||
|
import { Pattern, PatternOutput, RenderUpdate } from "./proto";
|
||||||
|
import { down, panLeft, panRight, startAddresses, tiltUp } from "./stage";
|
||||||
|
import { Tuple4 } from "./types";
|
||||||
|
|
||||||
|
const SNOOPY_COLOR: Tuple4<number> = [
|
||||||
|
0, 255, 0, 0
|
||||||
|
]
|
||||||
|
|
||||||
|
const LEFT_RIGHT_TIME: number = 5 // seconds;
|
||||||
|
|
||||||
|
export class SnoopDoggPattern implements Pattern {
|
||||||
|
lastUpdate: number;
|
||||||
|
left: boolean;
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.lastUpdate = 0;
|
||||||
|
this.left = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(update: RenderUpdate): PatternOutput {
|
||||||
|
const t = update.absolute;
|
||||||
|
if (t - this.lastUpdate > LEFT_RIGHT_TIME) {
|
||||||
|
this.left = !this.left;
|
||||||
|
this.lastUpdate = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tiltTarget = tiltUp + 0.25 * Math.PI * down;
|
||||||
|
|
||||||
|
const target = this.left
|
||||||
|
? [panLeft, tiltTarget]
|
||||||
|
: [panRight, tiltTarget];
|
||||||
|
|
||||||
|
const [pan, tilt] = target;
|
||||||
|
|
||||||
|
return (startAddresses.map((startAddress) => {
|
||||||
|
const state: MovingHeadState = {
|
||||||
|
startAddress: startAddress,
|
||||||
|
pan: pan,
|
||||||
|
tilt: tilt,
|
||||||
|
brightness: {
|
||||||
|
type: "dimmer",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
rgbw: SNOOPY_COLOR,
|
||||||
|
speed: 0.1,
|
||||||
|
reset: false
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
})) as PatternOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,7 +4,12 @@ export const startAddresses: Tuple4<number> = [1, 15, 29, 43]
|
|||||||
|
|
||||||
export const panLeft = 0;
|
export const panLeft = 0;
|
||||||
export const panRight = Math.PI;
|
export const panRight = Math.PI;
|
||||||
export const panForward = (panLeft + panRight) / 2;
|
export const panForward = 0.5 * Math.PI;
|
||||||
|
|
||||||
|
export const left = -1;
|
||||||
|
export const right = 1;
|
||||||
|
export const up = 1;
|
||||||
|
export const down = -1;
|
||||||
|
|
||||||
export const tiltUp = 0.5 * Math.PI;
|
export const tiltUp = 0.5 * Math.PI;
|
||||||
export const tiltDown = 0;
|
export const tiltDown = 0;
|
||||||
|
@ -13,7 +13,7 @@ export class TestPattern implements Pattern {
|
|||||||
]
|
]
|
||||||
|
|
||||||
render(update: RenderUpdate): PatternOutput {
|
render(update: RenderUpdate): PatternOutput {
|
||||||
let t = update.absolute % this.rgbw.length;
|
let t = (1.5 * update.absolute) % this.rgbw.length;
|
||||||
let second = Math.floor(t);
|
let second = Math.floor(t);
|
||||||
let brightness = 1 - (t % 1);
|
let brightness = 1 - (t % 1);
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ const Frontend: React.FC<{ state: AppState }> = ({ state }) => {
|
|||||||
return <div className="container">
|
return <div className="container">
|
||||||
<ConfigControls updateDelay={state.trackerConfig.zeroCrossingBeatDelay} />
|
<ConfigControls updateDelay={state.trackerConfig.zeroCrossingBeatDelay} />
|
||||||
<div>
|
<div>
|
||||||
<BongoCat onClick={tap} beatProgress={state.beatProgress} />
|
<BongoCat onClick={tap} beatProgress={state.beatProgress} high={state.selectedPattern === "snoop"}/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: "80%", marginTop: 80 }} className="element-row">
|
<div style={{ width: "80%", marginTop: 80 }} className="element-row">
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ const Cone: React.FC<{ color: string, translate: [number, number] , pan : number
|
|||||||
// TODO: adjust if necessary
|
// TODO: adjust if necessary
|
||||||
const degreesPan = pan / (2* Math.PI) * 360 - 45;
|
const degreesPan = pan / (2* Math.PI) * 360 - 45;
|
||||||
|
|
||||||
console.log(degreesTilt);
|
// console.log(degreesTilt);
|
||||||
return <g className="cone" style={{transform: `rotate(${degreesTilt}deg) rotateX(${degreesPan}deg)`}} >
|
return <g className="cone" style={{transform: `rotate(${degreesTilt}deg) rotateX(${degreesPan}deg)`}} >
|
||||||
<path stroke="black" fill="gray" d="M 15 0 L 45 0 L 60 30 L 0 30 L 15 0" />
|
<path stroke="black" fill="gray" d="M 15 0 L 45 0 L 60 30 L 0 30 L 15 0" />
|
||||||
<path fill={color} d="M 15 30 L 0 150 L 60 150 L 45 30 " />
|
<path fill={color} d="M 15 30 L 0 150 L 60 150 L 45 30 " />
|
||||||
|
BIN
boilerbloat/src/res/snoop.png
Normal file
BIN
boilerbloat/src/res/snoop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 296 KiB |
Loading…
Reference in New Issue
Block a user