📄 sound.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: sound.cpp
// Purpose: wxSound
// Author: Marcel Rasche, Vaclav Slavik
// Modified by:
// Created: 25/10/98
// RCS-ID: $Id: sound.cpp,v 1.12.2.1 2006/03/07 23:21:08 VZ Exp $
// Copyright: (c) Julian Smart, Open Source Applications Foundation
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "sound.h"
#pragma implementation "soundbase.h"
#endif
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/setup.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#if wxUSE_SOUND
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#endif
#ifndef WX_PRECOMP
#include "wx/event.h"
#include "wx/intl.h"
#include "wx/log.h"
#endif
#include "wx/thread.h"
#include "wx/file.h"
#include "wx/module.h"
#include "wx/sound.h"
#include "wx/dynlib.h"
#if wxUSE_THREADS
// mutex for all wxSound's synchronization
static wxMutex gs_soundMutex;
#endif
// ----------------------------------------------------------------------------
// wxSoundData
// ----------------------------------------------------------------------------
void wxSoundData::IncRef()
{
#if wxUSE_THREADS
wxMutexLocker locker(gs_soundMutex);
#endif
m_refCnt++;
}
void wxSoundData::DecRef()
{
#if wxUSE_THREADS
wxMutexLocker locker(gs_soundMutex);
#endif
if (--m_refCnt == 0)
delete this;
}
wxSoundData::~wxSoundData()
{
delete[] m_dataWithHeader;
}
// ----------------------------------------------------------------------------
// wxSoundBackendNull, used in absence of audio API or card
// ----------------------------------------------------------------------------
class wxSoundBackendNull : public wxSoundBackend
{
public:
wxString GetName() const { return _("No sound"); }
int GetPriority() const { return 0; }
bool IsAvailable() const { return true; }
bool HasNativeAsyncPlayback() const { return true; }
bool Play(wxSoundData *WXUNUSED(data), unsigned WXUNUSED(flags),
volatile wxSoundPlaybackStatus *WXUNUSED(status))
{ return true; }
void Stop() {}
bool IsPlaying() const { return false; }
};
// ----------------------------------------------------------------------------
// wxSoundBackendOSS, for Linux
// ----------------------------------------------------------------------------
#ifdef HAVE_SYS_SOUNDCARD_H
#ifndef AUDIODEV
#define AUDIODEV "/dev/dsp" // Default path for audio device
#endif
class wxSoundBackendOSS : public wxSoundBackend
{
public:
wxString GetName() const { return _T("Open Sound System"); }
int GetPriority() const { return 10; }
bool IsAvailable() const;
bool HasNativeAsyncPlayback() const { return false; }
bool Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status);
void Stop() {}
bool IsPlaying() const { return false; }
private:
int OpenDSP(const wxSoundData *data);
bool InitDSP(int dev, const wxSoundData *data);
int m_DSPblkSize; // Size of the DSP buffer
bool m_needConversion;
};
bool wxSoundBackendOSS::IsAvailable() const
{
int fd;
fd = open(AUDIODEV, O_WRONLY | O_NONBLOCK);
if (fd < 0)
return false;
close(fd);
return true;
}
bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status)
{
int dev = OpenDSP(data);
if (dev < 0)
return false;
ioctl(dev, SNDCTL_DSP_SYNC, 0);
do
{
bool play = true;
int i;
unsigned l = 0;
size_t datasize = data->m_dataBytes;
do
{
if (status->m_stopRequested)
{
wxLogTrace(_T("sound"), _T("playback stopped"));
close(dev);
return true;
}
i= (int)((l + m_DSPblkSize) < datasize ?
m_DSPblkSize : (datasize - l));
if (write(dev, &data->m_data[l], i) != i)
{
play = false;
}
l += i;
} while (play && l < datasize);
} while (flags & wxSOUND_LOOP);
close(dev);
return true;
}
int wxSoundBackendOSS::OpenDSP(const wxSoundData *data)
{
int dev = -1;
if ((dev = open(AUDIODEV, O_WRONLY, 0)) <0)
return -1;
if (!InitDSP(dev, data) || m_needConversion)
{
close(dev);
return -1;
}
return dev;
}
bool wxSoundBackendOSS::InitDSP(int dev, const wxSoundData *data)
{
unsigned tmp;
// Reset the dsp
if (ioctl(dev, SNDCTL_DSP_RESET, 0) < 0)
{
wxLogTrace(_T("sound"), _T("unable to reset dsp"));
return false;
}
m_needConversion = false;
tmp = data->m_bitsPerSample;
if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SAMPLESIZE)"));
return false;
}
if (tmp != data->m_bitsPerSample)
{
wxLogTrace(_T("sound"),
_T("Unable to set DSP sample size to %d (wants %d)"),
data->m_bitsPerSample, tmp);
m_needConversion = true;
}
unsigned stereo = data->m_channels == 1 ? 0 : 1;
tmp = stereo;
if (ioctl(dev, SNDCTL_DSP_STEREO, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_STEREO)"));
return false;
}
if (tmp != stereo)
{
wxLogTrace(_T("sound"), _T("Unable to set DSP to %s."), stereo? _T("stereo"):_T("mono"));
m_needConversion = true;
}
tmp = data->m_samplingRate;
if (ioctl(dev, SNDCTL_DSP_SPEED, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SPEED)"));
return false;
}
if (tmp != data->m_samplingRate)
{
// If the rate the sound card is using is not within 1% of what the
// data specified then override the data setting. The only reason not
// to always override this is because of clock-rounding
// problems. Sound cards will sometimes use things like 44101 when you
// ask for 44100. No need overriding this and having strange output
// file rates for something that we can't hear anyways.
if (data->m_samplingRate - tmp > (tmp * .01) ||
tmp - data->m_samplingRate > (tmp * .01)) {
wxLogTrace(_T("sound"),
_T("Unable to set DSP sampling rate to %d (wants %d)"),
data->m_samplingRate, tmp);
m_needConversion = true;
}
}
// Do this last because some drivers can adjust the buffer sized based on
// the sampling rate, etc.
if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_GETBLKSIZE)"));
return false;
}
return true;
}
#endif // HAVE_SYS_SOUNDCARD_H
// ----------------------------------------------------------------------------
// wxSoundSyncOnlyAdaptor
// ----------------------------------------------------------------------------
#if wxUSE_THREADS
class wxSoundSyncOnlyAdaptor;
// this class manages asynchronous playback of audio if the backend doesn't
// support it natively (e.g. OSS backend)
class wxSoundAsyncPlaybackThread : public wxThread
{
public:
wxSoundAsyncPlaybackThread(wxSoundSyncOnlyAdaptor *adaptor,
wxSoundData *data, unsigned flags)
: wxThread(), m_adapt(adaptor), m_data(data), m_flags(flags) {}
virtual ExitCode Entry();
protected:
wxSoundSyncOnlyAdaptor *m_adapt;
wxSoundData *m_data;
unsigned m_flags;
};
#endif // wxUSE_THREADS
// This class turns wxSoundBackend that doesn't support asynchronous playback
// into one that does
class wxSoundSyncOnlyAdaptor : public wxSoundBackend
{
public:
wxSoundSyncOnlyAdaptor(wxSoundBackend *backend)
: m_backend(backend), m_playing(false) {}
~wxSoundSyncOnlyAdaptor()
{
delete m_backend;
}
wxString GetName() const
{
return m_backend->GetName();
}
int GetPriority() const
{
return m_backend->GetPriority();
}
bool IsAvailable() const
{
return m_backend->IsAvailable();
}
bool HasNativeAsyncPlayback() const
{
return true;
}
bool Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status);
void Stop();
bool IsPlaying() const;
private:
friend class wxSoundAsyncPlaybackThread;
wxSoundBackend *m_backend;
bool m_playing;
#if wxUSE_THREADS
// player thread holds this mutex and releases it after it finishes
// playing, so that the main thread knows when it can play sound
wxMutex m_mutexRightToPlay;
wxSoundPlaybackStatus m_status;
#endif
};
#if wxUSE_THREADS
wxThread::ExitCode wxSoundAsyncPlaybackThread::Entry()
{
m_adapt->m_backend->Play(m_data, m_flags & ~wxSOUND_ASYNC,
&m_adapt->m_status);
m_data->DecRef();
m_adapt->m_playing = false;
m_adapt->m_mutexRightToPlay.Unlock();
wxLogTrace(_T("sound"), _T("terminated async playback thread"));
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -