Please consider registering

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —

— Match —

— Forum Options —

Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed sp_TopicIcon
Dealing with subsamples
No permission to create posts
May 19, 2015
1:25 pm
Forum Posts: 23
Member Since:
December 21, 2014
sp_UserOfflineSmall Offline

Hi Will,

With respect to your code, I want to process the subsamples (as in the case of hard sync where I process two discontinuities separately in the slave osc)

float doOscillate {
y = doSawtooth(m_dModulo, etc)
// -- advance phase by some subsamples
m_dModulo += subsamples
y2 = doSawtooth(m_dModulo, etc)

return dOut = y + y2 ? // <---- how do I take care of this? What should be the correct way to get dOut?
Thanks. Hope you understand what I'm trying to say.

May 19, 2015
6:53 pm
W Pirkle
Forum Posts: 143
Member Since:
January 28, 2017
sp_UserOfflineSmall Offline

Hi Pier

Actually, not sure what you are trying to say, but the above code is not hard-sync. It appears to just mix two sawtooth waveforms, but by modifying the modulo counter, it will screw up the first oscillator.

The way I implemented it was to add a second modulo counter (m_dModulo2) to the oscillator object. The second modulo is the master, while the first (ordinary one) is the slave. The second modulo counter has its own wrap-code and m_dFo2 (a second oscillator frequency) so it is like having two oscillators in one object. I did this so the two oscillator objects would not need to hold pointers to each other since the master must reset the slave.

Not considering the double-correction issue, you will need to call the BLEP function under two circumstances - the normal sawtooth (height = 1.0) or the discontinuity that arises from the reset operation, in which case you need to calculate the height of the second discontinuity. If using 2-point BLEP, you will also need to know when a reset is pending - i.e. lookahead two sample periods.

My advice would be to get hard-sync running without any BLEP correction at all, which is what it looks like you are doing. You can verify the output using the RAFX analyzer in SCOPE mode (or if using VST3/AU there are oscilloscope plugins out there to use).

Then, get it working with only the normal BLEP correction - one for the regular discontinuity and one for the reset discontinuity. This will work for low master fo and low slave fo. Then, work on the multiple-correction issue we've discussed in other threads.

My code for the basic version looks like this (there are my approaches here - mine is not the sole answer, and it also can be done with two oscillators rather than one). The input variable bWrap is set by the calling function when the master oscillator has rolled over (ie it is the reset command). Also, I show how to use 2-point polyBLEP() which is easier to deal with than N-point BLEP. Once working, you can change it to whatever BLEP you want.

The checkWrapModulo2() function is just like the book code, only using the second modulo counter.

double CXYZOscillator::doHardSyncSaw(bool bWrap)
double dOut = 0.0;

// reset detection - only used for BLEP
bool bResetPending = false;
bool bReset = false;

// detect if reset is occurring now - only used for BLEP
bReset = true;
// detect if reset will occur on the NEXT sample period
else if (m_dModulo + m_dInc >= 1.0)
bResetPending = true;

// do the modulo wrap on slave osc

// calculate the ratio
double dRatio = m_dFo2/m_dFo;

// move the slave modulo to the master location scaled by height
m_dModulo2 = dRatio*m_dModulo;

// unipolar to bipolar
double dTrivialHS = unipolarToBipolar(m_dModulo2);

/* un-comment this out for BLEP
if(bReset || bResetPending)
// height of transition
double dHeight = 1.0;
if(dRatio - (int)dRatio > 0)
dHeight = dRatio - (int)dRatio; // scale the height

// use the master modulo because it is ultimately responsible for the
// transition location scale by height of discontinuity
dOut = dTrivialHS + dHeight*doPolyBLEP_2(m_dModulo, m_dInc, dHeight, false);
else // test for the normal PolyBLEP transition
dOut = dTrivialHS + doPolyBLEP_2(m_dModulo2, m_dInc2, 1.0, false); // height is 1.0 for normal saw

return dTrivialHS;
// return dOut; <-- for BLEP only


Hard Sync is not trivial to implement.

May 20, 2015
7:54 am
Forum Posts: 23
Member Since:
December 21, 2014
sp_UserOfflineSmall Offline

Hi Will,

Thanks... it's an interesting way of implementing it. I'll look into it.
What I'm trying to ask in the above pseudo code is how do I sum up 2 calculations within a sample.
Here's how I try to do HS.

In the master oscillator, if it wraps,
subSamplesToHS = (m_dModulo) / m_dInc; // -- number of subsamples after master has wrapped

So in the slave I do this at the end of the doOscillate() in the same sample calculation

y = dSawTooth (m_dModulo ...) ;

if (doReset) { // -- doReset being an indication from Master that it has wrapped
m_dModulo = 0.0f + subsamplesToStartFrom * m_dInc; // -- increment slave modulo to the same amount at this point of time

However, what if I know that my slave is supposed to wrap in this sample, and shortly after it is triggered by master's doReset (within the same sample) ?
In this case, I have to calculate sawtooth / blep 2 times , right? How would I handle this situation?
Simplistically I know I can just do within the sample:
(1) normal slave calculation as per no master reset happened
(2) calculation with master reset happening (doReset as per above)

How do I combine (1) and (2) ? Is it a simple add?

May 20, 2015
7:57 am
Forum Posts: 23
Member Since:
December 21, 2014
sp_UserOfflineSmall Offline

Separate question :
(1) Why do you check for bResetPending in your code?
(2) Also what does "if(dRatio - (int)dRatio > 0)" actually indicate in theory?
(3) To clarify, there is still an external real master oscillator that provides the bWrap into your doHardSyncSaw function, right?
(4) In your code it seems that m_dModulo2 is for the slave, m_dModulo is for the master, contrary to what you said?

Many thanks.

June 3, 2015
8:53 pm
W Pirkle
Forum Posts: 143
Member Since:
January 28, 2017
sp_UserOfflineSmall Offline

Hi Pier

Sorry for the delayed reply, lost track of the thread.

First, in my implementation there is only one oscillator object; it has two independent modulo and inc variables, so it is really like two oscillators in one. I did this so I would not need to connect two oscillators via pointers and deal with them individually, but you could certainly take that approach.

if(dRatio - (int)dRatio > 0) finds the fractional portion of dRatio. This is how you can calculate the height of the reset-discontinuity. You need the height for the BLEP algo to work.

Yes, I was reversed on the modulo vs modulo2 in the post above - you are correct.

In my version, I am only doing 2-point BLEP correction, one on each side of the discontinuity. You have to lookahead and check to see if a reset will occur on the *next* sample interval so you can correct it prior to the reset event - if you don't, you will miss the event. For 4-point-per-side correction you would have to look further ahead.

The multiple-BLEP issue occurs when you need to correct a point for being on "both sides of a discontinuity" which occurs then two discontinuities occur within your 'transition region' (that is Valimaki's term). If you are doing 4-points per side, then anytime two discontinuities occur within that 8-sample transition region, they will need multiple BLEP corrections.

When using 1-point per side correction, this will happen when the two discontinuities are 2-samples apart. So for example, you are correcting a point on the right side of the normal discontinuity, but that point is also on the left-side of the reset discontinuity. So, it needs to be corrected first as the right-side point with height = 1, then again as the left-side point with the height you calculate from the ratio equation.

The Korg patent uses a delay line to accomplish this. To simplify, I use Valamaki's method of doing the lookahead in the BLEP function itself.

- Will

Forum Timezone: America/New_York

Most Users Ever Online: 36

Currently Online:
5 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Skyler: 47

Peter: 41

Derek: 41

clau_ste: 39

Frodson: 38

Gwen: 32

EZB: 24

lppier: 23

Msaldaña: 18

Jorge: 17

Member Stats:

Guest Posters: 1

Members: 477

Moderators: 1

Admins: 4

Forum Stats:

Groups: 11

Forums: 30

Topics: 483

Posts: 1877

Newest Members:

Jaggxn, sam, annaharris, Marie Weaver, kev, Steven, Mr Anderson, mguy, omelc

Moderators: W Pirkle: 143

Administrators: Tom: 65, JD Young: 80, Will Pirkle: 0, W Pirkle: 143