📄 sndwin.cpp
字号:
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;
}
// -------------------------------------------------------------------------
// FreeHeader(int mode)
//
// "mode" has the same mean as for OpenDevice() except that the two flags must
// be exclusive.
// FreeHeader() frees a memory block and "unprepares" it.
// -------------------------------------------------------------------------
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;
}
// -------------------------------------------------------------------------
// FreeHeaders(int mode)
//
// "mode" has the same mean as for OpenDevice() except that the two flags must
// be exclusive.
// FreeHeaders() frees all an operation queue once it has checked that
// all buffers have been terminated.
// -------------------------------------------------------------------------
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]) {
// We wait for the end of the buffer
WaitFor((*headers)[i]);
// Then, we free the header
FreeHeader((*headers)[i], mode);
}
}
delete[] (*headers);
(*headers) = NULL;
}
// -------------------------------------------------------------------------
// WaitFor(wxSoundInfoHeader *info)
//
// "info" is one element of an IO queue
// WaitFor() checks whether the specified block has been terminated.
// If it hasn't been terminated, it waits for its termination.
//
// NB: if it's a partially filled buffer it adds it to the Windows queue
// -------------------------------------------------------------------------
void wxSoundStreamWin::WaitFor(wxSoundInfoHeader *info)
{
// If the buffer is finished, we return immediately
if (!info->m_playing) {
// We begun filling it: we must send it to the Windows queue
if (info->m_position != 0) {
memset(info->m_data + info->m_position, 0, info->m_size);
AddToQueue(info);
}
}
if (m_waiting_for) {
// PROBLEM //
return;
}
m_waiting_for = true;
// Else, we wait for its termination
while (info->m_playing || info->m_recording)
wxYield();
m_waiting_for = false;
}
// -------------------------------------------------------------------------
// AddToQueue(wxSoundInfoHeader *info)
//
// For "info", see WaitFor()
// AddToQueue() sends the IO queue element to the Windows queue.
//
// Warning: in the current implementation, it partially assume we send the
// element in the right order. This is true in that implementation but if
// you use it elsewhere, be careful: it may shuffle all your sound datas.
// -------------------------------------------------------------------------
bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader *info)
{
MMRESULT result;
if (info->m_mode == wxSOUND_INPUT) {
// Increment the input fragment pointer
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;
}
// -------------------------------------------------------------------------
// ClearHeader(wxSoundInfoHeader *info)
//
// ClearHeader() reinitializes the parameters of "info" to their default
// value.
// -------------------------------------------------------------------------
void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader *info)
{
info->m_playing = false;
info->m_recording = false;
info->m_position = 0;
info->m_size = GetBestSize();
}
// -------------------------------------------------------------------------
// wxSoundInfoHeader *NextFragmentOutput()
//
// NextFragmentOutput() looks for a free output block. It will always
// return you a non-NULL pointer but it may waits for an empty buffer a long
// time.
// -------------------------------------------------------------------------
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];
}
// -------------------------------------------------------------------------
// The behaviour of Write is documented in the global documentation.
// -------------------------------------------------------------------------
wxSoundStream& wxSoundStreamWin::Write(const void *buffer, wxUint32 len)
{
m_lastcount = 0;
if (!m_internal->m_output_enabled) {
m_snderror = wxSOUND_NOTSTARTED;
return *this;
}
while (len > 0) {
wxSoundInfoHeader *header;
wxUint32 to_copy;
// Get a new output fragment
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 the fragment is full, we send it to the Windows queue.
if (header->m_size == 0)
if (!AddToQueue(header)) {
m_snderror = wxSOUND_IOERROR;
return *this;
}
}
return *this;
}
// -------------------------------------------------------------------------
// NextFragmentInput is not functional.
// -------------------------------------------------------------------------
wxSoundInfoHeader *wxSoundStreamWin::NextFragmentInput()
{
wxSoundInfoHeader *header;
// Queue pointer: reader
m_current_frag_in = (m_current_frag_in + 1) % WXSOUND_MAX_QUEUE;
header = m_headers_rec[m_current_frag_in];
// If the current buffer is in recording mode, we must wait for its
// completion.
if (header->m_recording)
WaitFor(header);
// We reached the writer position: the queue is full.
if (m_current_frag_in == m_input_frag_in)
m_queue_filled = true;
return header;
}
// -------------------------------------------------------------------------
// The behaviour of Read is documented in the global documentation.
// -------------------------------------------------------------------------
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_IOERROR;
return *this;
}
}
}
return *this;
}
// -------------------------------------------------------------------------
// NotifyDoneBuffer(wxUint32 dev_handle)
//
// NotifyDoneBuffer() is called by wxSoundHandlerProc each time a sound
// fragment finished. It reinitializes the parameters of the fragment and
// sends an event to the clients.
// -------------------------------------------------------------------------
void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 WXUNUSED(dev_handle), int flag)
{
wxSoundInfoHeader *info;
if (flag == wxSOUND_OUTPUT) {
if (!m_internal->m_output_enabled)
return;
// Queue pointer: reader
m_output_frag_out = (m_output_frag_out + 1) % WXSOUND_MAX_QUEUE;
info = m_headers_play[m_output_frag_out];
// Clear header to tell the system the buffer is free now
ClearHeader(info);
m_queue_filled = false;
if (!m_waiting_for)
// Try to requeue a new buffer.
OnSoundEvent(wxSOUND_OUTPUT);
} else {
if (!m_internal->m_input_enabled)
return;
// Recording completed
m_headers_rec[m_input_frag_in]->m_recording = false;
// Queue pointer: writer
m_input_frag_in = (m_input_frag_in + 1) % WXSOUND_MAX_QUEUE;
if (!m_waiting_for)
OnSoundEvent(wxSOUND_INPUT);
m_queue_filled = false;
}
}
// -------------------------------------------------------------------------
// SetSoundFormat()
// -------------------------------------------------------------------------
bool wxSoundStreamWin::SetSoundFormat(const wxSoundFormatBase& base)
{
// TODO: detect best format
return wxSoundStream::SetSoundFormat(base);
}
// -------------------------------------------------------------------------
// StartProduction()
// -------------------------------------------------------------------------
bool wxSoundStreamWin::StartProduction(int evt)
{
if (!m_internal)
return false;
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(wxSOUND_OUTPUT);
if (evt & wxSOUND_INPUT) {
int i;
for (i=0;i<WXSOUND_MAX_QUEUE;i++)
AddToQueue(m_headers_rec[i]);
waveInStart(m_internal->m_devin);
}
return true;
}
// -------------------------------------------------------------------------
// StopProduction()
// ------------------------------------------------------------------------
bool wxSoundStreamWin::StopProduction()
{
if (!m_production_started) {
m_snderror = wxSOUND_NOTSTARTED;
return false;
}
m_snderror = wxSOUND_NOERROR;
m_production_started = false;
CloseDevice();
return true;
}
// -------------------------------------------------------------------------
// QueueFilled()
// -------------------------------------------------------------------------
bool wxSoundStreamWin::QueueFilled() const
{
return (!m_production_started || m_queue_filled);
}
// --------------------------------------------------------------------------
// wxSoundWinModule
// --------------------------------------------------------------------------
class 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;
}
#endif
// __WINDOWS__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -