OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / audio / compAudio.cxx
1 // compAudio.cxx - description.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #include "config.h"
8 #include "components.h"
9
10
11 // Stuff usually defined in mmreg.h 
12 #ifndef WAVE_FORMAT_ALAW
13 #define WAVE_FORMAT_ALAW 0x0006
14 #endif
15
16 #ifndef WAVE_FORMAT_MULAW
17 #define WAVE_FORMAT_MULAW 0x0007
18 #endif
19
20 #ifndef WAVE_FORMAT_ADPCM
21 #define WAVE_FORMAT_ADPCM 0x0002
22 #endif
23
24
25
26 // ----------------------------------------------------------------------------
27
28
29 ostream& 
30 operator << (ostream& o, const audio_config& c)
31 {
32   o << c.num_bits_per_sample << "-bit";
33
34   o << " ";
35
36   switch (c.encoding) 
37     {
38     case audio_config::ulaw:
39       o << "uLaw"; break;
40     case audio_config::alaw:
41       o << "aLaw"; break;
42     case audio_config::pcm:
43       o << "PCM"; break;
44     default:
45       o << "?"; break;
46     }
47
48   o << " ";
49
50   switch (c.num_channels)
51     {
52     case 1:
53       o << "mono"; break;
54     case 2:
55       o << "stereo"; break;
56     default:
57       o << "?"; break;
58     }
59
60   o << " ";
61
62   o << c.sampling_frequency << "Hz";
63   return o;
64 }
65
66
67 istream& 
68 operator >> (istream& i, audio_config& c)
69 {
70   // Don't support parsing above string.
71   i.setstate (ios::badbit);
72   return i;
73 }
74
75
76
77 audio_config::audio_config ()
78 {
79   this->num_bits_per_sample = 8;
80   this->encoding = audio_config::ulaw;
81   this->num_channels = 1;
82   this->sampling_frequency = 8000;
83 }
84
85
86 host_int_4
87 audio_config::encode () const
88 {
89   return
90     ((this->sampling_frequency << 0) & 0x0000FFFF) |
91     ((this->num_channels << 16) & 0x00070000) |
92     ((static_cast<int>(this->encoding) << 20) & 0x00300000) |
93     ((this->num_bits_per_sample << 24) & 0x0F000000);
94 }
95
96
97 audio_config::audio_config (host_int_4 value)
98 {
99   this->sampling_frequency = (value & 0x0000FFFF) >> 0;
100   this->num_channels = (value & 0x00070000) >> 16;
101   this->encoding = static_cast<encoding_t>((value & 0x00300000) >> 20);
102   this->num_bits_per_sample = (value & 0x0F000000) >> 24;
103 }
104
105
106
107 // ----------------------------------------------------------------------------
108
109 generic_audio::generic_audio ():
110   tx_mode_pin (this, & generic_audio::tx_mode_pin_handler),
111   tx_sample_pin (this, & generic_audio::tx_sample_pin_handler),
112   rx_mode_pin (this, & generic_audio::rx_mode_pin_handler),
113   config_set_pin (this, & generic_audio::config_set_pin_handler),
114   reset_pin (this, & generic_audio::reset_pin_handler),
115   poll_pin (this, & generic_audio::poll_pin_handler)
116 {
117   this->tx_active_p = false;
118   this->rx_active_p = false;
119   this->poll_count = 0;
120   this->tx_samples_count = 0;
121   this->tx_blocks_count = 0;
122   this->rx_samples_count = 0;
123   this->rx_blocks_count = 0;
124
125   // Use default audio_config
126
127   add_pin ("tx-mode", & this->tx_mode_pin);
128   add_attribute ("tx-mode", & this->tx_mode_pin, "pin");
129   add_pin ("tx-pending", & this->tx_pending_pin);
130   add_attribute ("tx-pending", & this->tx_pending_pin, "pin");
131   add_pin ("tx-sample", & this->tx_sample_pin);
132   add_attribute ("tx-sample", & this->tx_sample_pin, "pin");
133   add_attribute_ro ("tx-mode?", & this->tx_active_p, "register");
134   add_attribute_ro ("tx-buffer", & this->tx_buffer, "register");
135
136   add_pin ("rx-mode", & this->rx_mode_pin);
137   add_attribute ("rx-mode", & this->rx_mode_pin, "pin");
138   add_pin ("rx-pending", & this->rx_pending_pin);
139   add_attribute ("rx-pending", & this->rx_pending_pin, "pin");
140   add_pin ("rx-sample", & this->rx_sample_pin);
141   add_attribute ("rx-sample", & this->rx_sample_pin, "pin");
142   add_attribute_ro ("rx-mode?", & this->rx_active_p, "register");
143   add_attribute_ro ("rx-buffer", & this->rx_buffer, "register");
144
145   add_attribute_ro ("config", & this->config, "setting");
146   add_pin ("config-set", & this->config_set_pin);
147   add_attribute ("config-set", & this->config_set_pin, "pin");
148
149   add_pin ("reset", & this->reset_pin);
150   add_attribute ("reset", & this->reset_pin, "pin");
151
152   add_pin ("poll", & this->poll_pin);
153   add_attribute ("poll", & this->poll_pin, "pin");
154
155   add_attribute ("poll-count", & this->poll_count, "register");
156   add_attribute ("tx-blocks-count", & this->tx_blocks_count, "register");
157   add_attribute ("tx-samples-count", & this->tx_samples_count, "register");
158   add_attribute ("rx-blocks-count", & this->rx_blocks_count, "register");
159   add_attribute ("rx-samples-count", & this->rx_samples_count, "register");
160 }
161
162
163 bool
164 generic_audio::pending_tx_p ()
165 {
166   return (this->tx_buffer != "");
167 }
168
169
170 void
171 generic_audio::update_txrx_pending_pins ()
172 {
173   // possible rising tx-pending edge
174   if (this->pending_tx_p ())
175     if (this->tx_pending_pin.recall() == 0)
176       tx_pending_pin.drive (1);
177   
178   // possible falling tx-pending edge
179   if (! this->pending_tx_p ())
180     if (this->tx_pending_pin.recall() != 0)
181       tx_pending_pin.drive (0);
182
183   // possible rising rx-pending edge
184   if (this->rx_active_p)
185     if (this->rx_pending_pin.recall() == 0)
186       this->rx_pending_pin.drive (1);
187
188   // possible falling rx-pending edge
189   if (! this->rx_active_p)
190     if (this->rx_pending_pin.recall() != 0)
191       this->rx_pending_pin.drive (0);
192 }
193
194
195 void
196 generic_audio::tx_mode_pin_handler (host_int_4 value)
197 {
198   if (value != 0)
199     {
200       if (this->tx_active_p)
201         {
202           cerr << "sid-io-audio: already in tx mode" << endl;
203           return;
204         }
205       
206       bool ok = this->begin_tx (this->config);
207       if (! ok)
208         {
209           cerr << "sid-io-audio: cannot begin tx" << endl;
210           return;
211         }
212       
213       this->tx_active_p = true;
214       this->tx_blocks_count ++;
215     }
216   else
217     {
218       if (! this->tx_active_p)
219         {
220           cerr << "sid-io-audio: already out of tx mode" << endl;
221           return;
222         }
223
224       // try flushing tx-buffer once, as a last gasp measure
225       if (this->pending_tx_p ())
226         {
227           this->poll_pin_handler (0);
228         }
229
230       if (this->pending_tx_p ())
231         {
232           cerr << "sid-io-audio: flushing buffers on tx close" << endl;
233           this->tx_buffer = "";
234         }
235
236       this->end_tx ();
237       this->tx_active_p = false;
238     }
239
240   this->update_txrx_pending_pins ();
241 }
242
243
244 void
245 generic_audio::rx_mode_pin_handler (host_int_4 value)
246 {
247   if (value != 0)
248     {
249       if (this->rx_active_p)
250         {
251           cerr << "sid-io-audio: already in rx mode" << endl;
252           return;
253         }
254       
255       bool ok = this->begin_rx (this->config);
256       if (! ok)
257         {
258           cerr << "sid-io-audio: cannot begin rx" << endl;
259           return;
260         }
261       
262       this->rx_active_p = true;
263       this->rx_blocks_count ++;
264     }
265   else
266     {
267       if (! this->rx_active_p)
268         {
269           cerr << "sid-io-audio: already out of rx mode" << endl;
270           return;
271         }
272       
273       this->end_rx ();
274       this->rx_active_p = false;
275     }
276
277   this->update_txrx_pending_pins ();
278 }
279
280
281 void
282 generic_audio::config_set_pin_handler (host_int_4 value)
283 {
284   // Update settings only if we are idle
285   if (! (this->rx_active_p || this->tx_active_p))
286     this->config = audio_config (value);
287 }
288
289
290 void
291 generic_audio::reset_pin_handler (host_int_4)
292 {
293   if (this->rx_active_p)
294     {
295       this->end_rx ();
296       this->rx_active_p = false;
297       this->rx_buffer = "";
298     }
299
300   if (this->tx_active_p)
301     {
302       this->end_tx ();
303       this->tx_active_p = false;
304       this->tx_buffer = "";
305     }
306
307   this->update_txrx_pending_pins ();
308 }
309
310
311
312 void
313 generic_audio::tx_sample_pin_handler (host_int_4 value)
314 {
315   if (this->tx_active_p)
316     this->tx_buffer += static_cast<unsigned char>((value & 0xFF));
317   else
318     {
319       // cerr << "sid-io-audio: Ignoring unexpected tx sample." << endl;
320     }
321 }
322
323
324
325 void
326 generic_audio::poll_pin_handler (host_int_4)
327 {
328   this->poll_count ++;
329
330   if (this->tx_active_p)
331     {
332       string remains = this->poll_tx (this->tx_buffer);
333       this->tx_samples_count += this->tx_buffer.size() - remains.size();
334       this->tx_buffer = remains;
335     }
336
337   if (this->rx_active_p)
338     {
339       string rxbuf = this->poll_rx ();
340       for (unsigned i=0; i<rxbuf.size(); i++)
341         {
342           this->rx_samples_count ++;
343           host_int_1 byte = rxbuf[i];
344           host_int_4 value = byte;
345           this->rx_sample_pin.drive (value);
346         }
347     }
348
349   this->update_txrx_pending_pins ();
350 }
351
352
353 // ----------------------------------------------------------------------------
354
355
356 fd_audio::fd_audio()
357 {
358   this->tx_fd = -1;
359   this->rx_fd = -1;
360   this->devaudio = "/dev/audio";
361
362   add_attribute ("device", & this->devaudio, "setting");
363 }
364
365
366 fd_audio::~fd_audio()
367 {
368   if (this->rx_fd >= 0)
369     close (this->rx_fd);
370   if (this->tx_fd >= 0)
371     close (this->tx_fd);
372 }
373
374
375 static void
376 asyncificate (int fd)
377 {
378   // Make this file descriptor nonblocking.
379   // Don't make it O_ASYNC though - we don't care about SIGIO.
380
381   // POSIX way
382   int flags = fcntl (fd, F_GETFL, 0);
383   flags |= O_NONBLOCK;
384   int rc = fcntl (fd, F_SETFL, flags);
385
386   if (rc == -1)
387     cerr << "fcntl error: " << std_error_string() << endl;
388
389   // This was necessary for cygwin sockets - see sid/component/consoles/socketio.cxx
390 #if 0
391   // CYGWIN way
392   int yes = 1;
393   rc = ioctl (fd, FIONBIO, (void*) & yes);
394
395   if (rc == -1)
396     cerr << "ioctl error: " << std_error_string() << endl;
397 #endif
398 }
399
400
401 bool
402 fd_audio::begin_tx (const audio_config& c)
403 {
404   assert (this->tx_fd < 0);
405
406   this->tx_fd = open (this->devaudio.c_str(), O_WRONLY);
407   if (this->tx_fd < 0)
408     {
409       cerr << "sid-io-audio: error opening " << devaudio << ": " << std_error_string() << endl;
410       return false;
411     }
412
413   asyncificate (this->tx_fd);
414
415   bool ok = this->set_audio_config (this->tx_fd, c);
416   if (! ok)
417     {
418       cerr << "sid-io-audio: error setting mode " << c << endl;
419       close (this->tx_fd);
420       this->tx_fd = -1;
421       return false;
422     }
423
424   return true;
425 }
426
427
428 void
429 fd_audio::end_tx ()
430 {
431   assert (this->tx_fd >= 0);
432   close (this->tx_fd);
433   this->tx_fd = -1;
434 }
435
436
437
438 bool
439 fd_audio::begin_rx (const audio_config& c)
440 {
441   assert (this->rx_fd < 0);
442
443   this->rx_fd = open (this->devaudio.c_str(), O_RDONLY);
444   if (this->rx_fd < 0)
445     {
446       cerr << "sid-io-audio: error opening " << devaudio << ": " << std_error_string() << endl;
447       return false;
448     }
449
450   asyncificate (this->rx_fd);
451   
452   bool ok = this->set_audio_config (this->rx_fd, c);
453   if (! ok)
454     {
455       cerr << "sid-io-audio: error setting mode " << c << endl;
456       close (this->rx_fd);
457       this->rx_fd = -1;
458       return false;
459     }
460
461   return true;
462 }
463
464
465 void
466 fd_audio::end_rx ()
467 {
468   assert (this->rx_fd >= 0);
469   close (this->rx_fd);
470   this->rx_fd = -1;
471 }
472
473
474 static bool
475 innocent_errno_p (int err)
476 {
477   return ((err == EWOULDBLOCK) 
478           || (err == EINPROGRESS)
479           || (err == EINTR)
480           || (err == EAGAIN));
481 }
482
483
484 string
485 fd_audio::poll_tx (const string& txbuf)
486 {
487   if (txbuf.length() == 0)
488     return txbuf;
489
490   assert (this->tx_fd >= 0);
491
492   int count = write (this->tx_fd, txbuf.data(), txbuf.length());
493   if ((count < 0) && (! innocent_errno_p (errno)))
494     {
495       cerr << "sid-io-audio: write error: " << std_error_string() << endl;
496       // Act as if sample was consumed
497       return string();
498     }
499   else if (count <= 0 && innocent_errno_p (errno))
500     {
501       // Return entire string for future poll
502       return txbuf;
503     }
504   else if (count == txbuf.length())
505     {
506       // Everything was sent!
507       return string ();
508     }
509   else
510     {
511       // Return unsent portion
512       return txbuf.substr (count);
513     }
514 }
515
516
517 string
518 fd_audio::poll_rx ()
519 {
520   assert (this->rx_fd >= 0);
521
522   enum { rx_buffer_size = 65536 } ;
523   static char rx_buffer [rx_buffer_size];
524
525   int count = read (this->rx_fd, rx_buffer, rx_buffer_size);
526   if ((count < 0) && (! innocent_errno_p (errno)))
527     {
528       cerr << "sid-io-audio: read error: " << std_error_string() << endl;
529       // Act as if nothing was returned
530       return string();
531     }
532   else if (count <= 0 && innocent_errno_p (errno))
533     {
534       // Try again later
535       return string();
536     }
537   else
538     {
539       // Return received portion
540       return string (rx_buffer, count);
541     }
542 }
543
544
545 // ----------------------------------------------------------------------------
546
547
548 #if defined(SOUND_CYGWIN)
549
550 // XXX: CONTINUE HERE
551
552 cygwin_audio::cygwin_audio() 
553 {
554   this->waveOut = 0;
555   this->waveIn = 0;
556
557   this->rx_buffer_size = 8000;
558   add_attribute ("rx-buffer-size", & this->rx_buffer_size, "setting");
559   this->rx_buffer_count = 8;
560   add_attribute ("rx-buffer-count", & this->rx_buffer_count, "setting");
561 }
562
563
564 cygwin_audio::~cygwin_audio () 
565 {
566 }
567
568
569 bool
570 cygwin_audio::begin_tx (const audio_config& c) 
571
572   assert (this->waveOut == 0);
573
574   WAVEFORMATEX win_format;
575
576   switch (c.encoding)
577     {
578     case audio_config::ulaw:
579       win_format.wFormatTag = WAVE_FORMAT_MULAW;
580       break;
581       
582     case audio_config::alaw:
583       win_format.wFormatTag = WAVE_FORMAT_ALAW;
584       break;
585
586     case audio_config::pcm:
587       win_format.wFormatTag = WAVE_FORMAT_PCM;
588       break;
589
590     default:
591       return false;
592     }
593
594   win_format.wBitsPerSample = c.num_bits_per_sample;
595   win_format.nChannels = c.num_channels;
596   win_format.nSamplesPerSec = c.sampling_frequency;
597   win_format.nAvgBytesPerSec = 
598     c.sampling_frequency * (c.num_bits_per_sample / 8) * c.num_channels;
599   win_format.nBlockAlign = (c.num_bits_per_sample / 8) * c.num_channels;
600   win_format.cbSize = 0;
601
602   unsigned res = waveOutOpen (& this->waveOut, WAVE_MAPPER,
603                               & win_format, 0, 0L, CALLBACK_NULL);
604   if (res || (this->waveOut == 0))
605     {
606       cerr << "sid-io-audio: waveOutOpen error " << res << endl;
607       return false;
608     }
609
610   return true; 
611 }
612
613
614 bool
615 cygwin_audio::pending_tx_p ()
616 {
617   return generic_audio::pending_tx_p () || (! this->tx_bufs.empty ());
618 }
619
620
621 void
622 cygwin_audio::end_tx () 
623 {
624   assert (this->waveOut != 0);  
625
626   unsigned res = waveOutReset (this->waveOut);
627   if (res)
628     cerr << "sid-io-audio: waveOutReset rc=" << res << endl;
629
630   // Free up tx buffers
631   while (! this->tx_bufs.empty())
632     {
633       win32_audio_tx_buf* b = this->tx_bufs.front();
634       delete b;
635       this->tx_bufs.pop_front ();
636     }
637
638   res = waveOutClose (this->waveOut);
639   if (res != 0)
640     cerr << "sid-io-audio: waveOutClose rc=" << res << endl;
641
642   this->waveOut = 0;
643 }
644
645
646
647 bool
648 cygwin_audio::begin_rx (const audio_config& c)
649 {
650   assert (this->waveIn == 0);
651
652   WAVEFORMATEX win_format;
653
654   switch (c.encoding)
655     {
656     case audio_config::ulaw:
657       win_format.wFormatTag = WAVE_FORMAT_MULAW;
658       break;
659       
660     case audio_config::alaw:
661       win_format.wFormatTag = WAVE_FORMAT_ALAW;
662       break;
663
664     case audio_config::pcm:
665       win_format.wFormatTag = WAVE_FORMAT_PCM;
666       break;
667
668     default:
669       return false;
670     }
671
672   win_format.wBitsPerSample = c.num_bits_per_sample;
673   win_format.nChannels = c.num_channels;
674   win_format.nSamplesPerSec = c.sampling_frequency;
675   win_format.nAvgBytesPerSec = 
676     c.sampling_frequency * (c.num_bits_per_sample / 8) * c.num_channels;
677   win_format.nBlockAlign = (c.num_bits_per_sample / 8) * c.num_channels;
678   win_format.cbSize = 0;
679
680   unsigned res = waveInOpen (& this->waveIn, WAVE_MAPPER,
681                              & win_format, 0, 0L, CALLBACK_NULL);
682   if (res || (this->waveIn == 0))
683     {
684       cerr << "sid-io-audio: waveInOpen error " << res << endl;
685       return false;
686     }
687
688   // Create rx buffers
689   for (unsigned i=0; i<this->rx_buffer_count; i++)
690     {
691       win32_audio_rx_buf* b = new win32_audio_rx_buf (this->waveIn, this->rx_buffer_size);
692       this->rx_bufs.push_back (b);
693     }
694
695   // Start receiving into them
696   res = waveInStart (this->waveIn);
697   if (res)
698     {
699       cerr << "sid-io-audio: waveInStart error " << res << endl;
700     }
701
702   return true; 
703 }
704
705
706 void
707 cygwin_audio::end_rx ()
708 {
709   assert (this->waveIn != 0);  
710
711   unsigned res = waveInStop (this->waveIn);
712   if (res)
713     cerr << "sid-io-audio: waveInStop rc=" << res << endl;
714
715   res = waveInReset (this->waveIn);
716   if (res)
717     cerr << "sid-io-audio: waveInReset rc=" << res << endl;
718
719   // Free up pending rx buffers
720   while (! this->rx_bufs.empty())
721     {
722       win32_audio_rx_buf* b = this->rx_bufs.front ();
723       delete b;
724       this->rx_bufs.pop_front ();
725     }
726
727   res = waveInClose (this->waveIn);
728   if (res)
729     cerr << "sid-io-audio: waveInClose rc=" << res << endl;
730
731   this->waveIn = 0;
732 }
733
734
735 string
736 cygwin_audio::poll_tx (const string& buf)
737 {
738   // Free up spent tx buffers
739   while (! this->tx_bufs.empty())
740     {
741       win32_audio_tx_buf* b = this->tx_bufs.front();
742       if (! b->done_p())
743         break;
744
745       delete b;
746       this->tx_bufs.pop_front ();
747     }
748
749   if (buf.length() == 0)
750     return buf;
751
752   win32_audio_tx_buf* b = new win32_audio_tx_buf (this->waveOut, buf);
753   this->tx_bufs.push_back (b);
754   
755   // We always consume entire supplied buffer
756   return string ();
757 }
758
759
760 string
761 cygwin_audio::poll_rx ()
762 {
763   string everything;
764
765   // Free up pending rx buffers
766   while (! this->rx_bufs.empty())
767     {
768       win32_audio_buf* b = this->rx_bufs.front ();
769       if (! b->done_p())
770         break;
771
772       everything += b->buffer ();
773       delete b;
774       this->rx_bufs.pop_front ();
775
776       win32_audio_rx_buf* b2 = new win32_audio_rx_buf (this->waveIn, this->rx_buffer_size);
777       this->rx_bufs.push_back (b2);
778     }
779
780   return everything;
781 }
782
783
784 win32_audio_buf::win32_audio_buf (host_int_4 size)
785 {
786   this->block_handle = GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, size);
787   if (! this->block_handle)
788     {
789       cerr << "sid-io-audio: GlobalAlloc " << size << " failed." << endl;
790       // Act as if we're already done.
791       this->header.dwFlags |= WHDR_DONE;
792       return;
793     }
794   this->block_addr = static_cast<HPSTR>(GlobalLock (this->block_handle));
795
796   this->header.lpData = this->block_addr;
797   this->header.dwBufferLength = size;
798   this->header.dwFlags = 0;
799   this->header.dwLoops = 0;
800   this->header.dwBytesRecorded = 0;
801   this->header.dwUser = 0;
802 }
803
804
805 win32_audio_buf::~win32_audio_buf ()
806 {
807   if (this->block_handle == 0)
808     return;
809
810   GlobalUnlock (this->block_addr);
811   GlobalFree (this->block_handle);
812 }
813
814
815 bool
816 win32_audio_buf::done_p ()
817 {
818   return (this->header.dwFlags & WHDR_DONE);
819 }
820
821
822 win32_audio_tx_buf::win32_audio_tx_buf (HWAVEOUT dev, const string& buf):
823   win32_audio_buf (buf.length ())
824 {
825   this->device = dev;
826   
827   // Copy data into this buffer
828   memcpy (this->block_addr, buf.data(), buf.length());
829
830   unsigned res = waveOutPrepareHeader (this->device, & this->header, sizeof (this->header));
831   if (res)
832     {
833       cerr << "sid-io-audio: waveOutPrepareHeader error " << res << endl;
834       return;
835     }
836
837   res = waveOutWrite (this->device, & this->header, sizeof (this->header));
838   if (res)
839     {
840       cerr << "sid-io-audio: waveOutWrite error " << res << endl;
841       return;
842     }
843 }
844
845
846 win32_audio_rx_buf::win32_audio_rx_buf (HWAVEIN dev, host_int_4 size):
847   win32_audio_buf (size)
848 {
849   this->device = dev;
850
851   unsigned res = waveInPrepareHeader (this->device, & this->header, sizeof (this->header));
852   if (res)
853     {
854       cerr << "sid-io-audio: waveInPrepareHeader error " << res << endl;
855       return;
856     }
857
858   res = waveInAddBuffer (this->device, & this->header, sizeof (this->header));
859   if (res)
860     {
861       cerr << "sid-io-audio: waveInAddBuffer error " << res << endl;
862       return;
863     }
864 }
865
866
867 win32_audio_rx_buf::~win32_audio_rx_buf ()
868 {
869   unsigned res = waveInUnprepareHeader (this->device, & this->header, sizeof (this->header));
870   if (res)
871     {
872       cerr << "sid-io-audio: waveInUnprepareHeader error " << res << endl;
873       return;
874     }
875 }
876
877
878 win32_audio_tx_buf::~win32_audio_tx_buf ()
879 {
880   unsigned res = waveOutUnprepareHeader (this->device, & this->header, sizeof (this->header));
881   if (res)
882     {
883       cerr << "sid-io-audio: waveOutUnprepareHeader error " << res << endl;
884       return;
885     }
886 }
887
888
889 string
890 win32_audio_buf::buffer ()
891 {
892   // fetch buffer contents
893   string value = string (this->block_addr, this->header.dwBufferLength);
894   return value;
895 }
896
897
898
899 #endif // CYGWIN