#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <Audio.h>
#include <AudioDebug.h>
#include <AudioBuffer.h>
int
Audio::idctr = 0;
Audio::
Audio(
const char *str):
id(++idctr), refcnt(0), readpos(0.), writepos(0.), errorfunc(0)
{
char *s;
s = (char *)((str == NULL) ? "" : str);
name = new char[strlen(s) + 1];
(void) strcpy(name, s);
#ifndef DEBUG
if (GetDebug() > 0)
#endif
errorfunc = AudioStderrMsg;
PrintMsg(_MGET_("Audio object create"), InitMessage);
}
Audio::
~Audio()
{
if (refcnt < 0) {
PrintMsg(_MGET_("Audio object multiple destroy"), InitFatal);
} else if (refcnt > 0) {
PrintMsg(_MGET_("Referenced Audio object destroyed"),
InitFatal);
} else {
refcnt = -1;
PrintMsg(_MGET_("Audio object destroy"), InitMessage);
}
delete name;
}
AudioError Audio::
RaiseError(
AudioError code,
AudioSeverity sev,
const char *msg) const
{
if (code == AUDIO_SUCCESS)
return (code);
if (errorfunc != 0) {
(void) (*errorfunc)(this, code, sev, msg);
}
if ((sev == Fatal) || (sev == InitFatal))
abort();
return (code);
}
void Audio::
PrintMsg(
char *msg,
AudioSeverity sev) const
{
if (errorfunc != 0) {
(void) (*errorfunc)(this, AUDIO_NOERROR, sev, msg);
}
if ((sev == Fatal) || (sev == InitFatal)) {
fprintf(stderr, _MGET_("** Fatal Error: %s\n"), msg);
abort();
}
}
void Audio::
Reference()
{
if (refcnt < 0) {
PrintMsg(_MGET_("Reference to destroyed Audio object"), Fatal);
} else {
refcnt++;
}
}
void Audio::
Dereference()
{
if (refcnt < 0) {
PrintMsg(_MGET_("Dereference of destroyed Audio object"),
Fatal);
} else if (refcnt == 0) {
PrintMsg(_MGET_("Audio object dereference underflow"), Fatal);
} else if (--refcnt == 0) {
delete this;
}
}
void Audio::
SetName(
const char *str)
{
delete name;
name = new char[strlen(str) + 1];
(void) strcpy(name, str);
}
Double Audio::
setpos(
Double& pos,
Double newpos,
Whence w)
{
if (w == Relative)
newpos += pos;
else if (w == Relative_eof) {
if (!Undefined(GetLength()))
newpos += GetLength();
else
return (AUDIO_UNKNOWN_TIME);
}
if (newpos < 0.)
newpos = 0.;
pos = newpos;
return (pos);
}
Double Audio::
SetReadPosition(
Double pos,
Whence w)
{
return (setpos(readpos, pos, w));
}
Double Audio::
SetWritePosition(
Double pos,
Whence w)
{
return (setpos(writepos, pos, w));
}
AudioError Audio::
Read(
void* buf,
size_t& len)
{
return (ReadData(buf, len, readpos));
}
AudioError Audio::
Write(
void* buf,
size_t& len)
{
return (WriteData(buf, len, writepos));
}
AudioError Audio::
AppendData(
void* buf,
size_t& len,
Double& pos)
{
return (WriteData(buf, len, pos));
}
AudioError Audio::
Copy(
Audio* to)
{
Double frompos = AUDIO_UNKNOWN_TIME;
Double topos = AUDIO_UNKNOWN_TIME;
Double limit = AUDIO_UNKNOWN_TIME;
return (Copy(to, frompos, topos, limit));
}
AudioError Audio::
Copy(
Audio* to,
Double& frompos,
Double& topos,
Double& limit)
{
Double len;
Double svpos;
AudioError err;
if (Undefined(frompos))
frompos = ReadPosition();
if (Undefined(topos))
topos = to->WritePosition();
svpos = frompos;
do {
if (Undefined(limit)) {
len = limit;
} else {
len = limit - (frompos - svpos);
if (len < 0.)
len = 0.;
}
err = AsyncCopy(to, frompos, topos, len);
if (!err) {
switch (err.sys) {
default:
case 0:
break;
case AUDIO_COPY_SHORT_OUTPUT:
goto outofloop;
case AUDIO_COPY_ZERO_LIMIT:
goto outofloop;
case AUDIO_COPY_SHORT_INPUT:
goto outofloop;
}
}
} while (err == AUDIO_SUCCESS);
outofloop:
limit = frompos - svpos;
if (limit > 0.)
return (AUDIO_SUCCESS);
return (err);
}
AudioError Audio::
AsyncCopy(
Audio* to,
Double& frompos,
Double& topos,
Double& limit)
{
caddr_t bptr;
size_t bufsiz;
size_t lim;
Double svfrom;
Double svto;
AudioBuffer* tob;
AudioHdr tohdr;
AudioError err;
tohdr = to->GetHeader();
err = tohdr.Validate();
if (err != AUDIO_SUCCESS)
return (err);
if (limit < 0.)
return (RaiseError(AUDIO_ERR_BADARG));
lim = (size_t)tohdr.Time_to_Bytes(limit);
if (to->isBuffer()) {
tob = (AudioBuffer*) to;
bptr = (caddr_t)tob->GetAddress(topos);
bufsiz = bptr - (caddr_t)tob->GetAddress();
if ((bptr == NULL) || (tob->GetByteCount() <= bufsiz)) {
limit = 0.;
err = AUDIO_EOF;
err.sys = AUDIO_COPY_OUTPUT_EOF;
return (err);
}
bufsiz = tob->GetByteCount() - bufsiz;
if (!Undefined(limit) && (lim < bufsiz))
bufsiz = lim;
(void) tohdr.Bytes_to_Bytes(bufsiz);
err = ReadData((void*) bptr, bufsiz, frompos);
limit = tohdr.Bytes_to_Time(bufsiz);
topos += limit;
tob->SetLength(topos);
return (err);
}
if (tohdr.channels < 2) {
bufsiz = (size_t)tohdr.Time_to_Bytes(2.0);
} else {
bufsiz = (size_t)tohdr.Time_to_Bytes(1.0);
}
if (!Undefined(limit) && (lim < bufsiz))
bufsiz = lim;
limit = 0.;
if ((bptr = new char[bufsiz]) == NULL)
return (AUDIO_UNIXERROR);
svfrom = frompos;
err = ReadData((void*)bptr, bufsiz, frompos);
if (!err) {
svto = topos;
lim = bufsiz;
if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
AUDIO_DEBUG((1,
"Read returned a fraction of a sample frame?!\n"));
lim = bufsiz;
}
if (bufsiz > 0) {
err = to->WriteData(bptr, bufsiz, topos);
limit = topos - svto;
if (bufsiz < lim) {
lim = bufsiz;
if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
AUDIO_DEBUG((1,
"Write returned a fraction of a sample frame?!\n"));
}
frompos = svfrom + limit;
if (!err)
err.sys = AUDIO_COPY_SHORT_OUTPUT;
}
}
}
delete[] bptr;
return (err);
}