Digital Sound Synthesizer for lab 4
Dependencies: LSM9DS1_Library_cal PinDetect mbed-rtos mbed
main.cpp
- Committer:
- nsloth
- Date:
- 2016-03-15
- Revision:
- 0:0d977b83a68d
File content as of revision 0:0d977b83a68d:
#include "mbed.h" #include "rtos.h" #include "mpr121.h" #include "PinDetect.h" #include "LSM9DS1.h" // Sound waveform synthesizer // The program precomputes 128 data points on one wave cycle // for triangular, sawtooth, and sine waves. These are stored // and outout to the PWM to vary the PWM duty cycle. A very high // PWM frequency is used and the frequency of the output soundwave // is changed by changing the sampling rate. The program uses the // IMU to shift frequencies, the keypad to choose center frequencies, // the RGB LED to visually display pitch, and a pushbutton to switch between wave modes. #define PI 3.141592653589793238462 InterruptIn irq(p11); I2C i2c1(p9,p10); Mpr121 touchpad(&i2c1, Mpr121::ADD_VSS); PwmOut PWM(p26); Serial pc(USBTX,USBRX); LSM9DS1 IMU(p28, p27, 0xD6, 0x3C); Mutex stdio_mutex; PwmOut RGBLED_r(p21); PwmOut RGBLED_g(p22); PwmOut RGBLED_b(p23); PinDetect pb1(p17); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); //Global variables used by interrupt routines and threads volatile int i=0; volatile int j=0; float sineInit[128]; float sawInit[128]; float triInit[128]; volatile float baseFreq = 440; float maxDeltaFreq = 200; float maxDeltaXAxis = 15; volatile float freq = 900; volatile float deltaFreq = 0; volatile float deltaXAxis = 0; volatile float deltaXAxisOld = 0; float frequencyScales[12] = {261.626, 293.665, 329.628, 349.228, 391.995, 440.0, 493.883, 523.251, 587.33, 659.255, 783.991, 880}; enum Waveforms {sine=0,sawTooth,triangle}; Waveforms wave = sine; //Samples IMU every .5 seconds and adjusts frequencies accordingly void sample_IMU(void const *args) { while(1) { if(IMU.accelAvailable()) { stdio_mutex.lock(); deltaXAxisOld = deltaXAxis; deltaXAxis = (0.0024*IMU.readAccel(X_AXIS)); //Measures difference of IMU from base value of 0 stdio_mutex.unlock(); } Thread::wait(500); } } //Plays the current waveform at the current frequency void playSineWave() { while(j<150) { //Controls how many cycles. Plays about 3 full cycles switch(wave) { case sine: PWM = (sineInit[i]); break; case sawTooth: PWM = sawInit[i]; break; case triangle: PWM = triInit[i]; break; default: led2 = 0; led3 = 0; led4 = 0; break; } //(1.0 + sin((float(i)*freq*6.28318530717959/(128.0))))/2.0); // increment pointer and wrap around back to 0 at 128 if(i>60) { j++; } i = (i+1) & 0x07F; wait_us(1000000.0/((freq+deltaFreq)*128)); } //At the end of 3 cycles, reset counters i=0; j=0; int value=touchpad.read(0x00); value +=touchpad.read(0x01)<<8; if (value == 0) { //Reset values if keypad is not being touched PWM = 0; deltaFreq = 0; deltaXAxis = 0; RGBLED_r = 0; RGBLED_g = 0; RGBLED_b = 0; } else { //If the keypad has a nonzero value, update the frequency and play more cycles stdio_mutex.lock(); float diff = (abs(deltaXAxis - deltaXAxisOld) > 2) ? deltaXAxis : deltaXAxisOld; //Makes the delta frequency resistant to noise in the IMU stdio_mutex.unlock(); //Calculates delta frequency from center frequency based off of IMU accelerometer if(abs(diff) > maxDeltaXAxis) deltaFreq = maxDeltaFreq; else { deltaFreq = diff/maxDeltaXAxis*maxDeltaFreq; } RGBLED_r = abs(freq-deltaFreq-220)/880; RGBLED_g = abs(freq-220)/880; RGBLED_b = abs(freq+deltaFreq-220)/880;; playSineWave(); } } //Called when the touchpad is tapped void fallInterrupt() { int key_code=0; int n=0; int value=touchpad.read(0x00); value +=touchpad.read(0x01)<<8; for (n=0; n<12; n++) { if (((value>>n)&0x01)==1) { key_code=n+1; } } //sets frequency based on the tapped value freq = frequencyScales[key_code-1]; if (value != 0) { playSineWave(); } } //Switches the current waveform and leds void pb1_released_callback(void){ if (wave == triangle) { led2 = 1; led3 = 0; led4 = 0; wave = sine; } else if (wave == sine) { led2 = 0; led3 = 1; led4 = 0; wave = sawTooth; } else { led2 = 0; led3 = 0; led4 = 1; wave = triangle; } } int main() { pc.printf("Program starting."); PWM.period(1.0/200000.0); led2 = 1; led3 = 0; led4 = 0; // Precompute 128 sample points on one wave cycle for three wave forms // used for continuous wave output later for(int k=0; k<128; k++) { sineInit[k] = 1.0*((1.0 + sin((float(k)/128.0*2*PI)))/2.0); sawInit[k] = (1.0 + ((-2.0*1.0/PI)*atan(cos(float(k)*PI/128.0)/sin(float(k)*PI/128.0))))/2.0; triInit[k] = (1.0 + ((2.0*1.0/PI)*asin(sin(2.0*PI*float(k)/128.0))))/2.0; // scale the waves from 0.0 to 1.0 - as needed for AnalogOut arg } //Configure the IMU IMU.begin(); if (!IMU.begin()) { pc.printf("Failed to communicate with LSM9DS1.\n"); } IMU.calibrate(1); //Configure the Push button pb1.mode(PullUp); wait(0.01); pb1.attach_deasserted(&pb1_released_callback); pb1.setSampleFrequency(); //Set up the I2C Touch keypad interrupt irq.fall(&fallInterrupt); irq.mode(PullUp); //And the IMU Sample thread Thread t1(sample_IMU); while(1) {} }