//===============================================================
//------------------- VoxPHONE PROTO - 021 ----------------------
//---------------------- 2018 - 02 - 09 -------------------------
//--------------------- NICOLAS__LETARTE ------------------------
//===============================================================
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SD_t3.h>
#include <SerialFlash.h>
//#include <Time.h>
//#include <TimeLib.h>
// write wav
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate * numChannels * (bitsPerSample / 8); // samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels * bitsPerSample / 8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;
// Audio input on Teensy
const int myInput = AUDIO_INPUT_MIC;
// GUItool: begin automatically generated code
AudioInputI2S i2s2; //xy=188,136
AudioSynthWaveform waveform1; //xy=233,360
AudioPlaySdWav playSdWav1; //xy=235,318
AudioMixer4 mixer1; //xy=398,343
AudioRecordQueue queue1; //xy=411,93
AudioAnalyzePeak peak1; //xy=413,178
AudioOutputI2S i2s1; //xy=658,347
AudioConnection patchCord1(i2s2, 0, queue1, 0);
AudioConnection patchCord2(i2s2, 0, peak1, 0);
AudioConnection patchCord6(i2s2, 0, mixer1, 1);
AudioConnection patchCord3(waveform1, 0, mixer1, 2);
AudioConnection patchCord4(waveform1, 0, mixer1, 3);
AudioConnection patchCord5(playSdWav1, 0, mixer1, 0);
//AudioConnection patchCord6(playSdWav1, 1, mixer1, 1);
AudioConnection patchCord7(mixer1, 0, i2s1, 0);
AudioConnection patchCord8(mixer1, 0, i2s1, 1);
AudioControlSGTL5000 audioShield; //xy=103,62
// GUItool: end automatically generated code
///const int HOME_MSG = "HOME/ACCU.WAV";
// Use these with the Teensy 3.5 & 3.6 SD card
#define SDCARD_CS_PIN BUILTIN_SDCARD
#define SDCARD_MOSI_PIN 11 // not actually used
#define SDCARD_SCK_PIN 13 // not actually used
#define b1Pin 0
//#define b1ON digitalWrite(b1Pin,HIGH)
//#define b1OFF digitalWrite(b1Pin,LOW)
#define b2Pin 1
//#define b2ON digitalWrite(b2Pin,HIGH)
//#define b2OFF digitalWrite(b2Pin,LOW)
#define vPin 2
#define vLedON digitalWrite(vPin,HIGH)
#define vLedOFF digitalWrite(vPin,LOW)
#define rPin 3
#define rLedON digitalWrite(rPin,HIGH)
#define rLedOFF digitalWrite(rPin,LOW)
#define aPin 4
#define aLedON digitalWrite(aPin,HIGH)
#define aLedOFF digitalWrite(aPin,LOW)
// Bounce objects to easily and reliably read the buttons
Bounce lineUpButton = Bounce(b1Pin, 12);
Bounce lineDownButton = Bounce(b2Pin, 12);
// Variables globales
int mode = 0; // 0=Stby, 1=homeMsg, 2=beep1, 3=recording, 4=beep2, 5=stopAll
int line; // 0=Down, 1=Up
// Timers
elapsedMillis recTime;
elapsedMillis UpTime;
elapsedMillis AlertTime;
// The file where data is recorded
File frec;
//===============================================================
//===============================================================
//===============================================================
void setup() {
Serial.begin(9600);
AudioMemory(60);
pinMode(b1Pin, INPUT_PULLUP);
pinMode(b2Pin, INPUT_PULLUP);
pinMode(vPin, OUTPUT);
pinMode(rPin, OUTPUT);
pinMode(aPin, OUTPUT);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.micGain(10); //0-63
audioShield.volume(0.6);
mixer1.gain(0, 0.9); // Accueil
mixer1.gain(1, 0.4); // Micro
mixer1.gain(2, 0.4); // Synth L
// mixer1.gain(3, 0.4); // Synth R
waveform1.begin(WAVEFORM_SINE);
aLedON;
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
while (1) {
Serial.println("Impossible d\'acceder à la carte SD");
rLedON;
vLedOFF;
delay(500);
rLedOFF;
vLedON;
delay(500);
}
}
vLedON;
Serial.println("Bienvenue dans VoxPHONE");
delay(500);
Serial.println("VoxPHONE en Stand by");
delay(1000);
}
void loop() {
lineDownButton.update();
if (lineDownButton.fallingEdge()) {
line = 0;
audioShield.volume(0);
Serial.println("La ligne est fermee");
if (mode > 0) stopAll();
}
lineUpButton.update();
if (lineUpButton.fallingEdge()) {
line = 1;
audioShield.volume(0.6);
Serial.println("La ligne est ouverte");
vLedOFF;
rLedON;
if (mode == 0) startHomeMsg();
}
if (line == 1) {
if (mode == 1) continueHomeMsg();
if (mode == 2) playBeepOne();
if (mode == 3) recordUser();
if (mode == 4) continueRecordUser();
if (mode == 5) playBeepTwo();
if (mode == 6) alert();
if (mode == 8) alertLoop();
}
// // read the knob position (analog input A1 ou 15) =========================== VOLUME GLOBAL
// int knob = analogRead(15);
// float vol = (float)knob / 1280.0;
// audioShield.volume(vol);
}
//=======================================================================================
//=======================================================================================
//=======================================================================================
void alert() { //================================================================ ALERT!
lineDownButton.update();
if (lineDownButton.fallingEdge()) {
waveform1.amplitude(0);
stopAll();
} else {
if (UpTime >= 10000) {
Serial.println("Veuillez raccrocher");
mode = 8;
waveform1.frequency(1320);
waveform1.amplitude(0.1);
delay(1000);
AlertTime = 0;
}
}
}
void alertLoop() {
if (AlertTime >= 15000) {
waveform1.amplitude(0);
rLedON;
vLedON;
line = 0;
Serial.println("S.V.P. Veuillez raccrocher...");
} else {
waveform1.frequency(1000);
waveform1.amplitude(0.1);
rLedOFF;
vLedON;
delay(100);
waveform1.amplitude(0);
rLedON;
vLedOFF;
delay(100);
}
}
void startHomeMsg() { //===================================================== HOME MSG
delay(1000);
Serial.println("Message d\'accueil");
playSdWav1.play("HOME/ACCU.WAV");
mode = 1;
delay(10); // wait for library to parse WAV info
}
void continueHomeMsg() {
if (playSdWav1.isPlaying() == 0) {
playSdWav1.stop();
mode = 2;
}
}
void stopHomeMsg() {
if (mode == 1) playSdWav1.stop();
}
void playBeepOne() { //===================================================== BEEP 1
lineDownButton.update();
if (lineDownButton.fallingEdge()) {
stopAll();
} else {
waveform1.frequency(880);
waveform1.amplitude(0.1);
delay(1000);
waveform1.amplitude(0);
mode = 3;
}
}
void recordUser() { //===================================================== RECORD
Serial.println("Enregistrement du message");
String fileName = String();
unsigned int filenumber = 1;
while (!filenumber == 0) {
fileName = "VP_";
fileName += filenumber;
fileName += ".WAV";
char charFileName[fileName.length() + 1];
fileName.toCharArray(charFileName, sizeof(charFileName));
if (SD.exists(charFileName)) {
filenumber++;
}
else {
//File dataFile = SD.open(charFileName, FILE_WRITE);
frec = SD.open(charFileName, FILE_WRITE);
filenumber = 0;
}
//Serial.println("Nouveau fichier audio créé");
}
if (frec) {
queue1.begin();
recTime = 0;
mode = 4;
recByteSaved = 0L;
}
}
void continueRecordUser() {
if (recTime >= 90000) { // 90000 ou 1:30
stopRecording();
} else {
if (queue1.available() >= 2) {
byte buffer[512];
memcpy(buffer, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer + 256, queue1.readBuffer(), 256);
queue1.freeBuffer();
//elapsedMicros usec = 0;
// write all 512 bytes to the SD card
frec.write(buffer, 512);
//Serial.print("SD write, us=");
//Serial.println(usec);
recByteSaved += 512;
}
}
}
void stopRecording() {
Serial.println("Fin de l\'enregistrement");
queue1.end();
if (mode == 4) {
while (queue1.available() > 0) {
frec.write((byte*)queue1.readBuffer(), 256);
queue1.freeBuffer();
recByteSaved += 256;
}
writeOutHeader();
frec.close();
}
mode = 5;
}
void playBeepTwo() { //===================================================== BEEP 2
lineDownButton.update();
if (lineDownButton.fallingEdge()) {
stopAll();
} else {
waveform1.frequency(880);
waveform1.amplitude(0.1);
delay(1000);
waveform1.frequency(440);
delay(125);
waveform1.frequency(220);
delay(500);
waveform1.amplitude(0);
mode = 6;
UpTime = 0;
}
}
void stopAll() { //====================================================================================== STOP-ALL
if (mode == 1) playSdWav1.stop();
if ((mode == 3) | (mode == 4)) stopRecording();
if ((mode == 2) | (mode == 5)) waveform1.amplitude(0);
rLedOFF;
vLedON;
mode = 0;
Serial.println("VoxPHONE en Stand by");
}
void writeOutHeader() { //============================================== RAW TO WAV
Subchunk2Size = recByteSaved;
ChunkSize = Subchunk2Size + 36;
frec.seek(0);
frec.write("RIFF");
byte1 = ChunkSize & 0xff;
byte2 = (ChunkSize >> 8) & 0xff;
byte3 = (ChunkSize >> 16) & 0xff;
byte4 = (ChunkSize >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.write("WAVE");
frec.write("fmt ");
byte1 = Subchunk1Size & 0xff;
byte2 = (Subchunk1Size >> 8) & 0xff;
byte3 = (Subchunk1Size >> 16) & 0xff;
byte4 = (Subchunk1Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = AudioFormat & 0xff;
byte2 = (AudioFormat >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = byteRate & 0xff;
byte2 = (byteRate >> 8) & 0xff;
byte3 = (byteRate >> 16) & 0xff;
byte4 = (byteRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
frec.write("data");
byte1 = Subchunk2Size & 0xff;
byte2 = (Subchunk2Size >> 8) & 0xff;
byte3 = (Subchunk2Size >> 16) & 0xff;
byte4 = (Subchunk2Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.close();
// Serial.println("header written");
// Serial.print("Subchunk2: ");
// Serial.println(Subchunk2Size);
}
//=====================================================
//===================== TODOS =========================
//=====================================================
/*
√- Indexer les fichiers enregistres
√ - Traduire en WAV les enregistrements RAW
√- Connecteurs électriques slims + rallonger le fil
- Bouton On/Off ext
√- Bouton reset ext
- Potentiometre de volume ext
- LED différent lorsqu'un utilisateur enregistre son message
- Pouvoir enregistrer le message d'accueil à même le VoxPhone
- Pouvoir toujours détecter la présence de la carte SD !!!!!
- Port Micro USB F
*/