//////////////////////////////////////////////////////////////////////////////// // Name: sndfrag.cpp // Purpose: wxMMedia // Author: Guilhem Lavaux // Created: 1997 // Updated: 1998 // Copyright: (C) 1997, 1998, Guilhem Lavaux // License: wxWindows license //////////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "sndfrag.h" #endif #include #ifdef WX_PRECOMP #include "wx_prec.h" #else #include "wx/wx.h" #endif #include "sndfrag.h" #ifdef __BORLANDC__ #pragma hdrstop #endif wxFragmentBuffer::wxFragmentBuffer(wxSound& io_drv) : m_iodrv(&io_drv), m_maxoq(0), m_maxiq(0), m_optrs(NULL), m_iptrs(NULL), m_lstoptrs(NULL), m_lstiptrs(NULL), m_buf2free(FALSE), m_dontq(FALSE), m_freeing(FALSE) { } wxFragmentBuffer::~wxFragmentBuffer() { } void wxFragmentBuffer::AbortBuffer(wxSndBuffer *buf) { for (wxUint8 i=0;iMember(buf)) { if (m_lstoptrs[i].state == wxBUFFER_PLAYING) // TODO: Do something. ; m_lstoptrs[i].state = wxBUFFER_TOFREE; } for (wxUint8 i=0;iMember(buf)) { if (m_lstiptrs[i].state == wxBUFFER_PLAYING) // Do something. ; m_lstiptrs[i].state = wxBUFFER_TOFREE; } } wxFragmentBuffer::wxFragBufPtr *wxFragmentBuffer::FindFreeBuffer( wxFragBufPtr *list, wxUint8 max_queue) { if (!list) return NULL; for (wxUint8 i=0;iOnSetupDriver(*buf, wxSND_OUTPUT)) return FALSE; while (1) { // Find the first free (at least partly free) output buffer ptr = FindFreeBuffer(m_lstoptrs, m_maxoq); // No free : go out ! if (!ptr) return FALSE; // Find the end of the buffer raw_buf = ptr->data + ptr->ptr; rawbuf_size = ptr->size - ptr->ptr; // Fill it up buf->OnNeedOutputData(raw_buf, rawbuf_size); // No data to fill the buffer: dequeue the current wxSndBuffer if (!rawbuf_size) { if (buf->IsNotSet(wxSND_KEEPQUEUED)) { buf->Set(wxSND_UNQUEUEING); m_iodrv->m_buffers.DeleteObject(buf); } return TRUE; } // Data: append it to the list ptr->buffers->Append(buf); ptr->ptr += rawbuf_size; // Output buffer full: send it to the driver if (ptr->ptr == ptr->size) { ptr->state = wxBUFFER_FFILLED; OnBufferFilled(ptr, wxSND_OUTPUT); } } } bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf) { wxFragBufPtr *ptr; char *raw_buf; wxUint32 rawbuf_size; if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT)) return FALSE; while (1) { ptr = FindFreeBuffer(m_lstiptrs, m_maxiq); if (!ptr) return FALSE; raw_buf = ptr->data + ptr->ptr; rawbuf_size = ptr->size - ptr->ptr; rawbuf_size = (buf->Available() < rawbuf_size) ? buf->Available() : rawbuf_size; if (!rawbuf_size) { if (buf->IsNotSet(wxSND_KEEPQUEUED)) { buf->Set(wxSND_UNQUEUEING); m_iodrv->m_buffers.DeleteObject(buf); } // Get data now when there isn't anymore buffer in the queue if (!LastBuffer() && ptr->ptr) { ptr->state = wxBUFFER_FFILLED; if (!OnBufferFilled(ptr, wxSND_INPUT)) return FALSE; } return TRUE; } ptr->buffers->Append(buf); ptr->ptr += rawbuf_size; // Input buffer full => get data if (ptr->ptr == ptr->size) { ptr->state = wxBUFFER_FFILLED; if (!OnBufferFilled(ptr, wxSND_INPUT)) return FALSE; } } return TRUE; } void wxFragmentBuffer::FreeBufToFree(bool force) { wxUint8 i; // Garbage collecting m_dontq = TRUE; m_buf2free = FALSE; for (i=0;idata; size = ptr->size; node = ptr->buffers->First(); while (node) { buf = (wxSndBuffer *)node->Data(); if (buf->GetMode() == wxSND_OUTPUT) { buf->OnBufferOutFinished(); } else { data_read = buf->OnBufferInFinished(data, size); data += data_read; size -= data_read; } if (buf->IsSet(wxSND_UNQUEUEING)) buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY); delete node; node = ptr->buffers->First(); } ptr->ptr = 0; ptr->state = wxBUFFER_FREE; } void wxFragmentBuffer::OnBufferFinished(wxFragBufPtr *ptr) { wxNode *node; wxSndBuffer *buf; bool ret = TRUE; if (m_freeing) { ptr->state = wxBUFFER_TOFREE; m_buf2free = TRUE; return; } m_freeing = TRUE; // Clean up the old buffer. if (ptr && ptr->state != wxBUFFER_FREE) ClearBuffer(ptr); // Garbage collecting ... if (m_buf2free) FreeBufToFree(); // If we are queueing, return immediately. if (m_dontq) { m_freeing = FALSE; return; } node = m_iodrv->m_buffers.First(); while (node && ret) { buf = (wxSndBuffer *)node->Data(); node = node->Next(); buf->HardLock(); // Stop request on this buffer. if (buf->IsSet(wxSND_BUFSTOP)) { buf->Clear(wxSND_BUFSTOP); continue; } if (buf->GetMode() == wxSND_OUTPUT) ret = NotifyOutputBuffer(buf); else ret = NotifyInputBuffer(buf); buf->HardUnlock(); } m_freeing = FALSE; }