Musical Theremin
Description:
Create a simple smart theremin using mbed. Our approach includes the following features:
- Improve distance sensing sonar to play only designated pitches in a scale
- Add second sonar sensor to control volume
- Plot sine wave of pitch (frequency) vs amplitude (volume) in real time
- Print pitch (Hz) and volume (0-100%)
- Add Bluetooth to customize “smart” theremin
- Choose between major and minor keys
- Allows you to input your own name
Parts List:
- LPC1768 mbed: https://os.mbed.com/platforms/mbed-LPC1768/
- uLCD: https://os.mbed.com/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
- Potentiometer: https://os.mbed.com/components/Potentiometer/
- (2) HR-SR04 Sonar Sensors: https://os.mbed.com/users/4180_1/notebook/using-the-hc-sr04-sonar-sensor/
- Class D Audio Amp: https://os.mbed.com/users/4180_1/notebook/tpa2005d1-class-d-audio-amp/
- Speaker: https://os.mbed.com/users/4180_1/notebook/using-a-speaker-for-audio-output/
- Adafruit Bluefruit Bluetooth: https://os.mbed.com/users/4180_1/notebook/adafruit-bluefruit-le-uart-friend---bluetooth-low-/
- Simple breadboard
- External Power Supply
- 2 330uF capacitors
Schematic/Block Diagram:
Source Code:
musical
#include "mbed.h" #include "ultrasonic.h" #include "rtos.h" #include "uLCD_4DGL.h" #include <string> // Define some colors: #define Q 0x808000 //OLIVE #define I 0x008000 //GREEN #define S 0xC0C0C0 //SILVER #define C 0x17202A //UFO GLASS #define D 0x797D7F //DARK GREY #define L 0x00FF00 //LIME #define P 0xFF00FF //PINK #define R 0xF1C40F //YELLOW #define O 0xF39C12 //ORANGE #define G 0xAAB7B8 //GREY #define _ 0x000000 //BLACK #define X 0xFFFFFF //WHITE #define B 0x0000FF //BLUE #define r 0xFF0000 //RED PwmOut audio(p26); //output to speaker amp or audio jack DigitalOut led(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); Serial pc(USBTX,USBRX); uLCD_4DGL uLCD(p28, p27, p29); Serial bluemod(p9,p10); Mutex myMut; volatile float half_cycle_time = 1; volatile float secondhalf_cycle_time = 1; //Buffers volatile float half_cycle_time2; volatile float half_cycle_time3; volatile float half_cycle_time4; volatile float half_cycle_time5; volatile float half_cycle_time6; volatile float half_cycle_time7; volatile float half_cycle_time8; volatile float half_cycle_time9; volatile float half_cycle_time10; volatile float secondhalf_cycle_time2; volatile float secondhalf_cycle_time3; volatile float secondhalf_cycle_time4; volatile float secondhalf_cycle_time5; volatile float secondhalf_cycle_time6; volatile float secondhalf_cycle_time7; volatile float secondhalf_cycle_time8; volatile float secondhalf_cycle_time9; volatile float secondhalf_cycle_time10; // Averaging Values: volatile float avghalf_cycle_time; volatile float secavghalf_cycle_time; volatile float pitch; volatile int x = 1; volatile int xpos = 1; volatile int y = 120; // Offset to start printing sinusoid volatile int color = WHITE; volatile bool major = true; // play D Major = true volatile bool cont = true; // continue with main thread once name inputted volatile string name; // Holds person's name volatile int scalar = 2; string s; //volatile string key; void Dmajor(void const *argument) { while(1) { led = !led; // Buffer for the key of D Major if(avghalf_cycle_time>300/scalar&&avghalf_cycle_time<700/scalar) { pitch = 1.0/294; audio.period(pitch);//D color = X; } else if(avghalf_cycle_time>700/scalar&&avghalf_cycle_time<1100/scalar) { pitch = 1.0/274; audio.period(pitch);//c# color = B; // blue } else if(avghalf_cycle_time>1100/scalar&&avghalf_cycle_time<1500/scalar) { if(major) { pitch = 1.0/246; audio.period(pitch); //B color = I; } else if(!major) { pitch = 1.0/232; audio.period(pitch); //Bflat color = I; } } else if(avghalf_cycle_time>1500/scalar&&avghalf_cycle_time<1900/scalar) { pitch = 1.0/220; audio.period(pitch);// A color = R; //yellow } else if(avghalf_cycle_time>1900/scalar&&avghalf_cycle_time<2300/scalar) { pitch = 1.0/194; audio.period(pitch); //G color = O; // ORANGE } else if(avghalf_cycle_time>2300/scalar&&avghalf_cycle_time<2700/scalar) { if(major) { pitch = 1.0/184; audio.period(pitch); //f# color = r; // red } else if(!major) { pitch = 1.0/176; audio.period(pitch); //fnat color = r; // red } } else if(avghalf_cycle_time>2700/scalar&&avghalf_cycle_time<3100/scalar) { pitch = 1.0/166; audio.period(pitch); //E color = G; // grey } else if(avghalf_cycle_time>3100/scalar) { pitch = 1.0/146; audio.period(pitch); //D color = Q; //OLIVE } // Buffer to control the volume if(secavghalf_cycle_time>200&&secavghalf_cycle_time<300)audio = .001; else if(secavghalf_cycle_time>200&&secavghalf_cycle_time<500) audio = .02; else if(secavghalf_cycle_time>500&&secavghalf_cycle_time<800) audio = .03; else if(secavghalf_cycle_time>800&&secavghalf_cycle_time<1100) audio = .05; else if(secavghalf_cycle_time>1100&&secavghalf_cycle_time<1400) audio = .1; else if(secavghalf_cycle_time>1400&&secavghalf_cycle_time<1700) audio = .2; else if(secavghalf_cycle_time>1700&&secavghalf_cycle_time<2000) audio = .25; else if(secavghalf_cycle_time>2000&&secavghalf_cycle_time<2300) audio = .4; else if(secavghalf_cycle_time>2300&&secavghalf_cycle_time<2700) audio = .5; Thread::wait(50); } } void newdist(int distance) { //update frequency based on new sonar data led2 = !led2; half_cycle_time5 = half_cycle_time4; half_cycle_time4 = half_cycle_time3; half_cycle_time3 = half_cycle_time2; half_cycle_time2 = half_cycle_time; half_cycle_time = distance<<3; avghalf_cycle_time = (half_cycle_time + half_cycle_time2 + half_cycle_time3 +half_cycle_time4 +half_cycle_time5)/5.0; } void secnewdist(int distance2) { led3 = !led3; secondhalf_cycle_time5 = secondhalf_cycle_time4; secondhalf_cycle_time4 = secondhalf_cycle_time3; secondhalf_cycle_time3 = secondhalf_cycle_time2; secondhalf_cycle_time2 = secondhalf_cycle_time; secondhalf_cycle_time = distance2<<3; secavghalf_cycle_time = (secondhalf_cycle_time + secondhalf_cycle_time2 + secondhalf_cycle_time3 +secondhalf_cycle_time4 +secondhalf_cycle_time5)/5.0; } //2 HC-SR04 Sonar modules ultrasonic mu(p12, p13, .1, 1, &newdist); // Pitch ultrasonic mu2(p14,p15,.1,1,&secnewdist); // Volume void sonar1(void const *argument) { while(1) { myMut.lock(); mu.checkDistance(); uLCD.locate(0,7); myMut.unlock(); Thread::wait(1); } } void sonar2(void const *argument) { while(1) { myMut.lock(); mu2.checkDistance(); myMut.unlock(); Thread::wait(50); } } void screen(void const *argument) { while(1) { myMut.lock(); uLCD.text_height(2); uLCD.locate(0,2); uLCD.printf("Pitch(Hz): %3.1f",1/pitch); uLCD.locate(0,4); uLCD.printf("Volume(%%): %2.2f", ((float(audio))/.5)*100); myMut.unlock(); Thread::wait(1000); } } void sinusoid(void const *argument) { while(1) { xpos = xpos+1; x = xpos % (144); y = 100 + 20*audio*sin(3.14*x/(pitch)); myMut.lock(); uLCD.filled_rectangle(x, 85,x+1 , 115, BLACK); uLCD.pixel(x, y, color); myMut.unlock(); Thread::wait(1); } } int main() { audio = 0; led = 0; char Temp1; char Temp2; uLCD.baudrate(3000000); uLCD.line(0,10,144,10,WHITE); uLCD.line(0,14,144,14,WHITE); uLCD.line(0,18,144,18,WHITE); uLCD.line(0,22,144,22,WHITE); uLCD.filled_circle(10,12,3,WHITE); uLCD.filled_circle(20,10,3,WHITE); uLCD.filled_circle(30,22,3,WHITE); uLCD.filled_circle(40,20,3,WHITE); uLCD.filled_circle(50,18,3,WHITE); uLCD.line(0,110,144,110,WHITE); uLCD.line(0,114,144,114,WHITE); uLCD.line(0,118,144,118,WHITE); uLCD.line(0,122,144,122,WHITE); uLCD.filled_circle(60,120,3,WHITE); uLCD.filled_circle(70,110,3,WHITE); uLCD.filled_circle(80,115,3,WHITE); uLCD.filled_circle(90,118,3,WHITE); uLCD.filled_circle(100,121,3,WHITE); uLCD.filled_circle(110,120,3,WHITE); uLCD.locate(0,6); uLCD.text_height(1); uLCD.text_width(1); uLCD.color(G); uLCD.printf("Welcome to\n\nMBED Theremin!"); wait(5); uLCD.cls(); uLCD.printf("\n\nPlease enter your name.\n\nPress:\n\n1) for minor \n\n2) for major\n\nPress the down key when finished."); wait(3); while(cont) { char bnum=0; char bhit=0; if(bluemod.readable()) { Temp1 = bluemod.getc(); if (Temp1 <= 'z' && Temp1 >= 'A') { s.push_back(Temp1); } else if (Temp1 == '!') { Temp2 = bluemod.getc(); if (Temp2=='B') { //button data packet bnum = bluemod.getc(); //button number bhit = bluemod.getc(); //1=hit, 0=release if (bluemod.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK? switch (bnum) { case '1': //button 1, number 1 (minor if (bhit=='1') { major = false; key = "d minor"; } break; case '2': //button 2, number 2 (major if (bhit=='1') { major = true; key = "D major"; } break; case '6': //button 6 down arrow if (bhit=='1') { uLCD.cls(); cont = false; } break; } // end switch } } } // End of button check }//end if(readable) }//end while uLCD.locate(0,5); uLCD.printf("You look great \ntoday, %s\n",s); wait(5); uLCD.locate(0,10); uLCD.printf("Enjoy your\nnew theremin!"); wait(2); uLCD.cls(); myMut.lock(); uLCD.locate(0,0); uLCD.text_height(2); uLCD.printf("Key: %s",key); myMut.unlock(); mu.startUpdates();//start measuring the distance with the sonar mu2.startUpdates(); Thread thread1(sonar1); Thread thread2(sonar2); Thread thread3(Dmajor); Thread thread5(screen); Thread thread6(sinusoid); while(1) { led4 = !led4; Thread::yield(); } }
Below is our project:
Import programFinalProjectRTOSVIII
Musical Theremin Using Bluetooth
Video Demo:
Images:
Please log in to post comments.