wxWidgets/utils/wxMMedia/sndfrag.cpp
Guilhem Lavaux 8a7c9dcc1c * Fixes and updates on wxMMedia.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1722 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1999-02-18 18:18:06 +00:00

272 lines
6.2 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// 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 <stdio.h>
#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_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;i<m_maxoq;i++)
if (m_lstoptrs[i].buffers->Member(buf)) {
if (m_lstoptrs[i].state == wxBUFFER_PLAYING)
// TODO: Do something.
;
m_lstoptrs[i].state = wxBUFFER_TOFREE;
}
for (wxUint8 i=0;i<m_maxiq;i++)
if (m_lstiptrs[i].buffers->Member(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;i<max_queue;i++) {
if (list[i].state == wxBUFFER_FREE)
return &list[i];
}
return NULL;
}
bool wxFragmentBuffer::NotifyOutputBuffer(wxSndBuffer *buf)
{
wxFragBufPtr *ptr;
wxSoundCodec *codec = buf->GetCurrentCodec();
if (!m_iodrv->OnSetupDriver(*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 == NULL)
return FALSE;
// Normally, these three functions could be called only once.
codec->SetOutStream(ptr->sndbuf);
codec->InitIO(m_drvformat);
codec->InitMode(wxSoundCodec::DECODING);
// Fill it up
codec->Decode();
// No data to fill the buffer: dequeue the current wxSndBuffer
if (codec->Available() == 0) {
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);
// Output buffer full: send it to the driver
if (ptr->sndbuf->GetDataLeft() == 0) {
ptr->state = wxBUFFER_FFILLED;
OnBufferFilled(ptr, wxSND_OUTPUT);
}
}
}
bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
{
wxFragBufPtr *ptr;
size_t inc;
if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT))
return FALSE;
while (1) {
ptr = FindFreeBuffer(m_lstiptrs, m_maxiq);
if (ptr == NULL)
return FALSE;
if (buf->Available() == 0) {
if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
buf->Set(wxSND_UNQUEUEING);
m_iodrv->m_buffers.DeleteObject(buf);
}
if (LastBuffer() == NULL && ptr->sndbuf->GetIntPosition() != 0) {
ptr->state = wxBUFFER_FFILLED;
if (!OnBufferFilled(ptr, wxSND_INPUT))
return FALSE;
}
return TRUE;
}
ptr->buffers->Append(buf);
// TODO: Add an "incrementer" in wxStreamBuffer.
inc = (buf->Available() < ptr->sndbuf->GetDataLeft()) ?
buf->Available() : ptr->sndbuf->GetDataLeft();
ptr->sndbuf->SetIntPosition(ptr->sndbuf->GetIntPosition() + inc);
if (ptr->sndbuf->GetDataLeft() == 0) {
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;i<m_maxoq;i++) {
if ((m_lstoptrs[i].state == wxBUFFER_TOFREE) ||
(force && m_lstoptrs[i].state == wxBUFFER_FFILLED))
ClearBuffer(&m_lstoptrs[i]);
}
for (i=0;i<m_maxiq;i++) {
if ((m_lstiptrs[i].state == wxBUFFER_TOFREE) ||
(force && m_lstoptrs[i].state == wxBUFFER_FFILLED))
ClearBuffer(&m_lstiptrs[i]);
}
m_dontq = FALSE;
}
void wxFragmentBuffer::ClearBuffer(wxFragBufPtr *ptr)
{
wxNode *node;
wxSndBuffer *buf;
wxSoundCodec *codec;
node = ptr->buffers->First();
while (node) {
buf = (wxSndBuffer *)node->Data();
if (buf->GetMode() == wxSND_OUTPUT) {
buf->OnBufferOutFinished();
} else {
codec = buf->GetCurrentCodec();
// Normally, these three functions could be called only once.
codec->SetInStream(ptr->sndbuf);
codec->InitIO(m_drvformat);
codec->InitMode(wxSoundCodec::ENCODING);
// As there is an "auto-stopper" in the codec, we don't worry ...
codec->Encode();
}
if (buf->IsSet(wxSND_UNQUEUEING))
buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY);
delete node;
node = ptr->buffers->First();
}
ptr->sndbuf->ResetBuffer();
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;
}
switch (buf->GetMode()) {
case wxSND_OUTPUT:
ret = NotifyOutputBuffer(buf);
break;
case wxSND_INPUT:
ret = NotifyInputBuffer(buf);
break;
case wxSND_DUPLEX:
case wxSND_OTHER_IO:
// ret = NotifyDuplexBuffer(buf);
break;
}
buf->HardUnlock();
}
m_freeing = FALSE;
}