📄 sndwin.cpp
字号:
// --------------------------------------------------------------------------
// Name: sndwin.cpp
// Purpose:
// Date: 08/11/1999
// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
// CVSID: $Id: sndwin.cpp,v 1.12 2005/09/23 12:47:52 MR Exp $
// wxWindows licence
// --------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __WINDOWS__
#ifndef WX_PRECOMP
#include "wx/defs.h"
#include "wx/app.h"
#include "wx/string.h"
#endif
#include "wx/module.h"
#include "wx/msw/private.h"
// -------------------------------------------------------------------------
// MMedia headers
// -------------------------------------------------------------------------
#include "wx/mmedia/sndbase.h"
#include "wx/mmedia/sndwin.h"
#include "wx/mmedia/sndpcm.h"
// -------------------------------------------------------------------------
// System headers
// -------------------------------------------------------------------------
#include <windows.h>
#include <mmsystem.h>
// -------------------------------------------------------------------------
// External definitions, forward, ...
// -------------------------------------------------------------------------
typedef struct _wxSoundInternal wxSoundInternal;
typedef struct _wxSoundInfoHeader wxSoundInfoHeader;
extern const wxChar *wxCanvasClassName;
wxList *wxSoundHandleList = NULL;
static inline wxSoundStreamWin *wxFindSoundFromHandle(WXHWND hWnd)
{
wxObjectList::compatibility_iterator node = wxSoundHandleList->Find((long)hWnd);
if (!node)
return NULL;
return (wxSoundStreamWin *)node->GetData();
}
struct _wxSoundInternal {
HWND m_sndWin;
HWAVEIN m_devin;
HWAVEOUT m_devout;
bool m_output_enabled, m_input_enabled;
};
struct _wxSoundInfoHeader {
HGLOBAL m_h_header, m_h_data;
char *m_data;
WAVEHDR *m_header;
int m_mode;
bool m_playing, m_recording;
wxUint32 m_position, m_size;
wxSoundStreamWin *m_driver;
};
#define WXSOUND_MAX_QUEUE 10
wxSoundStreamWin::wxSoundStreamWin()
{
wxSoundFormatPcm pcm;
m_production_started = false;
m_internal = new wxSoundInternal;
if (!m_internal) {
m_snderror = wxSOUND_MEMERROR;
m_internal = NULL;
return;
}
m_snderror = wxSOUND_NOERROR;
// Setup defaults
CreateSndWindow();
SetSoundFormat(pcm);
m_internal->m_input_enabled = false;
m_internal->m_output_enabled = false;
m_waiting_for = false;
if (!OpenDevice(wxSOUND_OUTPUT)) {
m_snderror = wxSOUND_NOERROR; //next call to OpenDevice won't do this
if (!OpenDevice(wxSOUND_INPUT))
return;
}
CloseDevice();
}
wxSoundStreamWin::~wxSoundStreamWin()
{
if (m_internal) {
if (m_production_started)
StopProduction();
DestroySndWindow();
delete m_internal;
}
}
// -----------------------------------------------------------------------
// _wxSoundHandlerWndProc: Window callback to handle buffer completion
// -----------------------------------------------------------------------
LRESULT APIENTRY _EXPORT
_wxSoundHandlerWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM WXUNUSED(lParam))
{
wxSoundStreamWin *sndwin;
sndwin = wxFindSoundFromHandle((WXHWND)hWnd);
if (!sndwin)
return (LRESULT)0;
switch (message) {
case MM_WOM_DONE:
sndwin->NotifyDoneBuffer(wParam, wxSOUND_OUTPUT);
break;
case MM_WIM_DATA:
sndwin->NotifyDoneBuffer(wParam, wxSOUND_INPUT);
break;
default:
break;
}
return (LRESULT)0;
}
// -----------------------------------------------------------------------
// CreateSndWindow() creates an hidden window which will receive the sound
// events
// -----------------------------------------------------------------------
void wxSoundStreamWin::CreateSndWindow()
{
FARPROC proc = MakeProcInstance((FARPROC)_wxSoundHandlerWndProc,
wxGetInstance());
// NB: class name must be kept in sync with wxCanvasClassName in
// src/msw/app.cpp!
m_internal->m_sndWin = ::CreateWindow(wxT("wxWindowClass"), NULL, 0,
0, 0, 0, 0, NULL, (HMENU) NULL,
wxGetInstance(), NULL);
GetLastError();
::SetWindowLong(m_internal->m_sndWin, GWL_WNDPROC, (LONG)proc);
// Add this window to the sound handle list so we'll be able to redecode
// the "magic" number.
wxSoundHandleList->Append((long)m_internal->m_sndWin, (wxObject *)this);
}
// -----------------------------------------------------------------------
// DestroySndWindow() destroys the hidden window
// -----------------------------------------------------------------------
void wxSoundStreamWin::DestroySndWindow()
{
if (m_internal->m_sndWin) {
::DestroyWindow(m_internal->m_sndWin);
wxSoundHandleList->DeleteObject((wxObject *)this);
}
}
// -------------------------------------------------------------------------
// OpenDevice(int mode) initializes the windows driver for a "mode"
// operation. mode is a bit mask: if the bit "wxSOUND_OUTPUT" is set,
// the driver is opened for output operation, and if the bit "wxSOUND_INPUT"
// is set, then the driver is opened for input operation. The two modes
// aren't exclusive.
// The initialization parameters (sample rate, ...) are taken from the
// m_sndformat object.
// At the end, OpenDevice() calls AllocHeaders() to initialize the Sound IO
// queue.
// -------------------------------------------------------------------------
bool wxSoundStreamWin::OpenDevice(int mode)
{
wxSoundFormatPcm *pcm;
WAVEFORMATEX wformat;
if (!m_sndformat) {
m_snderror = wxSOUND_INVFRMT;
return false;
}
pcm = (wxSoundFormatPcm *)m_sndformat;
wformat.wFormatTag = WAVE_FORMAT_PCM;
wformat.nChannels = pcm->GetChannels();
wformat.nBlockAlign = wformat.nChannels * pcm->GetBPS() / 8;
wformat.nSamplesPerSec = pcm->GetSampleRate();
wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign;
wformat.wBitsPerSample = pcm->GetBPS();
wformat.cbSize = 0;
// -----------------------------------
// Open the driver for Output operation
// -----------------------------------
if (mode & wxSOUND_OUTPUT) {
MMRESULT result;
result = waveOutOpen(&m_internal->m_devout,
WAVE_MAPPER, &wformat,
(DWORD)m_internal->m_sndWin, 0,
CALLBACK_WINDOW);
if (result != MMSYSERR_NOERROR) {
m_snderror = wxSOUND_INVDEV;
return false;
}
m_output_frag_out = WXSOUND_MAX_QUEUE-1;
m_current_frag_out = 0;
m_internal->m_output_enabled = true;
}
// -----------------------------------
// Open the driver for Input operation
// -----------------------------------
if (mode & wxSOUND_INPUT) {
MMRESULT result;
result = waveInOpen(&m_internal->m_devin,
WAVE_MAPPER, &wformat,
(DWORD)m_internal->m_sndWin, 0,
CALLBACK_WINDOW);
if (result != MMSYSERR_NOERROR) {
m_snderror = wxSOUND_INVDEV;
return false;
}
m_current_frag_in = WXSOUND_MAX_QUEUE-1;
m_input_frag_in = 0;
m_internal->m_input_enabled = true;
}
if (mode & wxSOUND_OUTPUT) {
if (!AllocHeaders(wxSOUND_OUTPUT)) {
CloseDevice();
return false;
}
}
if (mode & wxSOUND_INPUT) {
if (!AllocHeaders(wxSOUND_INPUT)) {
CloseDevice();
return false;
}
}
return true;
}
// -------------------------------------------------------------------------
// CloseDevice() closes the driver handles and frees memory allocated for
// IO queues.
// -------------------------------------------------------------------------
void wxSoundStreamWin::CloseDevice()
{
if (m_internal->m_output_enabled) {
FreeHeaders(wxSOUND_OUTPUT);
m_internal->m_output_enabled = false;
waveOutClose(m_internal->m_devout);
}
if (m_internal->m_input_enabled) {
FreeHeaders(wxSOUND_INPUT);
m_internal->m_input_enabled = false;
waveInClose(m_internal->m_devin);
}
}
// -------------------------------------------------------------------------
// AllocHeader(int mode)
//
// mode has the same mean as in OpenDevice() except that here the two flags
// must be exclusive.
// AllocHeader() initializes an element of an operation (this can be input
// or output). It means it allocates the sound header's memory block
// and "prepares" it (It is needed by Windows). At the same time, it sets
// private datas so we can the header's owner (See callback).
//
// It returns the new allocated block or NULL.
// -------------------------------------------------------------------------
wxSoundInfoHeader *wxSoundStreamWin::AllocHeader(int mode)
{
wxSoundInfoHeader *info;
WAVEHDR *header;
// Some memory allocation
info = new wxSoundInfoHeader;
info->m_h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, GetBestSize());
info->m_h_header = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
if (!info->m_h_data || !info->m_h_header) {
delete info;
m_snderror = wxSOUND_MEMERROR;
return NULL;
}
// Get the two pointers from the system
info->m_data = (char *)GlobalLock(info->m_h_data);
info->m_header = (WAVEHDR *)GlobalLock(info->m_h_header);
// Set the header's mode
info->m_mode = mode;
// Set the parent of the header
info->m_driver = this;
// Clean it up
ClearHeader(info);
header = info->m_header;
// Initialize Windows variables
header->lpData = info->m_data;
header->dwBufferLength = GetBestSize();
header->dwUser = (DWORD)info;
header->dwFlags = WHDR_DONE;
// "Prepare" the header
if (mode == wxSOUND_INPUT) {
MMRESULT result;
result = waveInPrepareHeader(m_internal->m_devin, header,
sizeof(WAVEHDR));
if (result != MMSYSERR_NOERROR) {
// If something goes wrong, free everything.
GlobalUnlock(info->m_data);
GlobalUnlock(info->m_header);
GlobalFree(info->m_h_data);
GlobalFree(info->m_h_header);
delete info;
m_snderror = wxSOUND_IOERROR;
return NULL;
}
} else if (mode == wxSOUND_OUTPUT) {
MMRESULT result;
result = waveOutPrepareHeader(m_internal->m_devout, header,
sizeof(WAVEHDR));
if (result != MMSYSERR_NOERROR) {
// If something goes wrong, free everything.
GlobalUnlock(info->m_data);
GlobalUnlock(info->m_header);
GlobalFree(info->m_h_data);
GlobalFree(info->m_h_header);
delete info;
m_snderror = wxSOUND_IOERROR;
return NULL;
}
}
return info;
}
// -------------------------------------------------------------------------
// AllocHeaders(int mode)
//
// "mode" has the same mean as for OpenDevice() except that the two flags must
// be exclusive.
// AllocHeaders() allocates WXSOUND_MAX_QUEUE (= 128) blocks for an operation
// queue. It uses AllocHeader() for each element.
//
// Once it has allocated all blocks, it returns true and if an error occurred
// it returns false.
// -------------------------------------------------------------------------
bool wxSoundStreamWin::AllocHeaders(int mode)
{
int i;
wxSoundInfoHeader **headers;
if (mode == wxSOUND_OUTPUT)
headers = m_headers_play = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -