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