#include "mex.h"
#include "matrix.h"
#include "paMat.h"
#include "portaudio.h"

/* open a portaudio stream and register a matlab callback with that
 * stream. The interface for this function is:
 *
 * function err = ...
 *  Pa_OpenDefaultStream(numInputChannels, numOutputChannels, ...
 *  sampleRate, framesPerBuffer, callback)
 *
 * Where everything is as you would expect except the "callback"
 * argument is just a string indicating the name of the function to
 * call, not any as fancy as a function pointer.
 */
void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  /* if there is already a stream open, close it, issue a matlab
     warning message */
  if(matStream != NULL) {
    mexWarnMsgTxt("There was already another stream open. Closing it...");
    paMatClose();
  }

  /* create appropriate data structure to hold info */
  data = (paMatData*)mxMalloc(sizeof(paMatData));
  if(data == NULL) {
    mexErrMsgTxt("Couldn't allocate memory for data structure!");
    return;
  }

  /* Convert matlab arguments to C arguments */
  int nInC = (int)mxGetScalar(prhs[0]);
  int nOutC = (int)mxGetScalar(prhs[1]);
  int sr = (int)mxGetScalar(prhs[2]);
  int fpb = (int)mxGetScalar(prhs[3]);
  data->samplesPerInFrame = nInC;
  data->samplesPerOutFrame = nOutC;

  /* copy name of function */
  int strLen = mxGetM(prhs[4]) + 1;
  data->function = mxMalloc(strLen * sizeof(char));
  mxGetString(prhs[4], data->function, strLen);

  /* allocate matlab arrays */
  data->nrhs = 3;
  data->prhs[0] = mxCreateDoubleMatrix(1, data->samplesPerInFrame*fpb, mxREAL);
  data->prhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL);
  data->prhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL);

  /* call real portaudio OpenDefaultStream function */
  Pa_OpenDefaultStream(&matStream, nInC, nOutC, paFloat32, sr, fpb, 
		       0, paMatCallback, data);

  if(matStream == NULL) {
    mexWarnMsgTxt("matStream is null after calling PA");
    paMatClose();
  }
}
