squinewave

squinewave — A mostly bandlimited shape-shifting square-pulse-saw-sinewave oscillator with hardsync.

Description

This oscillator generates a variable shape waveform that can morph freely between classical shapes sine, square, pulse and saw. The shape is controlled by two interacting values: clip (squareness) and "skew" (symmetry). All shapes use a minimum number of samples per transition (ie, the sharp end of a saw or a pulse uses minimum N samples), this makes output bandlimited. At higher frequency, the minimum sweep rate takes over, so over a certain pitch all shapes "degrade" to sinewave. The minimum sweep rate is i-time configurable. Hardsync (a very quick sweep to phase=0) is supported, and a sync signal is output once per cycle.

Syntax

aout [, asyncout] squinewave acps, aClip, aSkew, asyncin [, iMinSweep] [, iphase]
aout [, asyncout] squinewave acps, aClip, aSkew [, ksyncin] [, iMinSweep] [, iphase]

Initialization

iMinSweep (optional) -- Range 4 and up. Sample count of the shortest square/pulse edges. Default: sr/3000 (mostly alias-free).

iphase (optional, default=-1) -- initial phase, range 0-2, proportional to the segments of the waveform (see notes). If negative value is given, skip setting phase

Performance

aout -- audio output, normalized +/-1

asyncout -- (optional) - Sync signal: 1 at endpoint of each cycle, else 0.

acps -- frequency. Range 0-anything; negative freq not implemented.

aClip -- "squareness" of waveform shape. Range 0-1. Clip 0 is sinewave (or saw), clip 1 is squarewave (or pulse).

aSkew -- symmetry of waveform shape. Range -1 to +1. Skew = 0 is symmetric like sine or square. Skew +1 or -1 is right/left-facing saw or pulse.

asyncin/ksyncin -- (optional, ignored if not a-rate) - when >= 1, waveform quickly sweeps to phase 0. Sweep length is 0 to about 1.5*iMinSweep samples depending on current phase.

The squinewave opcode is a variable shape oscillator with internally generated waveform. The waveform has two parts:

  1. cosine sweep down, followed by flat part at -1

  2. cosine sweep up, followed by flat part at +1

At the end of (2), sync signal is output.

Clip (0-1) controls the proportion of flatness to sweep length in each segment.
Skew (-1 to +1) controls the proportions of segments (1) and (2) in the waveform cycle.

If skew < 0, part (1) is shorter, if skew > 0, (1) is longer than (2)

Classic waveforms have simple values:

  • sine: clip=0, skew=0

  • saw(like): clip=0, skew=+1 or -1 (left- or right-facing)

  • square: clip=1, skew=0

  • pulse: clip=1, skew=+1 or -1

Fractional values generate intermediate waveforms.

asyncin

Hardsync input (asyncin >= 1) makes the waveform quickly sweep to end by raising frequency to 2 * sr/iMinSweep. Sync pulses are thus sharper than the pulse waveform.

iMinSweep

The waveform is bandlimited by always using a minimum number of samples for cosine sweeps, even when clip/skew are at extreme values. This is controlled by iMinSweep. Since iMinSweep is counted in samples, the waveform output is dependent on samplerate, but the spectrum will be very similiar independent of sr. Default sr/3000 is fairly "soft", the actual values are 14 samples at 44.1K, 16 at 48K, 32 at 96K etc. iMinSweep is counted in integers, although not strictly necessary.

If several units of squinewave are run in unison, it is recommend to use different iMinSweep values. The min sweep value creates "dips" or quieter areas in the overtone series. By using slightly different min sweep settings, spectrum is filled, rather than emphasizing the spectral profile.

Notes

squinewave is based on cosine instead of sine to generate the waveform. (This simplifies the controlling logic.) The difference is that cosine cos(0) = 1, whereas sin(0) = 0. This means that hardsync occurs when waveform is at peak, just about to enter its down sweep. (Sinewave hardsync would occur at a zero-crossing)

Tip

The length of hardsync sweeps allows chain syncing several squinewave units, creating staggered hardsync pulses.

Pitch stability

Note that iMinSweep and shape limits the ability of squinewave to match frequency exactly. When skew or clip is active, and FM is applied, the squinewave waveform will be longer or shorter than the exact period. The differences even out however, so with symmetric FM, squinewave drifts back to match average frequency. Sinewave unshaped signal (clip=skew=0) matches poscil output to 7-8 significant digits (also under FM).

Initial phase

Setting initial phase is useful if squinewave is used as a shaped LFO. Init phase is split into 4 segments with symbolic values range 0-2, so it will start at the expected place regardless of skew/clip values. 0-1 represents the first part, 1-2 the second. Some interesting iphase segment values are:

  • 0 - start of 1st sweep down.

  • 0.5 - end of down sweep (start of "low" flat section).

  • 1 - midpoint, end of 1st flat section, start 2nd, "up" sweep

  • 1.5 - end of up sweep, (start of "high" flat section)

  • 0.25 and 1.25 are 0-crossings at middle of down/up sweep sections.

  • 0.75 and 1.75 are middle of low/high flat sections.

If iphase < 0 (skip) at first use, initial phase is set to 1.25, ie 0-crossing of the "up" sweep. This makes output look like a sinewave.

Examples

Here is an example of the squinewave opcode. It uses the file squinewave.csd.

Example 1003. Example of the squinewave opcode.

See the sections Real-time Audio and Command Line Flags for more information on using command line flags.

<CsoundSynthesizer>
<CsOptions>
; Select audio/midi flags here according to platform
-odac      ;;;realtime audio out
;-iadc    ;;;uncomment -iadc if realtime audio input is needed too
; For Non-realtime ouput leave only the line below:
; -o sqrt.wav -W ;;; for file output any platform
</CsOptions>
<CsInstruments>

;#################################################
0dbfs = 1.1
nchnls = 2
ksmps = 100

; aSyncin, FMod for instr 2
gafmod init 0
gasync init 0

; Modulator squinewave
instr 1
    ; freq start, end
    acps  line  p4, p3, p5
    ; shape start, end
    aclip  line  p6, p3, p7
    askew  line  p8, p3, p9

;  ar, async   squinewave   aFreq , aclip, askew [, asyncin, iMinSweep, iphase]
    aout1, gasync   squinewave  cpsoct(acps), aclip, askew, 0, 17

	outs1 aout1

	gaFMod = aout1
endin


; squinewave using gaFMod and gasync input from i1
instr 2
    ; freq & shape start, end
    acps  line  p4, p3, p5
    aclip  line  p6, p3, p7
    askew  line  p8, p3, p9

    aFMindex line  p10, p3, p11
	asyncin = gasync * p12
	afreq = cpsoct(acps + aFMindex * gaFMod)

;  ar  squinewave   aFreq, aclip, askew [, asyncin, iMinSweep, iphase]
    aout2  squinewave   afreq , aclip, askew, asyncin

	outs2 aout2
endin


</CsInstruments>
<CsScore>


; First part instr 1 hardsyncs instr 2 (p12)

;          p4=fund   clip     skew 
i1 0  1.  6.11 6.06  0   1    -1  +1
i1 +  1.  pp5  2.03  pp7  0   pp9  0
i1 +  1.  pp5  7.11  pp7  .8  pp9 -.8
i1 +  2.  pp5  8.11  pp7  .2  pp9  1
i1 +  .5  pp5  6.05  pp7  .5  pp9  -.6
i1 +  2.5 pp5  6.05  pp7  1   pp9  1

;          p4=fund   clip     skew      p10=FM    p12=sync
i2 0  .5  1.08 2.06  0   .3   -.5  +.5  0     0   1
i2 +  .5  pp5  4.03  pp7 .5   pp9  -.6  pp11  .   .
i2 +  .5  pp5  5.11  pp7 1    pp9   .5  pp11  .   .
i2 +  .5  pp5  6.01  pp7 .8   pp9  -.5  pp11  .   .
i2 +  .5  pp5  2.11  pp7 .1   pp9   .3  pp11  .   .
i2 +  .5  pp5  3.11  pp7 .8   pp9  -.8  pp11  .   .
i2 +  2.  pp5  4.00  pp7  0   pp9   0   pp11  .   .
i2 +  3.  pp5  3.00  pp7  .3  pp9   1   pp11  .   .


s  ; End section, reset clock

; Second part instr 1 outputs FM for instr 2 (p10, p11)

;          p4=fund   clip     skew 
i1 0  1.  6.11 6.06  0    1   -.3  +.3
i1 +  1.  pp5  2.03  pp7  0   pp9  0
i1 +  1.  pp5  7.11  pp7  .8  pp9  .8
i1 +  2.  pp5  8.11  pp7  0   pp9  .4
i1 +  .5  pp5  6.05  pp7 .5   pp9 -.6
i1 +  2.5 pp5  6.05  pp7 .4   pp9  .8


;          p4=fund   clip     skew      p10=FM    p12=sync
i2 0  .5  8.08 6.06  0   .3   -.5  +.5  0     3   0
i2 +  .5  pp5  6.03  pp7 .5   pp9  -.6  pp11  2   .
i2 +  .5  pp5  5.11  pp7 1    pp9   .5  pp11  <   .
i2 +  .5  pp5  6.01  pp7 .8   pp9  -.5  pp11  1   .
i2 +  .5  pp5  5.11  pp7 .5   pp9   .3  pp11  <   .
i2 +  .5  pp5  9.04  pp7 .1   pp9  -.3  pp11  .5  .
i2 +  2.  pp5  8.11  pp7 .4   pp9   .4  pp11  2   .
i2 +  3.  pp5  8.11  pp7 0    pp9   0   pp11  3   .

e

</CsScore>
</CsoundSynthesizer>


Credits

Author: Rasmus Ekman
November 2017

New in version 6.10