惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
L
LINUX DO - 热门话题
PCI Perspectives
PCI Perspectives
www.infosecurity-magazine.com
www.infosecurity-magazine.com
爱范儿
爱范儿
D
DataBreaches.Net
Simon Willison's Weblog
Simon Willison's Weblog
S
Secure Thoughts
S
SegmentFault 最新的问题
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
P
Proofpoint News Feed
The Hacker News
The Hacker News
T
ThreatConnect
N
News and Events Feed by Topic
T
Threatpost
The Register - Security
The Register - Security
WordPress大学
WordPress大学
博客园 - Franky
Recorded Future
Recorded Future
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
腾讯CDC
F
Future of Privacy Forum
F
Full Disclosure
Cyberwarzone
Cyberwarzone
J
Java Code Geeks
李成银的技术随笔
Schneier on Security
Schneier on Security
Know Your Adversary
Know Your Adversary
H
Hacker News: Front Page
人人都是产品经理
人人都是产品经理
博客园_首页
Scott Helme
Scott Helme
Google DeepMind News
Google DeepMind News
美团技术团队
Malwarebytes
Malwarebytes
Last Week in AI
Last Week in AI
T
Tailwind CSS Blog
T
The Exploit Database - CXSecurity.com
G
GRAHAM CLULEY
Recent Announcements
Recent Announcements
C
CXSECURITY Database RSS Feed - CXSecurity.com

CSS-Tricks

Revealing Text With CSS letter-spacing | CSS-Tricks Technical Writing in the AI Age | CSS-Tricks Cross-Document View Transitions: Scaling Across Hundreds of Elements | CSS-Tricks Cross-Document View Transitions: Scaling Across Hundreds of Elements | CSS-Tricks The State of CSS Centering in 2026 | CSS-Tricks Stack Overflow: When We Stop Asking | CSS-Tricks Cross-Document View Transitions: The Gotchas Nobody Mentions | CSS-Tricks What’s !important #11: 3D Voxel Scenes, Flying Focus, CSS Syntaxes, and More | CSS-Tricks Computing and Displaying Discounted Prices in CSS | CSS-Tricks rotateX() | CSS-Tricks rotateY() | CSS-Tricks rotateZ() | CSS-Tricks rotate() | CSS-Tricks Soon We Can Finally Banish JavaScript to the ShadowRealm | CSS-Tricks Using CSS corner-shape For Folded Corners | CSS-Tricks A Scrollytelling Gift for Mum on Mother’s Day 2026 | CSS-Tricks Google’s Prompt API | CSS-Tricks Making Zigzag CSS Layouts With a Grid + Transform Trick | CSS-Tricks Fixed-Height Cards: More Fragile Than They Look | CSS-Tricks What’s !important #10: HTML-in-Canvas, Hex Maps, E-ink Optimization, and More | CSS-Tricks The Importance of Native Randomness in CSS | CSS-Tricks contrast() | CSS-Tricks contrast-color() | CSS-Tricks Let’s Use the Nonexistent ::nth-letter Selector Now | CSS-Tricks Quick Hit #126 Recreating Apple’s Vision Pro Animation in CSS | CSS-Tricks Quick Hit #125 Enhancing Astro With a Markdown Component | CSS-Tricks Quick Hit #124 Markdown + Astro = ❤️ | CSS-Tricks Quick Hit #123 What’s !important #9: clip-path Jigsaws, View Transitions Toolkit, Name-only Containers, and More | CSS-Tricks A Well-Designed JavaScript Module System is Your First Architecture Decision | CSS-Tricks hypot() | CSS-Tricks The Radio State Machine | CSS-Tricks 7 View Transitions Recipes to Try | CSS-Tricks Quick Hit #122 Quick Hit #121 Selecting a Date Range in CSS | CSS-Tricks saturate() | CSS-Tricks justify-self | CSS-Tricks Quick Hit #120 Alternatives to the !important Keyword | CSS-Tricks Quick Hit #119 New CSS Multi-Column Layout Features in Chrome | CSS-Tricks Quick Hit #118 Making Complex CSS Shapes Using shape() | CSS-Tricks Quick Hit #117 Front-End Fools: Top 10 April Fools’ UI Pranks of All Time | CSS-Tricks Sniffing Out the CSS Olfactive API | CSS-Tricks What’s !important #8: Light/Dark Favicons, @mixin, object-view-box, and More | CSS-Tricks Quick Hit #116 Form Automation Tips for Happier User and Clients | CSS-Tricks Quick Hit #115 Generative UI Notes | CSS-Tricks Quick Hit #114 Quick Hit #113 Experimenting With Scroll-Driven corner-shape Animations | CSS-Tricks Quick Hit #112 JavaScript for Everyone: Destructuring | CSS-Tricks Quick Hit #111 Quick Hit #110 What’s !important #7: random(), Folded Corners, Anchored Container Queries, and More | CSS-Tricks 4 Reasons That Make Tailwind Great for Building Layouts | CSS-Tricks Quick Hit #109 Quick Hit #108 Abusing Customizable Selects | CSS-Tricks Quick Hit #107 The Value of z-index | CSS-Tricks Quick Hit #106 The Different Ways to Select <html> in CSS Quick Hit #105 Popover API or Dialog API: Which to Choose? Quick Hit #104 What’s !important #6: :heading, border-shape, Truncating Text From the Middle, and More Yet Another Way to Center an (Absolute) Element An Exploit ... in CSS?! Quick Hit #103 A Complete Guide to Bookmarklets Quick Hit #102 Loading Smarter: SVG vs. Raster Loaders in Modern Web Design Potentially Coming to a Browser :near() You Quick Hit #101 Distinguishing "Components" and "Utilities" in Tailwind Quick Hit #100 Spiral Scrollytelling in CSS With sibling-index() Interop 2026 Quick Hit #99 What’s !important #5: Lazy-loading iframes, Repeating corner-shape Backgrounds, and More Quick Hit #98 Making a Responsive Pyramidal Grid With Modern CSS Approximating contrast-color() With Other CSS Features Quick Hit #97 Trying to Make the Perfect Pie Chart in CSS Quick Hit #96 Quick Hit #95 CSS Bar Charts Using Modern Functions Quick Hit #94 No Hassle Visual Code Theming: Publishing an Extension Quick Hit #93
Dip Your Toes Into Hardware With WebMIDI
CSS-Tricks · 2019-12-12 · via CSS-Tricks

