0

DLLを使ってゲームメーカーでPortAudioを使いたいです。
C++ でコールバック関数を作成し、それを使用して受信サンプル ストリームの頻度を計算しました。DLL で、いくつかのエクスポート関数を作成しました。1 つはストリームを開始する関数、もう 1 つはストリームを閉じる関数、もう 1 つはコールバックによって生成された頻度変数を取得する関数です。
Game Maker で PortAudioStart() 関数を呼び出すと、ゲームは警告/エラー/メッセージなしでシャットダウンしました。コード行の間に MessageBox() を挿入して、クラッシュの原因を確認しました。最初、2番目、3番目のものを表示した後、クラッシュし、エラーMessageBoxも表示されませんでした。そのため、Pa_StartStream() が原因であることが判明しました。

ここで疑問に思うのは、なぜこのクラッシュが発生するのか、どうすれば修正できるのか?
注: C++ プログラムでこの DLL を呼び出せるようにして、この DLL をテストしました。その場合、完全に計画どおりに動作しました。

Cygwin 4 の gcc コンパイラで GM8.0 と NetBeans 7.3 を使用しています。

start 関数と end 関数 (グローバル変数のすべてのインクルードと定義を除外):

#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);

PS: 不明な点がある場合は、質問してください。私の C++ の知識はそれほど優れているわけではありません。

4

0 に答える 0