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
Diff: main.cpp
- Revision:
- 0:bec3a12e79e7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Apr 18 16:06:38 2017 +0000 @@ -0,0 +1,242 @@ +/* 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 + } +} \ No newline at end of file