Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java midi播放质量不一致_Java_Midi_Javasound - Fatal编程技术网

Java midi播放质量不一致

Java midi播放质量不一致,java,midi,javasound,Java,Midi,Javasound,我最近在开发的游戏中玩MIDI时遇到了一个奇怪的错误。我认为我的midi代码工作得很好,因为它过去播放midi时听起来并不奇怪。现在,每当它播放MIDI时,它们的声音都很小,回声很强,声音也很大 我已经很长时间没有接触我的midi播放器代码了,所以我想知道最近的Java更新是否可能暴露了我代码中一直存在的错误。或者在我的Java版本中可能存在某种我不知道的midi错误 每当我在游戏之外玩MIDI时,它的声音都很好 我正在运行Java6,更新31,构建1.6.0_31-b05。下面是一个重现问题的

我最近在开发的游戏中玩MIDI时遇到了一个奇怪的错误。我认为我的midi代码工作得很好,因为它过去播放midi时听起来并不奇怪。现在,每当它播放MIDI时,它们的声音都很小,回声很强,声音也很大

我已经很长时间没有接触我的midi播放器代码了,所以我想知道最近的Java更新是否可能暴露了我代码中一直存在的错误。或者在我的Java版本中可能存在某种我不知道的midi错误

每当我在游戏之外玩MIDI时,它的声音都很好

我正在运行Java6,更新31,构建1.6.0_31-b05。下面是一个重现问题的SSCE(它至少在我的JVM上重现了问题):

