@@ -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+
1526class 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 } }
0 commit comments