michaelforney / oscmix

Mixer for RME Fireface UCX II
Other
26 stars 5 forks source link

Babyface Pro support #9

Open Be-ing opened 9 months ago

Be-ing commented 9 months ago

Hi, I am excited to see this application! I tried reverse engineering my Babyface Pro a few years ago to build a similar application but got stuck, so I'm wondering how you have reverse engineered the MIDI protocol.

I started by running TotalMix FX in a Windows VM and intercepting the USB traffic on the Linux host with Wireshark. I was able to get fairly far with that using the USB control transfer messages that TotalMix FX uses with the Windows driver, which also worked in class compliant mode on Linux. Unfortunately, I hit a wall because the EQ and low cut controls communicate with a USB endpoint that doesn't exist in class compliant mode. :dizzy_face: RME told me that TotalMix FX on iOS uses MIDI to control every feature of the Babyface Pro. I got an old iPad to try reverse engineering that, and I was able to find iOS applications that showed incoming MIDI data, but I got stuck because I couldn't figure out how to monitor outgoing MIDI data.

So I'm wondering if you could point me towards a process for reverse engineering so I can help add Babyface Pro support.

huddx01 commented 9 months ago

I got an old iPad to try reverse engineering that, and I was able to find iOS applications that showed incoming MIDI data, but I got stuck because I couldn't figure out how to monitor outgoing MIDI data.

We had exactly the same problem. I could capture the Input from the Unit to iPad but not what is going out from the app to the Unit. See here: 4#issuecomment-1955388840

I am still investigating how coremidi works in iOS - my suspect (not prooved until now) is: Usual MIDI Apps offer an IAC- (also known as virtual) MIDI - Port for communicating via the MIDI Framework. TotalmixFX on iPad seems either to send directly to the Unit's port (without creating a virtual port) or it sends "raw" via the HID-USB Interface (=Camera Kit Adapter).

So I'm wondering if you could point me towards a process for reverse engineering so I can help add Babyface Pro support.

The easiest way would be if you have a Linux system with a UDC. And capturing via gadget.

Described in the wiki, in the capture section.

@michaelforney also describes the background here: 4#issuecomment-1955236042

michaelforney commented 9 months ago

Hi, I am excited to see this application! I tried reverse engineering my Babyface Pro a few years ago to build a similar application but got stuck, so I'm wondering how you have reverse engineered the MIDI protocol.

Wow, it seems you had pretty much the exact same idea for design as I ended up using!

I started by running TotalMix FX in a Windows VM and intercepting the USB traffic on the Linux host with Wireshark. I was able to get fairly far with that using the USB control transfer messages that TotalMix FX uses with the Windows driver, which also worked in class compliant mode on Linux. Unfortunately, I hit a wall because the EQ and low cut controls communicate with a USB endpoint that doesn't exist in class compliant mode. 😵 RME told me that TotalMix FX on iOS uses MIDI to control every feature of the Babyface Pro. I got an old iPad to try reverse engineering that, and I was able to find iOS applications that showed incoming MIDI data, but I got stuck because I couldn't figure out how to monitor outgoing MIDI data.

I'm not sure if you're interested in the whole story or not, but I think it's somewhat interesting and it seems like you went through a similar process, so I'll tell it anyway:

I started the same as you did: with TotalMix FX in a Windows VM and wireshark on Linux. At first I was overwhelmed by all the data going back and forth, but when I filtered just the data from TotalMix to the device, I was able to see some byte patterns change when I moved some sliders. This was happening on bulk endpoint 12, so I focused in on that, and gradually filtered out stuff that was getting sent in a steady state. Eventually I figured out that most controls resulted in a 4 byte value being sent, where the lowest 2 bytes were the value, and the upper two bytes were the thing I was controlling. The highest bit seemed to change arbitrarily, but was always consistent when a particular control was set to a particular value. With a little analysis I determined that it was a parity bit.

From here, I started mapping out addresses and values by changing every control in TotalMix and seeing what it sent. Some things were easy, some were much more difficult (see the volume, panning, and EQ formulas in https://github.com/michaelforney/oscmix/wiki/Protocol#mixer-volume-formulas), and some controls changed multiple registers at once. I figured that even if I couldn't get it to work in CC-mode, I might be able to control the device in USB-mode through the bulk endpoint, and use SPDIF to connect my computer to the interface.

I wasn't sure how this all worked in CC-mode, but I knew it must be possible since the iPad could do it. Then I had the idea of using some sort of proxy in between the iPad and the interface, since I knew Linux had support for acting as a USB device. But it turns out you need special hardware that has a UDC in order to do this. I had a raspberry pi, but it was an older one that had no UDC. I also had no iPad. But after asking around, I found that one of my friends had both and lent them to me.

Looking around for how to make linux proxy a USB device, I found the recently added raw-gadget kernel driver and https://github.com/AristoChen/usb-proxy. However, I wasn't able to get that program to work, so I ended up writing my own proxy program (https://gist.github.com/michaelforney/36f78621b79d6caaaf64be7416a8dec2). I then used tshark on the raspberry pi, piping it to wireshark on my desktop, and saw it sending MIDI packets back and forth.

I was pretty familiar with this, since just before this project I had managed to reverse engineer the software for a cheap looper pedal I had gotten (http://www.cuvave.com/productinfo/168785.html), which also used MIDI. I also had some background with USB audio, since I had added support for USB audio 2.0 to 9front a few years back. The official software for the looper had a symbol table, and I was able to find a function called something like LoadSongInfo and step through the assembly and watch as it constructed a packet. It then did a final encoding step before sending it off so it would be a valid SysEx packet, where bytes can only range from 0-127. It did this by essentially encoding the whole packet as base 128 (https://gist.github.com/michaelforney/d3a2790bb5f8cbcb1c931eabb50b5f20).

I figured this would be a good place to start, so I tried the same encoding technique, and I knew I was close when I saw 3E0467CD from TotalMix, which I had in my notes as "? sent at startup". The subsequent data didn't make sense, but I saw that every 5th byte had only the lowest 4 bits set. So I tried decoding each 5 byte chunk separately, and this turned out to be the correct encoding scheme.

From here, I went through that same process as before, changing all the controls on the iPad, and it seemed that my register map from before was still mostly correct except for a few minor differences. I eventually learned that whenever you change the value of 3F00, the device sends you back new registers that have changed. I also learned that when you send 3E04 67CD, the device begins to dump all its registers, and I used this to fill in some gaps in my map. I noticed that the organization of the map was almost identical to the device's UI (with the LCD and rotary encoder), which helped a lot, and the device would send data when I changed a setting from the device.

It turned out that you don't need a full USB proxy to get TotalMix on the iPad to recognize the raspberry pi as a device, and Linux's MIDI gadget was sufficient if I created a MIDI function with two ports, set the product name and device IDs (https://docs.kernel.org/usb/gadget-testing.html#testing-the-midi-function). Then, I could just make a bidirectional link between the gadget ports and the actual device ports with aconnect.

I slowly worked through all the unknowns and mysteries from my notes, until I had nearly everything figured out. I reached out to MC on the RME forum asking if was ok to share my project and with a few final questions about some bits I still didn't understand. He forwarded me to Ralf, who replied with some very helpful info about the low cut filter and DSP overload handling.

So I'm wondering if you could point me towards a process for reverse engineering so I can help add Babyface Pro support.

As @huddx01 mentioned, there are some capture docs at https://github.com/michaelforney/oscmix/wiki/Capture.

I also recently wrote tools/regtool can help you encode/decode SysEx messages in the appropriate format. You can connect it to your device's MIDI port to monitor what its sending, or your MIDI gadget to see what TotalMix is sending. You can also use the -w flag to send data in the correct format. Reading https://github.com/michaelforney/oscmix/wiki/Protocol should be helpful, I expect that the babyface has a lot of similarities.

I've also found that you don't actually need the physical interface to get TotalMix to recognize the rpi as it. I've been asking people for a capture of the steady state of the device while they send 3F00 to cycling values 0000-000F. It is enough to play back this capture to the iPad through the MIDI gadget, and then it shows as connected in TotalMix and I can see what each control sends. If you don't have a raspberry pi, you could follow https://github.com/michaelforney/oscmix/issues/5#issuecomment-1960265780, and I'll see what I can do.

Be-ing commented 9 months ago

Awesome! I'm glad you figured out a way to do this without expensive USB analyzer hardware!

michaelforney commented 9 months ago

Had a brief look at MIDI traffic between the iPad and a MIDI gadget Babyface Pro (XXXXXXXX). It didn't seem very similar to the other devices I looked at.

I attached a log (first column is timestamp), as well as a MIDI capture of TotalMix trying to connect to the gadget. You could try playing it back to your device and see if it outputs anything interesting.

bbfpro.log bbfpro.mid

stistrup commented 4 months ago

Very nice work and applause for all the reverse engineering.

And i've been down a rabbit hole since i decided to switch to linux a few months ago. Ended up first trying to make a GUI for my babyface by doing a tauri app partly to get more comfortable with rust, and since i already do frontend development for work i thought it could be a fun project. Realized that there was no way to control gain. Ended up writing a kernel patch to add gain control that i got working. But found new missing features and eventually found this project and thought that this would be perfect for my needs. So if theres anything i can do to help with the support of the babyface i'd be very happy to help.

Also heres the tauri app thing (very unpolished) and the patch if you're curious:

https://github.com/stistrup/rme-control-gui https://github.com/stistrup/rme-gain-kernel-patch

stistrup commented 4 months ago

That whole midi bit went a bit over my head but maybe i can have a look at that. I have a few RPI4s at home

huddx01 commented 4 months ago

Hi, i just did a first overlook around your gui and the patch. Awesome! But i'd have to look a little deeper, to understand everything. I also never used tauri/vue/etc...

What do you mean with the midi bit exactly? The protocol in michaels wiki? Maybe i can help a little out...

stistrup commented 4 months ago

The midi bit was refering to michaels comment above, using an RPI to sniff MIDI, if i understood it right..

And the tauri app, it's basically just a way of setting alsa paramaters in a gui. I also used pipewire to set buffer size and audio profile. Thats basically it as of right now. Got sidetracked when i realized there was no gain.

And the whole structure of setting configs on the vue side is needlessly complex and a bit weirdly done so don't pay too much attention to that ^^. I will go over that when i've managed to get more Babyface features and paramaters available

huddx01 commented 4 months ago

Yeah, basically to sniff midi sysexes between the unit (in CC-Mode) and the iPad App. RPI4 can be set up as a USB Gadget - see in the wiki: capture

stistrup commented 4 months ago

Diddn't really understand if i needed an ipad or not?

huddx01 commented 4 months ago

Maybe it would be easier to talk if you can join the irc chat? As mentioned in Michaels readme: There is an IRC channel #oscmix on irc.libera.chat.

stistrup commented 4 months ago

Aaah nice! I'll do that. Thanks. Sorry for not reading all the readmes and wikis properly..

huddx01 commented 4 months ago

np... i just logged in... should i wait for you? or anther day?

Be-ing commented 4 months ago

You do need an iPad to run the TotalMix FX iPad application which communicates with the audio interfaces via MIDI. You can get any cheap used iPad from eBay or wherever.

stistrup commented 4 months ago

Trying to figure out irc as i've never used it.. I think i connected to irc.libera.chat but cant find the #oscmix channel

EDIT: Found it

FancyEnigma commented 2 months ago

Had a brief look at MIDI traffic between the iPad and a MIDI gadget Babyface Pro (XXXXXXXX). It didn't seem very similar to the other devices I looked at.

I attached a log (first column is timestamp), as well as a MIDI capture of TotalMix trying to connect to the gadget. You could try playing it back to your device and see if it outputs anything interesting.

bbfpro.log bbfpro.mid

I've played the midi file back to the device and it replied with a bunch of stuff, as well as setting my monitors to +0db a couple of times. I however don't have an iPad or the app to test. I'd really like to have the EQ working on the device thats the only thing I crave from TotalMix I briefly tested on my Macbook. I've been using Debian as a daily driver for over ten years, I can't see myself using macOS for a damn audio driver. If you point me in the right direction I'd have no problem adding support to oscmix if it is any similar to the simple MIDI registers being set as in the UCX II for the three band EQ.

In addition to that, it also routes the input channels to the main out and dim and phantom power cant be enabled on the device anymore.

Here is the output I got from playing back bbfpro.mid: regtool.log

Cheers!