danigb / soundfont-player Goto Github PK
View Code? Open in Web Editor NEWQuick soundfont loader and player for browser
License: MIT License
Quick soundfont loader and player for browser
License: MIT License
Hi,
is it possible to use soundfontplayer linked sounds library in ToneJS and how?
Thank you
Hi,
This looks like a great library; congrats! Any plans to support looping (for sustain)? I know the SoundFont spec supports including loop points in instruments, although the files included with MIDI.js don't have this info unfortunately.
I think it would make a huge difference in the quality of current browser-based SoundFonts if this could be supported at some point, but I imagine it would be a great deal of work... anyways, if you're looking for some future work, having "endless" sustain would be a great feature, especially for instruments like organ. - Charlie
(I could use more documentation on how to use the player.on(event, callback) call. What are the acceptable values for "event", for instance?)
I'm trying to get a callback when a note is about to sound. When I use the player.on() method along with the player.schedule() method, I get all the start and started callbacks at once. The ended callbacks happen at the correct time, though.
As a test case, I created a new vue-cli app and replaced the Hello.vue file with this:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<button @click="play">Play</button>
</div>
</template>
<script>
import Soundfont from "soundfont-player";
export default {
name: 'hello',
mounted() {
console.log("loading piano...");
const self = this;
self.ac = new AudioContext();
Soundfont.instrument(self.ac, 'acoustic_grand_piano').then(function (piano) {
self.piano = piano;
self.piano.on('event', self.progress);
console.log("piano loaded");
});
},
data () {
return {
piano: null,
ac: null,
msg: 'soundfont player test'
}
},
methods: {
play: function(ev) {
console.log("play pushed");
//this.piano.play("C4");
this.piano.schedule(this.ac.currentTime, [
{ note: 60, time: 0.2 },
{ note: 64, time: 0.2 },
{ note: 68, time: 1.4 },
{ note: 72, time: 2.6 },
{ note: 76, time: 2.6 },
{ note: 78, time: 6.6 },
]);
},
progress: function(ev, time, obj, opts) {
console.log("progress", this.ac.currentTime, ev, time);
}
}
}
</script>
My console looks like this:
loading piano...
piano loaded
play pushed
progress 6.88 schedule 6.88
progress 6.88 start 7.08 60
progress 6.88 started 7.08 0
progress 6.88 start 7.08 64
progress 6.88 started 7.08 1
progress 6.88 start 8.28 68
progress 6.88 started 8.28 2
progress 6.88 start 9.48 72
progress 6.88 started 9.48 3
progress 6.88 start 9.48 76
progress 6.88 started 9.48 4
progress 6.88 start 13.48 78
progress 6.88 started 13.48 5
progress 10.112 ended 10.112 1
progress 10.112 ended 10.112 0
progress 11.296 ended 11.296 2
progress 12.512 ended 12.512 4
progress 12.512 ended 12.512 3
progress 16.512 ended 16.512 5
This first number is the time according to AudioContext and the second is the time the note should be scheduled.
I'd like to build a "bouncing ball" type application where I show something right when a note is started. Do I need to figure out the timing myself?
On your soundfont-player demo site, you're referencing
https://cdn.rawgit.com/gleitz/midi-js-soundfonts/master/FluidR3_GM/acoustic_grand_piano-ogg.js
which is 404. A currently valid location for the same file is here:
https://github.com/gleitz/midi-js-soundfonts/blob/gh-pages/FluidR3_GM/acoustic_grand_piano-ogg.js
I tried to try with VMPK virtual piano -> and had set Output connection to VMIDI 2
The soundfont-player example show "Loaded soundfont-player doesnt have parsing MIDI ability". What it mean?
https://github.com/danigb/soundfont-player/blob/master/examples/index.html
Does it support keys release?
soundfont-player
is missing TypeScript definitions
Currently the way to change the default url generation is by overriding a class method. While this is good for testing, it's not good for humans. Let's improve it.
Proposals:
new Soundfont(ctx, function(name) { return ... })
new Soundfont(ctx, { base: 'http://...', format: 'mp3' })
Any ideas?
Could you please provide a guide on how to convert a regular SoundFont file into a format supported by soundfont-player
? I can only see pre-generated JS soundfonts, but could not find scripts to perform the conversion for existing sf2 files.
When we load an instrument using Soundfont.instrument with the options.destination set to a node a create (for example GainNode), it is not taken into account.
The doc tells us about the option destination which is not used:
Here what I changed in the code to make it work:
`function instrument (ac, name, options) {
if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) }
var opts = options || {}
var isUrl = opts.isSoundfontURL || isSoundfontURL
var toUrl = opts.nameToUrl || nameToUrl
var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format)
return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) {
var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination)
p.url = url
p.name = name
return p
})
}
`
instead of this code
`function instrument (ac, name, options) {
if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) }
var opts = options || {}
var isUrl = opts.isSoundfontURL || isSoundfontURL
var toUrl = opts.nameToUrl || nameToUrl
var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format)
return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) {
var p = player(ac, buffers, opts).connect(ac.destination)
var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination)
p.url = url
p.name = name
return p
})
}
`
I'm not sure if this is the same as #7 but the duration parameter has no effect when playing a note. In this example (I'm loading in sounds locally), changing the duration from 2 to 200 to 2000 does nothing. It always plays the MP3 once and that's it.
var ac = new AudioContext()
Soundfont.instrument(ac, '/soundfont/cello-mp3.js').then(function (cello) {
cello.play('C4', ac.currentTime, 2000)
})
The marimba demo crackles on iOS after the first few notes start. You can hear the new notes starting slower too, until it catches up. I'm testing on an iPad mini (first generation).
I've noticed quite a lot of web audio applications behave this way especially on the older iPads. I think that the browser/CPU is not keeping up with the quantity of AudioBufferSourceNode nodes. I was able to make it work a bit better by
I'm interested to know if anything can be done to improve performance. The marimba demo doesn't actually seem to max out the CPU unlike some of the others I've seen but it's still not keeping up.
Some other apps I've noticed crackling issues with are MIDI.js (webaudio output is unusable on iOS) (CPU > 100% all the time), and even this simple sound effects demo http://webaudioapi.com/samples/rapid-sounds/
instrument names were changed in gleitz' repo on 6/11, causing 404's for multiple instruments, e.g. https://gleitz.github.io/midi-js-soundfonts/MusyngKite/synthbrass_1-mp3.js
(should now be https://gleitz.github.io/midi-js-soundfonts/MusyngKite/synth_brass_1-mp3.js)
See: https://github.com/gleitz/midi-js-soundfonts/commits/gh-pages/MusyngKite/names.json
Hi,
The documentation suggests there is a onready callback on soundfont level, but this function is missing from the library. The only onready i could find was on instrument level.
https://github.com/danigb/soundfont-player#soundfontonreadycallback
Weird thing is that this commit adds is: 8ac8296
Maybe got lost in the merges?
Hello -
Please forgive my ignorance as I am relatively new to programming.
I am using the Soundfont player for a sketch in p5.js. I have created a play button to play my song after I have chosen my instruments. If I press the play button right away, the sound is a bit choppy. If I wait a second or two, it's fine. Is there a simple line I can add that will prevent the song from playing until the sound is fully loaded?
i.e. if (instrument.isLoaded()){instrument.play}
Thanks
My midi tracks with notes on have a delta value on them:
{
byteIndex: 140
channel: 2
delta: 216
name: "Note on"
noteName: "D4"
noteNumber: 62
running: true
tick: 2444
track: 3
velocity: 0
}
Where do I insert these delta values while playing? It sounds pretty bad as it is. I tried playing midi tracks with delta being all 0 and it sounds perfect. But as it is most of my midi have tracks with delta greater than 0 on them. Pls. help.
Running the following code seems to be returning a "Uncaught TypeError: marimba.play is not a function".
var marimba = soundfont.instrument(new AudioContext(), 'marimba');
marimba.play('C4');
Seems as though every time I try to set a variable to an instrument I cannot play. Any suggestions?
Hi have spent some time trying to understand where the difference comes from in Firefox and Chrome and I am now reaching to you for help.
I run the following code that works well on Chrome (no crack and CPU comes back near flat after the test) but in Firefox it cracks and CPU is high and never goes back down even a few minutes after the test is finished.
Is that a bug in Firefox or is that a bug in the library?
The code will execute play on the instrument (woodblock) every 0.1 second for 20 seconds.
<html>
<head>
<title>test heavy load</title>
<script type="text/javascript" src="soundfont-player.min.js"></script>
<script type="text/javascript">
var audioContext = new AudioContext();
Soundfont.instrument(audioContext, 'woodblock', {
destination: audioContext.destination,
loop: false,
notes: ["C4"] })
.then(function (instrument) {
// console.log("instrument loaded");
var interval = 20; // in second
var iter = 10 * interval;
for(var i=0 ; i<iter ; i++) {
var time = audioContext.currentTime + interval/iter * i;
instrument.play("C4", time, time + 1);
}
});
</script>
</head>
<body>
TEST PAGE
</body>
</html>
This may be related to #28. The player is not working in Safari, but only on some machines.
The console contains the message ‘Buffer null not found’. What can I do to help debug this?
How do you tell the player to stop a note when you are using schedule?
Add basic ADSR envelope support. It will use https://www.npmjs.com/package/adsr. Work in progress.
Part of the #7
Hey man, great library. Both you and I seem to be interested in programming and music. I'm working on a MIDI player and am using this library for the sounds. I find that when I set gain
to 0
the note still sounds. Would be be possible for the note to be silent in that case?
Here's the MIDI player I'm working on: http://grimmdude.com/MidiPlayerJS/
Thanks,
Garrett
Can you please add Ben Gleitz repo's port of the fatboy soundfont? It's beautiful and he added it a few months ago.
How to use with Tuna.js
I need a demo
I have wrote code which encodes Doom's Mus into Midi and cannot find a method to play this inside javascript in a clean and simple way. Can this take an array buffer of midi data?
Hey,
I'm having trouble with loading and handling the library in iOS (works fine on PC/Android devices)
I've stripped my engine to this super simple page:
<!DOCTYPE html>
<head>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="soundfont-player.min.js" type="text/javascript"></script>
</head>
<body>
<button id="play" onclick="testNote()">click me to play a note</button>
<button id="playAgain" onclick="playAgain()">click me to stop and play again</button>
<script>
var midiout,
AudioContext;
$(document).ready(function(){
AudioContext = window.AudioContext || window.webkitAudioContext;
midiout = Soundfont.instrument(new AudioContext(), 'acoustic_grand_piano').then(function (piano) {
midiout = piano;
midiout.play(50);
});
});
function testNote() {
midiout.play(50);
}
function playAgain() {
midiout.stop();
midiout.play(50);
}
</script>
</body>
</html>
The issue: after a note starts playing, when the second button is clicked it behaves as expected, but only once.
I've connected my iPhone to a Mac for debugging through Safari develop mode - and the following error shows up in the console when clicking on #playAgain after it has been clicked once already:
InvalidStateError (DOM Exception 11): The object is in an invalid state. - in stop - soundfont-player.min.js:1:6434
When expanded, this is the information that's displayed:
Any light shed on the subject will be greatly appreciated.
Thanks in advance,
PS I unminified the library and 'line 1, column 6434' that is referenced in the error is in this line:
this._voltage.stop(endTime);
The comments for Soundfont.instrument() imply that you can supply a notes list to load in the options, using MIDI note numbers. However if you do that nothing is loaded.
I don't see any code which would map the note numbers to names before handing them to the audio-loader.
My test case is:
Soundfont.instrument(ac, 'marimba', { destination: vca, notes: [70, 72] }).then(function (marimba) {
Currently any instrument outputs to ctx.destination
. It would be very useful allow to override this behaviour.
What I'm thinking:
var ctx = new AudioContext()
var soundfont = new Soundfont(ctx)
var gain = ctx.createGain()
gain.gain.value = 0.5
gain.destination = ctx.destination
var instrument = soundfont.instrument('acoustic_grand_piano', { destination: gain })
I am trying to use samples from a .sf2 file that I downloaded from http://www.flamestudios.org/free/Soundfonts.
I am serving the file from my server and trying to call it like this:
Soundfont.instrument(this.fbs.audioContext, "IBNZSteelString.sf2", { from: 'http://localhost:3000/' }).then((instrument)=> {this.fbs.instrument = instrument;})
I'm getting the following error in the console: https://gleitz.github.io/midi-js-soundfonts/MusyngKite/IBNZSteelString.sf2-mp3.js 404 Not Found. It doesn't look like soundfont-player is making the call to my server, but rather to the default gleitz github.
What am I doing wrong?
Hi,
I'm experiencing choppy sound with Chromium 83.0.4096.0 on Android, testing here: https://ethereum.karimratib.me:8080/ which uses soundfont-player (please ignore the certificate warning).
I hope this helps! best regards
Please forgive me if I am not able to best ask this question - I am a relative novice and can't seem to figure this out.
I'm writing a p5.js sketch that uses the Soundfont player. I am wanting to load/use a different soundfont of my own creation. I have used the MIDI.js soundfont generator to render the soundfont into the .js format.
Before placing this newly created file into a repository, I was trying to load a different soundfont using the following line:
Soundfont.instrument (ac, "marimba-mp3.js", { from: "http://gleitz.github.io/midi-js-soundfonts/FatBoy/" }).then(function(play_marimba) { marimba = play_marimba})
I could not get the sound to load this way. As far as I know I have followed what you said to do in the readme file.
I also wondered if there was a way just to load the marimba-mp3.js file right into my sketch, but I couldn't figure that out either.
Sorry if my question is not clear enough.
Any help or clarification would be greatly appreciated!
Leo
from the README:
You can load your own Soundfont files passing the .js path or url:
Soundfont.instrument(ac, '/soundfonts/clavinet-mp3.js').then(...)
// or
Soundfont.instrument(ac, 'clavinet-mp3.js', { from: 'server.com/soundfonts/' })
404 for one of the js files on your website.
https://cdn.rawgit.com/gleitz/midi-js-soundfonts/master/FluidR3_GM/acoustic_grand_piano-ogg.js
Greetings! First, my gratitude for this great library. I tried several libraries for web MIDI and this is by far the most straightforward and usable that I've seen.
My setup seems to work but it's producing some warnings that I thought were worth reporting. I have two MIDI inputs that I'm listening to: a VMPK keyboard and a KORG-SP500 that hooks to my laptop with a MIDI-USB adapter.
Both of the inputs play sound in my browser, but when the KORG is connected I get these illegal message warnings in very quick succession. I'd be happy to drill in and gather more information for you, but I'm not sure what I'm looking for.
Thank you again for the great lib and for taking time to read through this issue.
Hey, just loaded up your example and noticed that none of the flats seem to play (Chrome & FF). Trying to play Eb2
yields:
Uncaught TypeError: Failed to set the 'buffer' property on 'AudioBufferSourceNode': The provided value is not of type 'AudioBuffer'.
at TypeError (native)
at Object.instrument.play (http://localhost:8080/dist/soundfont-loader.js:81:20)
at eval (eval at evaluate (unknown source), <anonymous>:1:7)
at Object.InjectedScript._evaluateOn (<anonymous>:895:55)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
at Object.InjectedScript.evaluateOnCallFrame (<anonymous>:954:21)
at http://localhost:8080/example/:24:9
at Array.forEach (native)
at HTMLAnchorElement.<anonymous> (http://localhost:8080/example/:23:35)
Strange because the object at that key (buffers.Eb2
) is indeed an AudioBuffer. I don't have time to delve deeper right now, but I can later. Just thought I'd raise it now in case the fix was obvious.
I get this message in chrome
player.js:37 [Deprecation] GainNode.gain.value setter smoothing is deprecated and will be removed in M64, around January 2018. Please use setTargetAtTime() instead if smoothing is needed. See https://www.chromestatus.com/features/5287995770929152 for more details.
Is this library is maintained?
Hi, how can i play a midi file like file.midi with the player? Should i use the web midi api?
Thanks for the great library!
One small API problem I ran into for my project: right now instrument()
is what takes the options
parameter with the gain and destination information. I feel it would be more flexible to have options
be an argument to play()
instead:
var inst = soundfont.instrument('guitar_harmonics');
inst.play('c2', 1, 0.5, { gain: 0.2, destination: my_dest });
I need this functionality to play notes softer or louder depending on how hard a user strikes my virtual instrument's strings.
I'll submit a PR shortly and you can see if you agree with the API change.
Just a quick note about using this library on iOS: I do not believe that the default ogg files are supported, but you can use the mp3 versions just fine:
const loader = name =>
'https://cdn.rawgit.com/gleitz/midi-js-Soundfonts/master/FluidR3_GM/' + name + '-mp3.js';
new Soundfont(ctx, loader);
It may be worth adding a note to the readme about this, or perhaps changing the default since I believe mp3 does have broader support:
http://caniuse.com/#feat=ogg-vorbis
http://caniuse.com/#feat=mp3
Your main readme file says I can do this:
// or stop only one
clavinet.play('C4').stop(ac.currentTime + 0.5)
but it doesn’t work, because play(), an alias for start(), does not return start()’s return value.
Changing
player.play = function (n, w, o) { player.start(n, w, o) }
to
player.play = function (n, w, o) { return player.start(n, w, o) }
makes it work.
I tried to file a pull request, but it’s not showing up. In any case, it had a mistake in it, in that it stopped microtones from working, so if the pull request does show up at some point it should be discarded.
This is a great little library, many thanks.
I would like to know if it's possible to register a function to be invoked when the scheduler plays each note. My use case is that I want to animate a UI element when each note plays.
Is this possible? If not, how might I go about implementing it?
Is it possible to use a custom sound font source other than MusyngKite and FluidR3_GM?
I get the depreciation below. Hope it will be included in an update.
[Deprecation] AudioParam value setter will become equivalent to AudioParam.setValueAtTime() in M65, around March 2018 See https://webaudio.github.io/web-audio-api/#dom-audioparam-value for more details.
I tried getting soundfont using Angular. I get this error:
Argument of type 'AudioContext' is not assignable to parameter of type '{ new (contextOptions?: AudioContextOptions): AudioContext; prototype: AudioContext; }'.
Property 'prototype' is missing in type 'AudioContext' but required in type '{ new (contextOptions?: AudioContextOptions): AudioContext; prototype: AudioContext; }'.
This is my code:
const newPlayer = SoundFont.instrument(new AudioContext(), 'assets/soundfonts/acoustic_grand_piano-mp3.js');
error is in new AudioContext()
part
I don't get any sound from the demos (either examples/index.html, nor the page at https://danigb.github.io/soundfont-player/ ) in Safari, either on the Mac or on iOS 9.3.2.
Firstly Safari uses the deprecated name webkitAudioContext. Once I changed that, I still don't get any sound from the soundfont-player page; it seems the soundfont loaded .then() promise is never called. I couldn't see why,
How do I turn a note off or set the duration of the note?
for notes on:
piano.play(event.noteName, ac.currentTime, {gain:event.velocity/5});
I have a midi off event, I would like to turn the note off
I tried piano.stop(event.noteName, ac.currentTime, {}); but this obviously doesn't work.
Any suggestions would be appreciated.
Thanks for your help.
Is there any way I can throw data from the Web MIDI API into this library to play it? Any examples of this?
Is it possible to add my own soundfonts?
Gracias por su trabajo en este proyecto -
the path to soundfont-player.js is relative to root vs /examples
<script src="/dist/soundfont-player.js"></script>
should be
<script src="../dist/soundfont-player.js"></script>
With that in place, /examples/index.html works wonderfully.
¡Ahora puedo pasar demasiado tiempo añadiendo sonido a las cosas!
Any plans to add a snare drum to the instruments list?
Hi Dani
Just noticed that the script URL in the GitHub page is incorrect.
https://raw.githubusercontent.com/danigb/soundfont-player/master/dist/soundfont-loader.min.js
Should be ...player.min.js
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.