1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #ifndef NST_DIRECTX_DIRECTSOUND_H
26 #define NST_DIRECTX_DIRECTSOUND_H
27 
28 #pragma once
29 
30 #include <vector>
31 #include "NstObjectPod.hpp"
32 #include "NstDirectX.hpp"
33 
34 #if NST_MSVC >= 1200
35 #pragma warning( push )
36 #pragma warning( disable : 4201 )
37 #endif
38 
39 #include <MMSystem.h>
40 
41 #if NST_MSVC >= 1200
42 #pragma warning( pop )
43 #endif
44 
45 #define DIRECTSOUND_VERSION 0x0800
46 #include <dsound.h>
47 
48 namespace Nestopia
49 {
50 	namespace DirectX
51 	{
52 		class DirectSound
53 		{
54 		public:
55 
56 			explicit DirectSound(HWND);
57 			~DirectSound();
58 
59 			enum Channels
60 			{
61 				MONO = 1,
62 				STEREO
63 			};
64 
65 			enum Pool
66 			{
67 				POOL_HARDWARE,
68 				POOL_SYSTEM
69 			};
70 
71 			struct Adapter : BaseAdapter
72 			{
73 				Adapter();
74 
75 				bool buggy;
76 			};
77 
78 			typedef std::vector<Adapter> Adapters;
79 
80 			cstring Update(uint,uint,uint,Channels,uint,Pool,bool);
81 			void Destroy();
82 			void StopStream();
83 
84 		private:
85 
86 			class SoundAdapters
87 			{
88 				static BOOL CALLBACK Enumerator(LPGUID,LPCTSTR,LPCTSTR,LPVOID);
89 
90 			public:
91 
92 				SoundAdapters();
93 
94 				Adapters list;
95 			};
96 
97 			struct Device : ComInterface<IDirectSound8>
98 			{
99 				explicit Device(HWND);
100 
101 				HWND const hWnd;
102 				ushort id;
103 				bool priority;
104 				bool buggy;
105 			};
106 
107 			class Buffer
108 			{
109 			public:
110 
111 				Buffer();
112 				~Buffer();
113 
114 				cstring Update(IDirectSound8&,bool,uint,uint,Channels,uint,Pool,bool);
115 				void StartStream();
116 				void StopStream(IDirectSound8*,bool);
117 				void Release();
118 
119 			private:
120 
121 				cstring Create(IDirectSound8&,bool);
122 
123 				enum
124 				{
125 					DC_OFFSET_8 = 0x80,
126 					DC_OFFSET_16 = 0x0000
127 				};
128 
129 				struct Com : ComInterface<IDirectSoundBuffer8>
130 				{
131 					Com();
132 
133 					uint writePos;
134 				};
135 
136 				struct Settings
137 				{
138 					Settings();
139 
140 					uint size;
141 					Pool pool;
142 					bool globalFocus;
143 				};
144 
145 				Com com;
146 				Object::Pod<WAVEFORMATEX> waveFormat;
147 				Settings settings;
148 
149 			public:
150 
GetWaveFormat() const151 				const WAVEFORMATEX& GetWaveFormat() const
152 				{
153 					return waveFormat;
154 				}
155 
GlobalFocus() const156 				bool GlobalFocus() const
157 				{
158 					return settings.globalFocus;
159 				}
160 
LockStream(void ** data,uint * size)161 				NST_FORCE_INLINE bool LockStream(void** data,uint* size)
162 				{
163 					DWORD pos;
164 
165 					if (SUCCEEDED(com->GetCurrentPosition( &pos, NULL )))
166 					{
167 						pos = (pos > com.writePos ? pos - com.writePos : pos + settings.size - com.writePos);
168 
169 						DWORD bytes[2];
170 
171 						if (SUCCEEDED(com->Lock( com.writePos, pos, data+0, bytes+0, data+1, bytes+1, 0 )))
172 						{
173 							com.writePos = (com.writePos + pos) % settings.size;
174 
175 							size[0] = bytes[0] / waveFormat.nBlockAlign;
176 							size[1] = bytes[1] / waveFormat.nBlockAlign;
177 
178 							return true;
179 						}
180 					}
181 
182 					com->Stop();
183 
184 					NST_DEBUG_MSG("DirectSound::Buffer::Lock() failed!");
185 
186 					return false;
187 				}
188 
UnlockStream(void ** data,uint * size) const189 				NST_FORCE_INLINE void UnlockStream(void** data,uint* size) const
190 				{
191 					NST_ASSERT( data && com );
192 					com->Unlock( data[0], size[0]*waveFormat.nBlockAlign, data[1], size[1]*waveFormat.nBlockAlign );
193 				}
194 
Streaming() const195 				bool Streaming() const
196 				{
197 					DWORD status;
198 
199 					return
200 					(
201 						com && SUCCEEDED(com->GetStatus( &status )) &&
202 						(status & (DSBSTATUS_BUFFERLOST|DSBSTATUS_PLAYING|DSBSTATUS_LOOPING)) == (DSBSTATUS_PLAYING|DSBSTATUS_LOOPING)
203 					);
204 				}
205 			};
206 
207 			Device device;
208 			Buffer buffer;
209 			const SoundAdapters adapters;
210 
211 		public:
212 
Streaming() const213 			bool Streaming() const
214 			{
215 				return buffer.Streaming();
216 			}
217 
StartStream()218 			void StartStream()
219 			{
220 				buffer.StartStream();
221 			}
222 
LockStream(void ** data,uint * size)223 			NST_FORCE_INLINE bool LockStream(void** data,uint* size)
224 			{
225 				return buffer.LockStream( data, size );
226 			}
227 
UnlockStream(void ** data,uint * size) const228 			NST_FORCE_INLINE void UnlockStream(void** data,uint* size) const
229 			{
230 				buffer.UnlockStream( data, size );
231 			}
232 
GetAdapters() const233 			const Adapters& GetAdapters() const
234 			{
235 				return adapters.list;
236 			}
237 
GetWaveFormat() const238 			const WAVEFORMATEX& GetWaveFormat() const
239 			{
240 				return buffer.GetWaveFormat();
241 			}
242 
GlobalFocus() const243 			bool GlobalFocus() const
244 			{
245 				return buffer.GlobalFocus();
246 			}
247 		};
248 	}
249 }
250 
251 #endif
252