Java Sound e arquivos midi

4 respostas
Rafu_net

Bom dia pessoal, não consigo tocar o meu arquivo midi com o codigo abaixo:

package music;

import javax.swing.JFrame;
import javax.sound.midi.*;
import javax.swing.*;
import java.awt.GridLayout;
import java.io.File;

public class PlayMidi extends JFrame
{
	public PlayMidi( String song)
	{
	  super("Tocar música");
	  setSize(180,100);
	  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	  MidiPanel midi = new MidiPanel(song);
	  add(midi);
	  setVisible(true);
	}
	
	public static void main( String args[])
	{
		if (args.length &lt 1)
		{
			System.out.println("Usage: Java PlayMidi filename");
		}
		else 
		{
			PlayMidi pm = new PlayMidi(args[0]);
		}
		
	}
	

}

class MidiPanel extends JPanel implements Runnable{
	Thread runner;
	JProgressBar progress = new JProgressBar();
	Sequence currentSound;
	Sequencer player;
	String songFile;
	
	MidiPanel(String song) {
		super();
		//song="junina.mid";
		songFile = song;
		JLabel label = new JLabel("Playing file...");
		setLayout(new GridLayout(2,1));
		add(label);
		add(progress);
		if(runner == null){
			runner = new Thread(this);
			runner.start();
		}
	}
	public void run(){
		try{
			File file = new File(songFile);
			currentSound = MidiSystem.getSequence(file);
			player = MidiSystem.getSequencer();
			player.open();
			player.setSequence(currentSound);
			progress.setMinimum(0);
			progress.setMaximum((int)player.getMicrosecondLength());
			player.start();
			while (player.isRunning()){
				progress.setValue((int)player.getMicrosecondPosition());
				try{
					Thread.sleep(1000);
				}catch (InterruptedException e){}
			}
			int position = (int) player.getMicrosecondPosition();
			if ( position &gt 0){
				progress.setValue(position);
			}
			player.close();
		}catch (Exception ex){
			System.out.println(ex.toString());
		}
	}
}

O nome do meu arquivo é junina.mid mas não sei onde devo botar ele no código. Me parecia que songFile representava este meu arquivo midi mas agora estou confuso. Quando boto o programa para rodar, ele imprima: "Usage: Java PlayMidi filename". Alguém poderia me dar uma dica?

4 Respostas

ViniGodoy

Olá, seja bem-vindo ao GUJ!

Bom, se ele escreve isso, é porque você está deixando de passar o argumento na linha de comando com o nome do seu midi!

Sua linha de comando é algo como:
java music.PlayMidi junina.mid
?

ViniGodoy

Achei estranho o método que você usou para tocar. Normalmente, basta usar o setSequence que o som já sai tocando direto.

No Vikanoid, eu desenvolvi a seguinte classe para tocar sons mid sem ter que ficar me preocupando com Sequence e afins. Dá uma olhada no código, talvez te ajude.

package jgf.sound;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

/**
 * Plays MIDI music. The objective of this class is to easy the manipulation of
 * the Sequencer object. Each MidiPlayer will control only one Sequencer. If the
 * sequencer is not available, the MidiPlayer will simply not play any
 * jgf.sound, not resulting in errors.
 * 
 * @author Vinicius
 */
public class MidiPlayer
{
    private Sequencer sequencer;
    private boolean paused;

    public MidiPlayer() {
        try {
            sequencer = MidiSystem.getSequencer();
            sequencer.open();
            paused = true;
        } catch (MidiUnavailableException e) {
            sequencer = null;
        }
    }

    /**
     * Start playing the given music in loop. This method returns immediatelly.
     * 
     * @param midi The MIDI to be played.
     */
    public void play(Sequence midi) {
        play(midi, true);
    }

