From 89a5bcb808711ee3cfe3b5e12a78709dc51291e6 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Sat, 30 May 2015 21:14:19 +0200 Subject: First working drafty arduino program --- arduino/fht_test.ino | 68 ------------ museduino/museduino.ino | 272 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+), 68 deletions(-) delete mode 100644 arduino/fht_test.ino create mode 100644 museduino/museduino.ino diff --git a/arduino/fht_test.ino b/arduino/fht_test.ino deleted file mode 100644 index 0e2f83c..0000000 --- a/arduino/fht_test.ino +++ /dev/null @@ -1,68 +0,0 @@ - -// FHT Options -#define FHT_N 256 -#define SCALE 256 -#define WINDOW 1 -#define REORDER 1 -#define LOG_OUT 1 -#define LIN_OUT 0 -#define LIN_OUT8 0 -#define OCTAVE 0 -#define OCT_NORM 0 - -#define BINS 128 - -#include - -void aquire_data() { - noInterrupts(); - - for (int i = 0; i < FHT_N; i++) { - while(!(ADCSRA & 0x10)); // wait for adc to be ready - ADCSRA = 0xf5; // restart adc - byte m = ADCL; // fetch adc data - byte j = ADCH; - int k = (j << 8) | m; // form into an int - k -= 0x0200; // form into a signed int - k <<= 6; // form into a 16b signed int - fht_input[i] = k; // put real data into bins - } - - interrupts(); -} - -void crunch_data() { - fht_window(); - fht_reorder(); - fht_run(); - //fht_mag_octave(); - fht_mag_log(); -} - -void setup() { - - Serial.begin(115200); - - TIMSK0 = 0; // turn off timer0 for lower jitter - ADCSRA = 0xe5; // set the adc to free running mode - ADMUX = 0x40; // use adc0 - DIDR0 = 0x01; // turn off the digital input for adc0 - -} - -char buf[2550] = ""; - -void loop() { - aquire_data(); - crunch_data(); - - for (int i = 0; i < BINS; i++) { - Serial.print(fht_log_out[i]); - Serial.print(' '); - } - - Serial.print('\n'); - - delay(10000); -} - diff --git a/museduino/museduino.ino b/museduino/museduino.ino new file mode 100644 index 0000000..b20e4ab --- /dev/null +++ b/museduino/museduino.ino @@ -0,0 +1,272 @@ + +/********************* + +EIG-2006 - Projet Arduino + +Museduino + +TRAN-GIRARD Pacien +NICOLE RĂ©mi + +**********************/ + + +/***** Parameters *****/ + +// FHT options +#define FHT_N 256 +#define SCALE 256 + +#define WINDOW 1 +#define REORDER 1 + +#define LOG_OUT 0 +#define LIN_OUT 0 +#define LIN_OUT8 1 + +#define OCTAVE 0 +#define OCT_NORM 0 + +// Data aquisition options +#define USE_FAST_AQUISITION 0 +#define PRESCALE_FACTOR 256 +#define DUMMY_SAMPLES 1 +#define WAIT_CYCLES 0 + +// Data bins +#define BINS 128 // FHT_N /2 +#define OCTAVES 8 // log2(FHT_N) + +// Note matching options +#define IGNORE_FIRST_BINS 2 +#define AMPLITUDE_THRESHOLD 10 + +// MIDI output +#define MIDI_INSTRUMENT 103 +#define MIDI_VOLUME 120 +#define MIDI_RESET_PIN 4 + + +/***** System setup *****/ + +#include +#include + +SoftwareSerial shieldSerial(2, 3); // RX, TX + +void setup_midi_shield() { + // setup soft serial link for MIDI control + shieldSerial.begin(31250); + + // reset the VS1053 + pinMode(MIDI_RESET_PIN, OUTPUT); + + digitalWrite(MIDI_RESET_PIN, LOW); + delay(100); + + digitalWrite(MIDI_RESET_PIN, HIGH); + delay(100); + + // set volume and instrument + talkMIDI(0xB0, 0x07, MIDI_VOLUME); + talkMIDI(0xC0, MIDI_INSTRUMENT, 0); +} + +void setup_serial_link() { + Serial.begin(115200); +} + +void setup_adc() { + #if USE_FAST_AQUISITION == 1 + ADCSRA = 0xe5; // set the adc to free running mode + ADMUX = 0x40; // use adc0 + DIDR0 = 0x01; // turn off the digital input for adc0 + #endif +} + +void setup() { + setup_serial_link(); + setup_midi_shield(); + setup_adc(); +} + + +/***** Data transforms *****/ + +void run_fht() { + #if WINDOW == 1 + fht_window(); + #endif + + #if REORDER == 1 + fht_reorder(); + #endif + + fht_run(); +} + +void mag_fht() { + #if LOG_OUT == 1 + fht_mag_log(); + #elif LIN_OUT == 1 + fht_mag_lin(); + #elif LIN_OUT8 == 1 + fht_mag_lin8(); + #endif +} + +int find_max_index() { + #if LOG_OUT == 1 + uint8_t* data = fht_log_out; + uint8_t m = 0; + #elif LIN_OUT == 1 + uint16_t* data = fht_lin_out; + uint16_t m = 0; + #elif LIN_OUT8 == 1 + uint8_t* data = fht_lin_out8; + uint8_t m = 0; + #endif + + int k = 0; + for (int i = IGNORE_FIRST_BINS; i < BINS; i++) { + if (data[i] > m && data[i] >= AMPLITUDE_THRESHOLD) { + m = data[i]; + k = i; + } + } + return k; +} + +int find_midi_note(float freq) { + float delta = 3.4028235E+38; // max float value + int note = 0; + for (int i = 0; i < 120; i++) { // exec time must be constant + float new_delta = abs(calc_midi_note_freq(i) - freq); + if (new_delta < delta) { + delta = new_delta; + note = i; + } + } + return note; +} + +float calc_bin_frequency(int k) { + #if DUMMY_SAMPLES == 0 + return (float(k) - 0.0616541) / 0.0287293; + #elif DUMMY_SAMPLES == 1 + return (float(k) - 0.00827068) / 0.0573534; + #endif +} + +float calc_midi_note_freq(int midi_note) { + return 8.1757989156 * pow(2, float(midi_note)/12); +} + + +/***** I/O wrappers *****/ + +void talkMIDI(byte cmd, byte data1, byte data2) { + shieldSerial.write(cmd); + shieldSerial.write(data1); + + // Some commands only have one data byte. + // All cmds less than 0xBn have 2 data bytes. + // (sort of: http://253.ccarh.org/handout/midiprotocol/) + if( (cmd & 0xF0) <= 0xB0) + shieldSerial.write(data2); +} + +void noteOn(byte channel, byte note, byte attack_velocity) { + talkMIDI((0x90 | channel), note, attack_velocity); +} + +void noteOff(byte channel, byte note, byte release_velocity) { + talkMIDI((0x80 | channel), note, release_velocity); +} + +void aquire_data() { + noInterrupts(); + + #if USE_FAST_AQUISITION == 1 + + for (int i = 0; i < FHT_N; i++) { + while(!(ADCSRA & 0x10)); // wait for adc to be ready + ADCSRA = 0xf5; // restart adc + byte m = ADCL; // fetch adc data + byte j = ADCH; + int k = (j << 8) | m; // form into an int + k -= 0x0200; // form into a signed int + k <<= 6; // form into a 16b signed int + fht_input[i] = k * PRESCALE_FACTOR; // put real data into bin + } + + #else + + for (int i = 0; i < FHT_N; i++) { + for (int s = -1; s < DUMMY_SAMPLES; s++) { + fht_input[i] = analogRead(A0) * PRESCALE_FACTOR; + } + } + + #endif + + interrupts(); +} + +void send_fht_output(int max_index, float fund_freq, int midi_note) { + #if LOG_OUT == 1 + uint8_t* data = fht_log_out; + #elif LIN_OUT == 1 + uint16_t* data = fht_lin_out; + #elif LIN_OUT8 == 1 + uint8_t* data = fht_lin_out8; + #endif + + Serial.print("{"); + Serial.print("\"spectrum\":["); + for (int i = 0; i < BINS; i++) { + if (i != 0) Serial.print(","); + Serial.print(data[i]); + } + Serial.print("],"); + + Serial.print("\"fundamental_bin\":"); + Serial.print(max_index); + Serial.print(","); + + Serial.print("\"fundamental_freq\":"); + Serial.print(fund_freq); + Serial.print(","); + + Serial.print("\"midi_note\":"); + Serial.print(midi_note); + + Serial.print("}\n"); +} + + +/***** Main program *****/ + +void loop() { + int note = 0; + + while (1) { + aquire_data(); + + run_fht(); + mag_fht(); + + int max_index = find_max_index(); + float fund_freq = calc_bin_frequency(max_index); + int midi_note = find_midi_note(fund_freq); + + send_fht_output(max_index, fund_freq, midi_note); + + if (midi_note != note) { + noteOff(0, note, 60); + noteOn(0, midi_note, 60); + + note = midi_note; + } + } +} -- cgit v1.2.3