audio-works

0.6.8 • Public • Published

audio-works

UTs CodeQL NPM Downloads GitHub last commit

WIP

Library meant for Electron (ver. 11.x - 13.x) to determine note based on the signal received from mic or file.

Currently, tested determining sounds down to C1 ~ 32.7Hz (Less than 2Hz difference between C1 and B0) so at the moment it's accurate enough down to at least 2Hz differences.

  • Added volume measuring
  • Still a lot a little of garbage left in methods waiting for removal
  • Added possibility to change input audio device (+ automatically changes when current device gets disconnected)
  • Still a lot a little bit Almost none of garbage left in methods waiting for removal
  • Added possibility to change input audio device (+ automatically updates list of devices on change / when current device gets disconnected)
  • Separated most micSetup and Renderer methods into modules
  • Changed objects into classes
  • Fixed bug with enabling mic after disabling it
  • Fixed bug with repeatedly changing input device while the mic is enabled resulting in problems with audioContext
  • Untangled logic, so it's a bit more simple and less convoluted now imo I was so wrong
  • Added A-, B- and C-weighting classes
  • Changed audio volume measurement using weighting classes
  • Added methods returning nyquist frequency and band range of current audioHandler setup
  • Added possibility to change output device

TODO right now:

  • [x] Add methods to frequencyMath
  • [x] Untangle deviceHandler and other redundant methods etc.
  • [ ] Adding possibility to automatically switch to default available device if currently used one gets disconnected
  • [x] General code refactor
  • [x] Output audio (the latency is/will be +- 1 second so not great, but it's Node + Chromium ¯\_(ツ)_/¯
  • [x] Changes in soundStorage module for storing and determining frequencies (in progress)
  • [ ] Anything else that will pop up later

ChangeLog:

Classes:

Test coverage

Setup, sample initialization

Electron's browser window should've contextIsolation set to false as well as nodeIntegration set to true.

window = new browserWindow({
  webPreferences: {
    contextIsolation: false,
    nodeIntegration: true,
  },
});

Then in rendering process sample initialization logging value of a correlated buffer from the default device could look like this:

const { AudioHandler, AudioEvents } = require("audio-works");

let mic = new AudioHandler();

mic.on(AudioEvents.audioProcessUpdate, (evt) => {
  console.log(evt.correlate());
}); // Event called from ScriptProcessor on new buffer chunk

await mic.setupStream(); // Start the mediaStreamSource

setTimeout(1000, () => {
  mic.end();
}); // close the stream after 1 second

It is also possible to output received signal by creating the html Audio object and setting it's srcObject property to the stream hold by the AudioHandler.

const { AudioHandler, AudioEvents } = require("audio-works");

let mic = new AudioHandler();
let audio = new Audio();

mic.on(AudioEvents.setupDone, (evt) => {
  audio.srcObject = evt.stream;
}); // Event emitted after setupStream()

await mic.setupStream(); // setupStream() is asynchronus but all the following
// actions can be done on emission of the "SetupDone" event
// so that await in such a case could be omitted

To change the device it's enough to pass an id of said device to the changeInput methods of the AudioHandler. List of devices can be accessed through DeviceHandler hold by the AudioHandler as deviceHandler property.

const { AudioHandler, Device } = require("audio-works");

let mic = new AudioHandler();

// if for some reason the device list is empty, which shouldn't really happen,
// then it can be easily fixed by calling `await mic.deviceHandler.updateDeviceList();`

// Retrieves a list of available devices
let inputs = mic.getDeviceList(Device.direction.input);
// Change default ('first available') input to the third one
mic.changeInput(inputs[2].id);

await mic.setupStream();

Classes

AudioSetup

File in GitHub
Main class responsible for setting up AudioHandler and AudioFileHandler holding two main obligatory nodes used by AudioContext which are AnalyserNode and GainNode. This class extends EventEmitter as after various steps instance dispatches related to them events.

Method Arguments Return value Description
constructor gain: Gain,
analyser: Analyser
AudioSetup Receives AudioNode and GainNode instances, saves them to class members stored as this.gain and this.analyser then immediately calls startAudioContext method
startAudioContext N/A void Creates new AudioContext instance that is stored as this.audioContext, then Analyser and Gain nodes passed to the instances in constructor are created. With AnalyserNode set up sample rate and bin count are stored as class members in_this.sampleRate_ and _this.binCount_Finally event "AudioContextStarted" is dispatched notifying about finished initial setup.
streamSetup MediaStreamSource: IAudioNode, ScripProcessor: IAudioNode void Connects Analyser to MediaStreamSource, then connects ScripProcessor to the Analyser. AudioContext.destination is being connected to both GainNode and ScripProcessor. Finally, ScripProcessor.onaudioprocess callback is defined which dispatches "AudioProcessUpdate" event holding instance of AudioSetup which holds the ScriptProcessor.
async streamClose N/A void Disconnects GainNode and AnalyserNode, then closes AudioContext.
async streamPause N/A void Suspends AudioContext. With Chromium backward compatibility it is heavily unreliable
async streamResume N/A void Basically just a shorthand for await this.audioContext.resume()
BFD dataContainer: Uint8Array void Shorthand for this.analyser.node.getByteFrequencyData(dataContainer)
BFDUint8 binCount: uint = this.binCount Uint8Array Shorthand call to this.BFD(...) that automatically creates Uint8Array of size passed to the method as binCount argument that defaults to this.binCount, that will be filled with data by_getByteFrequencyData_ and returns it afterwards.
FTD buffer: Float32Array void Shorthand for this.analyser.node.getFloatTimeDomainData(Buffer)
FTDFloat32 buflen: uint = this.buflen Float32Array Shorthand call to this.FTD(...) that automatically creates Float32Array of size passed to the method as buflen argument that defaults to this.buflen, that will be filled with data by_getFloatTimeDomainData_ and returns it afterwards.
selfCheckAudioContext N/A bool Checks state of AudioContext instance and starts it up again if it's currently in a closed state.

AudioHandler

File in GitHub
Extends AudioSetup as AudioContext is crucial for all the functionalities provided by this class. Handles live audio inputs like microphones or instruments connected to audio interfaces as well as output to any available devices.

Method Arguments Return value Description
constructor {
 general:
 {
 buflen: int,
 curveAlgorithm: string
 },
 gainNode: GainNode,
 analyserNode: AnalyserNode,
 correlationSettings:
 {
 rmsThreshold: double <0, 1),
 correlationThreshold: double <0, 1),
 correlationDegree: double <0, 1)
 }
 navigator: Optional[object]
}
AudioHandler Constructor receives object containing:
  • general: object containing buffer length used in correlation and curveAlgorithm to which audio spectrum will be able to be cast
  • GainNode passed to the base class constructor
  • AnalyserNode passed to the base class constructor
  • correlationSettings: object holding values for Correlation class initialization
After base class constructor call, setting buffer length and sound curve algorithm new DeviceHandler class is initialized and stored in member deviceHandler which will be used to access Audio IO devices.
async getMediaStream deviceId: Optional[string] MediaStream Returns output of navigator.mediaDevices.getUserMedia() method to which is passed the constraint. By default, initially, no video, only first default audio device. Sets stream for provided device ID and if not specified, first available input audio device.
async setupStream deviceId: Optional[string] void If no input device is available method throws 'No input audio input devices available'. If audioContext is closed it automatically starts a new one. Creates new instances of MediaStreamSource and ScriptProcessor sent further to the streamSetup method of base class. Stream from getMediaStream method is stored in class member this.stream. After that a Correlation instance is created and stored in this.correlation member. Sets stream for provided device ID and if not specified, first available input audio device.
nyquistFrequency N/A double Returns AudioContext sample rate divided by two which is... the nyquist frequency.
getVolume accuracy: int double An average of values stored in analysers ByteFrequencyData. The accuracy passed to the method represents decimal points of returned value.
getWeightedVolume accuracy: int double Purely empirical and subjective method that aggregates all the bands from the byte frequency data cast into a weighting curve then passed through logarithm of base 10 and finally multiplied by ten... The accuracy passed to the method represents decimal points of returned value. Seems to work better (from human ear perspective) then getVolume method especially with addition of few operations to limit the output value (ie. see Sample usage of getWeightedVolume below), but then again, it's not a concrete measure as it's a subjective value.
correlate N/A double Returns output of correlation (frequency in Hz) performed on float time domain data of the currently stored buffer.
async getDeviceList direction: Optional[Device.direction] Array[Device] Returns array of Device instances related to available audio IO devices. If no direction is specified all devices will be returned, otherwise only the devices in specified direction.
async pause N/A void Calls base class method streamPause(), sets running member of class to false and emits event "StreamPause" at the end
async resume N/A void Calls base class method streamResume(), sets running member of class to true and emits event "StreamResume" at the end

