25 #ifndef WIN32_LEAN_AND_MEAN 26 #define WIN32_LEAN_AND_MEAN 1 40 static void find_all_microphones_ds();
41 friend void find_all_microphones_ds();
58 static void delete_buffers(AudioBuffers &buffers);
60 friend class MicrophoneAudioCursorDS;
66 static void init_type() {
67 MicrophoneAudio::init_type();
68 register_type(_type_handle,
"MicrophoneAudioDS",
69 MicrophoneAudio::get_class_type());
72 return get_class_type();
74 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
90 typedef MicrophoneAudioDS::AudioBuffers AudioBuffers;
91 MicrophoneAudioCursorDS(MicrophoneAudioDS *src, AudioBuffers &bufs, HWAVEIN hwav);
92 virtual ~MicrophoneAudioCursorDS();
94 AudioBuffers _buffers;
96 int _samples_per_buffer;
99 virtual void read_samples(
int n, PN_int16 *data);
100 virtual int ready()
const;
113 static void init_type() {
114 MovieAudioCursor::init_type();
115 register_type(_type_handle,
"MicrophoneAudioCursorDS",
116 MovieAudioCursor::get_class_type());
119 return get_class_type();
121 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
127 TypeHandle MicrophoneAudioCursorDS::_type_handle;
135 void MicrophoneAudioDS::
136 find_all_microphones_ds() {
138 static int freqs[] = { 11025, 22050, 44100, 48000, 0 };
140 int ndevs = waveInGetNumDevs();
141 for (
int i=0; i<ndevs; i++) {
143 stat = waveInGetDevCaps(i, &caps,
sizeof(caps));
144 if (stat != MMSYSERR_NOERROR)
continue;
145 for (
int chan=1; chan<=2; chan++) {
146 for (
int fselect=0; freqs[fselect]; fselect++) {
148 int freq = freqs[fselect];
149 format.wFormatTag = WAVE_FORMAT_PCM;
150 format.nChannels = chan;
151 format.nSamplesPerSec = freq;
152 format.nAvgBytesPerSec = freq * chan * 2;
153 format.nBlockAlign = 2 * chan;
154 format.wBitsPerSample = 16;
156 stat = waveInOpen(NULL, i, &format, NULL, NULL, WAVE_FORMAT_QUERY);
157 if (stat == MMSYSERR_NOERROR) {
158 PT(MicrophoneAudioDS) p =
new MicrophoneAudioDS();
160 name <<
"WaveIn: " << caps.szPname <<
" Chan:" << chan <<
" HZ:" << freq;
161 p->set_name(name.str());
163 p->_manufacturer_id = caps.wMid;
164 p->_product_id = caps.wPid;
167 _all_microphones.push_back((MicrophoneAudioDS*)p);
174 void find_all_microphones_ds() {
175 MicrophoneAudioDS::init_type();
177 MicrophoneAudioDS::find_all_microphones_ds();
185 void MicrophoneAudioDS::
186 delete_buffers(AudioBuffers &buffers) {
187 for (
int i=0; i<(int)buffers.size(); i++) {
188 AudioBuf &buf = buffers[i];
189 if (buf._header_gh) {
190 GlobalUnlock(buf._header_gh);
191 GlobalFree(buf._header_gh);
193 if (buf._storage_gh) {
194 GlobalUnlock(buf._storage_gh);
195 GlobalFree(buf._storage_gh);
212 case 11025: samples=512;
break;
213 case 22050: samples=1024;
break;
214 case 44100: samples=2048;
break;
216 int bytes = _channels * samples * 2;
219 AudioBuffers buffers;
220 for (
int i=0; i<64; i++) {
227 buf._storage_gh = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, bytes);
228 buf._header_gh = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
sizeof(WAVEHDR));
229 if (buf._storage_gh != 0) {
230 buf._storage = (LPSTR)GlobalLock(buf._storage_gh);
232 if (buf._header_gh != 0) {
233 buf._header = (LPWAVEHDR)GlobalLock(buf._header_gh);
235 if (buf._storage && buf._header) {
236 ZeroMemory(buf._header,
sizeof(WAVEHDR));
237 buf._header->lpData = buf._storage;
238 buf._header->dwBufferLength = bytes;
242 buffers.push_back(buf);
247 delete_buffers(buffers);
248 nassert_raise(
"Could not allocate audio input buffers.");
253 format.wFormatTag = WAVE_FORMAT_PCM;
254 format.nChannels = _channels;
255 format.nSamplesPerSec = _rate;
256 format.nAvgBytesPerSec = _rate * _channels * 2;
257 format.nBlockAlign = 2 * _channels;
258 format.wBitsPerSample = 16;
262 MMRESULT stat = waveInOpen(&hwav, _device_id, &format, NULL, NULL, CALLBACK_NULL);
264 if (stat != MMSYSERR_NOERROR) {
265 delete_buffers(buffers);
266 nassert_raise(
"Could not open audio input device.");
270 for (
int i=0; i<(int)buffers.size(); i++) {
271 stat = waveInPrepareHeader(hwav, buffers[i]._header,
sizeof(WAVEHDR));
272 if (stat == MMSYSERR_NOERROR) {
273 stat = waveInAddBuffer(hwav, buffers[i]._header,
sizeof(WAVEHDR));
275 if (stat != MMSYSERR_NOERROR) {
277 delete_buffers(buffers);
278 nassert_raise(
"Could not queue buffers for audio input device.");
282 stat = waveInStart(hwav);
283 if (stat != MMSYSERR_NOERROR) {
285 delete_buffers(buffers);
286 nassert_raise(
"Could not start recording on input device.");
289 return new MicrophoneAudioCursorDS(
this, buffers, hwav);
297 MicrophoneAudioCursorDS::
298 MicrophoneAudioCursorDS(MicrophoneAudioDS *src, AudioBuffers &bufs, HWAVEIN hwav) :
305 _audio_rate = src->get_rate();
306 _audio_channels = src->get_channels();
309 _can_seek_fast =
false;
311 _samples_per_buffer = bufs[0]._header->dwBufferLength / (2 * _audio_channels);
319 void MicrophoneAudioCursorDS::
322 waveInClose(_handle);
325 MicrophoneAudioDS::delete_buffers(_buffers);
335 MicrophoneAudioCursorDS::
336 ~MicrophoneAudioCursorDS() {
345 void MicrophoneAudioCursorDS::
346 read_samples(
int n, PN_int16 *data) {
350 int index = _next % _buffers.size();
351 if ((_buffers[index]._header->dwFlags & WHDR_DONE)==0) {
356 PN_int16 *src = (PN_int16*)(_buffers[index]._storage);
357 src += (_offset * _audio_channels);
360 int samples = _samples_per_buffer;
362 if (samples > n) samples = n;
365 memcpy(data, src, samples * 2 * _audio_channels);
368 data += samples * _audio_channels;
371 _samples_read += samples;
372 if (_offset != _samples_per_buffer) {
375 _buffers[index]._header->dwFlags &= ~(WHDR_DONE);
376 MMRESULT stat = waveInUnprepareHeader(_handle, _buffers[index]._header,
sizeof(WAVEHDR));
377 if (stat == MMSYSERR_NOERROR) {
378 stat = waveInPrepareHeader(_handle, _buffers[index]._header,
sizeof(WAVEHDR));
380 if (stat == MMSYSERR_NOERROR) {
381 stat = waveInAddBuffer(_handle, _buffers[index]._header,
sizeof(WAVEHDR));
383 if (stat != MMSYSERR_NOERROR) {
384 movies_cat.error() <<
"Could not requeue audio buffers, closing microphone.\n";
393 memcpy(data, 0, n*2*_audio_channels);
402 int MicrophoneAudioCursorDS::
404 if (_handle == 0)
return 0;
406 for (
int i=0; i<(int)_buffers.size(); i++) {
407 int index = (_next + i) % (_buffers.size());
408 if ((_buffers[index]._header->dwFlags & WHDR_DONE)==0) {
411 total += _samples_per_buffer;
418 #endif // HAVE_DIRECTSHOW
Class MicrophoneAudio provides the means to read raw audio samples from a microphone.
This is our own Panda specialization on the default STL vector.
A MovieAudio is actually any source that provides a sequence of audio samples.
TypeHandle is the identifier used to differentiate C++ class types.