Monday, January 31, 2022

Matrix recalc speeds

Sooo... Since I realised that the matrix recalculation takes too long, I did some quick calculations and a tiny fix.

By changing the matrix accumulator from an int64_t to an int32_t, I got a reduction from 81us/loop to 48us. Looks like this fixed the envelope "jitter".

Then I started looking at how much happens during recalculation.

We do a staggering 2719 iterations over various params. If we assume that we can achieve 600 instructions every us (600MHz), and we do 12000 loops every second, we have 600 000 000 / 12 000 = 50 000 instructions available to us per loop. Divide this by 2719 iterations.and we end up with 18 instructions per param calculation. That is WITHOUT taking into account everything else that happens during that time, like calculating envelopes, updating the S&H buffers and writing to the DAC.

This is surprisingly low. I am not sure I can make it work but it makes for a great challenge! I should really start looking into more efficient matrix multiplication. 

Update:

Removing amount != 0 checks, e.g. calculating ALL possible params all the time, makes the loop time jump from 48us to 105us.

But then, replacing / 32767 with >> 15 (/32768) brings the time down to 71us. We do get a tiny accumulated error here, I need to check the implications. But it means the worst case scenario is 71us/loop if everything is modulated all the time (?). Still too much, but not as bad as expected. Combining >> 15 with still having the amount check will be the best solution for now.

Not updating envelopes after calculations dropped from 48us to 31us, so we should definitely check for changes before updating.

Things to try: Swapping ints for 32 bit floats and using range [-1, 1]. Means we don't have to divide/shift every calc.

Inline array lookups instead of using variables (though the compiler should figure this out...)

Update 2:

Adding a check for each destination to see if it is necessary to calculate the matrix brought the time down from 48s to 11us (but this will get progressively worse when more things are dynamically modulated). 

Should also add a check to see if env/lfo params have changed before actually updating, as this is a costly process.

Sunday, January 30, 2022

Big Bug Weekend

This is another one of those not-too-exciting posts, but one that sums up a lot of stuff I've done over the weekend.

Filter

I started off with work on the filter. As mentioned in the previous post, it now tracks the keyboard. I also added a filter envelope, but envelope amount is still missing.

I then did some quick calculations on the consequences of using +/-12V instead of +/-15V.

First of all, the filter cutoff mixer has a 270k resistor to V-. It raises the initial cutoff frequency by 5.55 oct with -15v, and 4.44 oct with -12V. Similarly, we have a trimmer between +/-V which lets us trim the same range. We do lose some range when reducing from 15 to 12V, but I have not yet tried trimming the filter so I'm unsure if it's an issue.

Second, the reference current in the cutoff exponential converter uses a 1M5 res to -15V to generate a 0.01mV current. This will now be 0.008mV, and it linearly offsets the cutoff frequency. This can be trimmed away using the cutoff and tracking trimmer, but again I have not tried to do this.

Third, the dead bands for resonance and VCA, e.g. the minimum voltage needed to start changing the params, will change slightly - from 12mV to 12mV for resonance, and 10mV to 8mV for the VCA.

All in all, the filter will probably work well though it needs a bit more testing.

DCO

I decided to get the second DCO going yesterday. I had to find and set up my windows computer, but other than that programming it went without issues. I decided not to try to figure out more about why it outputs 5V instead of 10V at the moment, as I was simply too tired to look at the code. UPDATE: It is because the 3.3Vref combined with using a 22k load on the DAC actually turns it into a 0-2.5V range instead of 0-5, so the charging current is half of what it should be)

DCO calibration

I did however look into how to fix the calibration circuit. The DCO uses its Vcc as a reference when trying to calibrate wave amplitude, and also for detecting "overflows" when pitch changes.

The PIC16F18346 has an internal 6bit DAC which in my case uses Vcc as reference. This has been set to 26/32 * Vcc for calibration and 27/32 * Vcc for overflow detection. 

When Vcc changes from 5V to 3.3V, calibration threshold goes from 4.0625V to 2,68125.

The onboard calibration circuit is simply a resistor divider with a 100k and 68k resistor. It divides a 10V input down to 4.048V, so by using the 4.0625V threshold we should be able to get a 0-10V output from the DCO.

When using Vcc = 3.3V instead, we need to make divider divide 10V down to approx 2.68125. As both ends of the 68k resistor are exposed, we can but another resistor in parallel. Using a combination of a 75k and 3.3k resistor (in series, so 78.3k), we end up with 2.668V from a 10V input, which is close to the same "error" as the 5V version.

As for overflow detection, 27/32 * 3.3 = 2.78, which means the output will reach 10.4V before overflowing. That's about 4% higher than the correct value. I'm not sure if this is audible, we just have to test it.

