2017-06-04 102 views
1

我試圖不斷播放聲音,這應該改變smoothley的頻率。例如,我的AudioTrack目前正在以100赫茲的頻率播放,而新的頻率是1000赫茲。然後我不想讓頻率跳躍,而是讓smoothley適應變化。我目前的代碼如下所示:平滑的頻率變化

int buffSize = AudioTrack.getMinBufferSize(sampleRate, 
              AudioFormat.CHANNEL_OUT_MONO, 
              AudioFormat.ENCODING_PCM_16BIT); 
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, 
             AudioFormat.CHANNEL_OUT_MONO, 
             AudioFormat.ENCODING_PCM_16BIT, buffSize, 
             AudioTrack.MODE_STREAM); 
short samples[] = new short[buffSize]; 
int amp = 10000; 
double twopi = 8. * Math.atan(1.); 
double phase = 0.0; 
audioTrack.play(); 
while (playing) 
{ 
    double newFrequency = getFrequency(); 
    for (int i = 0; i < buffSize; i++) 
    { 
     samples[i] = (short) (amp * Math.sin(phase)); 
     phase += twopi * newFrequency/sampleRate; 
    } 
    audioTrack.write(samples, 0, buffSize); 
} 
audioTrack.stop(); 
audioTrack.release(); 

這當然是在後臺運行。我的sampleRate自動設置爲可能的最低值:

private int getMinSampleRate() 
{ 
    for (int i = 1; i < 100000; i++) 
     if (AudioTrack.getMinBufferSize(i, AudioFormat.CHANNEL_OUT_MONO, 
             AudioFormat.ENCODING_PCM_16BIT) > 0) 
      return i; 

    return -1; 
} 

回答

1

您可以使用low-pass filter來平滑過渡。這是另一個example

double currentFrequency = getFrequency(); 
double smoothing = 10; // calculate based on your sample rate and desired time delta for the change 
while (playing) 
{ 
    double newFrequency = getFrequency(); 
    for (int i = 0; i < buffSize; i++) 
    { 
     // because you are filling the buffer, deltaTime will be a constant: the time between samples 
     currentFrequency += deltaTime * (newFrequency - currentFrequency)/smoothing; 
     samples[i] = (short) (amp * Math.sin(phase)); 
     phase += twopi * currentFrequency/sampleRate; 
    } 
    audioTrack.write(samples, 0, buffSize); 
} 

保持頻率的歷史記錄,並根據增量,使用增量步驟緩慢地將其更改爲新值。對於大三角洲,價值將在開始時變化更快,然後在結束時變慢。 IIRC,這稱爲一階濾波器,因爲您不控制變化的加速度。二階濾波器將平滑加速。

有很多不同的技術,請查看Wikipedia的過濾器。