squinewave~  

Bandlimited oscillator with morphing waveshape


  | what is it? | usage | code |

what is it?
A bandlimited morphing sine-saw-square-pulse oscillator with hardsync.

suggested use
Replace all sine/square/saw oscillators in approximately every softsynth ever created :-)

A bandlimited signal is created not by filtering or iFFT, more like a graphic pencil that draws the requested waveform sample by sample.
The waveshape is constructed from sine sweeps and straight (horizontal) lines.
See the Csound manual.

sound example
From Csound manual.
NB:
Not very musical, full amplitude. Best appreciated if you download and open in a soundfile editor with sample-level zoom and spectral view.
left channel hardsyncs right, then left FM modulates right

by rasmus.ekman@abc.se

hide
Notes

Waveshape is controlled by 2 parameters: clip (squareness) and skew (symmetry).
Hardsync raises freq very quickly until waveform is reset to beginning. Usually causes a pulse (bandlimited but sharp).

code usage
Initialize: Set min_sweep_length sample count; recommend range 4-20.
Runtime
  • All inputs should be fed each sample: freq, clip, skew, sync (0 or 1).
  • Call generate() for each sample. Batch calling for 8+ samples is usually an optimization
  • Now audio + sync signal is available on the output.

Make sure that you use smoothing on inputs so there are no hard edges. Otherwise there will be crackling noise in the signal.

GUI suggestion
The shape can be usefully controlled by an X/Y input, with drawing of the waveshape.
I have some code that might help (Java graphics2d and C++ for VstGui).

Inputs:
  • Frequency (0 - sample_rate/2)
  • Clip - Squareness of waveform (range 0-1)
  • Skew - right/left symmetry offset (range +/-1)
  • Sync - 0 or 1. Resets waveform in 0-20 samples when input is >= 1

Outlets:
  • Audio (range +/-1)
  • Sync - 1 sample per cycle, else 0

Init:
  • Min sweep (range 4-100)

The smallest number of samples for waveform sweeps.
Suggest to randomize in range 4-15.

If you run several squinewaves in unison, it's useful to init them with different values of min-sweep.
The square/pulse waveforms have dips in the spectrum due to the rounded waveform.
With different min-sweep values these dips will cancel out rather than be exaggerated.

Complexity:
All code is 64-bit doubles.
Max 1 sine library call per sample, and there is some branching in the code.
C/C++ measurements suggest cost about 2-3 x over a typical pure-sine oscillator.
However, you can get it back by skipping 1 filter in the signal chain, since decreasing clip value has the same effect.

hide
source code

2023-09-11: Through-Zero frequency modulation implemented for all versions. On negative frequency input, the waveform seems to move "backwards."
Gitlab repo added - because Github are raising obstacles for users.
Source Code: squinewave-src-2023-09-11.zip
Supercollider binaries: Squine-MacOS-v1.0.0-RC4.zip, Squine-Windows-v1.0.0-RC4.zip

2021-09-11: Github repo with versions for CSound, Java (Voltage Modular), SuperCollider.
See Releases for SuperCollider binaries.

2019-12-18: Java version for Voltage Modular.
See Squinewave module
Java source: squinewave-java_2019-11-25.zip

2017-11-05: Csound version.
Csound Git: Csound / Opcodes
C source: squinewave_csound_2017-11-05.zip

2017-11-20: New version, has not been released. Please suggest where to host it so Max users can find.
C++ source: squinewave~max-2017-11-20.zip

2016-10-10: Released Max object, later pulled and rewritten.


hide
2016-10-09 19:00