2009-04-11 3 views
5

다음 코드를 실행하면 백그라운드에서 약간의 왜곡 (윙윙 거리는 소리)이 발생합니다. 그것의 미묘한 성질 때문에 바이트 캐스팅 (byte casting)과 함께 일종의 앨리어스가 있다고 믿는다.Java에서 사인파를 생성 할 때 백그라운드에서 노이즈가 발생했습니다.

AudioFormat을 PCM_SIGNED = 44100.0 ㎐, 16 비트, 스테레오, 4 바이트/프레임, 빅 엔디안

주 : 데이터가 빅 엔디안되어 코드 (지금) 가정한다.

public static void playFreq(AudioFormat audioFormat, double frequency, SourceDataLine sourceDataLine) 
{ 
    System.out.println(audioFormat); 
    double sampleRate = audioFormat.getSampleRate(); 
    int sampleSizeInBytes = audioFormat.getSampleSizeInBits()/8; 
    int channels = audioFormat.getChannels(); 

    byte audioBuffer[] = new byte[(int)Math.pow(2.0, 19.0) * channels * sampleSizeInBytes]; 

    for (int i = 0; i < audioBuffer.length; i+=sampleSizeInBytes*channels) 
    { 
     int wave = (int) (127.0 * Math.sin(2.0 * Math.PI * frequency * i/(sampleRate * sampleSizeInBytes * channels)) ); 

     //wave = (wave > 0 ? 127 : -127); 

     if (channels == 1) 
     { 
      if (sampleSizeInBytes == 1) 
      { 
       audioBuffer[i] = (byte) (wave); 
      } 

      else if (sampleSizeInBytes == 2) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte)(wave >>> 8); 
      } 
     } 

     else if (channels == 2) 
     { 
      if (sampleSizeInBytes == 1) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte) (wave); 
      } 

      else if (sampleSizeInBytes == 2) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte)(wave >>> 8); 

       audioBuffer[i+2] = (byte) (wave); 
       audioBuffer[i+3] = (byte)(wave >>> 8); 
      } 
     } 
    } 

    sourceDataLine.write(audioBuffer, 0, audioBuffer.length); 
} 

답변

7

귀하의 의견에 따르면 코드가 빅 엔디안이라고 가정합니다.

기술적으로 당신은, 그러나 가장 중요한 바이트가 0

편집 항상 행운의 특질을 통해 때문에 중요하지 않는 것, 실제로은 리틀 엔디안에서 출력 위치 : 그 자세한 설명 -시 귀하의 가치는 127의 최대 값입니다. (0x00, 0x7f)를 작성해야합니다. 그러나 코드의 실제 출력은 (0x7f, 0x00) 32512입니다. 이것은 적절하게 가까운 숫자가됩니다. 16 비트 최대 값 32767이지만, 하위 8 비트는 모두 0입니다. 항상 최대 값으로 32767을 사용하는 것이 더 좋을 것이며, 필요한 경우 하단 8 비트를 버립니다.

즉, 16 비트 데이터를 출력하더라도 유효 해상도는 8 비트입니다. 이것은 음질의 부족을 설명하는 것 같습니다.

난 원시 데이터를 파일에 덤프하는 코드 버전을 만들었으며 비트 자체가 바뀌지 않는 한 잘못된 것을 볼 수 없습니다. 예기치 않은 부호 변경이나 손실 비트가 없지만 8 비트 샘플 품질과 일치하는 버즈가 있습니다. 무엇 당신의 수학은 당신이 샘플 개수에 따라 파동 방정식을 계산하면 쉬울 후 별도로 바이트 오프셋 걱정됩니다 가치에 대한

또한 :

int samples = 2 << 19; 
byte audioBuffer[] = new byte[samples * channels * sampleSizeInBytes]; 

for (int i = 0, j = 0; i < samples; ++i) 
{ 
    int wave = (int)(32767.0 * Math.sin(2.0 * Math.PI * frequency * i/sampleRate)); 
    byte msb = (byte)(wave >>> 8); 
    byte lsb = (byte) wave; 

    for (int c = 0; c < channels; ++c) { 
     audioBuffer[j++] = msb; 
     if (sampleSizeInBytes > 1) { 
      audioBuffer[j++] = lsb; 
     } 
    } 
} 
+0

아! 이제 오류를 확인하십시오. 진폭 부분을 수정 한 후에 오류가 명확 해졌지만 코드가 더 효율적입니다. 감사! – yxk

+0

분석을 완료했습니다! –

2

긴 소리를 재생하려면이 코드를 반복적으로 호출한다고 가정합니다.

생성중인 웨이브가 작성되기 전에 전체 기간을 완료하지 못할 가능성이 있습니까?

전체 기간을 완료하고 다음 웨이브가 출력에 쓰여지기 전에 웨이브가 "차단"되면, 이상한 소리가 들리 겠지만 윙윙 거리는 소리가 들릴 수도 있습니다. 예를 들어

:

 /-------\    /-------\    /-------\ 
    -----/   \  -----/   \  -----/   \ 
        \      \      \ 
        \-----     \-----     \----- 

공지 사항이 파의 부품 사이의 분리. 그것은 윙윙 거리는 소리를 일으킬 수 있습니다.

+0

예를, 그것은 그 문제가 아니다 버퍼가 있기 때문에 많은 사이클을 통해 소리에 대한 충분히 큰. 클릭에 대해서는 고려하지만 일정한 윙윙 소리는 고려하지 않습니다. – yxk

+0

이것은 올바른 대답이 아닙니다. 코드는 분명히 많은 샘플을 생성하며 각 사이클의 끝 부분에 아무런 절단이 없습니다. – Alnitak

+0

그리고 코드를 테스트하여 테스트했습니다. 실수로 8 비트 양자화 오류가 발생하여 버즈가 발생합니다. – Alnitak