* Added wxMMedia in the repository so people interrested in it can work on it
* WARNING! It is quite unstable on Windows and it doesn't work on Linux for the moment because I didn't finish fixing the CODEC stream. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@975 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
384
utils/wxMMedia/sndwin.cpp
Normal file
384
utils/wxMMedia/sndwin.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: sndwin.cpp
|
||||
// Purpose: wxMMedia
|
||||
// Author: Guilhem Lavaux
|
||||
// Created: 1997
|
||||
// Updated: 1998
|
||||
// Copyright: (C) 1997, 1998, Guilhem Lavaux
|
||||
// License: wxWindows license
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef WX_PRECOMP
|
||||
#include "wx/wxprec.h"
|
||||
#else
|
||||
#include "wx/wx.h"
|
||||
#endif
|
||||
#include <wx/msw/private.h>
|
||||
|
||||
#define WXMMEDIA_INTERNAL
|
||||
#include "sndwin.h"
|
||||
|
||||
#define MMD_WIN_IO_BSIZE 16384
|
||||
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
wxSndWinFragment::wxSndWinFragment(wxSound& io_drv)
|
||||
: wxFragmentBuffer(io_drv)
|
||||
{
|
||||
}
|
||||
|
||||
wxSndWinFragment::~wxSndWinFragment(void)
|
||||
{
|
||||
}
|
||||
|
||||
void wxSndWinFragment::AllocIOBuffer(void)
|
||||
{
|
||||
wxWinSound *w_snd = (wxWinSound *) m_iodrv;
|
||||
wxUint8 i;
|
||||
|
||||
m_maxoq = 5;
|
||||
m_maxiq = 5;
|
||||
|
||||
m_lstoptrs = m_optrs = new wxFragBufPtr[m_maxoq];
|
||||
m_lstiptrs = m_iptrs = new wxFragBufPtr[m_maxiq];
|
||||
|
||||
for (i=0;i<m_maxoq;i++) {
|
||||
m_lstoptrs[i].size = MMD_WIN_IO_BSIZE;
|
||||
m_lstoptrs[i].ptr = 0;
|
||||
m_lstoptrs[i].buffers = new wxList();
|
||||
m_lstoptrs[i].state = wxBUFFER_FREE;
|
||||
|
||||
w_snd->PrepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
|
||||
}
|
||||
|
||||
for (i=0;i<m_maxiq;i++) {
|
||||
m_lstiptrs[i].size = MMD_WIN_IO_BSIZE;
|
||||
m_lstiptrs[i].ptr = 0;
|
||||
m_lstiptrs[i].buffers = new wxList();
|
||||
m_lstiptrs[i].state = wxBUFFER_FREE;
|
||||
|
||||
w_snd->PrepareHeader(m_lstiptrs[i], wxSND_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void wxSndWinFragment::FreeIOBuffer(void)
|
||||
{
|
||||
wxWinSound *w_snd = (wxWinSound *)m_iodrv;
|
||||
wxUint8 i;
|
||||
|
||||
if (!m_lstoptrs && !m_lstiptrs)
|
||||
return;
|
||||
|
||||
for (i=0;i<m_maxoq;i++) {
|
||||
w_snd->UnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
|
||||
delete m_lstoptrs[i].buffers;
|
||||
}
|
||||
|
||||
for (i=0;i<m_maxiq;i++) {
|
||||
w_snd->UnprepareHeader(m_lstiptrs[i], wxSND_INPUT);
|
||||
delete m_lstiptrs[i].buffers;
|
||||
}
|
||||
|
||||
delete[] m_lstoptrs;
|
||||
delete[] m_lstiptrs;
|
||||
|
||||
m_lstoptrs = m_lstiptrs = NULL;
|
||||
m_maxoq = m_maxiq = 0;
|
||||
}
|
||||
|
||||
void wxSndWinFragment::WaitForAll()
|
||||
{
|
||||
bool buf_busy = TRUE;
|
||||
int i;
|
||||
|
||||
m_dontq = TRUE;
|
||||
|
||||
while (buf_busy) {
|
||||
buf_busy = FALSE;
|
||||
|
||||
for (i=0;i<m_maxoq;i++) {
|
||||
if (m_lstoptrs[i].state == wxBUFFER_FFILLED) {
|
||||
buf_busy = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wxYield();
|
||||
}
|
||||
|
||||
m_dontq = FALSE;
|
||||
FreeBufToFree(TRUE);
|
||||
}
|
||||
|
||||
bool wxSndWinFragment::OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode)
|
||||
{
|
||||
wxSndWinInfo *info = (wxSndWinInfo *)ptr->user_data;
|
||||
wxWinSound *w_snd = (wxWinSound *)m_iodrv;
|
||||
MMRESULT result;
|
||||
|
||||
switch (mode) {
|
||||
case wxSND_INPUT:
|
||||
result = waveInAddBuffer(w_snd->internal->devin_id, info->hdr,
|
||||
sizeof(WAVEHDR));
|
||||
break;
|
||||
case wxSND_OUTPUT:
|
||||
result = waveOutWrite(w_snd->internal->devout_id, info->hdr,
|
||||
sizeof(WAVEHDR));
|
||||
printf("WINOUT: result=%d\n", result);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wxWinSound::wxWinSound(void)
|
||||
: wxSound(),
|
||||
fragments(*this)
|
||||
{
|
||||
internal = new wxWinSoundInternal;
|
||||
internal->devout_id = 0;
|
||||
internal->devin_id = 0;
|
||||
internal->sndWin = 0;
|
||||
|
||||
wout_opened = FALSE;
|
||||
win_opened = FALSE;
|
||||
curr_o_srate = (wxUint32)-1;
|
||||
curr_o_bps = (wxUint8)-1;
|
||||
curr_o_stereo = (bool)-1;
|
||||
curr_i_srate = (wxUint32)-1;
|
||||
curr_i_bps = (wxUint8)-1;
|
||||
curr_i_stereo = (bool)-1;
|
||||
}
|
||||
|
||||
wxWinSound::~wxWinSound(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
fragments.WaitForAll();
|
||||
|
||||
if (wout_opened)
|
||||
waveOutReset(internal->devout_id);
|
||||
if (win_opened)
|
||||
waveInReset(internal->devout_id);
|
||||
|
||||
fragments.FreeIOBuffer();
|
||||
|
||||
if (wout_opened)
|
||||
waveOutClose(internal->devout_id);
|
||||
if (win_opened)
|
||||
waveInClose(internal->devin_id);
|
||||
|
||||
if (internal->sndWin)
|
||||
::DestroyWindow(internal->sndWin);
|
||||
|
||||
delete internal;
|
||||
}
|
||||
|
||||
bool wxWinSound::Wakeup(wxSndBuffer& buf)
|
||||
{
|
||||
if (!Reopen(buf, FALSE)) {
|
||||
buf.Clear(wxSND_BUFLOCKED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fragments.OnBufferFinished(NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wxWinSound::PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag,
|
||||
wxSndMode mode)
|
||||
{
|
||||
wxSndWinInfo *info;
|
||||
WAVEHDR *hdr;
|
||||
|
||||
if ((mode == wxSND_INPUT && !win_opened) ||
|
||||
(mode == wxSND_OUTPUT && !wout_opened))
|
||||
return;
|
||||
|
||||
info = new wxSndWinInfo;
|
||||
|
||||
info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, frag.size);
|
||||
info->h_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
|
||||
|
||||
info->data = (char *)GlobalLock(info->h_data);
|
||||
hdr = info->hdr = (WAVEHDR *)GlobalLock(info->h_hdr);
|
||||
|
||||
memset(hdr, 0, sizeof(*hdr));
|
||||
hdr->lpData = info->data;
|
||||
hdr->dwBufferLength = frag.size;
|
||||
hdr->dwUser = (DWORD)&frag;
|
||||
hdr->dwFlags = WHDR_DONE;
|
||||
|
||||
if (mode == wxSND_INPUT) {
|
||||
MMRESULT result = waveInPrepareHeader(internal->devin_id, hdr,
|
||||
sizeof(WAVEHDR));
|
||||
|
||||
printf("prepareIn = %d\n", result);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
wxExit();
|
||||
} else {
|
||||
MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr,
|
||||
sizeof(WAVEHDR));
|
||||
printf("prepareOut = %d\n", result);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
wxExit();
|
||||
}
|
||||
|
||||
frag.user_data = (char *)info;
|
||||
frag.data = info->data;
|
||||
}
|
||||
|
||||
void wxWinSound::UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag,
|
||||
wxSndMode mode)
|
||||
{
|
||||
wxSndWinInfo *info = (wxSndWinInfo *)frag.user_data;
|
||||
|
||||
if ((mode == wxSND_INPUT && !win_opened) ||
|
||||
(mode == wxSND_OUTPUT && !wout_opened))
|
||||
return;
|
||||
|
||||
MMRESULT result;
|
||||
|
||||
if (mode == wxSND_INPUT) {
|
||||
result = waveInUnprepareHeader(internal->devin_id, info->hdr, sizeof(*info->hdr));
|
||||
} else {
|
||||
result = waveOutUnprepareHeader(internal->devout_id, info->hdr, sizeof(*info->hdr));
|
||||
}
|
||||
|
||||
printf("unprepare = %d\n", result);
|
||||
|
||||
GlobalUnlock(info->h_hdr);
|
||||
GlobalUnlock(info->h_data);
|
||||
|
||||
GlobalFree(info->h_hdr);
|
||||
GlobalFree(info->h_data);
|
||||
|
||||
delete info;
|
||||
}
|
||||
|
||||
extern char wxCanvasClassName[];
|
||||
|
||||
LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND hWnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message) {
|
||||
case MM_WOM_DONE: {
|
||||
wxWinSound *snd_drv = (wxWinSound *)GetWindowLong(hWnd, GWL_USERDATA);
|
||||
WAVEHDR *hdr = (WAVEHDR *)lParam;
|
||||
wxFragmentBuffer::wxFragBufPtr *buf =
|
||||
(wxFragmentBuffer::wxFragBufPtr *)hdr->dwUser;
|
||||
|
||||
// To be sure ...
|
||||
hdr->dwFlags |= WHDR_DONE;
|
||||
|
||||
snd_drv->fragments.OnBufferFinished(buf);
|
||||
break;
|
||||
}
|
||||
case MM_WOM_OPEN:
|
||||
printf("wave Open ack\n");
|
||||
break;
|
||||
case MM_WOM_CLOSE:
|
||||
printf("wave Close ack\n");
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return (LRESULT)0;
|
||||
}
|
||||
|
||||
void wxWinSound::StopBuffer(wxSndBuffer& buf)
|
||||
{
|
||||
buf.HardLock();
|
||||
buf.Set(wxSND_BUFSTOP);
|
||||
fragments.AbortBuffer(buf);
|
||||
buf.HardUnlock();
|
||||
|
||||
while (buf.IsSet(wxSND_BUFSTOP))
|
||||
wxYield();
|
||||
}
|
||||
|
||||
bool wxWinSound::Reopen(wxSndBuffer& buf, bool force)
|
||||
{
|
||||
WAVEFORMATEX wformat;
|
||||
|
||||
if ((buf.GetSampleRate() != curr_o_srate) ||
|
||||
(buf.GetBps() != curr_o_bps) ||
|
||||
(buf.GetStereo() != curr_o_stereo) ||
|
||||
(buf.GetMode() != curr_mode))
|
||||
force = TRUE;
|
||||
|
||||
if (force) {
|
||||
wxUint32 *curr_srate =
|
||||
(buf.GetMode() == wxSND_OUTPUT) ? &curr_o_srate : &curr_i_srate;
|
||||
wxUint8 *curr_bps =
|
||||
(buf.GetMode() == wxSND_OUTPUT) ? &curr_o_bps : &curr_i_bps;
|
||||
bool *curr_stereo =
|
||||
(buf.GetMode() == wxSND_OUTPUT) ? &curr_o_stereo : &curr_i_stereo;
|
||||
|
||||
fragments.WaitForAll();
|
||||
fragments.FreeIOBuffer();
|
||||
|
||||
if (!internal->sndWin) {
|
||||
FARPROC proc = MakeProcInstance((FARPROC)wxSoundHandlerWndProc, wxGetInstance());
|
||||
|
||||
internal->sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0,
|
||||
0, 0, 0, 0, NULL, (HMENU) NULL,
|
||||
wxGetInstance(), 0);
|
||||
|
||||
::SetWindowLong(internal->sndWin, GWL_WNDPROC,
|
||||
(LONG)proc);
|
||||
::SetWindowLong(internal->sndWin, GWL_USERDATA, (LONG) this);
|
||||
}
|
||||
|
||||
if (wout_opened) {
|
||||
waveOutClose(internal->devout_id);
|
||||
wout_opened = FALSE;
|
||||
}
|
||||
if (win_opened) {
|
||||
waveInClose(internal->devin_id);
|
||||
win_opened = FALSE;
|
||||
}
|
||||
|
||||
*curr_srate = buf.GetSampleRate();
|
||||
*curr_bps = buf.GetBps();
|
||||
*curr_stereo = buf.GetStereo();
|
||||
wformat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wformat.nChannels = curr_o_stereo+1;
|
||||
|
||||
wformat.nSamplesPerSec = curr_o_srate;
|
||||
wformat.nBlockAlign = curr_o_bps / 8 * wformat.nChannels;
|
||||
wformat.nAvgBytesPerSec =
|
||||
wformat.nSamplesPerSec * wformat.nBlockAlign;
|
||||
wformat.wBitsPerSample = curr_o_bps;
|
||||
wformat.cbSize = 0;
|
||||
|
||||
if (buf.GetMode() == wxSND_OUTPUT) {
|
||||
MMRESULT result = waveOutOpen(&internal->devout_id,
|
||||
WAVE_MAPPER, &wformat,
|
||||
(DWORD)internal->sndWin, (DWORD)this,
|
||||
CALLBACK_WINDOW);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
return FALSE;
|
||||
internal->devin_id = 0;
|
||||
wout_opened = TRUE;
|
||||
curr_mode = wxSND_OUTPUT;
|
||||
|
||||
fragments.AllocIOBuffer();
|
||||
}
|
||||
else {
|
||||
MMRESULT result = waveInOpen(&internal->devin_id,
|
||||
WAVE_MAPPER, &wformat,
|
||||
(DWORD)internal->sndWin, (DWORD)this,
|
||||
CALLBACK_FUNCTION);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
return FALSE;
|
||||
internal->devout_id = 0;
|
||||
win_opened = TRUE;
|
||||
curr_mode = wxSND_INPUT;
|
||||
|
||||
fragments.AllocIOBuffer();
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
Reference in New Issue
Block a user