    /**
     * Start playing the given music. This method returns immediatelly.
     * 
     * @param midi The MIDI to be played.
     * @param loop If true, loop the game sound endlessly. Otherwise plays only
     *            once.
     */
    public void play(Sequence midi, boolean loop) {
        if (sequencer == null || midi == null)
            return;

        try {
            sequencer.setSequence(midi);
            sequencer.setMicrosecondPosition(0);
            if (loop)
                sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
            setPaused(false);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stops the music being played, if any.
     */
    public void stop() {
        if (sequencer == null || !sequencer.isOpen())
            return;

        sequencer.stop();
        sequencer.setMicrosecondPosition(0);
    }

    /**
     * Closes the device, indicating that the device should now release any
     * system resources it is using. Once closed, no jgf.sound will be played
     * again.
     */
    public void close() {
        if (sequencer == null || !sequencer.isOpen())
            return;

        sequencer.close();
    }

    /**
     * Pauses the jgf.sound being played.
     * 
     * @param paused True to pause, false to continue.
     * @see MidiPlayer#isPaused()
     */
    public void setPaused(boolean paused) {
        if (this.paused == paused || sequencer == null)
            return;

        this.paused = paused;

        if (paused)
            sequencer.stop();
        else
            sequencer.start();
    }

    /**
     * Indicate if the MIDI is paused or not.
     * 
     * @return True if the MIDI is paused, false otherwise.
     */
    public boolean isPaused() {
        return paused;
    }

    /**
     * Returns the current tempo factor. The default is 1.0.
     * 
     * @return The tempo factor.
     * @see MidiPlayer#setTempoFactor(float)
     */
    public double getTempoFactor() {
        if (sequencer == null)
            return 0;

        return sequencer.getTempoFactor();
    }

    /**
     * Obtains the current mute state for a track. The default mute state for
     * all tracks which have not been muted is false. In any case where the
     * specified track has not been muted, this method should return false. This
     * applies if the sequencer does not support muting of tracks, and if the
     * specified track index is not valid.
     * 
     * @param track the track number. Tracks in the current sequence are
     *            numbered from 0 to the number of tracks in the sequence minus
     *            1
     * @return <code>true</code> if muted, <code>false</code> if not.
     */
    public boolean getTrackMute(int track) {
        if (sequencer == null)
            return true;

        return sequencer.getTrackMute(track);
    }

    /**
     * Obtains the current solo state for a track. The default mute state for
     * all tracks which have not been solo'd is false. In any case where the
     * specified track has not been solo'd, this method should return false.
     * This applies if the sequencer does not support soloing of tracks, and if
     * the specified track index is not valid.
     * 
     * @param track the track number. Tracks in the current sequence are
     *            numbered from 0 to the number of tracks in the sequence minus
     *            1.
     * @return true if solo'd, false if not.
     */
    public boolean getTrackSolo(int track) {
        if (sequencer == null)
            return false;

        return sequencer.getTrackSolo(track);
    }

    /**
     * Scales the sequencer's actual playback tempo by the factor provided. The
     * default is 1.0. A value of 1.0 represents the natural rate (the tempo
     * specified in the sequence), 2.0 means twice as fast, etc. The tempo
     * factor does not affect the values returned by getTempoInMPQ and
     * getTempoInBPM. Those values indicate the tempo prior to scaling. Note
     * that the tempo factor cannot be adjusted when external synchronization is
     * used. In that situation, setTempoFactor always sets the tempo factor to
     * 1.0.
     * 
     * @param factor the requested tempo scalar
     */
    public void setTempoFactor(double factor) {
        if (sequencer == null)
            return;

        sequencer.setTempoFactor((float) factor);
    }

    /**
     * Sets the mute state for a track. This method may fail for a number of
     * reasons. For example, the track number specified may not be valid for the
     * current sequence, or the sequencer may not support this functionality. An
     * application which needs to verify whether this operation succeeded should
     * follow this call with a call to getTrackMute.
     * 
     * @param track the track number. Tracks in the current sequence are
     *            numbered from 0 to the number of tracks in the sequence minus
     *            1.
     * @param mute the new mute state for the track. true implies the track
     *            should be muted, false implies the track should be unmuted.
     */
    public void setTrackMute(int track, boolean mute) {
        if (sequencer == null)
            return;

        sequencer.setTrackMute(track, mute);
    }

    /**
     * Sets the solo state for a track. If solo is true only this track and
     * other solo'd tracks will jgf.sound. If solo is false then only other
     * solo'd tracks will jgf.sound, unless no tracks are solo'd in which case
     * all un-muted tracks will jgf.sound. This method may fail for a number of
     * reasons. For example, the track number specified may not be valid for the
     * current sequence, or the sequencer may not support this functionality. An
     * application which needs to verify whether this operation succeeded should
     * follow this call with a call to getTrackSolo.
     * 
     * @param track the track number. Tracks in the current sequence are
     *            numbered from 0 to the number of tracks in the sequence minus
     *            1.
     * @param solo the new solo state for the track. true implies the track
     *            should be solo'd, false implies the track should not be
     *            solo'd.
     */
    public void setTrackSolo(int track, boolean solo) {
        if (sequencer == null)
            return;

        sequencer.setTrackSolo(track, solo);
    }

    /**
     * Indicate if the sequencer was obtained and, therefore, if it's possible
     * to play musics with this object.
     * 
     * @return
     */
    public boolean isSequencerAvailable() {
        return sequencer != null;
    }
}
Rafu_net

Valeu pela dica, vou tentar aquele comando.

Rafu_net

Não consegui aplicar sua dica com o command mas eu fiz algumas transformações no meu código:


package music;

import javax.swing.JFrame;
import javax.sound.midi.*;
import javax.swing.*;
import java.awt.GridLayout;
import java.io.File;

public class PlayMidi extends JFrame
{
	public PlayMidi( String song)
	{
	  super("Tocar música");
	  setSize(180,100);
	  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	  MidiPanel midi = new MidiPanel(song);
	  add(midi);
	  setVisible(true);
	}
	
	public static void main( String args[])
	{
		
			PlayMidi pm = new PlayMidi("");
		
	}
	
}

class MidiPanel extends JPanel implements Runnable{
	Thread runner;
	JProgressBar progress = new JProgressBar();
	Sequence currentSound;
	Sequencer player;
	String songFile;
	
	MidiPanel(String song) {
		super();
		songFile = song;
		JLabel label = new JLabel("Playing file...");
		setLayout(new GridLayout(2,1));
		add(label);
		add(progress);
		if(runner == null){
			runner = new Thread(this);
			runner.start();
		}
	}
	public void run(){
		try{
			File file = new File("music/junina.mid");
			currentSound = MidiSystem.getSequence(file);
			player = MidiSystem.getSequencer();
			player.open();
			player.setSequence(currentSound);
			progress.setMinimum(0);
			progress.setMaximum((int)player.getMicrosecondLength());
			player.start();
			while (player.isRunning()){
				progress.setValue((int)player.getMicrosecondPosition());
				try{
					Thread.sleep(1000);
				}catch (InterruptedException e){}
			}
			int position = (int) player.getMicrosecondPosition();
			if ( position &gt 0){
				progress.setValue(position);
			}
			player.close();
		}catch (Exception ex){
			System.out.println(ex.toString());
		}
	}
}
Criado 18 de março de 2007
Ultima resposta 19 de mar. de 2007
Respostas 4
Participantes 2