Browse Source

loader using the SoX libst

Cary Sandvig 25 years ago
parent
commit
2bba74fc8b
1 changed files with 304 additions and 0 deletions
  1. 304 0
      panda/src/audio/audio_load_st.cxx

+ 304 - 0
panda/src/audio/audio_load_st.cxx

@@ -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);
+    }
+}