📄 sound.cpp
字号:
}
#endif
bool wxSoundSyncOnlyAdaptor::Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status)
{
Stop();
if (flags & wxSOUND_ASYNC)
{
#if wxUSE_THREADS
m_mutexRightToPlay.Lock();
m_status.m_playing = true;
m_status.m_stopRequested = false;
data->IncRef();
wxThread *th = new wxSoundAsyncPlaybackThread(this, data, flags);
th->Create();
th->Run();
wxLogTrace(_T("sound"), _T("launched async playback thread"));
return true;
#else
wxLogError(_("Unable to play sound asynchronously."));
return false;
#endif
}
else
{
#if wxUSE_THREADS
m_mutexRightToPlay.Lock();
#endif
bool rv = m_backend->Play(data, flags, status);
#if wxUSE_THREADS
m_mutexRightToPlay.Unlock();
#endif
return rv;
}
}
void wxSoundSyncOnlyAdaptor::Stop()
{
wxLogTrace(_T("sound"), _T("asking audio to stop"));
#if wxUSE_THREADS
// tell the player thread (if running) to stop playback ASAP:
m_status.m_stopRequested = true;
// acquire the mutex to be sure no sound is being played, then
// release it because we don't need it for anything (the effect of this
// is that calling thread will wait until playback thread reacts to
// our request to interrupt playback):
m_mutexRightToPlay.Lock();
m_mutexRightToPlay.Unlock();
wxLogTrace(_T("sound"), _T("audio was stopped"));
#endif
}
bool wxSoundSyncOnlyAdaptor::IsPlaying() const
{
#if wxUSE_THREADS
return m_status.m_playing;
#else
return false;
#endif
}
// ----------------------------------------------------------------------------
// wxSound
// ----------------------------------------------------------------------------
wxSoundBackend *wxSound::ms_backend = NULL;
// FIXME - temporary, until we have plugins architecture
#if wxUSE_LIBSDL
#if wxUSE_PLUGINS
wxDynamicLibrary *wxSound::ms_backendSDL = NULL;
#else
extern "C" wxSoundBackend *wxCreateSoundBackendSDL();
#endif
#endif
wxSound::wxSound() : m_data(NULL)
{
}
wxSound::wxSound(const wxString& sFileName, bool isResource) : m_data(NULL)
{
Create(sFileName, isResource);
}
wxSound::wxSound(int size, const wxByte* data) : m_data(NULL)
{
Create(size, data);
}
wxSound::~wxSound()
{
Free();
}
bool wxSound::Create(const wxString& fileName, bool isResource)
{
wxASSERT_MSG( !isResource,
_T("Loading sound from resources is only supported on Windows") );
Free();
wxFile fileWave;
if (!fileWave.Open(fileName, wxFile::read))
{
return false;
}
wxFileOffset lenOrig = fileWave.Length();
if ( lenOrig == wxInvalidOffset )
return false;
size_t len = wx_truncate_cast(size_t, lenOrig);
wxUint8 *data = new wxUint8[len];
if ( fileWave.Read(data, len) != lenOrig )
{
delete [] data;
wxLogError(_("Couldn't load sound data from '%s'."), fileName.c_str());
return false;
}
if (!LoadWAV(data, len, false))
{
delete [] data;
wxLogError(_("Sound file '%s' is in unsupported format."),
fileName.c_str());
return false;
}
return true;
}
bool wxSound::Create(int size, const wxByte* data)
{
wxASSERT( data != NULL );
Free();
if (!LoadWAV(data, size, true))
{
wxLogError(_("Sound data are in unsupported format."));
return false;
}
return true;
}
/*static*/ void wxSound::EnsureBackend()
{
if (!ms_backend)
{
// FIXME -- make this fully dynamic when plugins architecture is in
// place
#if wxUSE_LIBSDL
//if (!ms_backend)
{
#if !wxUSE_PLUGINS
ms_backend = wxCreateSoundBackendSDL();
#else
wxString dllname;
dllname.Printf(_T("%s/%s"),
wxDynamicLibrary::GetPluginsDirectory().c_str(),
wxDynamicLibrary::CanonicalizePluginName(
_T("sound_sdl"), wxDL_PLUGIN_BASE).c_str());
wxLogTrace(_T("sound"),
_T("trying to load SDL plugin from '%s'..."),
dllname.c_str());
wxLogNull null;
ms_backendSDL = new wxDynamicLibrary(dllname, wxDL_NOW);
if (!ms_backendSDL->IsLoaded())
{
wxDELETE(ms_backendSDL);
}
else
{
typedef wxSoundBackend *(*wxCreateSoundBackend_t)();
wxDYNLIB_FUNCTION(wxCreateSoundBackend_t,
wxCreateSoundBackendSDL, *ms_backendSDL);
if (pfnwxCreateSoundBackendSDL)
{
ms_backend = (*pfnwxCreateSoundBackendSDL)();
}
}
#endif
if (ms_backend && !ms_backend->IsAvailable())
{
wxDELETE(ms_backend);
}
}
#endif
#ifdef HAVE_SYS_SOUNDCARD_H
if (!ms_backend)
{
ms_backend = new wxSoundBackendOSS();
if (!ms_backend->IsAvailable())
{
wxDELETE(ms_backend);
}
}
#endif
if (!ms_backend)
ms_backend = new wxSoundBackendNull();
if (!ms_backend->HasNativeAsyncPlayback())
ms_backend = new wxSoundSyncOnlyAdaptor(ms_backend);
wxLogTrace(_T("sound"),
_T("using backend '%s'"), ms_backend->GetName().c_str());
}
}
/*static*/ void wxSound::UnloadBackend()
{
if (ms_backend)
{
wxLogTrace(_T("sound"), _T("unloading backend"));
Stop();
delete ms_backend;
ms_backend = NULL;
#if wxUSE_LIBSDL && wxUSE_PLUGINS
delete ms_backendSDL;
#endif
}
}
bool wxSound::DoPlay(unsigned flags) const
{
wxCHECK_MSG( IsOk(), false, _T("Attempt to play invalid wave data") );
EnsureBackend();
wxSoundPlaybackStatus status;
status.m_playing = true;
status.m_stopRequested = false;
return ms_backend->Play(m_data, flags, &status);
}
/*static*/ void wxSound::Stop()
{
if (ms_backend)
ms_backend->Stop();
}
/*static*/ bool wxSound::IsPlaying()
{
if (ms_backend)
return ms_backend->IsPlaying();
else
return false;
}
void wxSound::Free()
{
if (m_data)
m_data->DecRef();
}
typedef struct
{
wxUint32 uiSize;
wxUint16 uiFormatTag;
wxUint16 uiChannels;
wxUint32 ulSamplesPerSec;
wxUint32 ulAvgBytesPerSec;
wxUint16 uiBlockAlign;
wxUint16 uiBitsPerSample;
} WAVEFORMAT;
#define WAVE_FORMAT_PCM 1
#define WAVE_INDEX 8
#define FMT_INDEX 12
bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
{
WAVEFORMAT waveformat;
wxUint32 ul;
if (length < 32 + sizeof(WAVEFORMAT))
return false;
memcpy(&waveformat, &data[FMT_INDEX + 4], sizeof(WAVEFORMAT));
waveformat.uiSize = wxUINT32_SWAP_ON_BE(waveformat.uiSize);
waveformat.uiFormatTag = wxUINT16_SWAP_ON_BE(waveformat.uiFormatTag);
waveformat.uiChannels = wxUINT16_SWAP_ON_BE(waveformat.uiChannels);
waveformat.ulSamplesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulSamplesPerSec);
waveformat.ulAvgBytesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulAvgBytesPerSec);
waveformat.uiBlockAlign = wxUINT16_SWAP_ON_BE(waveformat.uiBlockAlign);
waveformat.uiBitsPerSample = wxUINT16_SWAP_ON_BE(waveformat.uiBitsPerSample);
if (memcmp(data, "RIFF", 4) != 0)
return false;
if (memcmp(&data[WAVE_INDEX], "WAVE", 4) != 0)
return false;
if (memcmp(&data[FMT_INDEX], "fmt ", 4) != 0)
return false;
if (memcmp(&data[FMT_INDEX + waveformat.uiSize + 8], "data", 4) != 0)
return false;
memcpy(&ul,&data[FMT_INDEX + waveformat.uiSize + 12], 4);
ul = wxUINT32_SWAP_ON_BE(ul);
//WAS: if (ul + FMT_INDEX + waveformat.uiSize + 16 != length)
if (ul + FMT_INDEX + waveformat.uiSize + 16 > length)
return false;
if (waveformat.uiFormatTag != WAVE_FORMAT_PCM)
return false;
if (waveformat.ulSamplesPerSec !=
waveformat.ulAvgBytesPerSec / waveformat.uiBlockAlign)
return false;
m_data = new wxSoundData;
m_data->m_channels = waveformat.uiChannels;
m_data->m_samplingRate = waveformat.ulSamplesPerSec;
m_data->m_bitsPerSample = waveformat.uiBitsPerSample;
m_data->m_samples = ul / (m_data->m_channels * m_data->m_bitsPerSample / 8);
m_data->m_dataBytes = ul;
if (copyData)
{
m_data->m_dataWithHeader = new wxUint8[length];
memcpy(m_data->m_dataWithHeader, data, length);
}
else
m_data->m_dataWithHeader = (wxUint8*)data;
m_data->m_data =
(&m_data->m_dataWithHeader[FMT_INDEX + waveformat.uiSize + 8]);
return true;
}
// ----------------------------------------------------------------------------
// wxSoundCleanupModule
// ----------------------------------------------------------------------------
class wxSoundCleanupModule: public wxModule
{
public:
bool OnInit() { return true; }
void OnExit() { wxSound::UnloadBackend(); }
DECLARE_DYNAMIC_CLASS(wxSoundCleanupModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxSoundCleanupModule, wxModule)
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -