-->

Android的音频 - 流正弦波音发生器古怪的行为(Android Audio - Streami

2019-06-23 15:13发布

第一次海报在这里。 我平时喜欢找自己的答案(无论是通过研究或试验和错误),但我在这里难住了。

我想要做的事:我建立一个简单的Android音频合成。 现在,我只是打在实时正弦基调,在为用户调整它改变音调的频率UI的滑块。

我是如何构建它:基本上,我有两个线程-一个工作线程和输出线程。 工作线程简单地填充与每一个其蜱()方法被调用时的正弦波数据的缓冲器。 一旦缓冲区被填满,它就会提醒输出线,该数据已准备好被写入音轨。 我使用两个线程的原因是audiotrack.write()块,我想工作线程能够开始尽快处理其数据(而不是等待音轨写完)。 UI上的滑块只是改变了工作线程的变量,使得任何改变的频率(通过滑块)将由工作线程的蜱()方法来读取。

什么工作:几乎所有的东西; 螺纹沟通好,有似乎并不在播放任何间隙或点击。 尽管大的缓冲区大小(感谢机器人),响应是OK。 频率可变确实变化,因为这样做在蜱()方法中的缓冲液的计算过程中使用的中间值(由Log.i验证())。

什么不起作用:出于某种原因,我似乎无法获得可听频率连续变化。 当我调整滑块,频率变化步骤,经常一样宽四分之三或五分之四。 从理论上讲,我应该听变化分钟为1Hz的,但我不是。 奇怪的是,它好像更改滑块造成正弦波通过在调和级数间隔发挥; 不过,我可以验证频率变量不是捕捉到默认频率的整数倍。

我的音轨被设置为这样的:

_buffSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
_audioTrackOut = new AudioTrack(AudioManager.STREAM_MUSIC, _sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, _buffSize, AudioTrack.MODE_STREAM);

工作线程的缓冲区被填充(通过蜱())这样:

public short[] tick()
{
    short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes) / 2
    for (int i = 0; i < _outBuffSize/2; i++) 
    {
        outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle)));

        //Update angleIncrement, as the frequency may have changed by now
        _angleIncrement = (float) (2.0f * Math.PI) * _freq / _sampleRate;
        _currentAngle = _currentAngle + _angleIncrement;    
    }
    return outBuff;     
}

音频数据被这样写的:

_audioTrackOut.write(fromWorker, 0, fromWorker.length);

任何帮助将不胜感激。 我怎样才能得到更多的频率逐渐变化? 我很有信心,我的蜱逻辑()是合理的,因为Log.i()验证变量angleIncrement和currentAngle中被正确地更新。

谢谢!

更新:

我在这里发现了一个类似的问题: Android的AudioTrack缓冲问题的解决提出了一个必须能够生产样品足够快的audioTrack,这是有道理的。 我垂下采样率22050Hz的,并进行了一些经验测试 - 我可以填补我缓冲液(通过蜱())在最坏的情况下大约为6ms。 这是绰绰有余。 在22050Hz的,所述audioTrack给我的2048个样本(或4096个字节)的缓冲大小。 因此,每个填充的缓冲器持续音频,这是比需要创建的数据(1〜6毫秒)更长的〜0.0928秒。 所以,我知道,我没有产生样本足够快的任何问题。

我也应该注意到,有关应用程序生命周期的前3秒,它工作正常 - 滑块的顺利横扫产生的音频输出平稳横扫。 在此之后,它开始变得真正波涛汹涌(音大约每100Mhz的唯一变化),之后,将停止响应滑块输入的。

我也是固定的一个错误,但我不认为它有一个作用。 AudioTrack.getMinBufferSize()返回在BYTES允许的最小缓冲器大小以及我使用这个号码作为缓冲器的蜱的长度() - 我现在用这一半数量(每个样品2个字节)。

Answer 1:

我找到了!

原来问题无关与缓冲器或线程。

这听起来在第一几秒钟的罚款,因为计算的角度相对较小。 在程序运行时,角度增加,Math.sin(_currentAngle)开始产生不可靠的值。

所以,我代替Math.sin()FloatMath.sin()

我还更换_currentAngle = _currentAngle + _angleIncrement;

_currentAngle = ((_currentAngle + _angleIncrement) % (2.0f * (float) Math.PI)); 的,所以角度始终<2 * PI。

奇迹般有效! 非常感谢您的帮助,腐败的机器人!



文章来源: Android Audio - Streaming sine-tone generator odd behaviour