#include "Sound.h" #include "Player.h" using namespace GSL; #ifdef WIN32 extern GSLPlayer *_player; void CALLBACK AudioOutProc( HWAVEOUT hOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ); #endif // Inhalt der Sound Klasse aus Sound.h // Konstruktor GSLSound::GSLSound( const SoundKopf &skpf ) : Thread() { kpf = skpf; dat = new Datei(); dat->setDatei( kpf.pfad ); #ifdef WIN32 status = 0; hAudioId = 0; uAudioDelay = 0; uAudioCount = 0; uAudioPlay = 16; hAudioEvent = 0; uAudioWrite = 0; uAudioStop = 0; lAudioDone = 0; uAudioWrOk = 0; iAudioThEnd = 0; linksV = 1; rechtsV = 1; #endif ref = 1; } // Destruktor GSLSound::~GSLSound() { #ifdef WIN32 if( status ) stopSound(); #endif dat->release(); } // privat int GSLSound::audioOpen() { #ifdef WIN32 WAVEFORMATEX sAudioWm; sAudioWm.wFormatTag = WAVE_FORMAT_PCM; sAudioWm.nChannels = kpf.channels; sAudioWm.nSamplesPerSec = kpf.sampleRate; sAudioWm.nBlockAlign = ( ( 16 * kpf.channels ) + 7 ) >> 3; sAudioWm.nAvgBytesPerSec = kpf.sampleRate * sAudioWm.nBlockAlign; sAudioWm.wBitsPerSample = 16; sAudioWm.cbSize = 0; MMRESULT uRes = waveOutOpen( &hAudioId, WAVE_MAPPER, &sAudioWm, (DWORD_PTR)AudioOutProc, 0x00000000, CALLBACK_FUNCTION ); if( uRes || !hAudioId ) { memset( &sAudioWm, 0, sizeof( sAudioWm ) ); return 1; } uAudioDelay = 0; uAudioWrite = 0; uAudioStop = 0; lAudioDone = 0; for( uAudioCount = 0; uAudioCount < 16; uAudioCount++ ) { aAudioHdr[ uAudioCount ] = (LPWAVEHDR)GlobalAllocPtr( GMEM_MOVEABLE | GMEM_SHARE, sizeof( WAVEHDR ) + 0x4000 ); if( !aAudioHdr[ uAudioCount ] ) break; aAudioHdr[ uAudioCount ]->dwFlags = WHDR_DONE; aAudioHdr[ uAudioCount ]->lpData = (LPSTR)aAudioHdr[ uAudioCount ] + sizeof( WAVEHDR ); aAudioHdr[ uAudioCount ]->dwBufferLength = 0x4000; aAudioHdr[ uAudioCount ]->dwUser = uAudioCount; aAudioHdr[ uAudioCount ]->dwBytesRecorded = 0; aAudioHdr[ uAudioCount ]->dwLoops = 1; aAudioHdr[ uAudioCount ]->lpNext = 0; aAudioPtr[ uAudioCount ] = (char*)( aAudioHdr[ uAudioCount ] ) + sizeof( WAVEHDR ); if( !waveOutPrepareHeader( hAudioId, aAudioHdr[ uAudioCount ], sizeof( WAVEHDR ) ) ) continue; GlobalFreePtr( (LPCVOID)aAudioHdr[ uAudioCount ] ); break; } uAudioPlay = uAudioCount - 1; if( uAudioCount < 12 ) { audioClose(); return 2; } hAudioEvent = CreateEvent( 0, TRUE, TRUE, 0 ); if( !hAudioEvent ) { audioClose(); return 3; } if( waveOutGetDevCaps( (UINT_PTR)hAudioId, (LPWAVEOUTCAPSA)&sAudioCaps, sizeof( WAVEOUTCAPS ) ) ) memset( &sAudioCaps, 0, sizeof( sAudioCaps ) ); waveOutReset( hAudioId ); waveOutSetVolume( hAudioId, 0xFFFFFFFF ); #endif dat->open( Datei::Style::lesen ); #ifdef WIN32 uAudioWrOk = 1; #endif return 0; } int GSLSound::audioClose() { int iErr = 0; #ifdef WIN32 if( !hAudioId ) return 1; audioStop(); while( uAudioCount > 0 ) { uAudioCount--; if( waveOutUnprepareHeader( hAudioId, aAudioHdr[ uAudioCount ], sizeof( WAVEHDR ) ) ) iErr = 1; if( GlobalFreePtr( (LPCVOID)aAudioHdr[ uAudioCount ] ) ) iErr = 1; aAudioHdr[ uAudioCount ] = 0; aAudioPtr[ uAudioCount ] = 0; } if( waveOutClose( hAudioId ) ) iErr = 1; if( !CloseHandle( hAudioEvent ) ) iErr = 1; hAudioId = 0; uAudioWrite = 0; uAudioDelay = 0; uAudioPlay = uAudioCount - 1; #endif dat->close(); return iErr; } int GSLSound::audioStop() { #ifdef WIN32 unsigned uPos; if( !hAudioId ) return 1; uAudioStop = 1; uAudioWrOk = 0; warteAufThread( 5000 ); SetEvent( hAudioEvent ); waveOutReset( hAudioId ); if( uAudioWrite != 0 && uAudioPlay != uAudioCount - 1 ) { for( uPos = 0; uPos < uAudioCount; uPos++ ) // clears all buffers { memset( aAudioHdr[ uPos ]->lpData, 0, 0x4000 ); break; } } uAudioPlay = uAudioCount - 1; uAudioWrite = 0; uAudioDelay = 0; SetEvent( hAudioEvent ); uAudioWrOk = 1; if( isRunning() ) // close thread { warteAufThread( 1000 ); if( !iAudioThEnd ) { warteAufThread( 1000 ); if( run ) ende(); Sleep( 100 ); } } #endif return 0; } int GSLSound::audioSchreiben( unsigned int uCount ) { #ifdef WIN32 int iDelta, i, iPos; WAVEHDR *pHeader; if( !uAudioWrOk ) return 4; if( uCount > 0x4000 ) return 2; if( WaitForSingleObject( hAudioEvent, 2000 ) == WAIT_FAILED ) return 1; if( uAudioDelay < 8 ) { aAudioSize[ uAudioDelay ] = uCount; uAudioDelay++; hAudioCs.lock(); // increase write pos uAudioWrite++; if( uAudioWrite >= uAudioCount ) uAudioWrite = 0; hAudioCs.unlock(); return 0; } if( uAudioDelay == 8 ) { uAudioDelay++; for( i = 8; i > 0; i-- ) { iPos = uAudioWrite - i; if( iPos < 0 )iPos += uAudioCount; pHeader = aAudioHdr[ iPos ]; pHeader->dwBufferLength = aAudioSize[ 8 - i ]; if( waveOutWrite( hAudioId, pHeader, sizeof( WAVEHDR ) ) ) return 3; } } pHeader = aAudioHdr[ uAudioWrite ]; pHeader->dwBufferLength = uCount; if( waveOutWrite( hAudioId, pHeader, sizeof( WAVEHDR ) ) ) return 3; hAudioCs.lock(); uAudioWrite++; if( uAudioWrite >= uAudioCount ) uAudioWrite = 0; iDelta = uAudioPlay - uAudioWrite; if( iDelta < 0 ) iDelta += uAudioCount; if( iDelta < 2 ) ResetEvent( hAudioEvent ); hAudioCs.unlock(); #endif return 0; } int GSLSound::audioLesen( char *buff, int len ) { if( dat->getLPosition() < kpf.datPos ) dat->setLPosition( kpf.datPos, 0 ); if( dat->getLPosition() >= kpf.datEnd ) return -1; if( dat->getLPosition() + len > kpf.datEnd ) len = (int)( kpf.datEnd - dat->getLPosition() ); if( len > 0 ) dat->lese( buff, len ); #ifdef WIN32 for( int i = 0; i < len; i++, buff++ ) { if( i % 4 >= 2 ) *buff = (char)( *buff * rechtsV ); else *buff = (char)( *buff * linksV ); } #endif return len; } // nicht constant void GSLSound::playSound() { #ifdef WIN32 if( !status ) { if( _player->addSound( (GSLSound*)getThis() ) ) status = 1; if( !audioOpen() ) start(); else { _player->removeSound( this ); status = 0; } } setPause( 0 ); #endif } void GSLSound::setPause( bool p ) { #ifdef WIN32 if( p ) { if( !status ) playSound(); if( status == 1 ) { waveOutPause( hAudioId ); status = 2; } } else { if( status == 2 ) { waveOutRestart( hAudioId ); status = 1; } } #endif } void GSLSound::stopSound() { #ifdef WIN32 setPause( 0 ); if( status == 1 ) { status = 0; _player->removeSound( this ); audioClose(); } #endif } void GSLSound::warteAufSound( int zeit ) { warteAufThread( zeit ); } void GSLSound::setVolume( unsigned int links, unsigned int rechts ) { #ifdef WIN32 linksV = (float)links / 0xFFFF; rechtsV = (float)rechts / 0xFFFF; #endif } #ifdef WIN32 void GSLSound::msg( UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) { WAVEHDR *pHeader; int iDelta; switch( uMsg ) { case WOM_DONE: pHeader = (WAVEHDR*)dwParam1; hAudioCs.lock(); InterlockedExchangeAdd( (unsigned __int64*)&lAudioDone, (__int64)pHeader->dwBufferLength ); iDelta = (int)( uAudioPlay - pHeader->dwUser ); if( iDelta < 0 ) iDelta += uAudioCount; if( iDelta > ( (int)uAudioCount >> 1 ) ) { uAudioPlay = (unsigned int)pHeader->dwUser; if( uAudioPlay >= uAudioCount ) uAudioPlay = 0; iDelta = uAudioPlay - uAudioWrite; if( iDelta < 0 ) iDelta += uAudioCount; if( iDelta >= 2 ) SetEvent( hAudioEvent ); } hAudioCs.unlock(); break; } } #endif void GSLSound::thread() { #ifdef WIN32 iAudioThEnd = 0; uAudioStop = 0; if( !hAudioId ) return; int iCount; while( !uAudioStop && hAudioId ) { iCount = audioLesen( aAudioPtr[ uAudioWrite ], 0x4000 ); if( iCount <= 0 ) break; audioSchreiben( iCount ); } iAudioThEnd = 1; stopSound(); #endif run = 0; } // zum Speichern void GSLSound::open() { #ifdef WIN32 if( !status ) { dat->open( Datei::Style::lesen ); status = 3; } #else dat->open( Datei::Style::lesen ); #endif } int GSLSound::getDaten( char *buffer, int len ) { #ifdef WIN32 if( status != 3 ) return -1; #endif return audioLesen( buffer, len ); } void GSLSound::close() { #ifdef WIN32 if( status == 3 ) { dat->close(); status = 0; } #else dat->close(); #endif } bool GSLSound::istMono() const { return kpf.channels == 1; } int GSLSound::getSampleRate() const { return kpf.sampleRate; } __int64 GSLSound::getDatLength() const { return kpf.datEnd - kpf.datPos; } // constant #ifdef WIN32 HWAVEOUT GSLSound::getHandle() const { return hAudioId; } #endif // Reference Counting GSLSoundV *GSLSound::getThis() { ref++; return this; } GSLSoundV *GSLSound::release() { ref--; if( !ref ) delete this; return 0; }