1998-11-09 18:37:38 +00: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),
|
1999-02-14 17:46:47 +00:00
|
|
|
m_lstoptrs(NULL), m_lstiptrs(NULL),
|
1998-11-09 18:37:38 +00:00
|
|
|
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(
|
1999-02-14 17:46:47 +00:00
|
|
|
wxFragBufPtr *list, wxUint8 max_queue)
|
1998-11-09 18:37:38 +00: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;
|
1998-12-23 18:16:19 +00:00
|
|
|
wxSoundCodec *codec = buf->GetCurrentCodec();
|
1998-11-09 18:37:38 +00: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 !
|
1999-02-14 17:46:47 +00:00
|
|
|
if (ptr == NULL)
|
1998-11-09 18:37:38 +00:00
|
|
|
return FALSE;
|
|
|
|
|
1999-02-18 18:18:06 +00:00
|
|
|
// Normally, these three functions could be called only once.
|
1998-12-23 18:16:19 +00:00
|
|
|
codec->SetOutStream(ptr->sndbuf);
|
|
|
|
codec->InitIO(m_drvformat);
|
1999-02-18 18:18:06 +00:00
|
|
|
codec->InitMode(wxSoundCodec::DECODING);
|
1998-11-09 18:37:38 +00:00
|
|
|
|
|
|
|
// Fill it up
|
1998-12-23 18:16:19 +00:00
|
|
|
codec->Decode();
|
1998-11-09 18:37:38 +00:00
|
|
|
|
|
|
|
// No data to fill the buffer: dequeue the current wxSndBuffer
|
1999-02-14 17:46:47 +00:00
|
|
|
if (codec->Available() == 0) {
|
1998-11-09 18:37:38 +00: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
|
1999-02-14 17:46:47 +00:00
|
|
|
if (ptr->sndbuf->GetDataLeft() == 0) {
|
1998-11-09 18:37:38 +00:00
|
|
|
ptr->state = wxBUFFER_FFILLED;
|
|
|
|
OnBufferFilled(ptr, wxSND_OUTPUT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
|
|
|
|
{
|
1999-02-14 17:46:47 +00:00
|
|
|
wxFragBufPtr *ptr;
|
|
|
|
size_t inc;
|
1998-12-23 18:16:19 +00:00
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
ptr = FindFreeBuffer(m_lstiptrs, m_maxiq);
|
|
|
|
if (ptr == NULL)
|
1998-11-09 18:37:38 +00:00
|
|
|
return FALSE;
|
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
if (buf->Available() == 0) {
|
1998-11-09 18:37:38 +00:00
|
|
|
if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
|
|
|
|
buf->Set(wxSND_UNQUEUEING);
|
|
|
|
m_iodrv->m_buffers.DeleteObject(buf);
|
|
|
|
}
|
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
if (LastBuffer() == NULL && ptr->sndbuf->GetIntPosition() != 0) {
|
1998-11-09 18:37:38 +00:00
|
|
|
ptr->state = wxBUFFER_FFILLED;
|
|
|
|
if (!OnBufferFilled(ptr, wxSND_INPUT))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
ptr->buffers->Append(buf);
|
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
// TODO: Add an "incrementer" in wxStreamBuffer.
|
|
|
|
inc = (buf->Available() < ptr->sndbuf->GetDataLeft()) ?
|
|
|
|
buf->Available() : ptr->sndbuf->GetDataLeft();
|
1998-11-09 18:37:38 +00:00
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
ptr->sndbuf->SetIntPosition(ptr->sndbuf->GetIntPosition() + inc);
|
1998-12-23 18:16:19 +00:00
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
if (ptr->sndbuf->GetDataLeft() == 0) {
|
1998-11-09 18:37:38 +00:00
|
|
|
ptr->state = wxBUFFER_FFILLED;
|
|
|
|
if (!OnBufferFilled(ptr, wxSND_INPUT))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
1998-12-23 18:16:19 +00:00
|
|
|
|
1998-11-09 18:37:38 +00: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;
|
1999-02-14 17:46:47 +00:00
|
|
|
wxSoundCodec *codec;
|
1998-11-09 18:37:38 +00:00
|
|
|
|
|
|
|
node = ptr->buffers->First();
|
|
|
|
|
|
|
|
while (node) {
|
|
|
|
buf = (wxSndBuffer *)node->Data();
|
|
|
|
|
|
|
|
if (buf->GetMode() == wxSND_OUTPUT) {
|
|
|
|
buf->OnBufferOutFinished();
|
|
|
|
} else {
|
1999-02-14 17:46:47 +00:00
|
|
|
codec = buf->GetCurrentCodec();
|
|
|
|
|
1999-02-18 18:18:06 +00:00
|
|
|
// Normally, these three functions could be called only once.
|
1999-02-14 17:46:47 +00:00
|
|
|
codec->SetInStream(ptr->sndbuf);
|
|
|
|
codec->InitIO(m_drvformat);
|
1999-02-18 18:18:06 +00:00
|
|
|
codec->InitMode(wxSoundCodec::ENCODING);
|
1998-11-09 18:37:38 +00:00
|
|
|
|
1999-02-14 17:46:47 +00:00
|
|
|
// As there is an "auto-stopper" in the codec, we don't worry ...
|
|
|
|
codec->Encode();
|
1998-11-09 18:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (buf->IsSet(wxSND_UNQUEUEING))
|
|
|
|
buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY);
|
|
|
|
|
|
|
|
delete node;
|
|
|
|
node = ptr->buffers->First();
|
|
|
|
}
|
|
|
|
|
1998-12-23 18:16:19 +00:00
|
|
|
ptr->sndbuf->ResetBuffer();
|
1998-11-09 18:37:38 +00: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;
|
|
|
|
}
|
1999-02-18 18:18:06 +00:00
|
|
|
switch (buf->GetMode()) {
|
|
|
|
case wxSND_OUTPUT:
|
1998-11-09 18:37:38 +00:00
|
|
|
ret = NotifyOutputBuffer(buf);
|
1999-02-18 18:18:06 +00:00
|
|
|
break;
|
|
|
|
case wxSND_INPUT:
|
1998-11-09 18:37:38 +00:00
|
|
|
ret = NotifyInputBuffer(buf);
|
1999-02-18 18:18:06 +00:00
|
|
|
break;
|
|
|
|
case wxSND_DUPLEX:
|
|
|
|
case wxSND_OTHER_IO:
|
|
|
|
// ret = NotifyDuplexBuffer(buf);
|
|
|
|
break;
|
|
|
|
}
|
1998-11-09 18:37:38 +00:00
|
|
|
|
|
|
|
buf->HardUnlock();
|
|
|
|
}
|
|
|
|
m_freeing = FALSE;
|
|
|
|
}
|