2012-06-09 16 views
5

Ho cercato di far funzionare il controllo del volume midi in una classe MidiPlayer per molto tempo. Ho cercato degli esempi per realizzare questo qui su StackOverflow e su Internet, ma nulla di quello che ho provato sembra funzionare. Il volume rimane lo stesso! Non cambia come voglio io.Il controllo del volume midi Java non funzionerà

Sto eseguendo Java 1.6.0_32 su Windows 7 Professional.

Qui! Avere SSCCE:

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

    public class MidiSSCCE { 
    public static void main(String[] args) 
    { 
     // creates the midi player and sets up its sequencer and synthesizer. 
     MidiPlayer midiP = new MidiPlayer();  
     double volume = 1.0; 

     // loads a midi from a url into the sequencer, but doesn't start playing it yet. 
     midiP.load("http://www.vgmusic.com/music/computer/microsoft/windows/touhou_6_stage3_boss.mid",true); 

     // set the midi to loop indefinitely. 
     midiP.loop(-1); 

     // start playing the midi. 
     midiP.play(true); 

     // while loop changes the volume of the midi while it is playing. 
     while(true) { 
      midiP.setVolume(volume); 
      try { Thread.sleep(300); } catch(Exception e) {} 
      volume -= 0.1; 
      if(volume < 0) volume += 1.0; 
     } 
    } 
    } 

    /** 
    * MidiPlayer 
    * author: Stephen Lindberg 
    * Last modified: Oct 14, 2011 
    * 
    * 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 { 
      // obtain the sequencer and synthesizer. 
      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 soundbank and receiver. 
      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: I just don't know what went wrong! 6_9"); 
     } 
    } 


    // 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, boolean isOnline) { 
     this.unload(); 
     try { 
      URL midiURL; 
      if(isOnline) midiURL = new URL(fileName); 
      else midiURL = getClass().getClassLoader().getResource(fileName); 

      seq = MidiSystem.getSequence(midiURL); 

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

      // load our sequence into the sequencer. 

      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: I just don't know what went wrong! 6_9"); 
     } 
    } 

    /** 
    * 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 


    /** 
    * 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) { 
     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(); 
     } 
    } 

    } 

Ho provato esempi ai seguenti fonti senza successo:

http://www.java2s.com/Code/Java/Development-Class/SettingtheVolumeofPlayingMidiAudio.htm

How to controll the MIDI channel's volume

https://forums.oracle.com/forums/thread.jspa?messageID=5389030

MIDI Song with CC

http://www.codezealot.org/archives/27

http://www.exampledepot.com/egs/javax.sound.midi/Volume.html

+0

Questo è bello. Puoi descrivere "cosa non funziona"? (E magari inserire un riassunto nel titolo.) –

+0

Ho dimenticato di mettere "Volume" nel titolo. È il cambio di volume che non funziona per me. Sembra che funzioni correttamente per te? – Cazra

+0

Il cambio di volume funziona se * prima * il MIDI inizia a suonare? –

risposta

1
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)); 
      } 
     } 
     // Very important! 
     seqr.setSequence(seq); 
    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
+1

Questo ha cambiato qualcosa ... ma non il volume. Quando ho aggiunto quella linea, i cambi di tempo sembrano non avere più effetto durante la riproduzione midi .. – Cazra

3

sto lottando con questi problemi molto sul controllo del suono e ho trovato un codice per modificare il volume che funziona. Unfurtunatly non ero in grado di capirlo, ma qui c'è qualcosa nel tuo codice che è diverso da quello che ho visto. Forse può aiutarti. Prova modificare la linea

seqr = MidiSystem.getSequencer(); 

per

seqr = MidiSystem.getSequencer(false); 

Forse ti aiuta, credo che utilizzando il "falso" il sequencer si collegherà al ricevitore, e non al sintetizzatore, poi quando si invia il messaggio al destinatario per impostare il volume che funzionerà.