I have a few technical questions about AnalogOscillator::RenderSaw from the Braids codebase:
1. I see sync is quantized to samples. Why is that ok as opposed to calculating the zero-crossing via interpolation?
2. Why is the de-phased saw wave reset to zero when synced as opposed to the phase offset determined by parameter_?
3. Why is the blep scale determined by the previous sample value as opposed to the actual size of the discontinuity of the waveform? (When I use the previous value I get quite a bit of aliasing in my own implementation)
4. When the two saws are fully de-phased, the waveform is only half as tall, but then transitions to a full height sine wave for high frequencies. Is that ok?
1. I can’t do better because the sync data comes from a digital input; so my input samples are either 0 or 1 and I can’t interpolate anything from that.
2. You could do that too. Does it impact the sound much?
3. I’ll try your suggestion and report. You’re suggesting using previous_sample - (phase_ >> 18) as a blep amplitude, right?
4. The sine is at half height.
1. Got it. What about the case of MacroOscillator::RenderSquareSync where you are running the master oscillator as well?
2. I’ll report back! I haven’t done a lot of testing of the interaction between sync and the de-phasing yet.
3. Actually, no. The difference between successive samples isn’t the size of the discontinuity. My implementation is floating point [-1, 1], so, without any de-phasing, the blep scale of a wrap discontinuity is always 2. I calculate the scale for sync separately using the values at the linearly interpolated sync point. I’m not sure how to combine wrap and sync discontinuities into a single AddBlep without using the approximation in your code.
4. Ah, ok. But shouldn’t the sine gain depend on parameter_?
5. Where does the code subtract from the phase when it wraps? I can’t seem to find it. :-\\
1. I could do it for the double square indeed, but I’m not, so that I can reuse the code. That’s a nice suggestion!
3. You lost me here, I’m not sure what’s the issue then?
4. Yes, we could simulate the drop of gain depending on the dephasing, but the effect is not that big.
5. The phase counter is an integer, so it wraps around “automatically”.
Out of curiosity, why are you using minBlep anyway? I actually plan to rewrite all this old code using polyBlep! I have some code if you want to play with it…
3. I drew a picture
The code already places the blep at the correct phase, but not the correct scale, as far as I can tell. Does that make sense?
5. Oh of course! I haven’t done any fixed point stuff :-\\
Re polyBlep: I have been thinking of trying polyblep with some oversampling. Polyblep would alias too much at 44.1, right? Anyway, it really isn’t much different from my current implementation, which accumulates bleps into a circular buffer (as opposed to maintaining an array of active bleps like the braids code), so it should be easy to try.
@pichenettes, I forked your polyblep code and added a saw sweep test. At 96kHz, I can’t hear any aliasing. I can hear some at 44.1 as the sweep gets high (around 10k).
Have you tried scaling the samples by 0.9 before writing them? Yesterday I was having an issue with an audio clip that sounded aliased while the spectrogram showed it shouldn’t - and it turned that my audio interface (or OS X, or audacity) did not like the fact that the file had so many samples hitting -32767 / 32767.
@pichenettes, if Audacity is to believed, all samples are within range. In fact the polyblep waveform decreases in amplitude as pitch increases. Should that be compensated for?
Here’s a comparison of aliasing between the polyblep and minblep via spectrum plots. As expected, the polyblep aliases a lot more, but I really don’t know what is an acceptable level of aliasing.
Also, polyblep just seems like minBlep with a size two table. Is that wrong? Is there something special about the polynomial interpolation functions?