Skip to content

Commit 5fab99f

Browse files
committed
Made seperate actions for osc. Added cycles.
1 parent 78bd635 commit 5fab99f

File tree

7 files changed

+135
-45
lines changed

7 files changed

+135
-45
lines changed

src/App.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class App extends React.Component {
5353
onCloseAboutModal () {
5454
this.setState({isAboutModalOpen: false})
5555
}
56+
onMasterGainChanged (e) {
57+
let action = Actions.masterGainChanged(e.target.value)
58+
this.props.dispatch(action)
59+
}
5660

5761
render () {
5862
// Shows a message if no audio support in the browser.
@@ -86,6 +90,7 @@ class App extends React.Component {
8690
min={0}
8791
max={100}
8892
step={1}
93+
onChange={this.onMasterGainChanged.bind(this)}
8994
value={this.props.Master.volume} />
9095
<MidiInput eventEmitter={eventEmitter} />
9196
<Presets presetId={this.props.Master.presetId} />

src/audio/LFO.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,3 @@ export default class LFO {
138138
return this.audioContext.createPeriodicWave(real, imag)
139139
}
140140
}
141-
142-
// might be better than default triangle ? :
143-
// let waveData = [0, 1]
144-
145-
// console.log('smooth sq', waveData)
146-
// let real = new Float32Array(waveData)
147-
// let imag = new Float32Array(waveData.length)
148-
// waveData = this.audioContext.createPeriodicWave(real, imag)
149-
// return waveData

src/data/Actions.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,24 @@ Actions.oscAlgorithmChanged = function oscAlgorithmChanged (id, algorithm) {
3434
}
3535
}
3636

37-
// An oscillator detune has changed.
38-
Actions.sliderChanged = function sliderChanged (id, value, name) {
39-
return {
40-
type: 'SLIDER_CHANGED',
41-
id,
42-
value,
43-
name
44-
}
37+
Actions.oscCyclesChanged = function oscCyclesChanged (id, value) {
38+
return {type: 'OSC_CYCLES_CHANGED', id, value}
39+
}
40+
41+
Actions.oscDetuneChanged = function oscDetuneChanged (id, value) {
42+
return {type: 'OSC_DETUNE_CHANGED', id, value}
43+
}
44+
45+
Actions.oscOctaveChanged = function oscDetuneChanged (id, value) {
46+
return {type: 'OSC_OCTAVE_CHANGED', id, value}
47+
}
48+
49+
Actions.onAmountChanged = function onAmountChanged (id, value) {
50+
return {type: 'OSC_AMOUNT_CHANGED', id, value}
51+
}
52+
53+
Actions.masterGainChanged = function masterGainChanged (value) {
54+
return {type: 'MASTER_GAIN_CHANGED', value}
4555
}
4656

4757
Actions.glideChanged = function oscGlideChanged (value) {

src/data/PresetData.js

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/data/Reducers.js

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ function initOscillator (URL, name, id, color) {
134134
channelDataB: [],
135135
computedChannelData: [],
136136
algorithm: URL[id + 'al'] || 'p',
137+
cycles: urlVal(URL[id + 'c'], 1),
137138
amount: urlVal(URL[id + 'a'], 75),
138139
detune: urlVal(URL[id + 'd'], 0),
139140
octave: urlVal(URL[id + 'o'], 0),
@@ -172,14 +173,10 @@ let initialState = initializeState(urlData)
172173
function MasterReducer (state, action) {
173174
state = state || initialState.Master
174175
switch (action.type) {
175-
case 'SLIDER_CHANGED':
176-
if (action.id === 'master') {
177-
state.volume = action.value
178-
updateURL('mv', action.value)
179-
return Object.assign({}, state)
180-
} else {
181-
return state
182-
}
176+
case 'MASTER_GAIN_CHANGED':
177+
state.volume = Number(action.value)
178+
updateURL('mv', action.value)
179+
return Object.assign({}, state)
183180
default:
184181
return state
185182
}
@@ -337,17 +334,37 @@ function computeWaveform (channelDataA, channelDataB, algorithm) {
337334
return []
338335
}
339336

340-
return channelDataB.map(function (data, index) {
341-
if (algorithm === 'p') {
342-
return limit(-1, 1, channelDataA[index] + channelDataB[index])
343-
} else if (algorithm === 'm') {
344-
return limit(-1, 1, channelDataA[index] - channelDataB[index])
345-
} else if (algorithm === 'd') {
346-
return limit(-1, 1, channelDataA[index] / (channelDataB[index] * 2))
347-
} else if (algorithm === 'x') {
348-
return limit(-1, 1, channelDataA[index] * channelDataB[index])
349-
}
350-
})
337+
let cycles = 256 // 1 can be min. 1024 might be a good max.
338+
let samplesCount = (600 * cycles) // - (overlap * cycles)
339+
let interpolatedData = new Float32Array(samplesCount * 2)
340+
let time = 0
341+
342+
// Interpolate from A to B.
343+
for (let i = 0; i < samplesCount; i++) {
344+
time = i / samplesCount
345+
interpolatedData[i] = slerp(channelDataA[i % 600], channelDataB[i % 600], time, algorithm)
346+
}
347+
348+
// Interpolate from B to A ( mirrors the previous ).
349+
for (let k = samplesCount; k < samplesCount * 2; k++) {
350+
time = (k - samplesCount) / (samplesCount) // Time starts at half way point.
351+
interpolatedData[k] = slerp(channelDataB[k % 600], channelDataA[k % 600], time, algorithm)
352+
}
353+
return interpolatedData
354+
}
355+
356+
// Modified lerp function based on algorithm chosen.
357+
// The 'minus' algorithm uses the normal lerp function.
358+
function slerp (v0, v1, t, algorithm) {
359+
if (algorithm === 'p') {
360+
return limit(-1, 1, v0 * (1 + t) + v1 * t) || 0.00001
361+
} else if (algorithm === 'm') {
362+
return limit(-1, 1, v0 * (1 - t) + v1 * t) || 0.00001 // Normal lerp function.
363+
} else if (algorithm === 'd') {
364+
return limit(-1, 1, v0 * (1 / t) + v1 * t) || 0.00001
365+
} else if (algorithm === 'x') {
366+
return limit(-1, 1, v0 * (1 * t) + v1 * t) || 0.00001
367+
}
351368
}
352369

353370
function OscillatorsReducer (state, action) {
@@ -399,7 +416,7 @@ function OscillatorsReducer (state, action) {
399416
})
400417
return [...state]
401418

402-
// The +, -, /, * selected operator was changed.
419+
// The +, -, /, * selected operator was changed, or the number of cycles changed.
403420
case 'OSC_ALGORITHM_CHANGED':
404421
state = state.map(function (osc) {
405422
if (osc.id === action.id) {
@@ -420,11 +437,44 @@ function OscillatorsReducer (state, action) {
420437
return [...state]
421438

422439
// Updates local osc values, detune, octave, and amt.
423-
case 'SLIDER_CHANGED':
440+
case 'OSC_CYCLES_CHANGED':
441+
state = state.map(function (osc) {
442+
if (osc.id === action.id) {
443+
osc.cycles = action.value
444+
const paramName = osc.id + 'c' // id + first letter of param.
445+
updateURL(paramName, action.value)
446+
}
447+
return osc
448+
})
449+
return [...state]
450+
451+
case 'OSC_DETUNE_CHANGED':
452+
state = state.map(function (osc) {
453+
if (osc.id === action.id) {
454+
osc.detune = action.value
455+
const paramName = osc.id + 'd' // id + first letter of param.
456+
updateURL(paramName, action.value)
457+
}
458+
return osc
459+
})
460+
return [...state]
461+
462+
case 'OSC_OCTAVE_CHANGED':
463+
state = state.map(function (osc) {
464+
if (osc.id === action.id) {
465+
osc.octave = action.value
466+
const paramName = osc.id + 'o' // id + first letter of param.
467+
updateURL(paramName, action.value)
468+
}
469+
return osc
470+
})
471+
return [...state]
472+
473+
case 'OSC_AMOUNT_CHANGED':
424474
state = state.map(function (osc) {
425475
if (osc.id === action.id) {
426-
osc[action.name] = action.value
427-
const paramName = osc.id + action.name[0] // id + first letter of param.
476+
osc.amount = action.value
477+
const paramName = osc.id + 'a' // id + first letter of param.
428478
updateURL(paramName, action.value)
429479
}
430480
return osc

src/views/Components/HorizontalSlider.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ class HorizontalSlider extends React.Component {
1414
}
1515

1616
handleChange (e) {
17-
const {id, name} = this.props
18-
let action = Actions.sliderChanged(id, Number(e.target.value), name)
19-
this.props.dispatch(action)
17+
this.props.onChange(e)
2018
}
2119

2220
sliderClassName () {

src/views/Oscillator/OscillatorView.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,31 @@ import WaveFileLoader from './WaveFileLoader.js'
99
import WaveLine from './WaveLine.js'
1010
import AlgorithmSwitch from './AlgorithmSwitch.js'
1111
import HorizontalSlider from '../Components/HorizontalSlider.js'
12+
import {connect} from 'react-redux'
13+
import Actions from '../../data/Actions.js'
1214

1315
class OscillatorView extends React.Component {
1416

17+
onCyclesChanged (e) {
18+
let action = Actions.oscCyclesChanged(this.props.id, Number(e.target.value))
19+
this.props.dispatch(action)
20+
}
21+
22+
onDetuneChanged (e) {
23+
let action = Actions.oscDetuneChanged(this.props.id, Number(e.target.value))
24+
this.props.dispatch(action)
25+
}
26+
27+
onOctaveChanged (e) {
28+
let action = Actions.oscOctaveChanged(this.props.id, Number(e.target.value))
29+
this.props.dispatch(action)
30+
}
31+
32+
onAmountChanged (e) {
33+
let action = Actions.onAmountChanged(this.props.id, Number(e.target.value))
34+
this.props.dispatch(action)
35+
}
36+
1537
render () {
1638
const colorStyle = {
1739
color: this.props.color
@@ -66,13 +88,24 @@ class OscillatorView extends React.Component {
6688
channelData={this.props.computedChannelData} />
6789
</div>
6890
<div className='oscillator-sliders'>
91+
<HorizontalSlider
92+
id={this.props.id}
93+
name='cycles'
94+
label='cycles'
95+
min={1}
96+
max={1024}
97+
step={1}
98+
onChange={this.onCyclesChanged.bind(this)}
99+
color={this.props.color}
100+
value={this.props.cycles} />
69101
<HorizontalSlider
70102
id={this.props.id}
71103
name='detune'
72104
label='detune'
73105
min={-12}
74106
max={12}
75107
step={1}
108+
onChange={this.onDetuneChanged.bind(this)}
76109
color={this.props.color}
77110
value={this.props.detune} />
78111
<HorizontalSlider
@@ -82,6 +115,7 @@ class OscillatorView extends React.Component {
82115
min={-3}
83116
max={3}
84117
step={1}
118+
onChange={this.onOctaveChanged.bind(this)}
85119
color={this.props.color}
86120
value={this.props.octave} />
87121
<HorizontalSlider
@@ -91,6 +125,7 @@ class OscillatorView extends React.Component {
91125
min={0}
92126
max={100}
93127
step={1}
128+
onChange={this.onAmountChanged.bind(this)}
94129
color={this.props.color}
95130
value={this.props.amount} />
96131
</div>
@@ -119,4 +154,4 @@ OscillatorView.defaultProps = {
119154
height: 200
120155
}
121156

122-
export default OscillatorView
157+
export default connect()(OscillatorView)

0 commit comments

Comments
 (0)