From 503aa33d55183bcbd8444e36ed8c273a18dab72f Mon Sep 17 00:00:00 2001 From: Guilhem Lavaux Date: Wed, 25 Aug 1999 17:22:26 +0000 Subject: [PATCH] Added wxSound for Windows support (successful WAV playback on VC++ 5) Fixes/Updates for the rest. PNM decoder uses now wxBufferedInputStream to (to be tested). Support for G72X is on the road ... git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3487 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagpnm.cpp | 17 +- utils/wxMMedia2/lib/sndaiff.cpp | 2 + utils/wxMMedia2/lib/sndbase.h | 3 + utils/wxMMedia2/lib/sndfile.cpp | 49 ++-- utils/wxMMedia2/lib/sndoss.cpp | 11 + utils/wxMMedia2/lib/sndoss.h | 3 +- utils/wxMMedia2/lib/sndwin.cpp | 537 ++++++++++++++++++++++++++++++++++++++++ utils/wxMMedia2/lib/sndwin.h | 63 +++++ 8 files changed, 653 insertions(+), 32 deletions(-) create mode 100644 utils/wxMMedia2/lib/sndwin.cpp create mode 100644 utils/wxMMedia2/lib/sndwin.h diff --git a/src/common/imagpnm.cpp b/src/common/imagpnm.cpp index e46916c..75a0b49 100644 --- a/src/common/imagpnm.cpp +++ b/src/common/imagpnm.cpp @@ -64,10 +64,11 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE * Read the PNM header */ - wxTextInputStream text_stream(stream); + wxBufferedInputStream buf_stream(stream); + wxTextInputStream text_stream(buf_stream); - Skip_Comment(stream); - if (stream.GetC()==_T('P')) c=stream.GetC(); + Skip_Comment(buf_stream); + if (buf_stream.GetC()==_T('P')) c=buf_stream.GetC(); switch (c) { @@ -84,9 +85,9 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE } text_stream >> line; // for the \n - Skip_Comment(stream); + Skip_Comment(buf_stream); text_stream >> width >> height ; - Skip_Comment(stream); + Skip_Comment(buf_stream); text_stream >> maxval; //cout << width << " " << height << " " << maxval << endl; @@ -108,7 +109,7 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE value=text_stream.Read32(); *ptr++=(unsigned char)value; - if (stream.LastError()!=wxSTREAM_NOERROR) + if (buf_stream.LastError()!=wxSTREAM_NOERROR) { wxLogError(_T("Loading PNM image : file seems truncated.")); return FALSE; @@ -116,11 +117,11 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE } } if (c=='6') // Raw RGB - stream.Read( ptr, 3*width*height ); + buf_stream.Read( ptr, 3*width*height ); image->SetMask( FALSE ); - return (stream.LastError()==wxStream_NOERROR || stream.LastError()==wxStream_EOF); + return (buf_stream.LastError()==wxStream_NOERROR || buf_stream.LastError()==wxStream_EOF); } bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) ) diff --git a/utils/wxMMedia2/lib/sndaiff.cpp b/utils/wxMMedia2/lib/sndaiff.cpp index a65f875..9ea8eb0 100644 --- a/utils/wxMMedia2/lib/sndaiff.cpp +++ b/utils/wxMMedia2/lib/sndaiff.cpp @@ -116,11 +116,13 @@ bool wxSoundAiff::PrepareToPlay() bool wxSoundAiff::PrepareToRecord(unsigned long time) { + // TODO return FALSE; } bool wxSoundAiff::FinishRecording() { + // TODO return FALSE; } diff --git a/utils/wxMMedia2/lib/sndbase.h b/utils/wxMMedia2/lib/sndbase.h index 26fae17..c49aefa 100644 --- a/utils/wxMMedia2/lib/sndbase.h +++ b/utils/wxMMedia2/lib/sndbase.h @@ -98,6 +98,9 @@ class wxSoundStream { wxSoundError GetError() const { return m_snderror; } size_t GetLastAccess() const { return m_lastcount; } + // This is only useful for device (I think). + virtual bool QueueFilled() const { return TRUE; } + protected: // Current sound format wxSoundFormatBase *m_sndformat; diff --git a/utils/wxMMedia2/lib/sndfile.cpp b/utils/wxMMedia2/lib/sndfile.cpp index 6525d2b..e3dfd1e 100644 --- a/utils/wxMMedia2/lib/sndfile.cpp +++ b/utils/wxMMedia2/lib/sndfile.cpp @@ -158,10 +158,11 @@ bool wxSoundFileStream::Play() if (!PrepareToPlay()) return FALSE; + m_state = wxSOUND_FILE_PLAYING; + if (!StartProduction(wxSOUND_OUTPUT)) return FALSE; - m_state = wxSOUND_FILE_PLAYING; return TRUE; } @@ -175,10 +176,10 @@ bool wxSoundFileStream::Record(unsigned long time) m_len = m_sndformat->GetBytesFromTime(time); + m_state = wxSOUND_FILE_RECORDING; if (!StartProduction(wxSOUND_INPUT)) return FALSE; - m_state = wxSOUND_FILE_RECORDING; return TRUE; } @@ -265,30 +266,32 @@ void wxSoundFileStream::OnSoundEvent(int evt) size_t len = m_sndio->GetBestSize(); char *buffer; - buffer = new char[m_sndio->GetBestSize()]; + buffer = new char[len]; wxSoundStream::OnSoundEvent(evt); - switch(evt) { - case wxSOUND_INPUT: - if (len > m_len) - len = m_len; - - len = m_codec.Read(buffer, len).GetLastAccess(); - PutData(buffer, len); - m_len -= len; - if (m_len == 0) { - Stop(); - return; - } - break; - case wxSOUND_OUTPUT: - len = GetData(buffer, len); - if (len == 0) { - Stop(); - return; + while (!m_sndio->QueueFilled()) { + switch(evt) { + case wxSOUND_INPUT: + if (len > m_len) + len = m_len; + + len = m_codec.Read(buffer, len).GetLastAccess(); + PutData(buffer, len); + m_len -= len; + if (m_len == 0) { + Stop(); + return; + } + break; + case wxSOUND_OUTPUT: + len = GetData(buffer, len); + if (len == 0) { + Stop(); + return; + } + m_codec.Write(buffer, len); + break; } - m_codec.Write(buffer, len); - break; } delete[] buffer; } diff --git a/utils/wxMMedia2/lib/sndoss.cpp b/utils/wxMMedia2/lib/sndoss.cpp index 8b890a0..e794b20 100644 --- a/utils/wxMMedia2/lib/sndoss.cpp +++ b/utils/wxMMedia2/lib/sndoss.cpp @@ -46,6 +46,7 @@ wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name) close(m_fd); m_oss_stop = TRUE; + m_q_filled = TRUE; } wxSoundStreamOSS::~wxSoundStreamOSS() @@ -64,6 +65,7 @@ wxSoundStream& wxSoundStreamOSS::Read(void *buffer, size_t len) int ret; m_lastcount = (size_t)ret = read(m_fd, buffer, len); + m_q_filled = TRUE; if (ret < 0) m_snderror = wxSOUND_IOERR; @@ -78,6 +80,7 @@ wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, size_t len) int ret; m_lastcount = (size_t)ret = write(m_fd, buffer, len); + m_q_filled = TRUE; if (ret < 0) m_snderror = wxSOUND_IOERR; @@ -220,6 +223,7 @@ static void _wxSound_OSS_CBack(gpointer data, int source, void wxSoundStreamOSS::WakeUpEvt(int evt) { + m_q_filled = FALSE; OnSoundEvent(evt); } @@ -263,6 +267,7 @@ bool wxSoundStreamOSS::StartProduction(int evt) ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig); m_oss_stop = FALSE; + m_q_filled = FALSE; return TRUE; } @@ -278,9 +283,15 @@ bool wxSoundStreamOSS::StopProduction() close(m_fd); m_oss_stop = TRUE; + m_q_filled = TRUE; return TRUE; } +bool wxSoundStreamOSS::QueueFilled() const +{ + return m_q_filled; +} + // // Detect the closest format (The best). // diff --git a/utils/wxMMedia2/lib/sndoss.h b/utils/wxMMedia2/lib/sndoss.h index 1fa28c0..84fc3f3 100644 --- a/utils/wxMMedia2/lib/sndoss.h +++ b/utils/wxMMedia2/lib/sndoss.h @@ -35,6 +35,7 @@ class wxSoundStreamOSS : public wxSoundStream { bool StopProduction(); void SetDuplexMode(bool duplex) {} + bool QueueFilled() const; // You should not call this. void WakeUpEvt(int evt); @@ -42,7 +43,7 @@ class wxSoundStreamOSS : public wxSoundStream { int m_fd; wxUint32 m_bufsize; int m_tag; - bool m_oss_stop; + bool m_oss_stop, m_q_filled; wxString m_devname; private: diff --git a/utils/wxMMedia2/lib/sndwin.cpp b/utils/wxMMedia2/lib/sndwin.cpp new file mode 100644 index 0000000..2b89209 --- /dev/null +++ b/utils/wxMMedia2/lib/sndwin.cpp @@ -0,0 +1,537 @@ +// -------------------------------------------------------------------------- +// Name: sndwin.cpp +// Purpose: +// Date: 08/11/1999 +// Author: Guilhem Lavaux (C) 1999 +// CVSID: $Id$ +// -------------------------------------------------------------------------- +#include + +#include +#include +#include +#include "sndbase.h" +#include "sndwin.h" +#include "sndpcm.h" + +#include +#include + +typedef struct _wxSoundInternal wxSoundInternal; +typedef struct _wxSoundInfoHeader wxSoundInfoHeader; + +extern char wxCanvasClassName[]; + +wxList *wxSoundHandleList = NULL; + +static inline wxSoundStreamWin *wxFindSoundFromHandle(WXHWND hWnd) +{ + wxNode *node = wxSoundHandleList->Find((long)hWnd); + if (!node) + return NULL; + return (wxSoundStreamWin *)node->Data(); +} + +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 128 + +wxSoundStreamWin::wxSoundStreamWin() +{ + wxSoundFormatPcm pcm; + + m_production_started = FALSE; + m_internal = new wxSoundInternal; + m_snderror = wxSOUND_NOERR; + + // Setup defaults + CreateSndWindow(); + SetSoundFormat(pcm); + + if (!OpenDevice(wxSOUND_OUTPUT)) + return; + + CloseDevice(); +} + +wxSoundStreamWin::~wxSoundStreamWin() +{ + if (m_production_started) + StopProduction(); + DestroySndWindow(); + + delete m_internal; +} + +LRESULT APIENTRY _EXPORT _wxSoundHandlerWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case MM_WOM_DONE: { + wxFindSoundFromHandle((WXHWND)hWnd)->NotifyDoneBuffer(wParam); + break; + } + default: + break; + } + return (LRESULT)0; +} + +void wxSoundStreamWin::CreateSndWindow() +{ + FARPROC proc = MakeProcInstance((FARPROC)_wxSoundHandlerWndProc, + wxGetInstance()); + int error; + + m_internal->m_sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0, + 0, 0, 0, 0, NULL, (HMENU) NULL, + wxGetInstance(), NULL); + + error = GetLastError(); + wxPrintf("%d\n", error); + + ::SetWindowLong(m_internal->m_sndWin, GWL_WNDPROC, (LONG)proc); + + wxSoundHandleList->Append((long)m_internal->m_sndWin, (wxObject *)this); +} + +void wxSoundStreamWin::DestroySndWindow() +{ + if (m_internal->m_sndWin) { + ::DestroyWindow(m_internal->m_sndWin); + wxSoundHandleList->DeleteObject((wxObject *)this); + } +} + +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 = pcm->GetBPS() / 8 * wformat.nChannels; + wformat.nAvgBytesPerSec = pcm->GetBytesFromTime(1); + wformat.nSamplesPerSec = pcm->GetSampleRate(); + wformat.wBitsPerSample = pcm->GetBPS(); + wformat.cbSize = 0; + + 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; + } + 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_input_frag_in = WXSOUND_MAX_QUEUE-1; + m_current_frag_in = 0; + + m_internal->m_input_enabled = TRUE; + } + + if (!AllocHeaders(mode)) { + CloseDevice(); + return FALSE; + } + return TRUE; +} + + +void wxSoundStreamWin::CloseDevice() +{ + if (m_internal->m_output_enabled) { + FreeHeaders(wxSOUND_OUTPUT); + waveOutReset(m_internal->m_devout); + waveOutClose(m_internal->m_devout); + } + + if (m_internal->m_input_enabled) { + FreeHeaders(wxSOUND_INPUT); + waveInReset(m_internal->m_devin); + waveInClose(m_internal->m_devin); + } + + m_internal->m_output_enabled = FALSE; + m_internal->m_input_enabled = FALSE; +} + +wxSoundInfoHeader *wxSoundStreamWin::AllocHeader(int mode) +{ + wxSoundInfoHeader *info; + WAVEHDR *header; + + 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_MEMERR; + return NULL; + } + + info->m_data = (char *)GlobalLock(info->m_h_data); + info->m_header = (WAVEHDR *)GlobalLock(info->m_h_header); + info->m_mode = mode; + info->m_driver = this; + ClearHeader(info); + + header = info->m_header; + + header->lpData = info->m_data; + header->dwBufferLength = GetBestSize(); + header->dwUser = (DWORD)info; + header->dwFlags = WHDR_DONE; + + if (mode == wxSOUND_INPUT) { + MMRESULT result; + + result = waveInPrepareHeader(m_internal->m_devin, header, + sizeof(WAVEHDR)); + + if (result != MMSYSERR_NOERROR) { + GlobalUnlock(info->m_data); + GlobalUnlock(info->m_header); + GlobalFree(info->m_h_data); + GlobalFree(info->m_h_header); + delete info; + + m_snderror = wxSOUND_IOERR; + return NULL; + } + } else if (mode == wxSOUND_OUTPUT) { + MMRESULT result; + + result = waveOutPrepareHeader(m_internal->m_devout, header, + sizeof(WAVEHDR)); + + if (result != MMSYSERR_NOERROR) { + GlobalUnlock(info->m_data); + GlobalUnlock(info->m_header); + GlobalFree(info->m_h_data); + GlobalFree(info->m_h_header); + delete info; + + m_snderror = wxSOUND_IOERR; + return NULL; + } + } + return info; +} + +bool wxSoundStreamWin::AllocHeaders(int mode) +{ + int i; + wxSoundInfoHeader **headers; + + if (mode == wxSOUND_OUTPUT) + headers = m_headers_play = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE]; + else + headers = m_headers_rec = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE]; + + memset(headers, 0, WXSOUND_MAX_QUEUE*sizeof(wxSoundInfoHeader *)); + + for (i=0;im_devout, header->m_header, sizeof(WAVEHDR)); + else + waveInUnprepareHeader(m_internal->m_devin, header->m_header, sizeof(WAVEHDR)); + + GlobalUnlock(header->m_data); + GlobalUnlock(header->m_header); + GlobalFree(header->m_h_header); + GlobalFree(header->m_h_data); + delete header; +} + +void wxSoundStreamWin::FreeHeaders(int mode) +{ + int i; + wxSoundInfoHeader ***headers; + + if (mode == wxSOUND_OUTPUT) + headers = &m_headers_play; + else + headers = &m_headers_rec; + + for (i=0;im_position != 0) { + memset(info->m_data + info->m_position, 0, info->m_size); + AddToQueue(info); + } + + if (!info->m_playing && !info->m_recording) + return; + + while (info->m_playing || info->m_recording) + wxYield(); +} + +bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader *info) +{ + MMRESULT result; + + if (info->m_mode == wxSOUND_INPUT) { + m_current_frag_in = (m_current_frag_in + 1) % WXSOUND_MAX_QUEUE; + result = waveInAddBuffer(m_internal->m_devin, + info->m_header, sizeof(WAVEHDR)); + if (result == MMSYSERR_NOERROR) + info->m_recording = TRUE; + else + return FALSE; + } else if (info->m_mode == wxSOUND_OUTPUT) { + result = waveOutWrite(m_internal->m_devout, + info->m_header, sizeof(WAVEHDR)); + if (result == MMSYSERR_NOERROR) + info->m_playing = TRUE; + else + return FALSE; + } + return TRUE; +} + +void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader *info) +{ + info->m_playing = FALSE; + info->m_recording = FALSE; + info->m_position = 0; + info->m_size = GetBestSize(); +} + +wxSoundInfoHeader *wxSoundStreamWin::NextFragmentOutput() +{ + if (m_headers_play[m_current_frag_out]->m_playing) { + m_current_frag_out = (m_current_frag_out + 1) % WXSOUND_MAX_QUEUE; + + if (m_headers_play[m_current_frag_out]->m_playing) + WaitFor(m_headers_play[m_current_frag_out]); + } + if (m_current_frag_out == m_output_frag_out) + m_queue_filled = TRUE; + return m_headers_play[m_current_frag_out]; +} + +wxSoundStream& wxSoundStreamWin::Write(const void *buffer, size_t len) +{ + m_lastcount = 0; + if (!m_internal->m_output_enabled) + return *this; + + while (len > 0) { + wxSoundInfoHeader *header; + size_t to_copy; + + header = NextFragmentOutput(); + + to_copy = (len > header->m_size) ? header->m_size : len; + memcpy(header->m_data + header->m_position, buffer, to_copy); + + header->m_position += to_copy; + header->m_size -= to_copy; + buffer = (((const char *)buffer) + to_copy); + len -= to_copy; + m_lastcount += to_copy; + + if (header->m_size == 0) + if (!AddToQueue(header)) { + m_snderror = wxSOUND_IOERR; + return *this; + } + } + return *this; +} + +wxSoundInfoHeader *wxSoundStreamWin::NextFragmentInput() +{ + wxSoundInfoHeader *header; + + // TODO // + header = m_headers_rec[m_current_frag_in]; + WaitFor(header); + + if (m_current_frag_in == m_input_frag_in) + m_queue_filled = TRUE; + + return header; +} + +wxSoundStream& wxSoundStreamWin::Read(void *buffer, size_t len) +{ + wxSoundInfoHeader *header; + size_t to_copy; + + m_lastcount = 0; + if (!m_internal->m_input_enabled) + return *this; + + while (len > 0) { + header = NextFragmentInput(); + + to_copy = (len > header->m_size) ? header->m_size : len; + memcpy(buffer, header->m_data + header->m_position, to_copy); + + header->m_position += to_copy; + header->m_size -= to_copy; + buffer = (((char *)buffer) + to_copy); + len -= to_copy; + m_lastcount += to_copy; + + if (header->m_size == 0) { + ClearHeader(header); + if (!AddToQueue(header)) { + m_snderror = wxSOUND_IOERR; + return *this; + } + } + } + return *this; +} + +void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 dev_handle) +{ + wxSoundInfoHeader *info; + + if (dev_handle == (wxUint32)m_internal->m_devout) { + m_output_frag_out = (m_output_frag_out + 1) % WXSOUND_MAX_QUEUE; + info = m_headers_play[m_output_frag_out]; + ClearHeader(info); + m_queue_filled = FALSE; + OnSoundEvent(wxSOUND_OUTPUT); + } else { + m_input_frag_in = (m_input_frag_in + 1) % WXSOUND_MAX_QUEUE; + OnSoundEvent(wxSOUND_INPUT); + m_queue_filled = FALSE; + } +} + +bool wxSoundStreamWin::SetSoundFormat(wxSoundFormatBase& base) +{ + return wxSoundStream::SetSoundFormat(base); +} + +bool wxSoundStreamWin::StartProduction(int evt) +{ + if ((m_internal->m_output_enabled && (evt & wxSOUND_OUTPUT)) || + (m_internal->m_input_enabled && (evt & wxSOUND_INPUT))) + CloseDevice(); + + if (!OpenDevice(evt)) + return FALSE; + + m_production_started = TRUE; + m_queue_filled = FALSE; + // Send a dummy event to start. + if (evt & wxSOUND_OUTPUT) + OnSoundEvent(evt); + + if (evt & wxSOUND_INPUT) { + int i; + for (i=0;i (C) 1999 +// CVSID: $Id$ +// -------------------------------------------------------------------------- +#ifndef _WX_SNDWIN_H +#define _WX_SNDWIN_H + +#include +#include "sndbase.h" + +typedef struct _wxSoundInternal wxSoundInternal; +typedef struct _wxSoundInfoHeader wxSoundInfoHeader; + +class WXDLLEXPORT wxSoundStreamWin : public wxSoundStream { + public: + wxSoundStreamWin(); + ~wxSoundStreamWin(); + + wxSoundStream& Write(const void *buffer, size_t len); + wxSoundStream& Read(void *buffer, size_t len); + + bool SetSoundFormat(wxSoundFormatBase& base); + void SetDuplexMode(bool on) {} + + bool StartProduction(int evt); + bool StopProduction(); + + bool QueueFilled() const; + + // Internal but defined as public + void NotifyDoneBuffer(wxUint32 dev_handle); + + protected: + wxSoundInternal *m_internal; + wxUint32 m_current_frag_in, m_current_frag_out; + wxUint32 m_input_frag_in, m_output_frag_out; + wxSoundInfoHeader **m_headers_play, **m_headers_rec; + + bool m_production_started, m_queue_filled; + + protected: + void CreateSndWindow(); + void DestroySndWindow(); + bool OpenDevice(int mode); + void CloseDevice(); + + wxSoundInfoHeader *AllocHeader(int mode); + void FreeHeader(wxSoundInfoHeader *header, int mode); + bool AllocHeaders(int mode); + void FreeHeaders(int mode); + + void WaitFor(wxSoundInfoHeader *info); + bool AddToQueue(wxSoundInfoHeader *info); + void ClearHeader(wxSoundInfoHeader *info); + + wxSoundInfoHeader *NextFragmentOutput(); + wxSoundInfoHeader *NextFragmentInput(); +}; + +#endif -- 2.7.4