- Full-size 3D printed keyboard
- 8-way polyphony
- 9 drawbars to adjust harmonics (like a Hammond organ)
- Sustain pedal
- Range C0 through B7 (96 notes)
- src - Source code for the microcontroller (AVR ATtiny861A)
- pcb/sensor - PCB for the key sensor board
- pcb/controller PCB for the controller board
- scad - OpenSCAD design
Holding the "function" key on the controller PCB switches into function mode.
Since we use the on-board oscillator, it is necessary to tune the clock frequency to make the notes in tune. This tuning is stored in EEPROM.
- F#0 - Flatten
- G#0 - Reset
- A#0 - Sharpen
- Keybed
- White keys (7)
- Black keys (5)
- Assembly tool (to help attach the rubber bands)
- Control board holder
The sensor PCB is snapped into the keybed and the keys are attached, one at a time along with the rubber band to pull the key up. Multiple keybeds can be attached together using zipties (there are holes for zipties in the standoff for the keys).
-
Controller PCB
- 1x ATtiny861A
- 1x USB-B socket
- 1x 2x3 IDC socket
- 1x 3.5mm audio jack
- 1x 3mm LED
- 1x 6mm SPST tactile switch
- 10x 10k linear POT
- 2x 1k resistor
- 12x 0.1u capacitor
- 1x 10u capacitor
- 1x 47u capacitor
- 1x 6-pin right-angle socket
-
Sensor PCB (1 per octave)
- 12x 12.6x6.5x5.7mm SPDT limit switch
- 2x 10k resistor
- 2x 74HC165
- 2x 0.1uF capacitor
- 1x 6-pin right-angle socket
- 1x 6-pin right-angle pin header
-
Other
- 12x small rubber bands (one set per octave)
- USB cord and power supply
Each note is controlled by a limit switch. The output of the limit switches are processed serially using two 74HC165 8-bit parallel input shift registers per octave. Since there are only 12 notes in an octave 4 bits are wasted for simplicity. Using this shift register interface, we can read all keys using only 3 pins of the microcontroller.
In software, the state of each key is recorded in a bitmap. When a new key press is detected, a "voice" is removed from the head of a linked list and placed at the end of the list. The frequency increment is set according to the index of the key that was pressed. The frequency increment is a 16-bit value used to move through the waveform every time the sample interrupt executes. The top 8 bits are used as an index into the 256 entry waveform.
When a key release is detected, the "voice" is removed and placed at the head of the list and the frequency increment is set to 0 to prevent the sample interrupt from moving through the waveform. The linked list is used so that the least recently pressed key is re-used if there are too many keys pressed at the same time.
Finally, the sustain pedal simply prevents the processing of key releases.
There are nine drawbars (potentiometers) that are sampled using the multiplexed ADC. One drawbar is sampled per iteration of the main loop. We track the quantized value of each drawbar. When a change is detected, its value is recorded and the waveform is recomputed.
Waveforms are generated by sampling a 256 point sine wave. The base waveform is at half the fundamental frequency (16') allowing us to generate the necessary harmonics by stepping through the sine wave at different rates:
- 16' - Sub-Octave (1x)
- 5 1/3' - Quint (3x)
- 8' - Principal (2x)
- 4' - Octave (4x)
- 2 2/3' - Nazard (6x)
- 2' - Super Octave (8x)
- 1 3/5' - Tierce (10x)
- 1 1/3' - Larigot (12x)
- 1' - Super-Super Octave (16x)
When a drawbar is changed, the waveform is recomputed by adding together the scaled contributions from each drawbar. Each contribution is determined by stepping through the sine wave at the specified rate (2 for 8', etc), wrapping around when necessary, and scaling the amplitude by the drawbar level. The final waveform is scaled down by the max total contribution. The waveform itself is stored as 256 8-bit values.
Audio is generated using 64 MHz pulse-width modulation. The duty cycle is configured to have 256 levels, leaving an output frequency of 250 kHz, which is well above the audio range and easy to filter. The duty cycle is determined by adding together the waveform contributions from each voice. Since there are 8 voices and the duty cycle is controlled by an 8-bit value, we get 5 bits of resolution (this avoids overflow in the case all voices are at the maximum position in the waveform at the same time). A 20 kHz timer interrupt causes us to move through the waveforms for each voice and update the PWM duty cycle.