DCO DAC ref voltage

This cannot be higher than 3.3V when running with Vcc = 3.3V. I have yet to calculate what this means for maximum charge current etc. 

DCO 2 on voice card controller

Now, this opened up a giant can of worms unfortunately. Once DCO 2 was in place, the top of the saw wave from both oscillators got cut off at around 4V. As the only thing connecting the two DCOs are the sync lines, I immediately suspected that something was going on there.

I completed the code for turning on and off sync, but that didn't help, so I decided to move DCO2 from its socket to a breadboard and run breadboard wires to the socket, to better be able to connect/disconnect the sync lines.

Unfortunately, while doing this, I swapped the DGND and +5V pins on DCO2. Fearing I broke something, I disconnected DCO2 and started testing the rest of the circuit. 

Now I noticed a sort of metallic sound on the attack portion of each note. This led me through a wild chase to pin down the problem. I swapped the DCOs, fortunately DCO2 still worked. I figured that the sound originated AFTER the filter and then realised it came from the envelope VCA CV. I tried replacing the CV DAC and sample & hold boards as well, with no result.

I then turned to the code and did a git diff. I quickly realised that I unintentionally updated DCO2 twice, once to the real CV and then to 0 to disable changes while debugging sync. This should really not have anything to do with the CV generation, but after a lot more debugging, it turns out that it somehow messes with the timings. It looks like every second update of the CV failed, and from the look of it one or more of the bits sent to the DAC was missing, or at least that is my theory. Removing the extra update fixed the metallic noise.

Envelope CV (bottom). The signal drops to an almost fixed level for every second update. The level follows the curve of the envelope, which leads me to believe that it's a case of missing bits in the DAC value.

I am quite certain that this issue will come back and bite me later!

DCO sync

Now, after all this, I finally went back to debug sync. I did realise that what was probably going on was something I've seen before - trying to input a voltage higher than Vcc to a pin on the MCU makes weird stuff happen. That was why I wanted to move DCO2 to the breadboard in the first place. I realised I've connected DCO out to the sync pin of the other DCO, meaning that it would see up to 10V! After carefully connecting DCO2 again, I could confirm that this was in fact the issue - though not exactly how I expected it to be.

What happens is that the OUTPUT of the DCO gets cut of at around 4V when connected to the sync pin. When I instead connected sync to the timer output of the other DCO, sync started working perfectly. I remember now that this was how I intended it to be done between two DCOs, I only opened up the posibility to also use an analog wave as input, but forgot that it has to be limited to 0-3.3v.

Hard sync. The waves are in phase in reality, I've only tapped them at different points in the circuit.



Missing +/-12V on the DCO debug headers 

This is just a tiny thing, but it threw me off for a bit. I have forgotten (?) to connect the analog power pins of the DCO to the debug pins next to the socket, so I didn't get any power to the DCO on the breadboard. This is fixed in v1.2.1 of the controller board.

Unexpected refresh rate and S&H caps

I can't remember what rate I was aiming for, but right now the S&H runs at 196kHz. That means around 12kHz per channel. I only wonder because I have a commented out line above it with twice that rate.

When replacing the S&H board, I realised that the one I have in the circuit uses 2.2nF caps. Not sure if I used the same board for testing in my earlier post, but it explains why I've seen a few examples where we couldn't charge the cap fast enough. However, it also tells me that 2.2nF is probably fine :)

Envelope nonlinearity and missing updates

This surprised me. When debugging the metallic noise, I realised that the envelope CV is not perfect, it has small drops along the way where it reverts to the previous sample instead of the next.

Turns out this is because the calculation of next step takes too much time, though not EVERY time for some reason, so the double buffered output array has not been updated and the old value is sent instead.

The output drops to the previous value for one cycle, then goes up again.

I added a counter that is incremented when this happens, and it looks like it actually happens A LOT. Matrix recalculations simply take too long, even with the very small number of params I'm using. This is extremely disappointing and something I need to look into

Here is a way of getting an average without constantly summing several numbers. I can use this to get average cycle time. If it overflows I can use two levels, first averaging 1000 and then averaging those again.


Update: It seems one update cycle takes about 80us. As it is run 12000 times per seconds, the updating alone takes 960000us, or 0.96s per second. This does of course include the time it takes to update the output, as that is interrupt based and happens during the calculations, but we need to look at what is actually taking so long. 80us should give us at least 600 * 80 = 48000 instructions to "play" with.

Testing using Little Phatty

I also had time to do a bit of testing and measuring with the Little Phatty.

Pitch bend

First of all, using the pitch bend on the LP made the stepping sounds go away, just as expected. The MPK25 simply does not have high enough resolution.

Clicks when filter keyboard tracking is off

I also confirmed that the LP makes some similar clicking sounds as the XM8 when filter keyboard tracking is turned off. Not entirely unexpected.

Pitch range

The LP pitch range is approximately 26Hz to 31000Hz when only using the keyboard - Osc set to 16' and lowest key + mod wheel all the way down = 26Hz, 2' Osc, highest key and mod wheel up = 31kHz (I'can't hear the last 5 semitones, and the last ones are pure sines on the scope).

The MPK25 sends midi note 0 to 120. Using midi from the MPK25 I was able to get down to approx 8.3Hz. As for the top, I can't get past oct#4 G# for some reason, and the pitch bend started working in the opposite direction??

I had some issues where bend up did not work for note 120, for 119 it works a bit so not entirely sure what is going on. I can't see from my notes if this was in fact for the LP or for XM8 though!

Electric Druid VCDO range

I started looking for what other DCOs do. The Electric Druid VCDO does 8-8kHz.

Juno range

The Juno apparently covers the entire midi spec range, by having a clock divider on the master clock for the two lowest octaves. It stays within 6 cents of the perfect pitch for all notes except midi note 127. More on this at Electric Druid.

Thursday, January 27, 2022

Filter cutoff - keyboard tracking

I did some work on the filter today. First, I switched from a 100k to a 36k resistor between the CV input and the 0-5V CV. This changes the filter range from 5 octaves to 14 octaves, like the original juno filter. 

I then added pitch to the filter cutoff cv in the matrix, making sure to compensate for the fact that the pitch range is 10 octaves and the filter is 14 octaves. Instant success! The filter tracked almost perfectly from the start, now the output amplitude stays constant between notes and most of the annoying clicks when changing note is gone!

I also added pitch bend. At the moment it has a lot of stepping when running from my MPK25, I will retry with pitch from the Little Phatty, I think this is only a midi issue. There is some noise on the pitch bend too. I first suspected that it was digital noise from the SPI bus, but when I did a small program change that updated the DCOs without actually changing the pitch, the clicks went away. Thus, they are entirely related to either DCO artifacts or the missing filter tracking.

Sunday, January 23, 2022

Emulator II PSU not working.

Crap. Testing the EII regulator board now, and something is seriously wrong. The power led keeps going on and off. 

I disconnected the +/-15V outputs and the 5V works fine. Reconnecting the +15V also works - but I can't trim the 13.2V all the way up, it stops at about 12.95V. That really sucks.

But the worst is that when I add -15V the flashing starts again. Damn.

Update: The -15V is caused by me messing up the polarity of the caps. Such a beginner mistake... The 13.2V is due to the PSU, even under load, only outputting +14V. I have an identical one that outputs 14.5V, that works as it should. Not sure if that means the first one is outside spec or what is going on...

Thursday, January 20, 2022

Voice card build and testing

I should really start off by screaming as loud as I can: "It's aliiiiiive!". This monday I hooked up a DCO, the waveshaper, a waveshape mixer, the Juno filter and an output VCA, all controlled by the voice controller and its internal modulation matrix. For the first time, I'm able to play my synthesizer using an external midi controller. It feels amazing! To think it took 7 years to get this far...

Anyway, it is not without bugs, but that's why I'm doing it this way in the first place, to test everything and how it works together.

There are a lot of things that work great right from the start. The waveshaper does its job perfectly, giving triangle, bi-directional saw, pulse with PWM and two sub oscillators with selectable square/saw output. 

The waveshape mixer CV generator I designed earlier works perfectly, as does the pulse wave amplitude control. 

The filter filters, though the range may be a bit lacking. It resonates beautifully too. I have yet to calibrate it and test it fully after moving from +/-15v to +/-12V. 

Finally, the output amp and envelope works great, though I had to fix a few rather hard to find bugs in my code.

Now, for each module, here are some things that must be fixed or improved.

Waveshaper

The sine wave amplitude is +/-4V while all the others are 5V. This can be fixed in the voice mixer by changing the input resistor or I can fix it on a new revision of the waveshaper.

The saw and triangle waves have noticeable ringing (noticeable on the scope, not necessarily audible). Adding caps in the feedback of the output will remove most of this. The rest goes away in the filter but I am not sure if it affects anything else. 

Pulse width: I don't think the pulse width is quite narrow enough.

When calibrating the symmetry of the sine wave, I can't seem to get a perfect setting that also gives a centered triangle wave. It is not a big issue though, but it means that the triangle is slightly "lower" than the other waveforms, perhaps by 0.5V or so. It is not audible, but it may affect how the circuit clips when mixing multiple oscillators. I'm going to leave it as it is for the time being.

