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

Posted: 10/13/2019 1:15:36 PM

From: Northern NJ, USA

Joined: 2/17/2012

Decoupled Coupling

It occurs to me that the mechanism which increases the harmonic content of the bass end of analog Theremins is highly similar to the method I use on the D-Lev to produce harmonics in a more general way: phase modulation. 

When analog Theremins "couple" (to make little Theremins ), the fixed oscillator "pulls" at the phase of the variable oscillator (and possibly vice versa) which skew-distorts the waveform to give higher harmonics. 

On the D-Lev, a sine wave oscillator phase modulates a second sine wave oscillator, and they are both fed integer multiples of the control frequency value so it doesn't sound like ring modulation.  Using the pmod and vmod knobs I can have this "coupling" be zero (sine wave), get stronger at the near or far end of the pitch field, be constant, vary directly or oppositely the volume, etc. - all the while limiting the maximum coupling strength (via polynomial) to prevent audible aliasing.  And since there are two sine wave oscillators per oscillator it can also do odd harmonic sounds like square waves.  It's a quite powerful approach (and highly amenable to digital implementation) when broken down into basic blocks and reassembled in a controlled manner.

The simplest implementation of the D-Lev type phase modulation is a sine wave oscillator modulating itself, and I believe this is analogous to analog Theremin type coupling.

On an analog Theremin I imagine that you are probably better off eliminating coupling (to make the bass end more playable) and using rectification and other means to shape the waveform in order to provide harmonic content.

Posted: 10/14/2019 6:38:56 PM

From: Porto, Portugal

Joined: 3/16/2017

The simplest implementation of the D-Lev type phase modulation is a sine wave oscillator modulating itself, and I believe this is analogous to analog Theremin type coupling.

What is a waveform for sine modulating itself?

Does it make sense to summarize several pairs of oscillators? E.g.    a1 sin(f0 b1 x + c1 sin(f0 d1 x) ) + a2 sin(f0 b2 x + c2 sin(f0 d2 x) ) + ...

What if divider is used instead of multiplier for modulating sine?

BTW, phase modulation with lower frequency could produce a kind of vibrato or tremolo.

Posted: 10/14/2019 7:56:35 PM

From: Northern NJ, USA

Joined: 2/17/2012

"What is a waveform for sine modulating itself?"

Digitally, a delay allows you to do this (makes it "causal").  You can play with my spreadsheet here: [LINK]

"Does it make sense to summarize several pairs of oscillators? E.g.    a1 sin(f0 b1 x + c1 sin(f0 d1 x) ) + a2 sin(f0 b2 x + c2 sin(f0 d2 x) ) + ..."

Yes, I'm summing 3 PM sine oscillators on the D-Lev.

"What if divider is used instead of multiplier for modulating sine?"

I think pitch would probably sound like the lowest frequency in the bunch?

(And with this, I find the free version of WPS Office Spreadsheet doesn't support VBA, nor does WPS Writer support mail merge - gaa!  Time to get away from all MS Office-based products.)

Posted: 10/16/2019 6:57:07 PM

From: Germany

Joined: 8/30/2014

I haven't seen the post which now disappeared (only seen it announced via mail).
But the part about "very large font" does not have to be the fault of the person who posted that... I know from first hand, this editor really likes to randomly make fonts big without you clicking anything, let alone insert code for it yourself.
The only remedy seems to be to hit the rightmost button on the editor with the smaller/greater symbols, and delete any opening (and corresponding closing) tags with "font=something" ... (or edit in some off-site text editor and paste here without changing)

Posted: 10/16/2019 7:52:22 PM

From: Northern NJ, USA

Joined: 2/17/2012

I think it was just a run-of-the-mill hit-and-run spammer (which I flagged the post as) but who knows.

Posted: 10/20/2019 7:12:05 PM

From: Northern NJ, USA

Joined: 2/17/2012

Doing What I Was Told Not To Do

Turns out ncurses isn't POSIX, so it isn't portable to MSWindows.  And it's "all or nothing" when it comes to taking over both your keyboard and screen in the console.  Simple stuff which took a long time for me to discover and therefore know that it's not a good fit for my Hive processor simulator.  I just need a couple of simple keyboard handling functions (kbhit() and getch() in the Win world) and can handle the screen myself.  If I'm taking the time to learn ncurses (which is ancient and clunky) I might as well be learning real GUI design.

Turns out the Linux / Unix / etc. console is highly "line oriented" in that keyboard events need a hard return at the end for the console to recognize them as input.  There's no way that I know of to "peek inside" the keyboard buffer before the hard return is entered.  Best I've been able to do here is find a function that lets you know how many bytes are in the buffer, which in the end wasn't useful.  There should be C++ functions that let you peek, count, flush, etc. the keyboard buffer, but no, they don't want you doing that. 

I tried a ton of stuff and believe I finally have a "not recommended" solution.  If you put the keyboard in "canonical" mode with echo turned off, no inter-character maximum delay time, and no minimum byte count, you can poll the keyboard buffer via getchar().  If -1 is returned then the buffer is empty.  So you put getchar() in a loop and reads the bytes out one at a time until -1 is returned.  Polling until a character is entered can peg your CPU, so inserting a delay of 1ms in the polling loop brings the usage down to just a couple of percent without significantly impacting response time.  It's uglier that I would like, but it works and nothing else I've found does.  Reverse engineering is the worst kind of engineering.

Single keypresses (e.g. CTRL-F12) can return up to 7 bytes (e.g. 1b 5b 32 34 3b 35 7e).  When concatenated big-endian this conveniently fits in a uint64_t, giving us a single "key code" association.  Pressing two or more keys at once sometimes confuses things, I assume due to some unspecified maximum inter-byte timing.  Ah well, I'm not making an interactive game here.

There are literally tons of people on the web asking for help with exactly this, and all of the answers are poor ("why would you want to do that?", "use ncurses", "don't do that!", "here's some code that doesn't work the way you want") or a fob off.  Accomplishing this in MSwin is an absolute no-brainer.

Anyway, I've got the keyboard buffer code running in a toy environment and will shortly integrate it into the sim.  I'm using ANSI escape commands to paint the text on the screen. 

What I'd like is something that would auto-generate C++ header files (*.h) from my source code (*.cpp).  The various IDEs I've got don't seem to have this capability, which seems like a glaring lack?  No help on the web, kind of surprising.

Posted: 10/20/2019 7:42:40 PM

From: Portland, Oregon

Joined: 2/22/2018

Ncurses with cygwin could be a possibility? 

Posted: 10/20/2019 7:57:32 PM

From: Northern NJ, USA

Joined: 2/17/2012

Cygwin is a possibility - thanks!  Though I've got the functionality modularized sufficiently for build switches to work easily. 

Ncurses is a no-go as it takes over the screen as well as the keyboard.  It's really ancient, and I couldn't get most of the examples to work.

I guess we're just not far enough away from TTY I/O, the detritus of which gums up the lower layers of Linux. 

Someone should make a cross-platform console that paints easily with text, has widgets and stuff, and gives you basic keyboard and mouse control.

Posted: 10/23/2019 7:31:38 PM

From: Northern NJ, USA

Joined: 2/17/2012

Hive Sim In POSIX

Finally got the Hive sim compiling and running OK on Ubuntu.  Here's a screen grab of the console:

Got hung up for over a day on a segmentation fault that happened whenever I pressed one of the function keys, arrow keys, or other control keys.  Said it was core dumping, but no core files could be found.  Turns out you have to enable that, then redirect the core file generation, then examine them with tools that don't tell you much.  Ended up just commenting stuff out until it didn't blow out, the culprit it seems was the C++ function isspace() being fed a 64 bit value.  I replaced it with my own functions and it seems to be fine now.  The C++ build process feels rather fragile and dependent on resources scattered all around.  I miss the days of small-ish compilers and IDEs bundled together. 

Also looked at using *.h files for this project, but decided against it yet again.  Header and make files are completely opaque to me.  I can see why more casual coders embrace newer languages like Python, where most of the evil legacy fleas have been shaken off, at least for a while.  The thing that g++ spits out is an object file that I have to run via ./hive_sim, for some reason the nautilus browser doesn't see this as an executable(?), so I can't just double click it to run it.

Anyway, the console sim display seems pretty snappy, which was something that was potentially worrying.  And I timed all 8 cores doing the verify thing for 1,000,000 cycles (8,000,000 core clocks) at about 110 seconds, which is 8,000,000/110 = 73kHz.  Since the core runs at 180MHz, this is a slowdown of around 2,500, which ain't too bad as these things go.

I also added a fifo to the keyboard buffer interface, so it's a lot harder to miss key presses or get bad codes out of it.  The multi-byte key code decoding is pretty simplistic, it could be made foolproof with more work (which I would do if I were writing an FPS) but it's more than fine for this project.  I'm thinking of taking a crack at a console-based scientific / programmer / tape calculator.

Posted: 10/23/2019 8:41:52 PM

From: Germany

Joined: 8/30/2014

The executable probably doesn't start out of the file browser since it's not a GUI based program and isn't kind enough to open a terminal emulator with a shell to also display the things you'd like to see.
If your program runs long enough to verify this, try a program like htop (might even be installed already) in a dedicated terminal to look whether you can see your process running, totally without a shell to output its text to  (or... maybe it insta-crashes if there is no shell, I'm not sure. Still no mistake to get acquainted with htop)

Does nautilus have a context menu option (on your hive executable) to "open in terminal" or something?

As for headers:
1. I don't like them either. While it can give a nice fluff-less overview without all the details (if the header is clean), well, an editor that has "fold all" does the same. But it is some amount of duplication. And then the question - where the interface documentation comments? In the header, because it is then part of the overview? Or in the .c(pp) file, because it's closer to what *actually* happens and comments getting stale is more easily detected and corrected? Or in both files (yay more duplication, and out-of-sync-with-reality issues).

And then there is the somewhat, but not extremely remote chance that due to copy & paste errors, more than one header has the same include guard #define's, and funny things happen that aren't immediately understood, due to enigmatic error messages that C/C++ tends to have...
The latter can be ameliorated by using just one line at the top of each header file:
  #pragma once
Then it happens what should happen (almost - you still have to type that silly line): The compiler takes care of nonsense like this. This is supported by every major compiler. (but like any pragma, not standard, hence the name)
There was (or maybe still is) one possibility of failure for this, but it's rather obscure: Under some circumstances when the source files are compiled from some network share, there can be sporadic wrong detection of whether two header files (out of different folders) are the same or not, or something akin to this description. I would say, whoever does something like that needs a beating anway - but it's, strictling speaking, "broken" (or was, haven't checked) - I  am using this for 15 years or so and never had a problem. Compiling from local drive, of course.

2. but how in the world can you make a program beyond hello world that can do without header files?

Some IDEs should have features to generate headers, or stubs in the .c files from headers, I think. (I tend not to use stuff like that)

You must be logged in to post a reply. Please log in or register for a new account.