/* Sound.c Sound Record/PlayBack for windows
   sebastien Metrot 27/01/97 12:50
*/

#include "x/Version.h"
#include "x/scolplugin.h"

#include <mmsystem.h>
#include <winsock.h>

#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "objstr.h"

#include "sound/sound.h"

int OBJTYPSOUND;

/* reflexes type SOUND */
#define RFLSOUND_NB         6

#define RFLSOUND_RECOPEN    0
#define RFLSOUND_RECBUF     1
#define RFLSOUND_RECCLOSE   2

#define RFLSOUND_PLAYOPEN   3
#define RFLSOUND_PLAYBUF    4
#define RFLSOUND_PLAYCLOSE  5

// Global variables & type defs
typedef struct WaveOutBuffer
{
  WORD Rate;
  BYTE nChannels;
  LONG dwDataSize;
  BYTE Resolution;
  HWND hwnd;
  HGLOBAL hWaveHdr;
  LPWAVEHDR lpWaveHdr;
  HANDLE hData;  // handle of waveform data memory 
  HPSTR  lpData;  // pointer to waveform data memory 
} WaveOutBuffer;

typedef struct WaveInBuffer
{
  WORD Rate;
  BYTE nChannels;
  LONG dwDataSize;
  BYTE Resolution;
  HWND hwnd;
  HGLOBAL hWaveHdr;
  LPWAVEHDR lpWaveHdr;
  HANDLE hData;  // handle of waveform data memory 
  HPSTR  lpData;  // pointer to waveform data memory 
} WaveInBuffer;

HWAVEOUT hWaveOut;
HWAVEIN hWaveIn;

#define NBUFFERS (8)
#define MAXBUFFERS (32)
int nPlayBuffers=NBUFFERS;
int nRecBuffers=NBUFFERS;
WaveOutBuffer WaveOutBuf[MAXBUFFERS];
WaveInBuffer WaveInBuf[MAXBUFFERS];
int SendOutBuffers=0;
int SendInBuffers=0;
int OutBufToSet=0;
int InBufToGet=0;
/*int PlaySrv=0;*/
/*int RecSrv=0;*/
int OutBufToFill=0;
int InBufToFill=0;
int PlayPending=-1;

BOOL StopPlayback=FALSE,StopRecord=FALSE;
BOOL PlaybackInitialised=FALSE,RecordInitialised=FALSE;

int sndSetPending (mmachine m)
{
	StopPlayback=TRUE;
	return MMpush(m,2);
}

int sndUnsetPending (mmachine m)
{
	StopPlayback=FALSE;
	return MMpush(m,2);
}

int sndSetPlayBuffersN(mmachine m)
{
  int n;

  n=MMget(m,0)>>1;

  if (n>MAXBUFFERS || n<1 || PlaybackInitialised)
  {
    MMset(m,0,nPlayBuffers<<1);
    return 0;
  }

  nPlayBuffers=n;
  MMset(m,0,n<<1);
  return 0;  
}

int sndSetRecBuffersN(mmachine m)
{
  int n;

  n=MMget(m,0)>>1;

  if (n>MAXBUFFERS || n<1 || RecordInitialised)
  {
    MMset(m,0,nRecBuffers<<1);
    return 0;
  }

  nRecBuffers=n;
  MMset(m,0,n<<1);
  return 0;  
}

int SoundOutFillBuffer(mmachine m,int i)
{
//  int n;
//  char buf[256];
  char * S;
  int slen;
  int s,k;

  OutBufToFill=i;
  if (WaveOutBuf[i].lpData==NULL) return 0;

  k=OBJbeginreflex(m,OBJTYPSOUND,4,RFLSOUND_PLAYBUF);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundPlayBuf %d\n",i);
		if (MMpush(m,i<<1)) return MERRMEM;
		if (k=OBJcallreflex(m,1)) return k;

    s=MMget(m,-2)>>1;
    if (s==NIL) 
    {
//      MMechostr(MSKDEBUG,"Sound Out Buffer NIL");
      return 0;
    }
    slen=MMsizestr(m,s);
/*    if (slen==0) 
    {
      MMechostr(MSKDEBUG,"Sound Out Buffer length 0");
      return 0;
    }*/
    S=MMstartstr(m,s);
    
    if (WaveOutBuf[OutBufToFill].lpData==NULL) 
    {
//      MMechostr(MSKDEBUG,"Sound Out Buffer length NULL");
      return 0;
    }

    if (slen>WaveOutBuf[OutBufToFill].dwDataSize) 
    {
      slen=WaveOutBuf[OutBufToFill].dwDataSize;
//      MMechostr(MSKDEBUG,"Sub Buffer len adjusted.\n");
    } 
    else if (WaveOutBuf[i].Resolution==8)
      memset(WaveOutBuf[i].lpData,128,WaveOutBuf[i].dwDataSize);
    else
      memset(WaveOutBuf[i].lpData,0,WaveOutBuf[i].dwDataSize);
    memcpy(WaveOutBuf[OutBufToFill].lpData,S,slen);  
	}
  else if (WaveOutBuf[i].Resolution==8)
    memset(WaveOutBuf[i].lpData,128,WaveOutBuf[i].dwDataSize);
  else
    memset(WaveOutBuf[i].lpData,0,WaveOutBuf[i].dwDataSize);
  return 0;
}

int SetBlock(mmachine m,int InBufToFill)
{
  char * S;
  int slen;
  int s;

  slen=WaveInBuf[InBufToFill].dwDataSize;
  s=MMmalloc(m,((slen+5)>>2)+1,TYPEBUF);
  if (s==NIL) 
  {
    return NIL;
  }
  MMstore(m,s,0,slen);
  S=MMstartstr(m,s);

  memcpy(S,WaveInBuf[InBufToFill].lpData,slen);
  S[slen]=0;
  return s+s+1;
}

int SoundInFillBuffer(mmachine m,int i)
{
  int k;

  InBufToFill=i;
  if (WaveInBuf[i].lpData==NULL) return 0;

  k=OBJbeginreflex(m,OBJTYPSOUND,2,RFLSOUND_RECBUF);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundRecBuf %d\n",i);
    if (MMpush(m,SetBlock(m,i))) return MERRMEM;
    if (MMpush(m,i<<1)) return MERRMEM;
		if (k=OBJcallreflex(m,2)) return k;
	}

  return 0;
}

void WaveInFreeAll()
{
  int i;
  for (i=0;i<nRecBuffers;i++)
  {
    waveInUnprepareHeader(hWaveIn,WaveInBuf[i].lpWaveHdr,sizeof(WAVEHDR));

    if (WaveInBuf[i].lpData != NULL)
        GlobalUnlock(WaveInBuf[i].hData);
    if (WaveInBuf[i].hData) 
      GlobalFree(WaveInBuf[i].hData);

    if (WaveInBuf[i].lpWaveHdr != NULL)
      GlobalUnlock(WaveInBuf[i].hWaveHdr);
    if (WaveInBuf[i].hWaveHdr)
      GlobalFree(WaveInBuf[i].hWaveHdr);
  }
  memset(WaveInBuf,0,nRecBuffers*sizeof(WaveInBuffer));
  RecordInitialised=FALSE;
  SendInBuffers=0;
  InBufToFill=0;
}

void WaveOutFreeAll()
{
  int i;
  for (i=0;i<nPlayBuffers;i++)
  {
    waveOutUnprepareHeader(hWaveOut,WaveOutBuf[i].lpWaveHdr,sizeof(WAVEHDR));

    if (WaveOutBuf[i].lpData != NULL)
        GlobalUnlock(WaveOutBuf[i].hData);
    if (WaveOutBuf[i].hData) 
      GlobalFree(WaveOutBuf[i].hData);

    if (WaveOutBuf[i].lpWaveHdr != NULL)
      GlobalUnlock(WaveOutBuf[i].hWaveHdr);
    if (WaveOutBuf[i].hWaveHdr)
      GlobalFree(WaveOutBuf[i].hWaveHdr);
  }
  memset(WaveOutBuf,0,nPlayBuffers*sizeof(WaveOutBuffer));
  PlaybackInitialised=FALSE;
  SendOutBuffers=0;
  OutBufToFill=0;
}

int SoundInitRecord(int rate,int nChannels,int ChannelSize,int BitsPerSample,HWND hwnd)
{
  UINT wResult;
  PCMWAVEFORMAT pcmWaveFormat;
  int r,i;
  if (RecordInitialised) return 0;
  memset(WaveInBuf,0,nRecBuffers*sizeof(WaveInBuffer));
  // Open a waveform device for output using window callback.

  if (BitsPerSample<8) BitsPerSample=8;
  if (BitsPerSample>8) BitsPerSample=16;
  pcmWaveFormat.wf.wFormatTag=WAVE_FORMAT_PCM;
  pcmWaveFormat.wf.nChannels=nChannels;
  pcmWaveFormat.wf.nSamplesPerSec=rate;
  pcmWaveFormat.wf.nAvgBytesPerSec=rate*nChannels*(BitsPerSample/8);
  pcmWaveFormat.wf.nBlockAlign=(nChannels*BitsPerSample)/8;
  pcmWaveFormat.wBitsPerSample=BitsPerSample;

  if (r=waveInOpen((LPHWAVEIN)&hWaveIn, WAVE_MAPPER,
                  (LPWAVEFORMATEX)&pcmWaveFormat,
                  (LONG)hwnd, 0L, CALLBACK_WINDOW))
  {
//      MMechostr(MSKDEBUG,"Record: Unable to Open Device\n");
      switch (r)
      {
        case MMSYSERR_ALLOCATED : MMechostr(MSKDEBUG,"Device allready allocated\n"); break;
        case MMSYSERR_BADDEVICEID : MMechostr(MSKDEBUG,"Bad device ID\n"); break;
        case MMSYSERR_NODRIVER : MMechostr(MSKDEBUG,"No driver\n"); break;
        case WAVERR_BADFORMAT : MMechostr(MSKDEBUG,"Bad Format\n"); break;
        case MMSYSERR_NOMEM : MMechostr(MSKDEBUG,"No memory\n"); break;
      }
      return 0;
  }

  for (i=0;i<nRecBuffers;i++)
  {
    WaveInBuf[i].nChannels=nChannels;
    WaveInBuf[i].Rate=rate;
    WaveInBuf[i].Resolution=BitsPerSample;
    WaveInBuf[i].dwDataSize=nChannels*(BitsPerSample/8)*ChannelSize;
    WaveInBuf[i].hwnd=hwnd;
    // Allocate and lock memory for the waveform data.
    WaveInBuf[i].hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, WaveInBuf[i].dwDataSize );
    if (!WaveInBuf[i].hData)
    {
//        MMechostr(MSKDEBUG,"Record: Unable to Allocate memory\n");
        return 0;
    }
    if ((WaveInBuf[i].lpData = GlobalLock(WaveInBuf[i].hData)) == NULL) {
//        MMechostr(MSKDEBUG,"Record: Unable to Lock Memory\n");
        WaveInFreeAll();
        return 0;
    }

    // Allocate and lock memory for the header.
    WaveInBuf[i].hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
        (DWORD) sizeof(WAVEHDR));
    if (WaveInBuf[i].hWaveHdr == NULL)
    {
        WaveInFreeAll();
//        MMechostr(MSKDEBUG,"Record: Unable to allocate wave header\n");
        return 0;
    }

    WaveInBuf[i].lpWaveHdr = (LPWAVEHDR) GlobalLock(WaveInBuf[i].hWaveHdr);
    if (WaveInBuf[i].lpWaveHdr == NULL)
    {
        WaveInFreeAll();
//        MMechostr(MSKDEBUG,"Record: Unable to Lock wave header memory\n");
        return 0;
    }

    // After allocation, set up and prepare header.

    WaveInBuf[i].lpWaveHdr->lpData = WaveInBuf[i].lpData;
    WaveInBuf[i].lpWaveHdr->dwBufferLength = WaveInBuf[i].dwDataSize;
    WaveInBuf[i].lpWaveHdr->dwUser = i;
    WaveInBuf[i].lpWaveHdr->dwFlags = 0L;
    WaveInBuf[i].lpWaveHdr->dwLoops = 0L;
    wResult=waveInPrepareHeader(hWaveIn,WaveInBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
      char buf[MAXERRORLENGTH];
      WaveOutFreeAll();
//      MMechostr(MSKDEBUG,"PrepareRecBuf: Unable to write block to the device\n");
      waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//      MMechostr(MSKDEBUG,buf);
//      MMechostr(MSKDEBUG,"\n");
      return 0;
    }

  }
    
  for (i=0;i<nRecBuffers;i++)
  {
    // Now the data block can be sent to the input device. The
    // waveOutWrite function returns immediately and waveform
    // data is sent to the output device in the background.
    wResult = waveInAddBuffer(hWaveIn,WaveInBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
        WaveInFreeAll();
//        MMechostr(MSKDEBUG,"Record: Unable to write block to the device\n");
        return 0;
    }
    SendInBuffers++;
  }
  waveInStart(hWaveIn);
  StopRecord=FALSE;
  RecordInitialised=TRUE;

  return 1;
}

int SoundInitPlayBack(int rate,int nChannels,int ChannelSize,int BitsPerSample,HWND hwnd,mmachine m)
{
  UINT wResult;
  PCMWAVEFORMAT pcmWaveFormat;
  int i;

  if (PlaybackInitialised) return 0;

//  memset(WaveOutBuf,0,nBuffers*sizeof(WaveOutBuffer));
  // Open a waveform device for output using window callback.

  if (BitsPerSample<8) BitsPerSample=8;
  if (BitsPerSample>8) BitsPerSample=16;
  pcmWaveFormat.wf.wFormatTag=WAVE_FORMAT_PCM;
  pcmWaveFormat.wf.nChannels=nChannels;
  pcmWaveFormat.wf.nSamplesPerSec=rate;
  pcmWaveFormat.wf.nAvgBytesPerSec=rate*nChannels*(BitsPerSample/8);
  pcmWaveFormat.wf.nBlockAlign=(nChannels*BitsPerSample)/8;
  pcmWaveFormat.wBitsPerSample=BitsPerSample;

  wResult=waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
                  (LPWAVEFORMATEX)&pcmWaveFormat,
                  (LONG)hwnd, 0L, CALLBACK_WINDOW);
  if (wResult != 0)
  {
    char buf[MAXERRORLENGTH];
//    MMechostr(MSKDEBUG,"waveOutOpen:");
    waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//    MMechostr(MSKDEBUG,buf);
//    MMechostr(MSKDEBUG,"\n");
	return 0;
  }

  for (i=0;i<nPlayBuffers;i++)
  {
    WaveOutBuf[i].nChannels=nChannels;
    WaveOutBuf[i].Rate=rate;
    WaveOutBuf[i].Resolution=BitsPerSample;
    WaveOutBuf[i].hwnd=hwnd;
    WaveOutBuf[i].dwDataSize=nChannels*(BitsPerSample/8)*ChannelSize;
    
    // Allocate and lock memory for the waveform data.
    WaveOutBuf[i].hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, WaveOutBuf[i].dwDataSize );
    if (!WaveOutBuf[i].hData)
    {
//        MMechostr(MSKDEBUG,"PlayBack: Unable to Allocate memory\n");
        return 0;
    }
    if ((WaveOutBuf[i].lpData = GlobalLock(WaveOutBuf[i].hData)) == NULL) {
//        MMechostr(MSKDEBUG,"PlayBack: Unable to Lock Memory\n");
        WaveOutFreeAll();
        return 0;
    }

    // Allocate and lock memory for the header.
    WaveOutBuf[i].hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
        (DWORD) sizeof(WAVEHDR));
    if (WaveOutBuf[i].hWaveHdr == NULL)
    {
        WaveOutFreeAll();
//        MMechostr(MSKDEBUG,"PlayBack: Unable to allocate wave header\n");
        return 0;
    }

    WaveOutBuf[i].lpWaveHdr = (LPWAVEHDR) GlobalLock(WaveOutBuf[i].hWaveHdr);
    if (WaveOutBuf[i].lpWaveHdr == NULL)
    {
        WaveOutFreeAll();
//        MMechostr(MSKDEBUG,"PlayBack: Unable to Lock wave header memory\n");
        return 0;
    }

    // After allocation, set up and prepare header.

    WaveOutBuf[i].lpWaveHdr->lpData = WaveOutBuf[i].lpData;
    WaveOutBuf[i].lpWaveHdr->dwBufferLength = WaveOutBuf[i].dwDataSize;
    WaveOutBuf[i].lpWaveHdr->dwUser = i;
    WaveOutBuf[i].lpWaveHdr->dwFlags = 0L;
    WaveOutBuf[i].lpWaveHdr->dwLoops = 1L;
    wResult = waveOutPrepareHeader(hWaveOut,WaveOutBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
      char buf[MAXERRORLENGTH];
//      MMechostr(MSKDEBUG,"PreparePlayBuf: Unable to write block to the device\n");
      waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//      MMechostr(MSKDEBUG,buf);
//      MMechostr(MSKDEBUG,"\n");
      wResult=waveOutClose(hWaveOut);
      if (wResult != 0)
      {
        char buf[MAXERRORLENGTH];
//        MMechostr(MSKDEBUG,"waveOutClose:");
        waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//        MMechostr(MSKDEBUG,buf);
//        MMechostr(MSKDEBUG,"\n");
      }
      WaveOutFreeAll();
      return 0;
    }
//	MMechostr(MSKDEBUG,"PrepareOK\n");

    SoundOutFillBuffer(m,i);
  }

  for (i=0;i<nPlayBuffers;i++)
  {
    // Now the data block can be sent to the output device. The
    // waveOutWrite function returns immediately and waveform
    // data is sent to the output device in the background.
    wResult = waveOutWrite(hWaveOut,WaveOutBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
      char buf[MAXERRORLENGTH];
      wResult=waveOutReset(hWaveOut);
      if (wResult != 0)
      {
        char buf[MAXERRORLENGTH];
//        MMechostr(MSKDEBUG,"waveOutClose:");
        waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//        MMechostr(MSKDEBUG,buf);
//        MMechostr(MSKDEBUG,"\n");
      }
      wResult=waveOutClose(hWaveOut);
      if (wResult != 0)
      {
        char buf[MAXERRORLENGTH];
//        MMechostr(MSKDEBUG,"waveOutClose:");
        waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//        MMechostr(MSKDEBUG,buf);
//        MMechostr(MSKDEBUG,"\n");
      }
      WaveOutFreeAll();
//      MMechostr(MSKDEBUG,"InitPlayBack: Unable to write block to the device\n");
      waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//      MMechostr(MSKDEBUG,buf);
//      MMechostr(MSKDEBUG,"\n");
      return 0;
    }
    SendOutBuffers++;
  }
  StopPlayback=FALSE;
  PlaybackInitialised=TRUE;
  return 1;
}

void SoundStopPlayback()
{
  waveOutReset(hWaveOut);
  StopPlayback=TRUE;
}

void SoundStopRecord()
{
  waveInReset(hWaveIn);
  waveInClose(hWaveIn);
  StopRecord=TRUE;
}

int SoundNextPlayBack(mmachine m,int i)
{
  WORD wResult;
  char buf[MAXERRORLENGTH];
  SendOutBuffers--;
  if (!StopPlayback)
  {
    SoundOutFillBuffer(m,i);
    wResult = waveOutWrite(hWaveOut,WaveOutBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
      WaveOutFreeAll();
      waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//      MMechostr(MSKDEBUG,buf);
//      MMechostr(MSKDEBUG,"\nPlayBackCB: Unable to write block to the device\n");
      return 0;
    }
    SendOutBuffers++;
  }
  else
  {
    if (!SendOutBuffers)
    {
      WaveOutFreeAll();
      StopPlayback=FALSE;
      waveOutClose(hWaveOut);
	}
  }
  return 1;
}

int SoundNextRecord(mmachine m,int i)
{
  WORD wResult;
  char buf[MAXERRORLENGTH];

  SendInBuffers--;
  if (!StopRecord)
  {
    SoundInFillBuffer(m,i);
    wResult = waveInAddBuffer(hWaveIn,WaveInBuf[i].lpWaveHdr,sizeof(WAVEHDR));
    if (wResult != 0)
    {
      WaveInFreeAll();
      waveOutGetErrorText(wResult,buf,MAXERRORLENGTH);
//      MMechostr(MSKDEBUG,buf);
//      MMechostr(MSKDEBUG,"\nRecordCB: Unable to write block to the device\n");
      return 0;
    }
    SendInBuffers++;
  }
  else
  {
    if (!SendInBuffers)
    {
      WaveInFreeAll();
      StopRecord=FALSE;
    }
  }
  return 1;
}

/* MAGMA LIBRARY FUNCTIONS : */
/* ------------------------- */
// fun [Srv I I I I] I
int sndPlayStart(mmachine m)
{
/*  int Srv;*/
  int rate,size,resolution,nchannels;

  nchannels=MMpull(m)>>1;
  resolution=MMpull(m)>>1;
  size=MMpull(m)>>1;
  rate=MMpull(m)>>1;

  if (!SoundInitPlayBack(rate,nchannels,size,resolution,(HWND)SCgetExtra("hscol"),m))
  {
    MMset(m,0,NIL);
    return 0; // Failled to start Playback
  }

  MMpush(m,4);
  return OBJcreate(m,OBJTYPSOUND,4,-1,0);
}

// fun [] I
int sndPlayStop(mmachine m)
{
  SoundStopPlayback();
  MMpush(m,2);
  return 0;
}

// fun [Srv I I I I] I
int sndRecStart(mmachine m)
{
  int rate,size,resolution,nchannels;
//  char buf[50];

  nchannels=MMpull(m)>>1;
  resolution=MMpull(m)>>1;
  size=MMpull(m)>>1;
  rate=MMpull(m)>>1;

  if (!SoundInitRecord(rate,nchannels,size,resolution,(HWND)SCgetExtra("hscol")))
  {
    MMset(m,0,NIL);
    return 0; // Failled to start Playback
  }

//  sprintf(buf,"Rec Sound Server : %d  Socket : %d\n",RecSrv,Srv);
//  MMechostr(50,buf);
  MMpush(m,2);
  return OBJcreate(m,OBJTYPSOUND,2,-1,0);
}

int sndrflRecOpen(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_RECOPEN);
}

int sndrflRecClose(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_RECCLOSE);
}

int sndrflRecBuf(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_RECBUF);
}

int sndrflPlayOpen(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_PLAYOPEN);
}

int sndrflPlayClose(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_PLAYCLOSE);
}

int sndrflPlayBuf(mmachine m)
{
	return OBJaddreflex(m,OBJTYPSOUND,RFLSOUND_PLAYBUF);
}

// fun [] I
int sndRecStop(mmachine m)
{
  SoundStopRecord();
  MMpush(m,2);
  return 0;
}

int SoundPlayCloseEvent(mmachine m,int wParam,LONG lParam)
{
  int k;

  k=OBJbeginreflex(m,OBJTYPSOUND,4,RFLSOUND_PLAYCLOSE);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundPlayClose %d\n",wParam);
		if (k=OBJcallreflex(m,0)) return k;
	}

  OBJdelTH(m,OBJTYPSOUND,4);

  return 0;
}

int SoundRecCloseEvent(mmachine m,int wParam,LONG lParam)
{
  int k;
  k=OBJbeginreflex(m,OBJTYPSOUND,2,RFLSOUND_RECCLOSE);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundRecClose %d\n",wParam);
		if (k=OBJcallreflex(m,0)) return k;
	}

  OBJdelTH(m,OBJTYPSOUND,2);

  return 0;
}

int SoundPlayOpenEvent(mmachine m,int wParam,LONG lParam)
{
  int k;
  k=OBJbeginreflex(m,OBJTYPSOUND,4,RFLSOUND_PLAYOPEN);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundPlayOpen %d\n",wParam);
		if (k=OBJcallreflex(m,0)) return k;
	}
  return 0;
}

int SoundRecOpenEvent(mmachine m,int wParam,LONG lParam)
{
  int k;
  k=OBJbeginreflex(m,OBJTYPSOUND,2,RFLSOUND_RECOPEN);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"SoundRecOpen %d\n",wParam);
		if (k=OBJcallreflex(m,0)) return k;
	}
  return 0;
}

int SCOLSoundRecEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundNextRecord(m,((LPWAVEHDR)lParam)->dwUser);
}

int SCOLSoundPlayEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundNextPlayBack(m,((LPWAVEHDR)lParam)->dwUser);
}

int SCOLSoundRecOpenEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundRecOpenEvent(m,wParam,lParam);
}

int SCOLSoundPlayOpenEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundPlayOpenEvent(m,wParam,lParam);
}

int SCOLSoundRecCloseEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundRecCloseEvent(m,wParam,lParam);
}

int SCOLSoundPlayCloseEvent(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
  return SoundPlayCloseEvent(m,wParam,lParam);
}

int D2SOUND(mmachine m,int handsys,int objm)
{
    if (handsys==2)   SoundStopRecord();
    else if (handsys==4)   SoundStopPlayback();
	return 0;
}

int IniSound(mmachine m)
{
	OBJTYPSOUND=OBJregister(RFLSOUND_NB,0,D2SOUND,"OBJTYPSOUND");
	OBJdefEvent(MM_WIM_OPEN,SCOLSoundRecOpenEvent);
    OBJdefEvent(MM_WIM_DATA,SCOLSoundRecEvent);
    OBJdefEvent(MM_WIM_CLOSE,SCOLSoundRecCloseEvent);
    OBJdefEvent(MM_WOM_OPEN,SCOLSoundPlayOpenEvent);
    OBJdefEvent(MM_WOM_DONE,SCOLSoundPlayEvent);
    OBJdefEvent(MM_WOM_CLOSE,SCOLSoundPlayCloseEvent);
	return 0;
}
