From 5b126a92737bba6264065c8ff437056c908204f5 Mon Sep 17 00:00:00 2001 From: trialuser02 Date: Sun, 12 Apr 2009 19:31:02 +0000 Subject: added wave output plugin git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@901 90c681e8-e032-0410-971d-27865f9a5e38 --- src/plugins/Output/waveout/outputwaveout.cpp | 244 +++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 src/plugins/Output/waveout/outputwaveout.cpp (limited to 'src/plugins/Output/waveout/outputwaveout.cpp') 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 +#include +#include + +#include +#include +#include + +#include +#include +#include +#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; +} + -- cgit v1.2.3-13-gbd6f