Converting Hz to CV
How to, Math, Lua, and Culture
Gahlord Dewald :: 11/28/22 :: Bogliasco, Italy
In this article, I'm going to take my time writing about how to make some Lua code that converts Hz to volts. Feel free to skip to the code examples.
While developing The Timbre of Starlight, I was faced with a challenge: how to transform frequencies measured in Hertz (Hz) into control voltage (CV) measured in volts (V).
What appeared to be a simple task required me to learn more about linear and logarithmic measurements. For the project to work, the conversion system needed to be accurate to the science aspects, functional for the synthesizer technology to work properly, and flexible enough to adapt to different creative and cultural practices.
The Eurorack system I assembled for the project is built around a few crow modules which are manufactured by the small music technology manufacturer monome. These crow modules can send and receive CV. They can also process Lua scripts. For this reason, the code examples in this article are in Lua. Fortunately, Lua is a fairly readable scripting language so you can adapt the examples however you like.
In order to develop this code, I'm going to briefly describe technical system for controlling (mostly analog) synthesizers, the scientific measurement systems of sound, and how these collide in cultural and creative practices. All of these will have to be balanced and accounted for in the equations I use in the project.
Most analog synthesizers use control voltage to set and animate things like the frequency of an oscillator. Control voltage is measured in volts and is most commonlyThere is another CV standard called Hz/V, used in Korg MS and Yamaha CS synthesizers, which I won't cover in this article, you'll need entirely different math for that. tuned so that adding one volt of current results in a frequency that we hear as one octave higher.
This standard, referred to as volt per octave (V/OCT), is linear; changing the voltage by 1/12 of a volt will change the pitch by a semitone in all octaves. It's a very handy method of controlling synthesizers: adding or subtracting one or two volts can quickly change the register of the instrument.
For the system I am building (and probably the system you are building as well), it's important to know precisely which pitch and what frequency is being called at zero volts (0V), the lowest pitch available to the synthesizer. The Hz at 0V will determine the base tuning of the instrument, which I discuss more below.
Frequency is measured in Hertz (Hz). One Hz is one wave cycle per second. If sound waves hit our ear at 30Hz we would perceive a quite low pitch. If they changed to 60Hz we would perceive the pitch to be one octave higher than the first pitch. And at 120Hz we would perceive the pitch to be two octaves higher than the first pitch. The Hz is doubling for each octave.
You may have noticed that Hz is a logarithmic measurement: changing octaves requires multiplying or dividing frequency by two. But CV, described above, is a linear measurement: changing octaves requires adding or subtracting whole volts. It's these two different ways of measuring that makes converting between Hz and volts tricky.
Musical Notes, Cultural and Creative Practices
On top of the measurement issues above, there are cultural and creative practice concerns to navigate.
Letters, Octaves, Semitones
A fair amount of music from the past couple hundred years, and nearly all pitch-senstive music technology, maps to the letter scale of Western European derived music theory. In this system, letters A through G each indicate a different tone and repeat as they go up or down octaves. Some of these tones can be altered a little bit up or down. As a result, even though there are only seven letters, there are 12 semitones in an octave. To make things even more squirrelly, octaves are measured from one C to the next C, not from A to A.
As you can see, not much of this makes a whole lot of sense. This is cultural practice. We agree to do it this way because we've been doing it this way for so long.And as a result we've built most of our musical tools around this way of thinking which further encodes the cultural practice into a specific technological limitation/affordance.
Because of the focus on C as a starting note, it's practical to place a C at specific landmarks in a musical instrument. Being able to find "middle C" is an important skill for any beginning piano player, for example.
With an instrument that is manipulated via control voltage, 0V is that landmark. Placing a C at 0V will make it easier to integrate keyboards and other musical technologies.
Base Tuning Systems
In addition to being able to quickly find a C, there's one more cultural practice to build into the equation: base tuning systems.
In order for musicians to play in tune together, it's helpful if we all agree on the frequency (Hz) to which our notes are tuned.In addition to general tuning notes, there are also different ways of determining how semitones are placed within an octave. In the equal temperament system every semitone is nudged a little up or down so that key changes can happen. There's another system called "just intonation" which is based on equal fractions of an octave and is sometimes considered more true to physics. It's a big, fascinating topic and beyond the scope of this article. For some reason this base tuning is usually referred to in terms of the frequency for A4 (the A above middle C). A very common base tuning is A440 or "A4 is 440Hz." But there are other common base tunings, such as A438 ("A4 is 438Hz") and the Berlin Philharmonic likes A443. A translation between Hz and CV needs to take into account which base tuning system is desired, otherwise the whole system will feel a little sharp or flat.
Given the concerns outlined above, a good equation for my use needs to:
- Account for the differences in the way our ears perceive frequencies, the way our mind perceives notes, and the way a synthesizer expects to receive pitch data
- Place a C at 0V, while maybe leaving room for me to choose a different note if I want to (even though I probably will never want to)
- Allow me to set 0V to a frequency that matches my base tuning system
Here's the equation in an abstract form along with explanations of each part:
Hz = (BaseTuning / LowestOctave) * FrequencyMultiplier^(Volts + Adjustment)
Hz: This is the frequency. In this form of the equation, the thing that is unknown.
BaseTuning: This establishes which base tuning system being used. For example, if we're using the relatively common A440 tuning system then we would substitute 440 for this variable.
LowestOctave: This variable divides that base tuning number down until it represents the lowest pitch we want to use with our instrument. To get down to a respectable bass octave a good number to enter here is 8.Note that if you're using A440, you could simplify the equation the
BaseTuning / LowestOctave business by entering 55. But I've included the long method and thinking here in case you want to be in tune with an orchestra like Berlin which likes to be jacked up to A443.
FrequencyMultiplier: Since our human ears and culture perceive octaves at a doubling of frequency, the number to swap in here will be 2. But if you want to get experimental and shrink octaves, or if you have to work with a particularly gnarly synth tuning problem, you can shrink or stretch the octave by trying different numbers. Experimental!
Volts: This is the voltage you will probably be sending to a synthesizer. It is a variable you will either already know or be seeking. In this form of the equation, it's probably the thing you know and you enter it here.
Adjustment: Since our BaseTuning variable specifies an A and we may prefer to have a C be our lowest note we can shift things around by adding in the exponent. In a V/OCT system every semitone is 1/12 of a volt. If we want to shift our 0V from the A specified in the BaseTuning variable to a C which we might prefer from a practical standpoint, we need to add 3 semitones or 3/12 or .25 to the exponent.
Here is the less abstract and more practical version of the equation:
hz = 55 * 2^(volts+.25)
This version assumes we're using A440, simplifies the
BaseTuning / LowestOctave math, and adjusts 0V to be C2.
The above equation is useful if you know the control voltage and want to calculate Hz. However, for my project I know Hz and need to calculate control voltage. Here's the same equation but solved for volts instead:
volts = log((hz/55)/2^.25)/log(2)
The above equation also assumes A440, simplifies the
BaseTuning / LowestOctave math, and adjusts our 0V to C2. I am very grateful to my partner Leilehua Lanzilotti for helping me do this math.
Examples of Hz to volts in Lua
Here are some code examples in Lua. You can use them to build whatever you're working on. These equations use A440, have already simplified the
BaseTuning / LowestOctave math, and place C2 at 0V.
The first example is solving for Hz when volts is known. The second example is solving for volts when Hz is known.
--The main equations, where hz is the frequency number in hz and volts is the cv.
--If you know how many volts you're working with then you can calculate the hz. I use this equation to tune oscillators or to provide a courtesy notification of which pitch I am hearing.
hz = 55 * 2^(volts+.25)
--If you know the frequency but need to calculate volts you can use the second of these equations.
volts = math.log((hz/55)/2^.25)/math.log(2)
This second code example is a small script that I built for debugging, a way of listening and printing out volts to Hz conversions using the monome crow, a device with 2 CV inputs, 4 CV outputs, and is programmable via MacOS Terminal or other command line tools in various OSes.
-- A volts-to-Hz calculator, it measures the volts coming in on input, converts it to hz, and prints it out when the function courtesyhz is run.
input.mode( 'stream', .01 )
input.stream = courtesyhz
courtesyhz = 55 * 2^(volts_in+.25)
"In 1v/octave, your volts represent "..courtesyhz.."Hz"
The monome ecosystem, which supports the crow device I use in Timbre of Starlight, also has a simple command as of V3.0:
hztovolts(freq [, reference]) -- convert a frequency to a voltage
-- default reference is middle-C == 0V
-- (optional) reference is the frequency that will be referenced as 0V
At the time I was building up my project I wanted to have more flexibility in how the tuning works. In the end, it was nice for me to go through the process of finding and understanding the equations. I hope that my own journey helps you to build your own rad synthesis stuff.
If you found this article useful, maybe you'll be into the music things I do or my Sound, Community, Culture Newsletter. You can find links etc here.