re-do.. now go back to 1 voice version. (old-school) again.

This commit is contained in:
Dooho Yi 2020-01-04 17:12:38 +09:00
parent 7fe2573a96
commit 0c4045e76b
3 changed files with 103 additions and 346 deletions

View file

@ -14,44 +14,19 @@ default_envs = teensy35
[common] [common]
lib_ignore = Audio, SD lib_ignore = Audio, SD
lib_deps = lib_deps =
721 ; TaskScheduler 721@3.0.2 ; TaskScheduler
322 ; SdFat 322@1.0.7 ; SdFat
401 ; Adafruit SleepyDog Library
[env:teensy35] [env:teensy35]
platform = teensy platform = teensy@3.6.0
board = teensy35 board = teensy35
framework = arduino framework = arduino
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} lib_ignore = ${common.lib_ignore}
[env:teensy36] [env:teensy36]
platform = teensy platform = teensy@3.6.0
board = teensy36 board = teensy36
framework = arduino framework = arduino
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} 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}

View file

@ -16,33 +16,14 @@
// (part-3) teensy35 : 'client:sampler' (mesh post --> play sounds) // (part-3) teensy35 : 'client:sampler' (mesh post --> play sounds)
// //
// //HACK: let auto-poweroff speakers stay turned ON! - (creative muvo mini)
// 2019 12 29 #define IDLE_FREQ 22000
// #define IDLE_AMP 0 // --> creative muvo 2 doesn't need this. they just stay on!
// multiple sound playback -> 4 voices -- TESTING
//
//----------<configuration>----------
//
// '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
//----------</configuration>----------
//watchdog
#include <Adafruit_SleepyDog.h>
//teensy audio //teensy audio
#include <Audio.h> #include <Audio.h>
// #include <SPI.h>
// #include <SD.h>
#include <SdFat.h> #include <SdFat.h>
SdFatSdioEX SD; SdFatSdioEX SD;
#include <SerialFlash.h> #include <SerialFlash.h>
@ -53,285 +34,98 @@ SdFatSdioEX SD;
#define SDCARD_SCK_PIN 13 // not actually used #define SDCARD_SCK_PIN 13 // not actually used
// GUItool: begin automatically generated code // GUItool: begin automatically generated code
AudioPlaySdWav playSdWav1; //xy=183,90 AudioPlaySdWav playSdWav1; //xy=224,265
AudioPlaySdWav playSdWav2; //xy=185,253 AudioSynthWaveformSine sine1; //xy=236,361
AudioPlaySdWav playSdWav3; //xy=187,411 AudioMixer4 mixer2; //xy=497,328
AudioPlaySdWav playSdWav4; //xy=188,579 AudioMixer4 mixer1; //xy=499,245
AudioAmplifier amp1; //xy=374,49 AudioAmplifier amp1; //xy=633,245
AudioAmplifier amp2; //xy=375,132 AudioAmplifier amp2; //xy=634,328
AudioAmplifier amp3; //xy=377,219 AudioOutputAnalogStereo dacs1; //xy=788,284
AudioAmplifier amp4; //xy=378,302 AudioConnection patchCord1(playSdWav1, 0, mixer1, 0);
AudioAmplifier amp5; //xy=378,370 AudioConnection patchCord2(playSdWav1, 1, mixer2, 0);
AudioAmplifier amp6; //xy=379,453 AudioConnection patchCord3(sine1, 0, mixer1, 1);
AudioAmplifier amp7; //xy=381,540 AudioConnection patchCord4(sine1, 0, mixer2, 1);
AudioAmplifier amp8; //xy=382,623 AudioConnection patchCord5(mixer2, amp2);
AudioMixer4 mixer2; //xy=620,413 AudioConnection patchCord6(mixer1, amp1);
AudioMixer4 mixer1; //xy=621,210 AudioConnection patchCord7(amp1, 0, dacs1, 0);
AudioOutputAnalogStereo dacs1; //xy=812,318 AudioConnection patchCord8(amp2, 0, dacs1, 1);
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);
// GUItool: end automatically generated code // 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 <vector>
#include <deque>
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<Voice> poly_bank;
static std::deque< std::pair<int, int> > poly_queue;
//task //task
#include <TaskScheduler.h> #include <TaskScheduler.h>
Scheduler runner; Scheduler runner;
// polyphonics //sample #
static int note_sched = 0; int sample_now = 0; //0~99
static int velocity_sched = 0; void sample_player_start()
void scheduleNoteOn()
{ {
//filename buffer - 8.3 naming convension! 8+1+3+1 = 13 //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 //search for the sound file
int note = note_sched; int note = sample_now;
int nnn = (note % 1000); // 0~999 int nnn = (note % 1000); // 0~999
int nn = (note % 100); // 0~99 int nn = (note % 100); // 0~99
fname[0] = '0' + (nnn / 100); // N__.WAV filename[0] = '0' + (nnn / 100); // N__.WAV
fname[1] = '0' + (nn / 10); // _N_.WAV filename[1] = '0' + (nn / 10); // _N_.WAV
fname[2] = '0' + (nn % 10); // __N.WAV filename[2] = '0' + (nn % 10); // __N.WAV
//TEST //TEST
Serial.println(fname); Serial.println(filename);
AudioNoInterrupts(); AudioNoInterrupts();
bool test = SD.exists(fname); bool test = SD.exists(filename);
AudioInterrupts(); AudioInterrupts();
if (!test) { if (!test) {
Serial.println("... does not exist."); Serial.println("... does not exist.");
return; return;
} }
//ok, let's schedule a voice //start the player!
//btw, is it already playing? //NOTE: block out 're-triggering'
// --> entry : (# of voice bank, playing note #) // if (playSdWav1.isPlaying() == false) {
bool is_already = false; playSdWav1.play(filename);
for (uint32_t idx = 0; idx < poly_queue.size(); idx++) { // }
if (poly_queue[idx].second == note) { //mark the indicator : HIGH: ON
//oh, it is alreay playing digitalWrite(13, HIGH);
// --> what to do? //to wait a bit for updating isPlaying()
// (1) re-trigger (stop-and-restart) delay(10);
// 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<int, int>(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<int, int>(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();
} }
// void sample_player_stop() {
Task scheduleNoteOn_task(0, TASK_ONCE, scheduleNoteOn); //filename buffer - 8.3 naming convension! 8+1+3+1 = 13
// char filename[13] = "NNN.WAV";
void scheduleNoteOff() { //search for the sound file
for (auto it = poly_queue.begin(); it != poly_queue.end(); ++it) { int note = sample_now;
//is this meaningful, btw? int nnn = (note % 1000); // 0~999
if ((*it).second == note_sched) { int nn = (note % 100); // 0~99
//okay. we've got that. filename[0] = '0' + (nnn / 100); // N__.WAV
Serial.println("okay. we've got that."); filename[1] = '0' + (nn / 10); // _N_.WAV
//a record : (# of voice bank, playing note #) filename[2] = '0' + (nn % 10); // __N.WAV
poly_bank[(*it).first].noteOff(); // stop the bank //TEST
poly_queue.erase(it); // remove the record Serial.println(filename);
break; AudioNoInterrupts();
} bool test = SD.exists(filename);
AudioInterrupts();
if (!test) {
Serial.println("... does not exist.");
return;
} }
//monitoring the queue //stop the player.
Serial.println("--notoOff:poly_queue---"); if (playSdWav1.isPlaying() == true) {
Serial.println("(voice#, note#)"); playSdWav1.stop();
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();
} }
// void sample_player_check() {
Task scheduleNoteOff_task(0, TASK_ONCE, scheduleNoteOff); if (playSdWav1.isPlaying() == false) {
//
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) {
//mark the indicator : LOW: OFF //mark the indicator : LOW: OFF
digitalWrite(13, LOW); digitalWrite(13, LOW);
} else { //let speaker leave turned ON!
//mark the indicator : HIGH: ON sine1.amplitude(IDLE_AMP);
digitalWrite(13, HIGH); }
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 //i2c
#include <Wire.h> #include <Wire.h>
@ -377,17 +171,20 @@ void receiveEvent(int numBytes) {
// //
int key = str_key.toInt(); int key = str_key.toInt();
int velocity = str_velocity.toInt(); // 0 ~ 127 sample_now = key;
int gate = str_gate.toInt();
// //
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) { if (gate == 0) {
note_sched = key; sample_player_stop_task.restart();
scheduleNoteOff_task.restart(); Serial.println("sample_player_stop_task");
} else { } else {
note_sched = key; sample_player_start_task.restart();
velocity_sched = velocity; Serial.println("sample_player_start_task");
scheduleNoteOn_task.restart();
} }
} }
} }
@ -439,8 +236,10 @@ void setup() {
// DISABLED.. due to bi-directional I2C hardship. ==> use UART. // DISABLED.. due to bi-directional I2C hardship. ==> use UART.
// Wire.onRequest(requestEvent); // 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()) {
// if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("[sd] initialization failed!"); Serial.println("[sd] initialization failed!");
return; return;
} }
@ -448,51 +247,34 @@ void setup() {
root = SD.open("/"); root = SD.open("/");
printDirectory(root, 0); 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 //audio
AudioMemory(20); // <-- used AudioMemoryUsageMax() to check out! AudioMemory(20);
#if !defined(TEENSY36) #if !defined(TEENSY36)
//NOTE!! teensy36 board.. //NOTE!! teensy36 board.. output broken? .. so disable this for teensy36.. this is the cause??
// output broken? ..
// so disable this for teensy36..
// this is the cause??
#if defined(ANALOG_REF_EXTERNAL_3P3V)
dacs1.analogReference(EXTERNAL); dacs1.analogReference(EXTERNAL);
#endif
#endif #endif
mixer1.gain(0,1.0); mixer1.gain(0,1.0);
mixer1.gain(1,1.0); mixer1.gain(1,1.0);
mixer1.gain(2,1.0); mixer1.gain(2,0);
mixer1.gain(3,1.0); mixer1.gain(3,0);
mixer2.gain(0,1.0); mixer2.gain(0,1.0);
mixer2.gain(1,1.0); mixer2.gain(1,1.0);
mixer2.gain(2,1.0); mixer2.gain(2,0);
mixer2.gain(3,1.0); mixer2.gain(3,0);
amp1.gain(1.0); amp1.gain(1.0);
amp2.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 //let auto-poweroff speakers stay turned ON!
runner.addTask(playcheck_task); sine1.frequency(IDLE_FREQ);
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);
//led //led
pinMode(13, OUTPUT); pinMode(13, OUTPUT);
digitalWrite(13, LOW); // LOW: OFF digitalWrite(13, LOW); // LOW: OFF
//player task
runner.addTask(sample_player_start_task);
runner.addTask(sample_player_stop_task);
// //
Serial.println("[setup] done."); Serial.println("[setup] done.");
} }

View file

@ -64,7 +64,7 @@
//==========<preset>=========== //==========<preset>===========
// (1) the backbone AP // (1) the backbone AP
#if 1 #if 0
#define DISABLE_I2C_REQ #define DISABLE_I2C_REQ
#define SET_CONTAINSROOT #define SET_CONTAINSROOT
// (2) osc client (the ROOT) // (2) osc client (the ROOT)
@ -72,7 +72,7 @@
#define SET_ROOT #define SET_ROOT
#define SET_CONTAINSROOT #define SET_CONTAINSROOT
// (3) sampler client // (3) sampler client
#elif 0 #elif 1
#define DISABLE_AP #define DISABLE_AP
#define DISABLE_I2C_REQ #define DISABLE_I2C_REQ
// //