commit c9db96557ad4f3ef4f86491ecced10c9cec07851
parent f46244201a8f673b964a016208c249db860f2945
Author: Massimo Siboldi <mdsiboldi@gmail.com>
Date: Wed, 6 Dec 2017 15:31:30 -0800
A set of bulk changes. Fews days worth, all together in one commit!
Diffstat:
10 files changed, 206 insertions(+), 57 deletions(-)
diff --git a/log.org b/log.org
@@ -11,3 +11,10 @@
** the synth
*** whenever the wave changes, it should be put into the osc node
*** whenever settings in UI change, they should change the nodes related to those settings.
+* <2017-12-03 Sun 19:18>
+** waveform becomes an array
+*** DONE be able to update, remove waveform at idx i
+*** DONE have convenience methods to update "active" waveform, acting the same as before
+*** DONE be able to change active waveform
+* <2017-12-03 Sun 21:35>
+here's an idea: make modules in vanilla js and interact with them via react. We'll get some reusability in other projects and keep react doing viewstuff, not statelogicstuff
diff --git a/src/App/index.js b/src/App/index.js
@@ -1,69 +1,163 @@
import { h, Component } from 'preact';
import WaveEditor from '../WaveEditor/';
+import WaveManager from '../WaveManager/';
import Synth from '../Synth/';
import './App.css';
import consts from '../consts.js';
-import helpers from '../helpers.js';
+
+const initialWave = new Array(consts.BUF_SIZE).fill(0);
+
+const immObjArray = {
+ update: (arr, idx, opts) => {
+ const newArr = arr.slice();
+ newArr[idx] = Object.assign({}, arr[idx], opts)
+ return newArr;
+ },
+ add: (arr, idx, opts) => {
+ const newArr = arr.slice();
+ newArr.splice(idx, 0, opts);
+ return newArr;
+ },
+ remove: (arr, idx) => {
+ const newArr = arr.slice();
+ newArr.splice(idx, 1);
+ return newArr;
+ }
+}
+
+const boolArray = {
+ setLength: (ba, newLength) => {
+ let newBa = ba.slice(0, newLength);
+ if (ba.length < newLength) {
+ newBa = newBa.concat(new Array(newLength - ba.length).fill(false));
+ }
+ return newBa;
+ },
+ create: (length) => {
+ return new Array(length).fill(false);
+ },
+ update: (ba, idx, val) => {
+ const newBa = ba.slice();
+ newBa[idx] = val;
+ return newBa;
+ }
+}
+
+
class App extends Component {
constructor() {
super();
+ let initBeats = 4;
this.state = {
- waveform: new Array(consts.BUF_SIZE).fill(0.5),
+ waveforms: [{
+ waveform: initialWave.slice(),
+ beats: boolArray.create(initBeats)
+ }],
+ numBeats: initBeats,
+ editingWaveformIdx: 0,
mouseData: {
down: false,
pos: {x: 0, y: 0}
}
}
}
- updateWaveform = (waveform) => {
- if (!waveform) {
- waveform = new Array(consts.BUF_SIZE).fill(0.0);
- }
+
+ editingWaveform = () => this.state.waveforms[this.state.editingWaveformIdx].waveform
+
+ updateWaveform = (idx = this.state.editingWaveformIdx, opts) => {
this.setState({
- waveform
+ waveforms: immObjArray.update(this.state.waveforms, idx, opts)
});
}
- handleMouseMove = (ev) => {
+
+ removeWaveform = (idx) => {
+ const waveforms = immObjArray.remove(this.state.waveforms, idx);
this.setState({
- mouseData: Object.assign({}, this.state.mouseData, {
- x: ev.x,
- y: ev.y,
- })
+ waveforms,
+ editingWaveformIdx: Math.min(
+ this.state.editingWaveformIdx,
+ waveforms.length - 1
+ )
});
}
- handleMouseDown = (ev) => {
- this.setState({
- mouseData: Object.assign({}, this.state.mouseData, {
- down: true,
- downTarget: ev.target
- })
+
+ changeEditingWaveform = (i) => this.setState({editingWaveformIdx: i})
+
+ addWaveform = (waveform = new Array(consts.BUF_SIZE).fill(0), at = this.state.waveforms.length, isEditing = false) => {
+ const waveforms = immObjArray.add(this.state.waveforms, at, {
+ waveform,
+ beats: boolArray.create(this.state.numBeats)
});
+
+ const state = {
+ waveforms
+ };
+
+ if (isEditing) {
+ state.editingWaveformIdx = at;
+ }
+
+ this.setState(state);
}
- handleMouseUp = (ev) => {
+ setBeats = (newNumBeats) => {
+ newNumBeats = Math.max(newNumBeats, 1);
this.setState({
- mouseData: Object.assign({}, this.state.mouseData, {
- down: false,
- downTarget: null
+ numBeats: newNumBeats,
+ waveforms: this.state.waveforms.map((val, idx) => {
+ let ret = Object.assign({}, val, {
+ beats: boolArray.setLength(val.beats, newNumBeats)
+ });
+ return ret;
})
- });
- };
+ })
+ }
+
render() {
+ const waves = this.state.waveforms.map((form, idx) => {
+ return (
+ <WaveManager
+ activate={this.changeEditingWaveform.bind(this, idx)}
+ remove={this.removeWaveform.bind(this, idx)}
+ duplicate={() => {
+ let pleaseActivate = false;
+ if (this.state.editingWaveformIdx === idx) {
+ pleaseActivate = true;
+ }
+ this.addWaveform(this.state.waveforms[idx].waveform.slice(), idx + 1, pleaseActivate);
+ }}
+ activated={idx === this.state.editingWaveformIdx}
+ beats={this.state.waveforms[idx].beats}
+ updateBeat={(i, val) => {
+ console.log('updating', i, val);
+ this.updateWaveform(idx, {
+ beats: boolArray.update(
+ this.state.waveforms[idx].beats,
+ i,
+ val
+ )
+ });
+ }}
+ ></WaveManager>
+ );
+ })
return (
- <div
- className="App"
- onMouseDown={this.handleMouseDown}
- onMouseMove={this.handleMouseMove}
- onMouseUp={this.handleMouseUp}
- >
- <button onClick={() => this.updateWaveform()}>click to update</button>
+ <div
+ className="App"
+ >
<WaveEditor
mouseData={this.state.mouseData}
- waveform={this.state.waveform}
- updateWaveform={this.updateWaveform}
+ waveform={this.editingWaveform()}
+ updateWaveform={(waveform) => {
+ this.updateWaveform(this.state.editingWaveformIdx, {waveform});
+ }}
></WaveEditor>
- <Synth waveform={this.state.waveform}></Synth>
- </div>
+ <button onClick={() => {this.setBeats(this.state.numBeats + 1)}}>+ beat</button>
+ <button onClick={() => {this.setBeats(this.state.numBeats - 1)}}>- beat</button>
+ <button onClick={() => this.addWaveform()}>+</button>
+ {waves}
+ <Synth waveform={this.editingWaveform()}></Synth>
+ </div>
);
}
}
diff --git a/src/Polyphonic.js b/src/Polyphonic.js
@@ -6,6 +6,7 @@ export default class Polyphonic {
constructor(audioContext) {
this.voices = [];
this.audioContext = audioContext;
+ this.periodicWave = null;
}
addVoice(note) {
let osc = this.audioContext.createOscillator();
@@ -13,8 +14,8 @@ export default class Polyphonic {
gain.gain.value = 0.5;
osc.connect(gain);
osc.frequency.value = note.frequency;
- if (this.wave) {
- osc.setPeriodicWave(this.wave);
+ if (this.periodicWave) {
+ osc.setPeriodicWave(this.periodicWave);
}
gain.connect(this.audioContext.destination);
osc.start();
@@ -34,10 +35,12 @@ export default class Polyphonic {
}
changeWave(waveform) {
FFT.forward(waveform);
- const periodicWave = this.ac.createPeriodicWave(new Float32Array(FFT.real),
- new Float32Array(FFT.imag));
+ this.periodicWave = this.audioContext.createPeriodicWave(
+ new Float32Array(FFT.real),
+ new Float32Array(FFT.imag)
+ );
for (let voice of this.voices) {
- voice.osc.setPeriodicWave(periodicWave);
+ voice.osc.setPeriodicWave(this.periodicWave);
}
}
}
diff --git a/src/Synth/.tern-port b/src/Synth/.tern-port
@@ -1 +1 @@
-32787
-\ No newline at end of file
+39991
+\ No newline at end of file
diff --git a/src/Synth/index.js b/src/Synth/index.js
@@ -1,6 +1,6 @@
import { Component } from 'preact';
import Polyphonic from '../Polyphonic';
-import AudioKeys from '../../AudioKeys/dist/audiokeys.min.js';
+import AudioKeys from '../../AudioKeys/dist/audiokeys.js';
export default class Synth extends Component {
componentWillMount() {
@@ -10,7 +10,6 @@ export default class Synth extends Component {
return false;
}
componentWillReceiveProps(newProps) {
- if (this.props.waveform !== newProps.waveform);
updateAudio(newProps.waveform);
}
render() {
@@ -30,7 +29,6 @@ function startAudio() {
keyboard.up((note) => {
P.removeVoice(note);
});
-
}
function updateAudio(waveform) {
diff --git a/src/WaveEditor/index.js b/src/WaveEditor/index.js
@@ -37,6 +37,23 @@ const smoothZoneRange = function (waveData, begin, end) {
export default class waveEditor extends Component {
componentDidMount() {
drawArea(this.props.waveform, this.canvasRef);
+ const handleMove = (ev) => {
+ this.updateWaveform({
+ x: ev.x,
+ y: ev.y
+ }, this.props.waveform);
+ }
+ document.addEventListener('mousedown', (ev) => {
+ if (ev.target === this.canvasRef) {
+ document.addEventListener('mousemove', handleMove);
+ }
+ });
+ document.addEventListener('mouseup', (ev) => {
+ document.removeEventListener('mousemove', handleMove);
+ this.setState({
+ prevZone: null
+ });
+ });
}
componentWillUpdate() {
return false;
@@ -74,27 +91,16 @@ export default class waveEditor extends Component {
}
componentWillReceiveProps(newProps) {
- const drawing = newProps.mouseData.down &&
- newProps.mouseData.downTarget === this.canvasRef;
-
if (newProps.waveform !== this.props.waveform) {
drawArea(newProps.waveform, this.canvasRef);
}
- else if (drawing) {
- this.updateWaveform(newProps.mouseData, newProps.waveform);
- }
- if (!drawing) {
- this.setState({
- prevZone: null
- })
- }
}
render() {
return (
<canvas
height={400}
width={800}
- ref={(canvas) => this.canvasRef = canvas}>
+ ref={(canvas) => {this.canvasRef = canvas}}>
</canvas>
);
}
diff --git a/src/WaveManager/.tern-port b/src/WaveManager/.tern-port
@@ -0,0 +1 @@
+36609
+\ No newline at end of file
diff --git a/src/WaveManager/index.js b/src/WaveManager/index.js
@@ -0,0 +1,22 @@
+import { h, Component} from 'preact';
+
+export default class WaveManager extends Component {
+ render() {
+ console.log(this.props.beats);
+ return (
+ <div class="wave-manager">
+ <div class="buttons">
+ {this.props.activated ? 'x' : ''}
+ <button onClick={this.props.activate}>activate</button>
+ <button onClick={this.props.remove}>remove</button>
+ <button onClick={this.props.duplicate}>dupe</button>
+ </div>
+ <div class="beats">
+ {this.props.beats.map((val, idx) => {
+ return <input type="checkbox" checked={val} onChange={(ev) => {this.props.updateBeat(idx, ev.target.checked)}}></input>
+ })}
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/src/WaveMaster.js b/src/WaveMaster.js
@@ -0,0 +1,17 @@
+export default {
+ update: (arr, idx, opts) => {
+ const newArr = arr.slice();
+ Object.assign({}, arr[idx], opts)
+ return newArr;
+ }
+ add: (arr, idx, opts) => {
+ const newArr = arr.slice();
+ newArr.splice(idx, 0, opts);
+ return newArr;
+ }
+ remove: (arr, idx) => {
+ const newArr = arr.slice();
+ newArr.splice(idx, 1);
+ return newArr;
+ }
+}
diff --git a/src/Waves.js b/src/Waves.js