2017-12-08 4 views
0

Ich programmiere einen Audio Visualizer. Um die Daten, die angezeigt werden sollen, mit der Musik selbst zu synchronisieren, muss ich die aktuelle Position des Clips/Players in der Audiodatei abrufen, indem ich/aufrufen. Dies funktioniert gut für den Clip. Das Problem ist, dass ich das Player-Objekt in einem anderen Thread definieren muss, da der Aufruf player.play() die gesamte Ausführung im aktuellen Thread stoppt, bis die Datei bis zum Ende abgespielt wird. Player ist eine Klasse aus der MP3SPI-Bibliothek (javazoom.jl.player.Player).Rückgabevariable aus der in einem anderen Thread definierten Klasse

Code:

public class AudioTools implements Runnable { 

public File file; 
public boolean isMP3 = false; 
public Player player; 
public Clip clip; 

public AudioTools(File file) { 
    this.file = file; 
    determineFilyType(); 
} 

private void determineFileType() { 
    if (file.getAbsolutePath().endsWith(".mp3")) { 
     this.isMP3 = true; 
    } else if (file.getAbsolutePath().endsWith(".wav")) { 
     this.isMP3 = false; 
    } else { 
     System.err.println("Invalid File Type!"); 
     System.exit(0); 
    } 

} 

public void play() { 
    if (isMP3) { 
     Thread t = new Thread(this); 
     t.start(); // play MP3 using Player class 
    } else { 
     playWav(file); // play WAV using Clip class 
    } 

} 

protected void playMP3(File file){ 
    try { 
     player = new Player(new FileInputStream(file)); 
     player.play(); 
    } catch (Exception e) { 
     System.out.println("Invalid MP3 File!"); 
     e.printStackTrace(); 
     System.exit(0); 
    } 

} 

@Override 
public void run() { 
    playMP3(file); 
} 

private void playWav(File file) { 
    try { 
     AudioInputStream ais = AudioSystem.getAudioInputStream(file); 
     DataLine.Info dataInfo = new DataLine.Info(Clip.class, null); 
     clip = (Clip) AudioSystem.getLine(dataInfo); 
     clip.open(ais); 
     clip.start(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     System.err.println("Invalid .wav file!"); 
     System.exit(0); 
    } 
} 

}

Hauptklasse:

public static void main(String[] args) { 

File file = new File(/*PATH_TO_FILE_HERE*/); 
AudioTools at = new AudioTools(file); 
at.play(); 
// at.clip.getMicrosecondPosition() works here if loaded file is .wav. 
// at.player.getPosition() returns null if loaded file is .mp3. 
} 

Von der Hauptklasse, würde Ich mag Lage sein, die aktuelle Position des Spielers zu bekommen. Wenn Sie dies versuchen, wird null zurückgegeben.

Alle hilfreiche Kommentare sind willkommen. Ich habe vorher eine ähnliche Frage gestellt, diese Bearbeitung hat die Frage etwas klarer und kürzer gemacht.

EDIT: Sollte den gesamten Code enthalten, um das Beispiel auszuführen.

+0

Ein MCVE könnte helfen. –

Antwort

1

Ich bin mir nicht sicher, ob ich Ihre Frage vollständig verstanden habe, aber ich werde versuchen, Ihnen einige Dinge zu erklären.

Nehmen wir an, Sie haben eine Klasse Clip wo zu einer zufälligen Zeit von 300ms bis 1000ms (nur zum Beispiel) spielt eine Sekunde des Clips und setzt die Variable currentLength was ist, was Sie von anderen Thread erhalten möchten.

public class Clip implements Runnable { 

    private int clipLength; 

    private volatile int currentLength; 

    public Clip(int clipLength) { 
     this.clipLength = clipLength; 
    } 

    public void run() { 

     while (currentLength <= clipLength) { 
      try { 
       currentLength += 1; 
       Thread.sleep(ThreadLocalRandom.current().nextInt(300, 1000 + 1)); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

    public int getCurrentLength() { 
     return currentLength; 
    } 

    public void setCurrentLength(int currentLength) { 
     this.currentLength = currentLength; 
    } 

} 

lässt sich auch sagen, Sie haben eine Klasse Player und was es tut, ist, dass nimmt den Clip-Objekt und nach einiger Zeit fordert er die aktuelle Länge davon.

public class Player implements Runnable { 

    private Clip clip; 

    public Player(Clip clip) { 
     this.clip = clip; 
    } 

    public void run() { 
     try { 
      Thread.sleep(1000); 
      System.out.println(clip.getCurrentLength()); 
      Thread.sleep(2000); 
      System.out.println(clip.getCurrentLength()); 
      Thread.sleep(1000); 
      System.out.println(clip.getCurrentLength()); 
      Thread.sleep(3000); 
      System.out.println(clip.getCurrentLength()); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Auch wir haben eine Hauptklasse den Start des Programms containg, wo wir ein Clip-Objekt erstellen und an die zu runnable Klasse übergeben.

public class Main { 
    public static void main(String[] args) { 
     Clip clip = new Clip(60); 
     Thread thread = new Thread(clip); 
     thread.start(); 
     Thread threadPlayer = new Thread(new Player(clip)); 
     threadPlayer.start(); 

    } 

} 

Ich denke, das ist das, was Sie gefragt, aber bevor er zu Ihrem Programm implementieren es sollten Sie über atomic access and volatile keyword lesen und auch gut über die Java memory model.

+0

Danke! Interessantes gelesen, obwohl es meine Frage nicht ganz beantwortet hat. – mindoverflow

0

mit einem anderen Ansatz gelöst zu wissen, dass nicht einmal ist Teil der Frage. Ich hatte bereits ein Array der entschlüsselten Audiodaten, die ich in einen AudioInputStream verwandeln kann, den Clip abspielen kann.

Verwandte Themen