Skip to content

Conversation

lselden
Copy link

@lselden lselden commented Mar 10, 2025

This is an extension that adds MIDI support using the WebMIDI API. It tries to cover most use cases - it supports notes, CC, Pitch Bend, Program Change messages, etc.

Features

  • Device detection/enumeration
  • MIDI Input (When Note On/Off, When any midi event)
  • MIDI Output (similar syntax to the "Music" extension) - uses music "tempo" if set
  • Event reporter for thread context's current event
  • human-readable (and forgiving) string formatting of events for parsing/formatting

Todo

  • Translations
  • Add blocks documentation
  • Add string format documentation
  • Add "Getting Started" / browser compatibility documentation
  • Test on target devices (in particular mac / android)
  • Feedback on blocks - are any missing? should some be pruned? Better naming convention?
  • Image
  • (OPTIONAL) Separate icons for input vs output?

lselden added 3 commits March 5, 2025 12:12
Added midi extension for input/output of midi using the WebMidi API. Still pending documentation and peer-review
use "t=<time>" instead of "@<time>". Allow using "type=note pitch=60" instead of "note 60" if need to be verbose. Some bugfixes
@github-actions github-actions bot added the pr: new extension Pull requests that add a new extension label Mar 10, 2025
@lselden lselden mentioned this pull request Mar 10, 2025
@Brackets-Coder
Copy link
Contributor

Brackets-Coder commented Mar 11, 2025

At a glance, this looks much better than mine. You'll definitely need to add it to the list in extensions.json and probably make a gallery thumbnail too for it to be accepted though. You probably spent a lot more than four hours on it like I did. I might give it a full review (just for my opinion) when I have more time but I'm a bit busy right now. If you'd like, I can submit a PR or so to your fork that adds translations so you have one less thing to worry about (but again, I'm a bit busy right now, I'll have to get around to it when I can).

