narenratan / mtsespy

Python bindings for ODDSound MTS-ESP
BSD Zero Clause License
2 stars 0 forks source link

mtsespy + tuneBfree on Raspberry Pi #1

Closed carlhenrikrolf closed 4 months ago

carlhenrikrolf commented 5 months ago

Hi, I'm trying to retune tuneBfree on a Raspberry Pi 4B running Raspberry Pi OS 64bit Bookworm (based on Debian). Despite going through the documentation for tuneBfree, mtsespy, and MTS-ESP, I'm uncertain how to make it work.

Setup: I have an MPE controller that sends the desired pitches as pitchbend messages over different channels (the MPE controller is a Yamaha Reface CP connected to a Blokas Midihub device that generates the pitch bends). The pitch bends represent the desired tuning. I have installed both mtsespy and tuneBfree. I have put the libMTS.so file at /usr/local/lib. I'm trying to set up a script to translate the MPE input into an MTS-ESP tuning to retune tuneBfree. Not sure it's the best approach, but I imagine I have to create a master client in mtsespy that takes the MPE input and translates it for MTS-ESP plugins.

What works: TuneBfree is installed and I can run the standalone command tool and get sound of it in normal tuning. Mtsespy is installed and imports correctly into Python3.

Problems: When tuneBfree is running and an mtsespy master is running, I still get 0 when I run mts.get_num_clients(). So, they don't seem to automatically connect. I've been unable to find more detailed documentation on how the system is meant to work, but I assume that the master plugin and the tuneBfree client should communicate through the libMTS.so file? Or do they need to communicate through a DAW somehow? Ideally, I would use the standalone plugins without a DAW. I have tried to use the Waveform DAW, but it doesn't recognise tuneBfree and I don't know how I would import a python script as a (master) plugin.

narenratan commented 4 months ago

Hi there, very sorry for my delay in getting back to you - thanks so much for trying out mtsespy and tuneBfree! I'll expand below but as a summary, what you're describing ought to be possible but may not be because of how I've currently handled MTS-ESP tuning changes in tuneBfree (sorry about that!).

Main question If I may ask, are you planning to use one fixed tuning for the whole piece you're playing - perhaps a tuning from a Scala scl file? If it's one fixed tuning for the whole piece, then if setting the tuning directly with MTS-ESP is an option (rather than converting the tuning from the Midihub), it would be possible to use tuneBfree. But if the tuning from the Midihub is changing dynamically, e.g. shifting between tunings across the whole piece or randomly changing, tuneBfree wouldn't currently work I'm afraid.

Details 1) The problem in tuneBfree is that currently notes are cut off after MTS-ESP tuning changes, so receiving tuning changes while playing music wouldn't work. I should say this is the wrong behaviour - dynamic tuning changes are one of the cool things about MTS-ESP! The reason tuneBfree currently behaves this way is because it builds a wavetable with the waves for each tonewheel/oscillator, and that table needs rebuilding every time the tuning changes (to contain notes with the new frequencies). Right now that's handled by reinitializing the tone generator (in the CLAP) or the whole plugin (in the LV2 and standalone), which cuts off any playing notes. I'd like to handle tuning changes properly but it might be a bit beyond my coding abilities at the moment. I'll add a limitations section describing this to the tuneBfree README.

2) On using mtsespy, I think the problem is that MTS-ESP on Raspberry Pi needs an ARM libMTS.so, and mtsespy needs a libMTS.so which supports IPC (this came up on discord). Right now the ipc branch of the mts-dylib-reference fork here can be used to build an ARM libMTS.so with IPC support; I made that branch to use mtsespy on a Raspberry Pi in fact! Based on this issue I've pushed some changes to mtsespy to check in the Master and Client context managers that libMTS.so exists where it's expected to and that it has IPC support. With these changes, at least mtsespy will throw an error with a message describing the problem if the shared object isn't set up as expected.

3) It's true that only libMTS.so is needed for an MTS-ESP client to get tunings from an MTS-ESP source; no DAW is required.

4) From what I could quickly find, I suspect Waveform doesn't support LV2 or CLAP plugins. It's possible to build a VST3 for tuneBfree using the CLAP wrapper; I'll add the commands to the tuneBfree README.

I'm always happy to help with mtsespy and tuneBfree stuff :) Thanks so much for trying them out!

carlhenrikrolf commented 4 months ago

Thank you! Now things seem to be working!

Dynamic tunings. Ideally, I would like dynamic updates to tunings, so I would be interested if anyone is making this work. However, restarting the tuneBfree plugin is acceptable. For reference, my setup is as follows: Each preset on Midihub corresponds to a different edo. I don't really wish to mix different edos, so restarting tuneBfree between presets should not be a problem. However, dynamic tunings would be useful within a preset. Take my 17edo preset as an example. I map the white keys to a maqam rast C scale. It can be retuned to a maqam ajam C scale (C major scale) by pushing the E and B keys on the bottom octave (they work as toggles and do not produce tones). Black keys in the bottom octave can also be used as toggles to get all the notes of 17edo. (This is similar to how a 'mini keyboard' on an oriental keyboard works. However such keyboards typically use 12edo + 12 microtones rather than something like 17edo). Here it would be nice to have dynamic tuning to do fast modulations and e.g. make 'chromatic' movements. A workaround could be to have the Midihub instead send keyboard mapping to the raspberry pi and have that change dynamically while 17edo is fixed? Not something I plan to implement at the moment though.

Minor error. When I first tried to use mtsespy, I tried to use it as a master for pianoteq. Pianoteq entered MTS mode but when I played a note it crashed. I proceeded with attempting to use Surge as a master (source) and then it worked without problems. When I tried to recreate the problem with mtsespy, there was no problem any longer. Mtsespy worked fine. I have been unable to recreate the initial error.

narenratan commented 4 months ago

Very happy to hear that things are working! If there's any trouble feel free to ping me on discord or github and I'll certainly try and help :) Thanks so much for the information on your setup too - it sounds fascinating and I imagine it produces some wonderful music! As it happens I'm going to the second night of a maqam festival tomorrow, really looking forward to it.

carlhenrikrolf commented 4 months ago

Hi again! I'm afraid the error I mentioned keep reappearing every time after boot. My current workaround is to run Surge as mts esp source then, stop running it as source, then start my python script using mtsespy. It works but is suboptimal. Here are some more details on the error:

Would you know what the problem is? Apart from this error it was very easy to make an mpe to mts esp conversion script with mtsespy and mido :) And how was the maqam festival? Haha, not sure how good it sounds, just a guitarist who thought retuning a digital keyboard would be easier than refretting a guitar. I have come to like 29edo though. Sounds smoother than 17edo or 24edo to my ears (and in some sense 29edo = 17edo union 24edo).

narenratan commented 4 months ago

Hey! Sorry to hear about the crashes - I think I roughly understand what's going on and I've pushed a new ipc2 branch to the mts-dylib-reference fork here to fix it. I could reproduce the crash (with tuneBfree) on x86_64 Linux; using the libMTS.so built with the new ipc2 branch I no longer get the crash.

It's a pretty interesting one! If I understand correctly, the mts-dylib-reference libMTS.so was initializing the MTS-ESP tuning table to 0.0. So if an MTS-ESP source registered but didn't set the tuning, any clients pulled 0.0Hz for every frequency. I would guess trying to play notes with all 0 frequency is a bit of an edge case for synths - very nice that Surge handles it!

Your workaround is super cool - I think it effectively uses Surge to initialize the MTS-ESP tuning table. I had a quick look in the Surge code and it looks like when Surge registers as an MTS-ESP source it immediately sets a default tuning.

In the ipc2 branch of that mts-dylib-reference fork I added some code to initialize the MTS-ESP tuning table to 12TET; I'll make an mts-dylib-reference PR with those changes. I've also pushed some mtsespy tests which test this behaviour (which fail with the ipc branch libMTS.so but pass with the ipc2 branch and the official libMTS.so).

Very glad to hear mtsespy worked nicely with mido! I love mido. Your script is just the sort of thing I was hoping mtsespy might be used for :)

The maqam festival was fantastic - beautiful music and a great atmosphere. I play a bit of guitar too, some 19EDO guitar and another similar tuning. I've never tried 29EDO - will try it out, many thanks for the tip!

carlhenrikrolf commented 4 months ago

Thank you! Works like a charm!