Skip to content

Instantly share code, notes, and snippets.

@ylh888
Created July 8, 2017 12:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ylh888/51cda38e2b5cfbaa0fa009ed8ef17d53 to your computer and use it in GitHub Desktop.
Save ylh888/51cda38e2b5cfbaa0fa009ed8ef17d53 to your computer and use it in GitHub Desktop.
node.js speaker sine wave playing example
var Speaker = require('speaker');
var Readable = require('stream').Readable;
// node v0.8.x compat
if (!Readable) Readable = require('readable-stream/readable');
// Examples :
// makeSound(440,0.5).play(8); // frequency, duration, delay
let s440 = makeSound(440, 1.0);
s440.play(); // play immediately
s440.play(2); // play 2 seconds later
// makeSound().play(); // cannot play simultaneously with s440.play() above
function makeSound(f, d) {
// the frequency to play
let freq = f || 440.0; // Concert A, default tone
// seconds worth of audio data to generate before emitting "end"
let duration = d || 0.4;
return {
play: play
};
function play(delay) { // delay in seconds
let d = delay || 0;
setTimeout(() =>
playIt(), delay * 1000);
}
function playIt() {
// A SineWaveGenerator readable stream
let sine = new Readable();
sine.bitDepth = 16;
sine.channels = 2;
sine.sampleRate = 44100;
sine.samplesGenerated = 0;
sine._read = read;
sine.pipe(new Speaker());
}
// the Readable "_read()" callback function
function read(n) {
let sampleSize = this.bitDepth / 8;
let blockAlign = sampleSize * this.channels;
let numSamples = n / blockAlign | 0;
let buf = new Buffer(numSamples * blockAlign);
let amplitude = 32760; // Max amplitude for 16-bit audio
// the "angle" used in the function, adjusted for the number of
// channels and sample rate. This value is like the period of the wave.
let t = (Math.PI * 2 * freq) / this.sampleRate;
for (let i = 0; i < numSamples; i++) {
// fill with a simple sine wave at max amplitude
for (let channel = 0; channel < this.channels; channel++) {
let s = this.samplesGenerated + i;
let val = Math.round(amplitude * Math.sin(t * s)); // sine wave
let offset = (i * sampleSize * this.channels) + (channel * sampleSize);
buf['writeInt' + this.bitDepth + 'LE'](val, offset);
}
}
this.push(buf);
this.samplesGenerated += numSamples;
if (this.samplesGenerated >= this.sampleRate * duration) {
// after generating "duration" second of audio, emit "end"
this.push(null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment