Bläddra i källkod

woo! mp3 support

Cary Sandvig 25 år sedan
förälder
incheckning
dfb5f81965
1 ändrade filer med 481 tillägg och 0 borttagningar
  1. 481 0
      panda/src/audiotraits/audio_load_mp3.cxx

+ 481 - 0
panda/src/audiotraits/audio_load_mp3.cxx

@@ -0,0 +1,481 @@
+// Filename: audio_load_mp3.cxx
+// Created by:  cary (11Oct00)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include <dconfig.h>
+#include "audio_pool.h"
+#include "config_audio.h"
+#include "audio_trait.h"
+
+Configure(audio_load_mp3);
+
+extern "C" {
+#include <mpg123.h>
+}
+
+static bool initialized = false;
+static struct audio_info_struct ai;
+static struct frame fr;
+struct parameter param = {
+  FALSE, /* aggressive */
+  FALSE, /* shuffle */
+  FALSE, /* remote */
+  DECODE_AUDIO, /* write samples to audio device */
+  FALSE, /* silent operation */
+  FALSE, /* xterm title on/off */
+  0, /* second level buffer size */
+  TRUE, /* resync after stream error */
+  0, /* verbose level */
+#ifdef TERM_CONTROL
+  FALSE, /* term control */
+#endif /* TERM_CONTROL */
+  -1, /* force mono */
+  0, /* force stereo */
+  0, /* force 8-bit */
+  0, /* force rate */
+  0, /* down sample */
+  FALSE, /* check range */
+  0, /* double speed */
+  0, /* half speed */
+  0, /* force re-open. always (re)opens audio device for next song */
+  0, /* 3Dnow: autodetect from CPUFLAGS */
+  FALSE, /* 3Dnow: normal operation */
+  FALSE, /* try to run process in 'realtime mode' */
+  { 0, }, /* wav, cdr, au filename */
+  NULL, /* esdserver */
+  NULL, /* equalfile */
+  0, /* enable_equalizer */
+  32768, /* outscale */
+  0, /* startFrame */
+};
+static long numframes = -1;
+static int intflag = FALSE;
+static struct mpstr mp;
+// stuff I have to have to make the linkage happy
+int OutputDescriptor;
+int buffer_fd[2];
+struct reader *rd;
+txfermem* buffermem;
+
+static void set_synth_functions(struct frame* fr) {
+  typedef int (*func)(real*, int, unsigned char*, int*);
+  typedef int (*func_mono)(real*, unsigned char*, int*);
+  typedef void (*func_dct36)(real*, real*, real*, real*, real*);
+
+  int ds = fr->down_sample;
+  int p8=0;
+
+  static func funcs[][4] = {
+    { synth_1to1,
+      synth_2to1,
+      synth_4to1,
+      synth_ntom } ,
+    { synth_1to1_8bit,
+      synth_2to1_8bit,
+      synth_4to1_8bit,
+      synth_ntom_8bit }
+  };
+  static func_mono funcs_mono[2][2][4] = {
+    { { synth_1to1_mono2stereo,
+	synth_2to1_mono2stereo,
+	synth_4to1_mono2stereo,
+	synth_ntom_mono2stereo } ,
+      { synth_1to1_8bit_mono2stereo,
+	synth_2to1_8bit_mono2stereo,
+	synth_4to1_8bit_mono2stereo,
+	synth_ntom_8bit_mono2stereo } } ,
+    { { synth_1to1_mono,
+	synth_2to1_mono,
+	synth_4to1_mono,
+	synth_ntom_mono } ,
+      { synth_1to1_8bit_mono,
+	synth_2to1_8bit_mono,
+	synth_4to1_8bit_mono,
+	synth_ntom_8bit_mono } } ,
+  };
+
+  if ((ai.format & AUDIO_FORMAT_MASK) == AUDIO_FORMAT_8)
+    p8 = 1;
+  fr->synth = funcs[p8][ds];
+  fr->synth_mono = funcs_mono[param.force_stereo?0:1][p8][ds];
+  if (p8)
+    make_conv16to8_table(ai.format);
+}
+
+static void initialize(void) {
+  if (initialized)
+    return;
+  // make sure params say what we want
+  param.quiet = TRUE;
+  param.force_stereo = 1;
+  param.force_rate = audio_mix_freq;
+
+  memset(&mp, 0, sizeof(struct mpstr));
+  audio_info_struct_init(&ai);
+  audio_capabilities(&ai);
+  set_synth_functions(&fr);
+  make_decode_tables(param.outscale);
+  init_layer2(); /* inits also shared tables with layer1 */
+  init_layer3(fr.down_sample);
+  equalizer_cnt = 0;
+  for (int i=0; i<32; ++i) {
+    equalizer[0][i] = equalizer[1][i] = 1.0;
+    equalizer_sum[0][i] = equalizer_sum[1][i] = 0.0;
+  }
+  initialized = true;
+}
+
+ostream* my_outstream;
+
+extern "C" {
+int audio_open(struct audio_info_struct* ai) {
+  return 0;
+}
+
+int audio_reset_parameters(struct audio_info_struct* ai) {
+  audio_set_format(ai);
+  audio_set_channels(ai);
+  audio_set_rate(ai);
+  return 0;
+}
+
+int audio_rate_best_match(struct audio_info_struct* ai) {
+  if (!ai || ai->rate < 0)
+    return -1;
+  ai->rate = audio_mix_freq;
+  return 0;
+}
+
+int audio_set_rate(struct audio_info_struct* ai) {
+  if (ai->rate != audio_mix_freq)
+    audio_cat->warning()
+      << "trying to decode mp3 to rate other then mix rate (" << ai->rate
+      << " != " << audio_mix_freq << ")" << endl;
+  return 0;
+}
+
+int audio_set_channels(struct audio_info_struct* ai) {
+  if (ai->channels != 2)
+    audio_cat->warning() << "trying to decode mp3 to non-stereo ("
+			 << ai->channels << " != 2)" << endl;
+  return 0;
+}
+
+int audio_set_format(struct audio_info_struct* ai) {
+  if (ai->format != AUDIO_FORMAT_SIGNED_16)
+    audio_cat->warning()
+      << "trying to decode mp3 to format other then signed 16-bit" << endl;
+  return 0;
+}
+
+int audio_get_formats(struct audio_info_struct* ai) {
+  return AUDIO_FORMAT_SIGNED_16;
+}
+
+int audio_play_samples(struct audio_info_struct* ai, unsigned char* buf,
+		       int len) {
+  for (int i=0; i<len; ++i)
+    (*my_outstream) << buf[i];
+  return len;
+}
+
+int audio_close(struct audio_info_struct* ai) {
+  return 0;
+}
+
+// we won't use these functions, but they have to exist
+int cdr_open(struct audio_info_struct *ai, char *ame) { return 0; }
+int au_open(struct audio_info_struct *ai, char *name) { return 0; }
+int wav_open(struct audio_info_struct *ai, char *wavfilename) { return 0; }
+int wav_write(unsigned char *buf,int len) { return 0; }
+int cdr_close(void) { return 0; }
+int au_close(void) { return 0; }
+int wav_close(void) { return 0; }
+int xfermem_get_usedspace(txfermem*) { return 0; }
+}
+
+static void init_output(void) {
+  static int init_done = FALSE;
+  if (init_done)
+    return;
+  init_done = TRUE;
+  // + 1024 for NtoM rate converter
+  if (!(pcm_sample = (unsigned char*)malloc(audiobufsize*2 + 2*1024))) {
+    audio_cat->fatal() << "cannot allocate sample buffer" << endl;
+    exit(1);
+  }
+  switch (param.outmode) {
+  case DECODE_AUDIO:
+    if (audio_open(&ai) < 0) {
+      audio_cat->fatal() << "could not open output stream" << endl;
+      exit(1);
+    }
+    break;
+  case DECODE_WAV:
+    wav_open(&ai, param.filename);
+    break;
+  case DECODE_AU:
+    au_open(&ai, param.filename);
+    break;
+  case DECODE_CDR:
+    cdr_open(&ai, param.filename);
+    break;
+  }
+}
+
+static void reset_audio(void) {
+  if (param.outmode == DECODE_AUDIO) {
+    audio_close(&ai);
+    if (audio_open(&ai) < 0) {
+      audio_cat->fatal() << "couldn't reopen" << endl;
+      exit(1);
+    }
+  }
+}
+
+int play_frame(struct mpstr* mp, int init, struct frame* fr) {
+  int clip;
+  long newrate;
+  long old_rate, old_format, old_channels;
+
+  if (fr->header_change || init) {
+    if (fr->header_change > 1 || init) {
+      old_rate = ai.rate;
+      old_format = ai.format;
+      old_channels = ai.channels;
+      newrate = freqs[fr->sampling_frequency]>>(param.down_sample);
+      fr->down_sample = param.down_sample;
+      audio_fit_capabilities(&ai, fr->stereo, newrate);
+      // check whether the fitter set our proposed rate
+      if (ai.rate != newrate) {
+	if (ai.rate == (newrate >> 1))
+	  fr->down_sample++;
+	else if (ai.rate == (newrate >> 2))
+	  fr->down_sample += 2;
+	else {
+	  fr->down_sample = 3;
+	  audio_cat->warning() << "flexable rate not heavily tested!" << endl;
+	}
+	if (fr->down_sample > 3)
+	  fr->down_sample = 3;
+      }
+      switch (fr->down_sample) {
+      case 0:
+      case 1:
+      case 2:
+	fr->down_sample_sblimit = SBLIMIT >> (fr->down_sample);
+	break;
+      case 3:
+	{
+	  long n = freqs[fr->sampling_frequency];
+	  long m = ai.rate;
+	  synth_ntom_set_step(n, m);
+	  if (n>m) {
+	    fr->down_sample_sblimit = SBLIMIT * m;
+	    fr->down_sample_sblimit /= n;
+	  } else
+	    fr->down_sample_sblimit = SBLIMIT;
+	}
+	break;
+      }
+      set_synth_functions(fr);
+      init_output();
+      if (ai.rate != old_rate || ai.channels != old_channels ||
+	  ai.format != old_format || param.force_reopen) {
+	if (param.force_mono < 0) {
+	  if (ai.channels == 1)
+	    fr->single = 3;
+	  else
+	    fr->single = -1;
+	} else
+	  fr->single = param.force_mono;
+	param.force_stereo &= ~0x2;
+	if (fr->single >= 0 && ai.channels == 2)
+	  param.force_stereo |= 0x2;
+	set_synth_functions(fr);
+	init_layer3(fr->down_sample_sblimit);
+	reset_audio();
+      }
+      if (intflag)
+	return !0;
+    }
+  }
+  if (fr->error_protection)
+    bsi.wordpointer += 2;
+  // do the decoding
+  switch (fr->lay) {
+  case 1:
+    if ((clip=do_layer1(mp, fr, param.outmode, &ai)) < 0)
+      return 0;
+    break;
+  case 2:
+    if ((clip=do_layer2(mp, fr, param.outmode, &ai)) < 0)
+      return 0;
+    break;
+  case 3:
+    if ((clip=do_layer3(mp, fr, param.outmode, &ai)) < 0)
+      return 0;
+    break;
+  default:
+    clip = 0;
+  }
+  if (clip > 0 && param.checkrange)
+    audio_cat->warning() << clip << " samples clipped" << endl;
+  return !0;
+}
+
+static void read_file(Filename filename, unsigned char** buf,
+		      unsigned long& slen) {
+  int init;
+  unsigned long frameNum = 0;
+  ostringstream out;
+
+  initialize();
+  my_outstream = &out;
+  if (open_stream((char*)(filename.c_str()), -1)) {
+    long leftFrames, newFrame;
+
+    read_frame_init();
+    init = 1;
+    newFrame = param.startFrame;
+    leftFrames = numframes;
+    for (frameNum=0; read_frame(&fr) && leftFrames && !intflag; ++frameNum) {
+      if (frameNum < param.startFrame || (param.doublespeed &&
+					  (frameNum % param.doublespeed))) {
+	if (fr.lay == 3)
+	  set_pointer(512);
+	continue;
+      }
+      if (leftFrames > 0)
+	--leftFrames;
+      if (!play_frame(&mp, init, &fr)) {
+	audio_cat->error() << "Error in frame #" << frameNum << endl;
+	break;
+      }
+      init = 0;
+    }
+    rd->close(rd);
+    if (intflag) {
+      intflag = FALSE;
+    }
+  }
+  audio_flush(param.outmode, &ai);
+  free(pcm_sample);
+  switch (param.outmode) {
+  case DECODE_AUDIO:
+    audio_close(&ai);
+    break;
+  case DECODE_WAV:
+    wav_close();
+    break;
+  case DECODE_AU:
+    au_close();
+    break;
+  case DECODE_CDR:
+    cdr_close();
+    break;
+  }
+  // generate output
+  string s = out.str();
+  slen = s.length();
+  *buf = new byte[slen];
+  memcpy(*buf, s.data(), slen);
+  my_outstream = (ostream*)0L;
+}
+
+#ifdef AUDIO_USE_MIKMOD
+
+#include "audio_mikmod_traits.h"
+
+void AudioDestroyMp3(AudioTraits::SampleClass* sample) {
+  delete sample;
+}
+
+void AudioLoadMp3(AudioTraits::SampleClass** sample,
+		  AudioTraits::PlayingClass** state,
+		  AudioTraits::PlayerClass** player,
+		  AudioTraits::DeleteSampleFunc** destroy, Filename) {
+  audio_cat->warning() << "Mikmod doesn't support reading mp3 data yet"
+		       << endl;
+  *sample = (AudioTraits::SampleClass*)0L;
+  *state = (AudioTraits::PlayingClass*)0L;
+  *player = (AudioTraits::PlayerClass*)0L;
+  *destroy = AudioDestroyMp3;
+}
+
+#elif defined(AUDIO_USE_WIN32)
+
+#include "audio_win_traits.h"
+
+void AudioDestroyMp3(AudioTraits::SampleClass* sample) {
+  delete sample;
+}
+
+void AudioLoadMp3(AudioTraits::SampleClass** sample,
+		  AudioTraits::PlayingClass** state,
+		  AudioTraits::PlayerClass** player,
+		  AudioTraits::DeleteSampleFunc** destroy, Filename) {
+  audio_cat->warning() << "win32 doesn't support reading mp3 data yet"
+		       << endl;
+  *sample = (AudioTraits::SampleClass*)0L;
+  *state = (AudioTraits::PlayingClass*)0L;
+  *player = (AudioTraits::PlayerClass*)0L;
+  *destroy = AudioDestroyMp3;
+}
+
+#elif defined(AUDIO_USE_LINUX)
+
+#include "audio_linux_traits.h"
+
+void AudioDestroyMp3(AudioTraits::SampleClass* sample) {
+  delete sample;
+}
+
+void AudioLoadMp3(AudioTraits::SampleClass** sample,
+		  AudioTraits::PlayingClass** state,
+		  AudioTraits::PlayerClass** player,
+		  AudioTraits::DeleteSampleFunc** destroy, Filename filename) {
+  unsigned char* buf;
+  unsigned long len;
+  read_file(filename, &buf, len);
+  if (buf != (unsigned char*)0L) {
+    *sample = LinuxSample::load_raw(buf, len);
+    *state = ((LinuxSample*)(*sample))->get_state();
+    *player = LinuxPlayer::get_instance();
+    *destroy = AudioDestroyMp3;
+  } else {
+    *sample = (AudioTraits::SampleClass*)0L;
+    *state = (AudioTraits::PlayingClass*)0L;
+    *player = (AudioTraits::PlayerClass*)0L;
+    *destroy = AudioDestroyMp3;
+  }
+}
+
+#elif defined(AUDIO_USE_NULL)
+
+#include "audio_null_traits.h"
+
+void AudioDestroyMp3(AudioTraits::SampleClass* sample) {
+  delete sample;
+}
+
+void AudioLoadMp3(AudioTraits::SampleClass** sample,
+		  AudioTraits::PlayingClass** state,
+		  AudioTraits::PlayerClass** player,
+		  AudioTraits::DeleteSampleFunc** destroy, Filename) {
+  *sample = (AudioTraits::SampleClass*)0L;
+  *state = (AudioTraits::PlayingClass*)0L;
+  *player = (AudioTraits::PlayerClass*)0L;
+  *destroy = AudioDestroyMp3;
+}
+
+#else
+
+#error "unknown audio driver type"
+
+#endif
+
+ConfigureFn(audio_load_mp3) {
+  AudioPool::register_sample_loader("mp3", AudioLoadMp3);
+}