diff --git a/static/audio/README b/static/audio/Salamander_README similarity index 100% rename from static/audio/README rename to static/audio/Salamander_README diff --git a/static/audio/string_ensemble/A0.mp3 b/static/audio/string_ensemble/A0.mp3 new file mode 100755 index 0000000..d5af57f Binary files /dev/null and b/static/audio/string_ensemble/A0.mp3 differ diff --git a/static/audio/string_ensemble/A1.mp3 b/static/audio/string_ensemble/A1.mp3 new file mode 100755 index 0000000..fc90521 Binary files /dev/null and b/static/audio/string_ensemble/A1.mp3 differ diff --git a/static/audio/string_ensemble/A2.mp3 b/static/audio/string_ensemble/A2.mp3 new file mode 100755 index 0000000..ac427e1 Binary files /dev/null and b/static/audio/string_ensemble/A2.mp3 differ diff --git a/static/audio/string_ensemble/A3.mp3 b/static/audio/string_ensemble/A3.mp3 new file mode 100755 index 0000000..7f25bd9 Binary files /dev/null and b/static/audio/string_ensemble/A3.mp3 differ diff --git a/static/audio/string_ensemble/A4.mp3 b/static/audio/string_ensemble/A4.mp3 new file mode 100755 index 0000000..59aaa51 Binary files /dev/null and b/static/audio/string_ensemble/A4.mp3 differ diff --git a/static/audio/string_ensemble/A5.mp3 b/static/audio/string_ensemble/A5.mp3 new file mode 100755 index 0000000..85f25e6 Binary files /dev/null and b/static/audio/string_ensemble/A5.mp3 differ diff --git a/static/audio/string_ensemble/A6.mp3 b/static/audio/string_ensemble/A6.mp3 new file mode 100755 index 0000000..2b2fdfd Binary files /dev/null and b/static/audio/string_ensemble/A6.mp3 differ diff --git a/static/audio/string_ensemble/A7.mp3 b/static/audio/string_ensemble/A7.mp3 new file mode 100755 index 0000000..8441c45 Binary files /dev/null and b/static/audio/string_ensemble/A7.mp3 differ diff --git a/static/audio/string_ensemble/C1.mp3 b/static/audio/string_ensemble/C1.mp3 new file mode 100755 index 0000000..bd3c092 Binary files /dev/null and b/static/audio/string_ensemble/C1.mp3 differ diff --git a/static/audio/string_ensemble/C2.mp3 b/static/audio/string_ensemble/C2.mp3 new file mode 100755 index 0000000..8ceaadc Binary files /dev/null and b/static/audio/string_ensemble/C2.mp3 differ diff --git a/static/audio/string_ensemble/C3.mp3 b/static/audio/string_ensemble/C3.mp3 new file mode 100755 index 0000000..70d5e3a Binary files /dev/null and b/static/audio/string_ensemble/C3.mp3 differ diff --git a/static/audio/string_ensemble/C4.mp3 b/static/audio/string_ensemble/C4.mp3 new file mode 100755 index 0000000..8ffd1f4 Binary files /dev/null and b/static/audio/string_ensemble/C4.mp3 differ diff --git a/static/audio/string_ensemble/C5.mp3 b/static/audio/string_ensemble/C5.mp3 new file mode 100755 index 0000000..489c5c1 Binary files /dev/null and b/static/audio/string_ensemble/C5.mp3 differ diff --git a/static/audio/string_ensemble/C6.mp3 b/static/audio/string_ensemble/C6.mp3 new file mode 100755 index 0000000..432836f Binary files /dev/null and b/static/audio/string_ensemble/C6.mp3 differ diff --git a/static/audio/string_ensemble/C7.mp3 b/static/audio/string_ensemble/C7.mp3 new file mode 100755 index 0000000..2d2da9b Binary files /dev/null and b/static/audio/string_ensemble/C7.mp3 differ diff --git a/static/audio/string_ensemble/C8.mp3 b/static/audio/string_ensemble/C8.mp3 new file mode 100755 index 0000000..8441c45 Binary files /dev/null and b/static/audio/string_ensemble/C8.mp3 differ diff --git a/static/audio/string_ensemble/Ds1.mp3 b/static/audio/string_ensemble/Ds1.mp3 new file mode 100755 index 0000000..00c06f4 Binary files /dev/null and b/static/audio/string_ensemble/Ds1.mp3 differ diff --git a/static/audio/string_ensemble/Ds2.mp3 b/static/audio/string_ensemble/Ds2.mp3 new file mode 100755 index 0000000..984d179 Binary files /dev/null and b/static/audio/string_ensemble/Ds2.mp3 differ diff --git a/static/audio/string_ensemble/Ds3.mp3 b/static/audio/string_ensemble/Ds3.mp3 new file mode 100755 index 0000000..5eebcad Binary files /dev/null and b/static/audio/string_ensemble/Ds3.mp3 differ diff --git a/static/audio/string_ensemble/Ds4.mp3 b/static/audio/string_ensemble/Ds4.mp3 new file mode 100755 index 0000000..af404d1 Binary files /dev/null and b/static/audio/string_ensemble/Ds4.mp3 differ diff --git a/static/audio/string_ensemble/Ds5.mp3 b/static/audio/string_ensemble/Ds5.mp3 new file mode 100755 index 0000000..79706fc Binary files /dev/null and b/static/audio/string_ensemble/Ds5.mp3 differ diff --git a/static/audio/string_ensemble/Ds6.mp3 b/static/audio/string_ensemble/Ds6.mp3 new file mode 100755 index 0000000..3643761 Binary files /dev/null and b/static/audio/string_ensemble/Ds6.mp3 differ diff --git a/static/audio/string_ensemble/Ds7.mp3 b/static/audio/string_ensemble/Ds7.mp3 new file mode 100755 index 0000000..8441c45 Binary files /dev/null and b/static/audio/string_ensemble/Ds7.mp3 differ diff --git a/static/audio/string_ensemble/Fs1.mp3 b/static/audio/string_ensemble/Fs1.mp3 new file mode 100755 index 0000000..5c36762 Binary files /dev/null and b/static/audio/string_ensemble/Fs1.mp3 differ diff --git a/static/audio/string_ensemble/Fs2.mp3 b/static/audio/string_ensemble/Fs2.mp3 new file mode 100755 index 0000000..19b479e Binary files /dev/null and b/static/audio/string_ensemble/Fs2.mp3 differ diff --git a/static/audio/string_ensemble/Fs3.mp3 b/static/audio/string_ensemble/Fs3.mp3 new file mode 100755 index 0000000..121b959 Binary files /dev/null and b/static/audio/string_ensemble/Fs3.mp3 differ diff --git a/static/audio/string_ensemble/Fs4.mp3 b/static/audio/string_ensemble/Fs4.mp3 new file mode 100755 index 0000000..11e0d00 Binary files /dev/null and b/static/audio/string_ensemble/Fs4.mp3 differ diff --git a/static/audio/string_ensemble/Fs5.mp3 b/static/audio/string_ensemble/Fs5.mp3 new file mode 100755 index 0000000..e66a59e Binary files /dev/null and b/static/audio/string_ensemble/Fs5.mp3 differ diff --git a/static/audio/string_ensemble/Fs6.mp3 b/static/audio/string_ensemble/Fs6.mp3 new file mode 100755 index 0000000..764bfa5 Binary files /dev/null and b/static/audio/string_ensemble/Fs6.mp3 differ diff --git a/static/audio/string_ensemble/Fs7.mp3 b/static/audio/string_ensemble/Fs7.mp3 new file mode 100755 index 0000000..8441c45 Binary files /dev/null and b/static/audio/string_ensemble/Fs7.mp3 differ diff --git a/static/audio/string_ensemble_README b/static/audio/string_ensemble_README new file mode 100644 index 0000000..6a41c46 --- /dev/null +++ b/static/audio/string_ensemble_README @@ -0,0 +1,5 @@ +- Fluid-Soundfont + - Generated from [FluidR3_GM.sf2](http://www.musescore.org/download/fluid-soundfont.tar.gz) (141 MB uncompressed) + - Released under [Creative Commons Attribution 3.0 license](http://creativecommons.org/licenses/by/3.0/us/) + - Instrument names as .json file [here](http://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/names.json) + - URL prefix to fetch files: http://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/ \ No newline at end of file diff --git a/static/src/sound/Sampler.js b/static/src/sound/Sampler.js new file mode 100644 index 0000000..ad107ea --- /dev/null +++ b/static/src/sound/Sampler.js @@ -0,0 +1,88 @@ +/** + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Frequency from 'Tone/type/Frequency' +import Buffers from 'Tone/core/Buffers' +import MultiPlayer from 'Tone/source/MultiPlayer' +import Tone from 'Tone/core/Tone' +import AudioBuffer from 'Tone/core/Buffer' + +class Sampler{ + constructor(baseUrl='', range=[21, 108]){ + + //all the notes of the piano sampled every 3rd note + const notes = [21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108] + + const lowerIndex = notes.findIndex((note) => note >= range[0]) + let upperIndex = notes.findIndex((note) => note >= range[1]) + upperIndex = upperIndex === -1 ? upperIndex = notes.length : upperIndex + 1 + + const slicedNotes = notes.slice(lowerIndex, upperIndex) + + this._urls = {} + slicedNotes.forEach(note => { + this._urls[note - 1] = baseUrl + Frequency(note, 'midi').toNote().replace('#', 's') + '.mp3' + this._urls[note] = baseUrl + Frequency(note, 'midi').toNote().replace('#', 's') + '.mp3' + this._urls[note + 1] = baseUrl + Frequency(note, 'midi').toNote().replace('#', 's') + '.mp3' + }) + this._player = null + + this._loaded = false + AudioBuffer.on('load', () => { + this._loaded = true + }) + } + + load(){ + return new Promise(done => { + this._player = new MultiPlayer(this._urls, done).toMaster() + this._player.fadeOut = 0.2 + }) + } + + set volume(vol){ + if (this._loaded){ + this._player.volume.value = vol + } + } + + keyDown(note, time){ + if (this._loaded){ + let pitch = this._midiToFrequencyPitch(note) + const duration = this._player.buffers.get(note).duration * 0.95 + this._player.start(note, time, 0, duration - this._player.fadeOut, pitch) + } + } + + keyUp(note, time){ + if (this._loaded){ + this._player.stop(note, time) + } + } + + _midiToFrequencyPitch(midi){ + let mod = midi % 3 + if (mod === 1){ + return 1 + } else if (mod === 2){ + return -1 + } else { + return 0 + } + } +} + +export {Sampler} \ No newline at end of file diff --git a/static/src/sound/Sound.js b/static/src/sound/Sound.js new file mode 100644 index 0000000..8716145 --- /dev/null +++ b/static/src/sound/Sound.js @@ -0,0 +1,62 @@ +/** + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Tone from 'Tone/core/Tone' +import PolySynth from 'Tone/instrument/PolySynth' +import Frequency from 'Tone/type/Frequency' +import MonoSynth from 'Tone/instrument/MonoSynth' +import {Sampler} from 'sound/Sampler' + +class Sound { + constructor(){ + + this._range = [24, 108] + + this._piano = new Sampler('audio/Salamander/', this._range) + + this._synth = new Sampler('audio/string_ensemble/', this._range) + + } + + load(){ + return Promise.all([this._piano.load(), this._synth.load()]) + } + + keyDown(note, time=Tone.now(), ai=false){ + + if (note >= this._range[0] && note <= this._range[1]){ + this._piano.keyDown(note, time) + if (ai){ + this._synth.volume = -8 + this._synth.keyDown(note, time) + } + } + + + } + + keyUp(note, time=Tone.now(), ai=false){ + if (note >= this._range[0] && note <= this._range[1]){ + time += 0.05 + this._piano.keyUp(note, time) + if (ai){ + this._synth.keyUp(note, time) + } + } + } +} + +export {Sound} \ No newline at end of file diff --git a/static/third_party/Piano/LICENSE.md b/static/third_party/Piano/LICENSE.md deleted file mode 100644 index c015913..0000000 --- a/static/third_party/Piano/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -[The MIT License](http://opensource.org/licenses/MIT) - -Copyright © 2016 Yotam Mann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/static/third_party/Piano/README.md b/static/third_party/Piano/README.md deleted file mode 100644 index 7067eeb..0000000 --- a/static/third_party/Piano/README.md +++ /dev/null @@ -1,3 +0,0 @@ -A [Multisampled](https://en.wikipedia.org/wiki/Sample-based_synthesis#Multisampling) Piano at 5 velocity levels across 88 keys (sampled every third note) of a Yamaha C5. The sounds are from [Salamander Grand Piano](https://archive.org/details/SalamanderGrandPianoV3). - -See [Main.js](https://github.com/tambien/Piano/blob/master/Main.js) for an example of how to use the API with either a MIDI file or MIDI keyboard. diff --git a/static/third_party/Piano/src/Harmonics.js b/static/third_party/Piano/src/Harmonics.js deleted file mode 100644 index e188fe8..0000000 --- a/static/third_party/Piano/src/Harmonics.js +++ /dev/null @@ -1,41 +0,0 @@ -import Salamander from './Salamander' -import PianoBase from './PianoBase' -import {noteToMidi, createSource, midiToFrequencyRatio} from './Util' -import Buffers from 'Tone/core/Buffers' - -// the harmonics notes that Salamander has -const harmonics = [21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87] - -export default class Harmonics extends PianoBase { - - constructor(range=[21, 108]){ - super() - - const lowerIndex = harmonics.findIndex((note) => note >= range[0]) - let upperIndex = harmonics.findIndex((note) => note >= range[1]) - upperIndex = upperIndex === -1 ? upperIndex = harmonics.length : upperIndex - - const notes = harmonics.slice(lowerIndex, upperIndex) - - this._buffers = {} - - for (let n of notes){ - this._buffers[n] = Salamander.getHarmonicsUrl(n) - } - } - - start(note, gain, time){ - let [midi, ratio] = midiToFrequencyRatio(note) - if (this._buffers.has(midi)){ - const source = createSource(this._buffers.get(midi)).connect(this.output) - source.playbackRate.value = ratio - source.start(time, 0, undefined, gain, 0) - } - } - - load(baseUrl){ - return new Promise((success, fail) => { - this._buffers = new Buffers(this._buffers, success, baseUrl) - }) - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Note.js b/static/third_party/Piano/src/Note.js deleted file mode 100644 index 16916ea..0000000 --- a/static/third_party/Piano/src/Note.js +++ /dev/null @@ -1,124 +0,0 @@ -import Tone from 'Tone/core/Tone' -import Salamander from './Salamander' -import PianoBase from './PianoBase' -import {noteToMidi, createSource, midiToFrequencyRatio} from './Util' -import Buffers from 'Tone/core/Buffers' - -/** - * Internal class - */ -class Note extends Tone{ - constructor(time, source, velocity, gain){ - super() - //round the velocity - this._velocity = velocity - this._startTime = time - - this.output = source - this.output.start(time, 0, undefined, gain, 0) - } - - stop(time){ - if (this.output.buffer){ - - // return the amplitude of the damper playback - let progress = (time - this._startTime) / this.output.buffer.duration - progress = (1 - progress) * this._velocity - // stop the buffer - this.output.stop(time, 0.2) - - return Math.pow(progress, 0.5) - } else { - return 0 - } - } -} - -/** - * Maps velocity depths to Salamander velocities - */ -const velocitiesMap = { - 1 : [8], - 2 : [6, 12], - 3 : [1, 8, 15], - 4 : [1, 5, 10, 15], - 5 : [1, 4, 8, 12, 16], - 6 : [1, 3, 7, 10, 13, 16], - 7 : [1, 3, 6, 9, 11, 13, 16], - 8 : [1, 3, 5, 7, 9, 11, 13, 15], - 9 : [1, 3, 5, 7, 9, 11, 13, 15, 16], - 10 : [1, 2, 3, 5, 7, 9, 11, 13, 15, 16], - 11 : [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16], - 12 : [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16], - 13 : [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 16], - 14 : [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15, 16], - 15 : [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16], - 16 : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], -} - -const notes = [21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108] - -/** - * Manages all of the hammered string sounds - */ -export default class Strings extends PianoBase { - - constructor(range=[21, 108], velocities=1){ - super() - - const lowerIndex = notes.findIndex((note) => note >= range[0]) - let upperIndex = notes.findIndex((note) => note >= range[1]) - upperIndex = upperIndex === -1 ? upperIndex = notes.length : upperIndex + 1 - - const slicedNotes = notes.slice(lowerIndex, upperIndex) - - this._buffers = velocitiesMap[velocities].slice() - - this._buffers.forEach((vel, i) => { - this._buffers[i] = {} - slicedNotes.forEach((note) => { - this._buffers[i][note] = Salamander.getNotesUrl(note, vel) - }) - }) - } - - _hasNote(note, velocity){ - return this._buffers.hasOwnProperty(velocity) && this._buffers[velocity].has(note) - } - - _getNote(note, velocity){ - return this._buffers[velocity].get(note) - } - - start(note, velocity, time){ - - let velPos = velocity * (this._buffers.length - 1) - let roundedVel = Math.round(velPos) - let diff = roundedVel - velPos - let gain = 1 - diff * 0.5 - - let [midi, ratio] = midiToFrequencyRatio(note) - - if (this._hasNote(midi, roundedVel)){ - let source = createSource(this._getNote(midi, roundedVel)) - source.playbackRate.value = ratio - - let retNote = new Note(time, source, velocity, gain).connect(this.output) - - return retNote - } else { - return null - } - } - - load(baseUrl){ - const promises = [] - this._buffers.forEach((obj, i) => { - let prom = new Promise((success) => { - this._buffers[i] = new Buffers(obj, success, baseUrl) - }) - promises.push(prom) - }) - return Promise.all(promises) - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Pedal.js b/static/third_party/Piano/src/Pedal.js deleted file mode 100644 index 90d3157..0000000 --- a/static/third_party/Piano/src/Pedal.js +++ /dev/null @@ -1,64 +0,0 @@ -import PianoBase from './PianoBase' -import Salamander from './Salamander' -import {createSource} from './Util' -import Buffers from 'Tone/core/Buffers' - -export default class Pedal extends PianoBase { - constructor(load=true){ - super() - - this._downTime = Infinity - - this._currentSound = null - - this._buffers = null - - this._loadPedalSounds = load - } - - load(baseUrl){ - if (this._loadPedalSounds){ - return new Promise((success) => { - this._buffers = new Buffers({ - up : 'pedalU1.mp3', - down : 'pedalD1.mp3' - }, success, baseUrl) - }) - } else { - return Promise.resolve() - } - } - - /** - * Squash the current playing sound - */ - _squash(time){ - if (this._currentSound){ - this._currentSound.stop(time, 0.1) - } - this._currentSound = null - } - - _playSample(time, dir){ - if (this._loadPedalSounds){ - this._currentSound = createSource(this._buffers.get(dir)) - this._currentSound.connect(this.output).start(time, 0, undefined, 0.2) - } - } - - down(time){ - this._squash(time) - this._downTime = time - this._playSample(time, 'down') - } - - up(time){ - this._squash(time) - this._downTime = Infinity - this._playSample(time, 'up') - } - - isDown(time){ - return time > this._downTime - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Piano.js b/static/third_party/Piano/src/Piano.js deleted file mode 100644 index e611c4d..0000000 --- a/static/third_party/Piano/src/Piano.js +++ /dev/null @@ -1,189 +0,0 @@ -import Gain from 'Tone/core/Gain' -import Tone from 'Tone/core/Tone' -import Frequency from 'Tone/type/Frequency' -import Pedal from './Pedal' -import Note from './Note' -import Harmonics from './Harmonics' -import Release from './Release' -import Salamander from './Salamander' - -/** - * @class Multisampled Grand Piano using [Salamander Piano Samples](https://archive.org/details/SalamanderGrandPianoV3) - * @extends {Tone} - */ -export default class Piano extends Tone{ - - constructor(range=[21, 108], velocities=1, release=true){ - - super(0, 1) - - this._loaded = false - - this._heldNotes = new Map() - - this._sustainedNotes = new Map() - - this._notes = new Note(range, velocities).connect(this.output) - - this._pedal = new Pedal(release).connect(this.output) - - if (release){ - this._harmonics = new Harmonics(range).connect(this.output) - - this._release = new Release(range).connect(this.output) - } - } - - /** - * Load all the samples - * @param {String} baseUrl The url for the Salamander base folder - * @return {Promise} - */ - load(url){ - const promises = [this._notes.load(url), this._pedal.load(url)] - if (this._harmonics){ - promises.push(this._harmonics.load(url)) - } - if (this._release){ - promises.push(this._release.load(url)) - } - return Promise.all(promises).then(() => { - this._loaded = true - }) - } - - /** - * Put the pedal down at the given time. Causes subsequent - * notes and currently held notes to sustain. - * @param {Time} time The time the pedal should go down - * @returns {Piano} this - */ - pedalDown(time){ - if (this._loaded){ - time = this.toSeconds(time) - if (!this._pedal.isDown(time)){ - this._pedal.down(time) - } - } - return this - } - - /** - * Put the pedal up. Dampens sustained notes - * @param {Time} time The time the pedal should go up - * @returns {Piano} this - */ - pedalUp(time){ - if (this._loaded){ - time = this.toSeconds(time) - if (this._pedal.isDown(time)){ - this._pedal.up(time) - // dampen each of the notes - this._sustainedNotes.forEach((notes) => { - notes.forEach((note) => { - note.stop(time) - }) - }) - this._sustainedNotes.clear() - } - } - return this - } - - /** - * Play a note. - * @param {String|Number} note The note to play - * @param {Number} velocity The velocity to play the note - * @param {Time} time The time of the event - * @return {Piano} this - */ - keyDown(note, velocity=0.8, time=Tone.now()){ - if (this._loaded){ - time = this.toSeconds(time) - - if (this.isString(note)){ - note = Math.round(Frequency(note).toMidi()) - } - - if (!this._heldNotes.has(note)){ - let key = this._notes.start(note, velocity, time) - if (key){ - this._heldNotes.set(note, key) - } - } - } - return this - } - - /** - * Release a held note. - * @param {String|Number} note The note to stop - * @param {Time} time The time of the event - * @return {Piano} this - */ - keyUp(note, time=Tone.now()){ - if (this._loaded){ - time = this.toSeconds(time) - - if (this.isString(note)){ - note = Math.round(Frequency(note).toMidi()) - } - - if (this._heldNotes.has(note)){ - - let key = this._heldNotes.get(note) - this._heldNotes.delete(note) - - if (this._release){ - this._release.start(note, time) - } - - if (this._pedal.isDown(time)){ - let notes = [] - if (this._sustainedNotes.has(note)){ - notes = this._sustainedNotes.get(note) - } - notes.push(key) - this._sustainedNotes.set(note, notes) - } else { - let dampenGain = key.stop(time) - if (this._harmonics){ - this._harmonics.start(note, dampenGain, time) - } - } - } - } - return this - } - - /** - * Set the volumes of each of the components - * @param {String} param - * @param {Decibels} vol - * @return {Piano} this - * @example - * //either as an string - * piano.setVolume('release', -10) - */ - setVolume(param, vol){ - switch(param){ - case 'note': - this._notes.volume = vol - break - case 'pedal': - this._pedal.volume = vol - break - case 'release': - if (this._release){ - this._release.volume = vol - } - break - case 'harmonics': - if (this._harmonics){ - this._harmonics.volume = vol - } - break - } - return this - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/PianoBase.js b/static/third_party/Piano/src/PianoBase.js deleted file mode 100644 index a6278a1..0000000 --- a/static/third_party/Piano/src/PianoBase.js +++ /dev/null @@ -1,16 +0,0 @@ -import Tone from 'Tone/core/Tone' -import Master from 'Tone/core/Master' - -export default class PianoBase extends Tone { - constructor(vol=0){ - super(0, 1) - - this.volume = vol - } - get volume(){ - return this.gainToDb(this.output.gain.value) - } - set volume(vol){ - this.output.gain.value = this.dbToGain(vol) - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Release.js b/static/third_party/Piano/src/Release.js deleted file mode 100644 index 93e4c21..0000000 --- a/static/third_party/Piano/src/Release.js +++ /dev/null @@ -1,29 +0,0 @@ -import Salamander from './Salamander' -import PianoBase from './PianoBase' -import {createSource} from './Util' -import Buffers from 'Tone/core/Buffers' - -export default class Release extends PianoBase { - - constructor(range){ - super() - - this._buffers = {} - for (let i = range[0]; i <= range[1]; i++){ - this._buffers[i] = Salamander.getReleasesUrl(i) - } - } - - load(baseUrl){ - return new Promise((success) => { - this._buffers = new Buffers(this._buffers, success, baseUrl) - }) - } - - start(note, time){ - if (this._buffers.has(note)){ - let source = createSource(this._buffers.get(note)).connect(this.output) - source.start(time, 0, undefined, 0.01, 0) - } - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Salamander.js b/static/third_party/Piano/src/Salamander.js deleted file mode 100644 index bf15a37..0000000 --- a/static/third_party/Piano/src/Salamander.js +++ /dev/null @@ -1,16 +0,0 @@ -import {noteToMidi, midiToNote} from './Util' - -export default { - - getReleasesUrl(midi){ - return `rel${midi - 20}.mp3` - }, - - getHarmonicsUrl(midi){ - return `harmL${encodeURIComponent(midiToNote(midi))}.mp3` - }, - - getNotesUrl(midi, vel){ - return `${encodeURIComponent(midiToNote(midi))}.mp3` - } -} \ No newline at end of file diff --git a/static/third_party/Piano/src/Util.js b/static/third_party/Piano/src/Util.js deleted file mode 100644 index 992a56a..0000000 --- a/static/third_party/Piano/src/Util.js +++ /dev/null @@ -1,28 +0,0 @@ -import Tone from 'Tone/core/Tone' -import Frequency from 'Tone/type/Frequency' -import BufferSource from 'Tone/source/BufferSource' - -function noteToMidi(note){ - return Frequency(note).toMidi() -} - -function midiToNote(midi){ - return Frequency(midi, 'midi').toNote().replace('#', 's') -} - -function midiToFrequencyRatio(midi){ - let mod = midi % 3 - if (mod === 1){ - return [midi - 1, Tone.prototype.intervalToFrequencyRatio(1)] - } else if (mod === 2){ - return [midi + 1, Tone.prototype.intervalToFrequencyRatio(-1)] - } else { - return [midi, 1] - } -} - -function createSource(buffer){ - return new BufferSource(buffer) -} - -export {midiToNote, noteToMidi, createSource, midiToFrequencyRatio} \ No newline at end of file