Ricard contributions


#1

I've uploaded some non-audio objects which I've devised while porting the Axoloti to run on the Audiothingies P6 .

The P6 has 6 rotary encoders, which together with 9 push buttons (and 6 push buttons in the encoders) are connected to 74HC165 shift registers using an SPI-like interface (although in the P6 it is bit-banged rather than using an SPI interface in the STM32 chip).

There's also a quadrature decoder object for decoding the outputs from the rotary encoders, which takes two inputs and produces an up clock and a down clock, which output clocks depending on which way the encoder is turned. There's also a step output which outputs clocks independent of the direction of rotation.

Objects:
objects/ricard/gpio/in/165ctrl v.axo (control object specifying the pins used and number of bits employed (8 per 74HC165 chip), as well as the scanning rate.
objects/ricard/gpio/in/165in.axo (actual bit input object generating a boolean signal)
objects/ricard/logic/qdecode.axo (quadrature decoder)

The P6 also uses a 74HC595 shift register for controlling 8 of the LEDs on the front panel.

Objects:
objects/ricard/gpio/out/595ctrl.axo (control object specifying the pins used and number of bits employed (8 per 74HC595 chip).
objects/ricard/gpio/out/595out.axo (actual bit output object)

The P6 has a 2x24 character LCD, and I've devised a pair of objects for printing to the LCD. The connection is rather rudimentary, utilizing the 4-bit mode of the display, with no status readout, hence a 6 wire interface suffices, with RS, E and 4 data bits D4..D7. The R/W pin is assumed permanently low (i.e. write).

Objects:
objects/ricard/disp/lcdctrl.axo (control object specifying the pins used and size of the print queue (number of strings that may be printed at once and which will be printed in order as the display becomes available)
objects/ircard/disp/lcdprint.axo (output object outputting the string input to the module when the clock input goes high)

The strings can contain rudimentary cursor control using control characters, see the object definition for more details.

Finally a rather trivial object, which converts a vector of bits into a single bit masked output value, with a 9 bit input. I seem to remember there being an 8 bit version among the factory patches but I cannot find it now.

Object:
objects/ricard/logic/bitval 9.axo

Please note that for the control objects, more pins can be selected than normally on Axoloti modules, simply because I want to be able to run these objects on the P6, where some of the pins used are not available for general use in the Axoloti. So exercise caution when using the modules so you don't select pins which are not actually available.


Creating A Menu System
#2

hi ricard, great work! i have a p6 collecting dust and would be very interested in this. so what is the procedure? how do i "update" my p6? how do i upload patches? generally, what works, what not?

cheers


#3

Hi and thanks for your interest!

First, you need a patched version of the Axoloti firmware which adds support for the P6, mainly when it comes to differing clock crystal rates, UART assignment, and the different DAC used in the P6, but also removes support for things like the ADC since the STM32 analog inputs are not used in the P6.

The firmware is available in my Github repository, at github.com/polluxsynth/axoloti, on the p6 branch. Basically, you check out that branch (which is just a fork of the official Axoloti firmware), and build just as you would the standard Axoloti firmware.

To flash the P6, first start the Axoloti UI as usual, connect it to the P6 using a USB cable, and then set the P6 to DFU boot mode by holding the BOOT button inside the P6 and switching it on. Go into the Board -> Firmware -> Flash (rescue) menu in the Axoloti UI to flash the P6; the progress will be indicated in the main Axoloti log window. (For some reason which I haven't been able to figure out, upgrading to a newer version must be done in the same way, rather than use Board -> Firmware -> Flash .)

After that, it basically works the same as with the standard Axoloti, taking into consideration the limitations of the P6 hardware. MIDI input and output, also over USB, works directly in the platform, using the corresponding Axoloti objects. The LCD and other user interface elements require the special objects described above to access them. There's no audio input of course, since the P6 has no ADC, and there is no SD card, and no DRAM. So objects which use these elements won't work. Apart from the, there's the same DSP and RAM capacity as on the Axoloti hardware. In particular, the Patch -> Upload to internal flash function works, which is really nice on a box with its own user interface.

I just uploaded my test patch, patches/ricard/p6/p6test.axp which basically implements a complete P6 UI, with three embedded objects implementing user interface menus, parameter management, and a state machine for menu navigation. There's also an object which implements rudimentary patch storage in the P6 on-board 24C512 EEPROM. Mind you, these are patches in the UI sense of the embedded objects in the patch, not storage of true Axoloti patches. The reason for this is that my end goal was to implement a synth where only a subset parameters are user controllable, in order to make the user interface more managable, as on any pre-configured synth (such as the P6).

In order for the UI to have something to control, there's a very rudimentary synth implemented as a subpatch, a far cry from a real P6, basically just something to test the user interface on.

Just to be clear, neither the p6 branch of the firmware nor the p6test patch can load original P6 patches or anything, I'm just aiming for something with the same look and feel, as I really like the P6 UI approach.

I haven't done a lot of work on this lately, partly because I'm not fully convinced like things like the LCD and encoder control should be patcher objects, because I feel the Axoloti patcher environment is not ideal for things like state machines and things that are triggered from user buttons, as opposed to DSP code which does something useful all the time, The EEPROM support for instance is implemented partly in the firmware on the p6 branch, and then has a (currently embedded) object for the actual patcher interface, and a similar approach might be more viable for the LCD for instance. At the same time, the current approach means that the objects can be used for other, custom, hardware as well, which is a plus from a community perspective.


Axoloti controller plan - encoders, touch screen TFT
#4

thanks, ok will have a go at this sometime i think. time to setup an axoloti build environment.


#5

Fortunately, the Axoloti seems to be one of the user friendliest builds I've seen, not that I've seen many though. There's a lot of stuff it does, but it's basically download and go for the most part.


#6

hmm, i don't see your objects or patches anywhere in the contrib section...


#7

That's strange. I assume you've pulled from the repository recently, I uploaded them just a couple of days ago. Or else I've made some mistake; I pushed them to the 1.0.12 branch which seems to be the default one. Checked by cloning the axoloti-contrib repository just now and they are there.


#8

all good, it is there. sorry stupid mistake from my side. somehow syncing libraries got disabled at startup. and since i was so used to that i did not even check...


#9

I have updated my quadrature decoder object. It now features configurable debouncing, and configurable knob acceleration (output toggles at an accelerated rate when knob is turned faster). The configuration of the object is now is now in a separate configuration object, so the configuration does not have to be repeated when there are several quadrature decoders in the patch.

I've updated the P6 test patch (p6test.axp) to reflect this, and also added a new P6 patch with a basic single sawtooth oscillator patch, yielding 16 voices of polyphony (it would actually be more, but the Axoloti UI limits polyphony to 16).


#10

Inspired by @SmashedTransistors (tiar), I started out with his DP2Saw oscillator, then read this article by Vesa Välimäki et al:

https://www.researchgate.net/publication/236616321_Reducing_Aliasing_from_Synthetic_Audio_Signals_Using_Polynomial_Transition_Regions

on the more optimal PTR algorithm, resulting the following third order PTR sawtooth oscillator:

  • ricard/osc/PTRSaw.axo

(Note: What SmashedTransistors calls a 'second order DPW' algorithm I believe is actually a third order algorithm, since both the polynomial and differentiation functions match the third-order cases in https://www.researchgate.net/publication/224557976_Alias-Suppressed_Oscillators_Based_on_Differentiated_Polynomial_Waveforms (again by Välimäki and associates).)

What utterly fascinates me is how just making a few changes to the waveform in the sawtooth reset period reduces the aliasing to negligible levels. It becomes very obvious in the PTR algorithm, as the only actual waveform mangling takes place in the reset region, even though the actual output waveform is identical to the DPW algorithm (used in DP2Saw). However, due to the way the computation is performed, numerical precision isn't as important with PTR compared to DPW. Indeed, DP2Saw is quite noisy at lower frequencies which PTRSaw isn't.

A lot of research papers contain a lot of hairy math and are not immediately suitable for conversion to code, however, the above one is an exception, also providing ideas for a PWM oscilator which I have yet to realize.

Another paper which I found immediately useful is this one:

(also available as http://home.mit.bme.hu/~bank/publist/smc13.pdf)

outlining how to make a triangle wave oscillator with variable symmetry. Sadly, it only covers the second order case, but the level of harmonics in triangle waves is lower than in sawtooth or square waves to start with, so the results seem fairly usable anyway. Indeed, during some quick tests, the level of aliasing in both the third order PTR above and the second order EPTR oscillators below are less than the build-in BLEP based Axoloti oscillators. From the aforementioned paper I've derived the following implementations:

  • ricard/osc/EPTRSaw.axo : Second order EPTR sawtooth. Less alias than the Axoloti build in sawtooth, but more than the third order PTR above.
  • ricard/osc/EPTRTri.axo : Second order EPTR triangle oscillator, a rather crude proof-of-concept implementation just as a test of the EPTR algorithm.
  • ricard/osc/EPTRAsymTri.axo : Second order EPTR Asymmetric triangle. The waveform generation has been refined, but the symmetry control needs work to be useful, as it is there's much too much action around the zero point of the bipolar control.

All of these are work-in-progress, especially EPTRSaw and EPTRTri which are really just stopgaps while getting myself familiar with the algorithms. I've just made some quick tests, there might be weird quirks lingering in the code somewhere.

Indeed, with a combination of methods to make essentially alias free waveforms for both waveforms with discontinuities (e.g. sawtooth and square/pulse waves) as well as with discontinuities in the first derivative (i.e. the waveform is not discontinuous but changes direction, like the triangle wave does), a lot of interesting analog-synth-like waveforms could be constructed from piecewise linear waveform segments, since the PTR/EPTR algorithms only require adjustments of the corresponding trivial waveforms near the transition regions.

The advent of intrinsic hardware floating point capability in microcontrollers such as the STM32F4 means that it's much easier to implement efficient algorithms without having to convert everything to fixed point or integer math. This means that purely analytical measures can be used to calculate the exact sample points, in contrast to the practical implementation of algorithms such as BLEP which rely on pre-computed tables with the residual waves, suffering from limited phase resolution, rendering the in principle alias free BLEP algorithm not as alias free as intended.


#11

I'm still surprised to read that Prof Valimaki invented DPW.

This is one of the oldest anti aliasing method !!!

Integrals have been used to calculate mean values since they have been invented !
Anti aliasing with them is a basic and direct application.
The fact that higher order integration can be used to calculate means of means is also as old as Calculus.
Thus only Sir Isaac and Herr Gottfried Wilhelm should be allowed to claim for this !

Back in 1998, I used this trivial method in an exam for my students.
Here is an archived thread triggered by one of my student:

along with a discussion about state changes and clicks... note the archive date...

I do not claim anything about DPW, I just want to say that It is one of the oldest aliasing limiting method.

The first time i heard about DPW was in an application note for the Motorola DSP 56001 back in 1995.

The aliasing scheme of the D-5 D-10 D-50 Linear Arithmetic Synthesizers by Roland (1987) is consistent with DPW.

The 2D equivalent of pre integration for anti aliasing is known as "Summed-Area Tables" and was invented in 1984.


On the other hand, I don't really get his PTR gibberish.

Instead of calculating the value of a function at a sampled time,
fifferentiation of pre intergrated wave functions work by calculating mean values over the time segment between two samples (thanks to integrals).

The application of integrals to hard sync is straight forward: when you have a hard sync event, you split the calculus in two subsample segments instead of one:

  • the segment before the sync
  • the segment after the sync

#12

I don't want to take sides as to who invented DPW either. Despite my engineering background, I'm really a noob when it comes to this type of math. My gut feeling though is that even though integration followed by differentiation itself is old as the hills, the theoretical basis for this when it comes to cyclic waveforms has been sketchy, i.e. the math has to hold not only for the waveform itself but also for the discontinuity that appears as it looped, which is not obvious to me anyway.

As I understand it, PTR is not a new algorithm, it's just a mathematical rewrite of DPW, including the realization that the differential of an integrated waveform is identical to the waveform itself, with an offset, except for the transition regions. For the transition regions, instead of actually performing an integration/differentiation operation, the actual resulting sample values can be directly calculated using suitable formulae, the whole point being that over a complete cycle, the amount of CPU time for PTR will be less than DPW. From my point of view, it's appealing that waveforms can be constructed without pre-integration, just a couple of highly specific calculations at the transitions.

One advantage of PTR over DPW seems to be that there is less noise with finite resolution at low frequencies, indeed, other DPW implementations I've seen go for doubles to alleviate this.


#13

Sorry for polluting this thread with this kind of issues.
I think it is very important to state that these methods are "good old methods" and "state of the art" to avoid that some people have the idea to patent them.
As a concrete example, symmetric BLEPs have been patented by Korg in 2005 even if it was used by others before (EdgE algorithm by Canam Computers Quartz Audio, but as it has never been published, I think that Korg's patent is valid). I think that's why many people use asymmetric BLEPs or BLITs.


The differentiation causes issues when the step is small (ie for low frequencies). In this case, anti aliasing is not needed and you need a way to soft switch from DPW to trivial. That's what I do in my DPW distortions and phase modulated oscillator objects.

Example from distortion DP typeIIA:

  if(fabs(dx) > 0.005f){                     //<---- DP if the segment is 
    y0 = 1.5f * x0*x0 / (1 + x0*x0);                 large enough
    float dy = y1 - y0;                                   /
    outlet_out[i] = arm::float_to_q(dy / dx, 27);  <-----/
  } else {
    float inv = 1/(1 + x0*x0);                                     else
    y0 = 1.5f * x0*x0 * inv;
    outlet_out[i] = arm::float_to_q(3*x0*inv*inv , 27);   //<----- direct value
  }

The problem with higher order DPW is that it induces high frequency filtering (as it works as mean values over sample to sample segments).
So, i think that the best strategy consists in using oversampling combined with the integro diff scheme.

As far as i experimented simple precision floats are enough for

  • second order (ie two differentiation) for simple oscillators, and
  • first order (ie one differentiation) for distortions and phase modulated oscillators

double precision can be used for second order (two differentiations) for distortions and PM osc, but it is quite tricky to get the glitchless switching conditions (I got some working in jsfx / Reaper)


BLITs (and BLEPs) are generally "sharp" in the spectral domain and have Gibbs ondulations in the temporal domain. Thus, they are not good if the signal goes through distortions or saturations that would chop off these ondulations.
DPW do not cause these Gibbs overshoots. So the signal can be post distorted without too much trouble.

Note that it may be possible to design "soft" BLITs (or BLEPs) that will behave quite like DPW.


#14

Well, I suppose this is as good a place as any to discuss the issue.

That's amazing that Korg managed to patent that. I wonder if it's because its tricky to understand the small details of these algorithms and the fact that a lot of stuff is found in research papers rather than patents that it can slip through the patent system (notwithstanding the fact that a lot of patented stuff should never had made it that far).

I would think though that asymmetric BLEPs (which I'm assuming is not necessarily the same as minBLEPs although the minimum-phase reconstruction of the BLEP does result in a fully causal and asymmetric BLEP) as used in the Axoloti factory oscillators, have the computational advantage that nothing needs to be added before transitions, which otherwise would require some form of waveform lag or lookahead in order to insert the BLEP at the correct point.

Yes, I didn't think of that, that would take care of that issue. I still find the PTR algorithm elegant. The whole waveform generation for the PTRSaw oscillator comes out as:

p += dp; p -= (p > 1);
if (p < dp) { D = p/dp; y = (2 * dp - D) * D + 1; }
else if (p < 2*dp) { D = p/dp; y = (D + 2 * dp - 4) * D + 3; }
else y = 2*p - 1;
y -= 2 * dp;

(there's probably still room for optimizations. EDIT: Only calculate D when actually needed.).

This is something that fascinates me. From what I can tell, the magic lies in moving the phase of the harmonics around causing the ringings to dissolve. There's also a slight spectral droop with DPW from what I understand, but not enough to explain the complete lack of Gibbs ringings. But doesn't the altered relative phase positions have some form of drawback? After all, from a signal processing point of view, we've run a mathematically correct bandlimited oscillator through a filter whose major contribution is that it messes up the phase response.

Do you mean using the minimum-phase reconstructed residual instead of the obvious BLIT or BLEP?

I may be wrong, but it seems to me that the main problem in a system with limited processing power such as the Axoloti, that it's not possible to generate the BLIT or BLEP in real time, thus it must be added in the form of a waveform, which brings in the additional complexity of how to handle interpolation, for instance by oversampling the BLEP obtaining a polyphase BLEP. The resulting phase error for the BLEP in a practical implementation limits the antialiasing response, indeed, the Axoloti factory oscillators seem to have a lot more aliasing that the DPW (or PTR) algorithm to my ears. In contrast, DPW and PTR calculate to the available precision the exact sample points.


#15

To me the PTR very looks like a two point BLEP consisting of a parabola.


I think that good candidates for smooth band limited impulse can be taken from window functions (as they are designed with the same criterion):

(I think that PTR corresponds to a two point welsh window.)


#16

Loving this debate. All though I dont understand all of it, its interesting.

Thanks guys :wink:


#17

From what I can tell, it was derived by analyzing how each output sample in the corresponding-order DPW algorithm is related to the input (i.e. trivial waveform) samples. So it is mathematically identical to DPW if I understand correctly.

I would think that it's not unlikely that there are different ways to arrive at essentially the same sample values in the transition region, since all algorithms have the same goal of minimizing frequencies beyond half Nyquist.

Interesting. Have you or do you know of anyone else has elaborated further on this in the form of a paper or other report?


#18

Well... mmm... The BLEP described by Korg in their drawings have no Gibbs overshoot.
https://patents.google.com/patent/US20060145733A1

Anyway, it's not an issue to use a smooth symetric BLIT and integrate it.


#19

I would think it would be very difficult to enforce such a patent. Given an arbitrary bandlimited sawtooth oscillator, I would think it impossible to see in the output waveform how the bandlimiting was actually acheived; one would need to look at the actual algorithm for that.

Anyway, back to the thread, I've now uploaded the optimized version of the PTR sawtooth oscillator as described a few posts back.


#20

Finally got my PWM oscillator working yesterday:

  • ricard/osc/PTRPulse.axo

PWM input (and PWM parameter) has a range of -64 to +64, from maximally short negative to maximually short positive pulse, to the point that the oscillator actually goes silent at the extremes. With PWM at 0, the output is a square wave.

The PTR antialising means that the amplitude drops for small pulse widths at high frequencies. I'm thinking about adding a function to optionally limit the minimum pulse width in a frequency-dependent manner so that this doesn't happen, as at high frequencies the harmonics are not really discernible anyway, so the deviation from the intended pulse width would not be noticeable. On the other hand, an analog PW oscillator tends to behave in a similar manner due to limited slew rates, so perhaps it wouldn't buy much.