Featured Posts

PComp | Week 5 | Theremin v.3

This is my 3rd week working on this (see previous week and the previous previous post).

Last week I managed to somewhat smoothen the value given by the IR sensor, and controlled the value using a pot and Volume 3 library.

This was my "note to self" for next iteration:

  • Consider using other sensors, maybe stretch sensor to get more stable output

  • Try using another value-smoothing algorithm

  • Have another sensor as vibrato control

  • Consider using mp3 shield to output less-annoying sounds

Here was my approach to improving the theremin* with what we learned in class.

  1. Get new sensors: I bought short-distance IR sensor (8-30cm) for hopefully more stable values & photo cell meant for vibrato control.

  2. Apply new sensors to existing build from last week, make sure the values are smooth and I can get glissando pitch output.

  3. Use mp3 shield to play background music, so that the theremin* does not sound that annoying.

Theremin v3.1 (First attempt)

Function 1: Theremin simulator

  • New IR short distance sensor

  • Simple averaging/smoothing algorithm to avoid program getting stuck in a “for loop”

  • Photo cell as vibrato control

#include <TimerOne.h> #include <Volume3.h>

#define photoPin A1 #define IRPin A5 #define potPin A0 #define speakerPin 3

int photoRead = 0; int prevPhoto = 0; int diff = 0;

int IRRead = 0; int avgIR = 0;

int potVal = 0; int volume = 0;

int pitch = 0;

void setup() { Serial.begin(9600); }

void loop() {

photoRead = analogRead(photoPin); IRRead = analogRead(IRPin); potVal = analogRead(potPin);

volume = map(potVal, 0, 1023, 0, 1000); diff = photoRead - prevPhoto; //Serial.println(diff); prevPhoto = photoRead;

avgIR = 0.95 * avgIR + 0.05 * IRRead; //Serial.println(IRRead);

//diff = 0; pitch = avgIR + (diff*3); pitch = 800 - pitch;

Serial.println(IRRead);

//vol.tone(speakerPin, pitch, volume); tone(speakerPin, pitch); delay(5); }

But unfortunately when I ran pot and photocell together the photocell became very erratic. In the video it can be seen that the photocell fluctuates when I turn up the pot. I suspected that having so many things connected to the breadboard / arduino kind of messes with the current / voltage. I could not figure it out :(

I ended up factoring out the photocell values / vibrato.

Theremin v3.2 (Second Attempt)

Function 1: Theremin simulator

  • IR short distance sensor -> pitch control

  • pot -> volume control

  • photo cell -> vibrato control

Function 2: Background music player

  • DFPlayer Mini + speaker -> background music output

  • switch -> background music control (pause & play)

  • LED -> indicator of playing / not playing music

Building this was a nightmare....

There were so many inputs and outputs it was super hard to troubleshoot. My first speaker was busted (I think cos of the overclocking by Volume 3 library). My breadboard was so small often I got confused which pin connects to which. Even my button switch behaved erratically and I had to debounce it with a crude delay function.

And here's the source code:

#include <SoftwareSerial.h> #include <DFRobotDFPlayerMini.h> #include <TimerOne.h> #include <Volume3.h>

#define photoPin A1 #define IRPin A5 #define potPin A0 #define speakerPin 9 #define buttonPin 8 #define ledPin 7

#define C4 261 #define C5 523 #define C6 1046

SoftwareSerial mySerial(10, 11); //RX TX Pins DFRobotDFPlayerMini myDFPlayer;

int photoRead = 0; int prevPhoto = 0; int vibrato = 0;

int IRRead = 0; int avgIR = 0;

int potVal = 0; int avgPot = 0; int volume = 0;

int pitch = 0;

int switchState = 0; boolean isPlaying = false; boolean isFirstTime = true;

void setup() { mySerial.begin(9600); Serial.begin(9600);

Serial.println(); Serial.println(F("DFRobot DFPlayer Mini Demo")); Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

if (!myDFPlayer.begin(mySerial)) { //Use softwareSerial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while (true); } Serial.println(F("DFPlayer Mini online."));

pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT);

myDFPlayer.enableLoop(); //enable loop }

void loop() {

//THEREMIN FUNCTIONS // 1. Read all the inputs photoRead = analogRead(photoPin); IRRead = analogRead(IRPin); potVal = analogRead(potPin);

// 2. Vibrato control value (photo cell) vibrato = photoRead - prevPhoto; if (vibrato > 10 || vibrato < -10) { vibrato = 0; } prevPhoto = photoRead; //Serial.println(vibrato);

// 3. Smoothing IR & Pot Values avgIR = 0.95 * avgIR + 0.05 * IRRead; avgIR = constrain(avgIR, 170, 540); //Serial.println(avgIR); avgPot = 0.99 * avgPot + 0.01 * potVal;

// 4. Theremin output logic (Volume & Pitch)

avgPot = constrain(avgPot, 100, 1000); volume = map(avgPot, 100, 1000, 0, 1000); //Serial.println(volume);

pitch = map(avgIR, 170, 540, 0, C6 - C5); pitch = C6 - pitch; //pitch += vibrato * 10;

vol.tone(speakerPin, pitch, volume); //tone(speakerPin, pitch); //Serial.println(pitch); delay(1);

//BG MUSIC PLAYER switchState = digitalRead(buttonPin); //Serial.println(switchState);

if (switchState && isFirstTime) { myDFPlayer.volume(20); //Set volume value. From 0 to 30 myDFPlayer.playMp3Folder(2); digitalWrite(ledPin, HIGH); Serial.println("HELLO"); isFirstTime = false; isPlaying = true; delay(2000); switchState = LOW; }

if (switchState && isPlaying && !isFirstTime) { myDFPlayer.pause(); digitalWrite(ledPin, LOW); isPlaying = false; Serial.println("PAUSING"); delay(2000); switchState = LOW; }

if (switchState && !isPlaying && !isFirstTime) { myDFPlayer.start(); digitalWrite(ledPin, HIGH); isPlaying = true; Serial.println("RESUMING"); delay(2000); switchState = LOW; } }

#PComp #PhysicalComputing

Related Posts

See All
Recent Posts