-
-
Save kindanduseful/ab65eec42629e051e2d633e1bfe7defd to your computer and use it in GitHub Desktop.
Photon Audio Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MICROPHONE_PIN A5 | |
#define AUDIO_BUFFER_MAX 8192 | |
int audioStartIdx = 0, audioEndIdx = 0; | |
uint16_t audioBuffer[AUDIO_BUFFER_MAX]; | |
uint16_t txBuffer[AUDIO_BUFFER_MAX]; | |
// version without timers | |
unsigned long lastRead = micros(); | |
char myIpAddress[24]; | |
TCPClient audioClient; | |
TCPClient checkClient; | |
TCPServer audioServer = TCPServer(3443); | |
void setup() { | |
Serial.begin(115200); | |
pinMode(MICROPHONE_PIN, INPUT); | |
// This lines look up your Particle's local IP Address and make it available via | |
// `particle get MY_DEVICE_NAME ipAddress` from the CLI. | |
Spark.variable("ipAddress", myIpAddress, STRING); | |
IPAddress myIp = WiFi.localIP(); | |
sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]); | |
// 1/8000th of a second is 125 microseconds | |
audioServer.begin(); | |
// EDIT: This will print your local IP Address to Serial Monitor of a USB-attached computer (can be accessed through Arduino IDE) | |
Serial.println("local IP Address"); | |
Serial.println(myIpAddress); | |
lastRead = micros(); | |
} | |
void loop() { | |
checkClient = audioServer.available(); | |
if (checkClient.connected()) { | |
audioClient = checkClient; | |
} | |
//listen for 100ms, taking a sample every 125us, | |
//and then send that chunk over the network. | |
listenAndSend(100); | |
} | |
void listenAndSend(int delay) { | |
unsigned long startedListening = millis(); | |
while ((millis() - startedListening) < delay) { | |
unsigned long time = micros(); | |
if (lastRead > time) { | |
// time wrapped? | |
//lets just skip a beat for now, whatever. | |
lastRead = time; | |
} | |
//125 microseconds is 1/8000th of a second | |
if ((time - lastRead) > 125) { | |
lastRead = time; | |
readMic(); | |
} | |
} | |
sendAudio(); | |
} | |
// Callback for Timer 1 | |
void readMic(void) { | |
uint16_t value = analogRead(MICROPHONE_PIN); | |
if (audioEndIdx >= AUDIO_BUFFER_MAX) { | |
audioEndIdx = 0; | |
} | |
audioBuffer[audioEndIdx++] = value; | |
} | |
void copyAudio(uint16_t *bufferPtr) { | |
//if end is after start, read from start->end | |
//if end is before start, then we wrapped, read from start->max, 0->end | |
int endSnapshotIdx = audioEndIdx; | |
bool wrapped = endSnapshotIdx < audioStartIdx; | |
int endIdx = (wrapped) ? AUDIO_BUFFER_MAX : endSnapshotIdx; | |
int c = 0; | |
for(int i=audioStartIdx;i<endIdx;i++) { | |
// do a thing | |
bufferPtr[c++] = audioBuffer[i]; | |
} | |
if (wrapped) { | |
//we have extra | |
for(int i=0;i<endSnapshotIdx;i++) { | |
// do more of a thing. | |
bufferPtr[c++] = audioBuffer[i]; | |
} | |
} | |
//and we're done. | |
audioStartIdx = audioEndIdx; | |
if (c < AUDIO_BUFFER_MAX) { | |
bufferPtr[c] = -1; | |
} | |
} | |
// Callback for Timer 1 | |
void sendAudio(void) { | |
copyAudio(txBuffer); | |
int i=0; | |
uint16_t val = 0; | |
if (audioClient.connected()) { | |
write_socket(audioClient, txBuffer); | |
} | |
else { | |
// will only run if there's no script listening for audio | |
while( (val = txBuffer[i++]) < 65535 ) { | |
// this will generate a lot of output; comment out if you just want the IP address | |
Serial.print(val); | |
Serial.print(','); | |
} | |
Serial.println("DONE"); | |
} | |
} | |
// an audio sample is 16bit, we need to convert it to bytes for sending over the network | |
void write_socket(TCPClient socket, uint16_t *buffer) { | |
int i=0; | |
uint16_t val = 0; | |
int tcpIdx = 0; | |
uint8_t tcpBuffer[1024]; | |
while( (val = buffer[i++]) < 65535 ) { | |
if ((tcpIdx+1) >= 1024) { | |
socket.write(tcpBuffer, tcpIdx); | |
tcpIdx = 0; | |
} | |
tcpBuffer[tcpIdx] = val & 0xff; | |
tcpBuffer[tcpIdx+1] = (val >> 8); | |
tcpIdx += 2; | |
} | |
// any leftovers? | |
if (tcpIdx > 0) { | |
socket.write(tcpBuffer, tcpIdx); | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// make sure you have Node.js Installed! | |
// make sure you first run `npm install particle-api-js` | |
// Type in your local IP here! Or scroll down and get the script to find it on | |
//your behalf (comment out the next 4 lines if you go for this option). | |
var settings = { | |
ip: "YOUR_IP_ADDRESS", | |
port: 3443 | |
}; | |
var Particle = require('particle-api-js'); | |
var particle = new Particle(); | |
var token = 'YOUR_TOKEN_HERE'; // Find your token under "Settings" at https://build.particle.io/ | |
// EDIT: Connects to Particle Photon and saves token if you dont want to look it up | |
//particle.login({username: '[email protected]', password: 'yourpassword'}).then(function(data){ | |
// | |
// console.log('Logged in'); | |
// token = data.body.access_token; | |
// | |
//}); | |
// EDIT: Another way to ask the Particle for its Local IP Address | |
particle.getVariable({ deviceId: 'YOUR_DEVICE_NAME', name: 'ipAddress', auth: token }) | |
.then(function(data) { | |
console.log("IP address: ", data); | |
settings.ip = data.body.result; | |
/** | |
* Created by middleca on 7/18/15. | |
*/ | |
//based on a sample from here | |
// http://stackoverflow.com/questions/19548755/nodejs-write-binary-data-into-writablestream-with-buffer | |
var fs = require("fs"); | |
var samplesLength = 1000; | |
var sampleRate = 8000; | |
// EDIT: New additions - turns "test.wav" in "fs.createWriteStream("test.wav");"" | |
// into a variable that gets current time and date | |
var d = new Date(); | |
var outStream = fs.createWriteStream("Record--"+d.toString().split(' ').join('-')+".wav"); | |
// EDIT: Writes the beginning of the WAV file | |
var writeHeader = function() { | |
var b = new Buffer(1024); | |
b.write('RIFF', 0); | |
/* file length */ | |
b.writeUInt32LE(32 + samplesLength * 2, 4); | |
//b.writeUint32LE(0, 4); | |
b.write('WAVE', 8); | |
/* format chunk identifier */ | |
b.write('fmt ', 12); | |
/* format chunk length */ | |
b.writeUInt32LE(16, 16); | |
/* sample format (raw) */ | |
b.writeUInt16LE(1, 20); | |
/* channel count */ | |
b.writeUInt16LE(1, 22); | |
/* sample rate */ | |
b.writeUInt32LE(sampleRate, 24); | |
/* byte rate (sample rate * block align) */ | |
b.writeUInt32LE(sampleRate * 2, 28); | |
/* block align (channel count * bytes per sample) */ | |
b.writeUInt16LE(2, 32); | |
/* bits per sample */ | |
b.writeUInt16LE(16, 34); | |
/* data chunk identifier */ | |
b.write('data', 36); | |
/* data chunk length */ | |
//b.writeUInt32LE(40, samplesLength * 2); | |
b.writeUInt32LE(0, 40); | |
outStream.write(b.slice(0, 50)); | |
}; | |
writeHeader(outStream); | |
var net = require('net'); | |
console.log("connecting..."); | |
client = net.connect(settings.port, settings.ip, function () { | |
client.setNoDelay(true); | |
client.on("data", function (data) { | |
try { | |
console.log("GOT DATA"); | |
outStream.write(data); | |
//outStream.flush(); | |
console.log("got chunk of " + data.toString('hex')); | |
} | |
catch (ex) { | |
console.error("Er!" + ex); | |
} | |
}); | |
}); | |
setTimeout(function() { | |
console.log('recorded for 10 seconds'); | |
client.end(); | |
outStream.end(); | |
process.exit(0); | |
}, 10 * 1000); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment