Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIDI Extension #1725

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7fe72de
Create midi.js
Brackets-Coder Oct 15, 2024
c4f9954
Update extensions.json
Brackets-Coder Oct 15, 2024
6cc1d31
Create midi.png
Brackets-Coder Oct 15, 2024
4261daa
Delete images/MasterMath/midi.png
Brackets-Coder Oct 15, 2024
a61a1df
Create midi.png
Brackets-Coder Oct 15, 2024
cb7da19
Add midi.png
Brackets-Coder Oct 15, 2024
d67eb86
Attempt to fix midi.js prettier
Brackets-Coder Oct 16, 2024
d9a1df1
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Oct 16, 2024
2cc79ef
Add new block and improve efficiency
Brackets-Coder Oct 17, 2024
c9645ee
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Oct 26, 2024
9014297
Fix connection splice()
Brackets-Coder Oct 30, 2024
43a5839
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Nov 4, 2024
59c25b5
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Dec 14, 2024
bbff7de
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Jan 8, 2025
a5c6aee
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Jan 28, 2025
a7472ff
Add translations and fix stuff
Brackets-Coder Jan 28, 2025
42f6ab8
Merge branch 'midi' of https://github.com/Brackets-Coder/extensions i…
Brackets-Coder Jan 28, 2025
61e355d
oops missed one
Brackets-Coder Jan 28, 2025
c9bc1eb
requested changes
Brackets-Coder Jan 29, 2025
1c0c48b
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Feb 1, 2025
5dd9d64
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Feb 7, 2025
0f370e1
Merge branch 'TurboWarp:master' into midi
Brackets-Coder Feb 11, 2025
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
269 changes: 269 additions & 0 deletions extensions/MasterMath/midi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
// Name: MIDI
// ID: masterMathMidi
// Description: An extension that retrieves input from MIDI devices.
// By: -MasterMath- <https://scratch.mit.edu/users/-MasterMath-/>
// License: MPL-2.0

