-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathgsuiLFO.js
182 lines (169 loc) · 5.64 KB
/
gsuiLFO.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
"use strict";
class gsuiLFO extends gsui0ne {
#lfo = "gain";
#dur = 4;
#waveWidth = 300;
#nyquist = 24000;
constructor() {
super( {
$cmpName: "gsuiLFO",
$tagName: "gsui-lfo",
$elements: {
$beatlines: "gsui-beatlines",
$wave: "gsui-periodicwave",
$sliders: {
delay: [ ".gsuiLFO-prop[data-prop='delay'] gsui-slider", ".gsuiLFO-prop[data-prop='delay'] .gsuiLFO-propValue" ],
attack: [ ".gsuiLFO-prop[data-prop='attack'] gsui-slider", ".gsuiLFO-prop[data-prop='attack'] .gsuiLFO-propValue" ],
speed: [ ".gsuiLFO-prop[data-prop='speed'] gsui-slider", ".gsuiLFO-prop[data-prop='speed'] .gsuiLFO-propValue" ],
amp: [ ".gsuiLFO-prop[data-prop='amp'] gsui-slider", ".gsuiLFO-prop[data-prop='amp'] .gsuiLFO-propValue" ],
lowpassfreq: [ ".gsuiLFO-lowpassfreq gsui-slider", ".gsuiLFO-lowpassfreq .gsuiLFO-propValue" ],
},
},
$attributes: {
lfo: "gain",
toggle: false,
timedivision: "4/4",
type: "sine",
delay: 0,
attack: 1,
speed: 1,
amp: 1,
},
} );
Object.seal( this );
this.onchange = this.#onchangeForm.bind( this );
GSUlistenEvents( this, {
gsuiSlider: {
inputStart: GSUnoop,
inputEnd: GSUnoop,
input: ( d, sli ) => {
this.#oninputSlider( sli.dataset.prop, d.args[ 0 ] );
},
change: ( d, sli ) => {
this.#onchangeSlider( sli.dataset.prop, d.args[ 0 ] );
},
},
} );
}
// .........................................................................
$firstTimeConnected() {
this.$elements.$wave.$nbLines( 1 );
this.$updateWave();
}
static get observedAttributes() {
return [ "lfo", "toggle", "timedivision", "type", "delay", "attack", "speed", "amp", "lowpassfreq" ];
}
$attributeChanged( prop, val, prev ) {
if ( this.firstChild ) {
const num = +val;
switch ( prop ) {
case "lfo":
this.#lfo = val;
GSUsetAttribute( this.$elements.$sliders.amp[ 0 ], "max", val === "gain" ? 1 : 12 );
this.#changeProp( "amp", Math.abs( GSUgetAttribute( this, "amp" ) ) );
this.$onresize();
this.$updateWave();
break;
case "timedivision": GSUsetAttribute( this.$elements.$beatlines, "timedivision", val ); break;
case "toggle": this.#changeToggle( val !== null ); break;
case "type": this.#changeType( val ); break;
case "delay":
case "attack":
case "speed":
case "lowpassfreq":
this.#changeProp( prop, num );
break;
case "amp":
if ( num > 0 !== prev > 0 ) {
this.#changeAmpSign( num );
}
this.#changeProp( "amp", Math.abs( num ) );
break;
}
}
}
// .........................................................................
$updateWave( prop, val ) {
const w = this.$elements.$wave;
const bPM = +this.$getAttr( "timedivision" ).split( "/" )[ 0 ];
const opt = {
type: this.$getAttr( "type" ),
delay: prop === "delay" ? val : this.$getAttrNum( "delay" ),
attack: prop === "attack" ? val : this.$getAttrNum( "attack" ),
frequency: prop === "speed" ? val : this.$getAttrNum( "speed" ),
amplitude: prop === "amp" ? val : this.$getAttrNum( "amp" ),
};
if ( this.#lfo === "detune" ) {
opt.amplitude /= 12;
}
opt.duration =
this.#dur = Math.max( opt.delay + opt.attack + 2, bPM );
w.$options( 0, opt );
w.style.opacity = Math.min( 6 / opt.frequency, 1 );
this.#updatePxPerBeat();
}
// .........................................................................
#changeToggle( b ) {
this.querySelectorAll( ".gsuiLFO-typeRadio" ).forEach( el => GSUsetAttribute( el, "disabled", !b ) );
GSUsetAttribute( this.$elements.$sliders.delay[ 0 ], "disabled", !b );
GSUsetAttribute( this.$elements.$sliders.attack[ 0 ], "disabled", !b );
GSUsetAttribute( this.$elements.$sliders.speed[ 0 ], "disabled", !b );
GSUsetAttribute( this.$elements.$sliders.amp[ 0 ], "disabled", !b );
}
#changeType( type ) {
this.$elements.$wave.$options( 0, { type } );
this.querySelector( `.gsuiLFO-typeRadio[value="${ type }"]` ).checked = true;
}
#changeAmpSign( amp ) {
this.querySelector( `.gsuiLFO-ampSignRadio[value="${ Math.sign( amp ) || 1 }"]` ).checked = true;
}
#changeProp( prop, val ) {
const sli = this.$elements.$sliders[ prop ];
if ( sli ) {
sli[ 0 ].$setValue( val );
sli[ 1 ].textContent = gsuiLFO.#formatVal( prop, val );
}
}
#updatePxPerBeat() {
GSUsetAttribute( this.$elements.$beatlines, "pxPerBeat", this.#waveWidth / this.#dur );
}
static #formatVal( prop, val ) {
return val.toFixed( 2 );
}
// .........................................................................
$onresize() {
this.#waveWidth = this.$elements.$beatlines.getBoundingClientRect().width;
this.#updatePxPerBeat();
this.$elements.$wave.$resized();
}
#onchangeForm( e ) {
switch ( e.target.name ) {
case "gsuiLFO-type":
GSUsetAttribute( this, "type", e.target.value );
this.$updateWave();
this.$dispatch( "change", this.#lfo, "type", e.target.value );
break;
case "gsuiLFO-ampSign":
GSUsetAttribute( this, "amp", -this.$getAttrNum( "amp" ) );
this.$updateWave();
this.$dispatch( "change", this.#lfo, "amp", this.$getAttrNum( "amp" ) );
break;
}
}
#oninputSlider( prop, val ) {
const realval = prop !== "amp"
? val
: val * Math.sign( this.$getAttrNum( "amp" ) );
this.$elements.$sliders[ prop ][ 1 ].textContent = gsuiLFO.#formatVal( prop, val );
this.$updateWave( prop, realval );
this.$dispatch( "liveChange", this.#lfo, prop, realval );
}
#onchangeSlider( prop, val ) {
const nval = prop === "amp"
? val * Math.sign( this.$getAttrNum( "amp" ) )
: val;
GSUsetAttribute( this, prop, nval );
this.$dispatch( "change", this.#lfo, prop, nval );
}
}
GSUdefineElement( "gsui-lfo", gsuiLFO );