// // wirelessly connected cloud (Wireless Mesh Networking) // MIDI-like // spacial // sampler keyboard // // // Forest all/around @ MMCA, Seoul // // // 2019 12 11 // // (part-3) teensy35 : 'client:sampler' (mesh post --> play sounds) // //======================== //optionally pin3 will go HIGH/LOW in sync w/ sound PLAY/STOP #define MOTOR_PIN 3 // #define FAN_ACTION // this is noisy.... ==> not so recommendable.. #define NOTE_MIN 24 #define NOTE_MAX 84 //======================= //HACK: let auto-poweroff speakers stay turned ON! - (creative muvo mini) #define IDLE_FREQ 22000 #define IDLE_AMP 0 // --> creative muvo 2 doesn't need this. they just stay on! //teensy audio #include // #include // #include #include SdFatSdioEX SD; #include //teensy 3.5 with SD card #define SDCARD_CS_PIN BUILTIN_SDCARD #define SDCARD_MOSI_PIN 11 // not actually used #define SDCARD_SCK_PIN 13 // not actually used // GUItool: begin automatically generated code AudioPlaySdWav playSdWav1; //xy=224,265 AudioSynthWaveformSine sine1; //xy=236,361 AudioMixer4 mixer2; //xy=497,328 AudioMixer4 mixer1; //xy=499,245 AudioAmplifier amp1; //xy=633,245 AudioAmplifier amp2; //xy=634,328 AudioOutputAnalogStereo dacs1; //xy=788,284 AudioConnection patchCord1(playSdWav1, 0, mixer1, 0); AudioConnection patchCord2(playSdWav1, 1, mixer2, 0); AudioConnection patchCord3(sine1, 0, mixer1, 1); AudioConnection patchCord4(sine1, 0, mixer2, 1); AudioConnection patchCord5(mixer2, amp2); AudioConnection patchCord6(mixer1, amp1); AudioConnection patchCord7(amp1, 0, dacs1, 0); AudioConnection patchCord8(amp2, 0, dacs1, 1); // GUItool: end automatically generated code //task #include Scheduler runner; //sample # int sample_now = 0; //0~99 void sample_player_start() { //filename buffer - 8.3 naming convension! 8+1+3+1 = 13 char filename[13] = "NNN.WAV"; //search for the sound file int note = sample_now; int nnn = (note % 1000); // 0~999 int nn = (note % 100); // 0~99 filename[0] = '0' + (nnn / 100); // N__.WAV filename[1] = '0' + (nn / 10); // _N_.WAV filename[2] = '0' + (nn % 10); // __N.WAV //TEST Serial.println(filename); AudioNoInterrupts(); bool test = SD.exists(filename); AudioInterrupts(); if (!test) { Serial.println("... does not exist."); return; } //start the player! //NOTE: block out 're-triggering' // if (playSdWav1.isPlaying() == false) { playSdWav1.play(filename); // } #if defined(FAN_ACTION) //fan action digitalWrite(MOTOR_PIN, HIGH); #endif //mark the indicator : HIGH: ON digitalWrite(13, HIGH); //to wait a bit for updating isPlaying() delay(10); } void sample_player_stop() { //filename buffer - 8.3 naming convension! 8+1+3+1 = 13 char filename[13] = "NNN.WAV"; //search for the sound file int note = sample_now; int nnn = (note % 1000); // 0~999 int nn = (note % 100); // 0~99 filename[0] = '0' + (nnn / 100); // N__.WAV filename[1] = '0' + (nn / 10); // _N_.WAV filename[2] = '0' + (nn % 10); // __N.WAV //TEST Serial.println(filename); AudioNoInterrupts(); bool test = SD.exists(filename); AudioInterrupts(); if (!test) { Serial.println("... does not exist."); return; } //stop the player. if (playSdWav1.isPlaying() == true) { playSdWav1.stop(); #if defined(FAN_ACTION) //fan stop digitalWrite(MOTOR_PIN, LOW); #endif } } void sample_player_check() { if (playSdWav1.isPlaying() == false) { //mark the indicator : LOW: OFF digitalWrite(13, LOW); //let speaker leave turned ON! sine1.amplitude(IDLE_AMP); } else { //let speaker leave turned ON! sine1.amplitude(0); } } // Task sample_player_start_task(0, TASK_ONCE, sample_player_start); Task sample_player_stop_task(0, TASK_ONCE, sample_player_stop); Task sample_player_check_task(0, TASK_FOREVER, sample_player_check, &runner, true); //i2c #include #include "../../post.h" // DISABLED.. due to bi-directional I2C hardship. ==> use UART. // void requestEvent() { // Wire.write(" "); // no letter to send // } void receiveEvent(int numBytes) { //numBytes : how many bytes received(==available) static char letter_intro[POST_BUFF_LEN] = "................................"; // Serial.println("[i2c] on receive!"); int nb = Wire.readBytes(letter_intro, POST_LENGTH); if (POST_LENGTH == nb) { //convert to String String msg = String(letter_intro); Serial.println(msg); //parse letter string. // letter frame ( '[' + 30 bytes + ']' ) // : [123456789012345678901234567890] // 'MIDI' letter frame // : [123456789012345678901234567890] // : [KKKVVVG.......................] // : KKK - Key // .substring(1, 4); // : VVV - Velocity (volume/amp.) // .substring(4, 7); // : G - Gate (note on/off) // .substring(7, 8); String str_key = msg.substring(1, 4); String str_velocity = msg.substring(4, 7); String str_gate = msg.substring(7, 8); // Serial.println(str_key); // Serial.println(str_velocity); // Serial.println(str_gate); // int key = str_key.toInt(); if (key >= NOTE_MIN && key <= NOTE_MAX) { sample_now = key; // int velocity = str_velocity.toInt(); // 0 ~ 127 float amp_gain = (float)velocity / 127.0; amp1.gain(amp_gain); amp2.gain(amp_gain); // int gate = str_gate.toInt(); if (gate == 0) { sample_player_stop_task.restart(); Serial.println("sample_player_stop_task"); } else { sample_player_start_task.restart(); Serial.println("sample_player_start_task"); } } } } // SD TEST void printDirectory(File dir, int numTabs) { char filename[256] = ""; while(true) { File entry = dir.openNextFile(); if (!entry) { // no more files break; } for (uint8_t i=0; i get killed by watchdog.. :( // // while (!Serial) {} // --> use this.. to capture start-up messages, properly. very handy. //motor #if defined(FAN_ACTION) pinMode(MOTOR_PIN, OUTPUT); digitalWrite(MOTOR_PIN, LOW); #endif //i2c Wire.begin(I2C_ADDR); Wire.onReceive(receiveEvent); // DISABLED.. due to bi-directional I2C hardship. ==> use UART. // Wire.onRequest(requestEvent); //SD - AudioPlaySdWav @ teensy audio library needs SD.begin() first. don't forget/ignore! //+ let's additionally check contents of SD. if (!SD.begin()) { // if (!SD.begin(BUILTIN_SDCARD)) { Serial.println("[sd] initialization failed!"); return; } Serial.println("[sd] initialization done."); root = SD.open("/"); printDirectory(root, 0); //audio AudioMemory(20); #if !defined(TEENSY36) //NOTE!! teensy36 board.. output broken? .. so disable this for teensy36.. this is the cause?? dacs1.analogReference(EXTERNAL); #endif mixer1.gain(0,1.0); mixer1.gain(1,1.0); mixer1.gain(2,0); mixer1.gain(3,0); mixer2.gain(0,1.0); mixer2.gain(1,1.0); mixer2.gain(2,0); mixer2.gain(3,0); amp1.gain(1.0); amp2.gain(1.0); //let auto-poweroff speakers stay turned ON! sine1.frequency(IDLE_FREQ); //led pinMode(13, OUTPUT); digitalWrite(13, LOW); // LOW: OFF //player task runner.addTask(sample_player_start_task); runner.addTask(sample_player_stop_task); // Serial.println("[setup] done."); } void loop() { runner.execute(); }