aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Output/waveout/outputwaveout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/Output/waveout/outputwaveout.cpp')
-rw-r--r--src/plugins/Output/waveout/outputwaveout.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/plugins/Output/waveout/outputwaveout.cpp b/src/plugins/Output/waveout/outputwaveout.cpp
new file mode 100644
index 000000000..f97e267f8
--- /dev/null
+++ b/src/plugins/Output/waveout/outputwaveout.cpp
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * Copyright (C) 2006-2008 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * This program 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+
+#include <QObject>
+#include <QApplication>
+#include <QtGlobal>
+
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+
+#include <qmmp/constants.h>
+#include <qmmp/buffer.h>
+#include <qmmp/visual.h>
+#include "outputwaveout.h"
+
+#define MAX_WAVEBLOCKS 32
+
+static CRITICAL_SECTION cs;
+static HWAVEOUT dev = NULL;
+static int ScheduledBlocks = 0;
+static int PlayedWaveHeadersCount = 0; // free index
+static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS];
+
+
+
+static void CALLBACK wave_callback (HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{
+ if ( uMsg == WOM_DONE )
+ {
+ EnterCriticalSection (&cs);
+ PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
+ LeaveCriticalSection (&cs);
+ }
+}
+
+static void
+free_memory ( void )
+{
+ WAVEHDR* wh;
+ HGLOBAL hg;
+
+ EnterCriticalSection ( &cs );
+ wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
+ ScheduledBlocks--; // decrease the number of USED blocks
+ LeaveCriticalSection ( &cs );
+
+ waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
+
+ hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory
+ GlobalUnlock (hg);
+ GlobalFree (hg);
+
+ hg = GlobalHandle ( wh ); // Deallocate the header memory
+ GlobalUnlock (hg);
+ GlobalFree (hg);
+}
+
+static int
+Box ( const char* msg )
+{
+ //MessageBox ( NULL, ms"Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
+ return -1;
+}
+
+
+
+OutputWaveOut::OutputWaveOut(QObject * parent)
+ : Output(parent)
+{
+ //m_connection = 0;
+ //m_dev = 0;
+}
+
+OutputWaveOut::~OutputWaveOut()
+{
+ uninitialize();
+}
+
+void OutputWaveOut::configure(quint32 freq, int chan, int prec)
+{
+ WAVEFORMATEX fmt;
+ UINT deviceID = WAVE_MAPPER;
+
+ fmt.wFormatTag = WAVE_FORMAT_PCM;
+ fmt.wBitsPerSample = prec;
+ fmt.nChannels = chan;
+ fmt.nSamplesPerSec = (unsigned long)(freq);
+ fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample/8;
+ fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nChannels * fmt.wBitsPerSample/8;
+
+ switch (waveOutOpen (&dev, deviceID, &fmt, (DWORD)wave_callback, 0, CALLBACK_FUNCTION))
+ {
+ case MMSYSERR_ALLOCATED: return qWarning("OutputWaveOut: Device is already open.");
+ case MMSYSERR_BADDEVICEID: return qWarning("OutputWaveOut: The specified device is out of range.");
+ case MMSYSERR_NODRIVER: return qWarning("OutputWaveOut: There is no audio driver in this system.");
+ case MMSYSERR_NOMEM: return qWarning("OutputWaveOut: Unable to allocate sound memory.");
+ case WAVERR_BADFORMAT: return qWarning("OutputWaveOut: This audio format is not supported.");
+ case WAVERR_SYNC: return qWarning("OutputWaveOut: The device is synchronous.");
+ default: return qWarning("OutputWaveOut: Unknown media error.");
+ case MMSYSERR_NOERROR: break;
+ }
+
+ waveOutReset (dev);
+ InitializeCriticalSection ( &cs );
+ //SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );
+ Output::configure(freq, chan, prec);
+ return;
+}
+
+bool OutputWaveOut::initialize()
+{
+ if (!waveOutGetNumDevs ())
+ {
+ qWarning("OutputWaveOut: no audio device found");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+qint64 OutputWaveOut::latency()
+{
+ /*if (!m_connection)
+ return 0;
+ int error = 0;
+ qint64 delay = pa_simple_get_latency(m_connection, &error)/1000;
+ if (error)
+ {
+ qWarning("OutputWaveOut: %s", pa_strerror (error));
+ delay = 0;
+ }*/
+ return 0;
+}
+
+qint64 OutputWaveOut::writeAudio(unsigned char *data, qint64 len)
+{
+ /*int error;
+ if (!m_connection)
+ return -1;
+ if (pa_simple_write(m_connection, data, maxSize, &error) < 0)
+ {
+ mutex()->unlock();
+ qWarning("OutputWaveOut: pa_simple_write() failed: %s", pa_strerror(error));
+ return -1;
+ }*/
+ //return maxSize;
+ HGLOBAL hg;
+ HGLOBAL hg2;
+ LPWAVEHDR wh;
+ void* allocptr;
+
+ do
+ {
+ while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
+ free_memory ();
+
+ if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
+ break;
+ usleep (500);
+
+ } while (1);
+
+ if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer
+ return Box ( "GlobalAlloc failed." );
+
+ allocptr = GlobalLock (hg2);
+ CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want....
+
+ if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
+ return -1;
+
+ wh = (wavehdr_tag*)GlobalLock (hg);
+ wh->dwBufferLength = len;
+ wh->lpData = (CHAR *)allocptr;
+
+ if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR )
+ {
+ GlobalUnlock (hg);
+ GlobalFree (hg);
+ return -1;
+ }
+
+ if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR )
+ {
+ GlobalUnlock (hg);
+ GlobalFree (hg);
+ return -1;
+ }
+
+ EnterCriticalSection ( &cs );
+ ScheduledBlocks++;
+ LeaveCriticalSection ( &cs );
+
+ return len;
+}
+
+void OutputWaveOut::flush()
+{
+ /*int error;
+ if (m_connection)
+ pa_simple_flush(m_connection, &error); */
+}
+
+void OutputWaveOut::uninitialize()
+{
+ if (dev)
+ {
+ while ( ScheduledBlocks > 0 )
+ {
+ Sleep (ScheduledBlocks);
+ while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
+ free_memory ();
+ }
+
+ waveOutReset (dev); // reset the device
+ waveOutClose (dev); // close the device
+ dev = 0;
+ }
+
+ DeleteCriticalSection ( &cs );
+ ScheduledBlocks = 0;
+ return;
+}
+