Implement worse Upsampling for more Oscilloscope-like look
s-ol opened this issue · 6 comments
Like https://dood.al/oscilloscope/, which features the best look of all simulators I know so far:
This uses an upsampling filter to simulate a digital-analogue converter between the computer and the oscilloscope. It turns sharp corners in the signal into curves, loops or ringing artefacts. If the page is running slowly, try disabling upsampling.
It uses a Lanczos kernel, the code for that is here: https://git.s-ol.nu/xxy-oscilloscope/blob/master/oscilloscope.js#L-221 (not written by me, but looks port-able).
That scope also has nice line-rendering in general, which is taken from woscope (docs here: http://m1el.github.io/woscope-how/). I'm not sure what your rendering is like at the moment, but it might be worth taking that in as well. Porting from WebGL should be pretty straightforward
hi!
oh wow... the doodal scope looks incredible, so rich of detail!
the blur is neat, but als the dynamic effect of the beam is much nicer. would be great to include some of his features here.
on the upsampling, i haven't finished it yet, but i began work on upsampling, the ofx addon is here:
https://github.com/kritzikratzi/ofxLibsamplerate/
and there is a tiny bit of code in src/util/OsciResampler.h
so there are quite a few scenarios currently supported:
- 1ch input -> channels goes to y, an x-ramp is automatically generated
- 2ch input -> normal xy mode
- 3ch input -> xy + z-modulation (dynamic intensity control, eg. derek holzer uses this)
- 4ch input -> dual xy (anaglyph 3d)
i'm not sure how to structure the resampler yet (ie should it just handle one channel, or should it be multichannel).
i'm open to suggestions ...
@kritzikratzi I guess the most important thing either way is to use SIMD-something to speed it up?
As for the channel-count: why does that matter? is it just because of channel-interleaving?
Maybe it could be single-channel with aa glVertexPointer
-style API with data, count, stride
parameters so you can do this:
- upsample single channel:
float* samples;
int sampleCount;
OsciResampler sampler;
sampler.put(samples, sampleCount, sizeof(float));
- upsample 4ch from interleaved input: (
ABCDABCDABCD
)
float* samples;
int sampleCount;
OsciResampler samplers[4];
for (int i = 0; i < 4; i++)
samplers[i].put(samples + i, sampleCount, sizeof(float) * 4);
- upsample 4ch from serial input: (
AAABBBCCCDDD
)
float* samples[4];
int sampleCount;
OsciResampler samplers[4];
for (int i = 0; i < 4; i++)
samplers[i].put(samples[i], sampleCount, sizeof(float));
that way the resampler can be optimized independently of channelcount etc. but you also dont need to copy around memory blocks to realign data etc.
As for libsamplerate: I don't know a lot about DSP, so I'm not sure if the 'Lanczos upsampling' used in the dood.al scope is 'regular upsampling' as done by libsamplerate, or if it is intentionally-inaccurate upsampling to simulate cheap DACs. I think it might be the latter, so I'm not sure if libsamplerate might make the image 'too clean'. Also the upsampling code in JS is less than a hundred lines, so I would consider just porting it and dropping the dependency if that is feasible. I'll message the dood.al creator and maybe he can advise.
leaving this untouched until the changes for the linux version are done.
one major construction site is plenty :)
leaving this untouched until the changes for the linux version are done.
one major construction site is plenty :)
agreed 😉
snippets from a conversation with Neil Thapen (the dood.al author):
I'm using basically a lanczos filter, which I expect libsamplerate can be setup to do.
I tuned it to add visually nice ringing artifacts to a square wave - as far as I remember it's not based on any deep understanding of shitty vs good DACs.
One thing is that I tweaked the lanczos function slightly, to smooth the edges of the window - this is the last line of the createLanczosKernel function. I think I had some visual artifact I didn't like, and it was either do a tweak like this, or use higher-quality parameters in the filter, which would have cost performance.
I guess that first the rendering could be ported, to make it easier to evaluate whether the libsamplerate-based upsampling looks good.
hey
oh, i actually know that libsamplerate looks good, because that's what i'm using inside oscistudio already. but i can't just copy&paste it over because it's structured very differently.
there i basically upsample to 400khz, which makes it look very similar to a normal soundcard on an analog oscilloscope.
i think what the dood.al scope does really well are quite a few other things as well, the shine around the dot, the dynamics around slower curves, the blur effect in the background... it's surprisingly realistic in many scenarios.
btw: if you message me your email i can send you a copy of oscistudio (unless you have it already).