Android的音频 - 流媒体正弦音频发生器奇怪的行为 [英] Android Audio - Streaming sine-tone generator odd behaviour

查看:158
本文介绍了Android的音频 - 流媒体正弦音频发生器奇怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

first time poster here. I usually like to find the answer myself (be it through research or trial-and-error), but I'm stumped here.

我想要做的: 我建立了一个简单的Andr​​oid音频合成。现在,我只是玩一个正弦波音实时,在改变音调的频率作为用户调整其UI中的滑块。

What I'm trying to do: I'm building a simple android audio synthesizer. Right now, I'm just playing a sine-tone in real time, with a slider in the UI that changes the tone's frequency as the user adjusts it.

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

How I've built it: Basically, I have two threads - a worker thread and an output thread. The worker thread simply fills a buffer with the sine wave data every time its tick() method is called. Once the buffer is filled, it alerts the output thread that the data is ready to be written to the audio track. The reason I am using two threads is because audiotrack.write() blocks, and I want the worker thread to be able to begin processing its data as soon as possible (rather than waiting for the audio track to finish writing). The slider on the UI simply changes a variable in the worker thread, so that any changes to the frequency (via the slider) will be read by the worker thread's tick() method.

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

What works: Almost everything; The threads communicate well, there don't seem to be any gaps or clicks in the playback. Despite the large buffer size (thanks android), the responsiveness is OK. The frequency variable does change, as do the intermediate values used during the buffer calculations in the tick() method (verified by Log.i()).

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

What doesn't work: For some reason, I can't seem to get a continuous change in audible frequency. When I adjust the slider, the frequency changes in steps, often as wide as fourths or fifths. Theoretically, I should be hearing changes as minute as 1Hz, but I'm not. Oddly enough, it seems as if changes to the slider is causing the sine wave to play through intervals in the harmonic series; However, I can verify that the frequency variable is NOT snapping to integral multiples of the default frequency.

我的音轨设置为这样的:

My Audio track is set up as such:

_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);

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

The worker thread's buffer is being populated (via tick()) as such:

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;     
}

音频数据被这样写的:

The audio data is being written like this:

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

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

Any help would be greatly appreciated. How can I get more gradual changes in frequency? I'm pretty confident that my logic in tick() is sound, as Log.i() verifies that the variables angleIncrement and currentAngle are being updated properly.

感谢您!

更新:

我发现了一个类似的问题在这里:的Andr​​oid AudioTrack缓冲问题的 将溶液建议之一必须是能够生产的样品足够快的audioTrack,这是很有意义的。我垂下取样率22050Hz的,并进行了一些实证检验 - 我可以填补我的缓冲区(通过蜱())在最坏的情况下大约为6ms。这是足够有余。在22050Hz的,在audioTrack给了我2048个样本(或4096字节)的缓冲区大小。因此,每个填充缓冲器持续〜0.0928秒的音频,这是比需要创建数据(1〜6毫秒)更长的。所以,我知道,我没有任何问题,产生的样本不够快。

I found a similar problem here: Android AudioTrack buffering problems The solution proposed that one must be able to produce samples fast enough for the audioTrack, which makes sense. I lowered my sample rate to 22050Hz, and ran some empirical tests - I can fill my buffer (via tick()) in approximately 6ms in the worst case. This is more than adequate. At 22050Hz, the audioTrack gives me a buffer size of 2048 samples (or 4096 Bytes). So, each filled buffer lasts for ~0.0928 seconds of audio, which is much longer than it takes to create the data (1~6 ms). SO, I know that I don't have any problems producing samples fast enough.

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

I should also note that for about the first 3 seconds of the applications lifecycle, it works fine - a smooth sweep of the slider produces a smooth sweep in the audio output. After this, it starts to get really choppy (sound only changes about every 100Mhz), and after that, it stops responding to slider input at all.

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

I also fixed one bug, but I don't think it has an effect. AudioTrack.getMinBufferSize() returns the smallest allowable buffer size in BYTES, and I was using this number as the length of the buffer in tick() - I now use half this number (2 Bytes per sample).

推荐答案

我找到了!

原来,这个问题已经没有任何关系的缓冲区或螺纹。

It turns out the problem has nothing to do with buffers or threading.

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

It sounds fine in the first couple of seconds, because the angle of the computation is relatively small. As the program runs and the angle grows, Math.sin(_currentAngle) begins to produce unreliable values.

所以,我换成 Math.sin() FloatMath.sin()

我也取代 _currentAngle = _currentAngle + _angleIncrement;

_currentAngle =((_currentAngle + _angleIncrement)%(2.0f *(浮点)Math.PI)); ,所以角度始终&LT; 2 * PI。

_currentAngle = ((_currentAngle + _angleIncrement) % (2.0f * (float) Math.PI));, so the angle is always < 2*PI.

工程就像一个魅力!非常感谢您的帮助,腐败的机器人!

Works like a charm! Thanks very much for your help, praetorian droid!

这篇关于Android的音频 - 流媒体正弦音频发生器奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