A while a go I sent a message to Martin from Wintergatan that I want to help with the second version of his Modulin that he briefly talked about during one of his Marble Machine X videos.
He never replied, so I just decided to play around with my own ideas. The immediate goal is not so much to design a music instrument as it is to play around with touch input, digital signal processing, and analog filters.
For my first instrument I decided to build a chiptune violin by using a Game Boy as the synthesizer.
Step one was to figure out touch input. At first I wanted to do capacitive touch, but sensing position is not as easy as it’s made out to be. Then I found these SoftPot lineair potentiometers, which seem pretty good. At first I thought I would need a separate sensor strip to sense pressure, but by pressing down, a small track section of the SoftPot is shorted, resulting in a smaller total resistance that can be measured.
After playing with the Game Boy sound registers in the simulator for a while, I made a new copy of GALP for all the boilerplate code, then I added the following snippet to read an address and a byte from the Game Link port and simply write it to hiram. This code basically allows changing any register at all, not just the sound ones. The full code lives here.
; enable sound
ld a,%10000000 ; enable
ldh [rAUDENA],a
ld a,$ff ; all channels
ldh [rAUDTERM],a
ld a,$77 ; max volume
ldh [rAUDVOL],a
.loop
call SerialTransfer
ldh a,[rSB] ; new address
ld c, a
call SerialTransfer
ldh a,[rSB] ; new data
ld [$FF00+c],a ; write register
jr .loop
SerialTransfer:
ld a, $80 ; start external transfer
ldh [rSC], a
.transferWait
ldh a,[rSC]
bit 7, a ; is transfer done?
jr NZ, .transferWait
ret
Then I connected the SoftPot to an Analog input of an Arduino with a 100k pull-down, and connected the Arduino SPI pins to the Game Link port. The code then simply reads the analog pin and sets the correct sound register on the Game Boy to play the corresponding note. The full code lives here.
int oldValue = 0;
void loop() {
int sensorValue = analogRead(A9);
bool lowValue = sensorValue < 1;
bool oldLowValue = oldValue < 1;
int outputValue = map(sensorValue, 0, 1023, 440, 1760);
int oldOutputValue = map(oldValue, 0, 1023, 440, 1760);
if(!lowValue && oldLowValue) { // rising edge
ch2Length(63, 2);
ch2Envelope(15, 0, 0);
ch2Play(outputValue, 0, 1);
} else if (lowValue && !oldLowValue) { // falling edge
ch2Envelope(15, 3, 0);
ch2Play(oldOutputValue, 0, 1);
} else if(!lowValue) { // high
ch2Play(outputValue, 0, 0);
}
oldValue = sensorValue;
delay(10);
}
The current code does not sense pressure and just uses a square wave channel on the Game Boy with an envelope on release. Next items on the list of things I want to try are sensing pressure and playing with some bucket brigade chips that have been sitting in my drawer.