MFOS Sound Lab Mini Synthesizer (Part 2) – A MIDI2CV Converter


So my MFOS Mini Synth is working and a treat to the “synthetophile” ears. But at the time being it makes just experimental noises … what about connecting a keyboard and playing some lead synth lines?

Nope, the MFOS Synth has an analogue CV input (CV = control voltage) + external trigger. Do you have a CV compatible keyboard at home? (Or at least ever seen one with your own eyes?) – No! – But all my keyboards have a MIDI output … so I would need a …

MIDI to CV converter.


I found a first inspiration here:

This project utilizes an AVR microcontroller which controls a standard 8 bit DAC with an 8 bit parallel interface. The microcontroller receives the MIDI data through its serial interface (UART).

Now I wondered if it was possible to add nice features like pitch bend control, portamento and modulation to this bare bone concept. The answer is yes, with a few tricks and inexpensive components:


For this project I used an ATTiny 2313, it’s cheap and very sufficient for the job. As in the project from I use a standard 8 bit DAC to generate a CV signal. In addition to that I use three independent PWM channels for the “extra goodies”.

Let’s start with how I generate pitch bend functionality:

That’s pretty straight forward. While no pitch bend control arrives via MIDI, the pitch bend PWM pin generates a rectangle wave with 50% duty cycle. Moving the pitch wheel on the controller keyboard results in changing the duty cycle. After applying a low pass filter (RC filter) to the PWM signal, I get a MIDI controllable offset voltage that I simply add to the CV signal from the DAC (with the help of a summing amplifier). I can adjust the pitch bend range by using a trimmer potentiometer as a voltage divider (not shown in the block sketch). I set the range to be +/- two half notes.

Now how does the modulation control work?

I generate a low frequency triangle wave using a double op-amp. The triangle wave is then “chopped” by an analogue switch (MOS 4051, better not 74xx4051) which is controlled by another PWM output of the microcontroller. The resulting signal is then low pass filtered, this removes the undesired high frequency parts introduced by the modulation. I have effectively amplitude modulated the triangle wave with my PWM signal. Needless to say that the PWM frequency has to be relatively high compared to the triangle frequency. The following picture should make it clear:


Now I have a triangle shaped time dependent voltage that I can modulate in its amplitude between 0% and 100% with the mod wheel on my keyboard. The absolute range is adjustable via another trimmer potentiometer. I set it to something like +/- one half note. This voltage is also added to the CV signal inside the summing amplifier.

Now the most tricky part was implementing the portamento (some people call it “glide”) feature. I thought really long and hard about that. The glide effect can easily be achieved by low pass filtering the CV signal from the DAC, i.e. charging/decharging a capacitor with the CV voltage through a resistor. The time constant (R*C) of the filter determines the glide speed. So to alter the portamento time you could just use a potentiometer as “R”. But as you were able to see in the pictures in the last article there is no more space left for knobs on the front panel. Plus I want to control the portamento time via MIDI because I want to glide between notes only while playing legato, i.e. keep holding down the previously played key. How to change the time constant of a low pass filter digitally?

I made use of an analogue switch again! I employ it between the DAC and the RC filter and drive it with yet another PWM signal from the microcontroller. When the switch is closed the capacitor is charged, when the switch opens, the capacitor keeps its current fill state. If I drive the switch with a PWM signal that has only 50% duty cycle then the capacitor takes twice as long to charge as in the case of a closed switch. If I drive it with 33% duty cycle … three times as long … and so on. In my actual design I used an analogue multiplexer to both apply PWM and select between three different fixed resistors and a direct short (see schematic for details). With the three different resistors I create three different slopes in my portamento time function. This comes close enough to a logarithmic response of the control (lets you cover a higher dynamic range  of possible glide times). Here’s a theoretical plot I made with octave:


If you wonder about the “steppy” artefacts on the right side of the curve then contemplate this: You want to control the glide time. You have (linear/proportional) control over the duty cycle of the PWM signal. The discretely valued duty cycle is inversely proportional to the glide time (glide time ~ 1/duty cycle). This means that you have a quite good resolution for short glide times and relatively bad resolution for long glide times (even for 10 bit PWM mode). The three resistor solution helps counteracting that problem because large subsections of the slope can be “recycled” with another multiplier (higher R).

Oh, I almost forgot: The portamento time is controlled with the MIDI CC 5 signal. (MIDI Control Change No.5, assuming you start counting with 0)

Last but not least I added some power supply features:


The whole box (synth and MIDI2CV) are powered by a single 12V DC power supply. The synth needs +9V and -9V and the AVR needs +5V. The positive supply voltages I provide through linear fixed voltage regulators (LM7809, LM7805). For the negative supply rail I use a charge pump IC (LT1054) that is able to invert my incoming +12V. The resulting minus “eleven-dot-sth.” volts are cropped by a negative linear fixed voltage regulator (LM7909) to clean and smooth -9V. I power my synth with a 12V 0.6A DC switching wall power supply that I bought on for two or three Euros.

IMPORTANT: Never connect the metal heatsink part of the 7909 (or any similar negative voltage regulator) to GND. Especially do not connect electrically to the heatsinks of the other regulators (which ARE  connected to GND, that is the mean thing). I grilled most of my ICs by accidentally shorting the heatsinks with a screwdriver. That’s why you see shrinking hose around one of the regulators in the pictures 😀

Ah before I forget: Sorry my layout is so terribly crowded. But as you see in the pictures, it had to fit inside the box by all means!

The microcontroller firmware

The microcontroller listens to incoming MIDI packages on it’s UART. Decoding MIDI information on an AVR is no magic and there are some very good instruction documents around. If you are interested in that field, I advise you to read “MIDI and the AVR” .

So what the microcontroller does is pretty straight forward. Decode incoming MIDI, i.e. distinguish between note on, note off, mod wheel change, pitch wheel change and particular control change (for the portamento) events. It then translates the note and control parameters to their relative DAC and PWM settings.

What I think has to be mentioned is the use of a memory stack which is used in the following way:

When a note on event arrives -> store the note number (~tone pitch value) on top of the “note stack”

When a note off event arrives -> search through the stack and remove the corresponding note from the “note stack”

Always “play” the note which is on top of the stack.

This way if you press key #1 and hold it down while you then press and release key #2, the synth will first play pitch #1 then jump to pitch #2 and then, thanks to the memory stack, play pitch #1 again (until the note off-event for key #1 arrives).

I also use the fill state of the note stack to determine when to glide between two notes and when to jump:

If the stack is empty (no currently pressed keys) then jump directly to the note that is subsequently played.

If the stack already holds one or more elements then glide to the note played next.

The same way you get your gate signal almost for free:

If the stack is empty: Gate pin = low.

If the stack is partially filled: Gate pin = high.

Tuning procedure

What I totally forgot to explain is the reasons for all the potis!

1) RV_TUNE1 poti (MIDI to CV section):
This poti adjusts the scaling of your tonal output range. In other words: How much space( mV of CV voltage) is there between two neighbouring half tones. Connect a voltmeter between CV-Out and GND. Play two notes on the MIDI keyboard that are one octave apart. The output voltage should change by 1V. Then you have a CV signal according to the 1V/octave standard.

2) RV_BIAS1 poti (Mixer Section):
This poti adjusts the offset voltage of the CV signal, i.e. the absolute position of your tonal output range. Keep it in a middle position for the start or adjust to your needs, i.e. the CV input range of the synth oscillators.

3) RV_TRIG_FREQ1 poti (Triangle Generator):
Sets the speed of the Modulation vibrato. (set to ~4Hz or to taste …)

4) RV_MOD_AMP1 poti (Modulation Section):
Sets the depth of the Modulation vibrato. My desired vibrato depth is ~slightly more than one half tone (set by ear).

5) RV_PBEND1 poti (Pitch Bend Section):
Sets the tonal range of the pitch bend control. Standard setting would be +/- two half tones (set by ear).

I advise you to use multiturn trim potentiometers for all variable resistors in this project.


Pictures from the build:

Important updates:

May 15th, 2013:

Please note that I made a mistake in the schematic! The capacitors next to the quartz are actually 22p not 22n!  The quartz is 12 MHz, I forgot to tell you that, too.

July 27th, 2014:

Cleaned up the schematic and the KICAD project files, everything should be fine now. By the way, the pin “gate_mode” in the schematic has no meaning at all.

July 21th, 2018:

Please mind the fuse bits!

The fuse bits are three 8 bit registers that define certain basic settings of the ATTiny 2313 (as well as in other AVR micros). In particular the fuse bits determine what clock source the microcontroller should use. You are right, without the correct fuse bits my MIDI2CV converter should not work at all :D. By default the ATTiny 2313 uses its internal (not so precise) RC oscillator, running at 8 MHz. This clock is then divided internally by a factor of 8.

But we want: use external quartz running at 12 MHz, no internal clock division.

We achieve that by setting the following fuse bits:

low fuse: 0xf9
high fuse: 0xdf
extended fuse: 0xff

if you use avrdude to flash your chip then you would use the following arguments

avrdude -c [your programmer] -p attiny2313 -P [address of programmer] -U lfuse:w:0xf9:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m

fuse bits are not magic, but I agree they are not very human readable.
but you can help yourself with the following website that translates fuse bits back and forth:

July 23rd, 2018:

MIDI jacks are connected like this:


Microcontroller C code/hex file + PCB layouts for toner transfer + KiCAD project files:

or view the project’s Github page

