Hexi_Acceleromagnetic_Synth: Michael Yarnell, Alec Pierce, 2017 The program turns an NXP Hexiwear, its development board, and a Click buzzer collectively into an 'acceleromagnetic' synthesizer. That is to say that the synthesizer is controlled primarily via the on-board accelerometer and magnetometer units.

Dependencies:   FXOS8700 Hexi_KW40Z NeatGUI PWM_6_Tone_Library

main.cpp

Committer:
MTYarnell
Date:
2017-04-18
Revision:
0:bec3a12e79e7

File content as of revision 0:bec3a12e79e7:

/* Hexi_Acceleromagnetic_Synth
    2017 Michael Yarnell, Alec Pierce
    Class Project: ECE49500 SP17 (MEMS/NEMS/IoT/Wearables)
    IUPUI - Purdue School of Engineering and Technology

 The following program turns an NXP Hexiwear, its development board, and a Click
  buzzer collectively into an 'acceleromagnetic' synthesizer. That is to say
  that the synthsizer is controlled primarily via the onboard accelerometer and 
  magnetometer units.
 Once the appropriate initializations have been made, the program plays a short,
  preprogrammed tune.  If, at any time, the left or right screen buttons are
  pressed, they each emit unique "drumbeat" note sequences.  The accelerometer
  and magnetometer are read.  The accelerometer x and y (pitch and roll, 
  respectively) control note selection.  The magnetometer value RMS is
  calculated, and if the magnetic field RMS is greater than 250uT, the 
  instrument will emit corresponding notes.
  
 Adapted from examples:
  "Hexi_Magneto-v2_Example" 
    https://developer.mbed.org/teams/Hexiwear/code/Hexi_Magneto-v2_Example/
  "Hexi_Accelero-v2_Example" 
    https://developer.mbed.org/teams/Hexiwear/code/Hexi_Accelero-v2_Example/
  "Hexi_Click_Buzzer-v2_Example" 
    https://developer.mbed.org/teams/Hexiwear/code/Hexi_Click_Buzzer-v2_Example/
  "Hexi_Bubble_Game" 
    https://developer.mbed.org/teams/Hexiwear/code/Hexi_Bubble_Game/
*/

// TYPEDEFS
typedef     signed char             int8_t;
typedef     unsigned char           uint8_t;
typedef     signed long long int    int64_t;
typedef     unsigned long long int  uint64_t;

// LIBRARIES
//  Note that pwm_6_tone.h has been modified from the default library header.
#include "mbed.h"
#include <pwm_6_tone.h>
#include "Hexi_KW40Z.h"
#include "FXOS8700.h"
#include "string.h"

// PIN CONNECTIONS
// Define the Buzzer Pinout (PWM Out)
PwmOut Buzzer(PTA10);                               
// Instantiate the Hexi KW40Z Driver (UART TX, UART RX)
KW40Z kw40z_device(PTE24, PTE25);                   
// Accelerometer and Magnetometer instantiation
FXOS8700 mag(PTC11, PTC10);                         
FXOS8700 accel(PTC11, PTC10);
// Initialize Face LED
DigitalOut led1(LED_GREEN);
// Initialize Serial port
//Serial pc(USBTX, USBRX);          // Include to debug modified sensor values
                                    //  or enter a practice mode. 

// VARIABLES
float accel_data[3]; // Storage for the data from the sensor
float mag_data[3];   // Storage for the data from the sensor
float mag_rms=0.0;   // RMS value to be computed from sensor input

    // From Bubble
int xposg = 0;       // The roll position of the unit
int yposg = 0;       // The pitch position of the unit

    // New Variables
        // Note is a floating-point value that bears a number to send to the
        //  Tune function.
float  Note = 0.0;
        // This table holds the values determined to play the appropriate notes
        //  as reverse-engineered from the values in 
        //  "Hexi_Click_Buzzer-v2_Example" to widen range to nearly six octaves.
