Changed size_t to wxUint32 Added support for G72X WAV format multi-codec handling git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3508 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			538 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// --------------------------------------------------------------------------
 | 
						|
// Name: sndwin.cpp
 | 
						|
// Purpose:
 | 
						|
// Date: 08/11/1999
 | 
						|
// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
 | 
						|
// CVSID: $Id$
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
#include <wx/wxprec.h>
 | 
						|
 | 
						|
#include <wx/msw/private.h>
 | 
						|
#include <wx/module.h>
 | 
						|
#include <string.h>
 | 
						|
#include "sndbase.h"
 | 
						|
#include "sndwin.h"
 | 
						|
#include "sndpcm.h"
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
#include <mmsystem.h>
 | 
						|
 | 
						|
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;i<WXSOUND_MAX_QUEUE;i++) {
 | 
						|
    headers[i] = AllocHeader(mode);
 | 
						|
    if (!headers[i]) {
 | 
						|
      FreeHeaders(mode);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void wxSoundStreamWin::FreeHeader(wxSoundInfoHeader *header, int mode)
 | 
						|
{
 | 
						|
  if (mode == wxSOUND_OUTPUT)
 | 
						|
    waveOutUnprepareHeader(m_internal->m_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;i<WXSOUND_MAX_QUEUE;i++) {
 | 
						|
    if ((*headers)[i]) {
 | 
						|
      WaitFor((*headers)[i]);
 | 
						|
      FreeHeader((*headers)[i], mode);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  delete[] (*headers);
 | 
						|
  (*headers) = NULL;
 | 
						|
}
 | 
						|
 | 
						|
void wxSoundStreamWin::WaitFor(wxSoundInfoHeader *info)
 | 
						|
{
 | 
						|
  if (info->m_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, wxUint32 len)
 | 
						|
{
 | 
						|
  m_lastcount = 0;
 | 
						|
  if (!m_internal->m_output_enabled)
 | 
						|
    return *this;
 | 
						|
 | 
						|
  while (len > 0) {
 | 
						|
    wxSoundInfoHeader *header;
 | 
						|
    wxUint32 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, wxUint32 len)
 | 
						|
{
 | 
						|
  wxSoundInfoHeader *header;
 | 
						|
  wxUint32 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<WXSOUND_MAX_QUEUE;i++)
 | 
						|
      AddToQueue(m_headers_rec[i]);
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
bool wxSoundStreamWin::StopProduction()
 | 
						|
{
 | 
						|
  m_production_started = FALSE;
 | 
						|
  CloseDevice();
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
bool wxSoundStreamWin::QueueFilled() const
 | 
						|
{
 | 
						|
  return (!m_production_started || m_queue_filled);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// wxSoundWinModule
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
 | 
						|
class WXDLLEXPORT wxSoundWinModule : public wxModule {
 | 
						|
   DECLARE_DYNAMIC_CLASS(wxSoundWinModule)
 | 
						|
 public:
 | 
						|
   bool OnInit();
 | 
						|
   void OnExit();
 | 
						|
};
 | 
						|
 | 
						|
IMPLEMENT_DYNAMIC_CLASS(wxSoundWinModule, wxModule)
 | 
						|
 | 
						|
bool wxSoundWinModule::OnInit() {
 | 
						|
  wxSoundHandleList = new wxList(wxKEY_INTEGER);
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void wxSoundWinModule::OnExit() {
 | 
						|
  delete wxSoundHandleList;
 | 
						|
}
 |