]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/dscap.cpp
Initial revision
[taylor/freespace2.git] / src / sound / dscap.cpp
1 /*
2  * $Logfile: /Freespace2/code/Sound/dscap.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C module for DirectSoundCapture code
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:10  root
11  * Initial revision
12  *
13  * 
14  * 2     10/07/98 10:54a Dave
15  * Initial checkin.
16  * 
17  * 1     10/07/98 10:51a Dave
18  * 
19  * 11    5/05/98 4:49p Lawrance
20  * Put in code to authenticate A3D, improve A3D support
21  * 
22  * 10    4/24/98 2:17a Lawrance
23  * Clear out record buffer when recording begins
24  * 
25  * 9     3/24/98 9:37a Lawrance
26  * Only read up to a safe offset in the capture buffer.
27  * 
28  * 8     3/22/98 7:13p Lawrance
29  * Get streaming of recording voice working
30  * 
31  * 7     2/26/98 2:54p Lawrance
32  * Don't recreate capture buffer each time recording starts... just use
33  * one.
34  * 
35  * 6     2/15/98 11:10p Lawrance
36  * more work on real-time voice system
37  * 
38  * 5     2/15/98 4:43p Lawrance
39  * work on real-time voice
40  * 
41  * 4     2/09/98 8:07p Lawrance
42  * get buffer create working
43  * 
44  * 3     2/04/98 6:08p Lawrance
45  * Read function pointers from dsound.dll, further work on
46  * DirectSoundCapture.
47  * 
48  * 2     2/03/98 11:53p Lawrance
49  * Adding support for DirectSoundCapture
50  * 
51  * 1     2/03/98 4:48p Lawrance
52  *
53  * $NoKeywords: $
54  */
55
56 #include "pstypes.h"
57 #include "ds.h"
58 #include "dscap.h"
59
60 int dscap_inited=0;                                             // flag to indicate that DirectSoundCapture inited ok
61 int dscap_recording;                                            // flag to indicate that sound is being recorded
62
63 static LPDIRECTSOUNDCAPTURE                     pDSC;           // global capture interface
64 static LPDIRECTSOUNDCAPTUREBUFFER       pDSCB;  // global capture buffer
65
66 static WAVEFORMATEX     Dscap_wfx;
67
68 static unsigned long Dscap_last_capture_offset; 
69
70 // init the DirectSoundCapture system
71 // exit:        0       ->              success
72 //                      !0      ->              failure
73 int dscap_init()
74 {
75         HRESULT dsrval;
76
77         if ( dscap_inited ) {
78                 return 0;
79         }
80
81         if ( !pfn_DirectSoundCaptureCreate ) {
82                 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCaptureCreate function pointer\n" ));
83                 return -1;
84         }
85
86         dsrval = pfn_DirectSoundCaptureCreate(NULL, &pDSC, NULL);
87
88         if ( dsrval != DS_OK ) {
89                 nprintf(( "Sound", "SOUND ==> Error '%s' initializing DirectSoundCapture.\n", get_DSERR_text(dsrval)  ));
90                 return -1;
91         }               
92
93         pDSCB=NULL;
94
95         dscap_recording=0;
96         dscap_inited=1;
97
98         return 0;
99 }
100
101 void dscap_release_buffer()
102 {
103         if ( !pDSCB ) {
104                 return;
105         }
106
107         pDSCB->Release();
108         pDSCB = NULL;
109 }
110
111 // create a capture buffer with the specified format
112 // exit:        0       ->              buffer created successfully
113 //                      !0      ->              error creating the buffer
114 int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
115 {
116         HRESULT                 dsrval;
117         DSCBUFFERDESC   dscbd;
118         WAVEFORMATEX    wfx;
119
120         if ( !dscap_inited ) {
121                 dscap_init();
122         }
123
124         if ( !dscap_inited ) {
125                 return -1;
126         }
127
128         // Set up recording format
129         wfx.wFormatTag = WAVE_FORMAT_PCM;
130         wfx.nChannels = (unsigned short)nchannels;
131         wfx.nSamplesPerSec = freq;
132         wfx.wBitsPerSample = (unsigned short)bits_per_sample;
133         wfx.cbSize = 0;
134         wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
135         wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
136
137         Dscap_wfx = wfx;        // save the recording format
138
139         if ( pDSCB ) {
140                 dscap_release_buffer();
141         }
142
143         memset(&dscbd, 0, sizeof(DSCBUFFERDESC));
144         dscbd.dwSize = sizeof(DSCBUFFERDESC);
145         dscbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
146         dscbd.lpwfxFormat = &wfx;
147
148         dsrval = pDSC->CreateCaptureBuffer(&dscbd, &pDSCB, NULL);
149         if ( dsrval != DS_OK ) {
150                 nprintf(( "Sound", "SOUND ==> Error '%s' creating a DirectSoundCapture buffer.\n", get_DSERR_text(dsrval)  ));
151                 return -1;
152         }
153
154         Dscap_last_capture_offset=0;
155         return 0;
156 }
157
158 // check if DirectSoundCapture is supported
159 int dscap_supported()
160 {
161         if ( !dscap_inited ) {
162                 dscap_init();
163         }
164         return dscap_inited;
165 }
166
167 // fill up the capture buffer with silence
168 int dscap_fill_buffer_with_silence()
169 {
170         HRESULT                 dsrval;
171         unsigned long   buffer_len, size1, size2;
172         void                            *data1=NULL, *data2=NULL;
173
174         buffer_len = dscap_max_buffersize();
175
176         Assert(pDSCB);
177
178         dsrval = pDSCB->Lock(0, buffer_len, &data1, &size1, &data2, &size2, 0);
179         if ( dsrval != DS_OK ) {
180                 return -1;
181         }
182
183         unsigned char silence_byte;
184
185         switch(Dscap_wfx.wBitsPerSample) {
186         case 8:
187                 silence_byte = 0x80;
188                 break;
189         case 16:
190                 silence_byte = 0x00;
191                 break;
192         default:
193                 Int3();
194                 return -1;
195         }
196
197         if ( (data1) && (size1 > 0) ) {
198                 memset(data1, silence_byte, size1);
199         }
200
201         if ( (data2) && (size2 > 0) ) {
202                 memset(data2, silence_byte, size2);
203         }
204
205         dsrval = pDSCB->Unlock(data1, size1, data2, size2);
206         if ( dsrval != DS_OK ) {
207                 return -1;
208         }
209
210         return 0;
211 }
212
213 // start recording into the buffer
214 int dscap_start_record()
215 {
216         HRESULT dsrval;
217
218         if ( !dscap_inited ) {
219                 dscap_init();
220         }
221
222         if ( !dscap_inited ) {
223                 return -1;
224         }
225
226         if ( dscap_recording ) {
227                 return -1;
228         }
229
230         Assert(pDSCB);
231
232         dscap_fill_buffer_with_silence();
233
234         dsrval = pDSCB->Start(DSCBSTART_LOOPING);
235         if ( dsrval != DS_OK ) {
236                 return -1;
237         }
238
239         dscap_recording=1;
240 //      nprintf(("Alan","RTVOICE => start record\n"));
241         return 0;
242 }
243
244 // stop recording into the buffer
245 int dscap_stop_record()
246 {
247         HRESULT dsrval;
248
249         if ( !dscap_inited ) {
250                 return -1;
251         }
252
253         if ( !dscap_recording ) {
254                 return -1;
255         }
256
257         Assert(pDSCB);
258         dsrval = pDSCB->Stop();
259         if ( dsrval != DS_OK ) {
260                 return -1;
261         }
262
263         dscap_recording=0;
264 //      nprintf(("Alan","RTVOICE => stop record\n"));
265         return 0;
266 }
267
268 // close the DirectSoundCapture system
269 void dscap_close()
270 {
271         dscap_stop_record();
272         dscap_release_buffer();
273
274         if ( pDSC ) {
275                 pDSC->Release();
276                 pDSC=NULL;
277         }
278 }
279
280 // return the max buffer size
281 int dscap_max_buffersize()
282 {
283         DSCBCAPS        caps;
284
285         if ( !dscap_inited ) {
286                 dscap_init();
287         }
288
289         if ( !dscap_inited ) {
290                 return -1;
291         }
292
293         if (!pDSCB) {
294                 return 0;
295         }
296
297         caps.dwSize = sizeof(DSCBCAPS);
298         caps.dwFlags = 0;
299
300         pDSCB->GetCaps(&caps);
301
302         return caps.dwBufferBytes;
303 }
304
305 // retreive the recorded voice data
306 int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
307 {
308         HRESULT                 dsrval;
309         unsigned long   capture_offset, read_offset, num_bytes_captured, size1, size2;
310         void                            *data1=NULL, *data2=NULL;
311
312         if ( !dscap_inited ) {
313                 dscap_init();
314         }
315
316         if ( !dscap_inited ) {
317                 return -1;
318         }
319
320         if ( !pDSCB ) {
321                 return -1;
322         }
323
324         dsrval = pDSCB->GetCurrentPosition(&capture_offset, &read_offset);
325         if ( dsrval != DS_OK ) {
326                 return -1;
327         }
328
329         if ( read_offset >= Dscap_last_capture_offset ) {
330                 num_bytes_captured = read_offset-Dscap_last_capture_offset;
331         } else {
332                 unsigned long max_size = dscap_max_buffersize();
333                 num_bytes_captured = max_size - Dscap_last_capture_offset + read_offset;
334         }
335
336         if ( num_bytes_captured <= 0 ) {
337                 return -1;
338         }       
339
340         dsrval = pDSCB->Lock(Dscap_last_capture_offset, num_bytes_captured, &data1, &size1, &data2, &size2, 0);
341         if ( dsrval != DS_OK ) {
342                 return -1;
343         }
344
345         if ( max_size < (size1+size2) ) {
346                 return -1;
347         }
348
349         if ( (data1) && (size1 > 0) ) {
350                 memcpy(outbuf, data1, size1);
351         }
352
353         if ( (data2) && (size2 > 0) ) {
354                 memcpy(outbuf+size1, data2, size2);
355         }
356
357         dsrval = pDSCB->Unlock(data1, size1, data2, size2);
358         if ( dsrval != DS_OK ) {
359                 return -1;
360         }
361
362         Dscap_last_capture_offset = read_offset;
363         return (size1+size2);
364 }