Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

scratch-audio

Package Overview
Dependencies
Maintainers
1
Versions
432
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scratch-audio - npm Package Compare versions

Comparing version 0.1.0-prerelease.1497907229 to 0.1.0-prerelease.1498238771

3

package.json
{
"name": "scratch-audio",
"version": "0.1.0-prerelease.1497907229",
"version": "0.1.0-prerelease.1498238771",
"description": "audio engine for scratch 3.0",

@@ -33,3 +33,2 @@ "main": "dist.js",

"soundfont-player": "0.10.5",
"tone": "0.9.0",
"travis-after-all": "^1.4.4",

@@ -36,0 +35,0 @@ "webpack": "2.4.0"

const ArrayBufferStream = require('./ArrayBufferStream');
const Tone = require('tone');
const log = require('./log');

@@ -14,2 +13,9 @@

/**
* @param {AudioContext} audioContext - a webAudio context
* @constructor
*/
constructor (audioContext) {
this.audioContext = audioContext;
}
/**
* Data used by the decompression algorithm

@@ -44,3 +50,3 @@ * @type {Array}

* @param {ArrayBuffer} audioData - containing ADPCM encoded wav audio
* @return {Tone.Buffer} the decoded audio buffer
* @return {AudioBuffer} the decoded audio buffer
*/

@@ -82,4 +88,3 @@ decode (audioData) {

// @todo this line is the only place Tone is used here, should be possible to remove
const buffer = Tone.context.createBuffer(1, samples.length, this.samplesPerSecond);
const buffer = this.audioContext.createBuffer(1, samples.length, this.samplesPerSecond);

@@ -86,0 +91,0 @@ // @todo optimize this? e.g. replace the divide by storing 1/32768 and multiply?

const SoundPlayer = require('./SoundPlayer');
const Tone = require('tone');

@@ -7,7 +6,7 @@ class DrumPlayer {

* A prototype for the drum sound functionality that can load drum sounds, play, and stop them.
* @param {Tone.Gain} outputNode - a webAudio node that the drum sounds will send their output to
* @param {AudioContext} audioContext - a webAudio context
* @constructor
*/
constructor (outputNode) {
this.outputNode = outputNode;
constructor (audioContext) {
this.audioContext = audioContext;

@@ -39,5 +38,17 @@ const baseUrl = 'https://raw.githubusercontent.com/LLK/scratch-audio/develop/sound-files/drums/';

for (let i = 0; i < fileNames.length; i++) {
const url = `${baseUrl + fileNames[i]}_22k.wav`;
this.drumSounds[i] = new SoundPlayer(this.outputNode);
this.drumSounds[i].setBuffer(new Tone.Buffer(url));
this.drumSounds[i] = new SoundPlayer(this.audioContext);
// download and decode the drum sounds
// @todo: use scratch-storage to manage these sound files
const url = `${baseUrl}${fileNames[i]}_22k.wav`;
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = () => {
const audioData = request.response;
this.audioContext.decodeAudioData(audioData).then(buffer => {
this.drumSounds[i].setBuffer(buffer);
});
};
request.send();
}

@@ -51,6 +62,6 @@ }

* @param {number} drum - the drum number to play (0-indexed)
* @param {Tone.Gain} outputNode - a node to send the output to
* @param {AudioNode} outputNode - a node to send the output to
*/
play (drum, outputNode) {
this.drumSounds[drum].outputNode = outputNode;
this.drumSounds[drum].connect(outputNode);
this.drumSounds[drum].start();

@@ -57,0 +68,0 @@ }

@@ -1,3 +0,1 @@

const Tone = require('tone');
/**

@@ -9,8 +7,11 @@ * A pan effect, which moves the sound to the left or right between the speakers

*/
class PanEffect extends Tone.Effect {
constructor () {
super();
class PanEffect {
/**
* @param {AudioContext} audioContext - a webAudio context
* @constructor
*/
constructor (audioContext) {
this.audioContext = audioContext;
this.panner = this.audioContext.createStereoPanner();
this.value = 0;
this.panner = new Tone.Panner();
this.effectSend.chain(this.panner, this.effectReturn);
}

@@ -27,2 +28,6 @@

connect (node) {
this.panner.connect(node);
}
/**

@@ -29,0 +34,0 @@ * Change the effect value

@@ -1,3 +0,1 @@

const Tone = require('tone');
/**

@@ -24,3 +22,2 @@ * A pitch change effect, which changes the playback rate of the sound in order

this.ratio = 1; // the playback rate ratio
this.tone = new Tone();
}

@@ -56,3 +53,5 @@

getRatio (val) {
return this.tone.intervalToFrequencyRatio(val / 10);
const interval = val / 10;
// Convert the musical interval in semitones to a frequency ratio
return Math.pow(2, (interval / 12));
}

@@ -59,0 +58,0 @@

const log = require('./log');
const Tone = require('tone');

@@ -28,11 +27,11 @@ const PitchEffect = require('./effects/PitchEffect');

// effects setup
// Create the audio effects
this.pitchEffect = new PitchEffect();
this.panEffect = new PanEffect();
this.panEffect = new PanEffect(this.audioEngine.audioContext);
// the effects are chained to an effects node for this player, then to the main audio engine
// audio is sent from each soundplayer, through the effects in order, then to the global effects
// note that the pitch effect works differently - it sets the playback rate for each soundplayer
this.effectsNode = new Tone.Gain();
this.effectsNode.chain(this.panEffect, this.audioEngine.input);
// Chain the audio effects together
// effectsNode -> panEffect -> audioEngine.input
this.effectsNode = this.audioEngine.audioContext.createGain();
this.effectsNode.connect(this.panEffect.panner);
this.panEffect.connect(this.audioEngine.input);

@@ -63,3 +62,3 @@ // reset effects to their default parameters

// create a new soundplayer to play the sound
const player = new SoundPlayer();
const player = new SoundPlayer(this.audioEngine.audioContext);
player.setBuffer(this.audioEngine.audioBuffers[md5]);

@@ -155,5 +154,8 @@ player.connect(this.effectsNode);

constructor () {
this.input = new Tone.Gain();
this.input.connect(Tone.Master);
const AudioContext = window.AudioContext || window.webkitAudioContext;
this.audioContext = new AudioContext();
this.input = this.audioContext.createGain();
this.input.connect(this.audioContext.destination);
// global tempo in bpm (beats per minute)

@@ -163,7 +165,8 @@ this.currentTempo = 60;

// instrument player for play note blocks
this.instrumentPlayer = new InstrumentPlayer(this.input);
this.instrumentPlayer = new InstrumentPlayer(this.audioContext);
this.instrumentPlayer.outputNode = this.input;
this.numInstruments = this.instrumentPlayer.instrumentNames.length;
// drum player for play drum blocks
this.drumPlayer = new DrumPlayer(this.input);
this.drumPlayer = new DrumPlayer(this.audioContext);
this.numDrums = this.drumPlayer.drumSounds.length;

@@ -176,3 +179,2 @@

this.mic = null;
this.micMeter = null;
}

@@ -205,10 +207,10 @@

// Make a copy of the buffer because decoding detaches the original buffer
var bufferCopy = sound.data.buffer.slice(0);
const bufferCopy = sound.data.buffer.slice(0);
switch (sound.format) {
case '':
loaderPromise = Tone.context.decodeAudioData(bufferCopy);
loaderPromise = this.audioContext.decodeAudioData(bufferCopy);
break;
case 'adpcm':
loaderPromise = (new ADPCMSoundDecoder()).decode(bufferCopy);
loaderPromise = (new ADPCMSoundDecoder(this.audioContext)).decode(bufferCopy);
break;

@@ -222,3 +224,3 @@ default:

decodedAudio => {
storedContext.audioBuffers[sound.md5] = new Tone.Buffer(decodedAudio);
storedContext.audioBuffers[sound.md5] = decodedAudio;
},

@@ -296,16 +298,47 @@ error => {

* Sound is measured in RMS and smoothed.
* Some code adapted from Tone.js: https://github.com/Tonejs/Tone.js
* @return {number} loudness scaled 0 to 100
*/
getLoudness () {
if (!this.mic) {
this.mic = new Tone.UserMedia();
this.micMeter = new Tone.Meter('level', 0.5);
this.mic.open();
this.mic.connect(this.micMeter);
// The microphone has not been set up, so try to connect to it
if (!this.mic && !this.connectingToMic) {
this.connectingToMic = true; // prevent multiple connection attempts
navigator.mediaDevices.getUserMedia({audio: true}).then(stream => {
this.mic = this.audioContext.createMediaStreamSource(stream);
this.analyser = this.audioContext.createAnalyser();
this.mic.connect(this.analyser);
this.micDataArray = new Float32Array(this.analyser.fftSize);
})
.catch(err => {
log.warn(err);
});
}
if (this.mic && this.mic.state === 'started') {
return this.micMeter.value * 100;
// If the microphone is set up and active, measure the loudness
if (this.mic && this.mic.mediaStream.active) {
this.analyser.getFloatTimeDomainData(this.micDataArray);
let sum = 0;
// compute the RMS of the sound
for (let i = 0; i < this.micDataArray.length; i++){
sum += Math.pow(this.micDataArray[i], 2);
}
let rms = Math.sqrt(sum / this.micDataArray.length);
// smooth the value, if it is descending
if (this._lastValue) {
rms = Math.max(rms, this._lastValue * 0.6);
}
this._lastValue = rms;
// Scale the measurement so it's more sensitive to quieter sounds
rms *= 1.63;
rms = Math.sqrt(rms);
// Scale it up to 0-100 and round
rms = Math.round(rms * 100);
// Prevent it from going above 100
rms = Math.min(rms, 100);
return rms;
}
// if there is no microphone input, return -1
return -1;
}

@@ -312,0 +345,0 @@

@@ -1,2 +0,1 @@

const Tone = require('tone');
const Soundfont = require('soundfont-player');

@@ -13,7 +12,8 @@

* duration, or run it through the sprite-specific audio effects.
* @param {Tone.Gain} outputNode - a webAudio node that the instrument will send its output to
* @param {AudioContext} audioContext - a webAudio context
* @constructor
*/
constructor (outputNode) {
this.outputNode = outputNode;
constructor (audioContext) {
this.audioContext = audioContext;
this.outputNode = null;

@@ -46,3 +46,3 @@ // Instrument names used by Musyng Kite soundfont, in order to

this.instruments[instrumentNum].play(
note, Tone.context.currentTime, {
note, this.audioContext.currentTime, {
duration: sec,

@@ -64,3 +64,3 @@ gain: gain

}
return Soundfont.instrument(Tone.context, this.instrumentNames[instrumentNum])
return Soundfont.instrument(this.audioContext, this.instrumentNames[instrumentNum])
.then(inst => {

@@ -67,0 +67,0 @@ inst.connect(this.outputNode);

@@ -1,2 +0,1 @@

const Tone = require('tone');
const log = require('./log');

@@ -8,5 +7,10 @@

class SoundPlayer {
constructor () {
/**
* @param {AudioContext} audioContext - a webAudio context
* @constructor
*/
constructor (audioContext) {
this.audioContext = audioContext;
this.outputNode = null;
this.buffer = new Tone.Buffer();
this.buffer = null;
this.bufferSource = null;

@@ -19,3 +23,3 @@ this.playbackRate = 1;

* Connect the SoundPlayer to an output node
* @param {Tone.Gain} node - an output node to connect to
* @param {GainNode} node - an output node to connect to
*/

@@ -28,3 +32,3 @@ connect (node) {

* Set an audio buffer
* @param {Tone.Buffer} buffer Buffer to set
* @param {AudioBuffer} buffer - Buffer to set
*/

@@ -61,3 +65,3 @@ setBuffer (buffer) {

start () {
if (!this.buffer || !this.buffer.loaded) {
if (!this.buffer) {
log.warn('tried to play a sound that was not loaded yet');

@@ -67,4 +71,4 @@ return;

this.bufferSource = Tone.context.createBufferSource();
this.bufferSource.buffer = this.buffer.get();
this.bufferSource = this.audioContext.createBufferSource();
this.bufferSource.buffer = this.buffer;
this.bufferSource.playbackRate.value = this.playbackRate;

@@ -83,8 +87,7 @@ this.bufferSource.connect(this.outputNode);

finished () {
const storedContext = this;
return new Promise(resolve => {
storedContext.bufferSource.onended = function () {
this.bufferSource.onended = () => {
this.isPlaying = false;
resolve();
}.bind(storedContext);
};
});

@@ -91,0 +94,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

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