猿问

音频跟踪信号发生器从陀螺仪收听

我正在尝试创建信号发生器,其频率由陀螺仪传感器数据控制(通过移动手机)。问题是,我正在调用内部,并且我对输出进行了“点击”,因为每次更新senzor时,我都会调用AudioTrackonSensorChanged


stopSinus();

setSinus(Frequency);

startSinus();

它被定义为这样


 siAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE,

 AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,

 buffsize, AudioTrack.MODE_STATIC);


public void stopSinus() {

        int checkPlay = siAudioTrack.getPlayState();

        if (checkPlay == 3) {  //

         siaudioTrack.stop();

         }

}


public void startSinus() {

        siAudioTrack.reloadStaticData();

        siAudioTrack.setLoopPoints(0, sampleCount, -1);  

        siAudioTrack.play();


}


public void setSinus(int frequency) {


    sampleCount = (int) ((float) SAMPLE_RATE / frequency);

    short sample[] = new short[sampleCount];

    int amplitude = 32767;

    double twoPi = 2 * Math.PI;;

    double phase = 0.0;


    for (int i = 0; i < sampleCount; i++) {

        sample[i] = (short) (amplitude * Math.sin(phase));

        phase += twoPi * frequency / SAMPLE_RATE;

    }

    siAudioTrack.write(sample, 0, sampleCount);

}

onSensorChanged每秒变化几次,它将在波浪中间停止发电机 - 这就是“咔哒”的来源。


有人可以告诉我如何在一整波之后停止发电机吗?如何找出os何时通过零?还是一些不同的解决方案?phase


弑天下
浏览 112回答 1
1回答

慕哥6287543

没有实际的方法来确定应用于扬声器的相位何时通过0。最好放弃它。这是一个“不同”的解决方案,我认为您会发现它的工作原理要好得多:切换到 。要获得最低的延迟,请使用最小的可用缓冲区大小 ()。MODE_STREAMgetMinBufferSize()使用专用线程向 提供波形。该线程有一项工作:根据当前频率将小段波形写入 ,(您也可以使用主线程,并不断用非阻塞写入来填充,但在我看来,使用单独的线程更优雅。线程将花费大部分时间在阻塞调用中,这意味着缓冲区以最少的工作量保持最大填充。AudioTrackAudioTrackAudioTrackwrite()摆脱 和 .从头开始音频播放,并且在离开应用之前不要停止它。startSinus()stopSinus()进行更改,以便它只是将当前频率值传达给步骤 2 中描述的线程。使用任何标准的线程间通信机制。setSinus()当需要离开应用程序时,请使用标准的线程间通信机制来通知它应该终止的线程,然后它,清理等。join()其他详细信息:让你的小。也许一次只有100个样本。这有助于最大限度地减少延迟,同时仍保持所需的阻塞行为,并且无需担心 中有多少可用空间。write()sAudioTrack在工作线程中,使用 a 来跟踪阶段(就像您现在正在做的一样)。根据频率增加相位,但不要让它变得太大!通过让它包裹,使其保持在0到2 * PI之间(否则,由于量化,较大的相位误差会悄悄进入,并且频率会意外变化)。显然,在填充每个微小的100个样品缓冲液后,您不会重置。你只是让它滚来滚去。floatphase
随时随地看视频慕课网APP

相关分类

Java
我要回答