Ok, I think I have the Javascript MIDI library behaving in an acceptable manner finally. The losing-focus problem has been solved. In case you were wondering why it took me so long, it is extremely difficult to get something that behaves the same way in all browsers. Oh, and I really hate Microsoft, btw.
Anyway... Here it is:
Javascript and required filesDemo Applet demonstrating use of the javascript alongside the small version of Sound System
(
Java Source,
HTML Source)
To use this javascript, make sure the files playmidi.js and silence.mid are in the same directory, and place the following line of code somewhere on your HTML page:
<script type='text/javascript' src='playmidi.js'> </script>
Include the following methods in your extended JApplet class. These are just simple interfaces to the Javascript methods (the method names are pretty self-explanatory):
public void loadMIDI( String fileUrl, float gain, boolean loop )
{
if( fileUrl == null )
return;
int volume = (int) (gain * 100.0f);
if( volume > 100 )
volume = 100;
if( volume < 0 )
volume = 0;
String loopString;
if( loop )
loopString = "true";
else
loopString = "false";
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[3];
args[0] = fileUrl;
args[1] = String.valueOf( volume );
args[2] = loopString;
mainWindow.call( "loadMIDI", args );
}
public void playMIDI( String fileUrl )
{
if( fileUrl == null )
return;
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[1];
args[0] = fileUrl;
mainWindow.call( "playMIDI", args );
this.requestFocus();
}
public void pauseMIDI( String fileUrl )
{
if( fileUrl == null )
return;
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[1];
args[0] = fileUrl;
mainWindow.call( "pauseMIDI", args );
this.requestFocus();
}
public void stopMIDI( String fileUrl )
{
if( fileUrl == null )
return;
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[1];
args[0] = fileUrl;
mainWindow.call( "stopMIDI", args );
this.requestFocus();
}
public void rewindMIDI( String fileUrl )
{
if( fileUrl == null )
return;
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[1];
args[0] = fileUrl;
mainWindow.call( "rewindMIDI", args );
this.requestFocus();
}
public void setMIDIAttribute( String fileUrl, String attribute, String value )
{
if( fileUrl == null )
return;
JSObject mainWindow = JSObject.getWindow( this );
String[] args = new String[3];
args[0] = fileUrl;
args[1] = attribute;
args[2] = value;
mainWindow.call( "setMIDIAttribute", args );
}
To be able to compile your applet, you will also need to include the file 'plugin.jar', which can be found in your jre directory under the 'lib' subdirectory. Also, import netscape.javascript.JSObject at the top of your code. You do NOT need to include 'plugin.jar' in your applet's archive list at runtime - it will already be loaded when running the applet from inside a browser
I have the javascript working for all the major browsers using the QuickTime audio pluggin for MIDI, which is the default for most browsers, so most people are likely to be using it. The javascript may works with some other audio pluggins as well, but I haven't taken the time to test this yet. Problem is each pluggin uses its own method names for the controls (play() Play() or doPlay(), for example) so I'd have to check what audio pluggin a user has and call the correct methods for it). I may come back at some point to work on that, but for now it is probably going to work 90% of the time.
A couple of limitations / bugs with this javascript:
1) Apparently a "hidden" embed tag cannot be played in browsers based on Netscape technology (Firefox for example), so I had to make the player visible. A width and height to zero works fine in Firefox, but it does not compute in Internet Explorer, so I was forced to go with a width and height of 1. Therefore, the browser displays a single pixel for each embed tag wherever you place the javascript on your page. For that reason, I recommend placing the script at the bottom of the page (right before closing the </body>) Or if you have a better place on the page, just put it wherever. I'm going to tinker around with this some more to see if I can figure a way to make the thing completely invisible (I might have to brush up on my HTML skills).
2) With the QuickTime pluggin (possibly other pluggins as well), you can't change the "volume" and "looping" attributes via javascript once your <embed> tag has been created. For that reason, you must specify the volume and looping attributes of your MIDI file when you load it, and they can not be changed later.
3) The user has complete control over the MIDI playback, so if they have music or embed disabled in their browser, or their Synth volume control is muted, there's not much you can do about it.
4) I was having problems with loud scratching sounds in some browsers the first time a sound is played. To compensate, I had to make the javascript automatically play a silent MIDI file when it starts up. This is completely transparent, but you are required to place the file "silence.mid" wherever the javascript is located. On one of my test machines, I noticed the scratchiness had popped back up when loading the sounds from inside an applet rather than from the HTML. If this starts happening a lot, a workaround would be to pre-load the MIDI files directly from the HTML rather then from inside the applet:
<script type='text/javascript' src='playmidi.js'> </script>
<script type='text/javascript'>
<!--
loadMIDI( 'theme.mid', 100, true );
loadMIDI( 'Bach.mid', 40, false );
//-->
</script>