Das digitale Theremin sitzt auf einem Shield für den Arduino Uno, das einfach aufgesteckt wird. Es enthält ein analoges Low-Pass-Filter zur Verbesserung des Klangs und einen Regler für die Lautstärke. Über einen optischen Sensor wird die Tonhöhe gesteuert. Der Ton wird über einen Line-Ausgang im Miniklinkenformat wiedergegeben. Weiterhin gibt es einen Schalter für einen Reset der Software, eine Status-LED sowie eine schaltbare Notbeleuchtung für sehr dunkle Umgebungen.
Die Software bindet die Bibliothek Mozzi ein, die einen sehr schönen Sinuston für den analogen Ausgang des Arduino berechnet, der ansonsten nur Pulswellen erzeugen kann.
Die Daten des Sensors und des Lautstärkepotis werden über die serielle Schnittstelle auch an den Computer gesendet, die dann z.B. über den seriellen Monitor in der Arduino IDE ausgelesen werden können.
Code:
// Digital Theremin
// Version 1.0 by Christian Streng
// www.christianstreng.de/digital-theremin
#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin2048_int8.h> // sine table for oscillator
const char KNOB_PIN = 0; // set the input for the knob to analog pin 0
const char LDR_PIN = 1; // set the input for the LDR to analog pin 1
// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA);
byte volume;
int pin_switch = 2; // the number of the input pin
int pin_LED = 7; // the number of the output pin
// variables to hold the new and old switch states
boolean oldSwitchState = LOW;
boolean newSwitchState = LOW;
boolean LEDstatus = LOW;
void setup(){
Serial.begin(115200); // set up the Serial output so we can look at the analog levels
startMozzi(); // :))
pinMode(pin_LED, OUTPUT);
digitalWrite(pin_LED,HIGH);
pinMode(pin_switch, INPUT_PULLUP);
}
void updateControl(){
// read the potentiometer
int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023
// map it to an 8 bit volume range for efficient calculations in updateAudio
volume = knob_value >> 2; // 10 bits (0->1023) shifted right by 2 bits to give 8 bits (0->255)
// print the value to the Serial monitor for debugging
Serial.print("volume = ");
Serial.print((int)volume);
Serial.print("\t"); // prints a tab
// read the light dependent resistor
int light_level = mozziAnalogRead(LDR_PIN); // value is 0-1023
// print the value to the Serial monitor for debugging
Serial.print("light level = ");
Serial.print(light_level);
Serial.print("\t"); // prints a tab
// set the frequency
aSin.setFreq(light_level);
Serial.println(); // next line
}
int updateAudio(){
// cast char output from aSin.next() to int to make room for multiplication
return ((int)aSin.next() * volume) >> 8; // shift back into range after multiplying by 8 bit value
}
void loop(){
audioHook(); // required here
newSwitchState = digitalRead(pin_switch);
if ( newSwitchState != oldSwitchState )
{
// has the button switch been closed?
if ( newSwitchState == HIGH )
{
if ( LEDstatus == LOW ) { digitalWrite(pin_LED, HIGH); LEDstatus = HIGH; }
else { digitalWrite(pin_LED, LOW); LEDstatus = LOW; }
}
oldSwitchState = newSwitchState;
}
}