synthing

a waveform sequencing synth on the web
Log | Files | Refs | Submodules

commit 9272e0354f9d95a3108cf0bc374d7cb405efd31b
parent 5e980e1c2b4b22e82fc3765f20e234126a580340
Author: Massimo Siboldi <mdsiboldi@gmail.com>
Date:   Wed,  7 Mar 2018 15:40:03 -0800

Add master volume and change individual tones to just having a "mix"

Diffstat:
Msrc/App/index.js | 19++++++++++++++++---
Msrc/Polyphonic.js | 9++++++++-
Msrc/Synth/index.js | 7++++---
Msrc/Volume/index.js | 16++++++++++++----
Msrc/Volume/style.css | 7++++++-
Msrc/WaveManager/index.js | 5++++-
Msrc/WaveManager/style.css | 5+++--
Msrc/WaveTable/index.js | 1-
8 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/src/App/index.js b/src/App/index.js @@ -4,6 +4,7 @@ import WaveManager from '../WaveManager/'; import Synth from '../Synth/'; import CircleButton from '../CircleButton/'; import WaveTable from '../WaveTable/'; +import Volume from '../Volume/'; import Param from '../Param/'; import Wheel from '../Wheel/'; import './App.css'; @@ -98,6 +99,7 @@ class App extends Component { super(); let initBeats = 4; this.state = { + volume: 0.7, bpm: 120, beat: 0, playing: false, @@ -126,6 +128,12 @@ class App extends Component { }); } + updateVolume = (newVol) => { + this.setState({ + volume: newVol + }); + } + editingWaveform = () => this.state.tones[this.state.editingToneIdx].waveform activeTones = () => { @@ -261,7 +269,7 @@ class App extends Component { } render() { - const waves = this.state.tones.map((form, idx) => { + const tones = this.state.tones.map((form, idx) => { return ( <WaveManager activate={this.changeEditingTone.bind(this, idx)} @@ -352,12 +360,17 @@ class App extends Component { update={this.setBeats} /> <Adsr adsr={this.state.adsr} update={this.updateAdsr} /> + <Volume volume={this.state.volume} update={this.updateVolume} /> </div> <div class="wave-manager-container"> - {waves} + {tones} </div> <button onClick={() => this.addTone()}>+</button> - <Synth waveform={this.totalWaveform()} adsr={this.state.adsr}></Synth> + <Synth + waveform={this.totalWaveform()} + volume={this.state.volume} + adsr={this.state.adsr} + ></Synth> </div> ); } diff --git a/src/Polyphonic.js b/src/Polyphonic.js @@ -3,9 +3,16 @@ import Envelope from 'envelope-generator'; export default class Polyphonic { constructor(audioContext) { + const masterVol = audioContext.createGain(); + masterVol.gain.value = 0.7; + masterVol.connect(audioContext.destination); this.voices = {}; this.audioContext = audioContext; this.periodicWave = null; + this.masterVolume = masterVol; + } + setVolume(newVol) { + this.masterVolume.gain.value = newVol; } addVoice(note, adsr) { this.voices[note.note] = this.voices[note.note] || []; @@ -28,7 +35,7 @@ export default class Polyphonic { envelope.connect(gain.gain); osc.connect(gain); - gain.connect(this.audioContext.destination); + gain.connect(this.masterVolume); osc.start(); envelope.start(this.audioContext.currentTime - 0.1); diff --git a/src/Synth/index.js b/src/Synth/index.js @@ -26,6 +26,9 @@ export default class Synth extends Component { } componentWillReceiveProps(newProps) { updateAudio(newProps.waveform); + if (newProps.volume !== this.props.volume) { + P.setVolume(newProps.volume); + } } render() { return null; @@ -34,11 +37,9 @@ export default class Synth extends Component { function updateAudio(waveform) { FFT.forward(waveform); - //TODO: test what disableNormalization does. I'm guessing it allows me to have volume control, otherwise it would scale wave so max displacement is -1/1 instead of smaller val const periodicWave = ac.createPeriodicWave( new Float32Array(FFT.real), - new Float32Array(FFT.imag), - {disableNormalization: true} + new Float32Array(FFT.imag) ); P.changeWave(periodicWave); } diff --git a/src/Volume/index.js b/src/Volume/index.js @@ -2,11 +2,16 @@ import { h, Component } from 'preact'; import helpers from '../helpers'; import './style.css'; +const mapVol = (vol) => vol * vol; +const unmapVol = (vol) => Math.sqrt(vol); + export default class Volume extends Component { handleUpdate = (ev) => { const minVolX = this.sliderRef.offsetLeft; const maxVolX = this.sliderRef.offsetLeft + this.sliderRef.offsetWidth; - this.props.update(helpers.bounded((ev.x - minVolX) / (maxVolX - minVolX), 0, 1)); + const width = maxVolX - minVolX; + const offset = helpers.bounded(ev.x - minVolX, 0, width); + this.props.update(mapVol(offset / width)); } componentDidMount() { @@ -14,15 +19,18 @@ export default class Volume extends Component { } render() { return ( - <div class="Volume" ref={(ref) => {this.volRef = ref}}> - <span class="icon-volume"></span> + <div class={`Volume${this.props.class ? ' ' + this.props.class : ''}`} ref={(ref) => {this.volRef = ref}}> + {this.props.children.length + ? this.props.children + : (<span class="icon-volume"></span>) + } <div class="volume-triangle-container" ref={(ref) => {this.sliderRef = ref}} > <div class="volume-triangle -foreground" - style={`transform: scale(${this.props.volume});`} + style={`transform: scale(${unmapVol(this.props.volume)});`} ></div> <div class="volume-triangle -background"></div> </div> diff --git a/src/Volume/style.css b/src/Volume/style.css @@ -19,6 +19,11 @@ } .volume-triangle-container { - display: inline-block; + display: inline-flex; position: relative; + margin-left: 2px; +} + +.Volume { + display: inline-flex; } diff --git a/src/WaveManager/index.js b/src/WaveManager/index.js @@ -43,7 +43,10 @@ export default class WaveManager extends Component { <Volume volume={this.props.volume} update={this.props.updateVolume} - /> + class="item" + > + <span>mix</span> + </Volume> </div> </div> <div class="beats"> diff --git a/src/WaveManager/style.css b/src/WaveManager/style.css @@ -27,6 +27,7 @@ margin: 0 5px; cursor: pointer; padding: 2px 5px; + font-size: 10pt; } .wave-manager .buttons .item:first-child { @@ -43,10 +44,10 @@ background: none; } -.wave-manager .buttons .item { +.wave-manager .buttons button.item { opacity: 0.8; } -.wave-manager .buttons .item:hover { +.wave-manager .buttons button.item:hover { opacity: 1; } diff --git a/src/WaveTable/index.js b/src/WaveTable/index.js @@ -33,7 +33,6 @@ export default class WaveTable extends Component { } if (this.props.resize) { window.addEventListener('resize', (ev) => { - console.log('yo', this.forceUpdate) this.forceUpdate(); }) }