-
Notifications
You must be signed in to change notification settings - Fork 0
/
WeddingPhone.ino
235 lines (206 loc) · 6.01 KB
/
WeddingPhone.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <elapsedMillis.h>
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioPlaySdWav playWav; // xy=170,137
AudioSynthWaveform voicemailBeep; // xy=189,73
AudioInputI2S audioInput; // xy=199,326
AudioRecordQueue recQueue; // xy=410,324
AudioMixer4 mixerLeft; // xy=510,89
AudioMixer4 mixerRight; // xy=512,186
AudioOutputI2S audioOutput; // xy=697,136
AudioConnection patchCord1(playWav, 0, mixerLeft, 0);
AudioConnection patchCord2(playWav, 1, mixerRight, 0);
AudioConnection patchCord3(voicemailBeep, 0, mixerLeft, 1);
AudioConnection patchCord4(voicemailBeep, 0, mixerRight, 1);
AudioConnection patchCord5(audioInput, 0, recQueue, 0);
AudioConnection patchCord6(mixerLeft, 0, audioOutput, 0);
AudioConnection patchCord7(mixerRight, 0, audioOutput, 1);
AudioControlSGTL5000 sgtl5000_1; // xy=196,268
// GUItool: end automatically generated code
#define HOOK_PIN 0
#define SDCARD_CS_PIN 10
enum Mode
{
Ready,
Prompting,
Recording,
};
Bounce phoneHook = Bounce(HOOK_PIN, 40);
elapsedMillis waitTime = 0;
File currentVoicemail;
Mode mode = Mode::Ready;
bool isFinished = false;
char recFileName[19];
void writeWAVHeader(File &file, uint32_t dataSize)
{
file.seek(0);
file.write("RIFF", 4); // ChunkID
writeLittleEndian32(file, 36 + dataSize); // ChunkSize
file.write("WAVE", 4); // Format
file.write("fmt ", 4); // Subchunk1ID
writeLittleEndian32(file, 16); // Subchunk1Size (16 for PCM)
writeLittleEndian16(file, 1); // AudioFormat (1 for PCM)
writeLittleEndian16(file, 1); // NumChannels (1 for mono)
writeLittleEndian32(file, 44100); // SampleRate
writeLittleEndian32(file, 44100 * 2); // ByteRate (SampleRate * NumChannels * BitsPerSample/8)
writeLittleEndian16(file, 2); // BlockAlign (NumChannels * BitsPerSample/8)
writeLittleEndian16(file, 16); // BitsPerSample
file.write("data", 4); // Subchunk2ID
writeLittleEndian32(file, dataSize); // Subchunk2Size
}
void updateWAVHeader(File &file)
{
uint32_t fileSize = file.size();
uint32_t dataSize = fileSize - 44;
file.seek(4);
writeLittleEndian32(file, fileSize - 8); // ChunkSize
file.seek(40);
writeLittleEndian32(file, dataSize); // Subchunk2Size
}
void writeLittleEndian32(File &file, uint32_t value)
{
file.write(value & 0xFF);
file.write((value >> 8) & 0xFF);
file.write((value >> 16) & 0xFF);
file.write((value >> 24) & 0xFF);
}
void writeLittleEndian16(File &file, uint16_t value)
{
file.write(value & 0xFF);
file.write((value >> 8) & 0xFF);
}
void startRecording()
{
long randomSuffix = random(10000);
snprintf(recFileName, 19, "voicemail_%04ld.wav", randomSuffix);
while (SD.exists(recFileName))
{
// Pick a new filename
randomSuffix = random(10000);
snprintf(recFileName, 19, "voicemail_%04ld.wav", randomSuffix);
}
Serial.print("Recording new voicemail to ");
Serial.println(recFileName);
currentVoicemail = SD.open(recFileName, FILE_WRITE);
writeWAVHeader(currentVoicemail, 0);
if (currentVoicemail)
{
recQueue.begin();
}
}
void continueRecording()
{
if (recQueue.available() >= 2)
{
// Grab two 256 Byte Audio Packets and copy them to a buffer
byte buffer[512];
for (uint8_t i = 0; i < 2; i++)
{
memcpy(buffer + (i * 256), recQueue.readBuffer(), 256);
recQueue.freeBuffer();
}
// Write out to the current voicemail file
currentVoicemail.write(buffer, 512);
}
}
void stopRecording()
{
Serial.print("Stopping recording of ");
Serial.println(recFileName);
recQueue.end();
if (mode == Mode::Recording)
{
while (recQueue.available() > 0)
{
currentVoicemail.write((byte *)recQueue.readBuffer(), 256);
recQueue.freeBuffer();
}
updateWAVHeader(currentVoicemail);
currentVoicemail.close();
}
mode = Mode::Ready;
}
bool playGreeting()
{
playWav.play("GREETING.WAV");
// A brief delay to read the WAV info
delay(25);
while (playWav.isPlaying())
{
phoneHook.update();
// Return early if they put the phone down
if (phoneHook.risingEdge())
{
playWav.stop();
mode = Mode::Ready;
return false;
}
}
return true;
}
void playBeep()
{
voicemailBeep.frequency(1400);
voicemailBeep.amplitude(0.2);
delay(500);
voicemailBeep.amplitude(0.0);
}
void setup()
{
pinMode(HOOK_PIN, INPUT_PULLUP);
AudioMemory(60);
sgtl5000_1.enable();
sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
sgtl5000_1.micGain(10);
sgtl5000_1.volume(0.5);
while (!SD.begin(SDCARD_CS_PIN))
{
Serial.println("Unable to access the SD card");
delay(500);
}
Serial.println("Voicemail is online.");
}
void loop()
{
phoneHook.update();
if (mode == Mode::Ready)
{
if (phoneHook.fallingEdge())
{
Serial.println("Handset up, starting prompt...");
mode = Mode::Prompting;
}
}
else if (mode == Mode::Prompting)
{
delay(2000); // Wait for them to pick up the phone
bool playedGreeting = playGreeting();
if (!playedGreeting)
{
Serial.println("Handset down, ending prompt early...");
return;
}
playBeep();
Serial.println("Starting recording");
mode = Mode::Recording;
startRecording();
}
else if (mode == Mode::Recording)
{
if (phoneHook.risingEdge())
{
Serial.println("Handset down, ending recording...");
stopRecording();
mode = Mode::Ready;
}
else
{
continueRecording();
}
}
}