2012-08-05 3 views
5

주파수 값 배열 (예 : 440Hz, 880Hz, 1760Hz)을 사용하여 단일 AudioTrack에 결합 된 사운드를 재생하는 클래스를 만들고 있습니다. 나는 건전한 프로그래머가 아니므로, 경험있는 건전한 프로그래머에게는 상대적으로 쉬운 문제라고 생각하는 자신을 쓰는 것이 어렵습니다. 다음은 재생 메소드의 일부 코드입니다.Android - 여러 개의 정적 파형을 하나의 AudioTrack으로 믹싱

public void play() { 
    // Get array of frequencies with their relative strengths 
    double[][] soundData = getData(); 

    // TODO 
    // Perform a calculation to fill an array with the mixed sound - then play it in an infinite loop 
    // Need an AudioTrack that will play calculated loop 
    // Track sample info 
    int numOfSamples = DURATION * SAMPLE_RATE; 
    double sample[] = new double[numOfSamples]; 
    byte sound[] = new byte[2 * numOfSamples]; 

    // fill out the array 
    for (int i = 0; i < numOfSamples; ++i) { 
      sample[i] = Math.sin(2 * Math.PI * i/(SAMPLE_RATE/440)); 
    } 

    int i = 0; 
    for (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 
     sound[i++] = (byte) (val & 0x00ff); 
     sound[i++] = (byte) ((val & 0xff00) >>> 8); 
    } 

    // Obtain a minimum buffer size 
    int minBuffer = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); 

    if (minBuffer > 0) { 
     // Create an AudioTrack 
     AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
       AudioFormat.ENCODING_PCM_16BIT, numOfSamples, AudioTrack.MODE_STATIC); 

     // Write audio data to track 
     track.write(sound, 0, sound.length); 

     // Begin playing track 
     track.play(); 
    } 

    // Once everything has successfully begun, indicate such. 
    isPlaying = true; 
} 

지금이 코드는 단순히 콘서트 A (440Hz)를 재생합니다. 이 코드가 작동하는지 테스트하는 것이 었습니다. 이제 주파수를 가져 와서 일종의 계산을 수행하고 샘플 데이터를 작성해야합니다.

+0

안녕하세요 코드 주셔서 감사하지만 내가 알고 싶은 그 getdata 기능은 뭐하는거야 – Nitin

답변

2

좋아, 답은 단순한 합계 루프로 나타났습니다. 여기, 그냥 원래 하나 루프이 교체된다

// fill out the array 
    for (int i = 0; i < numOfSamples; ++i) { 
      double valueSum = 0; 

      for (int j = 0; j < soundData.length; j++) { 
       valueSum += Math.sin(2 * Math.PI * i/(SAMPLE_RATE/soundData[j][0])); 
      } 

      sample[i] = valueSum/soundData.length; 
    } 

을 자,이하는 일은, 가능한 모든 주파수를 가지고 변수, valueSum에 함께 추가, 다음의 길이에 따라 그 분할 단순히 주파수 배열은 soundData이며 이는 단순 평균입니다. 이는 임의의 긴 주파수 배열의 멋진 사인파 혼합을 만들어냅니다.

성능을 테스트하지는 않았지만 스레드에서 실행하고 있습니다. 그렇지 않으면 UI가 손상 될 수 있습니다. 그래서 이것이 도움이되기를 바랍니다. 저는 이것을 답으로 표시하고 있습니다.

2

여러 파형을 하나로 혼합하려는 경우 여러 가지 방법으로 클리핑을 방지 할 수 있습니다.

샘플 [i]가 모든 사운드의 합계를 나타내는 플로트라고 가정합니다.

HARD CLIPPING :

if (sample[i]> 1.0f) 
{ 
    sample[i]= 1.0f; 
} 
if (sample[i]< -1.0f) 
{ 
    sample[i]= -1.0f; 
} 

HEADROOM (Y = 1.1 - 곡선위한 0.2X^3 분 및 최대 1.0F 미만이 slighty CAP)

if (sample[i] <= -1.25f) 
{ 
    sample[i] = -0.987654f; 
} 
else if (sample[i] >= 1.25f) 
{ 
    sample[i] = 0.987654f; 
} 
else 
{ 
    sample[i] = 1.1f * sample[i] - 0.2f * sample[i] * sample[i] * sample[i]; 
} 

3 차 다항식 wavehapper (덜 부드럽게)의 경우 마지막 줄을 위의 마지막 줄로 대체하십시오.

sample[i]= 1.1f * sample[i]- 0.2f * sample[i] * sample[i] * sample[i];