ref: 6e79c8982f988d5caa0984d438e979078389f868
parent: e588f34341a53e9a3cd1f319050a02eaeb99b663
author: cbagwell <cbagwell>
date: Tue Aug 25 23:27:26 EDT 2009
Initial commit of native windows audio output driver.
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,7 +5,7 @@
sox-11gamma, followed by a list of prior authors and features.
-sox-14.0.1 2009-xx-xx
+sox-14.3.1 2009-xx-xx
----------
Previously deprecated features that have been removed in this release:
@@ -36,6 +36,8 @@
File formats:
Audio device drivers:
+
+ o Add native windows audio output driver. (Pavel Karneliuk)
Effects:
--- a/configure.ac
+++ b/configure.ac
@@ -428,7 +428,9 @@
AC_OPTIONAL_FORMAT(pulseaudio, PULSEAUDIO, [AC_CHECK_HEADER(pulse/simple.h, [AC_CHECK_LIB(pulse, pa_simple_new, PULSEAUDIO_LIBS="$PULSEAUDIO_LIBS -lpulse -lpulse-simple",using_pulseaudio=no,"-lpulse-simple")], using_pulseaudio=no)])
+AC_OPTIONAL_FORMAT(waveaudio, WAVEAUDIO, [AC_CHECK_HEADER(mmsystem.h, [WAVEAUDIO_LIBS="$WAVEAUDIO_LIBS -lwinmm"], using_waveaudio=no)])
+
AC_OPTIONAL_FORMAT(sndfile, SNDFILE, [SOX_PATH_SNDFILE(, using_sndfile=no)])
AC_SUBST(SNDFILE_CFLAGS)
@@ -543,6 +545,7 @@
echo "oss........................$using_oss"
echo "pulseaudio.................$using_pulseaudio"
echo "sunaudio...................$using_sunaudio"
+echo "waveaudio..................$using_waveaudio"
echo
echo "OPTIONAL FILE FORMATS"
echo "amrnb......................$using_amrnb"
--- a/src/formats.h
+++ b/src/formats.h
@@ -99,6 +99,9 @@
#if defined HAVE_PULSEAUDIO && (defined STATIC_PULSEAUDIO || !defined HAVE_LIBLTDL)
FORMAT(pulseaudio)
#endif
+#if defined HAVE_WAVEAUDIO && (defined STATIC_WAVEAUDIO || !defined HAVE_LIBLTDL)
+ FORMAT(waveaudio)
+#endif
#if defined HAVE_SNDIO && (defined STATIC_SNDIO || !defined HAVE_LIBLTDL)
FORMAT(sndio)
#endif
--- a/src/optional-fmts.am
+++ b/src/optional-fmts.am
@@ -144,6 +144,18 @@
endif
endif
+if HAVE_WAVEAUDIO
+if STATIC_WAVEAUDIO
+ libsox_la_SOURCES += waveaudio.c
+ libsox_la_LIBADD += @WAVEAUDIO_LIBS@
+ sox_LDADD += @WAVEAUDIO_LIBS@
+else
+ libsox_fmt_waveaudio_la_SOURCES = waveaudio.c
+ libsox_fmt_waveaudio_la_LIBADD = libsox.la @WAVEAUDIO_LIBS@
+ pkglib_LTLIBRARIES += libsox_fmt_waveaudio.la
+endif
+endif
+
if HAVE_SNDIO
if STATIC_SNDIO
libsox_la_SOURCES += sndio.c
--- a/src/optional-fmts.in
+++ b/src/optional-fmts.in
@@ -24,6 +24,7 @@
OPT_FORMAT(mp3, MP3, mp3.c mp3-duration.h)
OPT_FORMAT(oss, OSS, oss.c)
OPT_FORMAT(pulseaudio, PULSEAUDIO, pulseaudio.c)
+OPT_FORMAT(waveaudio, WAVEAUDIO, waveaudio.c)
OPT_FORMAT(sndio, SNDIO, sndio.c)
OPT_FORMAT(sunau, SUN_AUDIO, sunaudio.c)
OPT_FORMAT(vorbis, OGG_VORBIS, vorbis.c vorbis1.h)
--- /dev/null
+++ b/src/waveaudio.c
@@ -1,0 +1,200 @@
+/* libSoX (c) 2009 SoX contributors
+ * Copyright (c) 2009 Pavel Karneliuk pavel_karneliuk@users.sourceforge.net
+ * Implementation of audio output driver for Windows
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sox_i.h"
+#ifdef HAVE_WAVEAUDIO
+
+#include <assert.h>
+#include <windows.h>
+#include <mmsystem.h>
+
+#define num_buffers 16
+typedef struct {
+ HWAVEOUT waveout;
+ WAVEFORMATEX format;
+
+ HGLOBAL handle_data;
+ HGLOBAL handle_wavheader;
+
+ HPSTR ptr_data[num_buffers];
+ WAVEHDR* ptr_wavheader;
+
+ HANDLE need_more_data_blocks;
+} priv_t;
+
+void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR instance, DWORD_PTR Param1, DWORD_PTR Param2);
+
+int setup_write(sox_format_t* ft)
+{
+ DWORD buf_len;
+ int i;
+ priv_t *priv = (priv_t *)ft->priv;
+ if(priv == NULL) return SOX_EOF;
+
+ ft->signal.precision = 16;
+
+ priv->format.wFormatTag = WAVE_FORMAT_PCM;
+ priv->format.nChannels = ft->signal.channels;
+ priv->format.nSamplesPerSec = ft->signal.rate;
+ priv->format.wBitsPerSample = sizeof(int16_t)*8;
+ priv->format.nAvgBytesPerSec = priv->format.nSamplesPerSec * priv->format.wBitsPerSample/8;
+ priv->format.nBlockAlign = (priv->format.nChannels*priv->format.wBitsPerSample)/8;
+ priv->format.cbSize = 0;
+
+ buf_len = sox_globals.bufsiz * sizeof(int16_t);
+
+ priv->handle_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, buf_len * num_buffers);
+ priv->ptr_data[0] = (HPSTR) GlobalLock(priv->handle_data);
+ priv->handle_wavheader = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)sizeof(WAVEHDR) * num_buffers);
+ priv->ptr_wavheader = (WAVEHDR*) GlobalLock(priv->handle_wavheader);
+ memset(priv->ptr_wavheader, 0, sizeof(WAVEHDR) * num_buffers);
+ for(i=0; i<num_buffers; i++)
+ {
+ priv->ptr_data[i] = priv->ptr_data[0] + buf_len*i;
+
+ priv->ptr_wavheader[i].lpData = priv->ptr_data[i];
+ priv->ptr_wavheader[i].dwBufferLength = buf_len;
+ priv->ptr_wavheader[i].dwFlags = 0L;
+ priv->ptr_wavheader[i].dwLoops = 0L;
+ }
+
+ priv->waveout = NULL;
+
+ waveOutOpen((LPHWAVEOUT)&priv->waveout, WAVE_MAPPER, &priv->format,
+ (DWORD_PTR)waveOutProc, (DWORD_PTR)priv, CALLBACK_FUNCTION);
+
+ priv->need_more_data_blocks = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+ return priv->waveout ? SOX_SUCCESS : SOX_EOF;
+}
+
+int stop_write(sox_format_t* ft)
+{
+ priv_t *priv = (priv_t *)ft->priv;
+ if(priv == NULL) return SOX_EOF;
+
+ while(WAVERR_STILLPLAYING == waveOutClose(priv->waveout))
+ {
+/* // terminate
+ if( priv->is_cancelled() )
+ {
+ waveOutReset(priv->waveout);
+ }
+ else priv->update_pos();*/
+ Sleep(50);
+ }
+
+ CloseHandle(priv->need_more_data_blocks);
+
+ GlobalUnlock(priv->handle_wavheader);
+ GlobalFree(priv->handle_wavheader);
+
+ GlobalUnlock(priv->handle_data);
+ GlobalFree(priv->handle_data);
+
+ return SOX_SUCCESS;
+}
+
+static size_t write(sox_format_t * ft, const sox_sample_t* buf, size_t len)
+{
+ int i;
+ int clips = 0;
+ size_t j;
+ WAVEHDR* header = NULL;
+ MMRESULT res = 0;
+ priv_t *priv = (priv_t *)ft->priv;
+ if(priv == NULL) return SOX_EOF;
+
+ while(header == NULL)
+ {
+ // find first free header
+ for(i=0; i<num_buffers; i++)
+ {
+ if(priv->ptr_wavheader[i].dwFlags == 0 || priv->ptr_wavheader[i].dwFlags & WHDR_DONE )
+ {
+ header = &priv->ptr_wavheader[i];
+ break;
+ }
+ }
+
+ if(header == NULL) // not found free data blocks
+ {
+ while(WAIT_TIMEOUT == WaitForSingleObject(priv->need_more_data_blocks, 50))
+ {
+/* if(task->is_cancelled())
+ {
+ waveOutReset(task->waveout);
+ *osamp = 0;
+ return SOX_SUCCESS;
+ }
+ else priv->update_pos();*/
+ }
+ ResetEvent(priv->need_more_data_blocks);
+ }
+ }
+
+ /* put ibuf into data block for playback */
+ if(header)
+ {
+ res = waveOutUnprepareHeader(priv->waveout, header, sizeof(WAVEHDR));
+ assert(MMSYSERR_NOERROR == res);
+
+ for(j=0; j< len; ++j)
+ {
+ SOX_SAMPLE_LOCALS;
+ ((int16_t *)header->lpData)[j] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[j],clips);
+ }
+
+ header->dwBufferLength = len * sizeof(int16_t);
+ header->dwFlags = 0;
+
+ res = waveOutPrepareHeader(priv->waveout, header, sizeof(WAVEHDR));
+ assert(MMSYSERR_NOERROR == res);
+
+ waveOutWrite(priv->waveout, header, sizeof(WAVEHDR));
+ assert(MMSYSERR_NOERROR == res);
+ }
+
+ return len;
+}
+
+void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR instance, DWORD_PTR Param1, DWORD_PTR Param2)
+{
+ priv_t* priv = (priv_t*) instance;
+ /* unlock Sox pipeline if some data block has been processed*/
+ if( uMsg == WOM_DONE )
+ {
+ SetEvent(priv->need_more_data_blocks);
+ }
+}
+
+LSX_FORMAT_HANDLER(waveaudio)
+{
+ static const char * const names[] = {"waveaudio", NULL};
+ static unsigned const write_encodings[] = { SOX_ENCODING_UNKNOWN, 16, 0, 0};
+ static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
+ "Windows Multimedia Audio Output", names,
+ SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
+ NULL, NULL, NULL,
+ setup_write, write, stop_write,
+ NULL, write_encodings, NULL, sizeof(priv_t)
+ };
+ return &handler;
+}
+#endif