// Include the Mozzi and MIDI libraries
#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h>
#include <mozzi_midi.h>
#include <MIDI.h>
// Create a default MIDI instance
MIDI_CREATE_DEFAULT_INSTANCE();
// Define the pins for the potentiometers
#define POT_FREQ A0 // potentiometer for frequency
#define POT_AMP A1 // potentiometer for amplitude
#define POT_VIBRATO_RATE A2 // potentiometer for vibrato rate
#define POT_VIBRATO_DEPTH A3 // potentiometer for vibrato depth
// Define the pin for the audio output
#define AUDIO_OUT 9
// Define the pin for the LED
#define LED_PIN 2
// Define the control rate (must be a power of 2)
#define CONTROL_RATE 128
// Create an oscillator for the theremin sound using Oscil<> and SIN2048_INT8 table
Oscil<SIN2048_NUM_CELLS, AUDIO_RATE> thereminOsc(SIN2048_DATA);
// Create an oscillator for the vibrato modulation using Oscil<> and SIN2048_INT8 table
Oscil<SIN2048_NUM_CELLS, CONTROL_RATE> vibratoOsc(SIN2048_DATA);
// Create a variable for the frequency of the theremin sound
int freq = 440;
// Create a variable for the level of the theremin sound (0-255)
int level = 127;
// Create a variable for the vibrato rate
int vibratoRate = 1;
// Create a variable for the vibrato depth
int vibratoDepth = 10;
// Create a function to handle MIDI note on messages
void handleNoteOn(byte channel, byte note, byte velocity) {
// Set the frequency of the theremin oscillator to the MIDI note frequency
freq = mtof(note);
// Set the level of the theremin oscillator to the MIDI velocity
level = velocity;
}
// Create a function to handle MIDI note off messages
void handleNoteOff(byte channel, byte note, byte velocity) {
// Set the level of the theremin oscillator to zero
level = 0;
}
void setup() {
// Start the Mozzi library
startMozzi(CONTROL_RATE);
// Start the MIDI library and set the callbacks for note on and off messages
MIDI.begin();
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);
// Set the initial level of the theremin oscillator using setLevel()
thereminOsc.phMod(level);
// Set the initial frequency of the theremin oscillator using setFreq_Q16n16()
thereminOsc.setFreq_Q16n16(Q16n16_to_Q8n8(freq));
// Set the initial level of the vibrato oscillator using setLevel()
vibratoOsc.phMod(vibratoDepth);
// Set the initial frequency of the vibrato oscillator using setFreq_Q16n16()
vibratoOsc.setFreq_Q16n16(Q16n16_to_Q8n8(vibratoRate));
// Set the LED pin as an output
pinMode(LED_PIN, OUTPUT);
}
void updateControl() {
// Read the values from the potentiometers and map them to appropriate ranges
freq = map(analogRead(POT_FREQ), 0, 1023, 20, 2000); // map frequency from 20 Hz to 2000 Hz
level = map(analogRead(POT_AMP), 0, 1023, 0, 255); // map level from 0 to 255
vibratoRate = map(analogRead(POT_VIBRATO_RATE), 0, 1023, 1, CONTROL_RATE / 2); // map vibrato rate from 1 Hz to CONTROL_RATE / 2 Hz
vibratoDepth = map(analogRead(POT_VIBRATO_DEPTH), 0, 1023, -50, +50); // map vibrato depth from -50 to +50
// Update the level of the theremin oscillator using setLevel()
thereminOsc.setFreq_Q16n16(level);
// Update the frequency of the theremin oscillator using setFreq_Q16n16()
thereminOsc.setFreq_Q16n16(Q16n16_to_Q8n8(freq));
// Update the level of the vibrato oscillator using setLevel()
vibratoOsc.setFreq(vibratoDepth);
// Update the frequency of the vibrato oscillator using setFreq_Q16n16()
vibratoOsc.setFreq_Q16n16(Q16n16_to_Q8n8(vibratoRate));
// Write a HIGH or LOW value to the LED pin depending on the level of the theremin oscillator
if (level > 0) {
digitalWrite(LED_PIN, HIGH); // turn on LED if sound is playing
}
else {
digitalWrite(LED_PIN, LOW); // turn off LED if sound is silent
}
}
int updateAudio() {
// Get the next sample from the theremin oscillator and modulate it with the vibrato oscillator
return thereminOsc.next() * (1 + (vibratoOsc.next() / (float)256));
}
void loop() {
// Update the Mozzi library and process MIDI messages
audioHook();
MIDI.read();
}