Ok, I altered your playMidi method slightly, and it seems to be working. One important thing to note - volume changes for MIDI are not a linear function, and they can be overwritten if volume events are written into the sequence by the composer. Also, depending on the MIDI file and synthesizer, a volume of "0" does not necessarily mean completely silent. That being said, at least it is usually possible to reduce the volume down to an acceptable level. Here is the altered playMidi method (in a simple application), which works fine on my computer:
import java.io.IOException;
import java.net.URL;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;
public class MIDIVolumeProblem
{
public static void main(String[] args)
{
new MIDIVolumeProblem();
}
public MIDIVolumeProblem()
{
playMidi( "beethoven.mid", 0 );
try
{
Thread.sleep( 60000 );
}
catch( InterruptedException ie )
{}
}
private void playMidi( String filename, int midiVolume )
{
int CHANGE_VOLUME = 7;
Sequencer midiPlayer = null;
Synthesizer synthesizer = null;
Sequence sequence = null;
URL midiFile = getClass().getClassLoader().getResource(
"beethoven.mid" );
if( midiFile == null )
{
System.err.println( "Unable to load Midi file." );
return;
}
try
{
sequence = MidiSystem.getSequence( midiFile );
midiPlayer = MidiSystem.getSequencer();
midiPlayer.open();
midiPlayer.setSequence( sequence );
}
catch( IOException ioe )
{
System.err.println( "Input failed while reading from MIDI file." );
ioe.printStackTrace();
return;
}
catch( InvalidMidiDataException imde )
{
System.err.println( "Invalid MIDI data encountered, or not a MIDI "
+ "file." );
imde.printStackTrace();
return;
}
catch( MidiUnavailableException mue )
{
System.err.println( "MIDI unavailable, or MIDI device is already "
+ "in use." );
mue.printStackTrace();
return;
}
catch( Exception e )
{
System.err.println( "Problem loading MIDI file." );
e.printStackTrace();
return;
}
if( midiPlayer instanceof Synthesizer )
{
synthesizer = (Synthesizer) midiPlayer;
}
else
{
try
{
synthesizer = MidiSystem.getSynthesizer();
synthesizer.open();
Receiver receiver = synthesizer.getReceiver();
Transmitter transmitter = midiPlayer.getTransmitter();
transmitter.setReceiver( receiver );
}
catch( MidiUnavailableException mue )
{
System.err.println( "MIDI unavailable, or MIDI device is "
+ "already in use." );
mue.printStackTrace();
return;
}
catch( Exception e )
{
System.err.println( "Problem initializing the MIDI "
+ "synthesizer." );
e.printStackTrace();
return;
}
}
midiPlayer.start();
// wait a couple of seconds so you can hear the volume change:
// TODO: remove this
try
{
Thread.sleep( 2000 );
}
catch( InterruptedException ie )
{}
javax.sound.midi.MidiChannel[] channels = synthesizer.getChannels();
for( int c = 0; channels != null && c < channels.length; c++ )
{
channels[c].controlChange( CHANGE_VOLUME, midiVolume );
}
}
}
Oh, and I should mention, if you use a program (such as Cakewalk) to compose or edit your MIDI files, if you set the default volume for each channel very low, then you should have more control over the volume in your program (I haven't tested that yet myself, but that's the advice I got from someone else). Also, possible values for midVolume can actually go up to 255 (anything over 127 is an increase in the channel's volume, while values lower than 127 decrease the volume).