1998-11-09 13:37:38 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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_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;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(
|
1998-12-23 13:16:19 -05:00
|
|
|
xFragBufPtr *list, wxUint8 max_queue)
|
1998-11-09 13:37:38 -05:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
char *raw_buf;
|
|
|
|
wxUint32 rawbuf_size;
|
1998-12-23 13:16:19 -05:00
|
|
|
wxSoundCodec *codec = buf->GetCurrentCodec();
|
1998-11-09 13:37:38 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
return FALSE;
|
|
|
|
|
1998-12-23 13:16:19 -05:00
|
|
|
codec->SetOutStream(ptr->sndbuf);
|
|
|
|
codec->InitIO(m_drvformat);
|
1998-11-09 13:37:38 -05:00
|
|
|
|
|
|
|
// Fill it up
|
1998-12-23 13:16:19 -05:00
|
|
|
codec->Decode();
|
1998-11-09 13:37:38 -05:00
|
|
|
|
|
|
|
// No data to fill the buffer: dequeue the current wxSndBuffer
|
1998-12-23 13:16:19 -05:00
|
|
|
if (!codec->Available()) {
|
1998-11-09 13:37:38 -05:00
|
|
|
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
|
1998-12-23 13:16:19 -05:00
|
|
|
if (ptr->sndbuf->GetDataLeft()) {
|
1998-11-09 13:37:38 -05:00
|
|
|
ptr->state = wxBUFFER_FFILLED;
|
|
|
|
OnBufferFilled(ptr, wxSND_OUTPUT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
|
|
|
|
{
|
1998-12-23 13:16:19 -05:00
|
|
|
/*
|
|
|
|
wxFragBufPtr *ptr;
|
|
|
|
char *raw_buf;
|
|
|
|
wxUint32 rawbuf_size;
|
|
|
|
|
|
|
|
if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT))
|
1998-11-09 13:37:38 -05:00
|
|
|
return FALSE;
|
|
|
|
|
1998-12-23 13:16:19 -05:00
|
|
|
while (1) {
|
|
|
|
ptr = FindFreeBuffer(m_lstiptrs, m_maxiq);
|
|
|
|
if (!ptr)
|
|
|
|
return FALSE;
|
|
|
|
|
1998-11-09 13:37:38 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
1998-12-23 13:16:19 -05:00
|
|
|
|
1998-11-09 13:37:38 -05:00
|
|
|
if (ptr->ptr == ptr->size) {
|
|
|
|
ptr->state = wxBUFFER_FFILLED;
|
|
|
|
if (!OnBufferFilled(ptr, wxSND_INPUT))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
1998-12-23 13:16:19 -05:00
|
|
|
*/
|
|
|
|
|
1998-11-09 13:37:38 -05:00
|
|
|
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;
|
|
|
|
char *data;
|
|
|
|
wxUint32 size, data_read;
|
|
|
|
|
|
|
|
data = ptr->data;
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
1998-12-23 13:16:19 -05:00
|
|
|
ptr->sndbuf->ResetBuffer();
|
1998-11-09 13:37:38 -05:00
|
|
|
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;
|
|
|
|
}
|