⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sound.cpp

📁 A*算法 A*算法 A*算法 A*算法A*算法A*算法
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/////////////////////////////////////////////////////////////////////////////
// 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 + -