From 2bba74fc8bb586a09ac96a19cf51e5f4777b598c Mon Sep 17 00:00:00 2001 From: Cary Sandvig Date: Wed, 4 Oct 2000 23:12:43 +0000 Subject: [PATCH] loader using the SoX libst --- panda/src/audio/audio_load_st.cxx | 304 ++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 panda/src/audio/audio_load_st.cxx diff --git a/panda/src/audio/audio_load_st.cxx b/panda/src/audio/audio_load_st.cxx new file mode 100644 index 0000000000..80a8942472 --- /dev/null +++ b/panda/src/audio/audio_load_st.cxx @@ -0,0 +1,304 @@ +// Filename: audio_load_st.C +// Created by: cary (03Oct00) +// +//////////////////////////////////////////////////////////////////// + +#include +#include "audio_pool.h" +#include "config_audio.h" + +#include +#include + +#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; estart)(&efftab[e]); + if (efftabR[e].name) + (*efftabR[e].h->start)(&efftabR[e]); + } + // reserve output buffers for all effects + for (e=0; eread)(&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; e0; --e) + if (flow_effect(e)) + break; + // add to output data + if (efftab[neffects-1].olen>efftab[neffects-1].odone) { + for (LONG i=0; i> 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; eread)(&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 0) { + for (LONG i=0; i> 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; estop)(&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); + } +}