Sample object initialization

const { AudioHandler, Gain, Analyser } = require("audio-works");

let mic = new AudioHandler({ // All the values are optional.
    general: {               // Omitting some values in objects
        buflen: 8192,        // containing more properties will result
        curveAlgorithm: 'A'  // in assigment of default value
    },                       // only to the missing properties
    gainNode: new Gain({value: 1.5}),
    analyserNode: new Analyser({
        smoothingTimeConstant: 0.9,
        fftSize: 32768,
        minDecibels: -90,
        maxDecibels: -10
    }),
    correlation: {
        rmsThreshold: 0.01,
        correlationThreshold: 0.01,
        correlationDegree: 0.98
    }
});

Sample usage of getWeightedVolume

const vol = mic.getWeightedVolume(2); 
let volume = (vol / 200) * (vol / 2); // Let's take everything over 200dB as maximally "loud"
                                      // (alternatively can be written as vol^2 / 400)
volume = volume < 100 ? volume : 100; 

AudioFileHandler

File in GitHub
Extends AudioHandler class therefore retains possibility to handle live audio input but adds methods meant for audio file decoding, creating standard BufferSources with primary goal of audio output, or obtaining pulse-code modulation data.

Method Arguments Return value Description
constructor initData: Object[SameAsForAudioHandler],
filePath: string,
maxSmallContainerSize: uint = 35000
AudioFileHandler Given that this class extends AudioHandler the initData argument is the object passed to the base class. Additionally, it accepts filePath argument which, as the name suggests, should be the path to a file which will be processed. Because there's a need to decode the files, and their content will have to be converted to ArrayBuffer, "maxSmallContainerSize" uint will choose the appropriate method to convert the data as different solutions work faster for different container sizes. i.e. new Uint8Array(data).buffer will be faster for smaller containers than a standard for loop with value reassignments by ~30% as long as the "data" container has less than 35 000 elements. With more elements to process the situation is reversed and standard loop becomes faster for large containers.
async decode callback: function AudioBuffer Reads whole file, casts it to ArrayBuffer which is then passed along with a callback to the AudioContext method decodeAudioData that's returned from the method.
async getPCMData data: AudioBuffer,
channel: uint
Object{
 data: AudioBuffer,
 pcm: Array[int]
}
Data is supposed to be the output of AudioContext.decodeAudioData method which is actually the default value in case of no parameter passed to this method. Channel argument specifies which channel to read from the data. Returns object { data, pcm } where data is the original decode file data and pcm is the pulse-code modulation from the specified channel.
async initCorrelation buflen = this.buflen: uint void Correlation object is created during the setup of audio stream in base class. This case does not apply to the FileHandler variant and so to create the Correlation instance inside the AudioFileHandler instance this method call is required.
process pcm: pcm: Array[int],
action: function
void Action argument is supposed to be a callback handling chunks of data. This method loops through the pcm data performing on each chunk of data specified action.
async processEvent decoded: AudioBuffer,
channel: uint
void Decoded and channel arguments are the same ones used in getPCMData method as those are passed to it to retrieve the pcm data which is then passed to the process method with default callback simply emitting event "ProcessedFileChunk" that contains said chunk.
async processCallback callback: function,
decoded: AudioBuffer,
channel: uint
void Same method as processEvent with only difference of obligatory callback passed as the first argument that's going to be passed to the process method to handle the pcm data chunks.
async createSource callback: function AudioBufferSourceNode Creates BufferSource node from the AudioContext, then calls this.decode(action) where if callback was defined the action is exactly the same callback, and in case of undefined callback it sets BufferSource buffer as the -soon to be- decoded file while also connecting it to AudioContext.destination. Finally, the method returns BufferSource instance created in the beginning.

