在iOS上录制、修改和播放音频
编辑:最后,正如我在下面解释的那样,我使用了AVRecorder来录制语音,使用openAL进行音调转换和播放。结果很好 我有一个关于录音、修改和播放音频的问题。我以前问过一个类似的问题(),但现在我有了更多的信息,请给我一些进一步的建议 首先,这是我要做的(在主线程的一个单独线程上):在iOS上录制、修改和播放音频,ios,audio,avfoundation,audio-recording,pitch,Ios,Audio,Avfoundation,Audio Recording,Pitch,编辑:最后,正如我在下面解释的那样,我使用了AVRecorder来录制语音,使用openAL进行音调转换和播放。结果很好 我有一个关于录音、修改和播放音频的问题。我以前问过一个类似的问题(),但现在我有了更多的信息,请给我一些进一步的建议 首先,这是我要做的(在主线程的一个单独线程上): 监控iphone麦克风 检查声音是否大于一定音量 如果高于阈值,则开始录制,例如,此人开始讲话 继续记录,直到音量降至阈值以下,例如,人员停止讲话 修改录制声音的音调 播放声音 我正在考虑使用AVRecorde
所以我的问题是,我在上面列出的几点中的想法是否正确,我是否遗漏了什么,或者是否有更好/更简单的方法来做到这一点。我是否可以避免混用音频库,也可以使用AVFoundation来更改音高?您可以使用AVRecorder或类似实时IO音频单元的更低版本 “体积”的概念相当模糊。您可能希望了解计算峰值和RMS值之间的差异,并了解如何在给定时间内积分RMS值(例如VU仪表使用的300ms) 基本上你要求所有值的平方和。您可以取平方根,并使用10*log10f(sqrt(sum/num_samples))转换为dBFS,但使用20*log10f(sum/num_samples)一步就可以不用sqrt 您需要对集成时间和阈值进行大量调整,以使其按您想要的方式运行 对于音高变换,我认为OpenAL采用了这种技巧,其背后的技术称为带限插值- 此示例将rms计算显示为运行平均值。循环缓冲区保持平方的历史记录,并且消除了每次操作对平方求和的需要。我没有运行它,所以请将其视为伪代码;) 例如:
class VUMeter
{
protected:
// samples per second
float _sampleRate;
// the integration time in seconds (vu meter is 300ms)
float _integrationTime;
// these maintain a circular buffer which contains
// the 'squares' of the audio samples
int _integrationBufferLength;
float *_integrationBuffer;
float *_integrationBufferEnd;
float *_cursor;
// this is a sort of accumulator to make a running
// average more efficient
float _sum;
public:
VUMeter()
: _sampleRate(48000.0f)
, _integrationTime(0.3f)
, _sum(0.)
{
// create a buffer of values to be integrated
// e.g 300ms @ 48khz is 14400 samples
_integrationBufferLength = (int) (_integrationTime * _sampleRate);
_integrationBuffer = new float[_integrationBufferLength + 1];
bzero(_integrationBuffer, _integrationBufferLength);
// set the pointers for our ciruclar buffer
_integrationBufferEnd = _integrationBuffer + _integrationBufferLength;
_cursor = _integrationBuffer;
}
~VUMeter()
{
delete _integrationBuffer;
}
float getRms(float *audio, int samples)
{
// process the samples
// this part accumulates the 'squares'
for (int i = 0; i < samples; ++i)
{
// get the input sample
float s = audio[i];
// remove the oldest value from the sum
_sum -= *_cursor;
// calculate the square and write it into the buffer
double square = s * s;
*_cursor = square;
// add it to the sum
_sum += square;
// increment the buffer cursor and wrap
++_cursor;
if (_cursor == _integrationBufferEnd)
_cursor = _integrationBuffer;
}
// now calculate the 'root mean' value in db
return 20 * log10f(_sum / _integrationBufferLength);
}
};
class真空计
{
受保护的:
//每秒采样数
浮式采样器;
//积分时间(秒)(vu计为300ms)
浮点积分时间;
//它们维护一个循环缓冲区,其中包含
//音频样本的“正方形”
int_积分缓冲长度;
浮点*集成缓冲区;
浮点*\u集成缓冲区结束;
浮动*光标;
//这是一种用于运行的累加器
//平均效率更高
浮点数;
公众:
VUMeter()
:_采样器(48000.0f)
积分时间(0.3f)
,_和(0)
{
//创建要集成的值缓冲区
//例如,48khz时300ms为14400个样本
_integrationBufferLength=(int)(\u integrationTime*\u sampleRate);
_integrationBuffer=新浮点[_integrationBufferLength+1];
bzero(_integrationBuffer,_integrationBufferLength);
//为循环缓冲区设置指针
_integrationBufferEnd=\u integrationBuffer+\u integrationBufferLength;
_游标=\u集成缓冲区;
}
~VUMeter()
{
删除集成缓冲区;
}
浮点getRms(浮点*音频,整数样本)
{
//处理样品
//此部分累积“正方形”
对于(int i=0;i
您可以使用AVRecorder或类似实时IO音频单元的更低版本
“体积”的概念相当模糊。您可能希望了解计算峰值和RMS值之间的差异,并了解如何在给定时间内积分RMS值(例如VU仪表使用的300ms)
基本上你要求所有值的平方和。您可以取平方根,并使用10*log10f(sqrt(sum/num_samples))转换为dBFS,但使用20*log10f(sum/num_samples)一步就可以不用sqrt
您需要对集成时间和阈值进行大量调整,以使其按您想要的方式运行
对于音高变换,我认为OpenAL采用了这种技巧,其背后的技术称为带限插值-
此示例将rms计算显示为运行平均值。循环缓冲区保持平方的历史记录,并且消除了每次操作对平方求和的需要。我没有运行它,所以请将其视为伪代码;)
例如:
class VUMeter
{
protected:
// samples per second
float _sampleRate;
// the integration time in seconds (vu meter is 300ms)
float _integrationTime;
// these maintain a circular buffer which contains
// the 'squares' of the audio samples
int _integrationBufferLength;
float *_integrationBuffer;
float *_integrationBufferEnd;
float *_cursor;
// this is a sort of accumulator to make a running
// average more efficient
float _sum;
public:
VUMeter()
: _sampleRate(48000.0f)
, _integrationTime(0.3f)
, _sum(0.)
{
// create a buffer of values to be integrated
// e.g 300ms @ 48khz is 14400 samples
_integrationBufferLength = (int) (_integrationTime * _sampleRate);
_integrationBuffer = new float[_integrationBufferLength + 1];
bzero(_integrationBuffer, _integrationBufferLength);
// set the pointers for our ciruclar buffer
_integrationBufferEnd = _integrationBuffer + _integrationBufferLength;
_cursor = _integrationBuffer;
}
~VUMeter()
{
delete _integrationBuffer;
}
float getRms(float *audio, int samples)
{
// process the samples
// this part accumulates the 'squares'
for (int i = 0; i < samples; ++i)
{
// get the input sample
float s = audio[i];
// remove the oldest value from the sum
_sum -= *_cursor;
// calculate the square and write it into the buffer
double square = s * s;
*_cursor = square;
// add it to the sum
_sum += square;
// increment the buffer cursor and wrap
++_cursor;
if (_cursor == _integrationBufferEnd)
_cursor = _integrationBuffer;
}
// now calculate the 'root mean' value in db
return 20 * log10f(_sum / _integrationBufferLength);
}
};
class真空计
{
受保护的:
//每秒采样数
浮式采样器;
//积分时间(秒)(vu计为300ms)
浮点积分时间;
//它们维护一个循环缓冲区,其中包含
//音频样本的“正方形”
int_积分缓冲长度;
浮点*集成缓冲区;
浮点*\u集成缓冲区结束;
浮动*光标;
//这是一种用于运行的累加器
//平均效率更高
浮点数;
公众:
VUMeter()
:_采样器(48000.0f)
积分时间(0.3f)
,_和(0)
{
//创建要集成的值缓冲区
//例如,48khz时300ms为14400个样本
_int