summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau <trondeau@vt.edu>2013-02-13 12:14:20 -0500
committerTom Rondeau <trondeau@vt.edu>2013-02-13 12:14:20 -0500
commitc6040bbd5637593c402f9db2d7cfd30ad4781988 (patch)
tree1e787b6ef025df0ee79bda37fe101f14221729f6
parenta7b63511accf436029cdcbd5953f2d73d5daa81f (diff)
audio: wip: converting windows audio to v3.7 style (untested).
-rw-r--r--gr-audio/lib/windows/audio_windows_sink.cc323
-rw-r--r--gr-audio/lib/windows/audio_windows_source.cc205
-rw-r--r--gr-audio/lib/windows/windows_sink.cc314
-rw-r--r--gr-audio/lib/windows/windows_sink.h (renamed from gr-audio/lib/windows/audio_windows_sink.h)68
-rw-r--r--gr-audio/lib/windows/windows_source.cc194
-rw-r--r--gr-audio/lib/windows/windows_source.h (renamed from gr-audio/lib/windows/audio_windows_source.h)57
6 files changed, 573 insertions, 588 deletions
diff --git a/gr-audio/lib/windows/audio_windows_sink.cc b/gr-audio/lib/windows/audio_windows_sink.cc
deleted file mode 100644
index 5284ce1734..0000000000
--- a/gr-audio/lib/windows/audio_windows_sink.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-/* -*- c++ -*- */
-/*
-* Copyright 2004-2011 Free Software Foundation, Inc.
-*
-* This file is part of GNU Radio
-*
-* GNU Radio is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 3, or (at your option)
-* any later version.
-*
-* GNU Radio is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with GNU Radio; see the file COPYING. If not, write to
-* the Free Software Foundation, Inc., 51 Franklin Street,
-* Boston, MA 02110-1301, USA.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gr_audio_registry.h"
-#include <audio_windows_sink.h>
-#include <gr_io_signature.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <iostream>
-#include <stdexcept>
-#include <string>
-#include <sstream>
-
-AUDIO_REGISTER_SINK(REG_PRIO_HIGH, windows)(
- int sampling_rate, const std::string &device_name, bool
-){
- return audio_sink::sptr(new audio_windows_sink(sampling_rate, device_name));
-}
-
-static const double CHUNK_TIME = 0.1; //0.001; // 100 ms
-
-// FIXME these should query some kind of user preference
-
-static std::string
-default_device_name ()
-{
- return "WAVE_MAPPER";
-}
-
-audio_windows_sink::audio_windows_sink (int sampling_freq, const std::string device_name)
- : gr_sync_block ("audio_windows_sink",
- gr_make_io_signature (1, 2, sizeof (float)),
- gr_make_io_signature (0, 0, 0)),
- d_sampling_freq (sampling_freq),
- d_device_name (device_name.empty ()? default_device_name () : device_name),
- d_fd (-1), d_buffer (0), d_chunk_size (0)
-{
- d_wave_write_event = CreateEvent (NULL, FALSE, FALSE, NULL);
- if (open_waveout_device () < 0)
- {
- //fprintf (stderr, "audio_windows_sink:open_waveout_device() failed\n");
- perror ("audio_windows_sink:open_waveout_device( ) failed\n");
- throw
- std::runtime_error ("audio_windows_sink:open_waveout_device() failed");
- }
-
- d_chunk_size = (int) (d_sampling_freq * CHUNK_TIME);
- set_output_multiple (d_chunk_size);
-
- d_buffer = new short[d_chunk_size * 2];
-
-}
-
-audio_windows_sink::~audio_windows_sink ()
-{
- /* Free the callback Event */
- CloseHandle (d_wave_write_event);
- waveOutClose (d_h_waveout);
- delete[]d_buffer;
-}
-
-int
-audio_windows_sink::work (int noutput_items,
- gr_vector_const_void_star & input_items,
- gr_vector_void_star & output_items)
-{
- const float *f0, *f1;
- bool playtestsound = false;
- if (playtestsound)
- {
- // dummy
-
- f0 = (const float *) input_items[0];
-
- for (int i = 0; i < noutput_items; i += d_chunk_size)
- {
- for (int j = 0; j < d_chunk_size; j++)
- {
- d_buffer[2 * j + 0] = (short) (sin (2.0 * 3.1415926535897932384626 * (float) j * 1000.0 / (float) d_sampling_freq) * 8192 + 0); //+32767
- d_buffer[2 * j + 1] = d_buffer[2 * j + 0];
- }
- f0 += d_chunk_size;
- if (write_waveout
- ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
- {
- fprintf (stderr, "audio_windows_sink: write failed\n");
- perror ("audio_windows_sink: write failed");
- }
- }
- // break;
- }
- else
- {
- switch (input_items.size ())
- {
-
- case 1: // mono input
-
- f0 = (const float *) input_items[0];
-
- for (int i = 0; i < noutput_items; i += d_chunk_size)
- {
- for (int j = 0; j < d_chunk_size; j++)
- {
- d_buffer[2 * j + 0] = (short) (f0[j] * 32767);
- d_buffer[2 * j + 1] = (short) (f0[j] * 32767);
- }
- f0 += d_chunk_size;
- if (write_waveout
- ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
- {
- //fprintf (stderr, "audio_windows_sink: write failed\n");
- perror ("audio_windows_sink: write failed");
- }
- }
- break;
-
- case 2: // stereo input
-
- f0 = (const float *) input_items[0];
- f1 = (const float *) input_items[1];
-
- for (int i = 0; i < noutput_items; i += d_chunk_size)
- {
- for (int j = 0; j < d_chunk_size; j++)
- {
- d_buffer[2 * j + 0] = (short) (f0[j] * 32767);
- d_buffer[2 * j + 1] = (short) (f1[j] * 32767);
- }
- f0 += d_chunk_size;
- f1 += d_chunk_size;
- if (write_waveout
- ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0)
- {
- //fprintf (stderr, "audio_windows_sink: write failed\n");
- perror ("audio_windows_sink: write failed");
- }
- }
- break;
- }
- }
- return noutput_items;
-}
-
-int
-audio_windows_sink::string_to_int (const std::string & s)
-{
- int i;
- std::istringstream (s) >> i;
- return i;
-} //ToInt()
-
-int
-audio_windows_sink::open_waveout_device (void)
-{
-
- UINT /*UINT_PTR */ u_device_id;
- /** 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.
- *
- * Value Meaning
- * WAVE_MAPPER The function selects a waveform-audio output device capable of playing the given format.
- */
- if (d_device_name.empty () || default_device_name () == d_device_name)
- u_device_id = WAVE_MAPPER;
- else
- u_device_id = (UINT) string_to_int (d_device_name);
- // Open a waveform device for output using event callback.
-
- unsigned long result;
- //HWAVEOUT outHandle;
- WAVEFORMATEX wave_format;
-
- /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */
- wave_format.wFormatTag = WAVE_FORMAT_PCM;
- wave_format.nChannels = 2;
- wave_format.nSamplesPerSec = d_sampling_freq; //44100;
- wave_format.wBitsPerSample = 16;
- wave_format.nBlockAlign =
- wave_format.nChannels * (wave_format.wBitsPerSample / 8);
- wave_format.nAvgBytesPerSec =
- wave_format.nSamplesPerSec * wave_format.nBlockAlign;
- wave_format.cbSize = 0;
-
- /* Open the (preferred) Digital Audio Out device. */
- 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
- if (result)
- {
- fprintf (stderr,
- "audio_windows_sink: Failed to open waveform output device.\n");
- perror ("audio_windows_sink: Failed to open waveform output device.");
- //LocalUnlock(hFormat);
- //LocalFree(hFormat);
- //mmioClose(hmmio, 0);
- return -1;
- }
-
- //
- // Do not Swallow the "open" event.
- //
- //WaitForSingleObject(d_wave_write_event, INFINITE);
-
- // Allocate and lock memory for the header.
-
- d_h_wave_hdr = GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE,
- (DWORD) sizeof (WAVEHDR));
- if (d_h_wave_hdr == NULL)
- {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf (stderr, "audio_windows_sink: Not enough memory for header.\n");
- perror ("audio_windows_sink: Not enough memory for header.");
- return -1;
- }
-
- d_lp_wave_hdr = (LPWAVEHDR) GlobalLock (d_h_wave_hdr);
- if (d_lp_wave_hdr == NULL)
- {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf (stderr, "audio_windows_sink: Failed to lock memory for header.\n");
- perror ("audio_windows_sink: Failed to lock memory for header.");
- return -1;
- }
- //d_lp_wave_hdr->dwFlags = WHDR_DONE;
- return 0;
-}
-
-int
-audio_windows_sink::write_waveout (HPSTR lp_data, DWORD dw_data_size)
-{
- UINT w_result;
- int teller = 100;
- // After allocation, set up and prepare header.
- /*while ((d_lp_wave_hdr->dwFlags & WHDR_DONE)==0 && teller>0)
- {
- teller--;
- Sleep(1);
- } */
- // Wait until previous wave write completes (first event is the open event).
- WaitForSingleObject (d_wave_write_event, 100); //INFINITE
- d_lp_wave_hdr->lpData = lp_data;
- d_lp_wave_hdr->dwBufferLength = dw_data_size;
- d_lp_wave_hdr->dwFlags = 0L;
- /* Clear the WHDR_DONE bit (which the driver set last time that
- this WAVEHDR was sent via waveOutWrite and was played). Some
- drivers need this to be cleared */
- //d_lp_wave_hdr->dwFlags &= ~WHDR_DONE;
-
- d_lp_wave_hdr->dwLoops = 0L;
- w_result =
- waveOutPrepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
- if (w_result != 0)
- {
- //GlobalUnlock( hData);
- //GlobalFree(hData);
- //fprintf (stderr, "audio_windows_sink: Failed to waveOutPrepareHeader. error %i\n",w_result);
- perror ("audio_windows_sink: Failed to waveOutPrepareHeader");
- }
- // Now the data block can be sent to the output device. The
- // waveOutWrite function returns immediately and waveform
- // data is sent to the output device in the background.
- //while (! readyforplayback) Sleep(1);
- //readyforplayback=false;
- //
- //
-
- w_result = waveOutWrite (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
- if (w_result != 0)
- {
- //GlobalUnlock( hData);
- //GlobalFree(hData);
- //fprintf (stderr, "audio_windows_sink: Failed to write block to device.error %i\n",w_result);
- perror ("audio_windows_sink: Failed to write block to device");
- switch (w_result)
- {
- case MMSYSERR_INVALHANDLE:
- fprintf (stderr, "Specified device handle is invalid. \n");
- break;
- case MMSYSERR_NODRIVER:
- fprintf (stderr, " No device driver is present. \n");
- break;
- case MMSYSERR_NOMEM:
- fprintf (stderr, " Unable to allocate or lock memory. \n");
- break;
- case WAVERR_UNPREPARED:
- fprintf (stderr,
- " The data block pointed to by the pwh parameter hasn't been prepared. \n");
- break;
- default:
- fprintf (stderr, "Unknown error %i\n", w_result);
- }
- waveOutUnprepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR));
- return -1;
- }
- // WaitForSingleObject(d_wave_write_event, INFINITE);
- return 0;
-}
diff --git a/gr-audio/lib/windows/audio_windows_source.cc b/gr-audio/lib/windows/audio_windows_source.cc
deleted file mode 100644
index 75b0a33bbc..0000000000
--- a/gr-audio/lib/windows/audio_windows_source.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004-2011 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gr_audio_registry.h"
-#include <audio_windows_source.h>
-#include <gr_io_signature.h>
-//include <sys/soundcard.h>
-//include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <iostream>
-#include <stdexcept>
-
-AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, windows)(
- int sampling_rate, const std::string &device_name, bool
-){
- return audio_source::sptr(new audio_windows_source(sampling_rate, device_name));
-}
-
-static const double CHUNK_TIME = 0.005; // 5 ms
-
-// FIXME these should query some kind of user preference
-
-static std::string
-default_device_name ()
-{
- return "/dev/dsp";
-}
-
-audio_windows_source::audio_windows_source (int sampling_freq, const std::string device_name)
- : gr_sync_block ("audio_windows_source",
- gr_make_io_signature (0, 0, 0),
- gr_make_io_signature (1, 2, sizeof (float))),
- d_sampling_freq (sampling_freq),
- d_device_name (device_name.empty ()? default_device_name () : device_name),
- d_fd (-1), d_buffer (0), d_chunk_size (0)
-{
- //FIXME TODO implement me
-#if 0
- if ((d_fd = open (d_device_name.c_str (), O_RDONLY)) < 0)
- {
- fprintf (stderr, "audio_windows_source: ");
- perror (d_device_name.c_str ());
- throw
- std::runtime_error ("audio_windows_source");
- }
-
- d_chunk_size = (int) (d_sampling_freq * CHUNK_TIME);
- set_output_multiple (d_chunk_size);
-
- d_buffer = new short[d_chunk_size * 2];
-
- int format = AFMT_S16_NE;
- int orig_format = format;
- if (ioctl (d_fd, SNDCTL_DSP_SETFMT, &format) < 0)
- {
- std::
- cerr << "audio_windows_source: " << d_device_name <<
- " ioctl failed\n";
- perror (d_device_name.c_str ());
- throw
- std::runtime_error ("audio_windows_source");
- }
-
- if (format != orig_format)
- {
- fprintf (stderr, "audio_windows_source: unable to support format %d\n",
- orig_format);
- fprintf (stderr, " card requested %d instead.\n", format);
- }
-
- // set to stereo no matter what. Some hardware only does stereo
- int channels = 2;
- if (ioctl (d_fd, SNDCTL_DSP_CHANNELS, &channels) < 0 || channels != 2)
- {
- perror ("audio_windows_source: could not set STEREO mode");
- throw
- std::runtime_error ("audio_windows_source");
- }
-
- // set sampling freq
- int sf = sampling_freq;
- if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0)
- {
- std::cerr << "audio_windows_source: "
- << d_device_name << ": invalid sampling_freq "
- << sampling_freq << "\n";
- sampling_freq = 8000;
- if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0)
- {
- std::
- cerr <<
- "audio_windows_source: failed to set sampling_freq to 8000\n";
- throw
- std::runtime_error ("audio_windows_source");
- }
- }
-#endif
-}
-
-audio_windows_source::~audio_windows_source ()
-{
- /*close (d_fd);
- delete [] d_buffer;
- */
-}
-
-int
-audio_windows_source::work (int noutput_items,
- gr_vector_const_void_star & input_items,
- gr_vector_void_star & output_items)
-{
- //FIXME TODO implement me
-#if 0
- float *f0 = (float *) output_items[0];
- float *f1 = (float *) output_items[1]; // will be invalid if this is mono output
-
- const int shorts_per_item = 2; // L + R
- const int bytes_per_item = shorts_per_item * sizeof (short);
-
- // To minimize latency, never return more than CHUNK_TIME
- // worth of samples per call to work.
- // FIXME, we need an API to set this value
-
- noutput_items = std::min (noutput_items, d_chunk_size);
-
- int base = 0;
- int ntogo = noutput_items;
-
- while (ntogo > 0)
- {
- int nbytes = std::min (ntogo, d_chunk_size) * bytes_per_item;
- int result_nbytes = read (d_fd, d_buffer, nbytes);
-
- if (result_nbytes < 0)
- {
- perror ("audio_windows_source");
- return -1; // say we're done
- }
-
- if ((result_nbytes & (bytes_per_item - 1)) != 0)
- {
- fprintf (stderr, "audio_windows_source: internal error.\n");
- throw std::runtime_error ("internal error");
- }
-
- int result_nitems = result_nbytes / bytes_per_item;
-
- // now unpack samples into output streams
-
- switch (output_items.size ())
- {
- case 1: // mono output
- for (int i = 0; i < result_nitems; i++)
- {
- f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767);
- }
- break;
-
- case 2: // stereo output
- for (int i = 0; i < result_nitems; i++)
- {
- f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767);
- f1[base + i] = d_buffer[2 * i + 1] * (1.0 / 32767);
- }
- break;
-
- default:
- assert (0);
- }
-
- ntogo -= result_nitems;
- base += result_nitems;
- }
-
- return noutput_items - ntogo;
-#endif
- return -1; // EOF
-}
diff --git a/gr-audio/lib/windows/windows_sink.cc b/gr-audio/lib/windows/windows_sink.cc
new file mode 100644
index 0000000000..f372bd0e75
--- /dev/null
+++ b/gr-audio/lib/windows/windows_sink.cc
@@ -0,0 +1,314 @@
+/* -*- c++ -*- */
+/*
+* Copyright 2004-2011,2013 Free Software Foundation, Inc.
+*
+* This file is part of GNU Radio
+*
+* GNU Radio is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 3, or (at your option)
+* any later version.
+*
+* GNU Radio is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GNU Radio; see the file COPYING. If not, write to
+* the Free Software Foundation, Inc., 51 Franklin Street,
+* Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "audio_registry.h"
+#include <windows_sink.h>
+#include <gr_io_signature.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <sstream>
+
+namespace gr {
+ namespace audio {
+
+ AUDIO_REGISTER_SINK(REG_PRIO_HIGH, windows)(int sampling_rate,
+ const std::string &device_name,
+ bool)
+ {
+ return sink::sptr
+ (new windows_sink(sampling_rate, device_name));
+ }
+
+ static const double CHUNK_TIME = 0.1; //0.001; // 100 ms
+
+ // FIXME these should query some kind of user preference
+
+ static std::string
+ default_device_name()
+ {
+ return "WAVE_MAPPER";
+ }
+
+ windows_sink::windows_sink(int sampling_freq, const std::string device_name)
+ : gr_sync_block("audio_windows_sink",
+ gr_make_io_signature(1, 2, sizeof(float)),
+ gr_make_io_signature(0, 0, 0)),
+ d_sampling_freq(sampling_freq),
+ d_device_name(device_name.empty() ? default_device_name() : device_name),
+ d_fd(-1), d_buffer(0), d_chunk_size(0)
+ {
+ d_wave_write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(open_waveout_device() < 0) {
+ //fprintf(stderr, "audio_windows_sink:open_waveout_device() failed\n");
+ perror("audio_windows_sink:open_waveout_device() failed\n");
+ throw
+ std::runtime_error ("audio_windows_sink:open_waveout_device() failed");
+ }
+
+ d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME);
+ set_output_multiple(d_chunk_size);
+
+ d_buffer = new short[d_chunk_size * 2];
+ }
+
+ windows_sink::~windows_sink()
+ {
+ /* Free the callback Event */
+ CloseHandle(d_wave_write_event);
+ waveOutClose(d_h_waveout);
+ delete [] d_buffer;
+ }
+
+ int
+ windows_sink::work(int noutput_items,
+ gr_vector_const_void_star & input_items,
+ gr_vector_void_star & output_items)
+ {
+ const float *f0, *f1;
+ bool playtestsound = false;
+ if(playtestsound) {
+ // dummy
+ f0 = (const float*)input_items[0];
+
+ for(int i = 0; i < noutput_items; i += d_chunk_size) {
+ for(int j = 0; j < d_chunk_size; j++) {
+ d_buffer[2*j + 0] = (short)(sin(2.0 * 3.1415926535897932384626 *
+ (float)j * 1000.0 / (float)d_sampling_freq) *
+ 8192 + 0); //+32767
+ d_buffer[2*j + 1] = d_buffer[2*j + 0];
+ }
+ f0 += d_chunk_size;
+ if(write_waveout
+ ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
+ fprintf(stderr, "audio_windows_sink: write failed\n");
+ perror("audio_windows_sink: write failed");
+ }
+ }
+ // break;
+ }
+ else {
+ switch(input_items.size ()) {
+ case 1: // mono input
+ f0 = (const float*)input_items[0];
+
+ for(int i = 0; i < noutput_items; i += d_chunk_size) {
+ for(int j = 0; j < d_chunk_size; j++) {
+ d_buffer[2*j + 0] = (short)(f0[j] * 32767);
+ d_buffer[2*j + 1] = (short)(f0[j] * 32767);
+ }
+ f0 += d_chunk_size;
+ if(write_waveout
+ ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
+ //fprintf(stderr, "audio_windows_sink: write failed\n");
+ perror("audio_windows_sink: write failed");
+ }
+ }
+ break;
+
+ case 2: // stereo input
+ f0 = (const float*)input_items[0];
+ f1 = (const float*)input_items[1];
+
+ for(int i = 0; i < noutput_items; i += d_chunk_size) {
+ for(int j = 0; j < d_chunk_size; j++) {
+ d_buffer[2*j + 0] = (short)(f0[j] * 32767);
+ d_buffer[2*j + 1] = (short)(f1[j] * 32767);
+ }
+ f0 += d_chunk_size;
+ f1 += d_chunk_size;
+ if(write_waveout
+ ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
+ //fprintf(stderr, "audio_windows_sink: write failed\n");
+ perror("audio_windows_sink: write failed");
+ }
+ }
+ break;
+ }
+ }
+ return noutput_items;
+ }
+
+ int
+ windows_sink::string_to_int(const std::string & s)
+ {
+ int i;
+ std::istringstream (s) >> i;
+ return i;
+ } //ToInt()
+
+ int
+ windows_sink::open_waveout_device(void)
+ {
+ UINT /*UINT_PTR */ u_device_id;
+
+ /** 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.
+ *
+ * Value Meaning
+ * WAVE_MAPPER The function selects a waveform-audio output
+ * device capable of playing the given format.
+ */
+ if(d_device_name.empty () || default_device_name () == d_device_name)
+ u_device_id = WAVE_MAPPER;
+ else
+ u_device_id = (UINT) string_to_int (d_device_name);
+ // Open a waveform device for output using event callback.
+
+ unsigned long result;
+ //HWAVEOUT outHandle;
+ WAVEFORMATEX wave_format;
+
+ /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */
+ wave_format.wFormatTag = WAVE_FORMAT_PCM;
+ wave_format.nChannels = 2;
+ wave_format.nSamplesPerSec = d_sampling_freq; //44100;
+ wave_format.wBitsPerSample = 16;
+ wave_format.nBlockAlign =
+ wave_format.nChannels * (wave_format.wBitsPerSample / 8);
+ wave_format.nAvgBytesPerSec =
+ wave_format.nSamplesPerSec * wave_format.nBlockAlign;
+ wave_format.cbSize = 0;
+
+ /* Open the (preferred) Digital Audio Out device. */
+ 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
+
+ if(result) {
+ //fprintf(stderr, "audio_windows_sink: Failed to open waveform output device.\n");
+ perror("audio_windows_sink: Failed to open waveform output device.");
+ //LocalUnlock(hFormat);
+ //LocalFree(hFormat);
+ //mmioClose(hmmio, 0);
+ return -1;
+ }
+
+ //
+ // Do not Swallow the "open" event.
+ //
+ //WaitForSingleObject(d_wave_write_event, INFINITE);
+
+ // Allocate and lock memory for the header.
+
+ d_h_wave_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
+ (DWORD)sizeof(WAVEHDR));
+ if(d_h_wave_hdr == NULL) {
+ //GlobalUnlock(hData);
+ //GlobalFree(hData);
+ //fprintf(stderr, "audio_windows_sink: Not enough memory for header.\n");
+ perror("audio_windows_sink: Not enough memory for header.");
+ return -1;
+ }
+
+ d_lp_wave_hdr = (LPWAVEHDR)GlobalLock(d_h_wave_hdr);
+ if(d_lp_wave_hdr == NULL) {
+ //GlobalUnlock(hData);
+ //GlobalFree(hData);
+ //fprintf(stderr, "audio_windows_sink: Failed to lock memory for header.\n");
+ perror("audio_windows_sink: Failed to lock memory for header.");
+ return -1;
+ }
+ //d_lp_wave_hdr->dwFlags = WHDR_DONE;
+ return 0;
+ }
+
+ int
+ windows_sink::write_waveout(HPSTR lp_data, DWORD dw_data_size)
+ {
+ UINT w_result;
+ int teller = 100;
+ // After allocation, set up and prepare header.
+ /*while ((d_lp_wave_hdr->dwFlags & WHDR_DONE)==0 && teller>0) {
+ teller--;
+ Sleep(1);
+ } */
+ // Wait until previous wave write completes (first event is the open event).
+ WaitForSingleObject(d_wave_write_event, 100); // INFINITE
+ d_lp_wave_hdr->lpData = lp_data;
+ d_lp_wave_hdr->dwBufferLength = dw_data_size;
+ d_lp_wave_hdr->dwFlags = 0L;
+ /* Clear the WHDR_DONE bit (which the driver set last time that
+ this WAVEHDR was sent via waveOutWrite and was played). Some
+ drivers need this to be cleared */
+ //d_lp_wave_hdr->dwFlags &= ~WHDR_DONE;
+
+ d_lp_wave_hdr->dwLoops = 0L;
+ w_result =
+ waveOutPrepareHeader(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
+ if(w_result != 0) {
+ //GlobalUnlock(hData);
+ //GlobalFree(hData);
+ //fprintf(stderr, "audio_windows_sink: Failed to waveOutPrepareHeader. error %i\n",w_result);
+ perror("audio_windows_sink: Failed to waveOutPrepareHeader");
+ }
+ // Now the data block can be sent to the output device. The
+ // waveOutWrite function returns immediately and waveform
+ // data is sent to the output device in the background.
+ //while(!readyforplayback) Sleep(1);
+ //readyforplayback=false;
+
+ w_result = waveOutWrite(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
+ if(w_result != 0) {
+ //GlobalUnlock(hData);
+ //GlobalFree(hData);
+ //fprintf(stderr, "audio_windows_sink: Failed to write block to device.error %i\n",w_result);
+ perror("audio_windows_sink: Failed to write block to device");
+ switch(w_result) {
+ case MMSYSERR_INVALHANDLE:
+ fprintf(stderr, "Specified device handle is invalid.\n");
+ break;
+ case MMSYSERR_NODRIVER:
+ fprintf(stderr, " No device driver is present.\n");
+ break;
+ case MMSYSERR_NOMEM:
+ fprintf(stderr, " Unable to allocate or lock memory.\n");
+ break;
+ case WAVERR_UNPREPARED:
+ fprintf(stderr,
+ " The data block pointed to by the pwh parameter hasn't been prepared.\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown error %i\n", w_result);
+ }
+ waveOutUnprepareHeader(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
+ return -1;
+ }
+ //WaitForSingleObject(d_wave_write_event, INFINITE);
+ return 0;
+ }
+
+ } /* namespace audio */
+} /* namespace gr */
diff --git a/gr-audio/lib/windows/audio_windows_sink.h b/gr-audio/lib/windows/windows_sink.h
index 1628ee73a0..2a33af3532 100644
--- a/gr-audio/lib/windows/audio_windows_sink.h
+++ b/gr-audio/lib/windows/windows_sink.h
@@ -32,42 +32,44 @@
#include <audio/sink.h>
#include <string>
-/*!
- * \brief audio sink using winmm mmsystem (win32 only)
- * \ingroup audio_blk
- *
- * input signature is one or two streams of floats.
- * Input samples must be in the range [-1,1].
- */
+namespace gr {
+ namespace audio {
+
+ /*!
+ * \brief audio sink using winmm mmsystem (win32 only)
+ * \ingroup audio_blk
+ *
+ * input signature is one or two streams of floats.
+ * Input samples must be in the range [-1,1].
+ */
+ class windows_sink : public audio_sink
+ {
+ int d_sampling_freq;
+ std::string d_device_name;
+ int d_fd;
+ short *d_buffer;
+ int d_chunk_size;
+ HWAVEOUT d_h_waveout;
+ HGLOBAL d_h_wave_hdr;
+ LPWAVEHDR d_lp_wave_hdr;
+ HANDLE d_wave_write_event;
-class audio_windows_sink : public audio_sink
-{
- int d_sampling_freq;
- std::string d_device_name;
- int d_fd;
- short *d_buffer;
- int d_chunk_size;
- HWAVEOUT d_h_waveout;
- HGLOBAL d_h_wave_hdr;
- LPWAVEHDR d_lp_wave_hdr;
- HANDLE d_wave_write_event;
+ protected:
+ int string_to_int(const std::string & s);
+ int open_waveout_device(void);
+ int write_waveout(HPSTR lp_data, DWORD dw_data_size);
-protected:
- int
- string_to_int (const std::string & s);
- int
- open_waveout_device (void);
- int
- write_waveout (HPSTR lp_data, DWORD dw_data_size);
+ public:
+ windows_sink(int sampling_freq,
+ const std::string device_name = "");
+ ~windows_sink();
-public:
- audio_windows_sink (int sampling_freq, const std::string device_name = "");
- ~audio_windows_sink ();
+ int work(int noutput_items,
+ gr_vector_const_void_star & input_items,
+ gr_vector_void_star & output_items);
+ };
- int
- work (int noutput_items,
- gr_vector_const_void_star & input_items,
- gr_vector_void_star & output_items);
-};
+ } /* namespace audio */
+} /* namespace gr */
#endif /* INCLUDED_AUDIO_WINDOWS_SINK_H */
diff --git a/gr-audio/lib/windows/windows_source.cc b/gr-audio/lib/windows/windows_source.cc
new file mode 100644
index 0000000000..89371cfa84
--- /dev/null
+++ b/gr-audio/lib/windows/windows_source.cc
@@ -0,0 +1,194 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004-2011,2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "audio_registry.h"
+#include <windows_source.h>
+#include <gr_io_signature.h>
+//include <sys/soundcard.h>
+//include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
+#include <stdexcept>
+
+namespace gr {
+ namespace audio {
+
+ AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, windows)(int sampling_rate,
+ const std::string &device_name,
+ bool)
+ {
+ return source::sptr
+ (new windows_source(sampling_rate, device_name));
+ }
+
+ static const double CHUNK_TIME = 0.005; // 5 ms
+
+ // FIXME these should query some kind of user preference
+
+ static std::string
+ default_device_name()
+ {
+ return "/dev/dsp";
+ }
+
+ windows_source::windows_source(int sampling_freq,
+ const std::string device_name)
+ : gr_sync_block("audio_windows_source",
+ gr_make_io_signature(0, 0, 0),
+ gr_make_io_signature(1, 2, sizeof(float))),
+ d_sampling_freq(sampling_freq),
+ d_device_name(device_name.empty() ? default_device_name() : device_name),
+ d_fd(-1), d_buffer(0), d_chunk_size(0)
+ {
+ //FIXME TODO implement me
+#if 0
+ if((d_fd = open(d_device_name.c_str(), O_RDONLY)) < 0) {
+ fprintf(stderr, "audio_windows_source: ");
+ perror(d_device_name.c_str());
+ throw std::runtime_error("audio_windows_source");
+ }
+
+ d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME);
+ set_output_multiple(d_chunk_size);
+
+ d_buffer = new short[d_chunk_size * 2];
+
+ int format = AFMT_S16_NE;
+ int orig_format = format;
+ if(ioctl(d_fd, SNDCTL_DSP_SETFMT, &format) < 0) {
+ std::cerr << "audio_windows_source: " << d_device_name
+ << " ioctl failed\n";
+ perror(d_device_name.c_str());
+ throw std::runtime_error("audio_windows_source");
+ }
+
+ if(format != orig_format) {
+ fprintf(stderr, "audio_windows_source: unable to support format %d\n",
+ orig_format);
+ fprintf(stderr, " card requested %d instead.\n", format);
+ }
+
+ // set to stereo no matter what. Some hardware only does stereo
+ int channels = 2;
+ if(ioctl(d_fd, SNDCTL_DSP_CHANNELS, &channels) < 0 || channels != 2) {
+ perror("audio_windows_source: could not set STEREO mode");
+ throw std::runtime_error("audio_windows_source");
+ }
+
+ // set sampling freq
+ int sf = sampling_freq;
+ if(ioctl(d_fd, SNDCTL_DSP_SPEED, &sf) < 0) {
+ std::cerr << "audio_windows_source: "
+ << d_device_name << ": invalid sampling_freq "
+ << sampling_freq << "\n";
+ sampling_freq = 8000;
+ if(ioctl(d_fd, SNDCTL_DSP_SPEED, &sf) < 0) {
+ std::cerr << "audio_windows_source: failed to set sampling_freq to 8000\n";
+ throw std::runtime_error ("audio_windows_source");
+ }
+ }
+#endif
+ }
+
+ windows_source::~windows_source()
+ {
+ /*close(d_fd);
+ delete [] d_buffer;
+ */
+ }
+
+ int
+ windows_source::work(int noutput_items,
+ gr_vector_const_void_star & input_items,
+ gr_vector_void_star & output_items)
+ {
+ //FIXME TODO implement me
+#if 0
+ float *f0 = (float*)output_items[0];
+ float *f1 = (float*)output_items[1]; // will be invalid if this is mono output
+
+ const int shorts_per_item = 2; // L + R
+ const int bytes_per_item = shorts_per_item * sizeof(short);
+
+ // To minimize latency, never return more than CHUNK_TIME
+ // worth of samples per call to work.
+ // FIXME, we need an API to set this value
+
+ noutput_items = std::min(noutput_items, d_chunk_size);
+
+ int base = 0;
+ int ntogo = noutput_items;
+
+ while(ntogo > 0) {
+ int nbytes = std::min(ntogo, d_chunk_size) * bytes_per_item;
+ int result_nbytes = read(d_fd, d_buffer, nbytes);
+
+ if(result_nbytes < 0) {
+ perror("audio_windows_source");
+ return -1; // say we're done
+ }
+
+ if((result_nbytes & (bytes_per_item - 1)) != 0) {
+ fprintf(stderr, "audio_windows_source: internal error.\n");
+ throw std::runtime_error("internal error");
+ }
+
+ int result_nitems = result_nbytes / bytes_per_item;
+
+ // now unpack samples into output streams
+ switch(output_items.size()) {
+ case 1: // mono output
+ for(int i = 0; i < result_nitems; i++) {
+ f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767);
+ }
+ break;
+
+ case 2: // stereo output
+ for(int i = 0; i < result_nitems; i++) {
+ f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767);
+ f1[base + i] = d_buffer[2 * i + 1] * (1.0 / 32767);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ ntogo -= result_nitems;
+ base += result_nitems;
+ }
+
+ return noutput_items - ntogo;
+#endif
+ return -1; // EOF
+ }
+
+ } /* namespace audio */
+} /* namespace gr */
diff --git a/gr-audio/lib/windows/audio_windows_source.h b/gr-audio/lib/windows/windows_source.h
index acf6971c07..473d8eb94d 100644
--- a/gr-audio/lib/windows/audio_windows_source.h
+++ b/gr-audio/lib/windows/windows_source.h
@@ -26,32 +26,35 @@
#include <audio/source.h>
#include <string>
-/*!
- * \brief audio source using winmm mmsystem (win32 only)
- * \ingroup audio_blk
- *
- * Output signature is one or two streams of floats.
- * Output samples will be in the range [-1,1].
- */
-
-class audio_windows_source : public audio_source
-{
-
- int d_sampling_freq;
- std::string d_device_name;
- int d_fd;
- short *d_buffer;
- int d_chunk_size;
-
-public:
- audio_windows_source (int sampling_freq, const std::string device_name = "");
-
- ~audio_windows_source ();
-
- int
- work (int noutput_items,
- gr_vector_const_void_star & input_items,
- gr_vector_void_star & output_items);
-};
+namespace gr {
+ namespace audio {
+
+ /*!
+ * \brief audio source using winmm mmsystem (win32 only)
+ * \ingroup audio_blk
+ *
+ * Output signature is one or two streams of floats.
+ * Output samples will be in the range [-1,1].
+ */
+ class windows_source : public audio_source
+ {
+ int d_sampling_freq;
+ std::string d_device_name;
+ int d_fd;
+ short *d_buffer;
+ int d_chunk_size;
+
+ public:
+ windows_source(int sampling_freq,
+ const std::string device_name = "");
+ ~windows_source();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star & input_items,
+ gr_vector_void_star & output_items);
+ };
+
+ } /* namespace audio */
+} /* namespace gr */
#endif /* INCLUDED_AUDIO_WINDOWS_SOURCE_H */