The square wave sub oscillators are not centred. This is because the reference voltage used in centring is derived from -15V, and when changing this to -12V the reference is wrong. Again not audible but nice to fix.

The triangle and sine waves have a very visible notch at the end of the phase, more about that in the DCO paragraph.

Waveshape mixer

As I wrote in my last post, the AS3364 has a sort of dead band in both ends of the CV. Since all waveshape mixer CVs are generated from one input, it means that there is no way to compensate for this without changing the CV generator. In practice, the dead band means that one waveform fades out completely before the next one has reached its maximum. This is especially apparent in the saw to pulse cross fade, where the wave has become a square before the square has reached its top. It is not particularly pronounced so I don't think I'll do anything about it.

DCO

These are not properly wired up yet, so some of these things may go away - right now they run with the wrong calibration circuit and only produce a 0-5V wave when they should give us 0-10V (at least that's what the waveshaper expects). To compensate for this, I'm running the wave through a non-inverting op amp amplifier with 2x gain.

There are a few shortcomings/bugs in the DCO. First of all, some ringing is introduced along the way. I've added a cap to the feedback of the non inverting amp, a 15pF in parallel with the 56k resistor I'm currently using.

It looks like discharging the DCO cap goes too slowly. Either that, or we are limited by the slew rate of the op amps. In any case, this means that the drop from top to bottom of the saw wave is not instantaneous. When generating the triangle wave we invert half of the saw wave to get the "missing" portion of the triangle - but since the falling edge is not perfectly vertical, we get a notch at the end of the triangle phase. I can't say I hear it, but  at 8kHz it is very visible on the scope.
DCO discharge is not vertical enough, leaving a notch in the saw wave.

Adding a 5p cap across the DCO output op amp takes away much of the ringing at the start of each cycle




15p cap takes away even more of the ringing. Saw output from the waveshaper at the bottom, some new ringing has been reintroduced.

Clicking on envelope retriggers: When we play a new note without releasing the previous one, we get a bit of clicking. So far I've been able to identify two probable causes - output amplitude and centring after the filter, and glitches in the DCO.

The DCO glitches manifest themselves as discontinuities in the triangle wave, it suddenly and abruptly changes value. The reasons are:
  • When changing from a high to a lower pitch: It looks like the period timer is not reset. Instead, the period is reset when the original frequency would have been reset. This means the amplitude is too low and the start/end matching of the triangle fails.
Saw does not reach its maximum as it is reset at the "old" frequency
  • When changing from a low to a higher pitch: now the timer lasts too long, meaning the cap is charged more than it should. It reaches its max and flats out, both distorting the saw/tri and introducing a spike with too high amplitude. That would definitely sound like a click. 





The last of these is to be expected. The DCO is supposed to check the amplitude against a known voltage, but without calibration this won't work. The other one on the other hand, is stranger. I need to check the code.

I also got a more serious error while testing the very limits of the DCO. When playing OCT+4 on the MPK-25, switching between e and g makes the DCO drop to a much lower frequency for a single cycle before recovering. It happens consistently. No idea what makes it happen.




Finally, the range of the DCO is currently too narrow. It maxes out at around 8.5kHz but should reach at least the double or ideally above 20kHz. Replacing the integrator cap and regenerating the timer code will probably solve this.

Filter

As with the DCO, the filter cutoff range needs looking into. I have not tried calibrating the filter at all, so it may not be a real problem though, but it looks like the filter is not open enough with CV at 5v.

There is also something going on when changing the wave frequency. Obviously, when the wave frequency reaches the cutoff point, higher frequencies will be attenuated more, so with the filter at a fixed cutoff, switching between two notes will make the amplitude jump up and down. This may be part of the click-sound I'm hearing. Also, the filter has some form of DC filtering, so the balance/centring of the wave changes with waveform/content. This is particularly visible with narrow pulse waves and resonance. Again, a bit of calibration may improve this but I also need to see what other synths do. Also, introducing keyboard tracking means that relative amplitude should not change as much between the notes.

Some kind of noise at the start of the envelope (not visible in the CV). This was before I hooked up a probe to the filter output so I don't know where it originated from



Weird glitch in output, again, no idea what this was, especially since it is not at the start of the envelope.

Quick retriggering that changes frequency leads to amplitude changes after filter

Output from filter is not centred. Had a lot of resonance and wave was not symmetric around the X axis.



Envelopes

These are software, and mostly finished. I still need to hook them up to the GUI to make it easier to test them, but for now they are controlled through 7bit midi. As they have a very large range - 1ms to 30s, I have to use some kind of linear-to-exponential mapping, or we would not get any resolution at the lower parts of the range. 

I feel that the mapping I use now still does not have right response to it. Fortunately, I have a script to generate mappings with so it's only a question of tweaking this.

GUI

The GUI should - in theory - output everything needed to control the synth over midi already. But since I want to PLAY the synth using my Akai controller, I'm using up the only available midi port on the voice controller card. I need to find a way to merge the midi output from the GUI with the controller. I THINK that MidiPipe may do the trick.

AS3364 response confirmed

I did a new test of the CV response for the AS3364. Connecting a 5V to the input, and a 0-2V (actually 5V but through a 33k/22k resistor divider at the CV input) saw wave connected to the CV gave the following output:


As we see, it has a confirmed "deadband" at the bottom, it doesn't start to get linear until about 250mV CV. Similarly, linearity breaks down again at the top, around 1.8V. Mind you, this is NOT distortion of the input SIGNAL, it's only the control that flats out, so it doesn't have too much of a consequence. If it becomes a problem it may be trimmed out in the CV generation.

This is for one chip only, I have not yet tested multiple to see if they respond differently. Nor have I done any temperature testing - after all, we're still dealing with an expo converter inside the chip, though I'm not sure if that is a problem.

Monday, January 10, 2022

Voice Controller v1.2b testing, including 16ch sample & hold

I've finally started testing the voice controller card that I made last spring. It's been so long it's almost a bit scary to start testing.

Voice card controller with peripherials

In the image above: To the left is the PSU interface. At the moment I get +/-12V from a Doepfer PSU. A 5V input is available but not used as the Teensy gets 5V from USB and powers the rest of the circuit through its internal 3.3V regulator. To change this later requires a trace on the Teensy to be cut.

The teensy (4.1) is the long narrow board closest to the top. Below it is my custom DCO, and left and right of that is DCO memory and reconstruction filter respectively. 

The tiny chip on a tiny PCB to the right of the midi sockets is a DAC, the card has room for four of them to be run in parallel.

Each DAC controls a 16ch multiplexed sample & hold card - those are shown to the right. In theory this should give me 64 CVs to play around with when the card is fully populated.

At the bottom is two port expander cards, each with 16 i/o pins for a total of 32 digital pins that can control switches etc on the voice card.

Testing

So far I've tested: 

Midi in and out - both work flawlessly. I use an H11L1 optocoupler running at 3.3v, both resistors in the input circuit are 220Ohm.

The two DCO positions, they both work fine but I only had one working DCO so I couldn't test sync between them. DCOs are controlled through SPI1 (hardware SPI).

DCO with constantly changing frequency, showing how it does NOT reset on frequency changes. Mmmmm.... Calibration is not in place yet so it does not reach full amplitude.


Port expander. I had to write my own little lib for these but it works great. Shares SPI1 with the DCOs.

DAC in slot 1. It's controlled via bit banged SPI at 50MHz and works great :) 


Now, yesterday I did a bit of soldering for the first time in years. I've built an enclosure that I hoped could help me with my health issues, but I'm not satisfied, I still felt considerable discomfort afterwards. Not completely sure of why though, but that's for another post.

Anyway, that meant that today I'm able to test the sample & hold circuits. First tests are very promising. Running the DAC at half the reference voltage (3.3v from the Teensy at the moment) shows 3.279-3.284 on my Saleae Logic Pro 16 scope pins , and alternating between 0 and 3.3v on each s&h pin shows hardly any visible artifacts at the start of each charge cycle. I'm using a 470R resistor between the dac buffer and the s&h mux btw, and this is the S&H board with 1nF caps (I have some with 2.2nF too, I will experiment with both combinations later).

I see a tiiiny dip at the start of the cycle, it consistently drops to 3.274V. The Logic Pro resolution is 5mV, so exactly how much a constant value fluctuates and how much it drops on charging is unknown, but around 5 to 10mV at most seems to be a good estimate. On the breadboard this drop was 30 to 50mV, so we're almost at an order of magnitude improvement, that's a good thing. A quick test with a board with 2.2nF caps instead of 1nF made the dip go away completely - but such a board may not be able to achieve the refresh rate / charge speed we need.



The dip when charging, dropping from 3.284/3.279 to 3.274 on the scope

The hold time is approx 80uS and there is no visible droop during that time. It also means that our refresh rate is around 12.5kHz.

A 5mV drop means we're seeing a 0.1% error at that moment. However, it only lasts for 0.3uS (out of the 80uS per cycle). I think it would be very hard to notice even for pitch CV though it may introduce a slight vibrato, who knows.