You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中通过AudioSystem终止line.write音频输出并动态调参

解决方案

要实现音频终止和动态参数调整,需要重构原代码的播放逻辑,从一次性生成全部采样改为实时流式生成,同时引入线程和状态控制变量。以下是具体实现步骤和修改后的代码:

核心改动说明

  • 将SourceDataLine设为类成员变量,方便终止时操作
  • 添加volatile修饰的状态变量isPlaying,线程安全控制播放启停
  • 重构play方法为线程播放,循环生成小块采样数据,实时读取最新参数
  • 添加stop方法终止音频输出
  • 修改createSinWaveBuffer为生成指定长度的采样块,适配流式播放

修改后的完整代码

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class SineGenerator {
    protected static final int SAMPLE_RATE = 16 * 1024;
    // 每次生成的采样块大小,可根据需求调整
    private static final int BUFFER_SIZE = 1024;

    // 用volatile保证多线程下参数可见性
    private volatile int freq;
    private volatile double amplitude;
    private volatile boolean inclAng;
    private volatile double modAmp;
    private volatile int numMod;

    private volatile boolean isPlaying;
    private SourceDataLine line;

    public SineGenerator(int freq, double amplitude, boolean incAng, double modAmp, int numMod) {
        this.freq = freq;
        this.amplitude = amplitude;
        this.inclAng = incAng;
        this.modAmp = modAmp;
        this.numMod = numMod;
    }

    // 生成指定长度的采样块
    private byte[] createSinWaveBuffer(int length) {
        byte[] output = new byte[length];
        // 维护全局角度累计,保证波形连续
        static double globalAngle = 0;

        for (int i = 0; i < output.length; i++) {
            globalAngle += 2.0 * Math.PI * freq / SAMPLE_RATE;
            double angle = globalAngle;

            if (modAmp <= 0) {
                output[i] = (byte) (Math.sin(angle) * amplitude);
            } else {
                output[i] = (byte) (Math.sin(recur(modAmp, angle, numMod, inclAng)) * 127f);
            }
        }

        return output;
    }

    public void play() throws LineUnavailableException {
        if (isPlaying) return; // 避免重复启动

        final AudioFormat af = new AudioFormat(SAMPLE_RATE, 8, 1, true, true);
        line = AudioSystem.getSourceDataLine(af);
        line.open(af, BUFFER_SIZE * 2);
        line.start();

        isPlaying = true;

        // 启动播放线程,避免阻塞主线程
        new Thread(() -> {
            while (isPlaying) {
                byte[] buffer = createSinWaveBuffer(BUFFER_SIZE);
                line.write(buffer, 0, buffer.length);
            }
            // 播放结束后清理资源
            line.drain();
            line.close();
            line = null;
        }).start();
    }

    // 终止音频输出
    public void stop() {
        isPlaying = false;
        if (line != null) {
            line.stop();
        }
    }

    public static double recur(double amplitude, double angle, int num, boolean inclAng) {
        if (num <= 1) {
            return inclAng ? angle + amplitude * Math.sin(angle) : amplitude * Math.sin(angle);
        } else {
            double inner = recur(amplitude, angle, num - 1, inclAng);
            return inclAng ? angle + amplitude * Math.sin(inner) : amplitude * Math.sin(inner);
        }
    }

    // 所有setter保持原样,volatile修饰的参数会被播放线程实时读取
    public void setFreq(int freq) {
        this.freq = freq;
    }

    public void setAmplitude(double amplitude) {
        this.amplitude = amplitude;
    }

    public void setInclAng(boolean inclAng) {
        this.inclAng = inclAng;
    }

    public void setModAmp(double modAmp) {
        this.modAmp = modAmp;
    }

    public void setNumMod(int numMod) {
        this.numMod = numMod;
    }
}

关键功能说明

  1. 终止音频:调用stop()方法时,会将isPlaying设为false,播放线程会退出循环,随后关闭音频线,终止输出。
  2. 动态修改参数:所有音频参数(频率、振幅等)都用volatile修饰,播放线程每次生成采样块时都会读取最新的参数值,修改后立刻生效,无需停止播放。
  3. 流式播放:每次生成BUFFER_SIZE大小的采样块,避免一次性生成大量数据占用内存,同时保证参数修改的实时性;新增全局角度累计,确保波形连续无断层。

使用示例

public class Main {
    public static void main(String[] args) throws LineUnavailableException, InterruptedException {
        SineGenerator generator = new SineGenerator(440, 127, false, 0.5, 2);
        generator.play();

        // 播放3秒后修改频率
        Thread.sleep(3000);
        generator.setFreq(880);

        // 再播放2秒后终止
        Thread.sleep(2000);
        generator.stop();
    }
}

内容的提问来源于stack exchange,提问作者user25332023

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:41:02