Did you know there is a well-supported browser API that allows you to interface with interesting and even custom-built hardware using a mature protocol that predates the web? Let me introduce you to MIDI and the WebMIDI API and show you how it presents a unique opportunity for front-end developers to break outside the browser and dabble in the world of hardware programming without leaving the relative comfort of JavaScript and the DOM.

What are MIDI and WebMIDI exactly?

MIDI is a niche protocol designed for musical instruments to communicate with each other. It was standardized in 1983 and is maintained to this day by an organization consisting of music industry companies and representatives. It’s not wildly different than how the W3C dictates and preserves web standards, in some sense.

Photo by Jiroe on Unsplash

The WebMIDI API is the browser-based implementation of this protocol and allows our web applications to “speak” MIDI and communicate with any MIDI-capable hardware that might be connected to a user’s device.

Not a musician? Don’t worry! We’ll discover very quickly that this simple protocol designed for electronic musical instruments can be used to build fun, interactive, and completely non-musical things.

Why would I want to do this?

Great question. The shortest answer: because it’s fun!

If that answer isn’t satisfying enough for you I’ll offer this: Creating something that straddles the line between the physical world and virtual world we spend most of our days building things for is a good exercise in thinking differently. It’s an opportunity for creative tinkering and for considering and creating new user interfaces and experiences to navigate. I truly think this kind of playful exploration helps make us use different parts of our brains and makes us better developers in the long-haul.

What kind of things can I build?

Cellular Automata on a MIDI controller
Playing Go
Whack-a-mole
Mixing colors with hand motions

What do I need to get started?

Here are the prerequisites to start experimenting with WebMIDI:

