[Ann]: squinewave~ bandlimited oscil with morphing waveform and hardsync

rasmus's icon

squinewave~ is an oscillator that morphs between sine, saw, square and pulse waveform.
Use 2 params ("Clip" and "Skew") to move freely between the waveforms.

Builds for Max7 / MacOS and Windows included in download.
Open the maxhelp or an example and check it out.

I think its mostly bugfree, but packaging and examples need improvements.

Any suggestions welcome.

I'm not sure if I need to build special 64-bit versions for OSX or Windows.
Perhaps many users are on Max 6 or 5? I could build for any of those I guess.
(I'm new to Max, not to audio programming - the code will be republished in other formats later)

Also please suggest if there are better places to publish the link.
I found some site for max objects, but it seems dead.

kleine's icon

This is very nice! But yes, 64bit builds would be lovely...

Thanks for sharing.

vichug's icon

On this c74 website, there are "tools" pages which should be appropriate to publich the link. Anyway thanks for this external ! and a 64 bits version is probably smthg that would be appreciated :)

rasmus's icon

- Small fix to hardsync.
- Added Windows .mxe64 build.

Not sure about Mac, it gives me option of building for "My Mac 64-bit" or 32-bit,
but the Product .mxo gets the same name?

I just did the default build and it (obviously) works on my macair...
Please holler if you need something else.

Thanks for suggestions.

Luigi Castelli's icon

Hi there,

great little object! Thank you.
Is the code available somewhere?
If not, could you make it available?

Thanks

- Luigi

rasmus's icon

Nice you like it.
Yes, the code will be available sometime soon, maybe a Csound opcode.
Still looking at some very minor details, possibly some optimization.

I hope it could be a standard part of any synth,
as of now it's criminal negligence to make users switch waveform by a menu or toggle button.

/re

Graham Wakefield's icon

I wonder if the code could be ported to gen~?

rasmus's icon

Ported as rewritten in gen~ notation?
I'm not sure what gen~ does with loops, if-then switches and subroutine calls etc.

The code is just some 400 lines C++, not all of it comments ;)
You'll be welcome to port it to any language later!

Graham Wakefield's icon

Gen can support loops, if-then switches and subroutine calls ;-)

rasmus's icon

Ah, after looking at the kindergarten tutorial I might understand your question. Sorry.
So,
I'm pretty sure it can be rewritten in gen~, not sure if it ends up very complex or quite simple though.
Just pasting the Csound code (if-when that appears) might also work.

brendan mccloskey's icon

"if-when" is that a Csound loop? LOL

looking forward to seeing the code

Brendan

ndivuyo's icon

Me too! Also this is crashing every time I enable my dac :(

rasmus's icon

Hi!
Do you have any more information about the crash?
Your max version, what OS are you on, a crash log, whatever.

You can also mail me directly (email at download site).
Thanks!

Luigi Castelli's icon

Hi there,

BTW it crashes here too…

The reason why I previously asked if you could make the source code available is exactly this one.
I am not bothered by the various crashes that users are experiencing. This is almost a necessary step when you release a new piece of code. However I am bothered by the fact that without having access to the source code I cannot and will not include your external in my work, even if I like it and it would be very interesting for me to use.

Let me explain:

I know that now squinewave~ is your new baby, you are all over it… if people email you with a crash and provide the appropriate information you may be able to fix the problem in a timely manner. It is fun for you, you have time for it and it is your priority. Everybody is happy.

What I am talking about is a year or two down the road when you will have moved to new projects and endeavors, and barely remember that once you wrote an external called squinewave~. Then if for any reason I experience another crash or simply the external stops working because Cycling74 has come out with a new version of Max/MSP (and every 3rd party external now requires a rewrite/recompilation to regain compatibility) then in this situation what am I gonna do? You certainly have the right not to provide any further maintenance/updates to your external since you gave it away for free with no warranty expressed or implied. So in the end I am screwed… I am forced to stop using my beloved squinewave~ external and completely restructure all my patches that were using it. Sometimes this may result in loss of features/functionality…. and always this will result in a waste of time from my part. Not good.

Sure I could ask for the source code then, but you may have lost it, you may have changed computer and no longer have it in your hard disk. A multitude of possible scenarios could arise that would not even be in my thoughts had you provided the source code ahead of time. So why not do it? I don’t care about the Csound opcode. I would like to have access to the source code of the Max/MSP external as you have released it and it seems that other people would like that too.

My point is:
I do appreciate you making your new external available to the community. I really do.
However if you want people to use your external in the long run, please include the source code for it, or at least make it available upon request.
Otherwise users will get bitten in the ass sooner or later as it happened to me a fair amount of times.

I understand that ultimately you have the right to do whatever you want with your code but I would like to invite you to at least consider my point, if you think it has some validity. Thanks for listening.

rasmus's icon

Hi Luigi,

Anything about crashes that might help me try to fix them?
OS? Max version? M4L or standalone?

You didn't mention a crash in your first post, did it come later, with some specific example, or in all kinds of use?

I understand your points. Don't worry, code will be released.
I'm guessing most users don't have a compiler, and nobody wants to chase bugs in tools they're trying to use,
so I'd like to fix them if I can only reproduce them.

/rasmus

Luigi Castelli's icon

Hi Rasmus,

you are right, it didn't crash before my first post. The crash came later.
The crash happened in some specific situation, not always.
I am on MacOS Sierra 10.12.1.
Max version 7.3.1 running in 64bit mode. Standalone.
If I am able to reproduce the crash I will send you a crashlog.

Thank you

- Luigi

volker böhm's icon
Max Patch
Copy patch and select New From Clipboard in Max.

for whoever is interested, here is a gen-version of what i believe is the basic algorithm - without fm and hardsync. especially the latter seems a little idiosyncratic in the original.

rasmus's icon

Cool, you got the behaviour right on the spot!
(the gen implementation is different, but does the same thing)

There's one tweak you may want:
Squinewave decays to pure sinewave at high frequencies (about > 2200 Hz, sample rate / 20),
the gen still tries to draw the waveform, but gets sharp corners and aliasing because there's no space for anything but a sinewave.
That's probably a simple switch to put in the code.
It seems the M4L version doesn't allow editing gen patches, so I can't fiddle with the code.

How do you mean the hardsync is idiosyncratic? Is that bad?

I looked at waveforms of some other synths (recorded analog and digital), there seem to be various ways to do it.
The squine way is to raise freq so we draw a very short sine chirp until phase wraps around to zero.
The result is a sharp but bandlimited pop.

If you don't like it I'd be very grateful to hear suggestions how it could be better!

volker böhm's icon

Squinewave decays to pure sinewave at high frequencies (about > 2200 Hz, sample rate / 20),
the gen still tries to draw the waveform, but gets sharp corners and aliasing because there’s no space for anything but a sinewave.

Max Patch
Copy patch and select New From Clipboard in Max.

right, this is an oversight, which is simple to fix.

How do you mean the hardsync is idiosyncratic? Is that bad?
...
The squine way is to raise freq so we draw a very short sine chirp until phase wraps around to zero.
The result is a sharp but bandlimited pop.

no, it's not bad.
I'm not an expert in bandlimited synthesis, but I would have expected something more like a bandlimited step (BLEP or MinBLEP or whatever) instead. you don't seem to care about the actual step size, so even if it would be a small step - lets say from 0.9 to 1.0, your algorithm swings down to -1 and up to 1. this, i think, is a little strange.
I wouldn't say the oscillator is bandlimited, but is sounds good, so who cares.

best,
vb

rasmus's icon

I would have expected something more like a bandlimited step (BLEP or MinBLEP or whatever) instead. you don’t seem to care about the actual step size, so even if it would be a small step – lets say from 0.9 to 1.0, your algorithm swings down to -1 and up to 1. this, i think, is a little strange.

Good then, thanks!

The hardsync behaviour is completely optional.
Either we ensure there's always a full pop or we just swing the shortest way to reset phase.

Both ways will sound different depending on where the waveform is when the hardsync comes.
In this version I opted to always make a full swing, to get more snappy pops.

But I don't have a strong opinion on which is best.
Actually happe to take a vote on this one -- So i consider this as your vote for the other way ;-)
Anyone else?

The non-BLEP solution is completely intentional, it should be Anti-Analog, not some fearful mimickry of old hardware with lots of low-pass filtering.
It works more like a graphical pen drawing the waveshape.

Since everything is based on sinewaves, aliasing is kept to a minimum and diminishes quickly.
The Min Sweep argument in squinewave~ constructor lets you control how low you want to cut it.

(you set it to 20, same as my default, it's trivial to make that optional)

Kasper's icon

hi just downloaded it and like it very much (actually fits perfectly my current project)

one question : what is the meaning of the argument [squinewave~ 20] in the help patch ? obviously it is not the frequency...

kasper

rasmus's icon

Nice you like it!

The constructor argument [squinewave~ 20] is Minimum sweep length, in samples.
This is how rounded the wave will be, even if you set it to square or pulse (or the "sharp" end of the saw wave). A "sweep" means a half cosine wave here.
It's the only stereo effect in the help patch. If you record some to a file and look at it close up in a sample viewer, it might be obvious.

So the narrowest possible pulse (clip=1 and skew = +1 or -1) is 2 x minsweep = 40 samps long in this squinewave. The others are default = 10 samps.

Default is 10 (so shortest pulse is 20 samps). Valid range is 4-100.
Special value 0 sets min sweep to a random value in range 8-16.

When you run several squines in unison, it's useful to have different values, because the fixed-lenght rounding creates "dips" in the spectrum, ie some frequencies are much softer, depending on min sweep and frequency.
They are clearly visible in the spectroscope once you know it.

There's detailed documentation of this somewhere, I gotta make it more visible though...

Kasper's icon

ok, thanks. so far it works nice, even if I had 2 crashes building a fairly simple patch. Not sure if it is related to the object (both times I was changing values in a M4L object)

best

kasper

rasmus's icon

Oh, but please send me the patch next time there's a crash if you can.
There were some reports before, but nobody has given me anything to go on...

Was sound playing meanwhile, or just editing?

I'm guessing it's the Max binding, I'm new to that part.

Thanks,
/rasmus

volker böhm's icon
Max Patch
Copy patch and select New From Clipboard in Max.

this popped up on the kvr forum, and might be of interest, too:

kleine's icon

Interesting - thanks for sharing, Volker...

rasmus's icon

Nice!

To avoid aliasing, I'd suggest limiting scale so it has to be positive, > ( freq*10 / samplerate ) or so.
scale near 0 causes aliasing.
Negative scale is not strictly needed, since rotation passes through the same waveshape.

(Can't do it myself since I just have M4L, but ofc easy to fix with surrounding objects)

Roman Thilenius's icon

first useful output of kvr forums in 15 years.

kleine's icon

I still wonder how sync can be achieved in the gen~ version. Any pointers?

oli larkin's icon

it's cool! it's a Phase Distortion oscillator right?