float  C_1 = 1000000/Do1, Cs_1 = 1000000/Do1s, D_1 = 1000000/Re1, Ds_1 = 1000000/Re1s,
       E_1 = 1000000/Mi1, F_1 = 1000000/Fa1, Fs_1 = 1000000/Fa1s, G_1 = 1000000/So1,
       Gs_1 = 1000000/So1s, A_1 = 1000000/La1, As_1 = 1000000/La1s, B_1 = 1000000/Ti1,
       
       C_2 = 1000000/Do2, Cs_2 = 1000000/Do2s, D_2 = 1000000/Re2, Ds_2 = 1000000/Re2s,
       E_2 = 1000000/Mi2, F_2 = 1000000/Fa2, Fs_2 = 1000000/Fa2s, G_2 = 1000000/So2,
       Gs_2 = 1000000/So2s, A_2 = 1000000/La2, As_2 = 1000000/La2s, B_2 = 1000000/Ti2,
       
       C_3 = 1000000/Do3, Cs_3 = 1000000/Do3s, D_3 = 1000000/Re3, Ds_3 = 1000000/Re3s,
       E_3 = 1000000/Mi3, F_3 = 1000000/Fa3, Fs_3 = 1000000/Fa3s, G_3 = 1000000/So3,
       Gs_3 = 1000000/So3s, A_3 = 1000000/La3, As_3 = 1000000/La3s, B_3 = 1000000/Ti3,
       
       C_4 = 1000000/Do4, Cs_4 = 1000000/Do4s, D_4 = 1000000/Re4, Ds_4 = 1000000/Re4s,
       E_4 = 1000000/Mi4, F_4 = 1000000/Fa4, Fs_4 = 1000000/Fa4s, G_4 = 1000000/So4,
       Gs_4 = 1000000/So4s, A_4 = 1000000/La4, As_4 = 1000000/La4s, B_4 = 1000000/Ti4,
       
       C_5 = 1000000/Do5, Cs_5 = 1000000/Do5s, D_5 = 1000000/Re5, Ds_5 = 1000000/Re5s,
       E_5 = 1000000/Mi5, F_5 = 1000000/Fa5, Fs_5 = 1000000/Fa5s, G_5 = 1000000/So5,
       Gs_5 = 1000000/So5s, A_5 = 1000000/La5, As_5 = 1000000/La5s, B_5 = 1000000/Ti5,
       
       C_6 = 1000000/Do6, Cs_6 = 1000000/Do6s, D_6 = 1000000/Re6, Ds_6 = 1000000/Re6s,
       E_6 = 1000000/Mi6, F_6 = 1000000/Fa6, Fs_6 = 1000000/Fa6s, G_6 = 1000000/So6,
       Gs_6 = 1000000/So6s, A_6 = 1000000/La6, As_6 = 1000000/La6s, B_6 = 1000000/Ti6;

//FUNCTIONS
void ButtonLeft(void)
{
// "Beat" 1
    Tune(Buzzer, C_5, 1); Tune(Buzzer, E_2, 1); 
    Tune(Buzzer, C_5, 1); Tune(Buzzer, E_1, 1);
}

void ButtonRight(void)
{
// "Beat" 2
    Tune(Buzzer, C_3, 1); Tune(Buzzer, E_2, 1); 
    Tune(Buzzer, C_1, 1); Tune(Buzzer, E_1, 1);
}

int main()
{
// Instantiate Buttons   
    kw40z_device.attach_buttonLeft(&ButtonLeft);
    kw40z_device.attach_buttonRight(&ButtonRight);
    
// Configure Accelerometer, Magnetometer FXOS8700
    accel.accel_config();
    mag.mag_config();
    
// Startup tune tones
    Tune(Buzzer, D_6,  2); wait_ms(5);   Tune(Buzzer, D_4,  2); wait_ms(5);
    Tune(Buzzer, C_5,  2); wait_ms(5);   Tune(Buzzer, D_4,  4); wait_ms(5);        
    Tune(Buzzer, D_2,  4); wait_ms(5);   Tune(Buzzer, Cs_1, 2); wait_ms(10);
    Tune(Buzzer, C_1, 16); wait_ms(10);  Tune(Buzzer, C_2,  8); wait_ms(25);
    Tune(Buzzer, C_3,  4); wait_ms(60);  Tune(Buzzer, C_4,  2); wait_ms(40);
    Tune(Buzzer, C_5,  4); wait_ms(100);

// This loop, modified from from the Bubble game example, locates the
//  x/y accelerometer information (within boundaries) to determine
//  the position of the user and thus the note to play.
    while(1) {

// Get accelerometer data
        accel.acquire_accel_data_g(accel_data);
        xposg=(accel_data[1] * (-20.0));
        if (xposg >  30) xposg =  30;  // Notes: 12 per octave
        if (xposg < -30) xposg = -30;
        yposg=(accel_data[0] * (40.0));
        if (yposg >  30) yposg =  30;  // Octaves: 6 available
        if (yposg < -30) yposg = -30;

// Find Note
//  Program first attempts to find Octave from accelerometer y values.
//  Then it further determines the and assigns the value of the note
//  from the x value.

        if (yposg > 29) {                  // Octave 1
            if (xposg >  20) Note = C_1;  // C
            if (xposg >  16) Note = Cs_1; // Cs
            if (xposg >  12) Note = D_1;  // D
            if (xposg >   8) Note = Ds_1; // Ds
            if (xposg >   4) Note = E_1;  // E
            if (xposg >=  0) Note = F_1;  // F
            if (xposg >  -4) Note = Fs_1; // Fs
            if (xposg >  -8) Note = G_1;  // G
            if (xposg > -12) Note = Gs_1; // Gs
            if (xposg > -16) Note = A_1;  // A
            if (xposg > -20) Note = As_1; // As
            else             Note = B_1;  // B
        } else if (yposg > 15) {           // Octave 2
            if (xposg >  20) Note = C_2;  // C
            if (xposg >  16) Note = Cs_2; // Cs
            if (xposg >  12) Note = D_2;  // D
            if (xposg >   8) Note = Ds_2; // Ds
            if (xposg >   4) Note = E_2;  // E
            if (xposg >=  0) Note = F_2;  // F
            if (xposg >  -4) Note = Fs_2; // Fs
            if (xposg >  -8) Note = G_2;  // G
            if (xposg > -12) Note = Gs_2; // Gs
            if (xposg > -16) Note = A_2;  // A
            if (xposg > -20) Note = As_2; // As
            else             Note = B_2;  // B
        } else if (yposg >= 0) {           // Octave 3
            if (xposg >  20) Note = C_3;  // C
            if (xposg >  16) Note = Cs_3; // Cs
            if (xposg >  12) Note = D_3;  // D
            if (xposg >   8) Note = Ds_3; // Ds
            if (xposg >   4) Note = E_3;  // E
            if (xposg >=  0) Note = F_3;  // F
            if (xposg >  -4) Note = Fs_3; // Fs
            if (xposg >  -8) Note = G_3;  // G
            if (xposg > -12) Note = Gs_3; // Gs
            if (xposg > -16) Note = A_3;  // A
            if (xposg > -20) Note = As_3; // As
            else             Note = B_3;  // B
        } else if (yposg > -15) {          // Octave 4
            if (xposg >  20) Note = C_4;  // C
            if (xposg >  16) Note = Cs_4; // Cs
            if (xposg >  12) Note = D_4;  // D
            if (xposg >   8) Note = Ds_4; // Ds
            if (xposg >   4) Note = E_4;  // E
            if (xposg >=  0) Note = F_4;  // F
            if (xposg >  -4) Note = Fs_4; // Fs
            if (xposg >  -8) Note = G_4;  // G
            if (xposg > -12) Note = Gs_4; // Gs
            if (xposg > -16) Note = A_4;  // A
            if (xposg > -20) Note = As_4; // As
            else             Note = B_4;  // B
        } else if (yposg > -29) {          // Octave 5
            if (xposg >  20) Note = C_5;  // C
            if (xposg >  16) Note = Cs_5; // Cs
            if (xposg >  12) Note = D_5;  // D
            if (xposg >   8) Note = Ds_5; // Ds
            if (xposg >   4) Note = E_5;  // E
            if (xposg >=  0) Note = F_5;  // F
            if (xposg >  -4) Note = Fs_5; // Fs
            if (xposg >  -8) Note = G_5;  // G
            if (xposg > -12) Note = Gs_5; // Gs
            if (xposg > -16) Note = A_5;  // A
            if (xposg > -20) Note = As_5; // As
            else             Note = B_5;  // B
        } else {                           // Octave 6
            if (xposg >  20) Note = C_6;  // C
            if (xposg >  16) Note = Cs_6; // Cs
            if (xposg >  12) Note = D_6;  // D
            if (xposg >   8) Note = Ds_6; // Ds
            if (xposg >   4) Note = E_6;  // E
            if (xposg >=  0) Note = F_6;  // F
            if (xposg >  -4) Note = Fs_6; // Fs
            if (xposg >  -8) Note = G_6;  // G
            if (xposg > -12) Note = Gs_6; // Gs
            if (xposg > -16) Note = A_6;  // A
            if (xposg > -20) Note = As_6; // As
            else             Note = B_6;  // B
        }

// Get magnetometer data
        mag.acquire_mag_data_uT(mag_data);
// Find RMS values of this 3-axis reading
        mag_rms = sqrt(((mag_data[0] * mag_data[0]) + (mag_data[1] * mag_data[1]) + (mag_data[2] * mag_data[2])) / 3);

        //printf("\tX: %i \tY: %i \tMAGRMS: %i", xposg, yposg, mag_rms);
        // Above line displays modified sensor results, useful for practice or
        //  debugging.

// If the magnetic field is strong enough, play a note.
        if (mag_rms > 150) { 
                Tune(Buzzer, Note, 2); }// Timing is out of 16ths
    }
}