通過OpenAL對音訊新增音效並存儲
阿新 • • 發佈:2019-02-06
1. 前言
本文談談如何對音訊進行渲染,然後儲存下來。
2. 初始化
初始化過程與之前的文章(OpenAL 使用基本流程)提到了基本一致,下面做了略微修改:
bool CHXALRender::init(int channels, int sampleRate)
{
if (m_context != nullptr)
{
clear();
}
ALCint attrs[8];
attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
if (channels == 1)
attrs[1] = ALC_MONO_SOFT;
else if(channels == 2)
attrs[1] = ALC_STEREO_SOFT;
else
{
XLOGE("Unhandled SDL channel count: %d\n", channels);
return false;
}
attrs[2] = ALC_FORMAT_TYPE_SOFT;
attrs[3 ] = ALC_SHORT_SOFT;
attrs[4] = ALC_FREQUENCY;
attrs[5] = sampleRate;
attrs[6] = 0;
mFrameSize = FramesToBytes(1, attrs[1], attrs[3]);
m_device = alcLoopbackOpenDeviceSOFT(NULL);
if(m_device == nullptr)
{
XLOGI("Create device failed!\n" );
return false;
}
if(alcIsRenderFormatSupportedSOFT(m_device, attrs[5], attrs[1], attrs[3]) == ALC_FALSE)
{
XLOGE("Render format not supported: %d, %d, %dhz\n", attrs[1], attrs[3], attrs[5]);
return false;
}
m_context = alcCreateContext(m_device, attrs);
if(m_context == nullptr)
{
XLOGE("Create context failed!\n");;
return false;
}
alcMakeContextCurrent(m_context);
alGenBuffers(MAX_CACHE, m_buffer);
alGenSources(1, &m_source);
if(CheckALError("CHXALPlayBack::init"))
return false;
for(auto buf : m_buffer)
{
m_bufferQueue.push_back(buf);
}
return true;
}
3. 處理流程
mIsRendering = true;
do {
size_t size = mWaveReader->readData(buffer, kByte, kChunckSize/kByte);
if (size <= 0)
{
XLOGI("Read end.");
break;
}
else
{
readDataSize += size;
XLOGI("Read data %d.", readDataSize);
}
mALRender->render(buffer, kByte * size, format, header->samplesPerSec);
getRenderedData(buffer, kByte * size);
size = fwrite(buffer, kByte, size, fout);
}while(1);
do {
getRenderedData(buffer, kByte * size);
size = fwrite(buffer, kByte, size, fout);
} while(alGetError() == AL_NO_ERROR && mALRender->isPlaying());
4. 渲染render
程式碼如下:
bool CHXALRender::render(const void *data, int dataSize, int format, int freq)
{
recycle();
if (data == nullptr)
{
return false;
}
ALuint buffer = 0;
if (m_bufferQueue.empty())
{
alGenBuffers(1, &buffer);
}
else
{
buffer = m_bufferQueue.front();
m_bufferQueue.pop_front();
}
alBufferData(buffer, format, data, dataSize, freq);
alSourceQueueBuffers(m_source, 1, &buffer);
resume();
}
recycle: 從OpenAL中回收buffer
resume: PlaySource
參見OpenAL 使用基本流程
5. 獲取渲染後的資料getRenderedData
void CHXALRender::getRenderedData(void *data, int len)
{
alcRenderSamplesSOFT(m_device, data, len/mFrameSize);
}