Reputation: 787
I'm working with the web audio API. In note.js
i try to fill an array with some couple of notes for index.js
to play. But it does not work as intended. However, when i set the array directly in index.js
it works.
I have no clue why it is like that. Basically i want index.js
to play whatever notes gets pushed into the array in note.js
. Below i have pasted the two versions of index.js
to demonstrate what i want to do.
Hope someone can help me with this one.
index.js (does work)
import NoteModule from './note.js';
const notelist = new NoteModule();
notelist.notes = ['C4','D4','E4','F4','G4','A4','B4','C5'];
let seq = new Tone.Sequence(function(time, note){
event.humanize = true;
synth.triggerAttackRelease(note,'8n');
}, notelist.notes, '8n');
index.js (does not work)
import NoteModule from './note.js';
const notelist = new NoteModule();
let seq = new Tone.Sequence(function(time, note){
event.humanize = true;
synth.triggerAttackRelease(note,'8n');
}, notelist.notes, '8n');
note.js
import $ from 'jquery';
export default class NoteModule {
constructor(possibleNotes,notes,note) {
this.possibleNotes = ['','C4','D4','E4','F4','G4','A4','B4'];
this.notes = notes;
this.note = 0;
}
init() {
console.log('NoteModule');
this.addListeners();
}
addListeners() {
$('div.step').on('click', this.step.bind(this));
}
step(e) {
let notes = [];
$(e.currentTarget).parent().find('.note').text(this.possibleNotes[this.note]);
this.note = (this.note+1)%(this.possibleNotes.length);
$('.pads div.note').each(function() {
let note = $(this).text();
if (note && note.length > 0) {
notes.push(note);
}
});
this.notes = notes;
}
}
HTML:
<div class="pads">
<div class="pad"><div class="note" data-play=""></div></div>
<div class="pad"><div class="note" data-play=""></div></div>
<div class="pad"><div class="note" data-play=""></div></div>
<div class="pad"><div class="note" data-play=""></div></div>
</div>
<div class="pads">
<div class="pad">
<div>
<div class="step"><i class="icon-up-open-mini"></i></div>
<div class="note"></div>
<div class="step"><i class="icon-down-open-mini"></i></div>
</div>
</div>
<div class="pad">
<div>
<div class="step"><i class="icon-up-open-mini"></i></div>
<div class="note"></div>
<div class="step"><i class="icon-down-open-mini"></i></div>
</div>
</div>
<div class="pad">
<div>
<div class="step"><i class="icon-up-open-mini"></i></div>
<div class="note"></div>
<div class="step"><i class="icon-down-open-mini"></i></div>
</div>
</div>
<div class="pad">
<div>
<div class="step"><i class="icon-up-open-mini"></i></div>
<div class="note"></div>
<div class="step"><i class="icon-down-open-mini"></i></div>
</div>
</div>
</div>
Upvotes: 4
Views: 343
Reputation: 35806
You need to rework a bit how your files are structured and how your module is working. It does not work, because you are creating the Tone.Sequence
before anything has the chance to be set in your NoteModule
class, and you are not really updating your notes array anyway, you also didn't bind your step
method in your constructor, meaning it won't have access to the this
context, leaving all your modifications not saved.
Refactor your module to do something like the following, passing a function callback that will be executed once you click on a play button (that you will have to create). If you want to play as soon as a new note is played, just call the callback like I did in the step
method.
import $ from 'jquery'
export default class NoteModule {
constructor (callback, notes) {
this.possibleNotes = ['','C4','D4','E4','F4','G4','A4','B4']
this.notes = notes
this.callback = callback
this.note = 0
// you need this otherwise the step method won't have access to the context
this.step = this.step.bind(this)
}
init () {
console.log('NoteModule')
// make sure this is called, otherwise your events won't work
$('div.step').on('click', this.step.bind(this))
$('.play').on('click', () => this.callback(this.notes))
}
step (e) {
const notes = []
$(e.currentTarget).parent()
.find('.note')
.text(this.possibleNotes[this.note])
this.note = (this.note + 1) % (this.possibleNotes.length)
$('.pads div.note').each(el => {
const note = $(el).text()
if (note && note.length > 0) {
notes.push(note)
}
})
this.notes = notes
// or callback here, as you want
}
}
And in your index.js
simply import, initialize your class and pass the function callback that will receive the notes:
import NoteModule from './note.js'
const callback = notes => {
const seq = new Tone.Sequence((time, note) => {
event.humanize = true
synth.triggerAttackRelease(note, '8n')
}, notes, '8n')
}
new NoteModule(callback)
Upvotes: 4