the old-new win32 port
[libpicofe.git] / win32 / dsnd.cpp
diff --git a/win32/dsnd.cpp b/win32/dsnd.cpp
new file mode 100644 (file)
index 0000000..4e1930e
--- /dev/null
@@ -0,0 +1,165 @@
+//#pragma warning (disable:4201)\r
+#include <stdlib.h>\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#include <mmsystem.h>\r
+#include <dsound.h>\r
+\r
+#include "dsnd.h"\r
+#include "../common/lprintf.h"\r
+\r
+#define NSEGS 4\r
+#define RELEASE(x) if (x) x->Release();  x=NULL;\r
+\r
+static LPDIRECTSOUND DSound;\r
+static LPDIRECTSOUNDBUFFER LoopBuffer;\r
+static LPDIRECTSOUNDNOTIFY DSoundNotify;\r
+static HANDLE seg_played_event;\r
+static int LoopLen, LoopWrite, LoopSeg; // bytes\r
+\r
+static int LoopBlank(void)\r
+{\r
+  void *mema=NULL,*memb=NULL;\r
+  DWORD sizea=0,sizeb=0;\r
+\r
+  LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);\r
+  \r
+  if (mema) memset(mema,0,sizea);\r
+\r
+  LoopBuffer->Unlock(mema,sizea, memb,sizeb);\r
+\r
+  return 0;\r
+}\r
+\r
+int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)\r
+{\r
+  DSBUFFERDESC dsbd;\r
+  WAVEFORMATEX wfx;\r
+  DSBPOSITIONNOTIFY notifies[NSEGS];\r
+  int i;\r
+\r
+  memset(&dsbd,0,sizeof(dsbd));\r
+  memset(&wfx,0,sizeof(wfx));\r
+\r
+  // Make wave format:\r
+  wfx.wFormatTag=WAVE_FORMAT_PCM;\r
+  wfx.nChannels=stereo ? 2 : 1;\r
+  wfx.nSamplesPerSec=rate;\r
+  wfx.wBitsPerSample=16;\r
+\r
+  wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);\r
+  wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;\r
+\r
+  // Create the DirectSound interface:\r
+  DirectSoundCreate(NULL,&DSound,NULL);\r
+  if (DSound==NULL) return 1;\r
+\r
+  LoopSeg = seg_samples * 2;\r
+  if (stereo)\r
+    LoopSeg *= 2;\r
+\r
+  LoopLen = LoopSeg * NSEGS;\r
+\r
+  DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);\r
+  dsbd.dwFlags=DSBCAPS_GLOBALFOCUS;  // Play in background\r
+  dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;\r
+\r
+  // Create the looping buffer:\r
+  dsbd.dwSize=sizeof(dsbd);\r
+  dsbd.dwBufferBytes=LoopLen;\r
+  dsbd.lpwfxFormat=&wfx;\r
+\r
+  DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);\r
+  if (LoopBuffer==NULL) return 1;\r
+\r
+  LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);\r
+  if (DSoundNotify == NULL) {\r
+    lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");\r
+    goto out;\r
+  }\r
+\r
+  seg_played_event = CreateEvent(NULL, 0, 0, NULL);\r
+  if (seg_played_event == NULL)\r
+    goto out;\r
+\r
+  for (i = 0; i < NSEGS; i++) {\r
+    notifies[i].dwOffset = i * LoopSeg;\r
+    notifies[i].hEventNotify = seg_played_event;\r
+  }\r
+  i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);\r
+  if (i != DS_OK) {\r
+    lprintf("SetNotificationPositions failed\n");\r
+    goto out;\r
+  }\r
+\r
+out:\r
+  LoopBlank();\r
+  LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);\r
+  return 0;\r
+}\r
+\r
+void DSoundExit(void)\r
+{\r
+  if (LoopBuffer)\r
+    LoopBuffer->Stop();\r
+  RELEASE(DSoundNotify);\r
+  RELEASE(LoopBuffer)\r
+  RELEASE(DSound)\r
+  CloseHandle(seg_played_event);\r
+  seg_played_event = NULL;\r
+}\r
+\r
+static int WriteSeg(const void *buff)\r
+{\r
+  void *mema=NULL,*memb=NULL;\r
+  DWORD sizea=0,sizeb=0;\r
+  int ret;\r
+\r
+  // Lock the segment at 'LoopWrite' and copy the next segment in\r
+  ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);\r
+  if (ret != DS_OK)\r
+    lprintf("LoopBuffer->Lock() failed: %i\n", ret);\r
+\r
+  if (mema) memcpy(mema,buff,sizea);\r
+//  if (memb) memcpy(memb,DSoundNext+sizea,sizeb);\r
+  if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);\r
+\r
+  ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);\r
+  if (ret != DS_OK)\r
+    lprintf("LoopBuffer->Unlock() failed: %i\n", ret);\r
+\r
+  return 0;\r
+}\r
+\r
+int DSoundUpdate(const void *buff, int blocking)\r
+{\r
+  DWORD play = 0;\r
+  int pos;\r
+\r
+  LoopBuffer->GetCurrentPosition(&play, NULL);\r
+  pos = play;\r
+\r
+  // 'LoopWrite' is the next seg in the loop that we want to write\r
+  // First check that the sound 'play' pointer has moved out of it:\r
+  if (blocking) {\r
+    while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {\r
+      WaitForSingleObject(seg_played_event, 5000);\r
+      LoopBuffer->GetCurrentPosition(&play, NULL);\r
+      pos = play;\r
+    }\r
+  }\r
+  else {\r
+    if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)\r
+      return 1;\r
+  }\r
+\r
+  WriteSeg(buff);\r
+\r
+  // Advance LoopWrite to next seg:\r
+  LoopWrite += LoopSeg;\r
+  if (LoopWrite + LoopSeg > LoopLen)\r
+    LoopWrite = 0;\r
+\r
+  return 0;\r
+}\r
+\r