Socket
Socket
Sign inDemoInstall

audio-vs1053b

Package Overview
Dependencies
Maintainers
2
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

audio-vs1053b - npm Package Compare versions

Comparing version 0.1.91 to 0.2.0

2

examples/audio-out-no-streams.js

@@ -14,3 +14,3 @@ // Any copyright is dedicated to the Public Domain.

audio.on('ready', function () { // Start recording data for a second into a file
audio.setOutput('headphone', function(err) {
audio.setOutput('headphones', function(err) {
// Open a file

@@ -17,0 +17,0 @@ var audioFile = fs.readFileSync('sample.mp3');

@@ -18,4 +18,4 @@ // Any copyright is dedicated to the Public Domain.

console.log("Audio module connected! Setting volume...");
// Set the volume in decibels. Around 20 is good; smaller is louder.
audio.setVolume(20, function(err) {
// Set the volume in decibels. Around .8 is good; 80% max volume or -25db
audio.setVolume(.8, function(err) {
if (err) {

@@ -22,0 +22,0 @@ return console.log(err);

@@ -15,3 +15,3 @@ // Any copyright is dedicated to the Public Domain.

// Start recording data for a second into a file
audio.setOutput('headphone', function(err) {
audio.setOutput('headphones', function(err) {
// Open a file

@@ -18,0 +18,0 @@ fs.createReadStream('sample.mp3').pipe(audio.createPlayStream());

@@ -16,2 +16,3 @@ // Copyright 2014 Technical Machine, Inc. See the COPYRIGHT

var Readable = require('stream').Readable;
var queue = require('sync-queue');

@@ -36,4 +37,6 @@ // VS10xx SCI Registers

// VS10xx Reset Command
var MODE_SM_RESET = 0x04;
// VS10xx GPIO Register adddresses
var GPIO_DIR_ADDR = 0xC017

@@ -43,17 +46,40 @@ , GPIO_READ_ADDR = 0xC018

// VS10xx GPIO for i/o
var inputReg = 0x05,
outputReg = 0x07;
// Datastructure for storing pending buffers and their allbacks
var _audioCallbacks = {};
// A double buffer for recording data
var _fillBuff = new Buffer(25000);
_fillBuff.fill(0);
function use (hardware, next) {
return new Audio(hardware, next);
// The SPI bus clock speed
var SPIClockSpeed = 4000000;
/*
* Both use() and Audio() initialize the audio module with a specific piece of hardware.
* use() is a common API wrapper around object construction for Tessel modules. Arguments:
*
* hardware The hardware the module is connected to (Tessel Port)
*
* callback A callback to be called when initialization completes. Upon
* success, callback is invoked as callback(null, audio),
* where `audio` is an Audio module object. Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for several reasons:
*
* Error Created when Tessel cannot communicate with the module or
* it receives a response that doesn't match with what was expected.
*
*/
function use (hardware, callback) {
return new Audio(hardware, callback);
}
function Audio(hardware, callback) {
var self = this;
// Set the spi port
this.spi = new hardware.SPI({
self.spi = new hardware.SPI({
clockSpeed: 1000000,

@@ -63,21 +89,25 @@ dataMode: 0

// Create a new queue to store commands
self.commandQueue = new queue();
// Set our register select pins
this.MP3_XCS = hardware.digital[0].output(true); //Control Chip Select Pin (for accessing SPI Control/Status registers)
this.MP3_DCS = hardware.digital[1].output(true); //Data Chip Select / BSYNC Pin
this.MP3_DREQ = hardware.digital[2].input() //Data Request Pin: Player asks for more data
self.MP3_XCS = hardware.digital[0].output(true); //Control Chip Select Pin (for accessing SPI Control/Status registers)
self.MP3_DCS = hardware.digital[1].output(true); //Data Chip Select / BSYNC Pin
self.MP3_DREQ = hardware.digital[2].input() //Data Request Pin: Player asks for more data
this.input = "";
this.output = "";
// Initializing state variables
self.input;
self.output;
// Waits for the audio completion event which signifies that a buffer has finished streaming
process.on('audio_playback_complete', this._handlePlaybackComplete.bind(this));
process.on('audio_playback_complete', self._handlePlaybackComplete.bind(self));
// Waits for the audio data event which is recorded data being output from the C shim
process.on('audio_recording_data', this._handleRecordedData.bind(this));
process.on('audio_recording_data', self._handleRecordedData.bind(self));
// Waits for final flushed buffer of a recording
process.on('audio_recording_complete', this._handleRecordedData.bind(this));
process.on('audio_recording_complete', self._handleRecordedData.bind(self));
// Initialize the module
this.initialize(callback);
self.commandQueue.place(self.initialize.bind(self, callback));
}

@@ -87,2 +117,16 @@

/*
* Reset the Audio module and set it into a known, default state
*
* callback A callback to be called when initialization completes. Upon
* success, callback is invoked as callback(null, audio),
* where `audio` is an Audio module object. Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for several reasons:
*
* Error Created when Tessel cannot communicate with the module or
* it receives a response that doesn't match with what was expected.
*
*/
Audio.prototype.initialize = function(callback) {

@@ -93,16 +137,12 @@ var self = this;

this._softReset(function(err) {
if (err) { self._failConnect(err, callback); }
else {
if (!self._failConnect(err, callback)) {
// Make sure we can comm and have the right version
self._checkVersion(function(err) {
if (err) { self._failConnect(err, callback); }
else {
if (!self._failConnect(err, callback)) {
// Set the clock speed higher
self._setClockSpeeds(function(err) {
if (err) { self._failConnect(err, callback); }
else {
if (!self._failConnect(err, callback)) {
// Enabke headphones and lineIn
self.setDefaultIO(function(err) {
if (err) { self._failConnect(err, callback); }
else {
if (!self._failConnect(err, callback)) {
// Call the callback

@@ -116,2 +156,4 @@ callback && callback(null, self);

});
self.commandQueue.next();
}

@@ -125,6 +167,39 @@ });

/*
* (Internal Function) The callback for the event when a stream finishes playing.
* This method is responsible for calling any callbacks associated with a given stream's
* completion and releasing the SPI lock if there are no more active streams.
*
* errBool An indicator of whether there was an error with playback.
*
* completedStream The track id of the buffer that just completed. This is the key
* stored in the callbacks datastructure for fetching the track information.
*
*/
Audio.prototype._handlePlaybackComplete = function(errBool, completedStream) {
var self = this;
if (self.lock) {
// Get the callback if one was saved
var track = _audioCallbacks[completedStream];
// If it exists
if (track) {
// Remove it from our datastructure
delete _audioCallbacks[completedStream];
// Call the callback
if (track.callback) {
track.callback();
}
// Emit the end event
self.emit('end', err);
}
// Get the number of streams still playing
var remaining = Object.keys(_audioCallbacks).length;
// If there are not still tracks playing and we have a lock reference
if (!remaining && self.lock) {
// Free the lock
self.lock.release(function(err) {

@@ -135,22 +210,2 @@ if (err) {

}
else {
// Get the callback if one was saved
var callback = _audioCallbacks[completedStream];
// If it exists
if (callback) {
// Remove it from our datastructure
delete _audioCallbacks[completedStream];
var err;
// Generate an error message if there was an error
if (errBool) {
err = new Error("Error sending buffer over SPI");
}
// Call the callback
callback(err);
self.emit('end', err);
}
}
});

@@ -160,2 +215,10 @@ }

/*
* (Internal Function) The callback for when a buffer of recorded data is returned from the C shim.
* This function is called repeatedly as a recording is made.
*
* length The number of bytes that that were recorded.
*
*/
Audio.prototype._handleRecordedData = function(length) {

@@ -168,10 +231,38 @@ // Copy the recorded data into a new buff for consumption

/*
* (Internal Function) A helper function to simplify error handling. It checks if an error occured,
* calls a callback if one was provided, or emits an error event.
*
* hardware The hardware the module is connected to (Tessel Port)
*
* callback A callback to be called when initialization completes.
*
* This function returns a boolean that indicates whether an error was handled (value of true).
*/
Audio.prototype._failConnect = function(err, callback) {
setImmediate(function() {
this.emit('error', err);
}.bind(this))
return callback && callback(err);
if (err) {
if (callback) {
callback(err);
}
else {
setImmediate(function() {
this.emit('error', err);
}.bind(this))
}
return true
}
else {
return false;
}
}
/*
* Opens up a writable stream which gets piped to the C shim for playback. Internally,
* it calls the queue method repeatedly. It continues concatenating piped data until
* the buffer is equal or greater than 10k bytes to ensure smooth playback.
*/
Audio.prototype.createPlayStream = function() {

@@ -228,3 +319,10 @@ var audio = this;

// Creates a Readable record stream
/*
* Opens up a readable stream where recording data will be emitted on an interval. Arguments:
*
* profile A string that indicates with recording profile will be used.
* The recording profile determines the sound quality. Available sound
* qualities can be found by calling availableRecordingProfiles()
*/
Audio.prototype.createRecordStream = function(profile) {

@@ -254,3 +352,13 @@ var audio = this;

/*
* (Internal Function) Performs a soft reset of the Audio module. Arguments:
*
* callback A callback to be called when resetting completes. Upon
* success, callback is invoked as callback(null). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._softReset = function(callback) {

@@ -271,2 +379,16 @@ this._readSciRegister16(SCI_MODE, function(err, mode) {

/*
* (Internal Function) Requests the chip version from the Audio Module to
* confirm working communication and valid module. Arguments:
*
* callback A callback to be called when checking completes. Upon
* success, callback is invoked as callback(null). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data. It
* can also fail if the returned version is not what was expected.
*/
Audio.prototype._checkVersion = function(callback) {

@@ -286,2 +408,13 @@ this._readSciRegister16(SCI_STATUS, function(err, MP3Status) {

/*
* (Internal Function) Sets the VS1053B clock speed. Arguments:
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(null). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._setClockSpeeds = function(callback) {

@@ -292,3 +425,3 @@ // Set multiplier to 3.0x

else {
this.spi.setClockSpeed(4000000);
this.spi.setClockSpeed(SPIClockSpeed);
return callback && callback();

@@ -300,2 +433,15 @@ }

/*
* (Internal Function) Transfer a single byte over SPI to the VS1053b. Arguments:
*
* byte The byte value to be transferred.
*
* callback A callback to be called when sending completes. Upon
* success, callback is invoked as callback(null). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._SPItransferByte = function(byte, callback) {

@@ -307,2 +453,16 @@ this._SPItransferArray([byte], function(err, ret) {

/*
* (Internal Function) Transfer an array of bytes over SPI to the vs1053b
* Arguments:
*
* array An array of bytes to be sent over spi
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(null). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._SPItransferArray = function(array, callback) {

@@ -314,3 +474,17 @@ this.spi.transfer(new Buffer(array), function(err, ret) {

//Read the 16-bit value of a VS10xx register
/*
* (Internal Function) Read the 16-bit value of a VS10xx register
* Arguments:
*
* addressbyte The address of the register to read
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(data) where data
* is a 16-bit word. Upon failure, callback is invoked as
* callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._readSciRegister16 = function(addressbyte, callback) {

@@ -343,2 +517,20 @@

/*
* (Internal Function) Write two 8-bit values value to a VS10xx register
* Arguments:
*
* addressbyte The address of the register to write to
*
* highbyte The high 8-bit value to write
*
* lowbyte The low 8-bit value to write
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._writeSciRegister = function(addressbyte, highbyte, lowbyte, callback) {

@@ -363,2 +555,18 @@

/*
* (Internal Function) Write a 16-bit value to a VS10xx register
* Arguments:
*
* addressbyte The address of the register to write to
*
* word The 16-bit word to write to the register
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._writeSciRegister16 = function(addressbyte, word, callback) {

@@ -368,2 +576,17 @@ this._writeSciRegister(addressbyte, (word >> 8) & 0xFF, word & 0xFF, callback);

/*
* (Internal Function) Sets the direction of the VS1053b GPIOs. Arguments:
*
* arg The value of the direction register that will be written.
* GPIOs to be used as outputs should have a 1 in the x bit
* position where x is the GPIO number.
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._setChipGpioDir = function(arg, callback) {

@@ -378,2 +601,17 @@ this._writeSciRegister16(SCI_WRAMADDR, GPIO_DIR_ADDR, function(err) {

/*
* (Internal Function) Sets the state of the VS1053b GPIO pins. Arguments:
*
* arg The value of the state register that will be written.
* GPIOs to be set high should have a 1 in the x bit
* position where x is the GPIO number.
*
* callback A callback to be called when setting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._setChipGpio = function(arg, callback) {

@@ -385,2 +623,15 @@ this._writeSciRegister16(SCI_WRAMADDR, GPIO_SET_ADDR, function(err) {

/*
* (Internal Function) Get the direction of each of the VS1053b GPIO pins. Arguments:
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(state) where
* state is a 16-bit word. The state can be interpreted
* as GPIO outputs having a 1 in their bit position. Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._getChipGpioDir = function(callback) {

@@ -390,2 +641,15 @@ this._getChipGPIOValue(GPIO_DIR_ADDR, callback);

/*
* (Internal Function) Get the state of each of the VS1053b GPIO pins. Arguments:
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(state) where
* state is a 16-bit word. The state can be interpreted
* as high GPIOs having a 1 in their bit position. Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._getChipGpio = function(callback) {

@@ -395,2 +659,17 @@ this._getChipGPIOValueFromAddr(GPIO_READ_ADDR, callback);

/*
* (Internal Function) A helper function that fetches the value of a GPIO address. Arguments:
*
* gpioValue The Address of the GPIO bank to read
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(state) where
* state is a 16-bit word. The state can be interpreted
* as high GPIOs having a 1 in their bit position. Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._getChipGPIOValueFromAddr = function(gpioValue, callback) {

@@ -410,2 +689,17 @@ this._writeSciRegister16(SCI_WRAMADDR, gpioValue, function(err) {

/*
* (Internal Function) In order to switch between different Audio inputs and outputs
* GPIOs on board the VS1053b are used. GPIO 5 toggles between different inputs
* and GPIO 7 toggles between different outputs. This function sets them both as
* outputs which is required for setting them high or low (thus, toggling state).
* Arguments:
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype._enableAudioOutput = function(callback) {

@@ -415,89 +709,175 @@ this._setChipGpioDir((1 << 7) + (1 << 5), callback);

/*
* Sets the default input/output arrangements for the module. Arguments:
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype.setDefaultIO = function(callback) {
var self = this;
self._enableAudioOutput(function(err) {
if (err) { self._failConnect(err, callback); }
else {
self.setInput('mic', function(err) {
if (err) { self._failConnect(err, callback); }
else {
self.setOutput('headphones', function(err) {
if (err) { self._failConnect(err, callback); }
else {
callback && callback();
}
});
}
});
}
self.commandQueue.place(function() {
self._enableAudioOutput(function(err) {
if (!self._failConnect(err, callback)) {
self.setInput('mic', function(err) {
if (!self._failConnect(err, callback)) {
self.setOutput('headphones', function(err) {
if (!self._failConnect(err, callback)) {
callback && callback();
}
});
}
});
self.commandQueue.next();
}
});
});
}
Audio.prototype.setVolume = function(leftChannelDecibels, rightChannelDecibels, callback) {
// If no volume was provided
if (leftChannelDecibels === undefined) {
// Just callback
if (callback) {
callback();
/*
* Sets the output volume for the Module. Arguments:
*
* leftchannel A float that indicates the level of sound from the left audio.
* channel. Can between 0 and 1, where 1 is the louded possible value.
*
* rightchannel [Optional] A float that indicates the level of sound from the left audio.
* channel. Can between 0 and 1, where 1 is the louded possible value.
* If this argument is omitted, the leftchannel value will be used.
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
*/
Audio.prototype.setVolume = function(leftChannel, rightChannel, callback) {
var self = this;
self.commandQueue.place(function() {
if(typeof leftChannel !== 'number'){ // if no volume provided
return (!typeof leftChannel === 'function') || leftChannel(); // call callback if provided
}
// and return
return;
}
// If the user passed in one decibel level and a callback
else if (typeof rightChannelDecibels === 'function' && !callback) {
// set the callback
callback = rightChannelDecibels;
// And make both channels the same
rightChannelDecibels = leftChannelDecibels;
}
// If the user only passed in a decibel level
else if (rightChannelDecibels === undefined && callback === undefined) {
// Make both channels the same
rightChannelDecibels = leftChannelDecibels;
}
leftChannel = self._normalizeVolume(leftChannel);
// The units are in half decibels
leftChannelDecibels = leftChannelDecibels/0.5;
rightChannelDecibels = rightChannelDecibels/0.5
// Set VS10xx Volume Register
this._writeSciRegister(SCI_VOL, leftChannelDecibels, rightChannelDecibels, callback);
if(typeof rightChannel !== 'number') {
if(typeof rightChannel === 'function') {
callback = rightChannel;
}
rightChannel = leftChannel; // set right channel = left channel
} else {
rightChannel = self._normalizeVolume(rightChannel);
}
// Set VS10xx Volume Register
self._writeSciRegister(SCI_VOL, leftChannel, rightChannel, callback);
setImmediate(self.commandQueue.next.bind(self));
});
}
/*
* (Internal Function) Converts user input from setVolume into a decibel level
* that the VS1053b expects. Arguments:
*
* vol A float from 0-1 that indicates the level of sound.
*
*/
Audio.prototype._normalizeVolume = function(vol){
vol = (vol > 1) ? 1 : (vol < 0) ? 0 : vol; // make sure val is in the range 0-1.
return Math.round((1 - vol) * 0xFE); // 0xFE = min sound level before completely off (0xFF)
}
/*
* Toggles between line in and the oboard microphone as a recording input. Arguments:
*
* input A string that is either `mic` or `lineIn`.
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
* It may also be created if the provided input is invalid.
*/
Audio.prototype.setInput = function(input, callback) {
if (input != 'lineIn' && input != 'mic') {
return callback && callback(new Error("Invalid input requested..."));
}
else {
this.input = input;
var self = this;
this._getChipGpio(function(err, gpio) {
if (err) { return callback && callback(err); }
else {
var newReg = (input === "lineIn" ? (gpio | (1 << inputReg)) : (gpio & ~(1 << inputReg)));
this._setChipGpio(newReg, callback);
}
}.bind(this));
}
self.commandQueue.place(function() {
if (input != 'lineIn' && input != 'mic') {
callback && callback(new Error("Invalid input requested..."));
setImmediate(self.commandQueue.next.bind(self));
return
}
else {
self.input = input;
self._getChipGpio(function(err, gpio) {
if (err) { return callback && callback(err); }
else {
var newReg = (input === "lineIn" ? (gpio | (1 << inputReg)) : (gpio & ~(1 << inputReg)));
self._setChipGpio(newReg, callback);
setImmediate(self.commandQueue.next.bind(self));
}
});
}
});
}
/*
* Toggles between line out and headphones as the output signal. Arguments:
*
* output A string that is either `headphones` or `lineOut`.
*
* callback A callback to be called when getting completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for one primary reasons:
*
* Error Created when the SPI bus is unable or fails to transceive data.
* It may also be created if the provided input is invalid.
*/
Audio.prototype.setOutput = function(output, callback) {
if (output != 'lineOut' && output != 'headphones') {
return callback && callback(new Error("Invalid output requested..."));
}
else {
this.output = output;
this._getChipGpio(function(err, gpio) {
if (err) { return callback && callback(err); }
else {
// Check if it's input or output and set the 7th bit of the gpio reg accordingly
var newReg = (output === 'lineOut' ? (gpio | (1 << outputReg)) : (gpio & ~(1 << outputReg)));
this._setChipGpio(newReg, callback);
}
}.bind(this));
}
var self = this;
self.commandQueue.place(function() {
if (output != 'lineOut' && output != 'headphones') {
callback && callback(new Error("Invalid output requested..."));
setImmediate(self.commandQueue.next.bind(self));
return;
}
else {
self.output = output;
self._getChipGpio(function(err, gpio) {
if (err) { return callback && callback(err); }
else {
// Check if it's input or output and set the 7th bit of the gpio reg accordingly
var newReg = (output === 'lineOut' ? (gpio | (1 << outputReg)) : (gpio & ~(1 << outputReg)));
self._setChipGpio(newReg, callback);
setImmediate(self.commandQueue.next.bind(self));
}
});
}
});
}
/*
* A helper class to keep track of the state of a provided buffer
*
* _buflen The length of a buffer
*
* id The generated ID that is used to distinguish the track from others
*
* callback A callback to be called when track playback completes
*/
function Track(length, id, callback) {

@@ -511,2 +891,20 @@ this._buflen = length;

/*
* Stops any currently playing tracks and places a new track at the beginning of the queue.
* Playback will start immediately. Arguments:
*
* buff A sound Buffer in a format that is supported by the VS1053b
*
* callback A callback to be called when playback completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if the Audio module can't obtain a lock
* on the SPI bus. It could be returned if the module is currently
* recording. It could be returned if all GPIO interrupts are
* being used elsewhere. It could be returned if there is no more
* available RAM memory for streaming.
*/
Audio.prototype.play = function(buff, callback) {

@@ -533,24 +931,50 @@ // Check if no buffer was passed in but a callback was

self.spi.lock(function(err, lock) {
if (err) {
if (callback) {
callback(err);
}
self.commandQueue.place(function() {
return;
// If we don't have a lock
if (!self.lock) {
// Obtain a lock
self.spi.lock(function(err, lock) {
if (err) {
if (callback) {
callback(err);
}
self.commandQueue.next();
return;
}
// Keep a reference to the lock
self.lock = lock;
// Play the track
_play_helper();
});
}
else {
// Play the track
_play_helper();
}
// Save the lock reference so we can free it later
self.lock = lock;
// Send this buffer off to our shim to have it start playing
var streamID = hw.audio_play_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length);
function _play_helper() {
// Send this buffer off to our shim to have it start playing
var streamID = hw.audio_play_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length);
var track = new Track(buff.length, streamID, callback);
var track = new Track(buff.length, streamID, callback);
self._handleTrack(track);
self._handleTrack(track);
self.emit('play', track);
self.emit('play', track);
self.commandQueue.next();
}
});
}
/*
* (Internal Function) Checks the callback of the queue or play command for error and
* places the created track onto the callbacks datastructure so their callback can
* be called upon completion. Arguments:
*
* track A Track Object created with a sound buffer
*/
Audio.prototype._handleTrack = function(track) {

@@ -579,7 +1003,4 @@ // If stream id is less than zero, an error occured

else {
// If a callback was provided
if (track.callback) {
// Add it to the callbacks dict
_audioCallbacks[track.id] = track.callback;
}
_audioCallbacks[track.id] = track;

@@ -590,2 +1011,20 @@ this.emit('queued', track.id);

/*
* Places a sound buffer at the end of the queue. Any currently playing tracks will continue.
* Arguments:
*
* buff A sound Buffer in a format that is supported by the VS1053b
*
* callback A callback to be called when queueing completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if the Audio module can't obtain a lock
* on the SPI bus. It could be returned if the module is currently
* recording. It could be returned if all GPIO interrupts are
* being used elsewhere. It could be returned if there is no more
* available RAM memory for streaming.
*/
Audio.prototype.queue = function(buff, callback) {

@@ -608,25 +1047,35 @@ var self = this;

// Initialize SPI to the correct settings
self.spi.initialize();
self.commandQueue.place(function() {
// If we don't have a SPI lock
if (!self.lock) {
// Initialize SPI to the correct settings
self.spi._initialize();
// If there was a lock in place, wait until it's released, and we have it
self.spi.lock(function(err, lock) {
// If there was a lock in place, wait until it's released
self.spi.lock(function(err, lock) {
if (err) {
if (callback) {
callback(err);
}
self.commandQueue.next();
return;
}
else {
self.lock = lock;
// Release the lock so that we don't wait until complete for next queue
lock.release();
self.lock = null;
if (err) {
if (callback) {
callback(err);
}
return;
// Queue the data
_queue_helper();
}
});
}
else {
// Queue the data
_queue_helper();
}
function _queue_helper() {
var streamID = hw.audio_queue_buffer(self.MP3_XCS.pin, self.MP3_DCS.pin, self.MP3_DREQ.pin, buff, buff.length);
var track = new Track(buf_len, streamID, callback);
self._handleTrack(track);
self.commandQueue.next();
}

@@ -636,2 +1085,16 @@ });

/*
* Pauses playback of the first sound buffer in the queue. Can be continued with resume().
* Arguments
*
* callback A callback to be called when pausing completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if the Audio module can't obtain a lock
* on the SPI bus. It could be returned if the module is currently
* recording.
*/
Audio.prototype.pause = function(callback) {

@@ -648,21 +1111,38 @@ var err;

// If we have a lock on the spi bus
if (this.lock) {
// Release it
this.lock.release(function(err) {
// Call the callback if we have one
self.commandQueue.place(function() {
// If we have a lock on the spi bus
if (this.lock) {
// Release it
this.lock.release(function(err) {
// Call the callback if we have one
if (callback) {
callback(err);
}
self.commandQueue.next();
return;
});
}
// If there is no lock, just call the callback
else {
if (callback) {
callback(err);
}
return;
});
}
// If there is no lock, just call the callback
else {
if (callback) {
callback(err);
self.commandQueue.next();
}
}
});
}
/*
* Stops the playback of an audio buffer and clears the queue.
*
* callback A callback to be called when stopping completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if the Audio module can't obtain a lock
* on the SPI bus. It could be returned if the module is currently
* recording.
*/
Audio.prototype.stop = function(callback) {

@@ -677,20 +1157,29 @@ var err;

// If we have a lock on the spi bus
if (this.lock) {
// Release it
this.lock.release(function(err) {
// Call the callback if we have one
self.commandQueue.place(function() {
if (this.lock) {
// Release it
this.lock.release(function(err) {
// Call the callback if we have one
if (callback) {
callback(err);
}
self.commandQueue.next();
return;
});
}
// If there is no lock, just call the callback
else {
if (callback) {
callback(err);
}
return;
});
}
// If there is no lock, just call the callback
else {
if (callback) {
callback(err);
self.commandQueue.next();
}
}
});
}
/*
* Returns an array of the available recording profiles that can be provided to
* startRecording().
*
*/
Audio.prototype.availableRecordingProfiles = function() {

@@ -706,4 +1195,20 @@ return [

/*
* Start recording sound through the input. Data can be collected with the `data
* event.
*
* profile The recording profile to use (sets the sound quality). By
* default, the best voice recording profile is used.
*
* callback A callback to be called when recording starts. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if memory for the incoming sound data
* couldn't be allocated. An error could be returned if an invalid
* recording profile name is passed in. Or an error could be returned
* if the module is in playback mode.
*/
Audio.prototype.startRecording = function(profile, callback) {

@@ -728,71 +1233,90 @@ var self = this;

// Initialize SPI to the correct settings
self.spi.initialize();
self.commandQueue.place(function() {
var pluginDir = __dirname + "/plugins/" + profile + ".img";
// Initialize SPI to the correct settings
self.spi.initialize();
var ret = hw.audio_start_recording(this.MP3_XCS.pin, this.MP3_DREQ.pin, pluginDir, _fillBuff);
var pluginDir = __dirname + "/plugins/" + profile + ".img";
if (ret < 0) {
var err;
var ret = hw.audio_start_recording(self.MP3_XCS.pin, self.MP3_DREQ.pin, pluginDir, _fillBuff);
if (ret == -1) {
err = new Error("Not able to allocate recording memory...");
if (ret < 0) {
var err;
if (ret == -1) {
err = new Error("Not able to allocate recording memory...");
}
else if (ret == -2) {
err = new Error("Invalid plugin file.");
}
else if (ret == -3) {
err = new Error("Module must be in an idle state to start recording.");
}
if (callback) {
callback(err);
}
return;
}
else if (ret == -2) {
err = new Error("Invalid plugin file.");
}
else if (ret == -3) {
err = new Error("Module must be in an idle state to start recording.");
}
if (callback) {
callback(err);
}
return;
}
else {
if (callback) {
callback();
}
else {
if (callback) {
callback();
self.emit('startRecording');
}
this.emit('startRecording');
}
self.commandQueue.next();
});
}
/*
* Stop recording sound through the input.
*
* callback A callback to be called when recording completes. Upon
* success, callback is invoked as callback(). Upon failure,
* callback is invoked as callback(err) instead.
*
* This function may fail for a number of reasons:
*
* Error Could be returned if the module is not in a valid state
* to stop recording (like if it's currently playing audio).
*/
Audio.prototype.stopRecording = function(callback) {
var self = this;
var ret = hw.audio_stop_recording();
self.commandQueue.place(function() {
if (ret < 0) {
var err = new Error("Not in valid state to stop recording.");
var ret = hw.audio_stop_recording();
if (callback) {
callback(err);
if (ret < 0) {
var err = new Error("Not in valid state to stop recording.");
if (callback) {
callback(err);
}
}
}
else {
else {
function recStopped(length) {
function recStopped(length) {
process.unref();
process.unref();
// If a callback was provided, return it
if (callback) {
callback();
// If a callback was provided, return it
if (callback) {
callback();
}
// Stop recording
self.emit('stopRecording');
}
// Stop recording
self.emit('stopRecording');
}
process.once('audio_recording_complete', recStopped);
process.once('audio_recording_complete', recStopped);
process.ref();
}
process.ref();
}
self.commandQueue.next();
});
}
exports.use = use;
{
"name": "audio-vs1053b",
"version": "0.1.91",
"version": "0.2.0",
"description": "Library to run the Tessel Audio Module. Plays and records sound.",

@@ -15,7 +15,8 @@ "main": "index.js",

"hardware": {
"./examples": "false",
"./test": "false"
"./examples": "false",
"./test": "false"
},
"author": "",
"dependencies": {},
"dependencies": {
"sync-queue": "0.0.1"
},
"devDependencies": {

@@ -22,0 +23,0 @@ "async": "^0.9.0",

@@ -39,4 +39,4 @@ #Audio

console.log("Audio module connected! Setting volume...");
// Set the volume in decibels. Around 20 is good; smaller is louder.
audio.setVolume(20, function(err) {
// Set the volume in decibels. Around .8 is good; 80% max volume or -25db
audio.setVolume(.8, function(err) {
if (err) {

@@ -69,3 +69,3 @@ return console.log(err);

&#x20;<a href="#api-audio-setVolume-leftChannelDb-rightChannelDb-callback-err-Set-the-output-volume-Level-is-a-Number-from-0-0-to-1-0" name="api-audio-setVolume-leftChannelDb-rightChannelDb-callback-err-Set-the-output-volume-Level-is-a-Number-from-0-0-to-1-0">#</a> audio<b>.setVolume</b>( leftChannelDb, [rightChannelDb,] callback(err) )
Set the output volume. Level is a Number from 0.0 to 1.0
Set the output volume. Level is a Number from 0.0 to 1.0 (-127dB to 0dB)

@@ -76,3 +76,3 @@ &#x20;<a href="#api-audio-setInput-input-callback-err-Set-the-input-to-either-lineIn-or-mic-Defaults-to-lineIn" name="api-audio-setInput-input-callback-err-Set-the-input-to-either-lineIn-or-mic-Defaults-to-lineIn">#</a> audio<b>.setInput</b>( input, callback(err) )

&#x20;<a href="#api-audio-setOutput-output-callback-err-Set-the-output-to-either-lineOut-or-headPhones-Defaults-to-lineOut" name="api-audio-setOutput-output-callback-err-Set-the-output-to-either-lineOut-or-headPhones-Defaults-to-lineOut">#</a> audio<b>.setOutput</b>( output, callback(err) )
Set the output to either 'lineOut' or 'headPhones'. Defaults to 'lineOut'.
Set the output to either 'lineOut' or 'headphones'. Defaults to 'lineOut'.

@@ -142,5 +142,5 @@ &#x20;<a href="#api-audio-startRecording-profile-callback-err-Start-recording-sound-from-the-input-Receive-data-in-the-data-event-Callback-called-after-recording-initialized-not-stopped-quality-is-an-optional-argument-that-can-be-voice-wideband-voice-wideband-stereo-hifi-voice-or-stereo-music-Default-is-hifi-voice" name="api-audio-startRecording-profile-callback-err-Start-recording-sound-from-the-input-Receive-data-in-the-data-event-Callback-called-after-recording-initialized-not-stopped-quality-is-an-optional-argument-that-can-be-voice-wideband-voice-wideband-stereo-hifi-voice-or-stereo-music-Default-is-hifi-voice">#</a> audio<b>.startRecording</b>( [profile] callback(err) )

###Further Examples
* [Audio Out No Streams](https://github.com/tessel/audio-vs1053b/blob/master/examples/audio-out-no-streams.js). This Audio Module demo sends audio from a file to Headphones/Line out without using streams..
* [Audio Out No Streams](https://github.com/tessel/audio-vs1053b/blob/master/examples/audio-out-no-streams.js). This Audio Module demo sends audio from a file to Headphones/Line out without using streams..
* [Record Sound](https://github.com/tessel/audio-vs1053b/blob/master/examples/record-sound.js). This Audio Module demo sends audio from the microphone to a file without using streams.
* [Stream Audio Out](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-audio-out.js). This Audio Module demo sends audio from a file to Headphones/Line out using streams.
* [Stream Audio Out](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-audio-out.js). This Audio Module demo sends audio from a file to Headphones/Line out using streams.
* [Stream Sound to File](https://github.com/tessel/audio-vs1053b/blob/master/examples/stream-sound-to-file.js). This Audio Module demo takes line-in and writes it to a file using streams.

@@ -147,0 +147,0 @@

@@ -23,3 +23,3 @@ var test = require('tinytap');

test("Changing the volume with single volume arg", function(t) {
var testValue = 10;
var testValue = .9;
audio.setVolume(testValue, function(err) {

@@ -30,4 +30,4 @@ t.equal(err, undefined, "error changing volume");

audio._readSciRegister16(0x0B, function(err, value) {
t.equal(testValue, ((value >> 8)/2), 'left channel volume not set correctly');
t.equal(testValue, ((value & 0xFF)/2), 'right channel volume not set correctly');
t.equal(audio._normalizeVolume(testValue), (value >> 8), 'left channel volume not set correctly');
t.equal(audio._normalizeVolume(testValue), (value & 0xFF), 'right channel volume not set correctly');
t.end();

@@ -40,4 +40,4 @@ });

test("Changing the volume with both volume args", function(t) {
var testValueLeft = 10;
var testValueRight = 20;
var testValueLeft = .9;
var testValueRight = .8;
audio.setVolume(testValueLeft, testValueRight, function(err) {

@@ -48,4 +48,4 @@ t.equal(err, undefined, "error changing volume");

audio._readSciRegister16(0x0B, function(err, value) {
t.equal(testValueLeft, ((value >> 8)/2), 'left channel volume not set correctly');
t.equal(testValueRight, ((value & 0xFF)/2), 'right channel volume not set correctly');
t.equal(audio._normalizeVolume(testValueLeft), (value >> 8), 'left channel volume not set correctly');
t.equal(audio._normalizeVolume(testValueRight), (value & 0xFF), 'right channel volume not set correctly');
t.end();

@@ -64,3 +64,3 @@ });

t.end();
});
});
});

@@ -78,3 +78,3 @@ }),

t.end();
});
});
});

@@ -99,3 +99,3 @@ }),

t.end();
});
});
});

@@ -112,3 +112,3 @@ }),

t.end();
});
});
});

@@ -121,3 +121,3 @@ }),

t.ok(err, 'error setting input');
t.end();
t.end();
});

@@ -151,6 +151,6 @@ }),

// Clear the
// Clear the
clearTimeout(timeout);
audio.removeAllListeners('data');
finished = true;

@@ -233,3 +233,1 @@

);
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc