JLayer: Wenn Musik läuft kann ich nihts mehr machen

Titel regelt.

Da ich in mein Programm per Menu-Auswahl einen Musik-Player hinzufügen wollte, hab ich mich erkundigt, wie man MP3s zum laufen kriegt. Dadurch bin ich auf JLayer gestoßen und ab mir diese Klasse gebaut:


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javazoom.jl.decoder.*;
import javazoom.jl.player.Player;

public class Musik {

    FileInputStream inputStream;

    public Musik(File audioFile) {
        try {
            inputStream = new FileInputStream(audioFile);
            Player player = new Player(inputStream);
            player.play();
        } catch (FileNotFoundException | JavaLayerException ex) {
            FileHandler fh = null;
            try {
                fh = new FileHandler("syserr.xml.log");
            } catch (IOException ex1) {
                System.err.println("Filehandler bei Musik kaputt");
            }
            Logger log = Logger.getLogger(SaveAs.class.getName());
            log.addHandler(fh);
            log.log(Level.SEVERE, null, ex);
        }
    }
}

So nun mein Problem: Es sollte im Hintergrund laufen, während ich im Vordergrund arbeiten kann. Aber das Programm reagiert auf gar nichts mehr, bis das Lied vorbei ist. Wenns vorbei ist, dann kann ich wieder machen. Aber wieso? Beim Hauseigenen Sound-Api mit Wav Dateien hatte ich das Problem nicht.

PS: Hat wer ne schlauere Idee für den 1. Catch-Block?^^ weil ein try-catch in einem catch iwie komisch ausschaut^^

Das liegt am Threading…

Du hast momentan nur einen Thread. Deinen Main-Thread und der ist damit beschäftigt das Lied abzuspielen und der Thread kann sich erst dann mit einer anderen Aufgabe beschäftigen, wenn diese abgeschlossen ist. Die andere API hat das Problem evtl. nicht weil sie selbst einen eigenen Thread aufmacht.

Solltest du von Threading noch gar nichts gehört haben google mal danach :)…

Lager das Musik Spielen in nen neuen Thread aus und invoke dann.

Grüße

Als Threading, Jein. Bei mir laufen zwar teilweise 2-3 Threads nebeneinander, aber ok, ich probiers mal.

Hat jemand nen Tipp?^^ Krieg run() in der Klasse Musik nicht sinnvoll eingebaut, da es ja Sachen vom Konstruktor braucht und ich sonst kein neues Thread-Objekt machen kann :confused: Kriegs nicht mal in meine Main implementiert, da ich wie gesagt run() nicht sinnvoll einbauen kann und sonst gehts ja nicht:


import javax.swing.SwingUtilities;


public class Demo { 

