我想通过使用DLL在Game Maker中使用PortAudio
我在C ++中创建了回调函数,并用它来计算传入样本流的频率。在DLL中我做了一些导出函数:一个用于启动流,一个用于关闭流,另一个用于获取回调生成的频率变量。
现在当我在Game Maker中调用PortAudioStart()函数时,游戏关闭时没有任何警告/错误/消息。我将MessageBox()放在代码行之间,以检查崩溃的来源。它显示了第一个,第二个和第三个,然后它崩溃了,甚至没有显示错误MessageBox。所以事实证明Pa_StartStream()引起了它。
现在我想知道:为什么会发生这种崩溃,我该如何解决呢? 注意:我通过让C ++程序调用它来测试这个DLL,在这种情况下,它完全按计划工作。
我使用GM8.0和NetBeans 7.3与Cygwin 4的gcc编译器。
开始和结束函数(省略全局变量的所有包含和定义):
#define GMEXPORT extern "C" __declspec (dllexport)
GMEXPORT double __cdecl PortAudioStart() {
err = Pa_Initialize();
if( err != paNoError ) goto error;
MessageBoxA(NULL, "1", "PortAudio DLL", MB_ICONINFORMATION);
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
goto error;
}
inputParameters.channelCount = 1; /* mono input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
MessageBoxA(NULL, "2", "PortAudio DLL", MB_ICONINFORMATION);
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL, //&outputParameters
SAMPLE_RATE,
FRAMES_PER_BUFFER,
0,
PaCallback,
NULL );
if( err != paNoError ) goto error;
MessageBoxA(NULL, "3", "PortAudio DLL", MB_ICONINFORMATION);
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
MessageBoxA(NULL, "4", "PortAudio DLL", MB_ICONINFORMATION);
return 1;
error:
MessageBoxA(NULL, "Apparently it doesn't work!", "PortAudio DLL", MB_ICONINFORMATION);
Pa_Terminate();
return 0;
}
GMEXPORT double __cdecl PortAudioEnd() {
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
Pa_Terminate();
return 1;
error:
MessageBoxA(NULL, "Apparently it doesn't work!", "PortAudio DLL", MB_ICONINFORMATION);
Pa_Terminate();
return 0;
}
GMEXPORT double __cdecl getFreq()
{
if (Pa_IsStreamStopped(stream) == 0)
{
return frequency; // this variable is constantly changed in the callback function
}
else
{
return 0;
}
}
void calculateFreq(bool sign)
{
unsigned int j;
bool check;
diffsamp = maxsamp - minsamp;
if (!sign)
{
diffsampmax = max((diffsampmax*.85), (double)diffsamp);
maxsamp = 0;
}
if (sign)
{
diffsampmax = max((diffsampmax*.85), (double)diffsamp);
minsamp = 0;
}
check = ( diffsamp > max(25.0,diffsampmax*.90) );
if (sign == lastsign)
{
check = false;
}
if (check)
{
if (timepassed - peaks[0] < 500)
{
for ( j=numpeaks-1; j>0; j-- )
{
peaks[j] = peaks[j-1];
}
}
else
{
for ( j=0; j<numpeaks; j++ )
{
peaks[j] = 0;
}
}
peaks[0] = timepassed;
double diff = peaks[0]-peaks[numpeaks-1];
double peaktime = diff/(numpeaks-1)*2; //*2 because maxdiff is at +>- and ->+
frequency = 1/((double)peaktime/(double)SAMPLE_RATE);
if (peaks[numpeaks-1] <= 0 || frequency < 20) frequency = 0;
lastsign = sign;
}
}
static int PaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
const SAMPLE *in = (const SAMPLE*)inputBuffer;
unsigned int i;
unsigned int j;
(void) timeInfo; // Prevent unused variable warnings.
(void) statusFlags;
(void) userData;
SAMPLE samp;
if( inputBuffer == NULL )
{
//nothing happens
}
else
{
for( i=0; i<framesPerBuffer; i++ )
{
timepassed += 1;
samp = *in++;
changed = false;
if (samp > 0)
{
if (!sign)
{
sign = true;
changed = true;
}
maxsamp = max(maxsamp,samp);
}
else
{
if (sign)
{
sign = false;
changed = true;
}
minsamp = min(minsamp,samp);
}
if (changed)
{
calculateFreq(sign);
}
}
}
return paContinue;
}
GML:
//// Script: pa_init()
globalvar _pa_freq,_pa_start,_pa_end;
var dll_name;
dll_name = "c:\Users\<Username>\Documents\NetBeansProjects\GMDLLtest\dist\Debug\Cygwin_4.x-Windows\libGMDLLtest.dll";
_pa_freq = external_define(dll_name, "getFreq", dll_cdecl, ty_real, 0);
_pa_start = external_define(dll_name, "PortAudioStart", dll_cdecl, ty_real, 0);
_pa_end = external_define(dll_name, "PortAudioEnd", dll_cdecl, ty_real, 0);
////--------------------------------------------------------------------------------
//// Script: pa_start()
return external_call(_pa_start);
////--------------------------------------------------------------------------------
//// Script: pa_end()
return external_call(_pa_end);
////--------------------------------------------------------------------------------
//// Script: pa_freq()
return external_call(_pa_freq);
P.S:如果有什么不清楚的地方,请问,我对C ++的了解并不是很出色。