Example of logging correlated data and playing the audio from a file:

const { AudioFileHandler, AudioEvents } = require("audio-works");

const fileHandler = new AudioFileHandler({}, "./audioFiles/sample.wav");
await fileHandler.initCorrelation(); // this call is needed as we don't
// call setupStream() method

// -- Event driven approach --
fileHandler.on(AudioEvents.processedFileChunk, (evt) => {
  // perform() is called directly on the correlation object stored
  // in fileHandler, unlike calling "correlate()" in AudioHandler,
  // as there's no mediaStream stored in the "stream" property,
  // therefore it requires to manually push the data chunk passed
  // to the listener in evt data to be correlated.
  console.log(fileHandler.correlation.perform(evt));
});

const audioSource = await fileHandler.createSource();
audioSource.start(0);

fileHandler.processEvent(); // start processing

// -- Callback approach --
const audioSource = await fileHandler.createSource();
audioSource.start(0);

fileHandler.processCallback((data) => {
  console.log(fileHandler.correlation.perform(data));
});
// While using callback processing starts immediately so there's
// no call like "processEvent()" in this case

Correlation

File in GitHub
Sole purpose of this class is performing autocorrelation on audio buffer, allowing a set-up of custom thresholds. The output of perform method is supposed to be a frequency of the sound (the fundamental frequency). This means it processes the signal in monophonic context.

Method Arguments Return value Description
constructor Object{
 sampleRate: uint,
 rmsThreshold: double <0,1),
 correlationThreshold: double <0,1),
correlationDegree: double <0,1),
buflen: uint,
returnOnThreshold: bool}
Correlation Creates a Correlation instance setting up rms and correlation thresholds. Sample rate is require for the last step of the autocorrelation as based on this value the frequency will be calculated. It is possible and encouraged to pass only the buflen and sampleRate values as the remaining values can be automatically set to default. Based on buffer length (buflen) value of the defaultCorrelationSampleStep property is determined: For buffer length below 8192 by default the value is set to 1 otherwise to 2. The purpose of it is that with large buffers the accuracy is good enough while looping over every second element/pair during the autocorrelation. This behaviour can be changed to standard looping over every element/pair bt simply passing value 1 to the perform method. It should be noted that with larger buffers not skipping any element results in higher latency where skipping every second pair boosts execution time by ~60-70% in case of buffers over 8192 samples compared to standard loop over every element/pair and in both scenarios the difference in results is around 4th decimal place therefore by default in case of larger buffers the algorithm sets defaultCorrelationSampleStep to 2.
perform buf: Float32Array,
defaultCorrelationSampleStep: uint = <1 or 2 depending on buffer size>
double This method receives buffer with data that will be processed up to the length specified in the this.buflen member. If RMS will be too low, meaning the signal is too weakk, -1 will be returned. In case autocorrelation algorithm result will be higher than this.correlationThreshold the output will be the fundamental frequency of the passed buffer, otherwise it will return -1. As mentioned before, defaultCorrelationSampleStep determines the incrementation of data for loops going through the buffer. The higher the value the more values/pairs will be skipped. It shouldn't be set to value higher than 2. For smaller buffers (< 8192) it's set to 1, for larger ones it's set to 2 to minimize latency.
_checkRms buf: Float32Array,
defaultCorrelationSampleStep: uint = <1 or 2 depending on buffer size>
bool Calculate sum of squares of all the values in the buffer and returns true if the square sum divided by amount of elements is higher than value specified in the constructor: this.rmsThreshold.

