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
  // read inputs and stuff
  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


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);


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);

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.