Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
17 KB
Referenced Files
None
Subscribers
None
diff --git a/util/gme/Music_Emu.h b/util/gme/Music_Emu.h
index 9e35413f..c3d4d8db 100644
--- a/util/gme/Music_Emu.h
+++ b/util/gme/Music_Emu.h
@@ -1,211 +1,211 @@
// Common interface to game music file emulators
// Game_Music_Emu 0.5.5
#ifndef MUSIC_EMU_H
#define MUSIC_EMU_H
#include "Gme_File.h"
class Multi_Buffer;
-struct Music_Emu : public Gme_File {
+class Music_Emu : public Gme_File {
public:
// Basic functionality (see Gme_File.h for file loading/track info functions)
// Set output sample rate. Must be called only once before loading file.
blargg_err_t set_sample_rate( long sample_rate );
// Start a track, where 0 is the first track. Also clears warning string.
blargg_err_t start_track( int );
// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
// errors set warning string, and major errors also end track.
typedef short sample_t;
blargg_err_t play( long count, sample_t* buf );
// Informational
// Sample rate sound is generated at
long sample_rate() const;
// Index of current track or -1 if one hasn't been started
int current_track() const;
// Number of voices used by currently loaded file
int voice_count() const;
// Names of voices
const char** voice_names() const;
// Track status/control
// Number of milliseconds (1000 msec = 1 second) played since beginning of track
long tell() const;
// Seek to new time in track. Seeking backwards or far forward can take a while.
blargg_err_t seek( long msec );
// Skip n samples
blargg_err_t skip( long n );
// True if a track has reached its end
bool track_ended() const;
// Set start time and length of track fade out. Once fade ends track_ended() returns
// true. Fade time can be changed while track is playing.
void set_fade( long start_msec, long length_msec = 8000 );
// Disable automatic end-of-track detection and skipping of silence at beginning
void ignore_silence( bool disable = true );
// Info for current track
using Gme_File::track_info;
blargg_err_t track_info( track_info_t* out ) const;
// Sound customization
// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
// Track length as returned by track_info() assumes a tempo of 1.0.
void set_tempo( double );
// Mute/unmute voice i, where voice 0 is first voice
void mute_voice( int index, bool mute = true );
// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
// 0 unmutes them all, 0x01 mutes just the first voice, etc.
void mute_voices( int mask );
// Change overall output amplitude, where 1.0 results in minimal clamping.
// Must be called before set_sample_rate().
void set_gain( double );
// Request use of custom multichannel buffer. Only supported by "classic" emulators;
// on others this has no effect. Should be called only once *before* set_sample_rate().
virtual void set_buffer( Multi_Buffer* ) { }
// Sound equalization (treble/bass)
// Frequency equalizer parameters (see gme.txt)
// See gme.h for definition of struct gme_equalizer_t.
typedef gme_equalizer_t equalizer_t;
// Current frequency equalizater parameters
equalizer_t const& equalizer() const;
// Set frequency equalizer parameters
void set_equalizer( equalizer_t const& );
// Equalizer settings for TV speaker
static equalizer_t const tv_eq;
public:
Music_Emu();
~Music_Emu();
protected:
void set_max_initial_silence( int n ) { max_initial_silence = n; }
void set_silence_lookahead( int n ) { silence_lookahead = n; }
void set_voice_count( int n ) { voice_count_ = n; }
void set_voice_names( const char* const* names );
void set_track_ended() { emu_track_ended_ = true; }
double gain() const { return gain_; }
double tempo() const { return tempo_; }
void remute_voices();
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
virtual void set_equalizer_( equalizer_t const& ) { };
virtual void mute_voices_( int mask ) = 0;
virtual void set_tempo_( double ) = 0;
virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this
virtual blargg_err_t play_( long count, sample_t* out ) = 0;
virtual blargg_err_t skip_( long count );
protected:
virtual void unload();
virtual void pre_load();
virtual void post_load_();
private:
// general
equalizer_t equalizer_;
int max_initial_silence;
const char** voice_names_;
int voice_count_;
int mute_mask_;
double tempo_;
double gain_;
long sample_rate_;
blargg_long msec_to_samples( blargg_long msec ) const;
// track-specific
int current_track_;
blargg_long out_time; // number of samples played since start of track
blargg_long emu_time; // number of samples emulator has generated since start of track
bool emu_track_ended_; // emulator has reached end of track
volatile bool track_ended_;
void clear_track_vars();
void end_track_if_error( blargg_err_t );
// fading
blargg_long fade_start;
int fade_step;
void handle_fade( long count, sample_t* out );
// silence detection
int silence_lookahead; // speed to run emulator when looking ahead for silence
bool ignore_silence_;
long silence_time; // number of samples where most recent silence began
long silence_count; // number of samples of silence to play before using buf
long buf_remain; // number of samples left in silence buffer
enum { buf_size = 2048 };
blargg_vector<sample_t> buf;
void fill_buf();
void emu_play( long count, sample_t* out );
Multi_Buffer* effects_buffer;
friend Music_Emu* gme_new_emu( gme_type_t, int );
friend void gme_set_stereo_depth( Music_Emu*, double );
};
// base class for info-only derivations
struct Gme_Info_ : Music_Emu
{
virtual blargg_err_t set_sample_rate_( long sample_rate );
virtual void set_equalizer_( equalizer_t const& );
virtual void mute_voices_( int mask );
virtual void set_tempo_( double );
virtual blargg_err_t start_track_( int );
virtual blargg_err_t play_( long count, sample_t* out );
virtual void pre_load();
virtual void post_load_();
};
inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const
{
return track_info( out, current_track_ );
}
inline long Music_Emu::sample_rate() const { return sample_rate_; }
inline const char** Music_Emu::voice_names() const { return voice_names_; }
inline int Music_Emu::voice_count() const { return voice_count_; }
inline int Music_Emu::current_track() const { return current_track_; }
inline bool Music_Emu::track_ended() const { return track_ended_; }
inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; }
inline void Music_Emu::set_tempo_( double t ) { tempo_ = t; }
inline void Music_Emu::remute_voices() { mute_voices( mute_mask_ ); }
inline void Music_Emu::ignore_silence( bool b ) { ignore_silence_ = b; }
inline blargg_err_t Music_Emu::start_track_( int ) { return 0; }
inline void Music_Emu::set_voice_names( const char* const* names )
{
// Intentional removal of const, so users don't have to remember obscure const in middle
voice_names_ = const_cast<const char**> (names);
}
inline void Music_Emu::mute_voices_( int ) { }
inline void Music_Emu::set_gain( double g )
{
assert( !sample_rate() ); // you must set gain before setting sample rate
gain_ = g;
}
#endif
diff --git a/util/sdl/mixer/music_mad.c b/util/sdl/mixer/music_mad.c
index e9dfead3..f4114b34 100644
--- a/util/sdl/mixer/music_mad.c
+++ b/util/sdl/mixer/music_mad.c
@@ -1,345 +1,345 @@
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2009 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef MP3_MAD_MUSIC
#include <string.h>
#include "music_mad.h"
mad_data *
mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
SDL_RWops *rw;
mad_data *mp3_mad;
rw = SDL_RWFromFile(filename, "rb");
if (rw == NULL) {
return NULL;
}
mp3_mad = mad_openFileRW(rw, mixer);
if (mp3_mad == NULL) {
SDL_FreeRW(rw);
return NULL;
}
mp3_mad->freerw = SDL_TRUE;
return mp3_mad;
}
mad_data *
mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
mad_data *mp3_mad;
mp3_mad = (mad_data *)malloc(sizeof(mad_data));
if (mp3_mad) {
mp3_mad->rw = rw;
mp3_mad->freerw = SDL_FALSE;
mad_stream_init(&mp3_mad->stream);
mad_frame_init(&mp3_mad->frame);
mad_synth_init(&mp3_mad->synth);
mp3_mad->frames_read = 0;
mad_timer_reset(&mp3_mad->next_frame_start);
mp3_mad->volume = MIX_MAX_VOLUME;
mp3_mad->status = 0;
mp3_mad->output_begin = 0;
mp3_mad->output_end = 0;
mp3_mad->mixer = *mixer;
}
return mp3_mad;
}
void
mad_closeFile(mad_data *mp3_mad) {
mad_stream_finish(&mp3_mad->stream);
mad_frame_finish(&mp3_mad->frame);
mad_synth_finish(&mp3_mad->synth);
if (mp3_mad->freerw) {
SDL_FreeRW(mp3_mad->rw);
}
free(mp3_mad);
}
/* Starts the playback. */
void
mad_start(mad_data *mp3_mad) {
mp3_mad->status |= MS_playing;
}
/* Stops the playback. */
void
mad_stop(mad_data *mp3_mad) {
mp3_mad->status &= ~MS_playing;
}
/* Returns true if the playing is engaged, false otherwise. */
int
mad_isPlaying(mad_data *mp3_mad) {
return ((mp3_mad->status & MS_playing) != 0);
}
/* Reads the next frame from the file. Returns true on success or
false on failure. */
static int
read_next_frame(mad_data *mp3_mad) {
if (mp3_mad->stream.buffer == NULL ||
mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
size_t read_size;
size_t remaining;
unsigned char *read_start;
/* There might be some bytes in the buffer left over from last
time. If so, move them down and read more bytes following
them. */
if (mp3_mad->stream.next_frame != NULL) {
remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
read_start = mp3_mad->input_buffer + remaining;
read_size = MAD_INPUT_BUFFER_SIZE - remaining;
} else {
read_size = MAD_INPUT_BUFFER_SIZE;
read_start = mp3_mad->input_buffer;
remaining = 0;
}
/* Now read additional bytes from the input file. */
read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
if (read_size <= 0) {
if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
if (read_size == 0) {
mp3_mad->status |= MS_input_eof;
} else {
mp3_mad->status |= MS_input_error;
}
/* At the end of the file, we must stuff MAD_BUFFER_GUARD
number of 0 bytes. */
memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
read_size += MAD_BUFFER_GUARD;
}
}
/* Now feed those bytes into the libmad stream. */
mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
read_size + remaining);
mp3_mad->stream.error = MAD_ERROR_NONE;
}
/* Now ask libmad to extract a frame from the data we just put in
its buffer. */
if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
return 0;
} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
return 0;
} else {
mp3_mad->status |= MS_decode_error;
return 0;
}
}
mp3_mad->frames_read++;
mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
return 1;
}
/* Scale a MAD sample to 16 bits for output. */
static signed int
scale(mad_fixed_t sample) {
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
/* Once the frame has been read, copies its samples into the output
buffer. */
static void
decode_frame(mad_data *mp3_mad) {
struct mad_pcm *pcm;
unsigned int nchannels, nsamples;
mad_fixed_t const *left_ch, *right_ch;
unsigned char *out;
int ret;
mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
pcm = &mp3_mad->synth.pcm;
out = mp3_mad->output_buffer + mp3_mad->output_end;
if ((mp3_mad->status & MS_cvt_decoded) == 0) {
mp3_mad->status |= MS_cvt_decoded;
/* The first frame determines some key properties of the stream.
In particular, it tells us enough to set up the convert
structure now. */
SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
}
/* pcm->samplerate contains the sampling frequency */
nchannels = pcm->channels;
nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
while (nsamples--) {
signed int sample;
/* output sample(s) in 16-bit signed little-endian PCM */
sample = scale(*left_ch++);
*out++ = ((sample >> 0) & 0xff);
*out++ = ((sample >> 8) & 0xff);
if (nchannels == 2) {
sample = scale(*right_ch++);
*out++ = ((sample >> 0) & 0xff);
*out++ = ((sample >> 8) & 0xff);
}
}
mp3_mad->output_end = out - mp3_mad->output_buffer;
/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
}
int
mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
int bytes_remaining;
int num_bytes;
Uint8 *out;
if ((mp3_mad->status & MS_playing) == 0) {
/* We're not supposed to be playing, so send silence instead. */
memset(stream, 0, len);
- return;
+ return 0;
}
out = stream;
bytes_remaining = len;
while (bytes_remaining > 0) {
if (mp3_mad->output_end == mp3_mad->output_begin) {
/* We need to get a new frame. */
mp3_mad->output_begin = 0;
mp3_mad->output_end = 0;
if (!read_next_frame(mp3_mad)) {
if ((mp3_mad->status & MS_error_flags) != 0) {
/* Couldn't read a frame; either an error condition or
end-of-file. Stop. */
memset(out, 0, bytes_remaining);
mp3_mad->status &= ~MS_playing;
return bytes_remaining;
}
} else {
decode_frame(mp3_mad);
/* Now convert the frame data to the appropriate format for
output. */
mp3_mad->cvt.buf = mp3_mad->output_buffer;
mp3_mad->cvt.len = mp3_mad->output_end;
mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
SDL_ConvertAudio(&mp3_mad->cvt);
}
}
num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
if (bytes_remaining < num_bytes) {
num_bytes = bytes_remaining;
}
if (mp3_mad->volume == MIX_MAX_VOLUME) {
memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
} else {
SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
num_bytes, mp3_mad->volume);
}
out += num_bytes;
mp3_mad->output_begin += num_bytes;
bytes_remaining -= num_bytes;
}
return 0;
}
void
mad_seek(mad_data *mp3_mad, double position) {
mad_timer_t target;
int int_part;
int_part = (int)position;
mad_timer_set(&target, int_part,
(int)((position - int_part) * 1000000), 1000000);
if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
/* In order to seek backwards in a VBR file, we have to rewind and
start again from the beginning. This isn't necessary if the
file happens to be CBR, of course; in that case we could seek
directly to the frame we want. But I leave that little
optimization for the future developer who discovers she really
needs it. */
mp3_mad->frames_read = 0;
mad_timer_reset(&mp3_mad->next_frame_start);
mp3_mad->status &= ~MS_error_flags;
mp3_mad->output_begin = 0;
mp3_mad->output_end = 0;
SDL_RWseek(mp3_mad->rw, 0, RW_SEEK_SET);
}
/* Now we have to skip frames until we come to the right one.
Again, only truly necessary if the file is VBR. */
while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
if (!read_next_frame(mp3_mad)) {
if ((mp3_mad->status & MS_error_flags) != 0) {
/* Couldn't read a frame; either an error condition or
end-of-file. Stop. */
mp3_mad->status &= ~MS_playing;
return;
}
}
}
/* Here we are, at the beginning of the frame that contains the
target time. Ehh, I say that's close enough. If we wanted to,
we could get more precise by decoding the frame now and counting
the appropriate number of samples out of it. */
}
void
mad_setVolume(mad_data *mp3_mad, int volume) {
mp3_mad->volume = volume;
}
#endif /* MP3_MAD_MUSIC */

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 11:16 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68690
Default Alt Text
(17 KB)

Event Timeline