DeviceHandler

File in GitHub
Main purpose of this class is interaction with navigator.mediaDevices and for that reason it uses a private helper class Device. Device class instances returned from methods of this class are only the copies of actual stored objects to keep the data stored by the instance consistent regardless of user actions on obtained device data.

Method Arguments Return value Description
constructor callback: function, navigator: Optional[object] DeviceHandler Callback passed to the constructor will be called on every ondevicechange event triggered from navigator.mediaDevices. Optional navigator field should be initialized with window.navigator object or an object with the same interface.
async deviceChangeEvent N/A void This method is called on every device change and is responsible for invoking the user callback passed previously to the constructor. It is called right after the invocation of updateDeviceList method.
async updateDeviceList N/A void This method updates the list of cached audio devices. It is called at every "ondevicechange" event generated by the navigator.mediaDevices. The previous list is completely cleared before creating the new one.
getFullDeviceList N/A Array[Device] Returns an array of devices (Device class instances) available through navigator that contains MediaDeviceInfo as well as it's direction, input or output.
getDeviceList requestedDirection: Device.direction Array[Device] Returns an array of devices in requested direction (Device class instances) available through navigator that contains MediaDeviceInfo as well as it's direction, input or output. Should be used with Device.direction.(input or output) to not use raw strings
getCurrentOrFirst N/A Object{
 in: Device,
 out: Device
}
Returns a object containing a pair of devices - in (input) and out (output). If values this.currentInput and this.currentOutput are set than this devices will be the value in the object. In case current device is not set than a first available one in respective direction will be set up in place of the ones supposed to bo holded by the instance.
changeDevice direction: Device.direction,
deviceId: Optional[string]
void In this method direction is a string stating the direction of the device that's going to be changed. If present than this.current-direction-device will be set to the device found in device list with requested id, or undefined in case of id that was not found. In case of no id passed to the method the first available device in requested direction will be chosen. Lastly the user defined callback handling device change will be called to which current device list of all available devices wil be passed along with the current input and output devices hold by the instance itself. Should be used with Device.direction.(input or output) to not use raw strings
changeInput deviceId: string void Shorthand for await deviceHandlerInstance.changeDevice('input', e)
changeOutput deviceId: string void Shorthand for await deviceHandlerInstance.changeDevice('output', e)
checkForInput N/A bool Returns boolean, true if there's at least one available input device and false if there's none.
navigatorInput N/A Union[Object{ exact: string }, undefined] Returns a constraint for navigator used in audio stream setup stating exact input device. The device will be this.currentInput if set, or first available one. If no input devices are accessible undefined will be returned.

Device

File in GitHub
A class representing navigators mediaDevices. It has no methods, holding only
values: id: device id, label: device label, and dir: device direction
Array of instances of this class is returned from the getDeviceList method of DeviceHandler.
Along the device direction there are also two boolean flags related to it: isOutput and isInput for more convenient array checks and filtering.
Class contains copy method for more convenient deep copies.
For more convenient direction description instead of raw strings class contains a static object serving as enum which can be accessed as Device.direction.(input|output).
For more convenient device type description instead of raw strings class contains a static object serving as enum which can be accessed as Device.type.(audio|video), nonetheless only "audio" option is used/checked in the whole implementation.

SoundStorage

File in GitHub
Class supposed to serve as a storage for outputs of the Correlation class holding methods helping correct sound frequency estimations in short periods of time.

