Java逐次播放WAV钢琴音符制作音乐卡顿问题及实现方案问询
Java逐音符拼接播放音乐的问题与解决方案
问题根因
卡顿、跳音、多音同时播放的核心原因是 Clip.start() 是异步调用:调用后会立刻返回,在后台线程播放音频,你用固定时长的Thread.sleep没法精准匹配每个音频的实际播放时长:
- sleep时长小于音频实际时长:音频还没播完就被
clip.close()强制关闭,出现卡顿、跳音 - 部分音频加载慢:异步启动的延迟累计,就会出现前一个还在播,后一个已经启动的重叠播放问题
另外原代码还有2处小bug:
- 第一个输入循环里的
response.toUpperCase();没有把返回值赋值回response,输入小写字母不会被正确匹配 - 播放控制的switch里
case("P")没有加break,执行完播放逻辑后会走到default分支输出无效响应
修复方案
方案1:用播放完成监听器替代固定sleep(适配现有代码的最小修改)
修改play方法,不用固定sleep,等待音频实际播放完成再关闭Clip:
public void play(File filename)throws UnsupportedAudioFileException, IOException,InterruptedException, LineUnavailableException{ AudioInputStream audioStream = AudioSystem.getAudioInputStream(filename); Clip clip = AudioSystem.getClip(); clip.open(audioStream); // 加锁等待播放完成 Object lock = new Object(); clip.addLineListener(event -> { if (event.getType() == LineEvent.Type.STOP) { synchronized (lock) { lock.notify(); } } }); clip.start(); synchronized (lock) { lock.wait(); // 一直等到播放完成的通知,不用固定时长sleep } clip.close(); }
这个方案修改量最小,能完美解决按顺序逐个播放的问题,不会出现重叠或者提前截断的问题。
方案2:预加载音频资源优化播放流畅度
现有代码每次播放都重新读本地文件、创建Clip,多次播放或者音符数量多的时候会有IO延迟,可以在用户输入完音符序列之后,就把所有用到的Clip提前加载好存到数组里,播放的时候直接启动就行,不用重复加载。
方案3:预拼接音频流一次性播放(适合生成固定曲目场景)
如果不需要实时控制每个音符的播放启停,可以提前把所有选中的音符的AudioInputStream按顺序拼接成一个完整的AudioInputStream,再用一个Clip一次性播放,完全没有拼接间隙,流畅度最高。
进阶音乐编辑器实现方案
如果要做功能更完整的音乐编辑器,可以基于Java Sound API扩展如下能力:
- 支持自定义每个音符的播放时长、音量
- 支持多轨道同时播放(比如同时加鼓点和钢琴音)
- 支持编辑完成后导出为完整的WAV音频文件
原生Java Sound API就能实现以上所有功能,不需要引入额外依赖。
内容的提问来源于stack exchange,提问作者Chingyam yeung
相关产品推荐
相关产品推荐

