diff --git a/sampler/platformio.ini b/sampler/platformio.ini index 3e51ed2..0d45977 100644 --- a/sampler/platformio.ini +++ b/sampler/platformio.ini @@ -14,44 +14,19 @@ default_envs = teensy35 [common] lib_ignore = Audio, SD lib_deps = - 721 ; TaskScheduler - 322 ; SdFat - 401 ; Adafruit SleepyDog Library + 721@3.0.2 ; TaskScheduler + 322@1.0.7 ; SdFat [env:teensy35] -platform = teensy +platform = teensy@3.6.0 board = teensy35 framework = arduino lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} [env:teensy36] -platform = teensy +platform = teensy@3.6.0 board = teensy36 framework = arduino lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} - - -; [platformio] -; env_default = teensy35 -; -; [common] -; lib_ignore = Audio, SD -; lib_deps = -; 721@3.0.2 ; TaskScheduler -; 322@1.0.7 ; SdFat -; -; [env:teensy35] -; platform = teensy@3.6.0 -; board = teensy35 -; framework = arduino -; lib_deps = ${common.lib_deps} -; lib_ignore = ${common.lib_ignore} -; -; [env:teensy36] -; platform = teensy@3.6.0 -; board = teensy36 -; framework = arduino -; lib_deps = ${common.lib_deps} -; lib_ignore = ${common.lib_ignore} diff --git a/sampler/src/main.cpp b/sampler/src/main.cpp index 33cb76c..7f0dc1a 100644 --- a/sampler/src/main.cpp +++ b/sampler/src/main.cpp @@ -16,33 +16,14 @@ // (part-3) teensy35 : 'client:sampler' (mesh post --> play sounds) // -// -// 2019 12 29 -// -// multiple sound playback -> 4 voices -- TESTING -// - -//-------------------- -// -// 'ANALOG_REF_EXTERNAL_3P3V' -// --> this will output 3.3v-pp from dacs pins of the board. -// outdoor or big space. you will need this. -// but, teensy36 board dacs pins once might have burned off cause of this? -// teensy35 was okay since they are stronger (5V compatible I/O) -// -// #define ANALOG_REF_EXTERNAL_3P3V -// -// 'LED_INDICATOR' -// --> this will enable red LED on/off according to the file playback status. -// -#define LED_INDICATOR -//-------------------- - -//watchdog -#include +//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 @@ -53,285 +34,98 @@ SdFatSdioEX SD; #define SDCARD_SCK_PIN 13 // not actually used // GUItool: begin automatically generated code -AudioPlaySdWav playSdWav1; //xy=183,90 -AudioPlaySdWav playSdWav2; //xy=185,253 -AudioPlaySdWav playSdWav3; //xy=187,411 -AudioPlaySdWav playSdWav4; //xy=188,579 -AudioAmplifier amp1; //xy=374,49 -AudioAmplifier amp2; //xy=375,132 -AudioAmplifier amp3; //xy=377,219 -AudioAmplifier amp4; //xy=378,302 -AudioAmplifier amp5; //xy=378,370 -AudioAmplifier amp6; //xy=379,453 -AudioAmplifier amp7; //xy=381,540 -AudioAmplifier amp8; //xy=382,623 -AudioMixer4 mixer2; //xy=620,413 -AudioMixer4 mixer1; //xy=621,210 -AudioOutputAnalogStereo dacs1; //xy=812,318 -AudioConnection patchCord1(playSdWav1, 0, amp1, 0); -AudioConnection patchCord2(playSdWav1, 1, amp2, 0); -AudioConnection patchCord3(playSdWav2, 0, amp3, 0); -AudioConnection patchCord4(playSdWav2, 1, amp4, 0); -AudioConnection patchCord5(playSdWav3, 0, amp5, 0); -AudioConnection patchCord6(playSdWav3, 1, amp6, 0); -AudioConnection patchCord7(playSdWav4, 0, amp7, 0); -AudioConnection patchCord8(playSdWav4, 1, amp8, 0); -AudioConnection patchCord9(amp1, 0, mixer1, 0); -AudioConnection patchCord10(amp2, 0, mixer2, 0); -AudioConnection patchCord11(amp3, 0, mixer1, 1); -AudioConnection patchCord12(amp4, 0, mixer2, 1); -AudioConnection patchCord13(amp5, 0, mixer1, 2); -AudioConnection patchCord14(amp6, 0, mixer2, 2); -AudioConnection patchCord15(amp7, 0, mixer1, 3); -AudioConnection patchCord16(amp8, 0, mixer2, 3); -AudioConnection patchCord17(mixer2, 0, dacs1, 1); -AudioConnection patchCord18(mixer1, 0, dacs1, 0); +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 -// -class Voice { - //private - - //teensy audio - AudioPlaySdWav& player; - AudioAmplifier& ampL; - AudioAmplifier& ampR; - - // a filename buffer - char filename[13]; - -public: - - // - int note_now; - int velocity_now; - - // - Voice(AudioPlaySdWav& player_, AudioAmplifier& ampL_, AudioAmplifier& ampR_) - : player(player_) - , ampL(ampL_) - , ampR(ampR_) - { - //initializations - note_now = 0; - velocity_now = 0; - strcpy(filename, "NNN.WAV"); - } - - // - void noteOn(int note) { - // present my 'note' -> 'occupied'. - note_now = note; - // set filename to play... - 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 - // the filename to play is... - Serial.println(filename); - // go! (re-triggering) - // if (player.isPlaying()) player.stop(); - player.play(filename); - // --> we just believe that this 'file' is existing & available. NO additional checking. - delay(10); - // --> let's wait a bit before exit, to give more room to work for background workers(==filesystem|audio-interrupts) - // --> if we get too fast 'player.play' twice, then the system might get broken/stalled. ? - } - // - void noteOff() { - player.stop(); - delay(10); // wait to close file? - // present my 'note' -> 'free'. - note_now = 0; - } - // - void setVelocity(int val) { - if (val < 0) val = 0; - float vv = (float)val / 127; // allowing +gain for values over 127. - ampL.gain(vv); - ampR.gain(vv); - } - // - bool isPlaying() { - return player.isPlaying(); - } -}; - -// voice banks -#include -#include -static Voice __voice_1(playSdWav1, amp1, amp2); -static Voice __voice_2(playSdWav2, amp3, amp4); -static Voice __voice_3(playSdWav3, amp5, amp6); -static Voice __voice_4(playSdWav4, amp7, amp8); -static std::vector poly_bank; -static std::deque< std::pair > poly_queue; - //task #include Scheduler runner; -// polyphonics -static int note_sched = 0; -static int velocity_sched = 0; -void scheduleNoteOn() +//sample # +int sample_now = 0; //0~99 +void sample_player_start() { //filename buffer - 8.3 naming convension! 8+1+3+1 = 13 - char fname[13] = "NNN.WAV"; + char filename[13] = "NNN.WAV"; //search for the sound file - int note = note_sched; + int note = sample_now; int nnn = (note % 1000); // 0~999 int nn = (note % 100); // 0~99 - fname[0] = '0' + (nnn / 100); // N__.WAV - fname[1] = '0' + (nn / 10); // _N_.WAV - fname[2] = '0' + (nn % 10); // __N.WAV + filename[0] = '0' + (nnn / 100); // N__.WAV + filename[1] = '0' + (nn / 10); // _N_.WAV + filename[2] = '0' + (nn % 10); // __N.WAV //TEST - Serial.println(fname); + Serial.println(filename); AudioNoInterrupts(); - bool test = SD.exists(fname); + bool test = SD.exists(filename); AudioInterrupts(); if (!test) { Serial.println("... does not exist."); return; } - //ok, let's schedule a voice - //btw, is it already playing? - // --> entry : (# of voice bank, playing note #) - bool is_already = false; - for (uint32_t idx = 0; idx < poly_queue.size(); idx++) { - if (poly_queue[idx].second == note) { - //oh, it is alreay playing - // --> what to do? - // (1) re-trigger (stop-and-restart) - // is_already = true; - // Voice& v = poly_bank[poly_queue[idx].first]; - // v.noteOff(); - // v.noteOn(note); - // v.setVelocity(velocity_sched); - // break; - // (2) do nothing (just let it play till end) - // is_already = true; - // break; - // (3) trigger a new one? (schedule a new one overlapping) - // --> then you just ignore the fact. - // i.e. do not tick 'is_already = true', - // then a new one will be automatically assigned. - break; - } - } - //it's sth. new.. - if (is_already == false) { - //fine, is there idle voice? - bool is_found_idle = false; - for (uint32_t idx = 0; idx < poly_bank.size(); idx++) { - if (poly_bank[idx].note_now == 0) { - //cool, got one. - is_found_idle = true; - //play start-up - Voice& v = poly_bank[idx]; - v.noteOn(note); - v.setVelocity(velocity_sched); - //leave a record : (# of voice bank, playing note #) - poly_queue.push_back(std::pair(idx, note)); - break; - } - } - //oh, no idle one! - if (is_found_idle == false) { - //then, who's the oldest? - int oldest = poly_queue.front().first; - poly_bank[oldest].noteOff(); - poly_queue.pop_front(); - // - int newentry = oldest; - // - Voice& v = poly_bank[newentry]; - v.noteOn(note); - v.setVelocity(velocity_sched); - //leave a record : (# of voice bank, playing note #) - poly_queue.push_back(std::pair(newentry, note)); - } - } - //small waiting time for 'isPlaying' update? - // delay(10); - //monitoring the queue - Serial.println("--notoOn:poly_queue---"); - Serial.println("(voice#, note#)"); - for (uint32_t idx = 0; idx < poly_queue.size(); idx++) { - Serial.print("("); - Serial.print(poly_queue[idx].first); - Serial.print(", "); - Serial.print(poly_queue[idx].second); - Serial.println(")"); - } - Serial.println(); + //start the player! + //NOTE: block out 're-triggering' + // if (playSdWav1.isPlaying() == false) { + playSdWav1.play(filename); + // } + //mark the indicator : HIGH: ON + digitalWrite(13, HIGH); + //to wait a bit for updating isPlaying() + delay(10); } -// -Task scheduleNoteOn_task(0, TASK_ONCE, scheduleNoteOn); -// -void scheduleNoteOff() { - for (auto it = poly_queue.begin(); it != poly_queue.end(); ++it) { - //is this meaningful, btw? - if ((*it).second == note_sched) { - //okay. we've got that. - Serial.println("okay. we've got that."); - //a record : (# of voice bank, playing note #) - poly_bank[(*it).first].noteOff(); // stop the bank - poly_queue.erase(it); // remove the record - break; - } +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; } - //monitoring the queue - Serial.println("--notoOff:poly_queue---"); - Serial.println("(voice#, note#)"); - for (uint32_t idx = 0; idx < poly_queue.size(); idx++) { - Serial.print("("); - Serial.print(poly_queue[idx].first); - Serial.print(", "); - Serial.print(poly_queue[idx].second); - Serial.println(")"); + //stop the player. + if (playSdWav1.isPlaying() == true) { + playSdWav1.stop(); } - Serial.println(); } -// -Task scheduleNoteOff_task(0, TASK_ONCE, scheduleNoteOff); - -// -extern Task playcheck_task; -void playcheck() { - // - if (playcheck_task.isFirstIteration()) { - //watchdog - Watchdog.enable(1000); - } - // -#if defined(LED_INDICATOR) - // - bool is_nosound = true; - for (uint32_t idx = 0; idx < poly_bank.size(); idx++) { - if (poly_bank[idx].isPlaying()) { - is_nosound = false; - } - } - if (is_nosound) { +void sample_player_check() { + if (playSdWav1.isPlaying() == false) { //mark the indicator : LOW: OFF digitalWrite(13, LOW); - } else { - //mark the indicator : HIGH: ON - digitalWrite(13, HIGH); + //let speaker leave turned ON! + sine1.amplitude(IDLE_AMP); + } + else { + //let speaker leave turned ON! + sine1.amplitude(0); } -#endif - - // // - // Serial.print("AM_max:"); - // Serial.println(AudioMemoryUsageMax()); - - //watchdog - Watchdog.reset(); - // Serial.println("Watchdog.reset"); } // -Task playcheck_task(200, TASK_FOREVER, playcheck); +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 @@ -377,17 +171,20 @@ void receiveEvent(int numBytes) { // int key = str_key.toInt(); - int velocity = str_velocity.toInt(); // 0 ~ 127 - int gate = str_gate.toInt(); - + 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) { - note_sched = key; - scheduleNoteOff_task.restart(); + sample_player_stop_task.restart(); + Serial.println("sample_player_stop_task"); } else { - note_sched = key; - velocity_sched = velocity; - scheduleNoteOn_task.restart(); + sample_player_start_task.restart(); + Serial.println("sample_player_start_task"); } } } @@ -439,8 +236,10 @@ void setup() { // DISABLED.. due to bi-directional I2C hardship. ==> use UART. // Wire.onRequest(requestEvent); - //SD + //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; } @@ -448,51 +247,34 @@ void setup() { root = SD.open("/"); printDirectory(root, 0); - //polyphonics - 4 voices - poly_bank.push_back(__voice_1); - poly_bank.push_back(__voice_2); - poly_bank.push_back(__voice_3); - poly_bank.push_back(__voice_4); - //audio - AudioMemory(20); // <-- used AudioMemoryUsageMax() to check out! + AudioMemory(20); #if !defined(TEENSY36) - //NOTE!! teensy36 board.. - // output broken? .. - // so disable this for teensy36.. - // this is the cause?? -#if defined(ANALOG_REF_EXTERNAL_3P3V) + //NOTE!! teensy36 board.. output broken? .. so disable this for teensy36.. this is the cause?? dacs1.analogReference(EXTERNAL); -#endif #endif mixer1.gain(0,1.0); mixer1.gain(1,1.0); - mixer1.gain(2,1.0); - mixer1.gain(3,1.0); + mixer1.gain(2,0); + mixer1.gain(3,0); mixer2.gain(0,1.0); mixer2.gain(1,1.0); - mixer2.gain(2,1.0); - mixer2.gain(3,1.0); + mixer2.gain(2,0); + mixer2.gain(3,0); amp1.gain(1.0); amp2.gain(1.0); - amp3.gain(1.0); - amp4.gain(1.0); - amp5.gain(1.0); - amp6.gain(1.0); - amp7.gain(1.0); - amp8.gain(1.0); - //tasks - runner.addTask(playcheck_task); - playcheck_task.restartDelayed(60000); // watchdog start after 60 sec. waiting task scheduling system stabilizing takes that so much time! - // - runner.addTask(scheduleNoteOn_task); - runner.addTask(scheduleNoteOff_task); + //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."); } diff --git a/src/main.cpp b/src/main.cpp index 6edb1c0..cd587f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,7 +64,7 @@ //===================== // (1) the backbone AP -#if 1 +#if 0 #define DISABLE_I2C_REQ #define SET_CONTAINSROOT // (2) osc client (the ROOT) @@ -72,7 +72,7 @@ #define SET_ROOT #define SET_CONTAINSROOT // (3) sampler client -#elif 0 +#elif 1 #define DISABLE_AP #define DISABLE_I2C_REQ //