Let's Design and Build a (mostly) Digital Theremin!

Posted: 12/9/2017 2:24:30 PM

From: Northern NJ, USA

Joined: 2/17/2012

"it may be interesting that in the new soviet republic, in 1930s, the C0 was exactly 16 Hz." - ILYA

Fascinating!

Though, other than the C's, the other notes look to be kinda off?  For C1 = 32Hz to C2 = 64Hz I calculate:

32, 33.9028, 35.9188, 38.0546, 40.3175, 42.7149, 45.2548, 47.9458, 50.7968, 53.8174, 57.0175, 60.4080, 64

It's not just rounding going on in that image.

Posted: 12/9/2017 2:42:11 PM

From: Northern NJ, USA

Joined: 2/17/2012

Volume Side

Still mucking about with the volume side code.  I thought I could get away with a simple "inverse of the difference" equation for rough linearity, but it turns out that linearization of the hand response very near the plate antenna (something that happens a lot on the volume side) is highly dependent on having a fractional power here.  So I put that back in and the volume response is now markedly more linear.  The non-linearity was confounding all the thresholding and gain stuff I was trying out, so sailing may go a bit smoother now.

Knowing the above may simplify the pitch side linearity adjustment procedure to just "dialing out the pooping out" right at the antenna.

I may have speculated on this before, but I can't help but wonder if the reverse volume sense on the Theremin (farther = louder) was chosen to give a certain response shape to the volume field that couldn't be achieved (with the simple analog circuitry) if the sense was reversed?  I've tried playing with conventional volume sense and I pretty much loathe it, closer = louder is infinitely more intuitive for me.  I think this is one of the big reasons why I couldn't get into my EWS when I owned it, and why I never really worked with the volume side.  I also didn't think that a certain amount of non-linearity on the volume side would be a big deal, but it really can be.  You want everything as linear as possible it seems.

Volume control seems like an afterthought with many Theremin designs, but I'm finding that it's really important to get it right.

[EDIT] Worked all day on the volume side and have a basic approach working.  It's a copy of the pitch side all the way up to the logical NOT to change the directional sense - here it's optional via a parameter.  After that is a stage that has one of two gains depending on the input value, with the first gain 1, and the second gain 1 thru 255.  The threshold is the half-way point of the 32 bit range, which gives a gain break-point of 16 bits on the exponential side of things (this roughly corresponds to the dynamic range of the human ear).  After the (unsigned integer) exponentiation itself that's pretty much it.  Setup is pretty simple: 1) power-up auto-null generally doesn't need touch-up;  2) adjust overall gain to set the general playing height above the antenna; 3) adjust break-point gain to set operating zone height.  Steps 2 & 3 interact somewhat so there's a bit of back and forth.  Once it's set the way you like it it doesn't need changing later.  Setting the break-point gain super high gives a sharp on/off envelope.

A dual gain on the volume side is necessary to maintain a good playing height above the volume antenna, and have this be independent of operating zone (full on to full off) height.  Not having dual gain on a regular analog Theremin means you need something like a volume loop antenna geometry (or side plate like the Melodia) so as not to hit it with certain gestures and gain settings.  I don't want to get anywhere near the thing for fear of banging it during play, and won't have to with this arrangement.

Also worked on the menus some (all params are now 16 bits, with individual high & low limits), just need to manage the display of numbers a bit better on the LCD and then I can move on.  Still not sure if I'll go with hex or decimal displayed values, though I'll definitely go with signed values.

Posted: 12/12/2017 2:20:57 AM

From: Northern NJ, USA

Joined: 2/17/2012

Basic Functionality Achieved (come try it if you want)

Beavered away for the last couple of days on the menu system.  Now have 7 parameters per screen, with 4 screens (pitch, volume, tuner, mixer).  Screen numbers are now signed decimals over the interval -999 to +9999 (to make room for the negative sign). Implementing BCD (binary coded decimal) was pretty simple (bumper sticker: "ask me about algorithms") but right justifying it and sticking the negative sign immediately to the left of the value was a bit of a bear.  The BCD ASCII is stored to the string address presented to the subroutine.  The string copy, etc. subroutines now don't return a status flag, I found I was just tossing it out all the time.  Also got away from my CH4 data construct, where 4 ASCII chars are stored in a 32 bit number - I wasn't using it much, and strings aren't that much less efficient storage or operation wise, and are much more flexible from a screen formatting perspective.