import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入java.io.*;
导入javax.sound.midi.*;
导入java.net.URL;
公共类MidiSSCCE扩展JFrame
{
公共MidiSSCCE()
{
超级(“声音问题SSCCE”);
这个.setSize(200100);
//实例化主窗口面板
JPanel screenP=新SSCCEPanel(本);
添加(screenP);
//游戏窗口的收尾工作
此.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
此.setVisible(true);
System.out.println(“游戏窗口成功创建!!!”;
}
公共静态void main(字符串[]args)
{
MidiSSCCE gui=新的MidiSSCCE();
}
}
/**
*SSCCEPanel是管理示例计时器、绘制和逻辑的JPanel。
**/
类SSCCEPanel扩展了JPanel
{
公共框架父框架;
私人定时器;
公共int逻辑循环;
公共双prevFPS;
布尔时差;
//示例使用MidiPlayer对象来播放midi。
公共MIDI播放器;
公共SSCCEPanel(帧父级)
{
超级(真);
父帧=父帧;
此参数为.setFocusable(true);
getDefaultToolkit().sync();
逻辑循环=0;
midiPlayer=新的midiPlayer();
TimerListener TimerListener=新TimerListener();
prevFPS=0;
timerReady=true;
计时器=新计时器(0,timerListener);
这是setFPS(60);
timer.start();
}
/** 
*setFPS()
*前提条件:fps是每秒的帧数
*后置条件:设置计时器的刷新率,以便
*每秒发射fps次。
**/
公共无效设置fps(整数fps)
{
int-mspf=(int)(1000.0/fps+0.5);
定时器设置延迟(mspf);
}
/**
*这是JPanel的计时器侦听器。它运行示例的逻辑并重新绘制
*方法每次获取计时器信号时。
**/
私有类TimerListener实现ActionListener
{
long startTime=System.currentTimeMillis();
long lastTime=this.startTime;
int ticks=0;
已执行的公共无效操作(操作事件e)
{
对象源=e.getSource();
如果(源==计时器)
{
//通过游戏逻辑执行循环并重新绘制。
已同步(此)
{
if(timerReady)
{
timerReady=false;
runSSCCELogic();
重新油漆();
timerReady=true;
}
}
//每秒帧数计数器的逻辑
这个.ticks++;
长currentTime=System.currentTimeMillis();
如果(当前时间-开始时间>=500)
{
prevFPS=1000.0*滴答声/(1.0*当前时间-开始时间);
系统输出打印项次(prevFPS);
开始时间=当前时间;
滴答声=0;
}
lastTime=当前时间;
}
}
}
/**
*重新绘制SSCCE。
*这只是显示当前FPS。
**/
公共组件(图形g)
{
超级组件(g);
Graphics2D g2D=(Graphics2D)g;
双舍入fps=数学舍入(prevFPS*10)/10.0;
g2D.setColor(新颜色(0x000000));
g2D.抽绳(FPS:+roundedFPS,20,20);
g、 处置();
}
/**
*runssceelogic()
*这就是SSCCE示例的运行时逻辑所在。
*它所做的只是加载和播放一个名为“mymidi.mid”的midi,它位于同一个目录中。
**/
public void runSSCCELogic()
{
if(logicLoops==1)
{
midiPlayer.load(“http://www.vgmusic.com/music/computer/microsoft/windows/touhou_6_stage3_boss.mid");
midiPlayer.play(真);
}
逻辑循环++;
}
}
/**
*MIDI播放器
*允许加载和播放midi文件的类。
**/
类MIDI播放器
{
私有序列seq;
专用序列器;
专用合成器合成器;
专用接收机;
私有文件;
私有字符串MIDID;
私有布尔加载;
私有布尔使用硬件undbank;
//建设者
公共MIDI播放器()
{
加载=错误;
尝试
{
seqr=MidiSystem.getSequencer();
synth=MidiSystem.getSynthesizer();
}
捕获(例外e)
{
System.out.println(“MIDI错误:您的系统似乎没有MIDI设备或设备不工作。”);
}
}
/**
*MidiPlayer(字符串文件名)
*构造函数,该构造函数还加载初始midi文件。
*前提条件:fileName是要加载的midi文件的名称。
*后置条件:midi播放器是用文件名指定的midi创建和加载的。
**/
公共MIDI播放器(字符串文件名)
{
这个();
加载(文件名);
}
//数据方法
/**
*l
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.sound.midi.*;
import java.net.URL;

public class MidiSSCCE extends JFrame
{

    public MidiSSCCE()
    {
        super("Sound problem SSCCE");
        this.setSize(200,100);

        // instantiate main window panel

        JPanel screenP = new SSCCEPanel(this);
        this.add(screenP);

        // finishing touches on Game window

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        System.out.println("Game Window successfully created!!!");
    }

    public static void main(String[] args)
    {
        MidiSSCCE gui = new MidiSSCCE();        
    }
}


/**
*   SSCCEPanel is the JPanel that manages the example's timer, painting, and logic. 
**/

class SSCCEPanel extends JPanel
{
    public Frame parentFrame;
    private Timer timer;
    public int logicLoops;
    public double prevFPS;
    boolean timerReady;

    // The MidiPlayer object is used by the example to play the midi.

    public MidiPlayer midiPlayer;

    public SSCCEPanel(Frame parent)
    {
        super(true);
        parentFrame = parent;
        this.setFocusable(true);

        Toolkit.getDefaultToolkit().sync();
        logicLoops = 0;

        midiPlayer = new MidiPlayer();

        TimerListener timerListener = new TimerListener();
        prevFPS = 0;
        timerReady = true;
        timer = new Timer(0,timerListener);
        this.setFPS(60);
        timer.start();
    }

    /** 
    *   setFPS()
    *   Preconditions: fps is a quantity of frames per second
    *   Postconditions: Sets the timer's refresh rate so that it 
    *       fires fps times per second.
    **/

    public void setFPS(int fps)
    {
        int mspf = (int) (1000.0 /fps + 0.5);
        timer.setDelay(mspf);
    }


    /**
    *   This is the JPanel's timer listener. It runs the example's logic and repaint
    *   methods each time it gets a timer signal.
    **/

    private class TimerListener implements ActionListener
    {
        long startTime = System.currentTimeMillis();
        long lastTime = this.startTime;
        int ticks = 0;

        public void actionPerformed(ActionEvent e)
        {
            Object source = e.getSource();
            if(source == timer)
            {
                // perform a loop through the game's logic and repaint.

                synchronized(this)
                {
                    if(timerReady)
                    {
                        timerReady = false;
                        runSSCCELogic();
                        repaint();
                        timerReady = true;
                    }
                }

                // Logic for Frames per Second counter

                this.ticks++;

                long currentTime = System.currentTimeMillis();

                if(currentTime - startTime >= 500) 
                {
                    prevFPS =  1000.0 * ticks/(1.0*currentTime - startTime);
                    System.out.println(prevFPS);
                    startTime = currentTime;
                    ticks = 0;
                }

                lastTime = currentTime;
            }
        }
    }


    /**
    *   repaints the SSCCE.
    *   This just shows the current FPS.
    **/

    public void paintComponent(Graphics g)
    {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g;
            double roundedFPS = Math.round(prevFPS*10)/10.0;

            g2D.setColor(new Color(0x000000));
            g2D.drawString("FPS: " + roundedFPS, 20,20);
            g.dispose();
    }

    /**
    *   runSSCCEELogic()
    *   This is where the run-time logic for the SSCCE example is. 
    *   All it does is load and play a midi called "mymidi.mid" which is located in the same directory.
    **/

    public void runSSCCELogic()
    {
        if(logicLoops == 1)
        {
            midiPlayer.load("http://www.vgmusic.com/music/computer/microsoft/windows/touhou_6_stage3_boss.mid");
            midiPlayer.play(true);
        }

        logicLoops++;
    }
}



/**
*   MidiPlayer
*   A class that allows midi files to be loaded and played. 
**/

class MidiPlayer
{
    private Sequence seq;
    private Sequencer seqr;
    private Synthesizer synth;
    private Receiver receiver;
    private File midiFile;
    private String midiID;
    private boolean loaded;
    private boolean usingHardwareSoundbank;

    // CONSTRUCTORS

    public MidiPlayer()
    {
        loaded = false;
        try
        {
            seqr = MidiSystem.getSequencer();
            synth = MidiSystem.getSynthesizer();
        }
        catch(Exception e)
        {
            System.out.println("MIDI error: It appears your system doesn't have a MIDI device or your device is not working.");
        }
    }

    /**
    *   MidiPlayer(String fileName)
    *   Constructor that also loads an initial midi file.
    *   Preconditions: fileName is the name of the midi file to be loaded. 
    *   Postconditions: The MidiPlayer is created and loaded with the midi specified by fileName.
    **/

    public MidiPlayer(String fileName)
    {
        this();
        load(fileName);
    }


    // DATA METHODS

    /**
    *   load(String fileName)
    *   loads a midi file into this MidiPlayer.
    *   Preconditions: fileName is the name of the midi file to be loaded.
    *   Postconditions: fileName is loaded and is ready to be played.
    **/

    public void load(String fileName)
    {
        this.unload();
        try
        {
            URL midiURL =  new URL(fileName);
        //  midiFile = new File(fileName);
            seq = MidiSystem.getSequence(midiURL);

            seqr.open();
            synth.open();

            System.out.println("MidiDeviceInfo: ");
            for(MidiDevice.Info info : MidiSystem.getMidiDeviceInfo())
            {
                System.out.println("\t" + info);
            }
            System.out.println();

            if(synth.getDefaultSoundbank() == null)
            {
                receiver = MidiSystem.getReceiver();
                usingHardwareSoundbank = true;
                System.out.println("using hardware soundbank");
            }
            else
            {
                receiver = synth.getReceiver();
                usingHardwareSoundbank = false;
                System.out.println("using default software soundbank:" + synth.getDefaultSoundbank());
            }
            seqr.getTransmitter().setReceiver(receiver);

            seqr.setSequence(seq);
            loaded = true;
        }
        catch(IOException ioe)
        {
            System.out.println("MIDI error: Problem occured while reading " + midiFile.getName() + ".");
        }
        catch(InvalidMidiDataException imde)
        {
            System.out.println("MIDI error: " + midiFile.getName() + " is not a valid MIDI file or is unreadable.");
        }
        catch(Exception e)
        {
            System.out.println("MIDI error: Unexplained error occured while loading midi.");
        }
    }

    /**
    *   unload()
    *   Unloads the current midi from the MidiPlayer and releases its resources from memory.
    **/

    public void unload()
    {
        this.stop();
        seqr.close();
        midiFile = null;
        loaded = false;
    }

    // OTHER METHODS

    /**
    *   setMidiID(String id)
    *   associates a String ID with the current midi.
    *   Preconditions: id is the ID we are associating with the current midi.
    **/

    public void setMidiID(String id)
    {
        midiID = id;
    }

    /**
    *   getMidiID(String id)
    *
    **/

    public String getMidiID()
    {
        return new String(midiID);
    }

    /**
    *   play(boolean reset)
    *   plays the currently loaded midi.
    *   Preconditions: reset tells our midi whether or nor to begin playing from the start of the midi file's current loop start point.
    *   Postconditions: If reset is true, then the loaded midi begins playing from its loop start point (default 0). 
    *       If reset is false, then the loaded midi resumes playing from its current position.
    **/

    public void play(boolean reset)
    {
        if(reset)
            seqr.setTickPosition(seqr.getLoopStartPoint());
        seqr.start();
    }

    /**
    *   stop()
    *   Pauses the current midi if it was playing.
    **/

    public void stop()
    {
        if(seqr.isOpen())
            seqr.stop();
    }

    /**
    *   isRunning()
    *   Returns true if the current midi is playing. Returns false otherwise.
    **/

    public boolean isRunning()
    {
        return seqr.isRunning();
    }


    /**
    *   loop(int times)
    *   Sets the current midi to loop from start to finish a specific number of times.
    *   Preconditions: times is the number of times we want our midi to loop.
    *   Postconditions: The current midi is set to loop times times. 
    *       If times = -1, the current midi will be set to loop infinitely.
    **/

    public void loop(int times)
    {
        loop(times,0,-1);
    }

    /**
    *   loop(int times)
    *   Sets the current midi to loop from a specified start point to a specified end point a specific number of times.
    *   Preconditions: times is the number of times we want our midi to loop.
    *       start is our loop's start point in ticks.
    *       end is our loop's end point in ticks.
    *   Postconditions: The current midi is set to loop from tick start to tick end times times. 
    *       If times = -1, the current midi will be set to loop infinitely.
    **/

    public void loop(int times, long start, long end)
    {
        if(start < 0)
            start = 0;
        if(end > seqr.getSequence().getTickLength() || end <= 0)
            end = seqr.getSequence().getTickLength();

        if(start >= end && end != -1)
            start = end-1;

        seqr.setLoopStartPoint(start);
        seqr.setLoopEndPoint(end);

        if(times == -1)
            seqr.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
        else
            seqr.setLoopCount(times);

    }


    public void setVolume(double vol)
    {
        try 
        {
            if(usingHardwareSoundbank)
            {
                ShortMessage volumeMessage = new ShortMessage();
                for ( int i = 0; i < 16; i++ ) 
                {
                    volumeMessage.setMessage( ShortMessage.CONTROL_CHANGE, i, 7, (int)(vol*127) );
                    receiver.send( volumeMessage, -1 );
                }
            }
            else
            {
                MidiChannel[] channels = synth.getChannels();
                for( int c = 0; channels != null && c < channels.length; c++ )
                {
                  channels[c].controlChange( 7, (int)( vol*127) );
                }
            }
        } 
        catch ( Exception e ) 
        {
            e.printStackTrace();
        }
    }

}
import javax.sound.midi.*;
import java.net.URL;

class PlayMidi {

     public static void main(String[] args) throws Exception {
          URL url = new URL("http://www.vgmusic.com/music/computer/microsoft/windows/touhou_6_stage3_boss.mid");

          Sequence sequence = MidiSystem.getSequence(url);
          Sequencer sequencer = MidiSystem.getSequencer();

          sequencer.open();
          sequencer.setSequence(sequence);

          sequencer.start();
     }
}
  package gameEngine;

  import javax.sound.midi.*;
  import java.io.File;
  import java.io.IOException;
  import java.net.URL;

  /**
  * MidiPlayer
  * author: Stephen Lindberg
  * Last modified: Oct 14, 2011
  * 
  * A class that allows midi files to be loaded and played.
  **/

  public class MidiPlayer
  {
     private Sequence seq;
     private Sequencer seqr;
     private Synthesizer synth;
     private Receiver receiver;
     private File midiFile;
     private String midiID;
     private boolean loaded;
     private boolean usingHardwareSoundbank;
     private float defaultTempo;

     // CONSTRUCTORS

     public MidiPlayer()
     {
        loaded = false;
        try
        {
           seqr = MidiSystem.getSequencer();
           synth = MidiSystem.getSynthesizer();

           // print the user's midi device info
           System.out.println("Setting up Midi Player...");
           System.out.println("MidiDeviceInfo: ");
           for(MidiDevice.Info info : MidiSystem.getMidiDeviceInfo())
           {
              System.out.println("\t" + info.getName() + ": " +info.getDescription());
           }
           System.out.println();

           // obtain the receiver. This will be used for changing volume.

           Soundbank soundbank = synth.getDefaultSoundbank();
           if(soundbank == null)
           {
              receiver = MidiSystem.getReceiver();
              usingHardwareSoundbank = true;
              System.out.println("using hardware soundbank");
           }
           else
           {
              synth.loadAllInstruments(soundbank);
              receiver = synth.getReceiver();
              usingHardwareSoundbank = false;
              System.out.println("using default software soundbank:" + soundbank);
           }
           seqr.getTransmitter().setReceiver(receiver);

        }
        catch(Exception e)
        {
           System.out.println("MIDI error: It appears your system doesn't have a MIDI device or your device is not working.");
        }
     }

     /**
     *  MidiPlayer(String fileName)
     *  Constructor that also loads an initial midi file.
     *  Preconditions: fileName is the name of the midi file to be loaded. 
     *  Postconditions: The MidiPlayer is created and loaded with the midi specified by fileName.
     **/

     public MidiPlayer(String fileName)
     {
        this();
        load(fileName);
     }


     // DATA METHODS

     /**
     *  load(String fileName)
     *  loads a midi file into this MidiPlayer.
     *  Preconditions: fileName is the name of the midi file to be loaded.
     *  Postconditions: fileName is loaded and is ready to be played.
     **/

     public void load(String fileName)
     {
        this.unload();
        try
        {
           URL midiURL =  getClass().getClassLoader().getResource(fileName);
           seq = MidiSystem.getSequence(midiURL);

           seqr.open();
           synth.open();

           // load our sequence into the sequencer.

           seqr.setSequence(seq);
           loaded = true;
           defaultTempo = seqr.getTempoInBPM();
        }
        catch(IOException ioe)
        {
           System.out.println("MIDI error: Problem occured while reading " + midiFile.getName() + ".");
        }
        catch(InvalidMidiDataException imde)
        {
           System.out.println("MIDI error: " + midiFile.getName() + " is not a valid MIDI file or is unreadable.");
        }
        catch(Exception e)
        {
           System.out.println("MIDI error: Unexplained error occured while loading midi.");
        }
     }

     /**
     *  unload()
     *  Unloads the current midi from the MidiPlayer and releases its resources from memory.
     **/

     public void unload()
     {
        this.stop();
        seqr.close();
        synth.close();
        midiFile = null;
        loaded = false;
     }

     // OTHER METHODS

     /**
     *  setMidiID(String id)
     *  associates a String ID with the current midi.
     *  Preconditions: id is the ID we are associating with the current midi.
     **/

     public void setMidiID(String id)
     {
        midiID = id;
     }

     /**
     *  getMidiID(String id)
     *
     **/

     public String getMidiID()
     {
        return new String(midiID);
     }

     /**
     *  play(boolean reset)
     *  plays the currently loaded midi.
     *  Preconditions: reset tells our midi whether or nor to begin playing from the start of the midi file's current loop start point.
     *  Postconditions: If reset is true, then the loaded midi begins playing from its loop start point (default 0). 
     *      If reset is false, then the loaded midi resumes playing from its current position.
     **/

     public void play(boolean reset)
     {
        if(reset)
           seqr.setTickPosition(seqr.getLoopStartPoint());
        seqr.start();
     }

     /**
     *  stop()
     *  Pauses the current midi if it was playing.
     **/

     public void stop()
     {
        if(seqr.isOpen())
           seqr.stop();
     }

     /**
     *  isRunning()
     *  Returns true if the current midi is playing. Returns false otherwise.
     **/

     public boolean isRunning()
     {
        return seqr.isRunning();
     }



     /**
     *  getTempo()
     *  Returns the current tempo of the MidiPlayer in BPM (Beats per Minute).
     **/

     public float getTempo()
     {
        return seqr.getTempoInBPM();
     }

     /**
     *  loop(int times)
     *  Sets the current midi to loop from start to finish a specific number of times.
     *  Preconditions: times is the number of times we want our midi to loop.
     *  Postconditions: The current midi is set to loop times times. 
     *      If times = -1, the current midi will be set to loop infinitely.
     **/

     public void loop(int times)
     {
        loop(times,0,-1);
     }

     /**
     *  loop(int times)
     *  Sets the current midi to loop from a specified start point to a specified end point a specific number of times.
     *  Preconditions: times is the number of times we want our midi to loop.
     *      start is our loop's start point in ticks.
     *      end is our loop's end point in ticks.
     *  Postconditions: The current midi is set to loop from tick start to tick end times times. 
     *      If times = -1, the current midi will be set to loop infinitely.
     **/

     public void loop(int times, long start, long end)
     {
        if(start < 0)
           start = 0;
        if(end > seqr.getSequence().getTickLength() || end <= 0)
           end = seqr.getSequence().getTickLength();

        if(start >= end && end != -1)
           start = end-1;

        seqr.setLoopStartPoint(start);
        seqr.setLoopEndPoint(end);

        if(times == -1)
           seqr.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
        else
           seqr.setLoopCount(times);

     }

     /**
     *  resetTempo()
     *  Resets the MidiPlayer's tempo the the initial tempo of its current midi.
     **/

     public void resetTempo()
     {
        this.changeTempo(this.defaultTempo);
     }

     /**
     *  changeTempo(float bpm)
     *  Changes the MidiPlayer's current tempo.
     *  Preconditions: bpm is the MidiPlayer's new tempo in BPM (Beats per Minute).
     *  Postconditions: The MidiPlayer's current tempo is set to bpm BPM.
     **/

     public void changeTempo(float bpm)
     {
        double lengthCoeff = bpm/seqr.getTempoInBPM();

        seqr.setLoopStartPoint((long) (seqr.getLoopStartPoint()*lengthCoeff));
        seqr.setLoopEndPoint((long) (seqr.getLoopEndPoint()*lengthCoeff));

        seqr.setTempoInBPM(bpm);
     }


     public void setVolume(double vol)
     {
        System.out.println("Midi volume change request: " + vol);

        try 
        {
           if(usingHardwareSoundbank)
           {
              ShortMessage volumeMessage = new ShortMessage();
              for ( int i = 0; i < 16; i++ ) 
              {
                 volumeMessage.setMessage( ShortMessage.CONTROL_CHANGE, i, 7, (int)(vol*127) );
                 receiver.send( volumeMessage, -1 );
              }
           }
           else
           {
              MidiChannel[] channels = synth.getChannels();

              for( int c = 0; c < channels.length; c++ )
              {
                 if(channels[c] != null) {
                    channels[c].controlChange( 7, (int)( vol*127) );
                 }
              }
           }
        } 
        catch ( Exception e ) 
        {
           e.printStackTrace();
        }
     }

  }