Why does the theremin's ground pin need to be floating?
anyfoo mit Posted: 6 May 2022, 06:15 AM Member Posts: 4 Joined: 6-May 22 All the project writeups are great, massively so. I spent a lot of time reading them.I have a question about the tiny Theremin project: Why does it have to be floating? I understand that one of the I/O pins has to be either connected to ground or to the player to form the capacitor, but why does the entire circuit floating matter?Heh, now that I type this out... is it because the vicinity of the I/O pins to ground would form a much larger capacitance, drowning out the player?While I'm at it, a comment about one of the synth players where the subject was reusing memory for different algorithms in C, without resorting to unions. Macros and direct addressing were suggested, but I think the simplest solution would just be to declare the data area in the wanted size, such as:`uint8_t data[4096]; // must at least be maximum size required by any algorithm`And then, have each algorithm have its own structure type, but addressed through a pointer with all pointers simply pointing to your data area:`struct alg_foo_t *alg_foo = (struct alg_foo_t*)data;struct alg_bar_t *alg_bar = (struct alg_bar_t*)data;struct alg_another_t *alg_another = (struct alg_another_t*)data;...`But the union has the benefit that you do not need to figure the size out. So instead of the opaque data area, do this:`union {struct alg_foo_t alg_foo;struct alg_bar_t alg_bar;struct alg_another_t alg_bar;...} data;struct alg_foo_t *alg_foo = &data.alg_foo; // could simply point to data, but this spares a cast and looks cleanerstruct alg_bar_t *alg_bar = &data.alg_bar;struct alg_another_t *alg_another = &data.alg_another;...`And you have the best of both worlds: An automatically sized data area, and easy addressing through a direct pointer to the structure with no union indirection.Last edit by anyfoo at 6 May 2022, 06:21 AM------------- [top] Posted: 6 May 2022, 09:46 AM yeah whatever Admin Posts: 541 Joined: 4-May 16 I can't answer the theremin question. Not only have I forgotten the details, but I didn't really understand how it worked at the time. It was mostly just about experimenting with different arrangements until I found something that works.Good point about the C memory though. I think if I had written it from scratch with sharing memory in mind, I would have gone with something like that. It gets a little uglier because there are arrays of structs, and some structs contain arrays. The channels/polyphonic oscillators looks like this:`struct channel { int32_t bend; uint8_t volume; uint8_t RPNstack[4]; uint8_t pbSensitivity; uint8_t mod; float lfo_depth; const float* tuning; unsigned sustain:1;} channels[16];struct oscillator { uint8_t channel; uint8_t notenumber; uint8_t stolen; uint8_t stolenChannel; float phase; float amplitude; float fm_phase; float fm_amplitude; float fm_depth_cache; float lfo_phase; uint32_t starttime; uint16_t velocity; unsigned alive:1; unsigned released:1; unsigned sustained:1; unsigned intAttack:1;} oscillators[POLYPHONY];`Polyphonic algorithm 3 uses the same oscillator struct, because it's nearly all the same, but the fm_whatever floats are used for different purposes. There's also concern about what values are valid, though I suppose when changing algorithm it could wipe them.The monophonic algorithms have their own array elsewhere... but it's only about 20 bytes, so it doesn't really matter, and I like how readable the struct definition is.The prototypes for the algorithms look like this:`typedef void doOscStereo_t(struct oscillator* osc, struct oscillator* osc2, uint16_t* buf, uint16_t* buf2);doOscStereo_t oscAlgo1Stereo;doOscStereo_t oscAlgo2Stereo;doOscStereo_t oscAlgo1Quad;doOscStereo_t oscAlgo2Quad;doOscStereo_t *doOscillatorStereo = &oscAlgo1Stereo;typedef void monophonicAlgo_t(float f, uint16_t* buf, uint16_t* buf2);monophonicAlgo_t algoMonophonic1;monophonicAlgo_t algoMonophonic2;monophonicAlgo_t algoMonophonic3_square;monophonicAlgo_t algoMonophonic3_saw;monophonicAlgo_t *monophonicAlgo = &algoMonophonic2;...typedef void generateIntoBuffer_t(uint16_t* buf, uint16_t* buf2);generateIntoBuffer_t generateIntoBufferFullPoly;generateIntoBuffer_t generateIntoBufferDualOsc;generateIntoBuffer_t generateIntoBufferPoly4;generateIntoBuffer_t generateIntoBufferMonophonic;generateIntoBuffer_t *generateIntoBuffer = &generateIntoBufferFullPoly;...etc`------------- [top]