Technically Speaking (Part 2)
Part two of Andy Honeybone's Voyage Home... return to control voltage synths, that is, and how to MIDI them up.
HAVING spent most of my early drinking years building analogue synthesisers, it seemed only right and proper to give them a new lease of life in the form of a MIDI interface. The software was presented last month and, in this second instalment, it will be elucidated along with a description of the necessary hardware.
The digital to analogue circuit was already present in one of my synths so I can't claim any originality. The heart of the design is a Ferranti ZN428-E DAC chip which is driven directly from the BBC's User Port. The latches in the 428 are therefore unused and you could effect some economy by using the 426 if you're prepared to do some re-design. The chip has an onboard 2.55 volt reference and, as the converter is eight-bit, this equates to 10 millivolts per bit.
As the majority of analogue synthesisers have 1 volt per octave logarithmic oscillators, an amplifier is required to boost the DAC output to 83.33 millivolts per bit. The component values shown around the non-inverting operational amplifier give a gain of around 8.5 when the 10 turn gain pot is positioned midway.
A second Op Amp is used in comparator configuration as a trigger interface. The trigger required for my home-brewed kit was -14v at rest and +14 for a key press and this may be a little fierce for some commercial designs. Negative going triggers can be obtained by swapping the non-inverting and inverting inputs of the comparator. I'm told that older Oberheim, Sequential, ARP and Roland gear requires 0 to 5 volt triggers; Korg and Yamaha work on 0 to minus 5 volt swings, and Moog appear to use 12 volt dropping to ground.
Shortage of space (not to mention hours in the day) make it impossible to display a separate circuit for every one of the analogue museum pieces that inhabit dusty attics. If you're able to follow the story so far, then you ought to be able to come up with your own simple arrangement of resistors and the odd diode to tame matters to your required trigger. But when faced with a pre-MIDI item of gear, check the manufacturer's trigger spec yourself, and be sure. We can get you so far, but we can't be held responsible for any damage that results from your own inventiveness.
The FORTH language in which the software is written allows the programmer to add new words to its vocabulary (unlike BASIC). The new words become incorporated in other definitions which become new words. In the end, the entire program becomes one word — in this case midi_cv.
At the top of the listing are the declarations of all the constants and variables used in the program. You can't just pluck them out of the air as you can with BASIC. The constant definitions also ease maintenance as, if I were to use a different MIDI interface, I would only have to change the addresses of the registers in one place.
Because forward referencing is not allowed, the most primitive routines are defined first. These are five machine code words which fill a circular buffer from an interrupt from the MIDI interface, transmit a single byte to the MIDI interface (xmit), turn the maskable system interrupts on and off (int_on and int_off) and allow the removal of a byte from the circular buffer (check_buf). The first routine doesn't have a name as it is an interrupt routine and is never called from FORTH. The concept of the circular buffer was explained in the 'transposer' article.
The definition 'numin' permits the user to enter a number. Error checking ensures that silly values aren't accepted. Three housekeeping utilities are then defined. The first, 'nmi_on' resets the MIDI interface and sets it up to interrupt when a byte is received. The second, 'prepare', initialises the pointers to the circular buffer, configures the User Port to be 8 outputs, pokes a 'jump to interrupt service routine address' instruction sequence into the nmi service area and finally turns off the computer's response to interrupts other than from the MIDI interface. The third, 'tidy_up', restores the changes made by 'prepare'.
The word 'keep_stat' monitors each byte and on receipt of a status byte which is not a system realtime command (and hence will not affect the running status), encodes the status into a number from 0 to 7 and saves the channel number. All the words beginning with 'is_' return logical true or false and form a set of tools by which the MIDI data stream can be characterised.
The real hard work is done in the main definition midi_cv. A loop begins and a MIDI byte is scanned for status information. Provided that the byte does not contain status, and that the channel associated with the running status is that set for the converter, a further test is made to see if the running status is either note on or note off. If this is the case, the byte must be a key value and 36 (the note number of the lowest key on most 5 octave MIDI keyboards) is subtracted to give a value that can be output to the converter. The next byte in the MIDI stream has to be a velocity byte and its value is duly stored.
If the running status is that of note on and the velocity byte wasn't zero (equivalent to note off) and the priority is such that a new note is in order, the key value is saved as the last note and is written to the DAC with the sixth 'trigger' bit raised.
When the running status is note off or note on with zero velocity and the key number is that of the note currently being output, the trigger bit must be lowered and no note playing is indicated by storing 255 as the last note. This last step is important for highest note priority since if the released note was not cleared, the next key pressed would have to be higher to be recognised.
The priority definition therefore works as follows: if no note is being played (last_note = FF), indicate that a new note may be generated; otherwise authorise a new note only when the new key number is greater than the old one. The priority is toggled between highest note and last note by the contents of the variable pri. When last note priority is selected, pri contains 1 and this value forces the outcome of the high note decision.
The loop completes by looking at function key f1 to see if it has been pressed and, if detected, terminates cleanly by turning off the current note and restoring the system.
Feature by Andy Honeybone
mu:zines is the result of thousands of hours of effort, and will require many thousands more going forward to reach our goals of getting all this content online.
If you value this resource, you can support this project - it really helps!