bugfix
[picodrive.git] / platform / win32 / dsnd.cpp
1 //#pragma warning (disable:4201)\r
2 #include <stdlib.h>\r
3 #define WIN32_LEAN_AND_MEAN\r
4 #include <windows.h>\r
5 #include <mmsystem.h>\r
6 #include <dsound.h>\r
7 \r
8 #include "dsnd.h"\r
9 #include "../common/lprintf.h"\r
10 \r
11 #define NSEGS 4\r
12 #define RELEASE(x) if (x) x->Release();  x=NULL;\r
13 \r
14 static LPDIRECTSOUND DSound;\r
15 static LPDIRECTSOUNDBUFFER LoopBuffer;\r
16 static LPDIRECTSOUNDNOTIFY DSoundNotify;\r
17 static HANDLE seg_played_event;\r
18 static int LoopLen, LoopWrite, LoopSeg; // bytes\r
19 \r
20 static int LoopBlank(void)\r
21 {\r
22   void *mema=NULL,*memb=NULL;\r
23   DWORD sizea=0,sizeb=0;\r
24 \r
25   LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);\r
26   \r
27   if (mema) memset(mema,0,sizea);\r
28 \r
29   LoopBuffer->Unlock(mema,sizea, memb,sizeb);\r
30 \r
31   return 0;\r
32 }\r
33 \r
34 int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)\r
35 {\r
36   DSBUFFERDESC dsbd;\r
37   WAVEFORMATEX wfx;\r
38   DSBPOSITIONNOTIFY notifies[NSEGS];\r
39   int i;\r
40 \r
41   memset(&dsbd,0,sizeof(dsbd));\r
42   memset(&wfx,0,sizeof(wfx));\r
43 \r
44   // Make wave format:\r
45   wfx.wFormatTag=WAVE_FORMAT_PCM;\r
46   wfx.nChannels=stereo ? 2 : 1;\r
47   wfx.nSamplesPerSec=rate;\r
48   wfx.wBitsPerSample=16;\r
49 \r
50   wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);\r
51   wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;\r
52 \r
53   // Create the DirectSound interface:\r
54   DirectSoundCreate(NULL,&DSound,NULL);\r
55   if (DSound==NULL) return 1;\r
56 \r
57   LoopSeg = seg_samples * 2;\r
58   if (stereo)\r
59     LoopSeg *= 2;\r
60 \r
61   LoopLen = LoopSeg * NSEGS;\r
62 \r
63   DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);\r
64   dsbd.dwFlags=DSBCAPS_GLOBALFOCUS;  // Play in background\r
65   dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;\r
66 \r
67   // Create the looping buffer:\r
68   dsbd.dwSize=sizeof(dsbd);\r
69   dsbd.dwBufferBytes=LoopLen;\r
70   dsbd.lpwfxFormat=&wfx;\r
71 \r
72   DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);\r
73   if (LoopBuffer==NULL) return 1;\r
74 \r
75   LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);\r
76   if (DSoundNotify == NULL) {\r
77     lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");\r
78     goto out;\r
79   }\r
80 \r
81   seg_played_event = CreateEvent(NULL, 0, 0, NULL);\r
82   if (seg_played_event == NULL)\r
83     goto out;\r
84 \r
85   for (i = 0; i < NSEGS; i++) {\r
86     notifies[i].dwOffset = i * LoopSeg;\r
87     notifies[i].hEventNotify = seg_played_event;\r
88   }\r
89   i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);\r
90   if (i != DS_OK) {\r
91     lprintf("SetNotificationPositions failed\n");\r
92     goto out;\r
93   }\r
94 \r
95 out:\r
96   LoopBlank();\r
97   LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);\r
98   return 0;\r
99 }\r
100 \r
101 void DSoundExit(void)\r
102 {\r
103   if (LoopBuffer)\r
104     LoopBuffer->Stop();\r
105   RELEASE(DSoundNotify);\r
106   RELEASE(LoopBuffer)\r
107   RELEASE(DSound)\r
108   CloseHandle(seg_played_event);\r
109   seg_played_event = NULL;\r
110 }\r
111 \r
112 static int WriteSeg(const void *buff)\r
113 {\r
114   void *mema=NULL,*memb=NULL;\r
115   DWORD sizea=0,sizeb=0;\r
116   int ret;\r
117 \r
118   // Lock the segment at 'LoopWrite' and copy the next segment in\r
119   ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);\r
120   if (ret != DS_OK)\r
121     lprintf("LoopBuffer->Lock() failed: %i\n", ret);\r
122 \r
123   if (mema) memcpy(mema,buff,sizea);\r
124 //  if (memb) memcpy(memb,DSoundNext+sizea,sizeb);\r
125   if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);\r
126 \r
127   ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);\r
128   if (ret != DS_OK)\r
129     lprintf("LoopBuffer->Unlock() failed: %i\n", ret);\r
130 \r
131   return 0;\r
132 }\r
133 \r
134 int DSoundUpdate(const void *buff, int blocking)\r
135 {\r
136   DWORD play = 0;\r
137   int pos;\r
138 \r
139   LoopBuffer->GetCurrentPosition(&play, NULL);\r
140   pos = play;\r
141 \r
142   // 'LoopWrite' is the next seg in the loop that we want to write\r
143   // First check that the sound 'play' pointer has moved out of it:\r
144   if (blocking) {\r
145     while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {\r
146       WaitForSingleObject(seg_played_event, 5000);\r
147       LoopBuffer->GetCurrentPosition(&play, NULL);\r
148       pos = play;\r
149     }\r
150   }\r
151   else {\r
152     if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)\r
153       return 1;\r
154   }\r
155 \r
156   WriteSeg(buff);\r
157 \r
158   // Advance LoopWrite to next seg:\r
159   LoopWrite += LoopSeg;\r
160   if (LoopWrite + LoopSeg > LoopLen)\r
161     LoopWrite = 0;\r
162 \r
163   return 0;\r
164 }\r
165 \r