Hard Oscillator Sync w Audio Library

Status
Not open for further replies.

jonbearr

New member
Hey all -

I'm trying to figure out how to use the audio library to "hard-sync" two oscillators. To me, this means that the phase of one oscillator will be programmatically reset to 0 with the period of the other. Many of the "synth" objects have a phase field, but I am struggling to determine a good way to utilize it in this context. For those familiar with Pure Data, having some sort of "bang" occur to reset the phase to 0 once per cycle would be ideal; perhaps I'm too locked into this way of thinking to find another solution.

Things I've thought of so far:

With explicit knowledge of the two oscillator frequencies, I have thought of using some sort of counter to reset the phase once the specified period has elapsed, but this seems kludgy at best, and all the counters I know of only have 1ms resolution, which means this solution is unworkable for frequencies above 1kHz.

I considered using the PWM waveform as well. It also seems ill-advised, but an idea that crossed my mind was to set the duty cycle to be extremely uneven (let's say 1 sample high and the rest low) and use peak-detection to trigger the phase-reset when the high value comes along once per cycle. This seems more workable than my first solution, but I'm craving a way to more directly link the phase-reset to a known period.

Thanks in advance for your input!!
- Jz
 
The first thing to know is that audio is processed in blocks of 128 samples. So if a phase reset needs to occur in the middle of a block, let's say, it won't be possible to reset the phase until the end of that block. So that will cause jitter in the resets, and it's hard to really know how bad or annoying that jitter will be.

Let's take a look at some of the oscillator code: https://github.com/PaulStoffregen/Audio/blob/master/synth_waveform.h (and .cpp)

The member phase_accumulator is responsible for tracking where the oscillator is, phase-wise, and that's the one you'll need to reset. So, I think you could do something like:
* Add logic to each oscillator to detect the end of it's period. I guess you could do this by tracking the phase.
* Add a flag to the oscillator class, let's say it's a boolean called endOfPeriod. In synth_waveform.cpp, look at your phase, and every time your phase wraps around, set endOfPeriod to true.
* Make phase_accumulator a public member so that it can be reset.

Then your application code would need to do the syncing. Maybe something like this:
Code:
void loop() {
    // ... synth code here ...

    if(osc1.getEndOfPeriod()) {
        osc2.setPhaseAccumulator(0);
        osc1.setEndOfPeriod(false);
    }
    // ... more synth code here ...
}

Of course... I'm probably overlooking some details that will make it a little trickier than I'm showing here. But I think it's possible as long as you are comfortable hacking the audio library. If the jitter of the resets is too bad, you can actually decrease the block size from 128 samples down to let's say, 32 samples. It should be possible but I have never tried it. Anyway good luck, hope that helps.

Edit: I should say, a more elegant way to do this is certainly possible. I can imagine adding a sync output and a sync input to the oscillator class, that way you would wire up the syncs in the GUI editor, and not need to do the syncing in your application code. That sort of solution would also come with the benefit of possibly eliminating the jitter entirely.
 
Last edited:
The most reliable approach would be to make one oscillator class that has multiple oscillators within the one class. That way, you can do any combination of hard sync, soft sync, or cross-mod that you'd like.

The alternative proposal (made above)of adding a sync input and output to the existing oscillator class is a good one. But, due to how the audio library works, there is no guarantee that the different instances of the oscillator class will get called in the order that you expect them to. The order that they get called all depends upon the order in which you create the audio_connection patch cables. So, most of the time, it'd probably work great. But, once in a while you might get sloppy, and you might make a small change to your code (adding or removing or reordering an audio connection) that causes the underlying audio library to call the audio objects in a slightly different order. Because sync and cross mod are highly dependent upon timing, you might unexpectedly just changed how it sounds, which will be confusing and annoying.

It's to avoid this condition that is why I suggested a single multi-oscillator class. When you've got it in one class, you know the sequence and timing of all of the interactions between oscillators will be exactly what you want.

Chip
 
Status
Not open for further replies.
Back
Top