woo! mp3 support

This commit is contained in:
Cary Sandvig 2000-10-12 21:36:33 +00:00
parent 7d7e84061a
commit dfb5f81965

View File

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