(function (Scratch) {
"use strict";

if (!Scratch.extensions.unsandboxed) {
throw new Error("This MIDI extension must run unsandboxed!");
}

let midiInputDevices = [];
let midiDeviceInfo = [];
let notesOn = [];
let noteVelocities = [];
let lastNotePressed = 0;
let lastNoteReleased = 0;

if (navigator.requestMIDIAccess) {
navigator.requestMIDIAccess().then(onSuccess, onError);

function onSuccess(midiAccess) {
midiAccess.onstatechange = (event) => {
if (event.port.state == "connected") {
midiInputDevices.push(
`[id: "${event.port.id}" name: "${event.port.name}"]`
);
midiDeviceInfo.push([event.port.id, event.port.name]);
} else if (event.port.state == "disconnected") {
// Find and remove from midiInputDevices
const inputIndex = midiInputDevices.findIndex(
(item) =>
item === `[id: "${event.port.id}" name: "${event.port.name}"]`
);
if (inputIndex !== -1) midiInputDevices.splice(inputIndex, 1);

// Find and remove from midiDeviceInfo
const infoIndex = midiDeviceInfo.findIndex(
(item) => item[0] === event.port.id
);
if (infoIndex !== -1) midiDeviceInfo.splice(infoIndex, 1);
}
};

function onMIDIMessage(event) {
const [status, note, velocity] = event.data;
const command = status & 0xf0;
if (command === 0x90 && velocity > 0) {
notesOn.push(note);
noteVelocities.push([note, velocity]);
lastNotePressed = note;
Scratch.vm.runtime.startHats("midi_whenAnyNote", {
pressedReleased: "pressed",
});
Scratch.vm.runtime.startHats("midi_whenNote", {
note: note,
pressedReleased: "pressed",
});
} else if (command === 0x80 || (command === 0x90 && velocity === 0)) {
lastNoteReleased = note;
notesOn.splice(notesOn.indexOf(note), 1);
noteVelocities.splice(
noteVelocities.findIndex((subArray) => subArray[0] === note),
1
);
Scratch.vm.runtime.startHats("midi_whenAnyNote", {
pressedReleased: "released",
});
Scratch.vm.runtime.startHats("midi_whenNote", {
note: note,
pressedReleased: "released",
});
} else {
console.log(
`Other MIDI Message: Status=${status}, Note=${note}, Velocity=${velocity}, Timestamp ${event.timeStamp}`
);
}
}

midiAccess.inputs.forEach((entry) => {
entry.onmidimessage = onMIDIMessage;
});
}

function onError(err) {
throw new Error("MIDI Access Error:", err);
}
} else {
throw new Error("MIDI is not supported on this browser.");
}

class MIDI {
getInfo() {
return {
id: "masterMathMidi",
name: Scratch.translate("MIDI"),
blocks: [
{
opcode: "MIDIinputDevices",
blockType: Scratch.BlockType.REPORTER,
text: Scratch.translate("connected MIDI input devices"),
disableMonitor: true,
},
{
opcode: "midiDeviceInfo",
blockType: Scratch.BlockType.REPORTER,
text: Scratch.translate("[info] of MIDI device [number]"),
arguments: {
info: {
type: Scratch.ArgumentType.STRING,
menu: "infoMenu",
},
number: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 0,
},
},
},
"---",
{
opcode: "whenAnyNote",
blockType: Scratch.BlockType.EVENT,
text: Scratch.translate("when any note [pressedReleased]"),
isEdgeActivated: false,
shouldRestartExistingThreads: true,
arguments: {
pressedReleased: {
type: Scratch.ArgumentType.STRING,
menu: "pressedReleased",
},
},
},
{
opcode: "whenNote",
blockType: Scratch.BlockType.EVENT,
text: Scratch.translate("when note [note] [pressedReleased]"),
isEdgeActivated: false,
shouldRestartExistingThreads: true,
arguments: {
note: {
type: Scratch.ArgumentType.NOTE,
defaultValue: 60,
},
pressedReleased: {
type: Scratch.ArgumentType.STRING,
menu: "pressedReleased",
},
},
},
{
opcode: "noteOn",
blockType: Scratch.BlockType.BOOLEAN,
text: Scratch.translate("is note [note] on?"),
arguments: {
note: {
type: Scratch.ArgumentType.NOTE,
defaultValue: 60,
},
},
},
{
opcode: "noteVelocity",
blockType: Scratch.BlockType.REPORTER,
text: Scratch.translate("velocity of note [note]"),
arguments: {
note: {
type: Scratch.ArgumentType.NOTE,
defaultValue: 60,
},
},
},
{
opcode: "activeNotes",
blockType: Scratch.BlockType.REPORTER,
text: Scratch.translate("all active notes"),
disableMonitor: true,
},
{
opcode: "lastNote",
blockType: Scratch.BlockType.REPORTER,
text: Scratch.translate("last note [pressedReleased]"),
disableMonitor: true,
arguments: {
pressedReleased: {
type: Scratch.ArgumentType.STRING,
menu: "pressedReleased",
},
},
},
],
menus: {
infoMenu: {
acceptReporters: false,
items: [
{
text: Scratch.translate("name"),
value: "name",
},
{
text: Scratch.translate("id"),
value: "id",
},
],
},
pressedReleased: {
acceptReporters: false,
items: [
{
text: Scratch.translate("pressed"),
value: "pressed",
},
{
text: Scratch.translate("released"),
value: "released",
},
],
},
},
};
}

MIDIinputDevices() {
return midiInputDevices;
}

midiDeviceInfo(args) {
args.number = Scratch.Cast.toNumber(args.number);
if (midiInputDevices[args.number] != null) {
Brackets-Coder marked this conversation as resolved.
Show resolved Hide resolved
return midiDeviceInfo[args.number][args.info == "id" ? 0 : 1];
} else {
return;
}
}

noteOn(args) {
return notesOn.includes(Scratch.Cast.toNumber(args.note));
}

noteVelocity(args) {
args.note = Scratch.Cast.toNumber(args.note);
if (
notesOn.includes(args.note) &&
noteVelocities.find((subArray) => subArray[0] === args.note)[1] !==
undefined
) {
return noteVelocities.find((subArray) => subArray[0] === args.note)[1];
}
}

activeNotes() {
return notesOn;
}

lastNote({ pressedReleased }) {
switch (pressedReleased) {
case "pressed":
return lastNotePressed;
case "released":
return lastNoteReleased;
default:
return "";
}
}
}

Scratch.extensions.register(new MIDI());
})(Scratch);
1 change: 1 addition & 0 deletions extensions/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"veggiecan/browserfullscreen",
"shreder95ua/resolution",
"XmerOriginals/closecontrol",
"MasterMath/midi",
"navigator",
"battery",
"PwLDev/vibration",
Expand Down
Binary file added images/MasterMath/midi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.