使用 JLayer 改变音量
Changing Volume with JLayer
我的音乐播放器项目中 JLayer
有一个非常具体的问题。我想包括一些东西来调整音量,但似乎不太容易实现。
这是因为 JLayer
本身并不支持它。我从我的项目中排除了 Player
class 并更改了一些方法,它可以很好地播放 mp3
。为了调整音量,我在 Player
class 这个方法中添加了:
public boolean setGain(float newGain) {
if (audio instanceof JavaSoundAudioDevice) {
System.out.println("InstanceOf");
JavaSoundAudioDevice jsAudio = (JavaSoundAudioDevice) audio;
try {
jsAudio.write(null, 0, 0);
} catch (JavaLayerException ex) {
ex.printStackTrace();
}
return jsAudio.setLineGain(newGain);
}
return false;
}
然后我提取了 JavaSoundAudioDevice
,反编译并更改了它:
public boolean setLineGain(float gain)
{
System.out.println("Vor Source");
if (source != null)
{
System.out.println("Nach Source");
FloatControl volControl = (FloatControl) source.getControl(FloatControl.Type.MASTER_GAIN);
float newGain = Math.min(Math.max(gain, volControl.getMinimum()), volControl.getMaximum());
volControl.setValue(newGain);
return true;
}
return false;
}
并且:
public void createSource() throws JavaLayerException {
Throwable t = null;
try {
Line line = AudioSystem.getLine(getSourceLineInfo());
if (line instanceof SourceDataLine) {
source = (SourceDataLine) line;
//source.open(fmt, millisecondsToBytes(fmt, 2000));
source.open(fmt);
/*
if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
{
FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
c.setValue(c.getMaximum());
}*/
source.start();
}
} catch (RuntimeException ex) {
t = ex;
} catch (LinkageError ex) {
t = ex;
} catch (LineUnavailableException ex) {
t = ex;
}
if (source == null) {
throw new JavaLayerException("cannot obtain source audio line", t);
}
}
但是已经实现的createSource
方法不起作用。在行
Line line = AudioSystem.getLine(getSourceLineInfo());
我总是得到 IllegalArgumentException:
java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 0.0 Hz, 16 bit, 0 channels, 0 bytes/frame, little-endian is supported.
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)
at javazoom.jl.player.JavaSoundAudioDevice.createSource(JavaSoundAudioDevice.java:80)
at javazoom.jl.player.JavaSoundAudioDevice.writeImpl(JavaSoundAudioDevice.java:119)
at javazoom.jl.player.AudioDeviceBase.write(Unknown Source)
at MusikPlayer.Erweiterungen.Players.MyPlayer.setGain(MyPlayer.java:192)
at MusikPlayer.PlayerTest.main(PlayerTest.java:21)
Exception in thread "main" java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 0.0 Hz, 16 bit, 0 channels, 0 bytes/frame, little-endian is supported.
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)
at javazoom.jl.player.JavaSoundAudioDevice.createSource(JavaSoundAudioDevice.java:80)
at javazoom.jl.player.JavaSoundAudioDevice.writeImpl(JavaSoundAudioDevice.java:119)
at javazoom.jl.player.AudioDeviceBase.write(Unknown Source)
at MusikPlayer.Erweiterungen.Players.MyPlayer.decodeFrame(MyPlayer.java:161)
at MusikPlayer.Erweiterungen.Players.MyPlayer.play(MyPlayer.java:87)
at MusikPlayer.Erweiterungen.Players.MyPlayer.play(MyPlayer.java:66)
at MusikPlayer.PlayerTest.main(PlayerTest.java:22)
有人知道为什么会这样吗?有谁知道如何解决这个问题?
嗯,我解决了..
此测试 class 使用:
public class PlayerTest {
public static void main(String[] args) {
try {
File f = new File("D:\Musik\Musik-Oberordner\Favoriten\06-ich_und_ich_-_so_soll_es_bleiben.mp3");
MyPlayer player = new MyPlayer(new FileInputStream(f));
player.setGain(-30f);
player.play();
} catch (JavaLayerException | FileNotFoundException ex) {
ex.printStackTrace();
}
}
setten Gain 将调整音量,从 -80.0f 到 6f。
更改后的 JavaSoundAudioDevice:
package javazoom.jl.player;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.JavaLayerException;
/**
* The <code>JavaSoundAudioDevice</code> implements an audio device by using the
* JavaSound API.
*
* @since 0.0.8
* @author Mat McGowan
*/
public class JavaSoundAudioDevice extends AudioDeviceBase {
private SourceDataLine source = null;
private AudioFormat fmt = null;
private byte[] byteBuf = new byte[4096];
protected void setAudioFormat(AudioFormat fmt0) {
fmt = fmt0;
}
protected AudioFormat getAudioFormat() {
// if (fmt == null) {
fmt = new AudioFormat(44100,
16,
2,
true,
false);
return fmt;
}
protected DataLine.Info getSourceLineInfo() {
AudioFormat fmt = getAudioFormat();
//DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt, 4000);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt);
return info;
}
public void open(AudioFormat fmt) throws JavaLayerException {
if (!isOpen()) {
setAudioFormat(fmt);
openImpl();
setOpen(true);
}
}
public boolean setLineGain(float gain) {
System.out.println("Vor Source");
if (source != null) {
System.out.println("Nach Source");
FloatControl volControl = (FloatControl) source.getControl(FloatControl.Type.MASTER_GAIN);
float newGain = Math.min(Math.max(gain, volControl.getMinimum()), volControl.getMaximum());
volControl.setValue(newGain);
return true;
}
return false;
}
public void openImpl()
throws JavaLayerException {
}
// createSource fix.
public void createSource() throws JavaLayerException {
Throwable t = null;
try {
Line line = AudioSystem.getLine(getSourceLineInfo());
if (line instanceof SourceDataLine) {
source = (SourceDataLine) line;
//source.open(fmt, millisecondsToBytes(fmt, 2000));
source.open(fmt);
// if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
// {
// System.out.println("Control");
// FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
// c.setValue(c.getMinimum());
// }
source.start();
}
} catch (RuntimeException ex) {
t = ex;
} catch (LinkageError ex) {
t = ex;
} catch (LineUnavailableException ex) {
t = ex;
}
if (source == null) {
throw new JavaLayerException("cannot obtain source audio line", t);
}
}
public int millisecondsToBytes(AudioFormat fmt, int time) {
return (int) (time * (fmt.getSampleRate() * fmt.getChannels() * fmt.getSampleSizeInBits()) / 8000.0);
}
protected void closeImpl() {
if (source != null) {
source.close();
}
}
protected void writeImpl(short[] samples, int offs, int len)
throws JavaLayerException {
if (source == null) {
createSource();
}
byte[] b = toByteArray(samples, offs, len);
source.write(b, 0, len * 2);
}
protected byte[] getByteArray(int length) {
if (byteBuf.length < length) {
byteBuf = new byte[length + 1024];
}
return byteBuf;
}
protected byte[] toByteArray(short[] samples, int offs, int len) {
byte[] b = getByteArray(len * 2);
int idx = 0;
short s;
while (len-- > 0) {
s = samples[offs++];
b[idx++] = (byte) s;
b[idx++] = (byte) (s >>> 8);
}
return b;
}
protected void flushImpl() {
if (source != null) {
source.drain();
}
}
public int getPosition() {
int pos = 0;
if (source != null) {
pos = (int) (source.getMicrosecondPosition() / 1000);
}
return pos;
}
/**
* Runs a short test by playing a short silent sound.
*/
public void test()
throws JavaLayerException {
// try {
open(new AudioFormat(22000, 16, 1, true, false));
short[] data = new short[22000 / 10];
write(data, 0, data.length);
flush();
close();
// } catch (RuntimeException ex) {
// throw new JavaLayerException("Device test failed: " + ex);
// }
}
}
现在你只需将它实现到你的项目中,覆盖旧的 JavaSoundDevice 并享受 VolumeAdjusting!
我的音乐播放器项目中 JLayer
有一个非常具体的问题。我想包括一些东西来调整音量,但似乎不太容易实现。
这是因为 JLayer
本身并不支持它。我从我的项目中排除了 Player
class 并更改了一些方法,它可以很好地播放 mp3
。为了调整音量,我在 Player
class 这个方法中添加了:
public boolean setGain(float newGain) {
if (audio instanceof JavaSoundAudioDevice) {
System.out.println("InstanceOf");
JavaSoundAudioDevice jsAudio = (JavaSoundAudioDevice) audio;
try {
jsAudio.write(null, 0, 0);
} catch (JavaLayerException ex) {
ex.printStackTrace();
}
return jsAudio.setLineGain(newGain);
}
return false;
}
然后我提取了 JavaSoundAudioDevice
,反编译并更改了它:
public boolean setLineGain(float gain)
{
System.out.println("Vor Source");
if (source != null)
{
System.out.println("Nach Source");
FloatControl volControl = (FloatControl) source.getControl(FloatControl.Type.MASTER_GAIN);
float newGain = Math.min(Math.max(gain, volControl.getMinimum()), volControl.getMaximum());
volControl.setValue(newGain);
return true;
}
return false;
}
并且:
public void createSource() throws JavaLayerException {
Throwable t = null;
try {
Line line = AudioSystem.getLine(getSourceLineInfo());
if (line instanceof SourceDataLine) {
source = (SourceDataLine) line;
//source.open(fmt, millisecondsToBytes(fmt, 2000));
source.open(fmt);
/*
if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
{
FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
c.setValue(c.getMaximum());
}*/
source.start();
}
} catch (RuntimeException ex) {
t = ex;
} catch (LinkageError ex) {
t = ex;
} catch (LineUnavailableException ex) {
t = ex;
}
if (source == null) {
throw new JavaLayerException("cannot obtain source audio line", t);
}
}
但是已经实现的createSource
方法不起作用。在行
Line line = AudioSystem.getLine(getSourceLineInfo());
我总是得到 IllegalArgumentException:
java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 0.0 Hz, 16 bit, 0 channels, 0 bytes/frame, little-endian is supported.
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)
at javazoom.jl.player.JavaSoundAudioDevice.createSource(JavaSoundAudioDevice.java:80)
at javazoom.jl.player.JavaSoundAudioDevice.writeImpl(JavaSoundAudioDevice.java:119)
at javazoom.jl.player.AudioDeviceBase.write(Unknown Source)
at MusikPlayer.Erweiterungen.Players.MyPlayer.setGain(MyPlayer.java:192)
at MusikPlayer.PlayerTest.main(PlayerTest.java:21)
Exception in thread "main" java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 0.0 Hz, 16 bit, 0 channels, 0 bytes/frame, little-endian is supported.
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)
at javazoom.jl.player.JavaSoundAudioDevice.createSource(JavaSoundAudioDevice.java:80)
at javazoom.jl.player.JavaSoundAudioDevice.writeImpl(JavaSoundAudioDevice.java:119)
at javazoom.jl.player.AudioDeviceBase.write(Unknown Source)
at MusikPlayer.Erweiterungen.Players.MyPlayer.decodeFrame(MyPlayer.java:161)
at MusikPlayer.Erweiterungen.Players.MyPlayer.play(MyPlayer.java:87)
at MusikPlayer.Erweiterungen.Players.MyPlayer.play(MyPlayer.java:66)
at MusikPlayer.PlayerTest.main(PlayerTest.java:22)
有人知道为什么会这样吗?有谁知道如何解决这个问题?
嗯,我解决了.. 此测试 class 使用:
public class PlayerTest {
public static void main(String[] args) {
try {
File f = new File("D:\Musik\Musik-Oberordner\Favoriten\06-ich_und_ich_-_so_soll_es_bleiben.mp3");
MyPlayer player = new MyPlayer(new FileInputStream(f));
player.setGain(-30f);
player.play();
} catch (JavaLayerException | FileNotFoundException ex) {
ex.printStackTrace();
}
}
setten Gain 将调整音量,从 -80.0f 到 6f。
更改后的 JavaSoundAudioDevice:
package javazoom.jl.player;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.JavaLayerException;
/**
* The <code>JavaSoundAudioDevice</code> implements an audio device by using the
* JavaSound API.
*
* @since 0.0.8
* @author Mat McGowan
*/
public class JavaSoundAudioDevice extends AudioDeviceBase {
private SourceDataLine source = null;
private AudioFormat fmt = null;
private byte[] byteBuf = new byte[4096];
protected void setAudioFormat(AudioFormat fmt0) {
fmt = fmt0;
}
protected AudioFormat getAudioFormat() {
// if (fmt == null) {
fmt = new AudioFormat(44100,
16,
2,
true,
false);
return fmt;
}
protected DataLine.Info getSourceLineInfo() {
AudioFormat fmt = getAudioFormat();
//DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt, 4000);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt);
return info;
}
public void open(AudioFormat fmt) throws JavaLayerException {
if (!isOpen()) {
setAudioFormat(fmt);
openImpl();
setOpen(true);
}
}
public boolean setLineGain(float gain) {
System.out.println("Vor Source");
if (source != null) {
System.out.println("Nach Source");
FloatControl volControl = (FloatControl) source.getControl(FloatControl.Type.MASTER_GAIN);
float newGain = Math.min(Math.max(gain, volControl.getMinimum()), volControl.getMaximum());
volControl.setValue(newGain);
return true;
}
return false;
}
public void openImpl()
throws JavaLayerException {
}
// createSource fix.
public void createSource() throws JavaLayerException {
Throwable t = null;
try {
Line line = AudioSystem.getLine(getSourceLineInfo());
if (line instanceof SourceDataLine) {
source = (SourceDataLine) line;
//source.open(fmt, millisecondsToBytes(fmt, 2000));
source.open(fmt);
// if (source.isControlSupported(FloatControl.Type.MASTER_GAIN))
// {
// System.out.println("Control");
// FloatControl c = (FloatControl)source.getControl(FloatControl.Type.MASTER_GAIN);
// c.setValue(c.getMinimum());
// }
source.start();
}
} catch (RuntimeException ex) {
t = ex;
} catch (LinkageError ex) {
t = ex;
} catch (LineUnavailableException ex) {
t = ex;
}
if (source == null) {
throw new JavaLayerException("cannot obtain source audio line", t);
}
}
public int millisecondsToBytes(AudioFormat fmt, int time) {
return (int) (time * (fmt.getSampleRate() * fmt.getChannels() * fmt.getSampleSizeInBits()) / 8000.0);
}
protected void closeImpl() {
if (source != null) {
source.close();
}
}
protected void writeImpl(short[] samples, int offs, int len)
throws JavaLayerException {
if (source == null) {
createSource();
}
byte[] b = toByteArray(samples, offs, len);
source.write(b, 0, len * 2);
}
protected byte[] getByteArray(int length) {
if (byteBuf.length < length) {
byteBuf = new byte[length + 1024];
}
return byteBuf;
}
protected byte[] toByteArray(short[] samples, int offs, int len) {
byte[] b = getByteArray(len * 2);
int idx = 0;
short s;
while (len-- > 0) {
s = samples[offs++];
b[idx++] = (byte) s;
b[idx++] = (byte) (s >>> 8);
}
return b;
}
protected void flushImpl() {
if (source != null) {
source.drain();
}
}
public int getPosition() {
int pos = 0;
if (source != null) {
pos = (int) (source.getMicrosecondPosition() / 1000);
}
return pos;
}
/**
* Runs a short test by playing a short silent sound.
*/
public void test()
throws JavaLayerException {
// try {
open(new AudioFormat(22000, 16, 1, true, false));
short[] data = new short[22000 / 10];
write(data, 0, data.length);
flush();
close();
// } catch (RuntimeException ex) {
// throw new JavaLayerException("Device test failed: " + ex);
// }
}
}
现在你只需将它实现到你的项目中,覆盖旧的 JavaSoundDevice 并享受 VolumeAdjusting!