loader using the SoX libst

This commit is contained in:
Cary Sandvig 2000-10-04 23:12:43 +00:00
parent b7da1b768c
commit 2bba74fc8b

View File

@ -0,0 +1,304 @@
// Filename: audio_load_st.C
// Created by: cary (03Oct00)
//
////////////////////////////////////////////////////////////////////
#include <config.h>
#include "audio_pool.h"
#include "config_audio.h"
#include <st.h>
#include <patchlvl.h>
#if (PATCHLEVEL == 16)
#define FORMATS formats
#define EFFECTS_TYPE struct effect
#define STREAM_TYPE struct soundstream
#define GETTYPE gettype
#define COMPAT_EOF (-1)
#define CHECKFORMAT checkformat
#define SIZES sizes
#define ENCODING styles
#define COPYFORMAT copyformat
#define GETEFFECT geteffect
#define UPDATEEFFECT(a, b, c, d)
#else /* PATCHLEVEL != 16 */
#define FORMATS st_formats
#define EFFECTS_TYPE struct st_effect
#define STREAM_TYPE struct st_soundstream
#define GETTYPE st_gettype
#define COMPAT_EOF ST_EOF
#define CHECKFORMAT st_checkformat
#define SIZES st_sizes_str
#define ENCODING st_encodings_str
#define COPYFORMAT st_copyformat
#define GETEFFECT st_geteffect
#define UPDATEEFFECT st_updateeffect
#endif /* PATCHLEVEL */
Configure(audio_load_st);
// the effects we will be using are to change the rate and number of channels
static EFFECTS_TYPE efftab[5]; // left/mono channel effects
static EFFECTS_TYPE efftabR[5]; // right channel effects
static int neffects; // how many effects are in action
static STREAM_TYPE informat; // holder for the input
static STREAM_TYPE outformat; // holder for fake output;
INLINE static void init_stream(void) {
informat.info.rate = 0;
informat.info.size = -1;
informat.info.encoding = -1;
informat.info.channels = -1;
informat.comment = (char*)0L;
informat.swap = 0;
informat.filetype = (char*)0L;
informat.fp = stdin;
informat.filename = "input";
outformat.info.rate = audio_mix_freq;
outformat.info.size = -1;
outformat.info.encoding = -1;
outformat.info.channels = 2;
outformat.comment = (char*)0L;
outformat.swap = 0;
outformat.filetype = (char*)0L;
outformat.fp = stdout;
outformat.filename = "output";
}
INLINE static void check_effects(void) {
bool needchan = (informat.info.rate != audio_mix_freq);
bool needrate = (informat.info.channels != 2);
// efftab[0] is always the input stream and always exists
neffects = 1;
// if reducing the number of samples, it is faster to run all effects
// after the resample effect
if (needrate) {
GETEFFECT(&efftab[neffects], "resample");
// setup and give default opts
(*efftab[neffects].h->getopts)(&efftab[neffects],(int)0,(char**)0L);
// copy format info to effect table
UPDATEEFFECT(&efftab[neffects], &informat, &outformat, 0);
// rate can't handle multiple channels so be sure and account for that
if (efftab[neffects].ininfo.channels > 1)
memcpy(&efftabR[neffects], &efftab[neffects], sizeof(EFFECTS_TYPE));
++neffects;
}
// if we ever have more then 2 channels in an input file, we will need to
// deal with that somewhere here
if (needchan) {
GETEFFECT(&efftab[neffects], "avg");
//setup and give default opts
(*efftab[neffects].h->getopts)(&efftab[neffects],(int)0,(char**)0L);
// copy format info to effect table
UPDATEEFFECT(&efftab[neffects], &informat, &outformat, 0);
++neffects;
}
}
static byte* read_file(Filename filename) {
int e, havedata;
ostringstream out;
init_stream();
if ((informat.fp = fopen(filename.c_str(), READBINARY)) == NULL) {
audio_cat->error() << "could not open '" << filename << "'" << endl;
return (byte*)0L;
}
informat.filname = filename.c_str();
informat.filetype = filename.get_extension();
informat.comment = filename.c_str(); // for lack of anything better
// now we start some more real work
GETTYPE(&informat);
// read and write starters can change their formats
if ((*informat.h->startread)(&informat) == COMPAT_EOF) {
audio_cat->error() << "failed to start read" << endl;
return (byte*)0L;
}
CHECKFORMAT(&informat);
if (audio_cat->is_debug())
audio_cat->debug() << "Input file '" << informat.filename
<< "': sample rate = " << informat.info.rate
<< " size = " << SIZES[informat.info.size]
<< " encoding = " << ENCODING[informat.info.encoding]
<< " " << informat.info.channels
<< (informat.info.channels > 1)?"channels":"channel"
<< endl;
if (audio_cat->is_debug())
audio_cat->debug() << "Input file comment: '" << informat.comment << "'"
<< endl;
COPYFORMAT(&informat, &outformat);
check_effects();
// start all effects
for (e=1; e<neffects; ++e) {
(*efftab[e].h->start)(&efftab[e]);
if (efftabR[e].name)
(*efftabR[e].h->start)(&efftabR[e]);
}
// reserve output buffers for all effects
for (e=0; e<neffects; e++) {
efftab[e].obuf = new LONG[BUFSIZ*sizeof(LONG)];
if (efftabR[e].name)
efftabR[e].obuf = new LONG[BUFSIZ*sizeof(LONG)];
}
// get the main while loop ready, have some data for it to start on
efftab[0].olen = (*informat.h->read)(&informat, efftab[0].obuf,
(LONG)BUFSIZ);
efftab[0].odone = 0;
// run input data thru effects and get more until olen == 0
while (efftab[0].olen > 0) {
// mark chain as empty
for (e=1; e<neffects; ++e)
efftab[e].odone = efftab[e].olen = 0;
do {
ULONG w;
// run entire chain backwards: pull, don't push
// this is because buffering system isn't a nice queueing system
for (e=neffects-1; e>0; --e)
if (flow_effect(e))
break;
// add to output data
if (efftab[neffects-1].olen>efftab[neffects-1].odone) {
for (LONG i=0; i<efftab[neffects-1].olen; ++i) {
LONG foo = efftab[neffects-1].obuf[i];
signed short bar = (foo >> 16);
unsigned char *b = &bar;
out << *b << *(++b);
}
efftab[neffects-1].odone = efftab[neffects-1].olen;
}
// if there is still stuff in the pipeline, setup to flow effects again
havedata = 0;
for (e=0; e<neffects-1; ++e)
if (efftab[e].odone < efftab[e].olen) {
havedata = 1;
break;
}
} while (havedata);
// read another chunk
efftab[0].olen = (*informat.h->read)(&informat, efftab[0].obuf,
(LONG)BUFSIZ);
efftab[0].odone = 0;
}
// drain the effects out first to last. push the residue thru subsequent
// effects. suck.
for (e=1; e<neffects; ++e)
while (1) {
if (drain_effect(e) == 0)
break; // get out of while loop
if (efftab[neffects-1].olen > 0) {
for (LONG i=0; i<efftab[neffects-1].olen; ++i) {
LONG foo = efftab[neffects-1].obuf[i];
signed short bar = (foo >> 16);
unsigned char *b = &bar;
out << *b << *(++b);
}
}
if (efftab[e].olen != BUFSIZ)
break;
}
// stop all effects. In so doing, some may generate more data
for (e=1; e<neffects; ++e) {
(*efftab[e].h->stop)(&efftab[e]);
if (efftabR[e].name)
(*efftabR[e].h->stop)(&efftabR[e]);
}
// stop reading the file
if ((*informat.h->stopread)(&informat) == COMPAT_EOF) {
audio_cat->error() << "error stoping input file" << endl;
}
fclose(informat.fp);
// generate output
string s = out.str();
int slen = s.length();
byte* ret = new byte[slen];
memcpy(ret, s.data(), slen);
return ret;
}
#ifdef USE_MIKMOD
void AudioDestroySt(AudioTraits::SampleClass* sample) {
delete sample;
}
void AudioLoadSt(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename) {
audio_cat->warning() << "MikMod doesn't support reading raw data yet"
<< endl;
*sample = (AudioTraits::SampleClass*)0L;
*player = (AudioTraits::PlayerClass*)0L;
*destroy = AudioDestroySt;
}
#else /* no MikMod */
ifdef PENV_WIN32
void AudioDestroySt(AudioTraits::SampleClass* sample) {
delete sample;
}
void AudioLoadSt(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename) {
audio_cat->warning() << "win32 doesn't support reading raw data yet"
<< endl;
*sample = (AudioTraits::SampleClass*)0L;
*player = (AudioTraits::PlayerClass*)0L;
*destroy = AudioDestroySt;
}
#else /* no win32 */
#ifdev PENV_LINUX
void AudioDestroySt(AudioTraits::SampleClass* sample) {
delete sample;
}
void AudioLoadSt(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename) {
audio_cat->warning() << "linux doesn't support reading raw data yet"
<< endl;
*sample = (AudioTraits::SampleClass*)0L;
*player = (AudioTraits::PlayerClass*)0L;
*destroy = AudioDestroySt;
}
#else /* no linux */
// Null driver
#include "audio_null_traits.h"
void AudioDestroySt(AudioTraits::SampleClass* sample) {
delete sample;
}
void AudioLoadSt(AudioTraits::SampleClass** sample,
AudioTraits::PlayerClass** player,
AudioTraits::DeleteSampleFunc** destroy, Filename) {
*sample = new NullSample();
*player = new NullPlayer();
*destroy = AudioDestroySt;
}
#endif /* linux */
#endif /* win32 */
#endif /* MikMod */
ConfigureFn(audio_load_st) {
for (int i=0; FORMATS[i].names != (char**)0L; ++i)
for (int j=0; FORMATS[i].names[j] != (char*)0L; ++j) {
if (audio_cat->is_debug())
audio_cat->debug() << "adding reader for '." << FORMATS[i].names[j]
<< "'" << endl;
AudioPool::register_sample_loader(FORMATS[i].names[j], AudioLoadSt);
}
}