Using .min and .max on scipy arrays instead of min() max(); seems to be more portable.
[debian/gnuradio] / gr-audio-windows / src / audio_windows_sink.cc
1 /* -*- c++ -*- */
2 /*
3 * Copyright 2004,2010 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <audio_windows_sink.h>
28 #include <gr_io_signature.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <iostream>
35 #include <stdexcept>
36 #include <string>
37 #include <sstream>
38
39 static const double CHUNK_TIME = 0.1;   //0.001;           // 100 ms
40
41 // FIXME these should query some kind of user preference
42
43 static std::string
44 default_device_name ()
45 {
46   return "WAVE_MAPPER";
47 }
48
49 audio_windows_sink::audio_windows_sink (int sampling_freq, const std::string device_name)
50   : gr_sync_block ("audio_windows_sink",
51                    gr_make_io_signature (1, 2, sizeof (float)),
52                    gr_make_io_signature (0, 0, 0)),
53     d_sampling_freq (sampling_freq),
54     d_device_name (device_name.empty ()? default_device_name () : device_name),
55     d_fd (-1), d_buffer (0), d_chunk_size (0)
56 {
57   d_wave_write_event = CreateEvent (NULL, FALSE, FALSE, NULL);
58   if (open_waveout_device () < 0)
59     {
60       //fprintf (stderr, "audio_windows_sink:open_waveout_device() failed\n");
61       perror ("audio_windows_sink:open_waveout_device( ) failed\n");
62       throw
63       std::runtime_error ("audio_windows_sink:open_waveout_device() failed");
64     }
65
66   d_chunk_size = (int) (d_sampling_freq * CHUNK_TIME);
67   set_output_multiple (d_chunk_size);
68
69   d_buffer = new short[d_chunk_size * 2];
70
71 }
72
73 audio_windows_sink::~audio_windows_sink ()
74 {
75   /* Free the callback Event */
76   CloseHandle (d_wave_write_event);
77   waveOutClose (d_h_waveout);
78   delete[]d_buffer;
79 }
80
81 audio_windows_sink_sptr
82 audio_windows_make_sink (int sampling_freq, const std::string dev)
83 {
84   return gnuradio::get_initial_sptr (new audio_windows_sink (sampling_freq, dev));
85 }
86
87
88 int
89 audio_windows_sink::work (int noutput_items,
90                           gr_vector_const_void_star & input_items,
91                           gr_vector_void_star & output_items)
92 {
93   const float *f0, *f1;
94   bool playtestsound = false;
95   if (playtestsound)
96     {
97       // dummy
98
99       f0 = (const float *) input_items[0];
100
101       for (int i = 0; i < noutput_items; i += d_chunk_size)
102         {
103           for (int j = 0; j < d_chunk_size; j++)
104             {
105               d_buffer[2 * j + 0] = (short) (sin (2.0 * 3.1415926535897932384626 * (float) j * 1000.0 / (float) d_sampling_freq) * 8192 + 0);   //+32767
106               d_buffer[2 * j + 1] = d_buffer[2 * j + 0];
107             }
108           f0 += d_chunk_size;
109           if (write_waveout
110               ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
111             {
112               fprintf (stderr, "audio_windows_sink: write failed\n");
113               perror ("audio_windows_sink: write failed");
114             }
115         }
116       // break;
117     }
118   else
119     {
120       switch (input_items.size ())
121         {
122
123         case 1:         // mono input
124
125           f0 = (const float *) input_items[0];
126
127           for (int i = 0; i < noutput_items; i += d_chunk_size)
128             {
129               for (int j = 0; j < d_chunk_size; j++)
130                 {
131                   d_buffer[2 * j + 0] = (short) (f0[j] * 32767);
132                   d_buffer[2 * j + 1] = (short) (f0[j] * 32767);
133                 }
134               f0 += d_chunk_size;
135               if (write_waveout
136                   ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
137                 {
138                   //fprintf (stderr, "audio_windows_sink: write failed\n");
139                   perror ("audio_windows_sink: write failed");
140                 }
141             }
142           break;
143
144         case 2:         // stereo input
145
146           f0 = (const float *) input_items[0];
147           f1 = (const float *) input_items[1];
148
149           for (int i = 0; i < noutput_items; i += d_chunk_size)
150             {
151               for (int j = 0; j < d_chunk_size; j++)
152                 {
153                   d_buffer[2 * j + 0] = (short) (f0[j] * 32767);
154                   d_buffer[2 * j + 1] = (short) (f1[j] * 32767);
155                 }
156               f0 += d_chunk_size;
157               f1 += d_chunk_size;
158               if (write_waveout
159                   ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
160                 {
161                   //fprintf (stderr, "audio_windows_sink: write failed\n");
162                   perror ("audio_windows_sink: write failed");
163                 }
164             }
165           break;
166         }
167     }
168   return noutput_items;
169 }
170
171 int
172 audio_windows_sink::string_to_int (const std::string & s)
173 {
174   int i;
175   std::istringstream (s) >> i;
176   return i;
177 }                               //ToInt()
178
179 int
180 audio_windows_sink::open_waveout_device (void)
181 {
182
183   UINT /*UINT_PTR */ u_device_id;
184         /** Identifier of the waveform-audio output device to open. It can be either a device identifier or a handle of an open waveform-audio input device. You can use the following flag instead of a device identifier.
185         *
186         * Value Meaning
187         * WAVE_MAPPER The function selects a waveform-audio output device capable of playing the given format.
188         */
189   if (d_device_name.empty () || default_device_name () == d_device_name)
190     u_device_id = WAVE_MAPPER;
191   else
192     u_device_id = (UINT) string_to_int (d_device_name);
193   // Open a waveform device for output using event callback.
194
195   unsigned long result;
196   //HWAVEOUT      outHandle;
197   WAVEFORMATEX wave_format;
198
199   /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */
200   wave_format.wFormatTag = WAVE_FORMAT_PCM;
201   wave_format.nChannels = 2;
202   wave_format.nSamplesPerSec = d_sampling_freq; //44100;
203   wave_format.wBitsPerSample = 16;
204   wave_format.nBlockAlign =
205     wave_format.nChannels * (wave_format.wBitsPerSample / 8);
206   wave_format.nAvgBytesPerSec =
207     wave_format.nSamplesPerSec * wave_format.nBlockAlign;
208   wave_format.cbSize = 0;
209
210   /* Open the (preferred) Digital Audio Out device. */
211   result = waveOutOpen (&d_h_waveout, WAVE_MAPPER, &wave_format, (DWORD_PTR) d_wave_write_event, 0, CALLBACK_EVENT | WAVE_ALLOWSYNC);   //|WAVE_FORMAT_DIRECT | CALLBACK_EVENT| WAVE_ALLOWSYNC
212   if (result)
213     {
214       fprintf (stderr,
215                "audio_windows_sink: Failed to open waveform output device.\n");
216       perror ("audio_windows_sink: Failed to open waveform output device.");
217       //LocalUnlock(hFormat);
218       //LocalFree(hFormat);
219       //mmioClose(hmmio, 0);
220       return -1;
221     }
222
223   //
224   // Do not Swallow the "open" event.
225   //
226   //WaitForSingleObject(d_wave_write_event, INFINITE);
227
228   // Allocate and lock memory for the header.
229
230   d_h_wave_hdr = GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE,
231                               (DWORD) sizeof (WAVEHDR));
232   if (d_h_wave_hdr == NULL)
233     {
234       //GlobalUnlock(hData);
235       //GlobalFree(hData);
236       //fprintf (stderr, "audio_windows_sink: Not enough memory for header.\n");
237       perror ("audio_windows_sink: Not enough memory for header.");
238       return -1;
239     }
240
241   d_lp_wave_hdr = (LPWAVEHDR) GlobalLock (d_h_wave_hdr);
242   if (d_lp_wave_hdr == NULL)
243     {
244       //GlobalUnlock(hData);
245       //GlobalFree(hData);
246       //fprintf (stderr, "audio_windows_sink: Failed to lock memory for header.\n");
247       perror ("audio_windows_sink: Failed to lock memory for header.");
248       return -1;
249     }
250   //d_lp_wave_hdr->dwFlags = WHDR_DONE;
251   return 0;
252 }
253
254 int
255 audio_windows_sink::write_waveout (HPSTR lp_data, DWORD dw_data_size)
256 {
257   UINT w_result;
258   int teller = 100;
259   // After allocation, set up and prepare header.
260   /*while ((d_lp_wave_hdr->dwFlags & WHDR_DONE)==0 && teller>0)
261      {
262      teller--;
263      Sleep(1);
264      } */
265   // Wait until previous wave write completes (first event is the open event).
266   WaitForSingleObject (d_wave_write_event, 100);        //INFINITE
267   d_lp_wave_hdr->lpData = lp_data;
268   d_lp_wave_hdr->dwBufferLength = dw_data_size;
269   d_lp_wave_hdr->dwFlags = 0L;
270   /* Clear the WHDR_DONE bit (which the driver set last time that
271      this WAVEHDR was sent via waveOutWrite and was played). Some
272      drivers need this to be cleared */
273   //d_lp_wave_hdr->dwFlags &= ~WHDR_DONE;
274
275   d_lp_wave_hdr->dwLoops = 0L;
276   w_result =
277     waveOutPrepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
278   if (w_result != 0)
279     {
280       //GlobalUnlock( hData);
281       //GlobalFree(hData);
282       //fprintf (stderr, "audio_windows_sink: Failed to waveOutPrepareHeader. error %i\n",w_result);
283       perror ("audio_windows_sink: Failed to waveOutPrepareHeader");
284     }
285   // Now the data block can be sent to the output device. The
286   // waveOutWrite function returns immediately and waveform
287   // data is sent to the output device in the background.
288   //while (!  readyforplayback) Sleep(1);
289   //readyforplayback=false;
290   //
291   //
292
293   w_result = waveOutWrite (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
294   if (w_result != 0)
295     {
296       //GlobalUnlock( hData);
297       //GlobalFree(hData);
298       //fprintf (stderr, "audio_windows_sink: Failed to write block to device.error %i\n",w_result);
299       perror ("audio_windows_sink: Failed to write block to device");
300       switch (w_result)
301         {
302         case MMSYSERR_INVALHANDLE:
303           fprintf (stderr, "Specified device handle is invalid. \n");
304           break;
305         case MMSYSERR_NODRIVER:
306           fprintf (stderr, " No device driver is present.  \n");
307           break;
308         case MMSYSERR_NOMEM:
309           fprintf (stderr, " Unable to allocate or lock memory.  \n");
310           break;
311         case WAVERR_UNPREPARED:
312           fprintf (stderr,
313                    " The data block pointed to by the pwh parameter hasn't been prepared.  \n");
314           break;
315         default:
316           fprintf (stderr, "Unknown error %i\n", w_result);
317         }
318       waveOutUnprepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
319       return -1;
320     }
321   //   WaitForSingleObject(d_wave_write_event, INFINITE);
322   return 0;
323 }