Skip to content

Commit

Permalink
Merge pull request #345 from tobyhede/master
Browse files Browse the repository at this point in the history
Extend playNote to handle note[]
  • Loading branch information
djipco authored Mar 10, 2023
2 parents 9db181b + 39041d1 commit 7c7e27f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 14 deletions.
32 changes: 18 additions & 14 deletions src/OutputChannel.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,20 +720,24 @@ export class OutputChannel extends EventEmitter {
// Send note on and, optionally, note off message (if duration is a positive number)
this.sendNoteOn(note, options);

if (parseInt(note.duration) > 0) {
const noteOffOptions = {
time: (Utilities.toTimestamp(options.time) || WebMidi.time) + parseInt(note.duration),
release: note.release,
rawRelease: note.rawRelease
};
this.sendNoteOff(note, noteOffOptions);
} else if (parseInt(options.duration) > 0) {
const noteOffOptions = {
time: (Utilities.toTimestamp(options.time) || WebMidi.time) + parseInt(options.duration),
release: options.release,
rawRelease: options.rawRelease
};
this.sendNoteOff(note, noteOffOptions);
const notes = Array.isArray(note) ? note : [note];

for(let note of notes) {
if (parseInt(note.duration) > 0) {
const noteOffOptions = {
time: (Utilities.toTimestamp(options.time) || WebMidi.time) + parseInt(note.duration),
release: note.release,
rawRelease: note.rawRelease
};
this.sendNoteOff(note, noteOffOptions);
} else if (parseInt(options.duration) > 0) {
const noteOffOptions = {
time: (Utilities.toTimestamp(options.time) || WebMidi.time) + parseInt(options.duration),
release: options.release,
rawRelease: options.rawRelease
};
this.sendNoteOff(note, noteOffOptions);
}
}

return this;
Expand Down
44 changes: 44 additions & 0 deletions test/OutputChannel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,50 @@ describe("OutputChannel Object", function() {

});

it("should call 'sendNoteOn()' with correct parameters if passed a Note", function () {

// Arrange
let note = new Note("C4", { duration: 250, attack: 0.5, rawAttack: 127 });
let options = { time: 10 };
let spy = sinon.spy(WEBMIDI_OUTPUT.channels[1], "sendNoteOff");

// Act
WEBMIDI_OUTPUT.channels[1].playNote(note, options);

// Assert
expect(spy.calledOnceWith(note)).to.be.true;
expect(spy.args[0][0]).to.equal(note);
expect(spy.args[0][0].attack).to.equal(note.attack);
expect(spy.args[0][0].rawAttack).to.equal(note.rawAttack);
expect(spy.args[0][1].time).to.equal(options.time + note.duration);
});

it("should call 'sendNoteOff()' for each note if parameter is Note[]", function () {

// Arrange
let note = new Note("C4", { duration: 250 });
let notes = [
note,
new Note("D#2", { duration: 500 }),
new Note("F3", { duration: 250 })
];

let options = {};
let spy = sinon.spy(WEBMIDI_OUTPUT.channels[1], "sendNoteOff");

// // Act
WEBMIDI_OUTPUT.channels[1].playNote(notes, options);

// // Assert
expect(spy.callCount).to.equal(3);
expect(spy.args[0][0]).to.equal(note);
// Hard to get exact timing values, assert in future
expect(spy.args[0][1].time).to.greaterThan(WebMidi.time);
expect(spy.args[0][1].release).to.equal(note.release);
expect(spy.args[0][1].rawRelease).to.equal(note.rawRelease);
});


it("should return 'OutputChannel' object for method chaining", function () {
expect(
WEBMIDI_OUTPUT.channels[1].playNote("C3")
Expand Down

0 comments on commit 7c7e27f

Please sign in to comment.