# Can someone help me convert pitch CV to "sample increment"?

My brain is tired and I could use some help on a fairly easy conversion. I’m trying to properly calculate sample playback rate based on the 1v/octave standard.

``````double sample_position = 0;

void process(const ProcessArgs &args) override
{
double sample_increment = getSampleIncrement(pitch_cv_input, wav_sample_rate, rack_sample_rate)
sample_position += sample_increment;
}

double getSampleIncrement(float pitch_cv_input, float wav_sample_rate, float rack_sample_rate)
{
// Here's where I'm hitting a mental block.
// I assume that I need to use f=f0 * approxExp2_taylor5(voltage),
// where f0 = dsp::FREQ_C4
// so maybe f = dsp::FREQ_C4 * approxExp2_taylor5(pitch_cv_input)
// but then, how would I convert "f" to the increment?
//
//
// in other words:
double sample_increment = 0;
double f = dsp::FREQ_C4 * approxExp2_taylor5(pitch_cv_input);
// ?? Somehow use wav_sample_rate and rack_sample_rate to calculate sample_increment
return(sample_increment);
}
``````

Thanks!

I did this in my module TapeRecorder. Just search for `tapeSpeed` and `SPEED_INPUT` in the following source code:

Ah, thank you! Let me walk through your code really quickly, just so I understand:

``````/*
Here, you are multiplying sampleTime (which is typically around 1/sampleRate,
but fluctuates) * sample rate.  I think that your comment of 1.f is
suggesting that this is normally around 1.0.
*/

tapeSpeed = args.sampleTime * args.sampleRate;//1.f;

// The next code that's important to me is in processSpeedInput(args):
tapeSpeed *= exp2(inputs[SPEED_INPUT].getVoltage());

// You have other code that modulates the tape speed,
// but that's not so important to my situation.

// And finally, you have
audioBufferPosition += tapeSpeed;

``````

So if I were to wrap that up into a function, it would look like:

``````double getSampleIncrement(float pitch_cv_input, float sample_time, float rack_sample_rate)
{
sample_increment = sample_time * rack_sample_rate;
sample_increment *= exp2(pitch_cv_intput);

return(sample_increment);
}
``````

I can give that a shot! However, in addition, one thing that I need to know is how to take the .wav file sample rate into account. Would that be something like this?

``````double getSampleIncrement(float pitch_cv_input, float sample_time, float rack_sample_rate, float wav_sample_rate)
{
sample_increment = (sample_time * rack_sample_rate) * (rack_sample_rate / wav_sample_rate);
sample_increment *= exp2(pitch_cv_intput);

return(sample_increment);
}
``````
1 Like

I think there’s no need to calc `args.sampleTime * args.sampleRate` because it should always be `1.f`

I think your formula should work with .wav files with different sample rates.

Thanks a ton. My function collapsed down to:

``````// pitch_cv_input should range from -1 to 1 for 2 octaves,
// -2.0 to 2.0 for four octaves, -3.0 to 3.0 for six octaves, etc.

double getSampleIncrement(float pitch_cv_input)
{
return(step_amount * exp2(pitch_cv_input));
}
``````

I compute `this->step_amount` only when the sample rate changes, using code like this:

``````void onSampleRateChange(const SampleRateChangeEvent& e) override
{
step_amount = wav_sample_rate / APP->engine->getSampleRate();
}
``````

So far, so good!

1 Like

especially now that ppl seem to be doing better sample rate conversion than drop/add sample.