SFML2.6 音频模块--录制音频

将音频录制到音频缓冲区

捕获的音频数据最常见的用途是保存到声音缓冲区(sf::SoundBuffer)中,以便可以播放或保存到文件中。

可以使用sf::SoundBufferRecorder类的非常简单的接口来实现这一点:

// first check if an input audio device is available on the system
if (!sf::SoundBufferRecorder::isAvailable())
{
    // error: audio capture is not available on this system
    ...
}

// create the recorder
sf::SoundBufferRecorder recorder;

// start the capture
recorder.start();

// wait...

// stop the capture
recorder.stop();

// retrieve the buffer that contains the captured audio data
const sf::SoundBuffer& buffer = recorder.getBuffer();

SoundBufferRecorder::isAvailable静态函数检查系统是否支持音频录制。如果返回false,则您将无法使用sf::SoundBufferRecorder类。

start和stop函数是不言自明的。捕获在其自己的线程中运行,这意味着您可以在start和stop之间进行任何操作。在捕获结束后,录制的音频数据可在用getBuffer函数获取的声音缓冲区中使用。

利用录制的数据,您可以执行以下操作:

  • 保存到文件
buffer.saveToFile("my_record.ogg");
  • 直接播放
sf::Sound sound(buffer);
sound.play();
  • 访问原始音频数据并进行分析、转换等操作。
const sf::Int16* samples = buffer.getSamples();
std::size_t count = buffer.getSampleCount();
doSomething(samples, count);

如果你想在recorder被销毁或重新启动后使用捕获的音频数据,请不要忘记复制音频缓冲区。

选择输入设备

如果您的计算机连接了多个声音输入设备(例如麦克风、声音接口(外部声卡)或网络摄像头麦克风),则可以指定用于录制的设备。声音输入设备通过其名称进行标识。std::vector< std::string > 包含所有连接设备的名称,可以通过静态的SoundBufferRecorder::getAvailableDevices()函数获得。然后,通过将所选设备的名称传递给setDevice()方法,可以从列表中选择一个设备进行录制。甚至可以在录制过程中更改设备。

当前使用的设备名称可以通过调用getDevice()方法获得。如果您没有自己选择设备,则将使用默认设备。其名称可以通过静态SoundBufferRecorder::getDefaultDevice()函数获得。

以下是如何设置输入设备的简单示例:

// get the available sound input device names
std::vector<std::string> availableDevices = sf::SoundRecorder::getAvailableDevices();

// choose a device
std::string inputDevice = availableDevices[0];

// create the recorder
sf::SoundBufferRecorder recorder;

// set the device
if (!recorder.setDevice(inputDevice))
{
    // error: device selection failed
    ...
}

// use recorder as usual

自定义录制

如果将捕获的数据存储在声音缓冲区中不是您想要的,您可以编写自己的录制器。这样做将允许您在捕获期间处理音频数据,(几乎)直接从录制设备。这样,您可以将捕获的音频流式传输到网络上,在其上执行实时分析等操作。

要编写自己的录制器,您必须从sf::SoundRecorder抽象基类继承。实际上,sf::SoundBufferRecorder只是这个类的内置特化。

您只需要在派生类中覆盖一个虚拟函数:onProcessSamples。每次捕获一个新的音频样本块时,它将被调用,因此这是您实现特定任务的地方。

默认情况下,音频样本每100毫秒提供给onProcessSamples方法一次。您可以使用setProcessingInterval方法更改间隔。如果您想实时处理录制的数据,则可以使用较小的间隔。请注意,这只是一个提示,实际周期可能会有所不同,因此不能依赖它来实现精确的定时。

还有两个额外的虚拟函数,您可以选择覆盖:onStart和onStop。它们分别在捕获开始/停止时调用。它们适用于初始化/清理任务。

以下是完整派生类的模板:

class MyRecorder : public sf::SoundRecorder
{
    virtual bool onStart() // optional
    {
        // initialize whatever has to be done before the capture starts
        ...

        // return true to start the capture, or false to cancel it
        return true;
    }

    virtual bool onProcessSamples(const sf::Int16* samples, std::size_t sampleCount)
    {
        // do something useful with the new chunk of samples
        ...

        // return true to continue the capture, or false to stop it
        return true;
    }

    virtual void onStop() // optional
    {
        // clean up whatever has to be done after the capture is finished
        ...
    }
}

isAvailable / start / stop函数定义在sf::SoundRecorder基类中,并因此继承在每个派生类中。这意味着您可以用与上文提到的sf::SoundBufferRecorder类完全相同的方式使用任何录音机类。

if (!MyRecorder::isAvailable())
{
    // error...
}

MyRecorder recorder;
recorder.start();
...
recorder.stop();

线程问题

由于录音是在单独的线程中进行的,因此了解发生的事情以及发生的位置非常重要。

onStart将直接由start函数调用,因此在调用它的同一线程中执行。但是,onProcessSample和onStop将始终从SFML创建的内部录制线程中调用。

如果您的录音机使用可能在调用线程和录制线程中同时访问的数据,则必须保护它(例如使用互斥锁)以避免并发访问,这可能会导致未定义的行为–记录损坏的数据,崩溃等。

如果您对线程不太熟悉,可以参考相应的教程以获取更多信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值