Cabbage Logo
Back to Cabbage Site

Squinewave

hi! adapting one of my synths to be used with squinewave for interchangeable waveforms but i’m really struggling to figure out how to use it. ive been through the forum on interchangeable waveforms on here and looked through the manual but using squinewave in cabbage to change the waveform with one or two knobs is a challenge given all examples utilise p values and a rate, no idea how to use cabbageGetValue values to control this. would love some help on this or if anyone more competent could give me an example code that would be amazing. just looking to get the most basic form of a squinewave plugin running.

cheers, finn

Hi @finnlovli. Welcome to the forum. I’ve not used squinewave before, but I assume you can just cast the cps, clip and skew parameter as k-rate:

aout squinewave a(p4), a(kClip), a(kSkew)

where p4 is the incoming frequency, and kClip an kSkew are sliders.

1 Like

Hi Finn, another possible implementation might be something like this:

<CsoundSynthesizer>
<CsOptions>
 -odac
</CsOptions>
<CsInstruments>

sr = 48000
ksmps = 32
nchnls = 1
0dbfs  = 1

instr 1
  kCps  = 220
  aCps  = upsamp(kCps)
  kWaveform = linseg:k(0, 8, 1)
  aClip = bpf:k(kWaveform, 0, 0, .5, 0, 1, 1)
  aSkew = bpf:k(kWaveform, 0, 0, .5, 1, 1, 0)
  kPW   = linseg:k(0, 10, 0, 3, 1, 3, 0, 3, -1, 3, 0)
  aSig  squinewave aCps, aClip, limit:a(aSkew + kPW, -1, 1), 0
  outs aSig
endin 

</CsInstruments>
<CsScore>
i1 0 22
</CsScore>
</CsoundSynthesizer>

The kWaveform & kPW values would be sliders (instead of the linsegs). The kWavform slider should have a range of 0 to 1; as you raise the value the waveform will morph between sine (0), then saw (.5), and finally square (1). The kPW slider should have a range of -1 to 1 with the default being in the center (0).

In this example the waveform will go from sine to saw to square, then sit there till the end. After 2 seconds there is PWM of the square wave.

Haven’t tested it with sliders though.

Obviously everyone’s different but you might find this a more intuitive way to handle things.

Hth,
Scott

1 Like

Good idea to pass the k signals through some kind of filter. That will definitely give better results than the crude casting I suggested :+1:

The ‘Air Raid Siren’ example in ‘Fun and Games’ uses squinewave. It also prints it to a gentable so you can see what the waveform looks like. The three controls pertaining to its shape are Clip, Skew and Rounding. Rounding is i-rate so it will always produce discontinuities when it is adjusted. I just converted clip and skew to a-rate using a() and it seems pretty smooth although a portk before that could also be considered. When you use a() it applies linear interpolation to get it up to a-rate so this provides some smoothing (not just crude!).

Hi Rory. Actually bpf isn’t a filter, it performs a break point function with interpolation.

A sine wave is Clip=0, Skew=0. Saw is Clip=0, Skew=1 (or -1). Square is Clip=1, Skew=0.

By using the two instances of bpf, when the kWaveform slider is at 0, Clip=0, Skew=0. As the slider moves to .5, Clip stays at 0 but Skew gradually interpolates to 1. So it morphs from a sine to a saw. Then as kWaveform moves from .5 to 1, Clip interpolates from 0 to 1 while Skew interpolates from 1 back to 0, so it morphs from the saw to a square.

This gives the typical emulation of a hardware synth where you turn a knob and it morphs from sine to saw to square, the two bpf opcodes do the necessary adjustments.

It’s (to me) much more efficient than trying to manipulate two different sliders (“knobs”, clip & skew) simultaneously to achieve the same result.

When the kWaveform is a square (value of 1), modulating the kPW (skew between -1 & 1) gives PWM. If kWaveform is .5 (saw) then modulating the skew from 1 to -1 shifts the saw from left to right facing (sloped up vs down).

1 Like

Whoops, I always make that mistake. I assumed you were just smoothing the signal, but anyway, if that was the case you would hardly have used a bandpass filter. Ok, I’ll return to my room now while the grown-ups discuss how best to make this work… :rofl:

Lol, I’ve made the same mistake before, maybe the opcode should have been called bpfunc to avoid confusion. But your response made me think maybe I should elaborate on the purpose of the bpf for others who might look at the ex. (thanks to Jeanette C. for turning me on to how useful the bpf can be). And you insulted my inner child but I won’t hold that against you :stuck_out_tongue_winking_eye:

1 Like