2017-06-04 76 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的过滤器。