使用Java源数据线进行音频时弹出/破解

我遇到了Java源数据线的问题。 我需要播放一个音调,所以我创建了一个仅代表音调的Tone类。 一切都很好,除了当我播放声音时,扬声器在声音的开头弹出。 有没有什么办法解决这一问题? 这是一个研究项目,需要在没有噼啪声的情况下运行,因为这可能会影响结果。 源代码如下。 谢谢!

package edu.jhu.halberda.audiopanamath; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.FloatControl; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.swing.JOptionPane; public class Tone { public enum Channel { LEFT, RIGHT, STEREO }; public static final float SAMPLE_RATE = 44104; // Should be a multiple of 8 protected byte[] buf; protected int hz, msecs; protected double vol; protected Channel channel; Tone() { } // necessary so that subclasses don't complain public Tone(int hz, int msecs, double vol, Tone.Channel channel) { if (hz <= 0) throw new IllegalArgumentException("Frequency <= 0 hz"); if (msecs <= 0) throw new IllegalArgumentException("Duration  1.0 || vol < 0.0) throw new IllegalArgumentException("Volume out of range 0.0 - 1.0"); this.channel = channel; this.hz = hz; this.vol = vol; this.msecs = msecs; generateTone(); } private void generateTone() { int len = (int)Math.ceil((2 * SAMPLE_RATE * msecs / 1000.0d)); if (len % 2 == 1) len = len + 1; buf = new byte[len]; for (int i = 0; i < buf.length /2; i++) { double angle = (i * hz / SAMPLE_RATE) * 2.0 * Math.PI; buf[2*i + 1] = buf[2*i] = (byte) Math.round(Math.sin(angle) * 127.0 * vol); } } public void play(SourceDataLine sdl) { // takes an opened SourceDataLine FloatControl panControl = (FloatControl) sdl .getControl(FloatControl.Type.PAN); if (panControl != null) { // Preferred method using built in sound // control, but not guaranteed to be // available if (channel == Channel.LEFT) { panControl.setValue(-1); } else if (channel == Channel.RIGHT) { panControl.setValue(1); } else { panControl.setValue(0); } } else { // fallback method is directly manipulates the buffer if (channel != Channel.STEREO) { int nSilenceOffset; byte nSilenceValue = 0; if (channel == Channel.LEFT) { nSilenceOffset = 1; } else { nSilenceOffset = 0; } for (int i = 0; i < buf.length; i += 2) { buf[i + nSilenceOffset] = nSilenceValue; } } } sdl.write(buf, 0, buf.length); sdl.drain(); } public static void main(String[] args) { AudioFormat af = new AudioFormat(Tone.SAMPLE_RATE, 8, 2, true, false); SourceDataLine sdl; try { sdl = AudioSystem.getSourceDataLine(af); } catch (LineUnavailableException e) { JOptionPane.showMessageDialog(null, "Couldn't get sound line"); return; } try { sdl.open(af); } catch (LineUnavailableException e) { JOptionPane.showMessageDialog(null, "Couldn't open sound line"); return; } sdl.start(); Tone left = new Tone(400, 2000, .5, Tone.Channel.LEFT); System.out.println("Playing left"); long t = System.currentTimeMillis(); left.play(sdl); System.out.println(System.currentTimeMillis()-t); System.out.println("Finished left"); Tone right = new Tone(400, 2000, .5, Tone.Channel.RIGHT); System.out.println("Playing right"); right.play(sdl); System.out.println("Finished right"); sdl.stop(); sdl.close(); } } 

尝试这种变体,它使用粗略的淡入/淡出效果。

 private void generateTone() { int len = (int)Math.ceil((2 * SAMPLE_RATE * msecs / 1000.0d)); if (len % 2 == 1) len = len + 1; buf = new byte[len]; int fadeCount = 1600; for (int i = 0; i < buf.length /2; i++) { double fadeRate = 1.0; double angle = (i * hz / SAMPLE_RATE) * 2.0 * Math.PI; if (i(buf.length/2)-fadeCount) { int bufLength = buf.length; int buf = bufLength/2; int countDown = buf-i; fadeRate = (double)countDown/(double)(fadeCount); } buf[2*i + 1] = buf[2*i] = (byte) Math.round( Math.cos(angle) * 127.0 * vol * fadeRate); } }