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

scratch-audioengine

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scratch-audioengine - npm Package Compare versions

Comparing version 0.1.0-prerelease.1479334367 to 0.1.0-prerelease.1479583259

2

package.json
{
"name": "scratch-audioengine",
"version": "0.1.0-prerelease.1479334367",
"version": "0.1.0-prerelease.1479583259",
"description": "audio engine for scratch 3.0",

@@ -5,0 +5,0 @@ "main": "dist.js",

@@ -8,2 +8,4 @@ /*

to do: I think this will ultimately need to run in a web worker
*/

@@ -15,67 +17,77 @@

function ADPCMSoundLoader (url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
function ADPCMSoundLoader () {
}
request.onload = function () {
var audioData = request.response;
var stream = new ArrayBufferStream(audioData);
ADPCMSoundLoader.prototype.load = function (url) {
var riffStr = stream.readUint8String(4);
if (riffStr != 'RIFF') {
log.warn('incorrect adpcm wav header');
}
return new Promise(function (resolve, reject) {
var lengthInHeader = stream.readInt32();
if ((lengthInHeader + 8) != audioData.byteLength) {
log.warn('adpcm wav length in header: ' + length + 'is incorrect');
}
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
var wavStr = stream.readUint8String(4);
if (wavStr != 'WAVE') {
log.warn('incorrect adpcm wav header');
}
request.onload = function () {
var audioData = request.response;
var stream = new ArrayBufferStream(audioData);
var formatChunk = this.extractChunk('fmt ', stream);
this.encoding = formatChunk.readUint16();
this.channels = formatChunk.readUint16();
this.samplesPerSecond = formatChunk.readUint32();
this.bytesPerSecond = formatChunk.readUint32();
this.blockAlignment = formatChunk.readUint16();
this.bitsPerSample = formatChunk.readUint16();
formatChunk.position += 2; // skip extra header byte count
this.samplesPerBlock = formatChunk.readUint16();
this.adpcmBlockSize = ((this.samplesPerBlock - 1) / 2) + 4; // block size in bytes
var riffStr = stream.readUint8String(4);
if (riffStr != 'RIFF') {
log.warn('incorrect adpcm wav header');
reject();
}
var samples = this.imaDecompress(this.extractChunk('data', stream), this.adpcmBlockSize);
var buffer = Tone.context.createBuffer(1, samples.length, this.samplesPerSecond);
var lengthInHeader = stream.readInt32();
if ((lengthInHeader + 8) != audioData.byteLength) {
log.warn('adpcm wav length in header: ' + lengthInHeader + ' is incorrect');
}
// todo: optimize this?
for (var i=0; i<samples.length; i++) {
buffer.getChannelData(0)[i] = samples[i] / 32768;
}
var wavStr = stream.readUint8String(4);
if (wavStr != 'WAVE') {
log.warn('incorrect adpcm wav header');
reject();
}
var source = Tone.context.createBufferSource();
source.buffer = buffer;
source.connect(Tone.Master);
source.start();
var formatChunk = this.extractChunk('fmt ', stream);
this.encoding = formatChunk.readUint16();
this.channels = formatChunk.readUint16();
this.samplesPerSecond = formatChunk.readUint32();
this.bytesPerSecond = formatChunk.readUint32();
this.blockAlignment = formatChunk.readUint16();
this.bitsPerSample = formatChunk.readUint16();
formatChunk.position += 2; // skip extra header byte count
this.samplesPerBlock = formatChunk.readUint16();
this.adpcmBlockSize = ((this.samplesPerBlock - 1) / 2) + 4; // block size in bytes
var samples = this.imaDecompress(this.extractChunk('data', stream), this.adpcmBlockSize);
}.bind(this);
request.send();
// this line is the only place Tone is used here, should be possible to remove
var buffer = Tone.context.createBuffer(1, samples.length, this.samplesPerSecond);
this.stepTable = [
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487,
12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767];
// todo: optimize this? e.g. replace the divide by storing 1/32768 and multiply?
for (var i=0; i<samples.length; i++) {
buffer.getChannelData(0)[i] = samples[i] / 32768;
}
this.indexTable = [
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8];
}
resolve(buffer);
}.bind(this);
request.send();
}.bind(this));
};
ADPCMSoundLoader.prototype.stepTable = [
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487,
12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767];
ADPCMSoundLoader.prototype.indexTable = [
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8];
ADPCMSoundLoader.prototype.extractChunk = function (chunkType, stream) {

@@ -82,0 +94,0 @@ stream.position = 12;

@@ -23,2 +23,15 @@ var log = require('./log');

this.wobble = new Tone.Effect();
var wobbleLFO = new Tone.LFO(10, 0, 1).start();
var wobbleGain = new Tone.Gain();
wobbleLFO.connect(wobbleGain.gain);
this.wobble.effectSend.chain(wobbleGain, this.wobble.effectReturn);
// telephone effect - simulating the 'tinny' sound coming over a phone line
// basically, a lowpass filter and a highpass filter
this.telephone = new Tone.Effect();
var telephoneLP = new Tone.Filter(1200, 'lowpass', -24);
var telephoneHP = new Tone.Filter(800, 'highpass', -24);
this.telephone.effectSend.chain(telephoneLP, telephoneHP, this.telephone.effectReturn);
// the effects are chained to an effects node for this clone, then to the master output

@@ -28,3 +41,6 @@ // so audio is sent from each player or instrument, through the effects in order, then out

this.effectsNode = new Tone.Gain();
this.effectsNode.chain(this.vocoder, this.distortion, this.delay, this.panner, this.reverb, Tone.Master);
this.effectsNode.chain(
// this.vocoder,
this.distortion, this.delay, this.telephone,
this.wobble, this.panner, this.reverb, Tone.Master);

@@ -36,3 +52,4 @@ // reset effects to their default parameters

this.soundPlayers = this.loadSounds(sounds);
this.soundPlayers = [];
this.loadSounds(sounds);
// Tone.Buffer.on('load', this._soundsLoaded.bind(this));

@@ -69,34 +86,39 @@

AudioEngine.prototype.loadSounds = function (sounds) {
var soundPlayers = [];
for (var i=0; i<sounds.length; i++) {
this.soundPlayers = [];
var buffer;
// create a set of empty sound player objects
// the sound buffers will be added asynchronously as they load
for (var i=0; i<sounds.length; i++){
var player = {};
player.buffer = null;
player.bufferSource = null;
this.soundPlayers[i] = player;
}
if (sounds[i].format == 'adpcm') {
// load the sounds- most sounds decode natively, but for adpcm sounds
// we use our own decoder
var storedContext = this;
for (var index=0; index<sounds.length; index++) {
if (sounds[index].format == 'adpcm') {
log.warn('attempting to load sound in adpcm format');
var loader = new ADPCMSoundLoader(sounds[i].fileUrl);
loader; // lint
// var audioBuffer = loader.getAudioBuffer();
// buffer = new Tone.Buffer(audioBuffer);
// create a closure to the sound index, to use when the
// docder completes and resolves the promise
(function () {
var storedIndex = index;
var loader = new ADPCMSoundLoader();
loader.load(sounds[storedIndex].fileUrl).then(function (audioBuffer) {
storedContext.soundPlayers[storedIndex].buffer = new Tone.Buffer(audioBuffer);
});
}());
} else {
buffer = new Tone.Buffer(sounds[i].fileUrl);
this.soundPlayers[index].buffer = new Tone.Buffer(sounds[index].fileUrl);
}
var player = {};
player.buffer = buffer;
player.bufferSource = null;
soundPlayers[i] = player;
}
return soundPlayers;
};
// AudioEngine.prototype._soundsLoaded = function() {
// console.log('all sounds loaded');
// }
AudioEngine.prototype.playSound = function (index) {
// if the soundplayer exists and its buffer has loaded
if (this.soundPlayers[index] && this.soundPlayers[index].buffer.loaded) {
if (this.soundPlayers[index].buffer && this.soundPlayers[index].buffer.loaded) {
// stop the sound if it's already playing

@@ -115,2 +137,4 @@ var b = this.soundPlayers[index].bufferSource;

return new Promise(function (resolve) {
// bufferSource.onended = resolve; // this works, but causes the block to display a
// blocklydropdowncontent that says 'BufferSource'
bufferSource.onended = function (){resolve();};

@@ -199,4 +223,4 @@ });

switch (effect) {
case 'ECHO':
this.delay.wet.value = (value / 100) / 2; // max 50% wet
case 'PITCH':
this._setPitchShift(value);
break;

@@ -206,11 +230,17 @@ case 'PAN':

break;
case 'ECHO':
this.delay.wet.value = (value / 100) / 2; // max 50% wet
break;
case 'REVERB':
this.reverb.wet.value = value / 100;
break;
case 'PITCH':
this._setPitchShift(value);
break;
case 'FUZZ' :
this.distortion.wet.value = value / 100;
break;
case 'TELEPHONE' :
this.telephone.wet.value = value / 100;
break;
case 'WOBBLE' :
this.wobble.wet.value = value / 100;
break;
case 'ROBOTIC' :

@@ -224,5 +254,4 @@ this.vocoder.wet.value = value / 100;

switch (effect) {
case 'ECHO':
this.delay.wet.value += (value / 100) / 2; // max 50% wet
this.delay.wet.value = this._clamp(this.delay.wet.value, 0, 0.5);
case 'PITCH':
this._setPitchShift(this.pitchEffectValue + Number(value));
break;

@@ -233,2 +262,6 @@ case 'PAN':

break;
case 'ECHO':
this.delay.wet.value += (value / 100) / 2; // max 50% wet
this.delay.wet.value = this._clamp(this.delay.wet.value, 0, 0.5);
break;
case 'REVERB':

@@ -238,5 +271,2 @@ this.reverb.wet.value += value / 100;

break;
case 'PITCH':
this._setPitchShift(this.pitchEffectValue + Number(value));
break;
case 'FUZZ' :

@@ -246,2 +276,10 @@ this.distortion.wet.value += value / 100;

break;
case 'TELEPHONE' :
this.telephone.wet.value += value / 100;
this.telephone.wet.value = this._clamp(this.telephone.wet.value, 0, 1);
break;
case 'WOBBLE' :
this.wobble.wet.value += value / 100;
this.wobble.wet.value = this._clamp(this.wobble.wet.value, 0, 1);
break;
case 'ROBOTIC' :

@@ -257,16 +295,21 @@ this.vocoder.wet.value += value / 100;

this.pitchEffectValue = value;
var freq = this._getPitchRatio() * Tone.Frequency('C3').eval();
this.vocoder.setCarrierOscFrequency(freq);
if (!this.soundPlayers) {
return;
}
var ratio = this._getPitchRatio();
this._setPlaybackRateForAllSoundPlayers(ratio);
var ratio = this._getPitchRatio();
};
AudioEngine.prototype._setPlaybackRateForAllSoundPlayers = function (rate) {
for (var i=0; i<this.soundPlayers.length; i++) {
var s = this.soundPlayers[i].bufferSource;
if (s && s.playbackRate) {
s.playbackRate.value = ratio;
s.playbackRate.value = rate;
}
}
var freq = this._getPitchRatio() * Tone.Frequency('C3').eval();
this.vocoder.setCarrierOscFrequency(freq);
};

@@ -292,3 +335,2 @@

this.delay.wet.value = 0;
this._setPitchShift(0);
this.panner.pan.value = 0;

@@ -298,2 +340,5 @@ this.reverb.wet.value = 0;

this.vocoder.wet.value = 0;
this.wobble.wet.value = 0;
this.telephone.wet.value = 0;
this._setPitchShift(0);

@@ -300,0 +345,0 @@ this.effectsNode.gain.value = 1;

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

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