Also wrote a low-res EXP2 subroutine that operates on UINT16 types.  Two poly terms give < +/-0.4% error max.  I'm using it to scale the static mixer volume numbers.  Not sure what I think of the gain control it gives, linear might be better on the low end.

Next up on the agenda is a mixer noise source, alias amelioration, HPF on the volume for attack, and vocal sim.  But the basics of prototype are implemented and fully functional, should anyone want to visit casa del dewster here in beautiful Boonton, NJ and give it a spin.  Come for the ruler-flat linearity, stay for the tuner!

My excuse for not learning to play the Theremin is gone :-(

Posted: 12/12/2017 9:35:35 PM

From: Northern NJ, USA

Joined: 2/17/2012

Gobs of DSP algorithms here: http://www.musicdsp.org/showmany.php

Posted: 12/13/2017 3:25:17 AM

Joined: 12/13/2017

dewster

Your passion for this project is infectious. I registered just to participate in this project.

Posted: 12/13/2017 6:06:25 PM

From: Northern NJ, USA

Joined: 2/17/2012

"Your passion for this project is infectious. I registered just to participate in this project."  - yldouright

Thanks!  I'm having trouble sleeping with the project hitting so hard and finally coming together.  Lots of fascinating little puzzles to work through and solve.  This thread seems to get hundreds of views per day, which is encouraging, but it's always nice to get more direct feedback.

What is your musical / electronics / programming background?

=========

The note display seems fine now, but I find I'm not paying any attention at all to the octave display on the tuner. I think it's too large, and could benefit from a readability standpoint by being constructed from segments rather than round LEDs.  So yesterday I ordered a couple of 1" red common anode 7-segment displays from China (eBay) which will no doubt get here after xmas due to the flurry of shipping going on (this time of year I hate ordering anything / going anywhere - bah, humbug!).  I kinda wanted green here, but all the larger ones seem to have two LEDs in series per segment - since these are powered from the USB 5V supply it can't tolerate that much forward voltage drop (it can barely do 2 reds in series @ 5V).

Since the LED drivers have 4 outputs left over (13 for the notes + 7 for the octaves = 20;  3 drivers * 8 outputs = 24;  24 - 20 = 4) I'm going to add a 4 LED volume side thermometer display when the 7-segment displays arrive.  This should really help "tune" the volume side thresholding.  (And maybe help the display appear less "Star Trek"-ish.)

Yesterday I implemented a 32 bit LFSR noise source and piped the output over to the mixer.  I sounds like white noise, but I wonder if aliasing could be an issue with it? Also took another look at the modified Chamberlin state-variable filter - have it coded up but not yet parameter scaled nor tested.  A straight sine wave sounds remarkably like whistling, but I'm hoping a resonant filter with dynamic Q control might be even more realistic.  I want to get as far away from tired old conventional analog synthesis as fast as possible.

Also, the last two rotary encoders I added were from Adafruit.  They're more expensive, and at first glance seem to be of higher quality than the Chinese ones I paid almost nothing for, but I'm finding they're fairly inconsistent in operation (movement doesn't always register).  Glad I didn't buy a bunch of them!  The Chinese ones work quite well, though who knows how long they'll last.

Posted: 12/15/2017 3:43:50 PM

From: Northern NJ, USA

Joined: 2/17/2012

Internal Scaling

One issue that seems to be resolving itself is the scaling of numbers in the Theremin software.  This is something that felt fairly arbitrary in my first all hardware prototype.  The difference is that the first prototype operated in the exponential domain, and this latest one operates in the linear domain.

