Hi folks. I’ve been working on a tremolo effect and I’d like to use a square wave without the nasty ticks and clicks that Oscillator::WAVE_SQUARE and Oscillator::WAVE_POLYBLEP_SQUARE produces at extreme “depths”. I want to just slightly round off the sharp corners of the square wave, (i.e., temporal filtering, Bessel or Gaussian filters, etc.)
Here’s a bit of MATLAB code that demonstrates, where A=amplitude, f=freq, and delta sets the amount of “rounding”:
t = linspace(0, 2*pi, 500);
A = 1;
f = 1/(2*pi);
deltas = [0.1, 0.01, 0.001];
colors = {'r-', 'g-', 'b-'};
figure; hold on;
for i = 1:length(deltas)
delta = deltas(i);
y = (A/atan(1/delta))*atan(sin(2*pi*t*f)/delta);
plot(t, y, colors{i}, 'LineWidth', 2);
end
legend('Delta 0.1', 'Delta 0.01', 'Delta 0.001', 'Location', 'SouthOutSide');
axis tight; axis square;
set(gca, 'FontSize', 15); grid on; box on;
drawnow;
Well, if anyone is playing along at home, I simply extended the Oscillator class with my own ExtendedOscillator. I added WAVE_SQUARE_ROUNDED to the enum and added this case to port my MATLAB code:
case WAVE_SQUARE_ROUNDED:
delta = 0.07; // Seems to handle discontinuities nicely @ 48kHz
out = (amp_ / atanf(1.0f / delta)) *
atanf(sinf(2.0f * PI_F * phase_) / delta);
break;
This works a treat for a tremolo effect. No clicking or ticking and it still sounds like a square wave to my ears. It also sounds fantastic in harmonic tremolo mode with the cutoff frequencies of the high and low bands somewhat wide (e.g., 1500Hz and 600Hz, respectively.)
Here’s the waveform in MATLAB (or Octave if you’re so inclined):
t = linspace(0, 2*pi, 500);
A = 1;
f = 1/(2*pi);
delta = 0.07;
color = 'r-';
figure;
y = (A/atan(1/delta))*atan(sin(2*pi*t*f)/delta);
plot(t, y, color, 'LineWidth', 2);
axis tight; axis square;
set(gca, 'FontSize', 15); grid on; box on;
drawnow;
If you want to experiment with different levels of “rounding”, change the value of delta. Lower values = less rounding. 0.07 works well for my application.
@tele_player Possibly so; I’ll submit and see what happens. On the other hand, it’s fairly easy for any hacker to implement and seems sorta niche, maybe? Let’s see.
@KnightHill I’m not so sure. As far as I know (see above - I’m about a month in to this DSP thing), there are many types of low pass filter. For example, while doinking with this, I found that a single-pole LPF basically results in the familiar “shark fin headed west” wave form. No other LPFs that I tried yielded what I was looking for. This basic trigonometry gave the desired results, but there may very well be other / better ways to make the magic happen.
It’s probably more accurate to call it a distorted sine wave than filtered square wave — although, since it’s all odd harmonics, there is some filter you could apply to a square wave the yields this shape.
DaisySP implements a “bandlimited” square oscillators — an approximation of a square wave by finitely many harmonics — whose waveform might not look quite as similar in shape to a classic square, but sounds very similar.
That is my understanding as well. It’s a sine wave shaped by the arctangent function.
The WAVE_POLYBLEP_SQUARE waveform in DaisySP does not work for my application: it ticks and clicks like mad and I found this solution before I found a filter that yielded anything close to this shape.
Just a quick follow-up re: filters after a square wave. Clearly not an exhaustive list of options, but after spelunking in a few source texts, I just resorted to the distorted sine wave approach.
Have you tested these for aliasing? usually above 1khz you’ll start to see any issues. If they do alias - it’s probably ok to use them as LFO’s but not raw OSC’s as long as they don’t push ur src OSC’s> -60db harmonics into reflection et…c.
Good point. The waveform suggested early in the thread — and then what was implemented — is intended for tremolo applications below 18Hz or so. Definitely LFO territory.
yeah I had a quick bash with it in reaper - it aliases around 1200hz, you could oversample to get rid of that if you wanted - but it’s fine for LFO. Why didn’t you use tanh instead of atan - tanh is perfectly suited since it’s range is -1 1?
Here’s the reaper jsfx code - just fire up before a EQ or FFT after it - both have a spectrum display.
Honestly, no reason other than the delta value felt more intuitive to me at the time. One could use either, but I got anchored on the atan approach by some interwebs fodder I found (linked above.)
If you’re doing R&D or just tinkering in DSP - reaper JSFX is the only thing to use, it will save you a ton of time - it’s soo fast in execution and instant compilation.