Es ist so, dass die Figur im Spiel einen kleinen Satz sagen soll, wenn bestimmte Items kombiniert werden. So weit so gut, aber das laden(abspielen), der Sounddatei, stellte sich als problematisch heraus.
Meine Frage: Weiß jemand, wie man ohne zusätslichen aufwand(wie optionale Klassenbibliotheken), ogg-Dateien laden bzw. abspielen kann(AudioClip von Applet & des Midi-Zeugs hab ich schon probiert, hat aber nicht so hingehauen)?
Mit reinen Bordmitteln wird man eine OGG kaum abspielen können. Bestimmte WAV-Arten sollten immer gehen, für das meiste andere braucht man Zusatz-Bibliotheken.
Ich kann ja die ogg auch umwandeln, aber abgesehen davon hab ich die Sache mit dem Midi zeug auch mit Wav probiert aber es funktioniert nicht.
“Funktioniert nicht” ist keine ausreichende Beschreibung. Es gibt genug Beispiele im Netz zum Abspielen von WAV-Dateien…
Ich hab jetzt was im Internet gefunden, bekomme aber folgende Exception:
Exception in thread “main” java.lang.IllegalArgumentException: No line matching class Java.Soc.Socius supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian, and buffers of 503808 to 503808 bytes is supported.
at javax.sound.sampled.AudioSystem.getLine(Unknown Source)
at Java.Soc.Socius.laden(Socius.java:175)
at Java.Soc.Socius.(Socius.java:122)
at Java.Soc.Socius.main(Socius.java:39)
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(new File(getClass().getResource("sounds/satz1.wav").getFile()));
} catch (UnsupportedAudioFileException e2) {
e2.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
AudioFormat af = audioInputStream.getFormat();
int size = (int)(af.getFrameSize() * audioInputStream.getFrameLength());
byte[] audio = new byte[size];
DataLine.Info info = new DataLine.Info(Socius.class, af, size);
try {
audioInputStream.read(audio, 0, size);
} catch (IOException e1) {
e1.printStackTrace();
}
clip = null;
try {
clip[1] = (Clip) AudioSystem.getLine(info);
} catch (LineUnavailableException e1) {
e1.printStackTrace();
}
try {
clip[1].open(af, audio, 0, size);
} catch (LineUnavailableException e1) {
e1.printStackTrace();
}
Ja, es gibt 1000 unterschiedliche WAV-Formate, und das wird offenbar nicht unterstützt. Man kann sich auch abfragen, welche unterstützt werden, aber versuch ggf’ einfach mal ein anderes…
Was genau sagt diese Exception eigentlich aus, und wie kann ich das Format ändern ?
Ein Soundexperte bin ich nicht, aber es gibt eben verschiedene WAV-Formate, die sich in den ganzen Eingenschaften wie Sample Rate, Frame size etc. unterscheiden (siehe http://docs.oracle.com/javase/6/docs/api/javax/sound/sampled/AudioFormat.html ), und das gegebene kann offenbar nicht abgespielt werden. Probier’ ggf. erstmal irgendeine andere Beispiel-WAV aus, ob man überhaupt was aus den Lautsprechern rausbekommt. Danach kann man sich ein Programm suchen, mit dem man die gegebene WAV ins richtige Format bringt.
Ich hab jetzt mit SUPER die Datei auf das niedrigste gemacht was geht, aber die Exeption kommt immer noch.
Hier die Daten: Mono, 16 bit, 176 kbps, 11025 Hz
Nachdem ich es geade mal rauskopiert habe, ist mir aufgefallen, dass du
new DataLine.Info(Socius.class, af, size);
geschrieben hast. Wie auch immer du darauf kommst: Es sollte zumindest
new DataLine.Info(TargetDataLine.class, af, size);
heißen. Ob es dann geht, weiß ich nicht, dazu müßte ich es erst vergleichen, mit einem der 1000 Codeschnipsel, die man findet, wenn man nach sowas wie “java play wav” websucht, und schauen, ob du (aus welchem Grund auch immer) weitere solcher Unterschiede eingebaut hast.
Jetzt kann er irgendwie die Line nicht mehr zu einem Clip casten:
Exception in thread “main” java.lang.ClassCastException: com.sun.media.sound.DirectAudioDevice$DirectTDL cannot be cast to javax.sound.sampled.Clip
at Java.Soc.Socius.laden(Socius.java:162)
at Java.Soc.Socius.(Socius.java:124)
at Java.Soc.Socius.main(Socius.java:41)
Hast du - nur mal testweise - sowas wie http://stackoverflow.com/questions/2416935/how-to-play-wav-files-with-java angeschaut, und probiert, ob man damit rigendwie was aus dem Lautsprecher rausbekommt? (Oft ist es so einfach: Man tippt in eine Suchmaschine ein, was man machen will, und findet dann den passenden Code - gerade wenn es um Sachen wie “Bilder laden” oder “Sounds abspielen” geht. Da hangelt man sich nicht an der API-Doku entlang, und nuckelt sich die Lösung zeilenweise aus den Fingern, sondern nimmt die Snippets, die es schon gibt…)
Danke, damit kann ich den Sound laden, aber ich kann ihn nicht abspielen, während ich einen String ausgebe,
es wird nur der Sound abgespielt.
s.currentcolor = Color.black;
s.currentstring = "Test.";
s.satz1 = true;
s.repaint();
s.currentsoundindex = 1;
if(!seq[s.currentsoundindex].isRunning()){
seq[s.currentsoundindex].start();
s.abgespielt = true;
}
if(!seq[s.currentsoundindex].isRunning() && s.abgespielt){
s.satz1 = false;
s.repaint();
s.abgespielt = false;
}
Dort wird vermutlich der Event Dispatch Thread blockiert. Der Sound muss dann wohl in einem eigenen Thread abgespielt werden.
Wie könnte so etwas aussehen ?
Grundsätzlich mit sowas wie
Thread t = new Thread(new Runnable()
{
@Override
public void run()
{
spieleSoundAb();
}
});
t.start();
aber spätestens wenn jetzt noch Threads dazukommen wirst du mit dieser „alles public in der Socius-Klasse“ keinen Spaß haben.
Mal einen Schritt zurück: Was soll das denn alles? Ist das eine Hausaufgabe oder so? Es bringt doch nichts, immer mehr schlechten Code zusammenzuschreiben…
Also für Spiele sind Clips auch völlig ungeeignet, weil jeder seinen eigenen Thread benötigt (maw: Ja, solange der Clip spielt, ist der Thread blockiert). Eine Implementation einer Soundengine wäre dazu geeigneter. Eine Klasse, der man Audiostreams übergeben kann, welche dann über einen einzigen (oder vllt. auch 2) Thread, der ständig läuft, zusammengemixt werden.
Wie dem auch sei. Beim Laden kann man standardmässig nur Clip, TargetDataline oder SourceDataline verwenden (Ports und Mixer dienen einem anderen Zweck) und die jeweils dadurch zurückgegebenen Objekte untereinander auch nicht casten (bis auf Line.class, was aber uninteressant wäre). Andere Info-Klassen kannst du in der sound-properties Datei im JRE Lib-Verzeichnis definieren, aber die Erklärung, wie das geht (bzw. warum mans nicht braucht) dauert länger, da befasst man sich besser selber eindringlicher mit der Sound-API. Ist zwar recht unzureichend dokumentiert (Auf der Insel oder bei Guido Krüger wird nur die Spitze des Eisbergs beschrieben), aber man findet durchaus was, vorwiegend in Englisch.
Vielleicht als kleine Einordnung für bestimmte Aussagen meinerseits: Der Zusammenhang, in dem die Frage steht, ist hier zu finden http://forum.byte-welt.net/showthread.php?p=19622#post19622 und ich wollte andeuten, dass es da IMHO Sachen gibt, die man ändern sollte, bevor man zusätzlich noch Sounds einfügt. Aber da ich - zugegeben - mit Audio allgemein und speziell Sounds in Spielen noch nicht soooo viel gemacht habe, kann/konnte ich da leider keine ausführlicheren Hinweise zu best practices o.ä geben. Jetzt findet sich da ja vielleicht eher jemand
[QUOTE=Marco13]Vielleicht als kleine Einordnung für bestimmte Aussagen meinerseits: Der Zusammenhang, in dem die Frage steht, ist hier zu finden http://forum.byte-welt.net/showthread.php?p=19622#post19622 und ich wollte andeuten, dass es da IMHO Sachen gibt, die man ändern sollte, bevor man zusätzlich noch Sounds einfügt. Aber da ich - zugegeben - mit Audio allgemein und speziell Sounds in Spielen noch nicht soooo viel gemacht habe, kann/konnte ich da leider keine ausführlicheren Hinweise zu best practices o.ä geben. Jetzt findet sich da ja vielleicht eher jemand ;)[/QUOTE]Okay… da ist Sound ehrlich gesagt doch noch bissl viel für den TO, denn was Sound keinesfalls verträgt, ist exessives “Thread.sleep()”. “.write()” blockiert nunmal (wegen dem Timing, damits nicht leiert), ob über Clip oder SourceDataline ist dabei völlig egal. Allerdings wäre als Einstieg dann auch die Implementation eines Mixers zuviel.
Und was genau wäre deine Idee(evtl. Beispiel)?