2014-10-28 3 views
0

결합 된 주파수로 사인파를 생성하고 싶습니다. 나는 이런 식으로 갈거야 :Android. 생성 된 사인파는 매초마다 노크 노이즈를 발생합니다.

public static byte[] combineSineWave(Collection<Double> frequencies) { 
    double[] sample = new double[SAMPLE_RATE]; 
    byte[] result = new byte[2 * SAMPLE_RATE]; 

    double coefficient = 2 * Math.PI; 

    for (int i = 0; i < SAMPLE_RATE; i++) { 
     double sum = 0; 

     for (double frequency : frequencies) { 
      sum += Math.sin(coefficient * i * frequency/SAMPLE_RATE); 
     } 

     sample[i] = sum/frequencies.size(); 
    } 

    convertToPCM16Bit(sample, result); 

    return result; 
} 

private static void convertToPCM16Bit(double[] sample, byte[] result) { 
    int idx = 0; 
    for (final double dVal : sample) { 
     // scale to maximum amplitude 
     final short val = (short) ((dVal * 32767)); 
     // in 16 bit wav PCM, first byte is the low order byte 
     result[idx++] = (byte) (val & 0x00ff); 
     result[idx++] = (byte) ((val & 0xff00) >>> 8); 
    } 
} 

을 그리고이 코드에 의해 생성 된 바이트를 재생 :

AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SoundWaveGenerator.SAMPLE_RATE, 
      AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2 * SoundWaveGenerator.SAMPLE_RATE, 
      AudioTrack.MODE_STREAM); 

    audioTrack.play(); 

    while (true) { 
     byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies); 
     audioTrack.write(bytes, 0, bytes.length); 
    } 

을하지만 문제는 내가 매 순간에 대한 딸깍 소리가 날 것입니다. 뭐가 문제 야?

답변

1

듣고있는 클릭은 combineSineWave 호출 사이의 불연속입니다. combineSineWave를 호출 할 때마다 각 주파수가 0도 위상을 시작합니다. 그러나 주파수에 따라 1 초 간격이 끝날 때까지 짝수 사이클을 생성하지 못할 수 있습니다. 주파수 중 하나가 두 번째 샘플의 마지막 샘플이 90도 (1.0)가되는 것과 같으면 다음 간격을 생성 할 때 불연속이 있다고 가정합니다.

이 문제를 해결하려면 연속 통화간에 일정한 상태를 추적해야합니다. 아래에 예제를 코딩했지만 Java로 참조로 전달하는 방법을 모르겠습니다. 또한, 내가 뒤집을 가능성에 대처해야합니다.

int i = 0; 
while (true) { 
    byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies, ref i); 
    audioTrack.write(bytes, 0, bytes.length); 
} 


public static byte[] combineSineWave(Collection<Double> frequencies, ref int i) { 
    double[] sample = new double[SAMPLE_RATE]; 
    byte[] result = new byte[2 * SAMPLE_RATE]; 

    double coefficient = 2 * Math.PI; 

    for (int j = 0; j < SAMPLE_RATE; j++) { 
     double sum = 0; 

     for (double frequency : frequencies) { 
      sum += Math.sin(coefficient * i++ * frequency/SAMPLE_RATE); 
     } 
     sample[i] = sum/frequencies.size(); 
    } 

    convertToPCM16Bit(sample, result); 

    return result; 
} 

P. 루프 바깥 쪽 SAMPLE_RATE으로 나눌 수 있습니다.

double coefficient = 2 * Math.PI/SAMPLE_RATE; 
+0

좋아요, 그래서 나는 "계속"해야합니다. 그러나이 경우 나는'i' 인덱스 오버 플로우를 얻을 것이다. 또한 나는 당신의 코드'saple [0] == sample [SAMPLE_RATE + 1]'에서 그것을 보았고 문제는 여전히 남아 있었다. 사이클 수가 짝수 일 때 소리의 정확한 길이를 계산할 수 있습니까? 사인파의 2 * Math.PI 정확한 기간이라고 생각하지 않습니까? –

+1

또한 짝수 사이클이있는 길이를 미리 계산하는 것은 좋지 않습니다. 1.0000kHz의 사인파와 결합 된 1kHz의 사인파를 상상해보십시오. – jaket

+0

그래서 솔루션은 "클릭"노이즈를 따로 떼어 놓을 수 있다는 것입니다. 우리는 1 초마다 그것을들을 수는 없지만 1 시간마다 (예를 들어)들을 것이다. 사실입니까? –