      public static void main(String[] args) {
        //Timer starten, indem er die Methode aufruft in run()
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TextEditor.timerListener();
            }
        });
    }

} ```

Nicht im Edt starten. Ich habe zur Zeit keine Tastatur und maus angeschlossen, sonst hätte ich das mit den Threads gezeigt.

Außerdem kennt anscheinend keiner javazoom.jl.* und außerdem kann Se auch .mp3’s abspielen („standard“ api).

Nimm doch einfach deine Musik-Klasse und implementiere Runnable. Dann setzt die nötigen Attribute per Konstruktor. Das play dann in die Run Methode und dann noch ne Main Methode die nen Thread erzeugt mit Übergabe der Musik-Klasse als Runnable und dann halt Thread.start

Also so circa würde ichs machen, nur ob das Gesamtkonzept noch stimmt bin ich mir gerade nicht sicher…

@Aldimann : so hab ichs ja gemacht:


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import javazoom.jl.decoder.*;
import javazoom.jl.player.Player;

public class Musik implements Runnable {

    FileInputStream inputStream;

    @SuppressWarnings("ResultOfObjectAllocationIgnored")
    public Musik(boolean multiSelection, boolean onlyDirectories) {
        JFileChooser musikChooser = new JFileChooser();
        File startFile = new File("E:\\");
        musikChooser.removeChoosableFileFilter(musikChooser.getFileFilter());
        FileNameExtensionFilter filter = new FileNameExtensionFilter("Unterstützte Musik-Formate", "wav", "mp3");
        musikChooser.setFileFilter(filter);
        musikChooser.setCurrentDirectory(startFile);
        musikChooser.setMultiSelectionEnabled(multiSelection);
        if (onlyDirectories) {
            musikChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        }
        int returnVal = musikChooser.showDialog(musikChooser, "MusikTrack wählen");
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            if (!onlyDirectories) {
                if (multiSelection) {
                    new Musik(musikChooser.getSelectedFile());
                } else {
                    new Musik(musikChooser.getSelectedFiles());
                }
            } else {
                File[] audioFiles = musikChooser.getSelectedFile().listFiles();
                new Musik(audioFiles);
            }
        }
    }

    private Musik(File... audioFiles) {
        for (File audioFile : audioFiles) {
            try {
                inputStream = new FileInputStream(audioFile);
                System.out.println("InputStream gesetzt");
            } catch (FileNotFoundException ex) {
                FileHandler fh = null;
                try {
                    fh = new FileHandler("syserr.xml.log");
                } catch (IOException ex1) {
                    System.err.println("Filehandler bei Musik kaputt");
                }
                Logger log = Logger.getLogger(Musik.class.getName());
                log.addHandler(fh);
                log.log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void run() {
        try {
            System.out.println("Thread gestartet");
            Player player = new Player(inputStream);
            player.play();
        } catch (JavaLayerException ex) {
            Logger.getLogger(Musik.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}

Und damit gestartet:

            @Override
            public void actionPerformed(ActionEvent ae) {
                Thread t = new Thread(new Musik(false, true));
                t.start();
            }
        });```

Aber das Problem ist, er setzt für alle Dateien im Ordner den inputStream hintereinander, ohne auf Fertigstellung zu warten. Am ende kommt dann noch ne nette NullPointerException bei rum.

> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> Thread gestartet
> Exception in thread "Thread-4" java.lang.NullPointerException: in
> 	at javazoom.jl.decoder.Bitstream.<init>(Unknown Source)
> 	at javazoom.jl.player.Player.<init>(Unknown Source)
> 	at javazoom.jl.player.Player.<init>(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:69)
> 	at java.lang.Thread.run(Thread.java:724)



@IknowwhatudidLast: Also ich bekamm da bei den meisten mp3s ne Exception, von wegen AudioStream konnte nicht geladen werden.

Habs inzwischen durch rumprobieren hingekriegt,aber noch eine Frage:
Wie kriege ich es hin, das wenn ich ein Lied höre und erneut auf das Menu klicke, das alte aufhört und das neue/ die neuen anfangen? Meine momentane Musik-Klasse:


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import javazoom.jl.decoder.*;
import javazoom.jl.player.Player;

public class Musik implements Runnable {

    FileInputStream inputStream;
    static Player player;
    static boolean isPlaying = false;

