mirror of
https://github.com/scratchfoundation/scratch-audio.git
synced 2025-06-29 13:20:23 -04:00
initial commit
This commit is contained in:
commit
b0cb3950fa
8 changed files with 268 additions and 0 deletions
11
.editorconfig
Normal file
11
.editorconfig
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{js,html}]
|
||||||
|
indent_style = space
|
2
.eslintignore
Normal file
2
.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/*
|
||||||
|
dist.js
|
22
.eslintrc
Normal file
22
.eslintrc
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"rules": {
|
||||||
|
"curly": [2, "multi-line"],
|
||||||
|
"eol-last": [2],
|
||||||
|
"indent": [2, 4],
|
||||||
|
"linebreak-style": [2, "unix"],
|
||||||
|
"max-len": [2, 120, 4],
|
||||||
|
"no-trailing-spaces": [2, { "skipBlankLines": true }],
|
||||||
|
"no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_"}],
|
||||||
|
"quotes": [2, "single"],
|
||||||
|
"semi": [2, "always"],
|
||||||
|
"space-before-function-paren": [2, "always"],
|
||||||
|
"strict": [2, "never"]
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": ["eslint:recommended"]
|
||||||
|
}
|
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Mac OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# NPM
|
||||||
|
/node_modules
|
||||||
|
npm-*
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
/.nyc_output
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
/dist.js
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- '4.2'
|
||||||
|
- 'stable'
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
32
package.json
Normal file
32
package.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "scratch-audioengine",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "audio engine for scratch 3.0",
|
||||||
|
"main": "dist.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "npm run lint && npm run build",
|
||||||
|
"build": "webpack --bail",
|
||||||
|
"watch": "webpack --watch",
|
||||||
|
"lint": "eslint ."
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/LLK/scratch-audioengine.git"
|
||||||
|
},
|
||||||
|
"author": "Massachusetts Institute of Technology",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/LLK/scratch-audioengine/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/LLK/scratch-audioengine#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.17.0",
|
||||||
|
"babel-eslint": "^7.0.0",
|
||||||
|
"babel-loader": "^6.2.5",
|
||||||
|
"babel-preset-es2015": "^6.16.0",
|
||||||
|
"eslint": "^3.7.1",
|
||||||
|
"soundfont-player": "^0.10.5",
|
||||||
|
"tone": "^0.8.0",
|
||||||
|
"webpack": "^1.13.2"
|
||||||
|
}
|
||||||
|
}
|
159
src/index.js
Normal file
159
src/index.js
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
var Tone = require('tone');
|
||||||
|
var Soundfont = require('soundfont-player');
|
||||||
|
|
||||||
|
function AudioEngine () {
|
||||||
|
|
||||||
|
// tone setup
|
||||||
|
|
||||||
|
this.tone = new Tone();
|
||||||
|
|
||||||
|
// effects setup
|
||||||
|
|
||||||
|
this.delay = new Tone.FeedbackDelay(0.25, 0.5);
|
||||||
|
this.panner = new Tone.Panner();
|
||||||
|
this.reverb = new Tone.Freeverb();
|
||||||
|
|
||||||
|
this.clearEffects();
|
||||||
|
|
||||||
|
Tone.Master.chain(this.delay, this.panner, this.reverb);
|
||||||
|
|
||||||
|
// drum sounds
|
||||||
|
|
||||||
|
// var drumFileNames = ['high_conga', 'small_cowbell',
|
||||||
|
// 'snare_drum', 'splash cymbal'];
|
||||||
|
// this.drumSamplers = this._loadSoundFiles(drumFileNames);
|
||||||
|
|
||||||
|
// sound urls - map each url to its tone.sampler
|
||||||
|
this.soundSamplers = [];
|
||||||
|
|
||||||
|
// soundfont setup
|
||||||
|
|
||||||
|
// instrument names used by Musyng Kite soundfont, in order to
|
||||||
|
// match scratch instruments
|
||||||
|
this.instrumentNames = ['acoustic_grand_piano', 'electric_piano_1',
|
||||||
|
'drawbar_organ', 'acoustic_guitar_nylon', 'electric_guitar_clean',
|
||||||
|
'acoustic_bass', 'pizzicato_strings', 'cello', 'trombone', 'clarinet'];
|
||||||
|
|
||||||
|
Soundfont.instrument(Tone.context, this.instrumentNames[0]).then(
|
||||||
|
function (inst) {
|
||||||
|
this.instrument = inst;
|
||||||
|
this.instrument.connect(Tone.Master);
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioEngine.prototype.playSound = function (soundNum) {
|
||||||
|
this.soundSamplers[soundNum].triggerAttack();
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.playSoundFromUrl = function (url) {
|
||||||
|
if (url) {
|
||||||
|
// if we've loaded it already, play it
|
||||||
|
if (this.soundSamplers[url]) {
|
||||||
|
// this.soundSamplers[url].triggerAttack();
|
||||||
|
this.soundSamplers[url].player.start();
|
||||||
|
} else {
|
||||||
|
// else load, play, and store it
|
||||||
|
// this results in a delay the first time you play the sound
|
||||||
|
var sampler = new Tone.Sampler(url, function () {
|
||||||
|
sampler.triggerAttack();
|
||||||
|
this.soundSamplers[url] = sampler;
|
||||||
|
}.bind(this)).toMaster();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.getSoundDuration = function (url) {
|
||||||
|
return this.soundSamplers[url].player.buffer.duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.playNoteForBeats = function (note, beats) {
|
||||||
|
this.instrument.play(
|
||||||
|
note, Tone.context.currentTime, {duration : Number(beats)}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.playDrumForBeats = function (drumNum) {
|
||||||
|
this.drumSamplers[drumNum].triggerAttack();
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.stopAllSounds = function () {
|
||||||
|
// stop drum notes
|
||||||
|
// for (var i = 0; i<this.drumSamplers.length; i++) {
|
||||||
|
// this.drumSamplers[i].triggerRelease();
|
||||||
|
// }
|
||||||
|
// stop sounds triggered with playSound (indexed by their urls)
|
||||||
|
for (var key in this.soundSamplers) {
|
||||||
|
this.soundSamplers[key].triggerRelease();
|
||||||
|
}
|
||||||
|
// stop soundfont notes
|
||||||
|
this.instrument.stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.setEffect = function (effect, value) {
|
||||||
|
switch (effect) {
|
||||||
|
case 'ECHO':
|
||||||
|
this.delay.wet.value = (value / 100) / 2; // max 50% wet
|
||||||
|
break;
|
||||||
|
case 'PAN':
|
||||||
|
this.panner.pan.value = value / 100;
|
||||||
|
break;
|
||||||
|
case 'REVERB':
|
||||||
|
this.reverb.wet.value = value / 100;
|
||||||
|
break;
|
||||||
|
case 'PITCH':
|
||||||
|
this._setPitchShift(value / 20);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.changeEffect = function (effect, value) {
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
case 'PAN':
|
||||||
|
this.panner.pan.value += value / 100;
|
||||||
|
this.panner.pan.value = this._clamp(this.panner.pan.value, -1, 1);
|
||||||
|
break;
|
||||||
|
case 'REVERB':
|
||||||
|
this.reverb.wet.value += value / 100;
|
||||||
|
this.reverb.wet.value = this._clamp(this.reverb.wet.value, 0, 1);
|
||||||
|
break;
|
||||||
|
case 'PITCH':
|
||||||
|
// this.pitchShift.pitch += value / 20;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype._setPitchShift = function (value) {
|
||||||
|
for (var i in this.soundSamplers) {
|
||||||
|
this.soundSamplers[i].player.playbackRate = 1 + value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype.clearEffects = function () {
|
||||||
|
this.delay.wet.value = 0;
|
||||||
|
this._setPitchShift(0);
|
||||||
|
this.panner.pan.value = 0;
|
||||||
|
this.reverb.wet.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// AudioEngine.prototype.loadSoundFromUrl = function(url) {
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
AudioEngine.prototype.loadSounds = function (sounds) {
|
||||||
|
for (var sound in sounds) {
|
||||||
|
var sampler = new Tone.Sampler(sound.fileUrl).toMaster();
|
||||||
|
this.soundSamplers[sound.fileUrl] = sampler;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioEngine.prototype._clamp = function (input, min, max) {
|
||||||
|
return Math.min(Math.max(input, min), max);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = AudioEngine;
|
||||||
|
|
23
webpack.config.js
Normal file
23
webpack.config.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
'dist': './src/index.js'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: __dirname,
|
||||||
|
library: 'AudioEngine',
|
||||||
|
libraryTarget: 'commonjs2',
|
||||||
|
filename: '[name].js'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
query: {
|
||||||
|
presets: ['es2015']
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue