Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dist/cjs/webmidi.cjs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5570,6 +5570,7 @@ declare class WebMidi extends EventEmitter {
sysex?: boolean;
validation?: boolean;
software?: boolean;
requestMIDIAccessFunction?: Function;
}): Promise<WebMidi>;

/**
Expand Down
1 change: 1 addition & 0 deletions dist/esm/webmidi.esm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5570,6 +5570,7 @@ declare class WebMidi extends EventEmitter {
sysex?: boolean;
validation?: boolean;
software?: boolean;
requestMIDIAccessFunction?: Function;
}): Promise<WebMidi>;

/**
Expand Down
21 changes: 20 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
"sinon-browser-only": "^1.12.1",
"system-commands": "^1.1.7",
"test-value": "^3.0.0",
"util": "^0.12.4"
"util": "^0.12.4",
"web-midi-test": "^1.1.9"
}
}
17 changes: 14 additions & 3 deletions src/WebMidi.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ class WebMidi extends EventEmitter {
* @param [options.software=false] {boolean} Whether to request access to software synthesizers on
* the host system. This is part of the spec but has not yet been implemented by most browsers as
* of April 2020.
*
* @param [options.requestMIDIAccessFunction] {function} A custom function to use to return
* the MIDIAccess object. This is useful if you want to use a polyfill for the Web MIDI API
* or if you want to use a custom implementation of the Web MIDI API - probably for testing
* purposes.
*
* @async
*
Expand Down Expand Up @@ -360,9 +365,15 @@ class WebMidi extends EventEmitter {

// Request MIDI access (this iw where the prompt will appear)
try {
this.interface = await navigator.requestMIDIAccess(
{sysex: options.sysex, software: options.software}
);
if (typeof options.requestMIDIAccessFunction === "function") {
this.interface = await options.requestMIDIAccessFunction(
{sysex: options.sysex, software: options.software}
);
} else {
this.interface = await navigator.requestMIDIAccess(
{sysex: options.sysex, software: options.software}
);
}
} catch(err) {
errorEvent.error = err;
this.emit("error", errorEvent);
Expand Down
39 changes: 21 additions & 18 deletions test/Forwarder.test.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
const expect = require("chai").expect;
const {Message, WebMidi, Note, Forwarder} = require("../dist/cjs/webmidi.cjs.js");
const midi = require("midi");
const WMT = require("web-midi-test");

// The virtual port is an "external" device so an input is seen as an output by WebMidi. To avoid
// confusion, the naming scheme adopts WebMidi's perspective.
let VIRTUAL_OUTPUT = new midi.Input();
let VIRTUAL_OUTPUT_NAME = "Virtual Output";
let VIRTUAL_OUTPUT = new WMT.MidiDst(VIRTUAL_OUTPUT_NAME);
/** @type {import("../dist/cjs/webmidi.cjs.js").Output} */
let WEBMIDI_OUTPUT;

function noop() {}

describe("Forwarder Object", function() {

before(function () {
VIRTUAL_OUTPUT.openVirtualPort(VIRTUAL_OUTPUT_NAME);
VIRTUAL_OUTPUT.ignoreTypes(false, false, false); // enable sysex, timing & active sensing
VIRTUAL_OUTPUT.connect();
// VIRTUAL_OUTPUT.ignoreTypes(false, false, false); // enable sysex, timing & active sensing
});

after(function () {
VIRTUAL_OUTPUT.closePort();
VIRTUAL_OUTPUT.disconnect();
});

beforeEach("Check support and enable WebMidi.js", async function () {
await WebMidi.enable({sysex: true});
await WebMidi.enable({sysex: true, requestMIDIAccessFunction: WMT.requestMIDIAccess});
WEBMIDI_OUTPUT = WebMidi.getOutputByName(VIRTUAL_OUTPUT_NAME);
});

Expand Down Expand Up @@ -97,15 +100,15 @@ describe("Forwarder Object", function() {
const data = [0x90, 64, 127];
const msg = new Message(data);
const forwarder = new Forwarder(WEBMIDI_OUTPUT);
VIRTUAL_OUTPUT.on("message", assert);
VIRTUAL_OUTPUT.receive = assert;

// Act
forwarder.forward(msg);

// Assert
function assert(deltaTime, message) {
function assert(message) {
expect(message).to.have.ordered.members(msg.data);
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
done();
}

Expand All @@ -119,19 +122,19 @@ describe("Forwarder Object", function() {
const msg = new Message(data);
const forwarder = new Forwarder(WEBMIDI_OUTPUT);
forwarder.suspended = true;
VIRTUAL_OUTPUT.on("message", assert);
VIRTUAL_OUTPUT.receive = assert;

// Act
forwarder.forward(msg);

const id = setTimeout(() => {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
done();
}, 250);

// Assert
function assert(deltaTime, message) {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
clearTimeout(id);
done(new Error("Callback should not have been triggered. " + message));
}
Expand All @@ -147,11 +150,11 @@ describe("Forwarder Object", function() {
const msg4 = new Message([0x9F, 64, 127]); // note on on ch. 16
const channel = 10;
const forwarder = new Forwarder(WEBMIDI_OUTPUT, {channels: channel});
VIRTUAL_OUTPUT.on("message", assert);
VIRTUAL_OUTPUT.receive = assert;

// Act
const id = setTimeout(() => {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
done();
}, 250);

Expand All @@ -162,7 +165,7 @@ describe("Forwarder Object", function() {

// Assert
function assert(deltaTime, message) {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
clearTimeout(id);
done(new Error("Callback should not have been triggered. " + message));
}
Expand All @@ -182,11 +185,11 @@ describe("Forwarder Object", function() {
0xD0
];
const forwarder = new Forwarder(WEBMIDI_OUTPUT, {types: target.name});
VIRTUAL_OUTPUT.on("message", assert);
VIRTUAL_OUTPUT.receive = assert;

// Act
const id = setTimeout(() => {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
done();
}, 250);

Expand All @@ -196,7 +199,7 @@ describe("Forwarder Object", function() {

// Assert
function assert(deltaTime, message) {
VIRTUAL_OUTPUT.removeAllListeners();
VIRTUAL_OUTPUT.receive = noop;
clearTimeout(id);
done(new Error("Callback should not have been triggered. " + message));
}
Expand Down
Loading