In a conventional analog Theremin, a fixed high frequency and a variable high frequency are subtracted (via non-linear mixing and some form of low pass filtering) and the resulting pitch spacing in the mid field sounds linear to our ears, which requires exponential spacing to sound linear, so the entire process leading up to our ears is exponential.  If one instead measures the variable high frequency to get a value (voltage or number), one can subtract this value from a bit larger constant, feed the result to a linear response (voltage or numerically controlled) oscillator, and achieve basically the same thing because in both cases we are subtracting frequency - the first in the time domain, and the second in the value domain.  So this particular value approach (or process) is also exponential all the way to our ears.  Heterodyning and other approaches which employ frequency difference directly will all give you the same qualitative hand / pitch response.

There are many reasons not to go the exponential processing route.  For one thing you get basic pitch field linearity that is identical to that of an analog Theremin, which isn't terrible (it's entirely playable) but cramps up near the antenna, and the notes have a fixed rather cramped pitch (~1 octave with open / closed hand) even in the linear mid-field zone.  Fixing the mid-field note cramping is just a matter of taking some root of the numbers (e.g. square root will double the inter-note distance).  But fixing the near-field cramping in the exponential domain is a pain, it's a pain even coming up with an algorithm to do it.

If you instead take the frequency difference and raise it to a fractional negative power (somewhere around -0.5 to -0.25, probably depending on the antenna geometry) the resulting numbers are remarkably linear with hand distance, and so must be fed to an exponential response oscillator in order for the note spacing to sound linear to our ears.  In fact, it sounds linear all the way up to the antenna, which is fantastic.  And there is only one "knob" necessary to adjust this linearity, which is doubly fantastic.  And the adjustment is simple and non-critical, which is triply fantastic.  And offsetting and scaling the pitch, as well as measuring and displaying it on a tuner, are all that much easier in the linear numeric domain (simple add, subtract, multiply, with no powers or roots needed).  It's win-win-win-win (win turtles all the way down).

What I didn't expect was for the linear / exponential "border crossing" at the input to the NCO (numerically controlled oscillator) to naturally set the basic gain of the processes leading to it, which is also pretty nice as it resolves things that were being arbitrarily set.  The best analogy here is an analog synthesizer, where the oscillators and filters convert linear voltages to exponential pitches, and the input standard here is usually 1V per octave.  The numeric approach has a natural gain based on the input format of the unsigned integer EXP2 function which feeds the NCO, which is a 32 bit 5.27 fixed decimal.  The upper 5 bits set the octave, the lower 27 bits set the octave fraction, and full scale change on the linear side (0 to 2^32 - 1) gives full scale change on the exponential side.  (The 5.27 format is used internally by the EXP2 subroutine, where the lower 27 are fed to the polynomial, and upper 5 shift the polynomial result; for a full shift over the 32 bit field the shift distance needs log2(32) = 5 bits).

So the unsigned 5.27 format is used for control throughout, for the pitch processing, for the tuner input, for the volume breakpoint processing, etc.

For processing 16 bit numbers (audio samples, volume settings, etc.), a 4.12 format seems in order (though perhaps implemented as 4.24 with the lower 16 output bits ignored).  I'm currently working on subroutines that require fewer cycles at this reduced precision / resolution (fewer polynomial terms), one in particular is the sin(x*pi) needed to correct the modified Chamberlin state-variable filter tuning.  Yesterday I finished a SIN2 subroutine that gives a maximum error of +/- 3 over 16 bits, which takes ~1/2 the time of the 32 bit version, and should be sufficient (spectrally pure enough) for audio generation and processing, particularly if it is attenuated at all.  Sine is a slightly better choice here than cosine, as the polynomial gives somewhat less error for the same number of terms (though for 32 bit high precision it's a wash as you hit a wall of diminishing returns given the same required number of terms either way).

Posted: 12/15/2017 8:38:43 PM

From: Germany (Black Forest)

Joined: 11/25/2017

Posted: 12/15/2017 8:48:51 PM

From: Northern NJ, USA

Joined: 2/17/2012

Gerd!  You did it, man!

Posted: 12/15/2017 11:33:15 PM

From: 60 Miles North of San Diego, CA

Joined: 10/1/2014