gpt4 book ai didi

java - 是否可以通过操作 Java 中 targetDataLine 生成的字节流来改变音量?

转载 作者:太空宇宙 更新时间:2023-11-04 06:27:19 27 4
gpt4 key购买 nike

我可以通过操作 targetDataLine 生成的字节数组来更改音频内容的音量吗?我知道我无法使用 java 更改操作系统音量级别。所以我问自己是否可以通过操纵信号本身来改变音量。是否可以?如果是的话怎么办?

最佳答案

如果您有样本,更改增益很简单,只需将所有样本相乘即可:

samples[i] = samples[i] * 0.5f; // reduce by -6dB (half)

不建议直接将字节相乘,除非您碰巧有 8 位 PCM 签名。你可以看我的问答'How do I use audio sample data from Java Sound'如果您打算学习如何自己解码字节流。

现在,理论上这也可以通过 Control 来完成可以从 Line#getControl 获取;但是,我发现 TargetDataLine 不支持此功能。我确实发现 SourceDataLine 支持 MASTER_GAIN因此,如果您正在播放录音,则可以使用输出。

这是一个 MCVE,使用 JSlider 演示了这一点。

Gain Control

重要提示:如果运行此示例,请确保使用耳机,因为它会执行实时录音的回放。如果您使用扬声器,它会反馈。为了安全起见, slider 默认为 0。

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import java.awt.BorderLayout;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;

public class LineGain {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Gain");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel content = new JPanel(new BorderLayout());

JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
content.add(slider, BorderLayout.CENTER);

Recorder rec = null;
try {
rec = new Recorder();
rec.setGain(slider.getValue());
} catch(Exception e) {
panic(e);
}
slider.addChangeListener(new Listener(rec));

frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

new Thread(rec).start();
}
});
}

static class Listener implements ChangeListener {
Recorder rec;

Listener(Recorder rec) {
this.rec = rec;
}

@Override
public void stateChanged(ChangeEvent ce) {
JSlider source = (JSlider)ce.getSource();
Integer newValue = source.getValue();
rec.setGain(newValue);
}
}

static class Recorder implements Runnable {
final Object memSync = new Object();
final AudioFormat fmt = new AudioFormat(44100f, 16, 1, true, false);
final int bufferSize = 2048;

final TargetDataLine in;
final SourceDataLine out;
final FloatControl ctrl;

Recorder() throws Exception {
in = AudioSystem.getTargetDataLine(fmt);
out = AudioSystem.getSourceDataLine(fmt);
ctrl = (FloatControl)out.getControl(FloatControl.Type.MASTER_GAIN);

in.open(fmt, bufferSize);
out.open(fmt, bufferSize);
}

void setGain(int percent) {
synchronized(memSync) {
float volume = percent / 100f;
float range = Math.abs(ctrl.getMaximum() - ctrl.getMinimum());
float value = ctrl.getMinimum() + (volume * range);
ctrl.setValue(value);
}
}

@Override
public void run() {
try {
byte[] buf = new byte[bufferSize];

in.start();
out.start();

for(int b; (b = in.read(buf, 0, buf.length)) > -1;) {
synchronized(memSync) {}
out.write(buf, 0, b);
}
} catch(Exception e) {
panic(e);
}

in.close();
out.close();
}
}

static void panic(Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}

关于java - 是否可以通过操作 Java 中 targetDataLine 生成的字节流来改变音量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26618446/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com