Method Arguments Return value Description
constructor bias = 0.03: double <0, 1) SoundStorage The only parameter for the constructor is bias which will be assigned to the this.biasThreshold member which purpose is removing outlier values during sound estimation. By default, it is set to 0.03. The lower the value the higher similarity sound values will have to have the most frequent value in this.freqArr for those to be taken into account during estimation.
add fx: double self Adds single sound data from the Correlation to the this.freqArr member with 2 decimal points accuracy.
average N/A double Returns rounded average of all the values in this.freqArr
most Array double Returns most frequent value in given array
determine N/A double Returns determined sound frequency based on the hold samples within this.freqArr. It is calculated by calculating a bias of most frequent value * this.biasThreshold. From there an average value is calculated based on all the values within the biased similarity to that most frequent value.
selfCheck N/A int Returns current length of the array this.freqArr holding samples.
emptyData N/A self Empties this.freqArr and returns the SoundStorage instance back.

SoundStorageEvent

File in GitHub
This class has the same purpose as SoundStorage extending it with a difference of utilizing EventEmitter allowing more diverse interactions with the storage.

Method Arguments Return value Description
constructor sampleTarget = 20: uint,
sampleLimit = 40: uint,
bias = 0.03: double <0, 1)
SoundStorageEvent The bias has the same purpose as in SoundStorage. Introduced here sampleTarget is a value representing this.freqArr length at which "SampleTarget" event will be triggered. The sampleLimit works the way as sampleTarget dispatching "SampleLimit" event upon reaching defined this.freqArr length.
add frequency: double void Checks if current this.freqArr requires an event emission. After that section a base class add(fx) method is called.
getCurrentBias N/A Object{
 most: double,
 bias: double
}
Returns current bias value based on user defined bias and most frequent sample value.
getOutliers N/A Array[double] Returns an array containing values that currently do not pass the similarity check based on the bias.
outlierPosition N/A Array[int] Returns array of indexes of values that does not pass the similarity check.
removeOutliers N/A self Remove values of this.getOutliers() from the ORIGINAL this.freqArr hold by the instance.
determine clean = true: bool double Although it works in a similar fashion to the base class here it returns -1 in case of less than 3 samples hold in the this.freqArr as this amount most likely is not sufficient for a proper estimation. Finally, method returns a square root of square powers of ALL the values without applying bias. It is encouraged to extend this class and override this method up to user requirements. To apply the bias before determining the frequency array it's sufficient to call removeOutliers() before calling this method. If clean argument is set to true the "removeOutliers" method will be called before the execution of this function
emptyData N/A self Calls emptyData() method of the base class.
basicDetermine N/A double Base class determine() method is still available through this endpoint.

FrequencyMath

File in GitHub
Class responsible for frequency calculations, as well as translating those to musical notation. It operates based on frequency in Hz or a distance of a note from sound A4. Class performs calculations in a context of equal tempered scale. It holds values about specific sound by holding data in members:

sound: string

Sound symbol of the tone [C - B] with only sharp notes in case of a half tone.

octave: int

Octave of the tone

flatNote: Optional[string]

If sound can be represented as flat note than this member hold a string of it.

flatOctave: Optional[int]

If sound has a flat note representation that has different octave (only C/Bb) it holds octave of the flat note.

initialFrequency: double

Frequency used to initialize class instance. In case of static constructor usage the frequency hold by this member is the perfect pitch of the sound passed to the constructor.

distance: [int]

Distance of given sound from A4.

Method Arguments Return value Description
constructor frequency: double FrequencyMath To initialize an instance only value needed is the frequency. Based on the frequency all the members will be initialized with correct values based on the frequency. In case of a pitch that's not exact the closest sound will be stored in the class instance.
static soundConstructor note: string,
octave: float
FrequencyMath Performs the same operations as standard constructor with a difference of the arguments passed to it as it calculates frequency of the sound from parameters, and then it returns FrequencyMath instance initialized with standard constructor taking frequency as the argument.
static symbolConstructor sound: string FrequencyMath Performs the same operations as standard constructor with a difference of the argument passed to it as it calculates frequency of the sound from parameter, and then it returns FrequencyMath instance initialized with static FrequencyMath.soundConstructor constructor taking note and octave deduced from the sound as the arguments. sound string has to start with one of: - ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] - ["Bb","Cb", "Db", "Eb","Fb", "Gb", "Ab",] immediately followed by a string that can be parsed into integer.
static getDistanceFromFrequency frequency: double int Returns the distance of not from frequency passed as the parameter, relative to the A sound.
static getDistanceFromNote note: string,
octave: int
int Returns distance of a given sound relative to A4 sound.
getNoteFromDistance distance: int int Returns index of sound symbol based on the distance from the A4 sounds. Index of an array of sounds in ALPHABETICAL orders that is from A to G#, not from C to B.
getFrequencyFromDistance distance: int double Returns frequency of a sound based on the distance from A4 sound. Parameters default value is a distance of the sound hold by the class instance.
static getFrequencyFromDistance distance: int double Performs the same operations as non-static version with only difference being the lack of the default value for the argument.
static info frequency: double Object Returns object that holds data about sound given in the parameter with members: distance: int: distance of the sound relative to A4 sound octave: int: octave of given sound soundId: unsigned: index of the tone symbol (alphabetical order)
static getOctaveFromDistance distance: int int Returns octave of a sound based on it's distance from the A4 sound
distanceBetweenNotes sound1: FrequencyMath,
sound2: FrequencyMath
int Returns a distance between two sounds. By default, the first sound is initialized as A4 sound, and the second on is the sound instance hold by the instance on which the method was called.
soundDistanceForward sound1: FrequencyMath,
sound2: FrequencyMath
int Default arguments are the same as in case of distanceBetweenNotes() method. Returns distance between sound1 and the next (forward) sound2 occurrence in the scale. Due to the forwarding octaves are not compared.
getIntervalCents frequency1: double,
frequency2: double
double Returns cents between two frequencies in relation Frequency1/Frequency2. The default value of frequency2 is the member initialFrequency hold by the class instance.
getFrequencyError frequency: double Object Returns object containing data about the given sound. By default, the frequency value is set to initialFrequency member. Object contains members: frequency: double: initialFrequency member of the class instance perfectPitch: double: perfect pitch of the potentially inexact frequency hold by initialFrequency error: double: difference in Hz between given frequency and perfect pitch centsError: double: difference in cents between given frequency and perfect pitch totalCentsBetweenNotes: double: difference in cents between given frequency and note half a tone higher if the initial one is too high, or half a tone lower when it is too low.
getSoundInfo frequency: double Object Works in a similar manner as static info() method, but holds more data in returned object. By default, the fx value is equal to initialFrequency member. The members of the object are: frequency: double: frequency passed to the method note: string: tone symbol step: int: distance of the sound relative to the A4 sound soundId: unsigned: index of the tone symbol (alphabetical order) octave: int: octave of the sound
toString N/A string Returns string as {tone symbol}{octave}

AudioEvents

File in GitHub
Class serving as an enum for events emitted from components.
The sole purpose of it is to diminish required changes in case of changes in
event string values, as well as more transparent place to find all the events.
All the members are static so that no class initialization is required.
Members:

  • audioContextStarted
  • audioProcessUpdate
  • processedFileChunk
  • deviceChange
  • setupDone
  • streamEnd
  • streamPause
  • streamResume
  • sampleLimit
  • sampleTarget

Default setup values

File in GitHub
Fields needed to construct crucial objects:

if not specified by user are loaded from this file.

Current test coverage

File % Stmts % Branch % Funcs % Lines Uncovered Line #s
All files 97.04 88.24 93.43 97.91
audioModules 95.82 88.3 92.31 97.05
AudioFileHandler.js 85.71 90 80 85.71 16-17,64-65
AudioHandler.js 93.98 72 75 97.3 48,77
FrequencyMath.js 100 100 100 100
SoundStorage.js 100 100 100 100
SoundStorageEvent.js 91.43 83.33 100 93.94 14-15
Weights.js 100 100 100 100
index.js 100 100 100 100
audioModules/audioHandlerComponents 98.13 82.35 93.02 98.7
AudioEvents.js 100 100 100 100
AudioSetup.js 97.37 66.67 92.31 97.3 49
Correlation.js 97.56 94.74 100 97.44 88
Device.js 100 100 100 100
DeviceHandler.js 97.73 70 90 100 13-26,66
NavigatorInputConstraint.js 100 100 100 100
defaultAudioValues.js 100 100 100 100
audioModules/audioHandlerComponents/audioSetupComponents 100 100 100 100
Analyser.js 100 100 100 100
Gain.js 100 100 100 100
IAudioNode.js 100 100 100 100
MediaStreamSource.js 100 100 100 100
ScriptProcessor.js 100 100 100 100
audioModules/utilities 100 100 100 100
convertToArrayBuffer.js 100 100 100 100
fillDefaults.js 100 100 100 100
utilities.js 100 100 100 100

ChangeLog

v0.6.8

  • SoundStorageEvent Uses base class empty method instead of custom implementation
  • convertToArrayBuffer function from utils has default value maxSmallContainerSize set to 35000
  • Small optimization of base class of A/B/C-Weight classes
  • getMediaStream method of AudioHandler now accepts device ID for which it should be created
  • setupStream method of AudioHandler now accepts device ID for which it should be created. If none is specified, as usual, the first available device will be used
  • Added optional navigator to AudioHandler (mainly for more convenient testing) it defaults to window.navigator
  • Added optional navigator to DeviceHandler (mainly for more convenient testing) it defaults to window.navigator

v0.6.7

  • DeviceHandler caches devices obtained through navigator in "cachedDevices_" property
  • DeviceHandler no longer sets input/output device to undefined if its ID is not found
  • Methods of DeviceHandler returning Device lists and IDs now operate on copies of stored objects to ensure consistency of stored data regardless of modifications performed on returned objects
  • Device class has new method "copy" that creates a new identical instance of the object
  • Correlation now has the value "returnOnThreshold" set to true by default (default audio values)

v0.6.6

  • ReadMe update

v0.6.5

  • D-weighting algorithm has been removed as it was unreliable and unsupported by ISO
  • FrequencyMath has additional static constructor symbolConstructor that can create a new instance of the class simply by a string like "C4" passed to it as an argument.
  • getMediaStream method of AudioHandler now doesn't accept custom constraint as it was unreliable, although it should be back in future

v0.6.4

  • No changes really ¯\_(ツ)_/¯

v0.6.3

  • Shorter execution time of perform method of Correlation class
  • Shorter execution time of getVolume method of AudioHandler class
  • Slightly shorter execution time of getWeightedVolume method of AudioHandler class
  • FTDFloat32(buflen: uint) method of AudioSetup class now takes this.buflen by default
  • perform method of Correlation class now takes additional argument defaultCorrelationSampleStep that defaults to 1 (for smaller buffers < 8192) or 2 (for larger buffers >= 8192) to minimize latency. Larger buffers can still work the same way as smaller ones by explicitly passing value 1 as second argument to the method.

v0.6.2

  • Added distance class member to FrequencyMath to limit recalculation of this value in other class methods
  • Removed non static getDistanceFromNote method from FrequencyMath as "distance" is now a class member
  • Renamed getVolume method of AudioHandler class to getWeightedVolume.
  • Added getVolume method to AudioHandler class that counts average of ByteFrequencyData stored in Analyser node and casts it into a double in <0, 1) range
  • getWeightedVolume returns Number instead of string

Package Sidebar

Install

npm i audio-works

Weekly Downloads

1

Version

0.6.8

License

ISC

Unpacked Size

132 kB

Total Files

24

Last publish

Collaborators

  • dawpar5