Dynamics now work! I'm using the breath velocity value from the cardboard breath sensor to set the MIDI breath controller value, and mapping that to volume in the synth. I'm sure there's a much more complex and nice-sounding config that can be done, but this is cool!
It needs to be a bit more linear, but that just means making some sort of calibration curve for the sensor. That can wait until I've got the 3D printed one working.
I've put the code up on https://gitlab.com/gbrnt/electro-sax
There's currently a latency problem - I need to check whether it's on the Arduino end or on the computer end. The breath sensor has some extra latency - I think that comes from the current prototype but I'm not entirely sure.
The end-to-end latency of the electro-sax is definitely too high right now. It's recommended to get it below 10ms (if you can) and here it is at 160ms.
That's enough that when you're doing something like a run of short notes you do one too many because the sound hasn't caught up yet.
Let's see how much I can improve this just by changing Jack settings. Not sure how Pipewire comes into this.
So far in my attempts to improve the sensitivity of my breath sensor, I've managed to make it worse.
The first cardboard prototype had a range of 0.38V, or 77 counts in an Arduino's 10-bit ADC. Ideally it'd be more than 127 for a completely step-free MIDI reading.
The 3D printed prototype got me 18 with the nitrile glove membrane, or 31 with a white balloon. Not great. Hopefully the sensor I designed it for will arrive tomorrow and I'll be able to try it out.
Hmm, not doing great with the BMP280 pressure sensor. It works really nicely for detecting a change in pressure, but it doesn't seem to be very good at going back to its original zero point.
So in the screenshot you can see the lows are at different points each time I stop blowing. I assume it's doing something clever, but whatever it is it makes it less useful to me.
The best breath sensor I've built is still the original LDR-based one, with a difference between "not blowing" and "blowing hard" of 77 counts.
I could tell that its response was slow, though. So now I've measured it!
Going from LED off to on, the response time is 30ms. From on to off it's 100ms. Luckily that's the ok way round, and normally it won't be varying by so much.
I'd like it to be faster but it's probably an ok solution for now.
Time for a slightly more scientific test of the TCRT5000 based solution. This is the reflective IR sensor with an IR LED and phototransistor.
So far it looks like I can make this good enough by correctly setting the distance between balloon and sensor, and the LED brightness.
I might also test the effect of changing the (current limiting?) resistor next to the transistor, because I've never really got my head round transistors.
It looks like I found the sweet spot for this sensor. With this setup it's 14-16mm from the membrane. My measurement of the distance is bad so I'll still need some adjustability.
I found it was best to set the current-limiting resistor for the LED so that the "non-blowing" voltage was about 4V - maximising the sensitivity.
Not sure why the distances needed in the datasheet are shorter than mine - they're using a mirror to reflect the beam so I'd expect it to be longer.
The electro-sax now has transposing! You press a key combination to activate transpose mode, and then play the key you want to transpose to. So if I want to play alto sax music in the right key, I play Eb and then press the octave key to lock it in. It seems to work well!
It needs a few octave keys so it can play in the correct octave, but that's fine for now - an octave off is still better than attempting to tranpose in my head.
Look mum, I did a science!
This is using the new sensor distance tester. It made it so much easier to do this experiment properly.
It looks like my previous conclusion was about right - 13-15mm between sensor base and membrane is about the right distance.
The good news is that with that distance, I get a range of ~270 ADC counts between "not blowing" and "blowing as hard as possible". That's great - it can easily be mapped into MIDI's 127 breath velocity values.
I tried switching back to Pulseaudio (from Pipewire) to see if that would reduce the MIDI/audio latency I'm seeing with the electro-sax. Haven't measured it yet but it doesn't seem like it made much of a difference.
Hopefully that's an indication that it's not on the (complicated) audio side and instead on the (slightly simpler) MIDI side. Better not be something fucky with USB.
Just to compare audio latency, I'm trying out a live USB of Ubuntu Studio. It looks like without doing anything, that cuts my latency from 150ms to 93ms. And changing my headphones to my front panel output instead of my USB DAC cuts it further to 24ms.
That's still not amazing, but it's a world of difference from being unable to play properly.
Some more progress on the updated breath sensor. It's still quite bulky, but at least with the longer mouthpiece I won't be bumping my nose into it!
Will try this for a while before deciding whether it needs a fake reed - the positioning of the air inlet might be enough to make it feel close enough to a real sax.
There's something weird going on with the new sensor - when blowing gently the reading from the sensor actually goes down!
Here's a graph of the readings as I gradually increase from not blowing to full speed. It dips down at the start. That's not good!
I'm guessing it's because I added a slight "bypass" between inlet and outlet, and the flowing air has a lower pressure that actually pulls the balloon towards it.
I spent a bunch of today trying out different combinations of software and hardware to figure out the best latency I can get.
I'm really not sure how to present the info so here's a table. It looks like I can get latency as low on Arch as I can on Ubuntu Studio (without tweaking Jack). The lowest latency synth is Yoshimi, but Qsynth is good. Pulseaudio seems to be lower latency than Pipewire.
I suspect a good chunk of the remaining latency could be on the Arduino side, so I'll have to measure that next.
New electro-sax breath sensor is attached. It looks pretty good but unfortunately it's kinda bad :(
It has the thing where if you start blowing suddenly the note is really quiet. I'm really not sure why. Got to figure out the actual cause.
The feel of the mouthpiece is good, but I need to be able to twist it to an angle for it to feel right. Aligned with the sax means I need to twist my head.
Maybe this is the cause - the response is really non-linear. It jumps very slightly above the 0 point, then sits level as I keep blowing more, then suddenly jumps up before increasing linearly.
The other graph is me playing a piece - it looks alright to be honest, so maybe it's not the non-linearity, it's something in my program?
A bit more playing around with touch sensing on the Teensy. It's a little stripboard keyboard which can only play a C arpeggio! It only uses one touch sensing pin along with a 4067 analog multiplexer to get 16 touch inputs.
That's enough for all the keys currently on the electro-sax, plus two more octave keys and... I dunno, two more to do something.
It didn't take long to build a touch-sensitive version of the electro-sax! This is definitely nicer to build than soldering a key matrix with diodes, but the analog sensors aren't quite as nice to deal with on the code side.
The key thing is that it works! I'm not actually sure whether I prefer the buttons or the capacitive sensors. I need to tweak the sensor calibration a bit before I'll be able to tell.
@fortifieduniverse Thanks! It's not a clear upgrade so I might go back to switches, but it could just be a matter of getting used to it.
@gbrnt Indeed. Love watching you iterate, though. Cool stuff.
Thinking about building my own keyboard controller someday... like mill all the keys from hardwood and build my own keybed and such. We'll see. Have a lot of stuff I need to build before that.
@fortifieduniverse This little macro-pad's wooden keys are quite neat! https://hackaday.io/project/179512-custom-wooden-mechanical-keyboard
Looks like they used laser cut layers and sanded them to shape. Routing would probably be an improvement.
@gbrnt The pressure sensitivity was also one of the first things I wondered about when I started thinking about this.
According to my naive current understanding, most inexpensive controllers actually have 2 activation switches that activate at different points in the keypress... the timing between the two activations is tracked to get velocity.
Not sure about aftertouch. I'm sure it can be figured out. Pressure sensitive resistor strips and such, maybe?
@fortifieduniverse That does make sense as a cheap way of sensing the speed! Pressure sensitive resistors definitely sounds like an expensive way to do aftertouch though!
@gbrnt It'll be fun to figure out what the right approaches are. If it ends up being expensive... well, building one's one keyboard controller from scratch is already kind of an expensive proposition, compared to just buying a plastic piece-of-crap on the internet. 😜
@fortifieduniverse It looks like for per-channel aftertouch it's common to use one long force sensitive resistor. Not sure if FSRs are still what they use for per-key versions though.
@gbrnt Makes sense. Will also have to look into what the new MIDI spec supports, to make sure the controller can support all the things.
This Mastodon instance is for people interested in technology. Discussions aren't limited to technology, because tech folks shouldn't be limited to technology either!