Midi note to 1v/octave CV

Is there a function that will convert a midi note number to a value that can be written into one of the DACs to produce a 1v/octave CV?

Sorry, I guess I didn’t give enough information. I’m using a Daisy Patch. I’ve looked at the documentation and it seems it can output voltages in the range of 0-5V with an input of 0 giving 0V and an input of 4095 giving 5V. I guess if I can assume that the range is linear I can figure out how to map a MIDI note to a 1V/octave CV.

Check this chapter of Miller Puckette’s pure data book (pdf and online version available here The Theory and Technique of Electronic Music).

Once you’ve got the frequency you’ll need to map that to 1V/octave - that depends on what your starting frequency is, but basically you have 83mV per semitone. With your 12 bit DAC with 4095 combinations, you get about 12mV per bit.

Cheers

@dbetz , there is an inline function in DaisySP, mtof() - which does what @jaradical’s link describes, ie map midi to frequency.

You can find it in DaisySP/Source/Utility/dsp.h. An example of its usage can be found in eg the Patch/vco example.

Thanks for the info about DaisySP.mtof(). I don’t suppose there is an equivalent for converting to a CV instead of a frequency? My code is generating CV values to control other modules. It isn’t directly generating an audio output. DaisySP.mtocv() would be nice.

This is how I did it in an old Arduino project (OscDigiSeq - Arduino CV/Gate Sequencer):

// convert note number to DAC mV’s
// DAC outputs from 0 to Vcc pin voltage (+5V)
// We have 1V/Oct, so 5 octaves
int midiToCV(byte pitch) {
float voltsPerNote = 0.0833; // 1/12 V
float mV; // from 0 to 0xFFF (4096);

mV = 1000 * (pitch * voltsPerNote);

return (constrain(map(mV, 0, 5000, 0, 4095), 0, 4095));
}

I don’t remember why I had to put that constrain() function on the map() result, I probably borrowed that from somewhere! :slight_smile:

Reference to the map() function including implementation: https://www.arduino.cc/reference/en/language/functions/math/map/.

Thanks! I’ll try that.

1 Like

And for the sake of completeness (and because I am working on a project with this right now :slight_smile: ), reading an Analong in and converting it into Hz so you can set the frequency of an Oscillator:

myOscillator.SetFreq(powf(2.0f, (myAnalogInput * 3.3f)) * 55 ); // for Seed (tested)

myOscillator.SetFreq(powf(2.0f, (myAnalogInput * 5.0f)) * 55 ); // for Patch (untested)

I don’t understand where that * 55 is coming from, but it works, and you can find this in DaisyExamples/patch/PolyOsc/PolyOsc.cpp.

My guess: the 55 comes from A=440.

1 Like

I should be able to understand this connection, but alas! :slight_smile: Can you elaborate?

I really was guessing, thinking it was related to note numbers. But since it’s a conversion from an analog input, I now think it’s just a number that makes it work.

:slight_smile: But 8 * 55 = 440, so… :slight_smile:

That was what I was thinking. I’d need to think harder, or run the code, to tell if that makes the pot start at a low A.

Confirmed, ran the code: that sets the lowest frequency to a low A, and 110,220,440 are octaves (they’re all A).

1 Like

Since the example doesn’t use calibration of any sort the 55 is actually just (5V range * 12 notes per octave - 5 (a number to get it to track better)). :slight_smile:

1 Like

@dbetz, just had to implement MIDI to CV in my own project using a Daisy Seed:

uint16_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// Convert MIDI note number to CV
// DAC outputs from 0 to 3v3 (3300 mV’s)
// We have 1V/Oct, so 3+ octaves on a 3v3 system
// The DAC wants values from 0 to 4095
uint16_t mtocv(uint8_t pitch)
{
float voltsPerNote = 0.0833f; // 1/12 V
float mV; // from 0 to 0xFFF (4095);

mV = 1000 * (pitch * voltsPerNote);

return (map(mV, 0, 3300, 0, 4095));
}

Seems wasteful to do arithmetic on constants for every call. Sure, it’s a fast processor, but this isn’t necessary.

Readability over speed. Important in a forum, I think! :slight_smile:

And this is called once per note press, so no problem.