您可以采用几种不同的方法在您的应用程序中获得复音。要么你自己混音,要么让 ALSA 帮你混音。
可能最简单的方法(也是最耗费资源的方法)是让 ALSA 为您进行混音。在这种情况下,您为每个打击垫打开一次 ALSA dmix 插件。您可以为每个焊盘创建一个类并将它们穿线,以便它们独立运行。每个类将音频数据加载到缓冲区,并在触发时将其播放回 ALSA dmix 插件。这是一个示例(使用提供 C++ libsox 音频文件处理、线程和 ALSA 处理的 gtkIOStream):
#include <Sox.H>
#include <ALSA.H>
#include <Thread.H>
using namespace ALSA;
class Pad : public PlayBack, WaitingThread {
Eigen::Array<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> audio; // the Eigen array which holds the audio buffer
public:
/// Constructor opens the audio plawyback device and reads in the audio file data
Pad(char* devName, string audioFile) : PlayBack(devName) {
Sox<int> sox; // instantiate libsox
sox.openRead(audioFile); // open the audio file to read
sox.read(audio); // read in the audio data
}
/// Configure the audio playback ([see here for example][2])
configurePlayback(){
// set channels, format, etc.
}
/// Playback the entire audio sound
play(){
*this<<audio; // stream the audio out through the PlayBack class
}
// In our threaded method, we wait to be signalled then we do playback, then wait again, [see here for examples on thread signalling][3]
void *threadMain(void){
while (continue) {
cond.lock();
cond.wait(); // wait till signalled
play(); // playback the audio
cond.unLock(); // unlock to be signalled again
}
return NULL;
}
};
Pad pad1("dmix", "src/audiosExa/a1.wav"); // instantiate a pad
Pad pad2("dmix", "src/audiosExa/a2.wav"); // instantiate a pad
// in your UI thread, you need to run each of the Pad thread
pad1.run();
pad2.run();
// in your UI thread, you need to signal the waiting pad threads
// Looks something like this for each pad
pad1.cond.lock(); pad1.cond.signal(); pad1.cond.unlock();
如果您想进行自己的混音,那么您将跟踪正在播放的音频垫以及您在垫的缓冲区中的位置,以便每次需要播放音频缓冲区时,将它们加在一起。在代码中(使用gtkIOStream),它看起来类似于取自ALSAPlaybackTest.C的这段代码:
const string deviceName="hw:0,0"; // could also be "default"
Playback playBack(deviceName.c_str()); // open the playback device
// configure the parameters of the playback device
Sox<short int> sox1, sox2; // instantiate two audio file readers (libsox)
int ret=sox1.openRead("src/audiosExa/a1.wav"); // load in their audio to an Eigen Array data buffer
Eigen::Array<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> pad1, pad2;
sox1.read(pad1);
ret=sox2.openRead("src/audiosExa/a2.wav");
sox2.read(pad2);
// now loop to constantly output, using outBuf to sum all pads which require output
Eigen::Array<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> outBuf;
while (continue){
// construct your output buffer by adding portions of your pads here
// something like : outBuf=pad1.block(...)+pad2.block(...)
playBack<<outBuf; // play the audio data
}