A MIDI controller

This might be the trickiest part. You’ll need to procure a MIDI-capable piece of hardware to experiment with. You might be able to find something cheap on Craigslist, Amazon or AliExpress. Or — if you’re really ambitious and have an Arduino available — you can build your own (see the end of this article for more information about this).

A WebMIDI-capable browser

Desktop

ChromeFirefoxIEEdgeSafari
43108No79No

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
147No147No

As of this writing, according to caniuse.com it’s supported by approximately 73% of browsers, though most of the heavy-lifting is done by Chromium. Any Chromium-based browser will support WebMIDI—that includes Electron apps and the newer Chromium-based Microsoft Edge. It’s also supported on Opera and the Samsung Internet Browser. On Firefox it’s still being discussed but hopefully coming sooner than later.

Hello, WebMIDI

Once you’ve procured both of those things we can start writing some code! Working with the WebMIDI is not terribly different than working with other browser APIs like the Geolocation or MediaDevices APIs, if you’re familiar with either of those.

The high-level flow looks like this:

  • We detect availability of the WebMIDI API in the browser.
  • If detected, we request permission from the user to access it.
  • Once we’re granted permission, we now have access to additional methods to detect and communicate with any connected MIDI devices.

Let’s see that in action:

if ("requestMIDIAccess" in navigator) {
  // The Web MIDI API is available to us!
}

Now, assuming we’re in a WebMIDI-capable browser, let’s request access:

navigator.requestMIDIAccess()
.then((access) =&gt; {
  // The user gave us permission. Now we can
  // access the MIDI-capable devices connected
  // to the user's machine.
})
.catch((error) =&gt; {
  // Permission was not granted. :(
});

If the user gives us permission, we should now have access to the MIDIAccess interface. This helps us build a list of the devices that we can receive MIDI input from and send MIDI output to.

Let’s do that next. This is the code that goes inside the function we’re passing into then from the previous code snippet:

const inputs = access.inputs;
const outputs = access.outputs;

// Iterate through each connected MIDI input device
inputs.forEach((midiInput) =&gt; {
  // Do something with the MIDI input device
});

// Iterate through each connected MIDI output device
outputs.forEach((midioutput) =&gt; {
  // Do something with the MIDI output device 
});

You might be wondering what the difference is between a MIDI input and output device. Some devices are setup to only send MIDI information to the computer (these will be listed as inputs) and others can receive information from the computer (these will appear as outputs). It’s not uncommon that a device can be send and receive, so you will find it listed under both.

Now that we have code that can iterate through all the connected MIDI devices, there are basically only two things we’ll want to do;

  • If it’s an input device, we’ll want to listen for any incoming MIDI messages emitting from it.
  • If it’s an output device, we might want to send MIDI message to it.

The code for setting up an event listener to respond to any incoming MIDI messages from our input devices looks very similar to an event listener you might setup for other DOM events, except in this case, the event we’re listening for is the midimessage event:

midiInput.addEventListener('midimessage', (event) =&gt; {
  // the `event` object will have a `data` property
  // that contains an array of 3 numbers. For examples:
  // [144, 63, 127]
})

If we want to send a MIDI message to an output device the code we can do so like this;

outputsend([144, 63, 127]);

Here is a CodePen demo with most of this put together for you. It will let you know about all of the MIDI inputs and output devices connected to your system and show you incoming MIDI messages as they happen:

See the Pen
WebMIDI Basic Test
by George Mandis (@georgemandis)
on CodePen.

WebMIDI Test demo screenshot highlighting which MIDI input and output devices were found
WebMIDI Test demo screenshot highlighting MIDI messages received by one of the MIDI input devices. In this case, we’re seeing when a key on the MIDI keyboard is pressed.
WebMIDI Test demo screenshot highlighting MIDI messages received by one of the MIDI input devices. In this case, we’re seeing when a key on the MIDI keyboard is released.

You might be wondering a couple things at this point:

  • When you’re listening for the midimessage event, how do I make heads or tails of that three number array in event.data?
  • Why did you send an array of three numbers to your MIDI output device and why did you send those specific numbers?

The answer to both of these questions lies in further exploring and understanding how the MIDI protocol works and the problems it was designed to solve.

Anatomy of a MIDI message

When a MIDI controller “speaks” to another MIDI-capable device or computer, they are sending and receiving MIDI messages with one another. The protocol underlying this communication is fairly simple in practice but a little verbose when explained. Still, I’ll try.

Every MIDI message consists of three bytes consisting of 8-bits (0-255). Represented in binary, a message might look like this:

10010000 | 00111100 | 01111111

There are only two types of MIDI messages: Status and data. Every message will consist of one status byte and two data bytes.

The status byte is intended to communicate what kind of message is being delivered, including things like:

  • Note On
  • Note Off
  • Pitch Bend Change
  • Control/Mode Change
  • Program Change

…and many others.

If you’re coming at this from a non-musical background, these status messages might seem kind of strange, but don’t worry too much about it. The data byte is intended to provide more information and context to the status. To give an example, if I have a MIDI piano plugged into my machine and press a key to play a note, it would send a “Note On” status byte accompanied by data bytes indicating which note I played, and perhaps how hard I pressed it.

A status byte will always begin with the number 1 and data bytes with the number 0.

1x0010000 | 0x0111100 | 0x1111111
    ^status     ^data1      ^data2

For data bytes that leaves 7-bits to express the data in that byte. That gives us an integer range of 0-127.

For status bytes, the next 3-bits after the first describe the type of status message while the remaining 4-bits describe the channel. To break down our binary representation:

1x001x0000

How this translates into WebMIDI and JavaScript

As you may have guessed from the code samples earlier, with the WebMIDI API, we seldom have to deal with these binary representations directly. When we send and receive these messages in JavaScript we simply use arrays like this:

[144, 63, 127]

If you’re working with existing musical hardware, it’s helpful to have this deeper understanding of how and why the messages are structured the way they are. It’s helpful to know that receiving a 144 in your first byte means a note is being turned on in the first channel and that a 128 would indicate that a note is being turned off.

However, if we’re building non-musical experiences and creating our own hardware, these numbers can be repurposed to represent whatever you want!

What kind of hardware can I use?

Any MIDI-capable device that can be connected to your computer should also be accessible through the WebMIDI API. Devices that are capable of sending MIDI data to another MIDI-capable device are often called MIDI controllers. A common example would be a simple, piano-style keyboard like this Korg nanoKey2:

But they can vary widely in appearance and modes of interaction. Buttons are certainly common, but you might also find some that incorporate dials or pressure-sensitive pads like the AKAI LPD8:

Others use more abstract and interesting modes of interaction, including mapping motion or breath to MIDI signals. For example, this controller (The Hothand from Source Audio) uses three accelerometers to map hand gestures to MIDI messages:

Some controllers can both send and receive MIDI messages, allowing for you to have a true two-way conversation with the physical world. The Novation Launchpad is a classic example — buttons can be pressed to send messages and messages can also be received to dynamically change colors on the device:

Can I build my own hardware?

It turns out they’re not terribly difficult to build and you can find a lot of home-brewed MIDI controllers out in the wild. They can get much more elaborate in a hurry. Some can be downright bananas:

Bananas connected by wires to an Adafruit Circuit Playground programmed to function as a MIDI instrument

Building your own MIDI controller will take you a bit outside the world of JavaScript, but it’s still surprisingly accessible if you’re familiar with or interested in the Arduino platform. The Circuit Playground Classic from Adafruit is a great device to get started with and you can find starter code to flash to the device and make it into a multi-faceted MIDI controller here on GitHub.

Summary

The WebMIDI API is a low-barrier-to-entry way for front-end developers to start experimenting with basic hardware and software interactions. The implementation is relatively straightforward compared to some other hardware web APIs (like Bluetooth) and the MIDI standard is well-documented. There are lots of existing MIDI-capable devices out there to experiment or build cool things with, and if you really want to go all-out and start building your own custom MIDI hardware for your project, you can do that too.

Go out there and make something!