[Kde-cygwin-cvs] CVS: qt-3/src/kernel qsound_win.cpp,1.1.2.8.2.9,1.1.2.8.2.10
Status: Inactive
Brought to you by:
habacker
From: Christian E. <che...@us...> - 2005-07-31 15:03:43
|
Update of /cvsroot/kde-cygwin/qt-3/src/kernel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20990/src/kernel Modified Files: Tag: QT_WIN32_3_3_BRANCH qsound_win.cpp Log Message: qsound_win.cpp implementation from qt4 :) Index: qsound_win.cpp =================================================================== RCS file: /cvsroot/kde-cygwin/qt-3/src/kernel/Attic/qsound_win.cpp,v retrieving revision 1.1.2.8.2.9 retrieving revision 1.1.2.8.2.10 diff -u -r1.1.2.8.2.9 -r1.1.2.8.2.10 --- qsound_win.cpp 31 Jul 2005 13:01:50 -0000 1.1.2.8.2.9 +++ qsound_win.cpp 31 Jul 2005 15:03:30 -0000 1.1.2.8.2.10 @@ -1,514 +1,193 @@ /**************************************************************************** -** $Id$ ** -** Implementation of QSound class and QAuServer internal class +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. ** -** Created : 20030119 -** -** Copyright (C) 2003 Holger Schroeder -** Copyright (C) 2003 Richard Lärkäng -** Copyright (C) 2004 Tom and Timi Cecka -** Copyright (C) 2004 Ralf Habacker -** -** This file is part of the kernel module of the Qt GUI Toolkit. +** This file is part of the gui module of the Qt Toolkit. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** ** See http://www.trolltech.com/pricing.html or email sa...@tr... for -** information about Qt Commercial License Agreements. -** See http://www.trolltech.com/qpl/ for QPL licensing information. +** information about Qt Commercial License Agreements. ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** -** Contact kde...@kd... if any conditions of this licensing are +** Contact in...@tr... if any conditions of this licensing are ** not clear to you. ** -**********************************************************************/ - -#define QT_CLEAN_NAMESPACE +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ #include "qsound.h" -#define QT_WIN_SUPPORT #ifndef QT_NO_SOUND -#include "qplatformdefs.h" #include "qapplication.h" -#include "qptrdict.h" -#include "qt_windows.h" - -#ifdef QT_WIN_SUPPORT +#include "qapplication_p.h" +#include <qfile.h> -static QPtrDict<void> *inprogress = 0; +#include <qt_windows.h> +#include <mmsystem.h> -class WaveFile; -class QAuBucketWin; -class QAuServerWin : public QAuServer +class QAuServerWindows : public QAuServer { Q_OBJECT public: - QAuServerWin( QObject* parent ); - ~QAuServerWin(); + QAuServerWindows( QObject* parent, const char* name = NULL ); + ~QAuServerWindows(); + + void playHelper( const QString &filename, int loop, QSound *snd ); + void play( const QString& filename, int loop ); + void play( QSound* ); - void init( QSound* ); - void play( const QString& filename ); - void play( QSound* s ); void stop( QSound* ); bool okay(); - void setDone( QSound* ); -public slots: - void dataReceived(); - void soundDestroyed( QObject *o ); - -private: - bool wave; - WaveFile *wv; - QAuBucketWin* bucket( QSound* s ) + int decLoop( QSound *snd ) { - return ( QAuBucketWin* ) QAuServer::bucket( s ); + return QAuServer::decLoop( snd ); } -}; - -/*======================================================================== - * start of win32 classes WavePlay and PlayObject implementation - * written by Ralf Habacker - *=======================================================================*/ - -#define OFFSET_FORMATTAG 20 -#define OFFSET_CHANNELS 22 -#define OFFSET_SAMPLESPERSEC 24 -#define OFFSET_AVGBYTESPERSEC 28 -#define OFFSET_BLOCKALIGN 32 -#define OFFSET_BITSPERSAMPLE 34 -#define OFFSET_WAVEDATA 44 -#define HEADER_SIZE OFFSET_WAVEDATA - -class PlayObject; - -// FIXME move all private elements to this class -class WaveFilePrivate - {} -; -/* a wave file, support multiple playing a wave file */ - -class WaveFile -{ -public: - enum PlayMode { waitEnd, returnImmediate }; - enum Error { NoError, FileNotFound, CouldNotPlay }; - - WaveFile( const char *fileName, QSound *s, QAuServerWin *server ); - ~WaveFile(); - - /// play a sound - PlayObject *play( PlayMode mode = waitEnd, bool loop = false ); - - /// return error code from last operation - inline Error getError() - { - return error; - } - - /// set volume (0-100) in % for both channels - void setVolume( int avol ) - { - vol = avol; - } - - /// set volume for left and right channel - // void setVolume(int leftvol, int rightvol); - - /// return volume (0=left, 1 = right) - int getVolume( void ) - { - return vol; - } - // int getVolume(int channel=0); - - static int debug; -protected: - char *lpfile; - int file_size; - WAVEFORMATEX wfex; - Error error; - int vol; - // int leftvol; - // int rightvol; - QSound *m_sound; - QAuServerWin *m_server; - - - friend class PlayObject; -}; - -void CALLBACK WaveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); - -/** - encapsulates one playing instance of a WaveFile object -*/ - -class PlayObject -{ -public: - PlayObject( WaveFile *_parent, int _count = 0 ) - { - counter = _count; - parent = _parent; - } - ~PlayObject(); - - bool play(); - inline int count( int offset = 0 ) - { - if ( !offset ) - return counter; - else - return counter += offset; - } - inline bool isPlaying() - { - return !done; - } - inline bool isloop() - { - return counter == -1; - } - inline void stop() - { - counter = 0; - } - inline void setDone() - { - done = true; - QAuServerWin *s = ( QAuServerWin * )inprogress->find( parent->m_sound ); - if ( s ) - s->setDone( ( QSound* ) parent->m_sound ); - } - void waitDone() - { - while ( !done ) - Sleep( 500 ); - } - -protected: - HWAVEOUT hwo; - WAVEHDR whdr; - WaveFile *parent; - int counter; - bool done; + HANDLE current; + HANDLE mutex; + HANDLE event; }; -bool PlayObject::play() +QAuServerWindows::QAuServerWindows( QObject* parent, const char* name ) : + QAuServer( parent, name ), current( 0 ) { - ZeroMemory( ( void* ) & whdr, sizeof( WAVEHDR ) ); - whdr.lpData = parent->lpfile + HEADER_SIZE; - whdr.dwBufferLength = parent->file_size - HEADER_SIZE; - whdr.dwUser = ( DWORD ) this; - done = false; - - // Find a waveOut device and open it - for ( UINT devid = 0; devid < waveOutGetNumDevs(); devid++ ) { - if ( devid == waveOutGetNumDevs() ) - // Error, no free devices found - return false; - if ( waveOutOpen( &hwo, WAVE_MAPPER, &parent->wfex, ( DWORD ) WaveOutProc, 0, CALLBACK_FUNCTION ) == MMSYSERR_NOERROR ) - // Usable device found, stop searching - break; - } - if ( parent && parent->debug ) { - DWORD vol; - waveOutGetVolume( hwo, &vol ); - fprintf( stderr, "%s original Volume: L:%04d R:%04d\n", __FUNCTION__, vol >> 16, vol & 0xffff ); - } - if ( parent && parent->vol != -1 ) { - int vol = ( int ) ( ( double ) parent->vol * 65535 / 100 ); - if ( parent->debug ) - fprintf( stderr, "%d %08x\n", vol, ( vol << 16 ) | vol ); - waveOutSetVolume( hwo, ( vol << 16 ) | vol ); - } - - if ( waveOutPrepareHeader( hwo, &whdr, sizeof( WAVEHDR ) ) != MMSYSERR_NOERROR ) - return false; - if ( waveOutWrite( hwo, &whdr, sizeof( WAVEHDR ) ) != MMSYSERR_NOERROR ) - return false; - return true; + mutex = CreateMutexA( 0, 0, 0 ); + event = CreateEventA( 0, false, false, 0 ); } -PlayObject::~PlayObject() +QAuServerWindows::~QAuServerWindows() { - waveOutClose( hwo ); -} + HANDLE mtx = mutex; + WaitForSingleObject( mtx, INFINITE ); + mutex = 0; -void CALLBACK WaveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD /*dwInstance*/, DWORD dwParam1, DWORD /*dwParam2*/ ) -{ - switch ( uMsg ) { - case WOM_OPEN: - break; - case WOM_DONE: { - WAVEHDR *whdr = ( WAVEHDR* ) dwParam1; - PlayObject *obj = ( PlayObject * ) whdr->dwUser; - if ( obj->count( -1 ) > 0 ) - waveOutWrite( hwo, whdr, sizeof( WAVEHDR ) ); - else { - waveOutUnprepareHeader( hwo, whdr, sizeof( WAVEHDR ) ); - // signal the parent that the sound isn't playing anymore - obj->setDone(); - // delete whdr; - } - } - break; - case WOM_CLOSE: - break; - } + ReleaseMutex( mtx ); + CloseHandle( mtx ); + CloseHandle( event ); } - -int WaveFile::debug = 1; - -WaveFile::WaveFile( const char *fileName, QSound *s, QAuServerWin *server ) : - lpfile(NULL), m_sound( s ), m_server( server ) +struct SoundInfo { - FILE * f; // Structure to load the file into memory - - vol = -1; - error = NoError; - // Open and read the wave file - f = fopen( fileName, "rb" ); - if ( !f ) { - if ( debug ) - fprintf( stderr, "%s(%s) - file not found\n", __FUNCTION__, fileName ); - error = FileNotFound; - return ; - } - if ( debug ) - fprintf( stderr, "%s(%s) - file loaded\n", __FUNCTION__, fileName ); - // Determine the file size - fseek( f, 0, SEEK_END ); - file_size = ftell( f ); - // Rewind the pointer to the begginning so we can read it - fseek( f, 0, SEEK_SET ); - - // Request enough memory to store the entire file - lpfile = new char [ file_size ]; - // 'Copy' the file to memory - fread( lpfile, 1, file_size, f ); - // Close the file, we won't need it anymore - fclose( f ); - - // Fill WAVEFORMATEX with the data from the file - wfex.wFormatTag = *( ( WORD* ) ( lpfile + OFFSET_FORMATTAG ) ); - wfex.nChannels = *( ( WORD* ) ( lpfile + OFFSET_CHANNELS ) ); - wfex.nSamplesPerSec = *( ( DWORD* ) ( lpfile + OFFSET_SAMPLESPERSEC ) ); - wfex.nAvgBytesPerSec = *( ( DWORD* ) ( lpfile + OFFSET_AVGBYTESPERSEC ) ); - wfex.nBlockAlign = *( ( WORD* ) ( lpfile + OFFSET_BLOCKALIGN ) ); - wfex.wBitsPerSample = *( ( WORD* ) ( lpfile + OFFSET_BITSPERSAMPLE ) ); - return ; -} + SoundInfo( const QString &fn, int lp, QSound *snd, QAuServerWindows *srv ) + : sound( snd ), server( srv ), filename( fn ), loops( lp ) + {} -WaveFile::~WaveFile() -{ - delete [] lpfile; -} + QSound *sound; + QAuServerWindows *server; + QString filename; + int loops; +}; -PlayObject *WaveFile::play( PlayMode mode, bool loop ) +DWORD WINAPI SoundPlayProc( LPVOID param ) { - if ( error != NoError ) - return NULL; + SoundInfo * info = ( SoundInfo* ) param; - PlayObject *obj = new PlayObject( this, loop ); + // copy data before waking up GUI thread + QAuServerWindows *server = info->server; + QSound *sound = info->sound; + int loops = info->loops; + QString filename = info->filename; + HANDLE mutex = server->mutex; + HANDLE event = server->event; + info = 0; + + // server must not be destroyed until thread finishes + // and all other sounds have to wait + WaitForSingleObject( mutex, INFINITE ); + + if ( loops <= 1 ) { + server->current = 0; + int flags = SND_FILENAME | SND_ASYNC; + if ( loops == -1 ) + flags |= SND_LOOP; + + QT_WA( { + PlaySoundW( ( TCHAR* ) filename.ucs2(), 0, flags ); + } , { + PlaySoundA( QFile::encodeName( filename ).data(), 0, flags ); + } ); + if ( sound && loops == 1 ) + server->decLoop( sound ); - if ( obj->play() ) { - if ( mode == waitEnd ) { - obj->waitDone(); - delete obj; - return NULL; - } else - return obj; + // GUI thread continues, but we are done as well. + SetEvent( event ); } else { - delete obj; - error = CouldNotPlay; - return NULL; - } -} - -/*======================================================================== - * end of win32 classes WavePlay and PlayObject implementation - *=======================================================================*/ - -// qt related code -class QAuBucketWin : public QAuBucket, public PlayObject -{ -public: - QAuBucketWin( WaveFile *wv ) : PlayObject( wv ) - { } - ~QAuBucketWin() - {} - friend class QAuServerWin; -} -; + // signal GUI thread to continue - sound might be reset! + QSound *guarded_sound = sound; + SetEvent( event ); + + for ( int l = 0; l < loops && server->current; ++l ) { + QT_WA( { + PlaySoundW( ( TCHAR* ) filename.ucs2(), 0, SND_FILENAME | SND_SYNC ); + } , { + PlaySoundA( QFile::encodeName( filename ).data(), 0, SND_FILENAME | SND_SYNC ); + } ); -// qt used the below defined class vars in QAuBucket. PlayObject defines vars -// with exactly the same meaning but other names, so that the redefine below -// makes is easier to compare this qt code with the x11 code for further patches -#define stopped done -#define numplaying counter - -QAuServerWin::QAuServerWin( QObject* parent ) : - QAuServer( parent, "Win32 Audio System" ), - wave(false), - wv(NULL) -{ - wave = true; -} - -QAuServerWin::~QAuServerWin() -{ - wave = false; - if ( wv ) - delete wv; -} - -void QAuServerWin::soundDestroyed( QObject *o ) -{ - if ( inprogress ) { - QSound * so = static_cast<QSound *>( o ); - while ( inprogress->remove( so ) ); // Loop while remove returns TRUE + if ( guarded_sound ) + server->decLoop( guarded_sound ); + } + server->current = 0; } -} + ReleaseMutex( mutex ); -void QAuServerWin::play( const QString& filename ) -{ - if ( wv ) - delete wv; - QSound s( filename ); - init ( &s ); - wv->play(); - dataReceived(); + return 0; } -void QAuServerWin::setDone( QSound* s ) +void QAuServerWindows::playHelper( const QString &filename, int loop, QSound *snd ) { - if ( wave ) { - decLoop( s ); - if ( s->loopsRemaining() && !bucket( s )->stopped ) { - bucket( s )->stopped = TRUE; - play( s ); - } else { - if ( --( bucket( s )->numplaying ) == 0 ) - bucket( s )->stopped = TRUE; - inprogress->remove( s ); - } - } -} + if ( loop == 0 ) + return ; + // busy? + if ( WaitForSingleObject( mutex, 0 ) == WAIT_TIMEOUT ) + return ; + ReleaseMutex( mutex ); -void QAuServerWin::play( QSound* s ) -{ - if ( wave ) { - ++( bucket( s )->numplaying ); - if ( !bucket( s )->stopped ) { - stop( s ); - } + DWORD threadid = 0; + SoundInfo info( filename, loop, snd, this ); + current = CreateThread( 0, 0, SoundPlayProc, &info, 0, &threadid ); + CloseHandle( current ); - bucket( s )->stopped = FALSE; - if ( !inprogress ) - inprogress = new QPtrDict<void>; - inprogress->insert( s, ( void* ) this ); - - /* - int iv=100; - AuFixedPoint volume=AuFixedPointFromFraction(iv,100); - QAuBucketNAS *b = bucket(s); - AuSoundPlayFromBucket(nas, b->id, AuNone, volume, - callback, s, 0, &b->flow, NULL, NULL, NULL); - AuFlush(nas); - */ - QAuBucketWin *b = bucket( s ); - b->play(); - dataReceived(); - } + WaitForSingleObject( event, INFINITE ); } -void QAuServerWin::stop( QSound* s ) +void QAuServerWindows::play( const QString& filename, int loop ) { - if ( wave && !bucket( s ) ->stopped ) { - bucket( s )->stopped = TRUE; - /* - AuStopFlow(nas, bucket(s)->flow, NULL); - AuFlush(nas); - */ - dataReceived(); - } + playHelper( filename, loop, 0 ); } -void QAuServerWin::init( QSound* s ) +void QAuServerWindows::play( QSound* s ) { - connect( s, SIGNAL( destroyed( QObject * ) ), - this, SLOT( soundDestroyed( QObject * ) ) ); - if ( wv ) - delete wv; - wv = new WaveFile( s->fileName(), s, this ); - wv->setVolume( 100 ); - setBucket( s, new QAuBucketWin( wv ) ); + playHelper( s->fileName(), s->loops(), s ); } -bool QAuServerWin::okay() +void QAuServerWindows::stop( QSound* ) { - return !!wave; + // stop unlooped sound + if ( !current ) + PlaySound( 0, 0, 0 ); + // stop after loop is done + current = 0; } -void QAuServerWin::dataReceived() -{} - -#include "qsound_win.moc" - -#endif - - -class QAuServerNull : public QAuServer +bool QAuServerWindows::okay() { -public: - QAuServerNull( QObject* parent ); - - void play( const QString& ) - { } - void play( QSound*s ) - { - while ( decLoop( s ) > 0 ) /* nothing */ - ; - } - void stop( QSound* ) -{ } - bool okay() - { - return FALSE; - } -}; - -QAuServerNull::QAuServerNull( QObject* parent ) : - QAuServer( parent, "Null Audio Server" ) -{} - + return true; +} QAuServer* qt_new_audio_server() { -#ifdef QT_WIN_SUPPORT - QAuServer * s = new QAuServerWin( qApp ); - if ( s->okay() ) { - return s; - } else { - delete s; - } -#endif - return new QAuServerNull( qApp ); + return ( QAuServer* ) new QAuServerWindows( qApp ); } +#include "qsound_win.moc" #endif // QT_NO_SOUND |