2012-03-09 3 views
1

Java 소스 데이터 라인에 문제가 있습니다. 톤을 연주해야하기 때문에 톤을 나타내는 톤 클래스를 만들었습니다. 사운드를 재생할 때 스피커가 사운드의 시작 부분에 튀는 것을 제외하고는 모든 것이 잘 작동합니다. 이 문제를 해결할 방법이 있습니까? 그것은 연구 프로젝트를위한 것이며 결과에 영향을 미칠 수 있으므로 딱딱 거리지 않고 실행해야합니다. 아래 소스 코드. 감사!오디오에 Java 소스 데이터 라인을 사용할 때 튀어 오름/크래킹

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 <= 0 msecs"); 
    if (vol > 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(); 
} 

} 

답변

2

이 변형은 조잡한 페이드 인/페이드 아웃 효과를 사용합니다.

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<fadeCount) { 
      fadeRate = (double)i/(double)fadeCount; 
     } else 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); 
    } 
} 
관련 문제