25 responses to “MFOS Sound Lab Mini Synthesizer (Part 2) – A MIDI2CV Converter

  1. Hi Michael,

    Thanks for developing this circuit and the excellent YouTube demo !

    Before I obtain the parts for this project, I need to ask you a few questions:

    1) From the schematic, is the negative terminal of C20 (MIDI to CV section) connected to cv_raw and is the crystal frequency 4Mhz ?
    Also, could you please explain what the diagrams on the left hand side of the MIDI to CV section refer to (i.e. those labelled “AVR-ISP-6” and P5-P12) ?

    2) I understand that I would need to build a programmer for the ATTINY2313 first, and then download the C code and hexfile onto it. Is this correct ?

    3) Finally, how much would it cost to build this project please ?

    I hope you can help.



    • Hello Manish,
      thank you for your interest in this project and for pointing out the glitches in my documentation.

      Your questions are fair, let me answer them:

      1) The negative terminal of C20 is connected to GND. Sry, the label somehow vanished during the pdf conversion.
      The crystal frequency is 12 MHz.
      The symbols P5-P12 can be ignored. They are artifacts of an untidyness.
      AVR-ISP-6 is a standardized 6 pin connector that serves as an interface between the microcontroller and its programming device.

      2) You need a proper programmer to flash the hexfile onto the microcontroller. The hexfile is an image containing the machine code that tells the microcontroller what tasks it has to perform. The rest of the files in the zip archive are the source code of the project. If you just want to recreate the MIDI2CV converter you can safely ignore everything but the “main.hex”.
      You can build your own COM port AVR programmer with just a few resistors, diodes and transistors ( but you probably figured that out yourself. That solves the “hen and egg” problem. While you’re at it, why not build a more comfortable usb based programmer like the “USBtiny” or the “little wire” in the same run?

      3) The most expensive chip in the project would be the LT1054 (0.1 A positive to negative voltage converter for up to 15V). It costs almost 5€. But it pays off as it also provides the negative supply voltage for the whole MFOS Mini Synth.
      The ATTiny costs ~ 1.5 €. The D/A converter chip is another euro. The rest are standard logic and analog ICs that cost between 20 and 50ct.
      All in all the parts should not cost more than 20€ or so.

      I hope I could help you!

      Best wishes


  2. Hello Mishael!
    Thank you for your project.
    but I have Problemme with Attiny2313, the HEX file that is really true, I have no idea in programming. What should I do with FUESE bits.
    For me all this does not work, no signal comes out.

    Help me please!

    Sory for my english, I’m from DE!

    Thanks in advance


    • The fuse bits are three 8 bit registers that define certain basic settings of the ATTiny 2313 (as well as in other AVR micros). In particular the fuse bits determine what clock source the microcontroller should use. You are right, without the correct fuse bits my MIDI2CV converter should not work at all :D. By default the ATTiny 2313 uses its internal (not so precise) RC oscillator, running at 8 MHz. This clock is then divided internally by a factor of 8.

      But we want: use external quartz running at 12 MHz, no internal clock division.

      We achieve that by setting the following fuse bits:

      low fuse: 0xf9
      high fuse: 0xdf
      extended fuse: 0xff

      if you use avrdude to flash your chip then you would use the following arguments

      avrdude -c [your programmer] -p attiny2313 -P [address of programmer] -U lfuse:w:0xf9:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m

      fuse bits are not magic, but I agree they are not very human readable.
      but you can help yourself with the following website that translates fuse bits back and forth:

  3. Hello Michael, Thanks very much for this MIDI2CV guide, i don’t try it, but how MFOS and Midi2cv running on DAW (Ableton maybe) ? Thank you very much

  4. Hello, did you write the Program in c++ ?
    So there is no chance to edit it with the Arduino Software?
    Because I would like to have a look at the code, and maybe try to change some things, for example the Midi Channel.

    • The code is written in plain c.
      I don’t know what your arduino software does …
      but you can change the MIDI channel simply by editing
      line 9 in main.c with a simple text editor.

      line 9 in main.c should look like this:

      #define MIDI_CHANNEL 0

      possible values are 0-15

      Save your changes and recompile the code with the avr c compiler of your choice (for example gcc-avr).
      voila !

  5. Hi!, I just wander if the MIDI_CV module can work as a standalone version (no modwheel, triangle or portamento), and what should I take into account? Thanks in advance,

    • Hi. Sorry for the late reply. Yes, you can operate it standalone. You see in the schematic that I drew blue boxes around the individual functional groups. If you don’t want modulation and pitch bend, simply leave out all parts in the boxes labeled “triangle generator”, “modulation” and “pitch bend”.
      If you want to remove the portamento functionality, leave out the parts in the box labeled “portamento”, but directly connect the line “cv raw” to the line “portamento”. All the best, Micha

  6. Amazing job, easily the best midi t cv converter explanation on the internet. Quick question, what is the output voltage of this? also, what is the benefit of having a 12V midi to cv and VCO to a 10V? thanks in advance.

    • Sorry my question is, if the output voltage of the midi to cv is not 12v. Then does that limit the octave range of the controller? also what ranges can you achieve ? thank you

      • Hi! The converter complies to the 1V/octave standard. The converter uses a Power Supply of +- 9V, so in principle I could have an output voltage range of almost 18V. The voltage is not the problem. I can easily cover a range of at least 5 octaves. But at some point you will run into tuning stability issues if you want to use such a broad range … greetings!

  7. Ah Ok, I think I understand now. thanks!

    One over thing, Im trying to simplify your code so that it only includes pitch CV and Gate. I feel that it will help me understand the code if I can take it down to a more basic level. Do you have such a code? Thanks

    • Hi. Thanks for your question. No I don’t have a separate code without modulation and pitch bend. But if you look at the code in main.c you will see there is a “switch” statement in line 169, where the microcontroller distinguishes between different types of incoming MIDI packets. There are code blocks “case NOTE_ON:” and “case NOTE_OFF:”, this is what is interesting for you. Just comment out the blocks beginning with “case PITCH_WHEEL:” and “case CONTROL_CHANGE:” and you have just the code you have asked for. Just plain generation of CV, nothing else.

  8. Another thing I have noticed is that there is no exponential converter in your design. How do the voltages become logarithmic?

  9. You state that gate_mode has no meaning, so does that mean that TXD is not used? Furthermore, why is TXD enabled in the code? Thanks 🙂 I am currently in the process of understanding your code. Thank you!

    • It’s been a long time. The TXD pin is part of the UART, which I use for receiving MIDI data. I think, when you activate the UART, you enable input and output. But I don’t use the output. I don’t remember what I initially planned to do with that pin. Ignore. 🙂

  10. Sorry to be a bother again, could you explain to me what this mean?

    dac_value = (last_active_key()-36)<<1;

    why is the DAC value equal to the last_active_key minus 36? I don't get what is happening there at all. It is from the part of the code!

    void make_cv() {
    static uint8_t dac_value = 0;

    dac_value = (last_active_key()-36)<<1;
    PORTD &= ~(0b00111100);
    PORTD |= (dac_value & 0x0F)<<2;
    PORTB &= ~(0b11100000);
    PORTB |= (dac_value & 0xF0)<<1;

    If you could shed some light, it would be much appreciated 🙂

    • Hi! The line in question maps the received MIDI key information to a DAC setting (which in turn will produce an analog voltage). last_active_key() is a function that returns the number of the last MIDI key that was pressed. The “-36” is just an offset, to use the middle part of the keyboard. For example the lowest C key (C0) on an 88 keys piano keyboard has number 24. 36 is the lowest key (C1) on a standard 64 keys keyboard, and this is the lowest note which I want to play with this converter. The <<1 is a binary shift by one, i.e. the value left of it will be multiplied by two. I do this to (effectively) turn my 8-bit DAC into a 7-bit DAC. I don't need all 256 steps, so I throw away the least significant bit and have 128 steps left, which is more than sufficient.

      and this part of the code:
      PORTD &= ~(0b00111100);
      PORTD |= (dac_value & 0x0F)<<2;
      PORTB &= ~(0b11100000);
      PORTB |= (dac_value & 0xF0)<<1;

      is just because the eight control bits of the DAC are connected to GPIO pins connected to two different ports of the microcontroller, so I split my data byte "dac_value" and shift it back and forth until the right states are at the right pins.

      Best wishes,

  11. Ahh ok that makes more sense! Is there a reason that you connected them to 2 different ports? Or was it due to you using the PWM at PB2 – 4 ? Sorry for all of these questions, I find your design very impressive and am using it as a means to learn AVR!

    • I don’t remember. Yeah, stuff like this is a limitation … not all GPIO pins can be used as PWM outputs … and then there is the problem of routing lines on the PCB, which sometimes makes you reconsider your pin mapping choices.

  12. Also, is there a reason to why you chose not to code Portamento, Pitch bend, Modulation and use circuitry instead?

    • Pitch bend: This is already the straightforward solution. Fine bends cannot be done with the DAC, the resolution is not high enough. So I add a small controllable extra voltage from a PWM output.

      Portamento and Modulation … well that would have introduced the complexity of simulating capacitor charging and calculating LFO in software. These would have been timing critical processes which would have to run in parallel with all the MIDI receiving and processing.

      Of course you could do all of that in software, but then you’d also need a high precision DAC to render it all. Maybe I’d do that if I were to build it again … But back then I wanted to keep everything as analog as possible and explore the ways of using PWM signals to control analog circuitry.

      I never claimed that my this is the best/only way to build a MIDI to CV converter 😀

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.