Вы можете использовать AVRecorder или что-то более низкое, например, аудиоустройство ввода-вывода реального времени.
Понятие «громкость» довольно расплывчато.Возможно, вы захотите взглянуть на разницу между вычислением пиковых и среднеквадратичных значений и понять, как интегрировать среднеквадратичное значение за определенный промежуток времени (скажем, 300 мс, который использует измеритель VU).
По сути, вы суммируете всеквадраты значений.Вы бы взяли квадратный корень и преобразовали бы в dBFS с 10 * log10f (sqrt (sum / num_samples)), но вы можете сделать это без sqrt за один шаг с 20 * log10f (sum / num_samples).
Вам нужно будет много отрегулировать время интеграции и пороги, чтобы заставить его вести себя так, как вы хотите.
Для смещения высоты тона, я думаю, OpenAL с этим справится, техника, стоящая за ним, называется bandограниченная интерполяция - https://ccrma.stanford.edu/~jos/resample/Theory_Ideal_Bandlimited_Interpolation.html
В этом примере показано среднеквадратичное вычисление среднеквадратичного значения.Круговой буфер поддерживает историю квадратов и устраняет необходимость суммирования квадратов при каждой операции.Я не запускал его, поэтому рассматривал его как псевдокод;)
Пример:
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);
}
};