Created
July 8, 2017 12:40
-
-
Save ylh888/51cda38e2b5cfbaa0fa009ed8ef17d53 to your computer and use it in GitHub Desktop.
node.js speaker sine wave playing example
This file contains 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
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