I was playing with different waveform strategies I used on analog synths to splice together a couple different waveforms into one new waveform. In an analog synth, a comparator with a voltage reference input is used to generate a trigger signal that drives a switch, often with a flip flop involved.
I put together a basic working example, turning a sine wave into a pseudo-saw that can be phase animated:
(
{
var sig, trig, ref=0.9999, out, pmRate=0.5;
sig = SinOsc.ar(30, SinOsc.kr(pmRate));
trig = (sig >= ref) + (sig <= ref.neg);
out = Select.ar(ToggleFF.ar(trig), [sig, sig.neg]);
[sig, out];
}.plot(duration:0.25);
)
This works just fine, but I’m wondering if there’s a better general approach that someone might recommend?
I do find it interesting that 0.9999 triggers only once at the peak of a sine wave, and doesn’t retrigger. I would have expected an intense burst of short pulses.
This is a great way to make interesting sounding/looking waveforms for sound or modulation sources:
I’m also wondering if there’s a way to continually log min and max values of a waveform that can be used to dynamically offset and scale it to fit a range. I feel like there must be a way to log and average min and max values, and use those for scaling, but that’s just a feeling I have. On an analog synth, splicing waveforms generally means watching an oscilloscope and tweaking an attenuverter that has a voltage offset to get the waveform to match up or sound right.
For example, in a case like this, the resulting combined waveform is within the 0 to 1 range, and would need to be offset by -0.5, and multiplied by 2 to shift and scale it to the -1 to 1 bipolar range:
(
{
var sig, trig, trigThresh = 0, out;
sig = SinOsc.ar(30);
trig = sig >= trigThresh;
out = Select.ar(trig, [sig.neg, sig]);
[sig, out, (out-0.5)*2];
}.plot(duration:0.1, minval:-1, maxval:1);
)
Is there a way to scale that without knowing the range, or hard coding the offset and amplification?
Assuming one can grab min and max values, it seems easy to derive offset and scale values. Something like:
That makes sense, thanks. I wasn’t expecting or hoping for any particular behavior, I’m just trying to get by head around the results I’m seeing and hearing compared to the analog gear I’m used to in this kind of approach.
There isn’t a Ugen equivalent for an analog voltage comparator that I’ve missed, is there?
The one thing that confuses me is why I can’t write something like:
trigger = signal > val1 || signal < val2;
it makes sense that I’m forced to mix triggers as a signal, but I think of these as logic operations:
trigger = (signal > val) + (signal < val2);
I feel like there’s a “mode” of writing from a logic standpoint that I’m missing.
I love it when waveforms really dance. Bonus points when they sound good too.
whats cool with digital audio is that you can mess with the phase instead of the amplitude of your signal. I think alot of the stuff you have been showing could be achieved with phase shaping, phase increment distortion or phase modulation, where you could work with normalized phases between 0 and 1 instead of trying to scale your amplitudes
In SC, || and && are for Booleans. There’s no such thing as a Boolean signal – only 0 and nonzero. So you have to treat “pseudo-Booleans” in the server using arithmetic operators, not logical operators.
That makes perfect sense, of course. I guess what makes it confusing is that there trigger inputs to various Ugens that presume a binary input, but, like you say, there’s no binary signal.
Thanks for the help in the thread. I was able to put together a version of what I was aiming to emulate from analog gear, which is switching between two waveforms when they level match, so there aren’t hard edges in the switch. I haven’t tested this extensively, but it seems to work.