使用 OpenAL 和 VC++ 在 winforms 中绘制音频波形
Drawing audio waveform in winforms using OpenAL and VC++
我有一个关于信号处理的研究项目,我有义务记录来自某些来源(例如麦克风)的声音并在两个图表上显示波形及其 FFT。我无法提供将缓冲区显示到图表中而不拖延整个程序的功能。
因为我还不知道 C#,所以我选择了 C++/CLI 下的 Winforms 和 OpenAL 来进行声音捕捉(声音处理方面的经验为 0,这在几个线程中被推荐,我的团队的其他成员正在使用它所以我有点不得不使用它)。我已经有了选择声音设备并将声音录制到缓冲区中的代码。我知道下面的 while 循环正在拖延程序。我正在考虑使用多线程,但不知道如何使用它。或者事件...
这是捕获开始的代码,在一些按钮事件中。
int go = 0;
const int SRATE = 44100;
const int SSIZE = 1024;
ALCdevice *hydromike;
ALbyte buffer[22050];
ALint sample;
some_event {
const char* diwajs = (msclr::interop::marshal_as<std::string>(item)).c_str();
hydromike = alcCaptureOpenDevice(diwajs, SRATE, AL_FORMAT_MONO16, SSIZE);
alcCaptureStart(hydromike);
buffering(); //function call for starting the buffer
}
void buffering(void)
{
while (go) {
alcGetIntegerv(hydromike, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
alcCaptureSamples(hydromike, (ALCvoid *)buffer, sample);
}
}
void drw(void)
{
chart1->Series["Bufor"]->Points->Clear();
for (int i = 0; i < 22050; i++)
{
chart1->Series["Bufor"]->Points->AddXY(i, (int)buffer[i]);
}
}
我设法完成了代码,问题是 UI 和 OpenAL 线程相互干扰,导致应用程序冻结。在另一个线程中启动缓冲并设置信号量解决了问题。
static Semaphore^ drawingSem = gcnew Semaphore(1, 1);
Thread^ oThread;
alcCaptureStart(hydromike);
oThread = gcnew Thread(gcnew ThreadStart(buffering));
oThread->Start();
static void buffering()
{
while (go) {
drawingSem->WaitOne();
alcGetIntegerv(hydromike, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), buffer);
alcCaptureSamples(hydromike, (ALCvoid *)buffer, sample*2);
drawingSem->Release();
}
}
void MyForm::drw()
{
drawingSem->WaitOne();
chart1->Series["Bufor"]->Points->Clear();
for (int i = 0; i < bufsize; i++)
{
chart1->Series["Bufor"]->Points->AddXY(i, (int)buffer[i]);
}
drawingSem->Release();
}
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
drw();
}
我有一个关于信号处理的研究项目,我有义务记录来自某些来源(例如麦克风)的声音并在两个图表上显示波形及其 FFT。我无法提供将缓冲区显示到图表中而不拖延整个程序的功能。
因为我还不知道 C#,所以我选择了 C++/CLI 下的 Winforms 和 OpenAL 来进行声音捕捉(声音处理方面的经验为 0,这在几个线程中被推荐,我的团队的其他成员正在使用它所以我有点不得不使用它)。我已经有了选择声音设备并将声音录制到缓冲区中的代码。我知道下面的 while 循环正在拖延程序。我正在考虑使用多线程,但不知道如何使用它。或者事件...
这是捕获开始的代码,在一些按钮事件中。
int go = 0;
const int SRATE = 44100;
const int SSIZE = 1024;
ALCdevice *hydromike;
ALbyte buffer[22050];
ALint sample;
some_event {
const char* diwajs = (msclr::interop::marshal_as<std::string>(item)).c_str();
hydromike = alcCaptureOpenDevice(diwajs, SRATE, AL_FORMAT_MONO16, SSIZE);
alcCaptureStart(hydromike);
buffering(); //function call for starting the buffer
}
void buffering(void)
{
while (go) {
alcGetIntegerv(hydromike, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
alcCaptureSamples(hydromike, (ALCvoid *)buffer, sample);
}
}
void drw(void)
{
chart1->Series["Bufor"]->Points->Clear();
for (int i = 0; i < 22050; i++)
{
chart1->Series["Bufor"]->Points->AddXY(i, (int)buffer[i]);
}
}
我设法完成了代码,问题是 UI 和 OpenAL 线程相互干扰,导致应用程序冻结。在另一个线程中启动缓冲并设置信号量解决了问题。
static Semaphore^ drawingSem = gcnew Semaphore(1, 1);
Thread^ oThread;
alcCaptureStart(hydromike);
oThread = gcnew Thread(gcnew ThreadStart(buffering));
oThread->Start();
static void buffering()
{
while (go) {
drawingSem->WaitOne();
alcGetIntegerv(hydromike, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), buffer);
alcCaptureSamples(hydromike, (ALCvoid *)buffer, sample*2);
drawingSem->Release();
}
}
void MyForm::drw()
{
drawingSem->WaitOne();
chart1->Series["Bufor"]->Points->Clear();
for (int i = 0; i < bufsize; i++)
{
chart1->Series["Bufor"]->Points->AddXY(i, (int)buffer[i]);
}
drawingSem->Release();
}
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
drw();
}