Hallo, ich habe eine Aufgabe bekommen, in der ich mit Java Musik machen soll. Ich arbeite mit Eclipse. Ich habe folgende Idee: Wenn man als Nutzer eine Tonleiter angibt (z.B. C-Dur) dann kommt eine Melodie in C-Dur. Und wenn man eine andere eingibt, kommt die gleiche Melodie in der anderen. Die Melodie würde ich dann selber spielen und einbauen.
Ich habe es schonmal geschafft, dass wenn ich ausführe eine Melodie kommt. Doch wie mache ich, dass der Nutzer erst eingeben muss, wie die Melodie ist? Dachte mir so mit if, weiß aber von selbst nicht genau wie das geht.
@kaoZ:
Weshalb generierst du die Buttons + Labels mit Schleifen? Macht das Sinn, für spätere Änderungen? Du legst hier ja doch ein statisches JButton Objekt mit 6 Objekten an, sprich auch hier müsste man dann eine Änderung vornehmen.
Würde mich interessieren, ansonsten ganz nettes Projekt!
Ok dann weiter im Text, da wir das ganze ja nicht nach einem Design Pattern wie z.B MVC umsetzen , werden wir einfach unserer Gui als Attribut eine Referenz auf unseren AudioPlayer geben.
in unserem Konstruktor der Klasse Gui werden wir nun diesen initialisieren, außerdem werden wir hier gleich die möglichkeit geben eine playlist an die Gui und somit an den Konstruktor des AudioPlayers zu geben :
nun werden wir noch über unseren listener definieren was beim klick auf die einzelnen Buttons passieren soll, also werden wir an dieser Stelle in der Gui folgenden code in der actionPerformed Methode abändern :
importjava.awt.BorderLayout;importjava.awt.Dimension;importjava.awt.Font;importjava.awt.GridLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjavax.swing.BorderFactory;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.JPanel;publicclassGuiextendsJFrameimplementsActionListener{privatestaticfinallong serialVersionUID =1L;publicfinalstaticDimension GUI_SIZE =newDimension(400,300);publicfinalstaticString GUI_TITLE ="Audio Player v1.0";privateJPanel contentPane;privateJPanel headerPane;privateAudioPlayer player;privateJButton[] btns;publicGui(Sound...sounds){setSize(GUI_SIZE);setTitle(GUI_TITLE);setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);setLocationRelativeTo(null);this.contentPane =newJPanel(newGridLayout(3,2,20,20));this.contentPane.setBorder(BorderFactory.createEmptyBorder(30,30,30,30));this.headerPane =newJPanel();this.btns =newJButton[6];this.player =newAudioPlayer(sounds);createComponents();}privatevoidcreateComponents(){JLabel header =newJLabel("<Html>Mit welchem Instrument soll 'Suit'<br>"+"von R.CH.Martin gespielt werden ?</Html>",JLabel.CENTER);Font newFont = header.getFont().deriveFont(14f);
header.setFont(newFont);String[] label ={"Bandoneon","Harfe","Blockflöte","Klavier","Glockenspiel","Orgel"};for(int i =0; i < btns.length; i++){
btns[i]=newJButton(label[i]);
btns[i].addActionListener(this);}for(int i =0; i < btns.length; i++){
contentPane.add(btns[i]);}this.headerPane.add(header);this.add(BorderLayout.PAGE_START, headerPane);this.add(BorderLayout.CENTER, contentPane);}@OverridepublicvoidactionPerformed(ActionEvent e){switch(e.getActionCommand()){case"Bandoneon":
player.play(player.getSongByName("one"));break;case"Harfe":
player.play(player.getSongByName("two"));break;case"Blockflöte":
player.play(player.getSongByName("three"));break;case"Klavier":
player.play(player.getSongByName("four"));break;case"Glockenspiel":
player.play(player.getSongByName("five"));break;case"Orgel"://player.play(player.getSongByName(""));break;}}}
In der Klasse AudioTest erzeugen wir nun ein Sound Array was uns als Playlist für unseren Player dient, und übergeben diesen an unsere Gui und somit an den dadurch referenzierten AudioPlayer:
wenn du die Anwendung nun startest , solltest du sehen können das zwar der Sound Abgespielt wird, aber solange dies der Fall ist der Button den du betätigst hast quasi blockiert wird und gedrückt bleibt, dies liegt daran das das abspielen der Sounds hier im gleichen Thread passiert
in welchem auch die Gui arbeitet , dieser nennt sich EDT, und man sollte immer vermeiden, längere und komplexe Aktionen in diesem Thread auszuführen , da sonst eben das Gui solange blockiert wird , wie die zusätzlich ausgeführte Aktion andauert.
Also wird der nächste logische Schritt sein das wir das abspielen der Sounds in einen Separaten Thread auslagern müssen und Benutzeraktionen nicht zu behindern.
Wenn du soweit bist und es ausprobiert hast und alles so funtkioniert wie es hier beschrieben ist getst weiter, wir sind nichtmehr weit vom Ziel entfernt
@kaoZ:
Weshalb generierst du die Buttons + Labels mit Schleifen? Macht das Sinn, für spätere Änderungen? Du legst hier ja doch ein statisches JButton Objekt mit 6 Objekten an, sprich auch hier müsste man dann eine Änderung vornehmen.
Einfach der Übersichtlichkeits halber, ist aber geschmackssache,
klar könnte man auch jeden Button über eine eigenes Attribut definieren, ich finde aber bei solch kleinen Projekten wesentlich übersichtlicher.
Zudem spare ich mir nen haufen Source Code , man könnte sogar noch weiter gehen und das ganze in einer doppelten for schleifen machen , dann allerdings wird das ganze ziemlich kryptisch.
wenn ich dann einen speziellen button benötige kann ich diesen immernoch über seinen index im Array ansprechen.
[EDIT]Wenn du natürlich im Vorfeld schon weißt das sich der ButtonText ggf. ändern könnte , vielleicht weil du ihn über die Songs in der Playlist generieren würdest, dann kannst du die Buttons auch einzeln als Attribut der Gui deklarieren, würde aber auch mit einem Array wie in meinem Beispiel funktionieren.[/EDIT]
[EDIT]
Du legst hier ja doch ein statisches JButton Objekt mit 6 Objekten an
Also ich hab versucht das so zu machen, aber ersetzt man mit dem was du zum AudioPlayer geschrieben hast das andere wo die files schon definiert sind?
Ich hab das probiert, hab auch mit beiden probiert, aber es kommen immer nur Fehlermeldungen.
Java:
package samples;importjava.util.Scanner;//Die Klasse Scanner ist in dem Paket java.util definiert.publicclassAudioTest2{Scanner sc;AudioPlayer player;String path;//sc repräsentiert den Scanner, der Scanner definiert Methoden zum Einlesen von Dateien publicAudioTest2(){
sc =newScanner(System.in);//Der Scanner liest normalerweise eine Datenquelle, hier die Konsolenangabe.
player =newAudioPlayer();
path ="C:/Users/Ela/Music/";//Der Pfad zu der .wav Datei, welcher abgespiel werden soll.fillPlaylist();//Diese Methode initialisiert die Playlist}//Die Sounddateien werden in der Playlist angegeben, um sie dann als Nutzer auszuwählen.publicstaticvoidmain1(String[] args){String path ="C:/Users/Ela/Music/";Sound[] playlist =newSound[6];
playlist[0]=newSound("one",path +"Bandoneon.wav");
playlist[1]=newSound("two",path +"Blockflöte.wav");
playlist[2]=newSound("three",path +"Glockenspiel.wav");
playlist[3]=newSound("four",path +"Harfe.wav");
playlist[4]=newSound("five",path +"Klavier.wav");
playlist[5]=newSound("six",path +"Orgel.wav");newGui(playlist).setVisible(true);}publicvoidstartSession(){boolean running =true;System.out.println("Hier können Sie sich für ein Instrument entscheiden, auf dem das Lied 'Suit' von R.Ch.Martin gespielt werden soll!");System.out.println("");System.out.println("1. Geben Sie als erstes 'Instrument' ein, um eine Übersicht zu erhalten.");System.out.println("2. Als nächstes geben Sie den Namen eines Instrumentes ein, um sie abzuspielen. Dies können Sie beliebig oft wiederholen.");System.out.println("3. Wenn Sie den Player beenden wollen, geben Sie 'stop' ein.");System.out.println("");System.out.println("***********************************************************************************************");while(running){String input = sc.nextLine();if(input.equals("Instrument")){System.out.println("");for(int i =0; i < player.getPlayList().size(); i++){System.out.println(player.getPlayList().get(i).getName());}continue;}if(input.equals("stop")){
running =false;
sc.close();System.out.println("Der Player wurde beendet. Hoffentlich haben Sie die Musik genossen!");System.out.println("Ich wünsche Ihnen noch einen schönen Tag!");}while(running){System.out.println("Das Lied wird mit "+ input +" gespielt. Viel Vergnügen!");
player.play(player.getSongByName(input));break;}}}publicAudioPlayergetPlayer(){returnthis.player;}publicstaticvoidmain(String[] args){newGui().setVisible(true);//Die Main Methode dient dazu um das Programm zu starten und die startSession(); Methode aufzurufen.}}
Hier mal die ganze Klasse AudioTest wie sie aussehen sollte
Java:
importjava.util.Scanner;publicclassAudioTest{Scanner sc;AudioPlayer player;String path;publicAudioTest(){
sc =newScanner(System.in);
player =newAudioPlayer();
path ="L:/OpenOffice/share/gallery/sounds/";fillPlaylist();}publicvoidfillPlaylist(){Sound one =newSound("one",path +"cow.wav");Sound two =newSound("two",path +"curve.wav");Sound three =newSound("three",path +"drama.wav");Sound four =newSound("four",path +"explos.wav");Sound five =newSound("five",path +"falling.wav");getPlayer().addToPlayList(one, two, three, four, five);}publicvoidstartSession(){boolean running =true;System.out.println("Willkommen beim AudioPlayer");System.out.println("***************************");System.out.println("- Gibt 'songlist' ein um eine Titelübersicht zu erhalten,");System.out.println("- gibt den Namen eines Sounds ein um ihn abzuspielen,");System.out.println("- gib 'remove' ein um einen Song aus der Playlist zu entfernen,");System.out.println("- oder 'stop' um den Player zu beenden.");System.out.println("_______________________________________");while(running){String input = sc.nextLine();if(input.equals("songlist")){System.out.println("Songlist");System.out.println("********");for(int i =0; i < player.getPlayList().size(); i++){System.out.println("Sound "+ i +": "+ player.getPlayList().get(i).getName());}continue;}if(input.equals("remove")){System.out.println("Geben Sie den Namen der Sounds ein den Sie entfernen möchten :");String sound = sc.nextLine();for(int i =0; i < player.getPlayList().size(); i++){if(player.getPlayList().get(i).getName().equals(sound)){
player.removeFromPlayList(sound);}}continue;}if(input.equals("stop")){
running =false;
sc.close();}while(running){
player.play(player.getSongByName(input));break;}}}publicAudioPlayergetPlayer(){returnthis.player;}publicstaticvoidmain(String[] args){String path ="L:/OpenOffice/share/gallery/sounds/";Sound[] playlist =newSound[5];
playlist[0]=newSound("one",path +"cow.wav");
playlist[1]=newSound("two",path +"curve.wav");
playlist[2]=newSound("three",path +"drama.wav");
playlist[3]=newSound("four",path +"explos.wav");
playlist[4]=newSound("five",path +"falling.wav");//new AudioTest().startSession(); // <<-- auskommentiert da nicht benutzt!newGui(playlist).setVisible(true);}}
Ich wollte dir damit eigentlich zeigen das du sowohl die Konsolenversion nutzen als auch die GuiVersion nutzen kannst, je nachdem von welcher Klasse du eine Instanz erzeugst, AudioTest für die KonsolenVersion, und Gui für die Version mit Grafischer Darstellung, wenn du das nicht nachvollziehen kannst können wir sonst auch eine gesonderte Klasse erstellen die die main Methode beinhaltet, falls dich das zu sehr verunsichern sollte
Jetzt hab ich es so gemacht und dann erscheint die fehlermeldung:
Exception in thread "main" java.lang.NullPointerException
at samples.AudioPlayer.addToPlayList(AudioPlayer.java:24)
at samples.AudioPlayer.<init>(AudioPlayer.java:20)
at samples.Gui.<init>(Gui.java:44)
at samples.AudioTest2.main(AudioTest2.java:102)
Also bei mir bleibt der Button so lange gedrückt wie das Lied lang ist, danach kann ich ein weiteres auswählen! Das ist doch das was ich wollte, oder fällt da noch etwas?
um genau dies zu beheben , werden wir die play() Methode der Klasse AudioPlayer , so um schrieben das das Abspielen der Sounds in einem eigenen Thread stattfindet:
nun kannst du sogar mehrere Sounds gleichzeitig abspielen , da jeder Sound in einem Separaten Thread abgespielt wird.
dies lässt sich ganz einfach folgendermaßen umsetzen :
hier hab ich mal den alten teil auskommentiert :
Java:
publicvoidplay(Sound song){try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){// Nur zum testen so implementiert};}catch(Exception e){if(song ==null){JOptionPane.showMessageDialog(null,"Sound wurde nicht gefunden !");}}}}.start();}catch(Exception ex){
ex.printStackTrace();}/* try {
AudioInputStream stream = AudioSystem.getAudioInputStream(song.getFile());
AudioFormat audioFormat = stream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(stream);
clip.start();
while(clip.getFramePosition() < clip.getFrameLength()) {
// Nur zum testen so implementiert
};
} catch (Exception e) {
if (song == null) {
System.out.println("Song wurde nicht in der Playlist gefunden, oder Existiert nicht !");
}
} */}
hier wird nun bei jedem aufruf dieser Methode ein neuer Thread gestartet, dessen Task , oder in dem Fall Runnable es ist die Daten aus dem Stream zu lesen, in einen Clip umzuwandeln und abzuspielen.
[EDIT]
Zugegeben das mit der Fehlerbehandlung ist eher unschön und Suboptimal , aber für ein einfaches Beispiel ausreichend und funktionsfähig!
[/EDIT]
Du kannst nun selbst bestimmen, ob du deine Anwendung in der Konsolenversion, oder mit der Gui startest.
dies kannst du in der Klasse AudioTest.java ganz einfach ausprobieren indem du ganz mal an dieser Stelle die Gui auskommentierst und eine Instanz der Klasse AudioTest erstellst
Das mit dem selbst bestimmen habe ich anders geregelt, ich habe AudioTest2 erstellt und das ist für GUI und das normale für Konsole, also das hatte ich schon.
Jetz habe ich Audioplayer bearbeitet und bei mir erscheint eine fehlermeldung, zudem ist "getPlayList().add" ; "(song.getFile());" ; "(song == null)" unterstrichen und auch die aller letzte } Klammer
Java:
//Der AudioPlayer spielt die Sounds ab.package samples;importjava.util.ArrayList;importjavax.sound.sampled.AudioFormat;importjavax.sound.sampled.AudioInputStream;importjavax.sound.sampled.AudioSystem;importjavax.sound.sampled.Clip;importjavax.sound.sampled.DataLine;publicclassAudioPlayer{privateArrayList<Sound> playList;publicAudioPlayer(){//Mit "public ..." werden die Methoden definiert ↓
playList =newArrayList<>();}publicAudioPlayer(Sound...songs){
playList =newArrayList<>();addToPlayList(songs);}publicvoidaddToPlayList(Sound...songs){for(Sound sound : songs){getPlayList().add(sound);}}publicvoidremoveFromPlayList(Sound sound){for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(sound)){
playList.remove(i);}}}publicSoundgetSongByName(String name){Sound sound =null;for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(name)){
sound = playList.get(i);}}return sound;}publicvoidplay(Sound song){//Hier werden die Lieder abgespielt.try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){// Nur zum testen so implementiert};}catch(Exception e){if(song ==null){System.out.println("Song wurde nicht in der Playlist gefunden, oder Existiert nicht !");}}}}.start();}catch(Exception ex){
ex.printStackTrace();}}// Auch die Playlist kann durch ein mehrfaches Eingeben wiederholt werden.
da fehlt unten auch eine Klammer , und der öffentliche Getter , also die Methode
Code:
getPlayList()
Java:
importjava.util.ArrayList;importjavax.sound.sampled.AudioFormat;importjavax.sound.sampled.AudioInputStream;importjavax.sound.sampled.AudioSystem;importjavax.sound.sampled.Clip;importjavax.sound.sampled.DataLine;importjavax.swing.JOptionPane;publicclassAudioPlayer{privateArrayList<Sound> playList;publicAudioPlayer(){
playList =newArrayList<>();}publicAudioPlayer(Sound...songs){
playList =newArrayList<>();addToPlayList(songs);}publicvoidaddToPlayList(Sound...songs){for(Sound sound : songs){getPlayList().add(sound);}}publicvoidremoveFromPlayList(String sound){for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(sound)){
playList.remove(i);}}System.out.println(sound +" wurde aus der Playlist entfernt!");}//Achtung , kann NPE auslösen , hier ist handlungsbedarf !publicSoundgetSongByName(String name){Sound sound =null;for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(name)){
sound = playList.get(i);}}return sound;}publicvoidplay(Sound song){try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){// Nur zum testen so implementiert};}catch(Exception e){if(song ==null){JOptionPane.showMessageDialog(null,"Sound wurde nicht gefunden !");}}}}.start();}catch(Exception ex){
ex.printStackTrace();}}publicArrayList<Sound>getPlayList(){returnthis.playList;}}
Jetzt ist immernoch was unterstrichen und wenn ich Klavier eingeben kommt das:
Klavier
Das Lied wird mit Klavier gespielt. Viel Vergnügen!
Exception in thread "Thread-1" java.lang.Error: Unresolved compilation problems:
Cannot refer to a non-final variable song inside an inner class defined in a different method
Cannot refer to a non-final variable song inside an inner class defined in a different method
und den Code der Klasse den du ausführen möchtest,
normalerweise sollte alles Funktionieren da wir die Variable song vom Typ Sound nur an einer Stelle in der inneren Klasse verwenden,
ansonsten füge an dieser stelle mal ein final hinzu:
Java:
publicvoidplay(finalSound song){// <---try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){// Nur zum testen so implementiert};}catch(Exception e){if(song ==null){JOptionPane.showMessageDialog(null,"Sound wurde nicht gefunden !");}}}}.start();}catch(Exception ex){
ex.printStackTrace();}}
Mit final ist es besser, aber wenn ich was falsches eingebe erscheint nicht das was soll, sondern er will das falsche abspielen.
Java:
//Der AudioPlayer spielt die Sounds ab.package samples;importjava.util.ArrayList;importjavax.sound.sampled.AudioFormat;importjavax.sound.sampled.AudioInputStream;importjavax.sound.sampled.AudioSystem;importjavax.sound.sampled.Clip;importjavax.sound.sampled.DataLine;importjavax.swing.JOptionPane;publicclassAudioPlayer{privateArrayList<Sound> playList;publicAudioPlayer(){//Mit "public ..." werden die Methoden definiert ↓
playList =newArrayList<>();}publicAudioPlayer(Sound...songs){
playList =newArrayList<>();addToPlayList(songs);}publicvoidaddToPlayList(Sound...songs){for(Sound sound : songs){getPlayList().add(sound);}}publicvoidremoveFromPlayList(Sound sound){for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(sound)){
playList.remove(i);}}System.out.println(sound +" wurde aus der Playlist entfernt!");}publicSoundgetSongByName(String name){Sound sound =null;for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(name)){
sound = playList.get(i);}}return sound;}publicvoidplay(finalSound song){try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){};}catch(Exception e){if(song ==null){JOptionPane.showMessageDialog(null,"Sound wurde nicht gefunden !");}}}}.start();}catch(Exception ex){
ex.printStackTrace();}}publicArrayList<Sound>getPlayList(){returnthis.playList;}}// Auch die Playlist kann durch ein mehrfaches Eingeben wiederholt werden.
Das liegt daran das wie uns noch nicht um anständige Fehler/Ausnahme Behandlung Gekümmert haben, hatte ich aber schon mehrfach erwähnt bin jetzt allerdings auch erstmal unterwegs.
Schaue mir das später nochmal an
Um dies zu umgehen das wenn du etwas eingibst was in der Playlist nicht existiert könntest du folgendes machen, da du ja 2 Versionen hast, hier eine lösung für die Konsolenvariante des Players :
Hier in der p
Code:
lay()
Methode des AudioPlayers
Java:
publicvoidplay(finalSound song){newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){};}catch(NullPointerException|IOException|UnsupportedAudioFileException|LineUnavailableException e){if(e instanceofNullPointerException){System.out.println("Dieser Song exestiert in der PlayList nicht !");}else{System.out.println("Folgender Fehler ist augetretten : "+ e.toString());//JOptionPane.showMessageDialog(null, "Folgender Fehler ist aufgetretten : " + e.toString());/* Muti-Catch lösung, hier wird bei einem Fehler die Anwendung weiter Ausgeführt,
* bei einer NPE wird hier gesondert ausgegeben das ein Sound mit diesem Namen nicht
* in der Playlist existiert, anderfalls wird
* der User aber über das Auftreten eines nicht normalen
* Programmverhaltens informiert!
*/}}}}.start();}
Es gäbe auch noch die Möglichkeit im Methodenkopf zu deklarieren das eine Ausnahme geworfen werden könnte, dies würde man dann so deklarieren:
Java:
publicvoidplay(Sound song)throwsException{....}
hier würde man dann die Exception an den Aufrufer dieser Methode delegieren und die Ausnahme nicht gleich behandeln, (hätten wir vorher gewusst das wir eine Gui Schreiben) hätte man gleich zu beginn dafür sorgen können hier mit Delegation zu arbeiten und die Fehlerbehandlung entweder durch die Gui, z.B durch das anzeigen eines Dialoges, oder durch die Klasse AudioTest in Form von gezielten und aussagekräftigen Konsolenausgaben zu realisieren.
Da wir bei der Gui Version hier selbst dafür verantwortlich sind welche sounds wir in die Playlist übergeben, können wir dies hier mehr oder weniger vernachlässigen da wir festlegen welcher Button welches Lied abspielt , anders bei der Konsolenversion, bei der der User ( und wir gehen im Normalfall immer vom DAU aus ) die Eingabe macht, wenn du nun die oben zuerst genannte Lösung nutzt sollte es so aussehen :
Code:
Willkommen beim AudioPlayer
***************************
- Gibt 'songlist' ein um eine Titelübersicht zu erhalten,
- gibt den Namen eines Sounds ein um ihn abzuspielen,
- gib 'remove' ein um einen Song aus der Playlist zu entfernen,
- oder 'stop' um den Player zu beenden.
_______________________________________
sdfsdf
Dieser Song existiert in dieser Playlist nicht !
Hier nochmal eine übersicht der Klassen wie sie nun bei mir aussehen :
Java:
importjava.io.File;/**
*
* @author kaoZ
*
* Diese Klasse hat keine andere Funktion als lediglich
* den Pfad und einen Namen zu einer AudioDatei zu speichern,
* man könnte also sagen Objekte dieser Klasse sind unsere Sounds,
* welche wir später abspielen wollen.
*
*/publicclassSound{privateString name;privateFile file;publicSound(String name,String filePath){this.name = name;this.file =newFile(filePath);}publicStringgetName(){returnthis.name;}publicFilegetFile(){returnthis.file;}}
Java:
importjava.io.IOException;importjava.util.ArrayList;importjavax.sound.sampled.AudioFormat;importjavax.sound.sampled.AudioInputStream;importjavax.sound.sampled.AudioSystem;importjavax.sound.sampled.Clip;importjavax.sound.sampled.DataLine;importjavax.sound.sampled.LineUnavailableException;importjavax.sound.sampled.UnsupportedAudioFileException;publicclassAudioPlayer{privateArrayList<Sound> playList;publicAudioPlayer(){
playList =newArrayList<>();}publicAudioPlayer(Sound...songs){
playList =newArrayList<>();addToPlayList(songs);}publicvoidaddToPlayList(Sound...songs){for(Sound sound : songs){getPlayList().add(sound);}}publicvoidremoveFromPlayList(String sound){for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(sound)){
playList.remove(i);}}System.out.println(sound +" wurde aus der Playlist entfernt!");}//Achtung , kann NPE auslösen , hier ist handlungsbedarf !publicSoundgetSongByName(String name){Sound sound =null;for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(name)){
sound = playList.get(i);}}return sound;}publicvoidplay(finalSound song){newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){};}catch(NullPointerException|IOException|UnsupportedAudioFileException|LineUnavailableException e){if(e instanceofNullPointerException){System.out.println("Dieser Song existiert in dieser Playlist nicht !");}else{System.out.println("Folgender Fehler ist aufgetretten : "+ e.toString());}}}}.start();}publicArrayList<Sound>getPlayList(){returnthis.playList;}}
Java:
importjava.util.Scanner;publicclassAudioTest{Scanner sc;AudioPlayer player;String path;publicAudioTest(){
sc =newScanner(System.in);
player =newAudioPlayer();
path ="L:/OpenOffice/share/gallery/sounds/";fillPlaylist();}publicvoidfillPlaylist(){Sound one =newSound("one",path +"cow.wav");Sound two =newSound("two",path +"curve.wav");Sound three =newSound("three",path +"drama.wav");Sound four =newSound("four",path +"explos.wav");Sound five =newSound("five",path +"falling.wav");getPlayer().addToPlayList(one, two, three, four, five);}publicvoidstartSession(){boolean running =true;System.out.println("Willkommen beim AudioPlayer");System.out.println("***************************");System.out.println("- Gibt 'songlist' ein um eine Titelübersicht zu erhalten,");System.out.println("- gibt den Namen eines Sounds ein um ihn abzuspielen,");System.out.println("- gib 'remove' ein um einen Song aus der Playlist zu entfernen,");System.out.println("- oder 'stop' um den Player zu beenden.");System.out.println("_______________________________________");while(running){String input = sc.nextLine();if(input.equals("songlist")){System.out.println("Songlist");System.out.println("********");for(int i =0; i < player.getPlayList().size(); i++){System.out.println("Sound "+ i +": "+ player.getPlayList().get(i).getName());}continue;}if(input.equals("remove")){System.out.println("Geben Sie den Namen der Sounds ein den Sie entfernen möchten :");String sound = sc.nextLine();for(int i =0; i < player.getPlayList().size(); i++){if(player.getPlayList().get(i).getName().equals(sound)){
player.removeFromPlayList(sound);}}continue;}if(input.equals("stop")){
running =false;
sc.close();}while(running){
player.play(player.getSongByName(input));break;}}}publicAudioPlayergetPlayer(){returnthis.player;}publicstaticvoidmain(String[] args){String path ="L:/OpenOffice/share/gallery/sounds/";Sound[] playlist =newSound[5];
playlist[0]=newSound("one",path +"cow.wav");
playlist[1]=newSound("two",path +"curve.wav");
playlist[2]=newSound("three",path +"drama.wav");
playlist[3]=newSound("four",path +"explos.wav");
playlist[4]=newSound("five",path +"falling.wav");newAudioTest().startSession();//new Gui(playlist).setVisible(true);}}
Java:
importjava.awt.BorderLayout;importjava.awt.Dimension;importjava.awt.Font;importjava.awt.GridLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjavax.swing.BorderFactory;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.JPanel;publicclassGuiextendsJFrameimplementsActionListener{privatestaticfinallong serialVersionUID =1L;publicfinalstaticDimension GUI_SIZE =newDimension(400,300);publicfinalstaticString GUI_TITLE ="Audio Player v1.0";privateJPanel contentPane;privateJPanel headerPane;privateAudioPlayer player;privateJButton[] btns;publicGui(Sound...sounds){setSize(GUI_SIZE);setTitle(GUI_TITLE);setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);setLocationRelativeTo(null);this.contentPane =newJPanel(newGridLayout(3,2,20,20));this.contentPane.setBorder(BorderFactory.createEmptyBorder(30,30,30,30));this.headerPane =newJPanel();this.btns =newJButton[6];this.player =newAudioPlayer(sounds);createComponents();}privatevoidcreateComponents(){JLabel header =newJLabel("<Html>Mit welchem Instrument soll 'Suit'<br>"+"von R.CH.Martin gespielt werden ?</Html>",JLabel.CENTER);Font newFont = header.getFont().deriveFont(14f);
header.setFont(newFont);String[] label ={"Bandoneon","Harfe","Blockflöte","Klavier","Glockenspiel","Orgel"};for(int i =0; i < btns.length; i++){
btns[i]=newJButton(label[i]);
btns[i].addActionListener(this);}for(int i =0; i < btns.length; i++){
contentPane.add(btns[i]);}this.headerPane.add(header);this.add(BorderLayout.PAGE_START, headerPane);this.add(BorderLayout.CENTER, contentPane);}@OverridepublicvoidactionPerformed(ActionEvent e){switch(e.getActionCommand()){case"Bandoneon":
player.play(player.getSongByName("one"));break;case"Harfe":
player.play(player.getSongByName("two"));break;case"Blockflöte":
player.play(player.getSongByName("three"));break;case"Klavier":
player.play(player.getSongByName("four"));break;case"Glockenspiel":
player.play(player.getSongByName("five"));break;case"Orgel"://player.play(player.getSongByName(""));break;}}}
Hierbei enthält die Klasse AudioTest die main Methode, diese könnte man auch einfach um ein besseres Verständniss dafür zu bekommen in eine andere beliebige Klasse auslagern , und die Klasse AudioTest.java z.B in KonsolenVersion.java umbenennen.
Also ich habe jetzt AudioPlayer bearbeitet und er sieht nun so aus:
Java:
//Der AudioPlayer spielt die Sounds ab.package samples;importjava.io.IOException;importjava.util.ArrayList;importjavax.sound.sampled.AudioFormat;importjavax.sound.sampled.AudioInputStream;importjavax.sound.sampled.AudioSystem;importjavax.sound.sampled.Clip;importjavax.sound.sampled.DataLine;importjavax.sound.sampled.LineUnavailableException;importjavax.sound.sampled.UnsupportedAudioFileException;importjavax.swing.JOptionPane;publicclassAudioPlayer{privateArrayList<Sound> playList;publicAudioPlayer(){//Mit "public ..." werden die Methoden definiert ↓
playList =newArrayList<>();}publicAudioPlayer(Sound...songs){
playList =newArrayList<>();addToPlayList(songs);}publicvoidaddToPlayList(Sound...songs){for(Sound sound : songs){getPlayList().add(sound);}}publicSoundgetSongByName(String name){Sound sound =null;for(int i =0; i < playList.size(); i++){if(playList.get(i).getName().equals(name)){
sound = playList.get(i);}}return sound;}publicvoidplay(finalSound song)throwsException{try{newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){};}catch(NullPointerException|IOException|UnsupportedAudioFileException|LineUnavailableException e){if(song ==null){JOptionPane.showMessageDialog(null,"Sound wurde nicht gefunden !");}else{System.out.println("Folgender Fehler ist aufgetretten : "+ e.toString());}}}}.start();}catch(Exception ex){
ex.printStackTrace();}}publicArrayList<Sound>getPlayList(){returnthis.playList;}}// Auch die Playlist kann durch ein mehrfaches Eingeben wiederholt werden.
Doch bei Gui wird bei jedem Instrument diese Zeile unterstrichen: player.play(player.getSongByName("Bandoneon"));
Entferne das throws Exception in Methodenkopf der play Methode da du im Catch block schon für behandlung eventuell auftretender Ausnahmen sorgst brauchst du das dort nicht.
Es war nur ein Beispiel wie man es anders machen könnte.
Dad liegt daran das du in deiner Klasse AudioTest irgendwo die Ausgabe Erzeugst das der aktuelle Sound gespielt wird bevor geprüfte wird ob dieser vorhanden ist, poste mal deine Klasse AudioTest
[EDIT]da ich arbeiten bin Scheibe ich zzt. Von Handy aus, sonst muss ich heute abend nochmal drüber schauen [/EDIT]
package samples;importjava.util.Scanner;//Die Klasse Scanner ist in dem Paket java.util definiert.publicclassKonsolenVersion{Scanner sc;AudioPlayer player;String path;//sc repräsentiert den Scanner, der Scanner definiert Methoden zum Einlesen von Dateien publicKonsolenVersion(){
sc =newScanner(System.in);//Der Scanner liest normalerweise eine Datenquelle, hier die Konsolenangabe.
player =newAudioPlayer();
path ="C:/Users/Ela/Music/";//Der Pfad zu der .wav Datei, welcher abgespiel werden soll.fillPlaylist();//Diese Methode initialisiert die Playlist}publicvoidfillPlaylist(){Sound b =newSound("Bandoneon",path +"Bandoneon.wav");Sound f =newSound("Blockflöte",path +"Blockflöte.wav");Sound g =newSound("Glockenspiel",path +"Glockenspiel.wav");Sound h =newSound("Harfe",path +"Harfe.wav");Sound k =newSound("Klavier",path +"Klavier.wav");Sound o =newSound("Orgel",path +"Orgel.wav");getPlayer().addToPlayList(b, f, g, h, k, o);//Die Sounddateien werden in der Playlist angegeben, um sie dann als Nutzer auszuwählen.}publicvoidstartSession()throwsException{boolean running =true;System.out.println("Hier können Sie sich für ein Instrument entscheiden, in der das Lied 'Suit' von R.Ch.Martin gespielt werden soll!");System.out.println("");System.out.println("1. Geben Sie als erstes 'Instrument' ein, um eine Übersicht zu erhalten.");System.out.println("2. Als nächstes geben Sie den Namen eines Instrumentes ein, um sie abzuspielen. Dies können Sie beliebig oft wiederholen.");System.out.println("3. Wenn Sie den Player beenden wollen, geben Sie 'stop' ein.");System.out.println("");System.out.println("***********************************************************************************************");while(running){String input = sc.nextLine();if(input.equals("Instrument")){System.out.println("");for(int i =0; i < player.getPlayList().size(); i++){System.out.println(player.getPlayList().get(i).getName());}continue;}if(input.equals("stop")){
running =false;
sc.close();System.out.println("Der Player wurde beendet. Hoffentlich haben Sie die Musik genossen!");System.out.println("Ich wünsche Ihnen noch einen schönen Tag!");}while(running){System.out.println("Das Lied wird mit "+ input +" gespielt. Viel Vergnügen!");
player.play(player.getSongByName(input));break;}}}publicAudioPlayergetPlayer(){returnthis.player;}publicstaticvoidmain(String[] args)throwsException{newKonsolenVersion().startSession();//Die Main Methode dient dazu um das Programm zu starten und die startSession(); Methode aufzurufen.}}
Wenn du es entfernst, sollte der Sound abgespielt werden ohne dass es eine Meldung gibt, wenn du etwas falsches eingibst sollte die Meldung erscheinen das der Titel in der playlist nicht Vorhanden ist, zur Not kopierte aus meinen letzten Post die Klasse AudioPlayer und ersetze deine dadurch, wenn du unbedingt eine Ausgabe haben möchtest, welcher Sound abgespielt wird, müsste man dies in der Methode play Realisieren und zuvor Prüfen ob der Titel existiert, dies können wir gern machen, allerdings nicht vom Handy aus
Das "Problem" ist das du parallel versucht hast eigene features hinzuzufügen , welche aber mir nicht bekannt waren/sind, deswegen funktioniert meine Version hier bei mir reibungslos und deine in Verbindung mit meiner nicht
Ich taste mich nochmal ganz langsam ran , also....
1. du musst nicht an jede Methode eine throws Deklaration anfügen, sondern
- nur da wo du das Exception Handling an den Aufrufer delegieren möchtest
- wo auch Exceptions geworfen werden können
2. wenn du möchstest das ausgegeben wird welcher Sound aktuell abgespielt wird, musst du dies
an folgender Stelle / folgendermaßen realisieren, wenn der eingegebene Sound nun nicht existiert wird hier schon beim Aufrufen geprüft oder null übergeben wurde, und wenn ja ein dementsprechender Hinweis ausgegeben :
Java:
publicvoidplay(finalSound song){if(song ==null){System.out.println("Dieser Sound existiert in der Playlist nicht !");}else{System.out.println("Es wird Sound "+ song.getName()+" abgespielt , viel Spaß !");newThread(){@Overridepublicvoidrun(){try{AudioInputStream stream =AudioSystem.getAudioInputStream(song.getFile());AudioFormat audioFormat = stream.getFormat();DataLine.Info info =newDataLine.Info(Clip.class, audioFormat);Clip clip =(Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();while(clip.getFramePosition()< clip.getFrameLength()){};}catch(IOException|UnsupportedAudioFileException|LineUnavailableException e){System.out.println("Folgender Fehler ist aufgetretten : "+ e.toString());}}}.start();}}
da wir hier die play Methode nur in verbindung mit der Methode
nutzen , und diese insofern der Sound nicht in der Playlist existieren sollte null zurück liefert, prüfen wir hier den eingabeparameter und falls null übergeben wurde geben wir eine entsprechende Meldung aus das der Sound nicht in der Liste existiert !
3. Exception Handling in separat zum Haupt Thread laufenden Threads ist um einiges Komplizierter als reguläres Exception Handling, da du hier beim Überschrieben der
Code:
run()
methode des Runnables keine throws deklaration hinzufügen kannst, sonder einen
Code:
ExceptionHandler
nutzen müsstest.
folgendermaßen sieht die Konsolenversion und dessen Ausgabe nach oben stehenden Modifikation nun aus :
Code:
Willkommen beim AudioPlayer
***************************
- Gibt 'songlist' ein um eine Titelübersicht zu erhalten,
- gibt den Namen eines Sounds ein um ihn abzuspielen,
- gib 'remove' ein um einen Song aus der Playlist zu entfernen,
- oder 'stop' um den Player zu beenden.
_______________________________________
sdfsdf
Dieser Sound existiert in der Playlist nicht !
three
Es wird Sound three abgespielt , viel Spaß !
Ich muss mein Programm per e-mail jemanden senden und dabei soll der jenige auch eclipse öffnen und alles so sehen wie ich es sehe. DasPproblem dabei ist, dass der Pfad zu den Songs auf meinem Rechner gespeichert ist, und wenn ich ihn verändern will, muss da dennoch C:/ oder sowas stehen und wenn ich dann versende wird die Musik nicht abgespielt.
Wie soll ich dass versenden, damit bei dem jenigen die Musik auch abspielt?