*/
function noteNameToMidiPitch(note, defaultOctave = 4) {
const parts =
/(?<pitch>[A-G])(?<flat>[b]+)?(?<sharp>[#]+)?_?(?<octave>-?\d+)?/i.exec(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be more human-readable if possible

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a regex with named groups to describe what's matched. added method comments to help describe what's valid. If anyone's interested in other implementations I used these for reference: strudel and tonaljs

function stringToMidi(text, opts = {}) {
if (typeof text !== "string") text = Cast.toString(text);
const fullRe =
/^\s*(?<type>[a-zA-Z]{2,})?\s*((?<pitch>[A-G][#b_]*-?\d?)|(?<data1>\b-?[0-9a-f]{1,5}\b))?\s*(?<data2>\b[0-9a-f]{1,3}\b)?\s*(?<keyvals>.+)\s*$/;
Copy link
Contributor

@Brackets-Coder Brackets-Coder Mar 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't fun to try to understand... Also you should use Scratch.Cast instead of Cast

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cast here is a local const of Scratch.Cast. Switched to the verbose Scratch.Cast to avoid confusion in the future

This comment was marked as abuse.

Comment on lines 2104 to 2105
// sanity check - don't let a note be more than 1 minute
// if anyone ever needs a longer note then they should manually write event string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?
I know it's a rare occurrence but as a musician (pianist), developer, and Scratch user you shouldn't generally limit the user's capabilities unless necessary. Notes technically can be a minute long and a user shouldn't have that length unexpectedly cut off...
Keep in mind this is just a quick look-over and I haven't fully analyzed it in depth yet

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hear ya. I checked and the Scratch Music extension clamps to 100 beats max (100 seconds at 60bpm) - updated code accordingly

This comment was marked as abuse.

}

//#endregion
Scratch.extensions.register(new MidiExtension());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class name is a bit overgeneralized?
Also your code style is not exactly like mine but I guess it's just a matter of preference. seems a bit cluttered to me but I guess it's just a personal problem.

Other than that it looks fine

This comment was marked as abuse.

@Brackets-Coder
Copy link
Contributor

Just a quick review, nothing in depth. Going over best practices for TW extensions in particular, not necessarily anything related to the functionality of the code.

lselden added 7 commits March 17, 2025 23:40
Existing code uses "dur" for "duration", and "pitch" for "noteName"
midi precision doesn't go under 2-5 milliseconds, so forcing numbers to be readable 1ms precision
Added midi extension for input/output of midi using the WebMidi API. Still pending documentation and peer-review
@AliceC-W
Copy link

AliceC-W commented Jul 5, 2025

Hello,

This doesn't seem to read my MIDI devices after my app has packaged (at least in Chrome on my Android when packaged from Penguinmod)

(To play a note on this, swipe from one clock position toward another (I will be adding more features to the face of this "clock, such as aftertouch, sustain, page turning, and menu))

Thanks for any help you can provide

Flick Talk.zip

@lselden
Copy link
Author

lselden commented Jul 9, 2025

Hello,

This doesn't seem to read my MIDI devices after my app has packaged (at least in Chrome on my Android when packaged from Penguinmod)

(To play a note on this, swipe from one clock position toward another (I will be adding more features to the face of this "clock, such as aftertouch, sustain, page turning, and menu))

Thanks for any help you can provide

Flick Talk.zip

@AliceC-W I couldn't get your app to do anything, so can't comment on it besides it looked like it's trying to play a 0 duration note, which might be an issue. That being said, browsers are particular about allowing MIDI access depending on the context - are you trying to open it as a local file? If so then try running it from a https link instead, which has fewer restrictions. You may also want to test if midi playback is supported by using the number of [output] devices block - it'll be 0 if no detected midi devices are available.

If you want further help then please make an example that just has the minimum necessary to reproduce (for example click/touch on the screen to play a single note)

@AliceC-W
Copy link

AliceC-W commented Jul 9, 2025

Hello,
This doesn't seem to read my MIDI devices after my app has packaged (at least in Chrome on my Android when packaged from Penguinmod)
(To play a note on this, swipe from one clock position toward another (I will be adding more features to the face of this "clock, such as aftertouch, sustain, page turning, and menu))
Thanks for any help you can provide
Flick Talk.zip

@AliceC-W I couldn't get your app to do anything, so can't comment on it besides it looked like it's trying to play a 0 duration note, which might be an issue. That being said, browsers are particular about allowing MIDI access depending on the context - are you trying to open it as a local file? If so then try running it from a https link instead, which has fewer restrictions. You may also want to test if midi playback is supported by using the number of [output] devices block - it'll be 0 if no detected midi devices are available.

If you want further help then please make an example that just has the minimum necessary to reproduce (for example click/touch on the screen to play a single note)

Yes I am trying to run it right on my phone in Android Chrome
(my address bar says content://media/external/file/1002145829 (in case that helps))

How do I run it from a https link? Will this require additional hardware (counting codebeautify.org)? Does Penguinmod offer a way to force that change in the address bar?

Here is a simple project detailing my only problem at the moment

Number of MIDI Devices Project.zip

@lselden
Copy link
Author

lselden commented Jul 11, 2025

Yes I am trying to run it right on my phone in Android Chrome (my address bar says content://media/external/file/1002145829 (in case that helps))

How do I run it from a https link? Will this require additional hardware (counting codebeautify.org)? Does Penguinmod offer a way to force that change in the address bar?

Here is a simple project detailing my only problem at the moment

Number of MIDI Devices Project.zip

Thanks for providing the project. I'm able to see my output devices on my laptop, and 0 devices on my iPhone (which is expected - Apple doesn't support WebMidi).

I'd recommend using Github Pages to host your content (which is free) if you don't mind it being publically accessible - I'm sure there's plenty of tutorials out there if you aren't that familiar with github. You could also try testing if you have a computer on the same network using any static web server software, for example fenix, python -m http.server or npx http-server (if you have python3 / node.js installed - google it). However, you may need to be using a https:// link (secure context) to get WebMidi to work - check to see if WebMidi works on the HTTP version of permission.site vs the HTTPS version of permission.site.

@AliceC-W
Copy link

Thanks

I just found out that Opera GX recognizes my MIDI devices even in airplane mode

I think it will do, at least until that environment can be simulated in the .html (directory) itself

I'm sorry to hear that about iPhone, definitely let me know if that changes

The equipment I used was:

  1. NUOSIYA Type-C to MIDI Cable 6.5Ft,Type-C MIDI Interface Adapter,MIDI to Type-C Cable Converter ​for Music Keyboard Piano to PC Mac Laptop Windows Android (purchased on Amazon.com on Jul 4, 2024)

  2. Android 13 on Samsung Galaxy A52 5G (Purchase recieved Mon, Sep 20, 2021)

  3. Yamaha PSR-275 (gifted on December 25, 2003 before I even knew that MIDI is actually just an interface)

@Brackets-Coder
Copy link
Contributor

Brackets-Coder commented Jul 12, 2025

@lselden I've used both macOS and Windows throughout various periods. About the iPhone -- It's not that Apple straight up just doesn't support WebMIDI, it's that all Safari Browsers across Apple devices don't support the API due to security concerns, which Apple seems to care a lot about. I've gotten WebMIDI to work as expected with Google Chrome on macOS

@Brackets-Coder
Copy link
Contributor

@lselden Is this still being worked on?

@Brackets-Coder
Copy link
Contributor

Hello @lselden,
I've tested the input portion of this extension on my Mac with Firefox, and it's working. I haven't tested MIDI output.

video.mov

extension had a WIP addition of the @tonejs/midi library for midi file support. Removing in favor of it being a separate extension
@lselden
Copy link
Author

lselden commented Sep 17, 2025

@Brackets-Coder No I'm not actively working on this. I had left this off with partial support for midi file in/out, but never finished. I just updated the library to remove the midi file code. If any one is interested in collaborating (@CHCAT1320 ?) I can submit what I have for midi-file handling as a separate PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: new extension Pull requests that add a new extension
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants