Shure MVX2U Linux Client

check static site compile

TODO: add more links to anything mentioned

TODO: add pictures

TODO: proofread, check sentence flow in case some paragraphs conveyed their meaning poorly

Professional audio has relied on XLR connectors for more than half a century, and it is possible to find cables that connect and convert from a microphone's XLR connector to a 3.5 mm socket, the headphone jack. Such cables come with a few issues: They typically change the impedance, use an unbalanced signal, have much higher handling noise, and they cannot power condensor microphones. Beyond that, you still need a combination headphone jack or dedicated 3.5mm microphone socket on your recorder if your recorder doesn't have XLR. Most modern tech, on the other hand, is moving to USB-C.

Enter Shure…

Shure has possibly the most recognized microphone brand in history with its SM58 and 55S Unidyne microphones—the latter used by Elvis and Frank Sinatra. This brand equips politicians as well as the Pope. They have a reputation for durable products and timeless designs. Many top podcasters use some variant of the SM7. Nearly every Shure mic uses a balanced XLR connector. Perhaps recognizing the surge in podcasting and recording on portable electronics, they have released an adapter to convert XLR to USB-C. It's really the confluence of two designs, the X2U adapter that outputs via a full-size USB 2.0 Type-B connector (think printer USB connector) and their MOTIV digital microphones, which all seem to be specific condensor microphone designs (stereo camera mic, videoconferencing ball, end-address studio mic aka podcast mic) that can be directly plugged in to a computer for recording. Using a MOTIV microphone means the hardware cannot change.

While the noise floor of the MVX2U is not amazing, they have made it possible to plug in any XLR microphone from your arsenal—dynamic, ribbon, condensor—and connect it to your smartphone or laptop. Theoretically, you could plug it into a power bank and connect to a recorder with a 3.5mm aux cable. Because USB audio is a well-implemented and established standard, this adapter just. works. Unlike most 1-channel audio interfaces, you can attach the Shure device directly onto the base of nearly any microphone. It is small and designed to be placed inline.

The Shure is still a tradeoff of different factors: performance, convenience, size, etc. However, nothing else I've seen will let me connect an instrument-mounted pro microphone—like the DPA 4099—with a single short USB cable and then put all of the recording tools (a smartphone) in a large pocket or pouch.

To get better performance in an almost-as-compact design, you'd need something like the Zoom F3 field recorder, which is twice as expensive as Shure's adapter and more than twice as large. There are cheap XLR-to-USB cables, but they won't power a condensor mic like the DPA or provide the dynamic range of the MVX2U.

The MVX2U is a nice and versatile adapter!

One Major Problem

The Shure XLR adapter does not have any switches or dials. You have to set it up in advance using a Windows PC or Mac. They also have an Android app but it has not been updated to configure the MVX2U.

There is an automatic mode, which detects the volume level and adjusts the recording gain so the output is always "reasonably normal" volume. You can't set how quickly it adjusts to "too loud", how short of a "too loud" to ignore, and how long it should average the output signal. (This is one area where other designs shine, such as field recorders with multiple preamps that save floating point audio.)

I tried recording a wind ensemble rehearsal in Auto mode. By the third note, the interface had adapted to the sudden loudness in the room. But, any time the music gets quieter for a few seconds, the interface has already adjusted. This strips nearly the entire performance of its dynamic quality. If there is a half-second pause, the gain is already starting to rise, so the next entrance will be relatively louder on the recording than the music slightly before the pause.

Here is an analogy: Imagine trying to take photos of a Formula 1 race, but you can only set up your camera a week before the race. You don't know the weather or where you'll be standing in relation to the track. That is Manual mode on this Shure interface when you do not have it plugged into a Mac/PC.

You have to know in advance roughly how loud your performance will be. Then, you'll need to know how sensitive your microphone is. You have to know what a good output volume should be. At least they have the decency to have a headphone jack so you can monitor and then move the microphone forward or back—as long as your headphones reject enough ambient sound to monitor the recording.1

Just as many professional photographers avoid Auto mode on cameras—especially for sudden action, panoramas, or suboptimal lighting—I would recommend only using Manual mode on the Shure MVX2U.

Open Source

I often use Linux at home. I only use Linux at home, in fact. I used to make exceptions for things like the Shure MVX2U, where Wine—the Windows emulator—does not come out-of-the-box with USB peripheral support. A few people have Linux-based (or platform-agnostic) tools for configuring Shure's other MOTIV microphones. After adding the product ID for the new adapter, it did not connect to the microphone. It was clear this was a different design than, say, the MV7.

Thus, I decided if Shure is not going to act quickly to support the MVX2U in the Android app and on Linux, I will need to develop my own script for communicating with the microphone.

(Shure has since released new firmware addressing some noise floor issues, but the desktop app is not an improvement and the mobile app only connects to the microphone as "External Mic" with no options to change onboard settings.)

Opening the hood

If you think about the adapter features and look at the verbose output of lsusb, you understand that the Shure adapter is mildly complex for a USB device. It has audio inputs plus outputs for both 16- and 24-bit. It has asynchronous, interrupt, and control endpoints. It's not immediately obvious, but the configuration data are transferred using a vendor-specific HID class.

There were two main ways to get what I needed from the device: Wireshark (packet captuer) and looking at the Electron source of their desktop application.

Wireshark

After figuring out how to set up Wireshark to capture USB communications and set filters, this was a really quick was to figure out which endpoint was being used for configuration, the steps taken before communication happens, and the exact data being transferred. It helps here that I've written some microcontroller code that configures and uses USB endpoints as well as a ton of SD/SPI protocol code, and there was a competition (probably Google Code Jam, a HackerRank contest, or Advent of Code) where you needed to write a decoder for variable length messages.

After staring at messages for an uncomfortable length of time, it seems they use pretty standard practices that probably make it easier to program the microcontroller inside the MVX2U: start and stop packets, sending the length of the packet right after the start packet, a unique ID for each message, a header section plus a data section, checksum, and so on. It also seems there's a simple 1-to-n enumeration of each possible data byte.

The biggest advantage to using Wireshark was that it became quickly clear that packages were consistent and predictable. This means you can send an old packet and get the same answer. The only issue is figuring out which USB library to use that lets you send the same packets. While I tried to get HID libraries to work for me, I eventually—seemingly randomly—sent a copy-pasted 64-byte packet to 0x83 and finally didn't get an error or timeout. I got back 64… as in "expect a 64-byte answer". I got back the same answer that Wireshark captured! I could finally talk to the device!

I noticed there were three packets that kept getting sent in a loop. I figured these were somewhat-packed binary data as they weren't too big but seemed low entropy enough that ...dda000000eddcccccc... could be bands of EQ settings and a handful of single-bit toggles or small bitfields. I changed some settings, plugged it back in, and… same data? What??! I captured more data and realized you need to ignore the looping packets and look out for the packets that get sent when a new selection is made in the MOTIV executable.

Electron

Shure has a disclaimer about reverse engineering. I think European laws are supposed to be a bit lax here. However, is it reverse engineering if you can open their executable in a text editor and see details and code in plain text?

One nice thing about Electron is that it does not strip away source very well—at least not the way Shure configures their Electron app. In their case, some of the source contains comments. In fact, one of the comments refers to a person in one of Shure's research centers who needs to sign off on a change.2 If you are enterprising enough, you can find base64-encoded server credentials. You can even tear apart the .apk, which is compiled with Kotlin but still can be decompiled into quasi-anonymous functions. For the purpose of designing a Linux app, these last steps were not needed.

By looking at the source, you can find all of the internal variable names used by the different MOTIV mics. You can also verify the command table once you know what to look for. The command table seems like it has a few pages and scattered addresses; not 1-to-n.3 The straightforward method of getting the command table, although it is time-consuming, is to click through each setting in MOTIV Desktop and watch which bytes change in Wireshark. If you find enough of these, you search the Electron source and find the remaining table. Some commands do not apply to the MVX2U: it does not record in stereo and there's not an "instrument" mode.

Building a client

I chose Python here because I can rip off mv7config, I am comfortable programming in Python, and it comes with virtually every desktop install of Linux.

Ever try to write USB code in C++? Ugh! If I tried to make a GUI app in C++, I need to install a ton of packages and spend a bunch of time figuring out how some framework works. I would avoid Qt because I understand just enough of their license to know it can become a headache later. That means something cross-platform, annoying, and ugly; or something native and good looking on one OS but then bug-prone. (Anyone who crashed a GTK4 app on their first day installing a new distro knows what I mean here!) And then do you release source? Binary? Try to send to your favorite package managers? Flatpak? Snap? AppImage?

If I tried to make a GUI app in Rust, I need to learn Rust, and then install even more packages and spend a whole bunch of time figuring out how some framework works as it is probably being actively developed. Plus all the other bullshit I mentioned with C++. No, thank you.

So, Python. If I need a GUI, I have choices: the same thing mv7config did, a GTK+/Glib application; or Tkinter, which is conveniently bundled in a lot of Python installations. It's also not a problem to leave it as a script with all its I/O in the console.

Time-consuming but necessary work

With much of the interesting part behind us—the reverse engineering—the major task remaining is to write functions: one to create packets, another to decode them, a few for sending and receiving, one for getting a config option, another for setting it, and then tables for config options and commands, variables for all of this, and then functions to let the user interact with the settings.

I am able to connect to the MVX2U using Linux and change various settings. If anything is buggy or missing, contact me and I'll work out a fix ASAP.

Development is happening at https://gitlab.com/PennRobotics/shux


  1. The MVX2U output headphone jack is also a pain sometimes. If you attach the MVX2U to a smartphone, it will usually automatically set the XLR port as the active microphone and the headphone jack on the MVX2U as the output speaker. On a few phones, one can manually change the output channel back to the phone speaker—necessary if you want to listen to what was just recorded without unplugging everything. On recent Galaxy S phones, you cannot change from the 3.5 mm jack back to the phone speaker as an output while the MVX2U is still connected. You need to unplug the USB cable, listen to your recording, and plug back in. Every time. Depending on which app you use to record, you have to close the app so it doesn't stay stuck on the built-in phone microphone. It would be lovely to have the option to disable the headphone jack as an audio sink entirely—to save energy, reduce PCB noise, and keep phones from remapping the sound configuration. In a perfect world, you could go further and retain the option to monitor the mic using the 3.5 mm port without ever connecting the USB headphone endpoint. (In other words: It would be cool to have XLR monitoring without creating a USB headphone connection.) I doubt this is possible without changing the hardware design, but having the MVX2U microcontroller turn off reporting the headphone jack as a possible audio sink? Doable. 

  2. According to LinkedIn, the employee signing off on Shure MOTIV stopped working there about a year ago. I think there are enough changes in the MVX2U vs other MOTIV mics that this is not so easy to add to the Android app. For instance, the firmware and DSP settings for older mics were sent in plain text, while the MVX2U sends an encrypted payload. The new mic seems like it does not use the "bootDSP c" command that older mics, like the MV7, use for starting a configuration connection. 

  3. It reminds me of InvenSense IMUs like the ICM-20948. Because they aren't contiguous, I wonder if these addresses are reserved internally for future designs or if these are used by the external ICs connected to the microcontroller. From taking apart the adapter, it looks like there is a codec or DSP IC made by Texas Instruments.