    @SuppressWarnings("ResultOfObjectAllocationIgnored")
    public Musik(boolean multiSelection, boolean onlyDirectories) {
        JFileChooser musikChooser = new JFileChooser();
        File startFile = new File("E:\\Metin2");
        musikChooser.removeChoosableFileFilter(musikChooser.getFileFilter());
        FileNameExtensionFilter filter = new FileNameExtensionFilter("Unterstützte Musik-Formate", "wav", "mp3");
        musikChooser.setFileFilter(filter);
        musikChooser.setCurrentDirectory(startFile);
        musikChooser.setMultiSelectionEnabled(multiSelection);
        if (onlyDirectories) {
            musikChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        }
        int returnVal = musikChooser.showDialog(musikChooser, "MusikTrack wählen");
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            if (!onlyDirectories) {
                if (multiSelection) {
                    new Musik(musikChooser.getSelectedFiles());
                } else {
                    new Musik(musikChooser.getSelectedFile());
                }
            } else {
                File[] audioFiles = musikChooser.getSelectedFile().listFiles();
                new Musik(audioFiles);
            }
        }
    }

    private Musik(File... audioFiles) {
        for (File audioFile : audioFiles) {
            try {
                isPlaying = false;
                inputStream = new FileInputStream(audioFile);
                System.out.println("InputStream gesetzt");
                player = new Player(inputStream);
                Thread t = new Thread(new Musik());
                t.start();
            } catch (FileNotFoundException | JavaLayerException ex) {
                FileHandler fh = null;
                try {
                    fh = new FileHandler("syserr.xml.log");
                } catch (IOException ex1) {
                    System.err.println("Filehandler bei Musik kaputt");
                }
                Logger log = Logger.getLogger(Musik.class.getName());
                log.addHandler(fh);
                log.log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void run() {
        try {
            if (!isPlaying) {
                System.out.println("Im if drin");
                isPlaying = true;
                player.play();
                System.out.println("ende vom if");
            }
        } catch (JavaLayerException ex) {
            Logger.getLogger(Musik.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Und die Menus mit denen gestartet wird:

            @Override
            public void actionPerformed(ActionEvent ae) {
                new Musik(false, false);
            }
        });

        musikItems[1].addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                new Musik(true, false);
            }
        });

        musikItems[2].addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (Musik.isPlaying) {
                    Musik.player.close();
                }
                new Musik(false, true);
            }
        });```

Ich starte erst einen normalen Song und will danach einen Ordner einbinden. Mit dem player.close() hört das Lied schonmal auf, wenn ich nochmal draufklicke. Wenn ich aber den Ordner dass auswähle kommt das:

> 
> InputStream gesetzt
> Im if drin
> ende vom if
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> Im if drin
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> Im if drin
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> Im if drin
> Im if drin
> InputStream gesetzt
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> Im if drin
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> InputStream gesetzt
> Im if drin
> Im if drin
> ende vom if
> ende vom if
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.JavaLayerException: Exception decoding audio frame
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.JavaLayerException: Exception decoding audio frame
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.JavaLayerException: Exception decoding audio frame
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.JavaLayerException: Exception decoding audio frame
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.JavaLayerException: Exception decoding audio frame
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> ende vom if
> Aug 07, 2013 3:15:18 AM TextEditor.Musik run
> SEVERE: null
> javazoom.jl.decoder.BitstreamException: Bitstream errorcode 102
> 	at javazoom.jl.decoder.Bitstream.newBitstreamException(Unknown Source)
> 	at javazoom.jl.decoder.Bitstream.readFrame(Unknown Source)
> 	at javazoom.jl.player.Player.decodeFrame(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at javazoom.jl.player.Player.play(Unknown Source)
> 	at TextEditor.Musik.run(Musik.java:77)
> 	at java.lang.Thread.run(Thread.java:724)
> 
> Exception while removing reference: java.lang.InterruptedException
> java.lang.InterruptedException
> 	at java.lang.Object.wait(Native Method)
> 	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
> 	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
> 	at sun.java2d.Disposer.run(Disposer.java:145)
> 	at java.lang.Thread.run(Thread.java:724)

Zudem werden dann alle Lieder gefühlt gleichzeitig abgespielt. Wieso spielt der dann so verrückt?

Sry für die Fragen, aber mit Threads hab ich mich noch nicht so sehr befasst^^ Aber mit ner if Abfrage + System.out.println() hab ich rausgefunden, das der Thread trotzdem noch lebt. Kann es daran liegen? Wenn ja, wie beende ich den? Die Methoden darf ich ja nicht verwenden

Das die SE-Standard-API inzwischen auch MP3 abspielt, halte ich auch fürn schlechtes Gerücht… (kurz nachschau… vergiss es ;))
Aber du kannst mit JavaZoom trotzdem AudioSystem, SourceDataLine usw zum Apspielen der MP3s verwenden, der JL-Player ist für Spiele eh’ nicht geeignet (ebensowenig wie “.play()”). Der Witz bei Spielen ist ja, dass man Sounds meistens vorbuffern will um sie dann getimed zu einem Ereignis abspielen zu können, deswegen ists mit 'nem einfachen LoadAndPlay selten getan.
Also:
Zuerst installierst du jl1.x.x.jar, tritonus_share.jar und mp3spi1.x.x.jar im ClassPath. Die JVM sollte dann in der Lage sein, den neuen Dateitypen zu erkennen.
Dann lädst du unterstützte Dateien mit einer der “AudioSystem.getAudioInputStream()”-Methoden.
Was nun folgt darf meines Erachtens bei keinem Ladevorgang von Sounddateien fehlen. Es wundert mich, warum dass die ganze Zeit über so geblieben ist und nie standardisiert wurde:

		AudioFormat af = source.getFormat();
		Encoding enc = af.getEncoding();
		if(!PCM_SIGNED.equals(enc) && !PCM_UNSIGNED.equals(enc)) {
			int ssb = af.getSampleSizeInBits();
			int c = af.getChannels();
			if(ssb < 8) {
				ssb = 8;
			}
			int minFs = c * ssb / 8;
			int fs = af.getFrameSize();
			if(fs < minFs) {
				fs = minFs;
			}
			af = new AudioFormat(
					AudioFormat.Encoding.PCM_SIGNED,
					af.getSampleRate(),
					ssb * 2,
					af.getChannels(),
					fs * 2,
					af.getSampleRate(),
					af.isBigEndian()
				);
			source = AudioSystem.getAudioInputStream(af, source);
		}
		return source;
}```Damit werden alle Soundformate auf ein ausgabefähiges Format gebracht. Alle vorhandenen Sounddatentypen sollten deswegen einen passenden FormatConversionProvier bereitstellen. Diese Art Sounds konvertieren zu müssen ist zwar ehrlich gesagt nicht gerade der Weisheit letzter Schluss, aber die verquere Implementierung der FCPs seitens Sun war es auch nicht, also was bleibt einem übrig.
Als nächstes besorgst du dir mit "AudioSystem.getSourceDataLine(<AudioStream>.getFormat())" eine solche und dann kanns eigentlich schon losgehen:
```public synchonized void start() {
  if(player == null) {
    try {
      line.open();
      line.start();
      player = new Thread() {
        byte[] buf = new byte[line.getBufferSize()];

        @Override
        public void run() {
          try {
            int r = 0;
            while((r = ais.read(buf)) != -1 && !isInterrupted()) {
              line.write(buf, 0, r);
            }
          } catch (IOException e) {
            e.printStackTrace();
            interrupt();
          }
          line.drain();
          line.close();
        }
      };
      player.start();
    } catch(LineUnavailableException e) {
      e.printStackTrace();
  }
}```Der Thread ist natürlich noch ausbaufähig, aber das ist schon mal das Prinzip.
Der Code stammt noch aus einem älteren Applet, welches einen LinePitcher und einen Lautstärkeregler besaß. Hier ist mal der gesamte Code, welcher mit jl-1.0.1, tritonus_share, mp3SPI1.9.5 und MP3-Dateien funktionieren sollte. Tut er es nicht, könnte das evtl. an einem weiteren JavaZoom-PlugIn (jaad-0.8.4.jar, für MP4-Dateien) liegen, welches mit mit mp3SPI1.9.5.jar leider nicht kompatibel ist.
```import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED;
import static javax.sound.sampled.AudioFormat.Encoding.PCM_UNSIGNED;

import java.applet.Applet;
import java.awt.GridLayout;
import java.awt.Scrollbar;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Control;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.Control.Type;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class PitchApplet extends Applet {
	private static final long serialVersionUID = 5249093657598621545L;

	private final Scrollbar pitch = new Scrollbar(Scrollbar.HORIZONTAL);
	private final Scrollbar volume = new Scrollbar(Scrollbar.HORIZONTAL);
	private FloatControl pitchValue, volumeValue;
	private AudioInputStream ais;
	private LinePitcher lp;
	private Thread player;

	@Override
	public void init() {
		super.init();
		try {
			final URL title = new URL(getDocumentBase(), getParameter("title"));
			ais = AudioSystem.getAudioInputStream(title);
			ais = ensurePCM(ais);
			lp = new LinePitcher(AudioSystem.getSourceDataLine(ais.getFormat()));
			pitchValue = (FloatControl) lp.getControl(LinePitcher.PITCH_CONTROL);
			volumeValue = (FloatControl) lp.getControl(FloatControl.Type.MASTER_GAIN);
		} catch(LineUnavailableException | UnsupportedAudioFileException | IOException e) {
			e.printStackTrace();
		}
		setLayout(new GridLayout(2, 1));
		add(pitch);
		add(volume);
		pitch.setMinimum(0);
		pitch.setMaximum(1000);
		pitch.setValue(500);
		pitch.addAdjustmentListener(new AdjustmentListener() {
			final float minimum = pitchValue.getMinimum();
			final float range = pitchValue.getMaximum() - minimum;

			{
				pitchValue.setValue(pitch.getValue() / 1000.0f * range + minimum);
			}

			@Override
			public void adjustmentValueChanged(AdjustmentEvent e) {
				pitchValue.setValue(pitch.getValue() / 1000.0f * range + minimum);
			}
		});
		volume.setMinimum(0);
		volume.setMaximum(1000);
		volume.setValue(500);
		volume.addAdjustmentListener(new AdjustmentListener() {
			final float minimum = dBToLinear(volumeValue.getMinimum());
			final float range = dBToLinear(volumeValue.getMaximum()) - minimum;

			{
				volumeValue.setValue(linearToDB(volume.getValue() / 1000.0f * range + minimum));
			}

			@Override
			public void adjustmentValueChanged(AdjustmentEvent e) {
				volumeValue.setValue(linearToDB(volume.getValue() / 1000.0f * range + minimum));
			}
		});
	}

	@Override
	public void start() {
		super.start();
		try {
			lp.open();
			lp.start();
			player = new Thread() {
				byte[] buf = new byte[lp.getBufferSize()];
				@Override
				public void run() {
					try {
						int r = 0;
						while((r = ais.read(buf)) != -1 && !isInterrupted()) {
							lp.write(buf, 0, r);
						}
					} catch (IOException e) {
						e.printStackTrace();
						interrupt();
					}
					lp.drain();
					lp.close();
				}
			};
			player.start();
		} catch(LineUnavailableException e) {
			e.printStackTrace();
		}
	}

	private final AudioInputStream ensurePCM(AudioInputStream source)
	{
		AudioFormat af = source.getFormat();
		Encoding enc = af.getEncoding();
		if(!PCM_SIGNED.equals(enc) && !PCM_UNSIGNED.equals(enc)) {
			int ssb = af.getSampleSizeInBits();
			int c = af.getChannels();
			if(ssb < 8) {
				ssb = 8;
			}
			int minFs = c * ssb / 8;
			int fs = af.getFrameSize();
			if(fs < minFs) {
				fs = minFs;
			}
			af = new AudioFormat(
					AudioFormat.Encoding.PCM_SIGNED,
					af.getSampleRate(),
					ssb * 2,
					af.getChannels(),
					fs * 2,
					af.getSampleRate(),
					af.isBigEndian()
				);
			source = AudioSystem.getAudioInputStream(af, source);
		}
		return source;
	}

	private float linearToDB(float f)
	{
		float f1 = (float) ((Math.log((f != 0.0) ? f : 1.0E-14) / Math.log(10.0)) * 20.0);
		return f1;
	}

	private float dBToLinear(float f)
	{
		float f1 = (float) Math.pow(10.0, f / 20.0);
		return f1;
	}
}

class LinePitcher implements SourceDataLine {
	public static final PitchControl.Type PITCH_CONTROL = new PitchControl.Type();
	private static final class PitchControl extends FloatControl {
		protected PitchControl() {
			super(PITCH_CONTROL, 0.0F, 2.0F, Float.MIN_VALUE, 10, 1.0F, "", "-", "+", "0");
		}

		private static final class Type extends FloatControl.Type {
			private Type() {
				super("Pitch Control");
			}
		}
	}
	private final Object lock = new Object();
	private final SourceDataLine source;
	private final List<Control> controls;
	private final PitchControl ctrl;
	private ByteBuffer bOut;
	private float samplePos, framePos;
	private int frameSize;

	public LinePitcher(SourceDataLine source) {
		this.source = source;
		try {
			source.open();
		} catch(LineUnavailableException e) {
			e.printStackTrace();
		}
		List<Control> controls = new ArrayList<>(Arrays.asList(source.getControls()));
		ctrl = new PitchControl();
		controls.add(ctrl);
		this.controls = Collections.unmodifiableList(controls);
		source.close();
	}

	@Override
	public void drain() {
		synchronized(lock) {
			source.drain();
		}
	}

	@Override
	public void flush() {
		synchronized(lock) {
			source.flush();
		}
	}

	@Override
	public void start() {
		synchronized(lock) {
			source.start();
		}
	}

	@Override
	public void stop() {
		synchronized(lock) {
			source.stop();
		}
	}

	@Override
	public boolean isRunning() {
		return source.isRunning();
	}

	@Override
	public boolean isActive() {
		return source.isActive();
	}

	@Override
	public AudioFormat getFormat() {
		return source.getFormat();
	}

	@Override
	public int getBufferSize() {
		return source.getBufferSize();
	}

	@Override
	public int available() {
		return source.available();
	}

	@Override
	public int getFramePosition() {
		return (int) framePos;
	}

	@Override
	public long getLongFramePosition() {
		return getFramePosition();
	}

	@Override
	public long getMicrosecondPosition() {
		return source.getMicrosecondPosition();
	}

	@Override
	public float getLevel() {
		return source.getLevel();
	}

	@Override
	public javax.sound.sampled.Line.Info getLineInfo() {
		return source.getLineInfo();
	}

	@Override
	public void open() throws LineUnavailableException {
		open(null);
	}

	@Override
	public void close() {
		source.close();
	}

	@Override
	public boolean isOpen() {
		return source.isOpen();
	}

	@Override
	public Control[] getControls() {
		return controls.toArray(new Control[controls.size()]);
	}

	@Override
	public boolean isControlSupported(Type control) {
		for(Control c : controls) {
			if(c.getType() == control) {
				return true;
			}
		}
		return false;
	}

	@Override
	public Control getControl(Type control) {
		for(Control c : controls) {
			if(c.getType() == control) {
				return c;
			}
		}
		return null;
	}

	@Override
	public void addLineListener(LineListener listener) {
		source.addLineListener(listener);
	}

	@Override
	public void removeLineListener(LineListener listener) {
		source.removeLineListener(listener);
	}

	

	@Override
	public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
		synchronized(lock) {
			source.open(format, bufferSize);
			bOut = ByteBuffer.wrap(new byte[bufferSize]);
			frameSize = format.getChannels() * ((format.getSampleSizeInBits() + 7) / 8);
			samplePos = 0.0f;
		}
	}

	@Override
	public void open(AudioFormat format) throws LineUnavailableException {
		if(format == null) {
			source.open();
			format = source.getFormat();
			source.close();
		}
		int bufferSize = format.getChannels() * ((format.getSampleSizeInBits() + 7) / 8);
		bufferSize *= (int) (format.getSampleRate() / 25.0f) * format.getFrameSize();
		open(format, bufferSize);
	}

	@Override
	public int write(byte[] b, int off, int len) {
		synchronized(lock) {
			ByteBuffer bIn = ByteBuffer.wrap(b, off, len);
			samplePos %= 1.0F;
			int p = 0;
			while(p < len) {
				for(int c = 0; c < frameSize; c++) {
					bOut.put(bIn.get(p + c + off));
				}
				if(bOut.position() == bOut.capacity()) {
					byte[] bb = bOut.array().clone();
					source.write(bb, 0, bOut.capacity());
					bOut.clear();
				}
				float fp = ctrl.getValue();
				samplePos += fp;
				framePos += fp;
				p = (int) samplePos * frameSize;
			}
			b = bOut.array().clone();
			source.write(b, 0, bOut.position());
			bOut.clear();
			return len;
		}
	}
}```BTW.: Ähnlich wie ich hier eine SourceDataLine implementiert habe, kann man auch eine TargetDataLine bauen, die im Prinzip ständig läuft und solange nichts gespielt wird, bei read(), einen Buffer voller 0-Bytes zurückgibt. An diese TargetDataLine könnte man so nach belieben mehrere andere AudioStreams schicken, die dann dort live zusammengemixt werden. So verhindert man in Games störende Knack-Geräusche und/oder Überlagerungen, die Auftreten, wenn man der Einfachheit halber mehrere Clips zusammen bzw. kurz hintereinander startet.