Skip to content

Commit 0a3566a

Browse files
author
Mark Murray
committed
more buttons
1 parent ee7a624 commit 0a3566a

File tree

2 files changed

+98
-25
lines changed

2 files changed

+98
-25
lines changed

src/components/Sequencer/Sequencer.js

Lines changed: 97 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,48 @@ var getNotesForOctave = function(octave) {
1212
}, {});
1313
};
1414

15+
const defaultPads = [
16+
[1,0,0,0,0,0,0,0],
17+
[0,1,0,0,0,0,0,0],
18+
[1,0,0,0,0,0,0,0],
19+
[0,0,0,0,1,0,0,0],
20+
[1,0,0,0,0,0,0,0],
21+
[0,1,0,0,0,0,0,0],
22+
[0,0,0,1,0,0,0,0],
23+
[0,0,0,0,0,1,0,0]
24+
];
25+
1526
class Synth {
1627
constructor() {
1728
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
1829
}
1930

20-
playNotes(notes = [], wave = 'sine') {
21-
var vco = this.ctx.createOscillator();
22-
vco.type = wave;
23-
vco.frequency.value = notes[0];
31+
playNotes(notes = [], state = {}) {
32+
33+
if (!notes.length) return;
34+
35+
var osc = this.ctx.createOscillator();
36+
osc.type = state.type.toLowerCase();
37+
osc.frequency.value = notes[0];
38+
39+
var delay = this.ctx.createDelay();
40+
delay.delayTime.value = state.delay ? (state.bpm / 10) / 100 : 0;
2441

2542
/* VCA */
2643
var vca = this.ctx.createGain();
2744
vca.gain.value = 1;
2845

2946
/* connections */
30-
vco.connect(vca);
47+
osc.connect(vca);
48+
vca.connect(delay);
3149
vca.connect(this.ctx.destination);
50+
delay.connect(this.ctx.destination);
3251

33-
vco.start(0);
52+
osc.start(0);
3453

3554
setTimeout(() => {
3655
vca.gain.setTargetAtTime(0, this.ctx.currentTime, 0.015);
37-
}, 50);
56+
}, state.release);
3857
}
3958
}
4059

@@ -47,26 +66,38 @@ class Sequencer extends Component {
4766

4867
this.state = {
4968
type: 'sine',
50-
pads: [],
51-
bpm: 80,
69+
pads: defaultPads,
70+
bpm: 140,
71+
release: 10,
5272
step: 0,
5373
steps: 8,
5474
playing: false,
55-
octave: 4
75+
octave: 4,
76+
delay: false,
77+
notes: getNotesForOctave(4)
5678
};
5779
}
5880

59-
componentWillMount() {
81+
changeRelease(release) {
82+
this.setState({
83+
release
84+
}, () => {
85+
this.pause();
86+
87+
if (this.state.playing) this.play();
88+
})
89+
}
6090

61-
var pads = [];
91+
changeBPM(bpm) {
6292

63-
for (let i = 0; i < this.state.steps; i++) {
64-
pads.push([1,0,0,0,0,0,0,0]);
65-
}
93+
if (bpm > 300 || bpm < 60) return;
6694

6795
this.setState({
68-
pads: pads,
69-
notes: getNotesForOctave(this.state.octave)
96+
bpm
97+
}, () => {
98+
this.pause();
99+
100+
if (this.state.playing) this.play();
70101
});
71102
}
72103

@@ -93,7 +124,7 @@ class Sequencer extends Component {
93124

94125
play() {
95126

96-
const { bpm, notes, type } = this.state;
127+
const { bpm, notes, type, release, delay } = this.state;
97128
const notesArray = Object.keys(notes).map(key => notes[key]);
98129

99130
this.setState({
@@ -111,11 +142,16 @@ class Sequencer extends Component {
111142
pad === 1 ? notesArray[i] : null
112143
).filter(x => x);
113144

114-
synth.playNotes(next, type.toLowerCase());
145+
synth.playNotes(next, {
146+
release,
147+
bpm,
148+
type,
149+
delay
150+
});
115151

116152
});
117153

118-
}, 200);
154+
}, ((60 * 1000) / this.state.bpm) / 2);
119155
}
120156

121157
pause() {
@@ -165,6 +201,17 @@ class Sequencer extends Component {
165201
Play
166202
</button>
167203

204+
<div class="select-wrapper">
205+
<span>BPM</span>
206+
<input
207+
type="number"
208+
min="80"
209+
max="300"
210+
step="1"
211+
defaultValue={this.state.bpm}
212+
onChange={(e) => this.changeBPM(e.target.value)} />
213+
</div>
214+
168215
<div class="select-wrapper">
169216
<span>Wave</span>
170217
<select
@@ -175,6 +222,7 @@ class Sequencer extends Component {
175222
class="wave">
176223
<option>Sine</option>
177224
<option>Square</option>
225+
<option>Sawtooth</option>
178226
<option>Triangle</option>
179227
</select>
180228
</div>
@@ -186,28 +234,53 @@ class Sequencer extends Component {
186234
onChange={(e) => this.changeOctave(e.target.value)}
187235
data-label="octave"
188236
class="octave">
237+
<option>1</option>
189238
<option>2</option>
190239
<option>3</option>
191240
<option>4</option>
192241
<option>5</option>
193242
<option>6</option>
243+
<option>7</option>
194244
</select>
195245
</div>
246+
247+
<div class="select-wrapper">
248+
<span>Release</span>
249+
<input
250+
type="number"
251+
min="0"
252+
max="400"
253+
step="1"
254+
defaultValue={this.state.release}
255+
onChange={(e) => this.changeRelease(e.target.value)} />
256+
</div>
257+
258+
<button
259+
onClick={() => {
260+
this.setState({
261+
delay: !this.state.delay
262+
}, () => {
263+
this.pause();
264+
if (this.state.playing) this.play();
265+
});
266+
}}
267+
class={classNames({ active: this.state.delay })}>
268+
Delay
269+
</button>
196270
</div>
197271

198272
<ul class="notes">
199273
{Object.keys(notes).slice(0, 8).reverse().map(note =>
200-
<li>{note.slice(0, note.length - 1)}</li>
274+
<li key={`note-${note}`}>{note.slice(0, note.length - 1)}</li>
201275
)}
202276
</ul>
203277

204278
<div class="flex">
205279
{pads.map((group, groupIndex) =>
206-
<div class="pads">
280+
<div key={`pad-${groupIndex}`} class="pads">
207281
{group.map((pad, i) =>
208282
<div
209-
data-note={notesArray[i]}
210-
note={notesArray[i]}
283+
key={`pad-group-${i}`}
211284
onClick={() => {
212285
this.togglePad(groupIndex, i);
213286
}}

src/styles/app.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ h1 {
5454
display: flex;
5555
padding: 0.35em 0 0.5em;
5656

57-
button, select {
57+
button, select, input {
5858
margin: 5px;
5959
outline: none;
6060
background: lighten($dark, 10%);

0 commit comments

Comments
 (0)