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