2017-06-04 6 views
1

生成された1秒より短い音を再生したい。ただし、AudioTrackのminBufferSizeは常に1秒以上と思われます。いくつかのデバイスでは、bufferSizeをAudioTrack.getMinBufferSizeと評価された値より小さく設定できますが、これはすべてのデバイスで可能ではありません。 AudioTrackのサウンドを短くすることが可能かどうかを知りたい。私は現在、(私は常に新しいfrequencesを取得していますので、それは、いくつかの平滑化が含まれています)、このコードを使用しています:実際に短く生成された音を再生する

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(); 
double currentFrequency = getFrequency(); 
double smoothing = 300; 
double deltaTime = buffSize/500; 
while (playing && PreferenceManager.getDefaultSharedPreferences(
     MainActivity.this).getBoolean("effect_switch", true)) 
{ 
    double newFrequency = getFrequency(); 
    for (int i = 0; i < buffSize; i++) 
    { 
     currentFrequency += deltaTime * (newFrequency - currentFrequency)/smoothing; 
     samples[i] = (short) (amp * Math.sin(phase)); 
     phase += twopi * currentFrequency/sampleRate; 
    } 
    audioTrack.write(samples, 0, buffSize); 
} 
audioTrack.stop(); 
audioTrack.release(); 

、私は音がより頻繁に更新することにしたい、私が必要とする理由でありますより短いサンプル。

+0

むしろより短いサウンドクリップに焦点を当ててから呼び出さnewSamples()方法は、あなただけの複数の同時audiotracksを実行することはできませんか? –

+0

私はこのいくつかを試してきました。私は約80msの 'minBufferSize'を得ています(私は信じています)。 8kHzサンプリング(一般的なテレコムオーディオサンプルレート)の場合は1280バイト、44.1kHzサンプリングの場合は7056バイト(最大)です。私は1つのデバイスを試してみました。あなたはいくつかのデバイスのための大きな最小値を得ますか? 'minBufferSize'、' CHANNEL_OUT_MONO'、 'ENCODING_PCM_16BIT'を得るために同じパラメータを使用しています。 – Gary99

+0

@ Gary99私は2つのデバイスでそれをテストしました – MetaColon

答えて

1

私はあなたに解決策があると思います。私の最小バッファーは1秒よりもはるかに小さいと思われるので、バッファーに5秒のデータをロードすることで問題をシミュレートしました。このトーンも5秒のデータを作成しましたが、わずか0.5秒しか再生しませんでした。&は、これを数回繰り返しました。それはすべて私のために働く。

また、これを私が作業している現在のプロジェクトに混乱させてしまったので、コードをカットアンドペーストするのは難しいです。私が私のソリューションをテストしている間、私がここに投稿したものは、書かれた通りに正確にテストされていません。それのいくつかは、&ペースト、いくつかの擬似コードがカットされています。

重要な機能は、OnPlaybackPositionUpdateListenerを使用していることです。

private AudioTrack.OnPlaybackPositionUpdateListener audioTrackListener = new AudioTrack.OnPlaybackPositionUpdateListener() { 
    @Override 
    public void onMarkerReached(AudioTrack audioTrack) { 
     int marker = audioTrack.getNotificationMarkerPosition(); 
     // I just used 8 tones of 0.5 sec each to determine when to stop but you could make 
     //  the condition based on a button click or whatever is best for you 
     if(marker < MAX_FRAME_POSITION) { 
      audioTrack.pause(); 
      newSamples(); 
      audioTrack.play(); 
     } else { 
      audioTrack.stop(); 
     } 
     audioTrack.setNotificationMarkerPosition(marker + FRAME_MARKER); 
     Log.d(TAG, "MarkerReached"); 
    } 

    @Override 
    public void onPeriodicNotification(AudioTrack audioTrack) { 
     int position = audioTrack.getPlaybackHeadPosition(); 
     if(position < MAX_FRAME_POSITION) { 
      audioTrack.pause(); 
      newSamples(); 
      audioTrack.play(); 
     } else { 
      audioTrack.stop(); 
     } 
     Log.d(TAG, "PeriodNotification"); 
    } 
}; 

その後

audioTrack.setPlaybackPositionUpdateListener(AudioTrackListener); 

私は

audioTrack.setNotificationMarkerPosition(MARKER_FRAMES);  

...私のテストのために(繰り返し再初期化する必要がある)マーカーを使用していますが使用することができるはずです定期的な通知もあります。

audioTrack.setPositionNotificationPeriod(PERIODIC_FRAMES); 

そしてリスナー

public void newSamples() { 
    /* 
    * generate buffer, I'm doing similar to you, without the smoothing 
    */ 

    // AudioTrack write is a blocking operation so I've moved it off to it's own Thread. 
    //  Could also be done with an AsyncTask. 
    Thread thread = new Thread(writeSamples); 
    thread.start(); 
} 

private Runnable writeSamples = new Runnable() { 
    @Override 
    public void run() { 
     audioTrack.write(samples, 0, buffSize); 
    } 
}; 
+0

後で試してみます。 – MetaColon

関連する問題