X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/641d87d868e0f46f4bfca3d8d7bede88032045e1..503aa33d55183bcbd8444e36ed8c273a18dab72f:/utils/wxMMedia2/lib/sndwin.cpp diff --git a/utils/wxMMedia2/lib/sndwin.cpp b/utils/wxMMedia2/lib/sndwin.cpp new file mode 100644 index 0000000000..2b892094b6 --- /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