Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
31 KB
Referenced Files
None
Subscribers
None
diff --git a/util/input/sdl/joystick.cpp b/util/input/sdl/joystick.cpp
index 6317188a..8ca13343 100644
--- a/util/input/sdl/joystick.cpp
+++ b/util/input/sdl/joystick.cpp
@@ -1,338 +1,405 @@
#ifdef USE_SDL
#include <SDL.h>
#include "joystick.h"
#include "util/debug.h"
#include <string>
+#include <vector>
using std::string;
+using std::vector;
class ButtonMapping{
public:
ButtonMapping(){
}
virtual ~ButtonMapping(){
}
virtual int toNative(int button) = 0;
virtual int fromNative(int button) = 0;
virtual Joystick::Key toKey(int button) = 0;
- virtual Joystick::Key axisMotionToKey(int axis, int motion) = 0;
+ virtual void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events) = 0;
};
class DefaultButtonMapping: public ButtonMapping {
public:
int toNative(int button){
return button;
}
int fromNative(int button){
return button;
}
Joystick::Key toKey(int button){
switch (button){
case 0: return Joystick::Button1;
case 1: return Joystick::Button2;
case 2: return Joystick::Button3;
case 3: return Joystick::Button4;
case 4: return Joystick::Quit;
default: return Joystick::Invalid;
}
}
- Joystick::Key axisMotionToKey(int axis, int motion){
+ void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
/* FIXME */
/*
if (axis == 0){
if (motion < 0){
return Joystick::Left;
} else if (motion > 0){
return Joystick::Right;
}
} else if (axis == 1){
if (motion < 0){
return Joystick::Up;
} else if (motion > 0){
return Joystick::Down;
}
}
*/
- return Joystick::Invalid;
}
};
/* used when a ps3 controller is plugged into a usb port of a normal pc */
class Playstation3Controller: public ButtonMapping {
public:
enum Buttons{
Cross = 14,
Circle = 13,
Triangle = 12,
Square = 15,
Start = 3,
Select = 0,
Up = 4,
Left = 7,
Down = 6,
Right = 5,
Stick1 = 1,
Stick2 = 2,
L2 = 8,
L1 = 10,
R2 = 9,
R1 = 11,
/* the middle ps3 button */
Ps3 = 16
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case Start: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
- Joystick::Key axisMotionToKey(int axis, int motion){
+ void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
+ }
+};
+
+class LogitechPrecision: public ButtonMapping {
+public:
+ enum Buttons{
+ Button1 = 0,
+ Button2 = 1,
+ Button3 = 2,
+ Button4 = 3,
+ Start = 8,
+ Select = 9,
+ R2 = 7,
+ R1 = 5,
+ L2 = 6,
+ L1 = 4
+ };
+
+ int toNative(int button){
+ return -1;
+ }
+
+ int fromNative(int button){
+ return -1;
+ }
+
+ Joystick::Key toKey(int button){
+ switch (button){
+ case Button1: return Joystick::Button1;
+ case Button2: return Joystick::Button2;
+ case Button3: return Joystick::Button3;
+ case Button4: return Joystick::Button4;
+ case Start: return Joystick::Quit;
+ }
return Joystick::Invalid;
}
+
+ /* axis 1. negative up, positive down
+ * axis 0, negative left, positive right
+ */
+ void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
+ if (axis == 0){
+ if (motion < 0){
+ events.push_back(Joystick::Event(Joystick::Left, true));
+ } else if (motion > 0){
+ events.push_back(Joystick::Event(Joystick::Right, true));
+ } else if (motion == 0){
+ /* fake a release for left and right */
+ events.push_back(Joystick::Event(Joystick::Left, false));
+ events.push_back(Joystick::Event(Joystick::Right, false));
+ }
+ } else if (axis == 1){
+ if (motion < 0){
+ events.push_back(Joystick::Event(Joystick::Up, true));
+ } else if (motion > 0){
+ events.push_back(Joystick::Event(Joystick::Down, true));
+ } else if (motion == 0){
+ events.push_back(Joystick::Event(Joystick::Up, false));
+ events.push_back(Joystick::Event(Joystick::Down, false));
+ }
+ }
+ }
};
/* used for the ps3 controller with psl1ght's SDL version */
class Ps3Controller: public ButtonMapping {
public:
enum Buttons{
Left = 0,
Down = 1,
Right = 2,
Up = 3,
Select = 7,
Start = 4,
Square = 8,
Cross = 9,
Circle = 10,
Triangle = 11
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case Start: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
- Joystick::Key axisMotionToKey(int axis, int motion){
- return Joystick::Invalid;
+ void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
};
ButtonMapping * makeButtonMapping(string name){
#ifdef PS3
return new Ps3Controller();
#endif
if (name == "Sony PLAYSTATION(R)3 Controller"){
return new Playstation3Controller();
}
+ if (name == "Logitech Logitech(R) Precision(TM) Gamepad"){
+ return new LogitechPrecision();
+ }
return new DefaultButtonMapping();
}
void SDLJoystick::poll(){
events.clear();
}
static bool read_button(SDL_Joystick * joystick, int button){
return SDL_JoystickGetButton(joystick, button);
}
JoystickInput SDLJoystick::readAll(){
JoystickInput input;
return input;
if (joystick){
int buttons = SDL_JoystickNumButtons(joystick);
switch (buttons > 5 ? 5 : buttons){
case 5: input.quit = read_button(joystick, buttonMapping->toNative(4));
case 4: input.button4 = read_button(joystick, buttonMapping->toNative(3));
case 3: input.button3 = read_button(joystick, buttonMapping->toNative(2));
case 2: input.button2 = read_button(joystick, buttonMapping->toNative(1));
case 1: input.button1 = read_button(joystick, buttonMapping->toNative(0));
case 0: {
break;
}
}
}
int axis = SDL_JoystickNumAxes(joystick);
if (axis > 0){
int position = SDL_JoystickGetAxis(joystick, 0);
if (position < 0){
input.left = true;
} else if (position > 0){
input.right = true;
}
}
if (axis > 1){
int position = SDL_JoystickGetAxis(joystick, 1);
if (position < 0){
input.up = true;
} else if (position > 0){
input.down = true;
}
}
int hats = SDL_JoystickNumHats(joystick);
if (hats > 0){
int hat = SDL_JoystickGetHat(joystick, 0);
if ((hat & SDL_HAT_UP) == SDL_HAT_UP){
input.up = true;
}
if ((hat & SDL_HAT_DOWN) == SDL_HAT_DOWN){
input.down = true;
}
if ((hat & SDL_HAT_LEFT) == SDL_HAT_LEFT){
input.left = true;
}
if ((hat & SDL_HAT_RIGHT) == SDL_HAT_RIGHT){
input.right = true;
}
if ((hat & SDL_HAT_RIGHTUP) == SDL_HAT_RIGHTUP){
input.right = true;
input.up = true;
}
if ((hat & SDL_HAT_RIGHTDOWN) == SDL_HAT_RIGHTDOWN){
input.right = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTDOWN) == SDL_HAT_LEFTDOWN){
input.left = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTUP) == SDL_HAT_LEFTUP){
input.left = true;
input.up = true;
}
}
return input;
}
SDLJoystick::~SDLJoystick(){
if (joystick){
SDL_JoystickClose(joystick);
}
}
SDLJoystick::SDLJoystick():
joystick(NULL){
if (SDL_NumJoysticks() > 0){
joystick = SDL_JoystickOpen(0);
Global::debug(1) << "Opened joystick '" << SDL_JoystickName(0) << "'" << std::endl;
buttonMapping = makeButtonMapping(SDL_JoystickName(0));
}
}
void SDLJoystick::pressButton(int button){
// Global::debug(0) << "Pressed button " << button << std::endl;
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, true));
}
}
}
void SDLJoystick::releaseButton(int button){
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, false));
}
}
}
void SDLJoystick::axisMotion(int axis, int motion){
+ // Global::debug(0) << "Axis motion on " << axis << " motion " << motion << std::endl;
if (joystick){
- Key move = buttonMapping->axisMotionToKey(axis, motion);
- if (move != Invalid){
- events.push_back(Event(move, true));
+ buttonMapping->axisMotionEvents(axis, motion, events);
+ /*
+ Event move = buttonMapping->axisMotionToEvent(axis, motion);
+ if (move.key != Invalid){
+ events.push_back(move);
}
+ */
}
}
int SDLJoystick::getDeviceId() const {
if (joystick){
return SDL_JoystickIndex(joystick);
}
return -1;
}
#endif
diff --git a/util/music-player.cpp b/util/music-player.cpp
index e2db6747..25b5d2c9 100644
--- a/util/music-player.cpp
+++ b/util/music-player.cpp
@@ -1,643 +1,649 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#include "music-player.h"
#include "globals.h"
#include "util/debug.h"
#include <iostream>
#include "configuration.h"
#include "sound.h"
#include "dumb/include/dumb.h"
#include "gme/Music_Emu.h"
#include "exceptions/exception.h"
#include <sstream>
#include <stdio.h>
#ifdef USE_ALLEGRO5
#include <allegro5/allegro_audio.h>
#endif
#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#ifdef _WIN32
/* what do we need winalleg for?
* reason: ...
*/
#include <winalleg.h>
#endif
#endif
#ifdef HAVE_MP3_MPG123
#include <mpg123.h>
#endif
#ifdef HAVE_MP3_MAD
#include <mad.h>
#endif
#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif
namespace Util{
class MusicException: public Exception::Base {
public:
MusicException(const std::string & file, int line, const std::string & reason):
Exception::Base(file, line),
reason(reason){
}
MusicException(const MusicException & copy):
Exception::Base(copy),
reason(copy.reason){
}
virtual ~MusicException() throw(){
}
protected:
virtual const std::string getReason() const {
return reason;
}
virtual Exception::Base * copy() const {
return new MusicException(*this);
}
std::string reason;
};
static double scaleVolume(double start){
return start;
}
/* 1 for big endian (most significant byte)
* 0 for little endian (least significant byte)
*/
/* FIXME: move this to global or something and find a better #ifdef */
int bigEndian(){
#ifdef PS3
return 1;
#else
return 0;
#endif
}
#ifdef USE_ALLEGRO5
const int DUMB_SAMPLES = 1024;
MusicRenderer::MusicRenderer(){
create(Sound::Info.frequency, 2);
}
MusicRenderer::MusicRenderer(int frequency, int channels){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
ALLEGRO_CHANNEL_CONF configuration = ALLEGRO_CHANNEL_CONF_2;
switch (channels){
case 1: configuration = ALLEGRO_CHANNEL_CONF_1; break;
case 2: configuration = ALLEGRO_CHANNEL_CONF_2; break;
case 3: configuration = ALLEGRO_CHANNEL_CONF_3; break;
case 4: configuration = ALLEGRO_CHANNEL_CONF_4; break;
case 5: configuration = ALLEGRO_CHANNEL_CONF_5_1; break;
case 6: configuration = ALLEGRO_CHANNEL_CONF_6_1; break;
case 7: configuration = ALLEGRO_CHANNEL_CONF_7_1; break;
default: configuration = ALLEGRO_CHANNEL_CONF_2; break;
}
stream = al_create_audio_stream(4, DUMB_SAMPLES, frequency, ALLEGRO_AUDIO_DEPTH_INT16, configuration);
if (!stream){
throw MusicException(__FILE__, __LINE__, "Could not create allegro5 audio stream");
}
queue = al_create_event_queue();
al_register_event_source(queue, al_get_audio_stream_event_source(stream));
}
void MusicRenderer::play(MusicPlayer & player){
al_attach_audio_stream_to_mixer(stream, al_get_default_mixer());
}
void MusicRenderer::pause(){
al_detach_audio_stream(stream);
}
MusicRenderer::~MusicRenderer(){
al_destroy_audio_stream(stream);
al_destroy_event_queue(queue);
}
void MusicRenderer::poll(MusicPlayer & player){
ALLEGRO_EVENT event;
while (al_get_next_event(queue, &event)){
if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) {
ALLEGRO_AUDIO_STREAM * stream = (ALLEGRO_AUDIO_STREAM *) event.any.source;
void * data = al_get_audio_stream_fragment(stream);
if (data != NULL){
player.render(data, al_get_audio_stream_length(stream));
al_set_audio_stream_fragment(stream, data);
}
}
}
}
#elif USE_SDL
MusicRenderer::MusicRenderer(){
create(Sound::Info.frequency, Sound::Info.channels);
}
MusicRenderer::MusicRenderer(int frequency, int channels){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
int format = AUDIO_S16;
if (bigEndian()){
format = AUDIO_S16MSB;
}
SDL_BuildAudioCVT(&convert, format, channels, frequency,
Sound::Info.format, Sound::Info.channels,
Sound::Info.frequency);
data = new Uint8[1024 * 32];
}
void MusicRenderer::mixer(void * arg, Uint8 * stream, int bytes){
MusicPlayer * player = (MusicPlayer*) arg;
int size = (int)((float) bytes / player->getRenderer()->convert.len_ratio / (float) player->getRenderer()->convert.len_mult);
// Global::debug(0) << "Incoming " << bytes << " render " << size << std::endl;
player->getRenderer()->convert.buf = player->getRenderer()->data;
player->getRenderer()->convert.len = size;
// player->render(stream, bytes / 4);
player->render(player->getRenderer()->data, size / 4);
SDL_ConvertAudio(&player->getRenderer()->convert);
memcpy(stream, player->getRenderer()->data, bytes);
}
void MusicRenderer::play(MusicPlayer & player){
Mix_HookMusic(mixer, &player);
}
void MusicRenderer::pause(){
Mix_HookMusic(NULL, NULL);
}
void MusicRenderer::poll(MusicPlayer & player){
}
MusicRenderer::~MusicRenderer(){
Mix_HookMusic(NULL, NULL);
delete[] data;
}
#elif USE_ALLEGRO
int BUFFER_SIZE = 1 << 11;
static int ALLEGRO_MONO = 0;
static int ALLEGRO_STEREO = 1;
MusicRenderer::MusicRenderer(){
create(Sound::Info.frequency, 1);
}
MusicRenderer::MusicRenderer(int frequency, int channels){
create(frequency, channels);
}
void MusicRenderer::create(int frequency, int channels){
int configuration = ALLEGRO_STEREO;
if (channels == 1){
configuration = ALLEGRO_MONO;
}
stream = play_audio_stream(BUFFER_SIZE, 16, configuration, frequency, 255, 128);
+ if (!stream){
+ throw MusicException(__FILE__, __LINE__, "Could not create Allegro stream");
+ }
+ if (stream->len != BUFFER_SIZE){
+ throw MusicException(__FILE__, __LINE__, "Buffer size mismatch");
+ }
voice_set_priority(stream->voice, 255);
}
void MusicRenderer::play(MusicPlayer & player){
voice_start(stream->voice);
}
void MusicRenderer::pause(){
voice_stop(stream->voice);
}
void MusicRenderer::poll(MusicPlayer & player){
short * buffer = (short*) get_audio_stream_buffer(stream);
if (buffer){
player.render(buffer, BUFFER_SIZE);
/* allegro wants unsigned data but gme produces signed so to convert
* signed samples to unsigned samples we have to raise each value
* by half the maximum value of a short (0xffff+1)/2 = 0x8000
*/
for (int i = 0; i < BUFFER_SIZE * 2; i++){
buffer[i] += 0x8000;
}
free_audio_stream_buffer(stream);
}
}
MusicRenderer::~MusicRenderer(){
stop_audio_stream(stream);
}
#endif
MusicPlayer::MusicPlayer():
volume(1.0),
out(new MusicRenderer()){
}
MusicPlayer::~MusicPlayer(){
}
void MusicPlayer::setRenderer(const ReferenceCount<MusicRenderer> & what){
this->out = what;
}
void MusicPlayer::play(){
out->play(*this);
}
void MusicPlayer::pause(){
out->pause();
}
void MusicPlayer::poll(){
out->poll(*this);
}
static const char * typeToExtension( int i ){
switch (i){
case 0 : return ".xm";
case 1 : return ".s3m";
case 2 : return ".it";
case 3 : return ".mod";
default : return "";
}
}
/* expects each sample to be 4 bytes, 2 bytes per sample * 2 channels */
DumbPlayer::DumbPlayer(const char * path){
music_file = loadDumbFile(path);
if (music_file == NULL){
std::ostringstream error;
error << "Could not load DUMB file " << path;
throw MusicException(__FILE__, __LINE__, error.str());
}
int n_channels = 2;
int position = 0;
renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
if (!renderer){
Global::debug(0) << "Could not create renderer" << std::endl;
throw Exception::Base(__FILE__, __LINE__);
}
}
void DumbPlayer::render(void * data, int samples){
double delta = 65536.0 / Sound::Info.frequency;
/* FIXME: use global music volume to scale the output here */
int n = duh_render(renderer, 16, 0, volume, delta, samples, data);
}
void DumbPlayer::setVolume(double volume){
this->volume = volume;
}
DumbPlayer::~DumbPlayer(){
duh_end_sigrenderer(renderer);
unload_duh(music_file);
}
DUH * DumbPlayer::loadDumbFile(const char * path){
DUH * what;
for (int i = 0; i < 4; i++){
/* the order of trying xm/s3m/it/mod matters because mod could be
* confused with one of the other formats, so load it last.
*/
switch (i){
case 0 : {
what = dumb_load_xm_quick(path);
break;
}
case 1 : {
what = dumb_load_s3m_quick(path);
break;
}
case 2 : {
what = dumb_load_it_quick(path);
break;
}
case 3 : {
what = dumb_load_mod_quick(path);
break;
}
}
if (what != NULL){
Global::debug(0) << "Loaded " << path << " type " << typeToExtension(i) << "(" << i << ")" << std::endl;
return what;
}
}
return NULL;
}
GMEPlayer::GMEPlayer(const char * path):
emulator(NULL){
gme_err_t fail = gme_open_file(path, &emulator, Sound::Info.frequency);
if (fail != NULL){
Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
throw MusicException(__FILE__, __LINE__, "Could not load GME file");
}
emulator->start_track(0);
Global::debug(0) << "Loaded GME file " << path << std::endl;
}
void GMEPlayer::render(void * stream, int length){
/* length/2 to convert bytes to short */
emulator->play(length * 2, (short*) stream);
if (emulator->track_ended()){
gme_info_t * info;
gme_track_info(emulator, &info, 0);
int intro = info->intro_length;
emulator->start_track(0);
// Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
/* skip past the intro if there is a loop */
if (info->loop_length != 0){
emulator->seek(intro);
}
}
/* scale for volume */
for (int i = 0; i < length * 2; i++){
short & sample = ((short *) stream)[i];
sample *= volume;
}
/*
short large = 0;
short small = 0;
for (int i = 0; i < length / 2; i++){
// ((short *) stream)[i] *= 2;
short z = ((short *) stream)[i];
if (z < small){
small = z;
}
if (z > large){
large = z;
}
}
Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
*/
}
void GMEPlayer::setVolume(double volume){
this->volume = volume;
}
GMEPlayer::~GMEPlayer(){
delete emulator;
}
#ifdef HAVE_MP3_MPG123
/* initialize the mpg123 library and open up an mp3 file for reading */
static void initializeMpg123(mpg123_handle ** mp3, const char * path){
/* Initialize */
if (mpg123_init() != MPG123_OK){
throw MusicException(__FILE__, __LINE__, "Could not initialize mpg123");
}
try{
*mp3 = mpg123_new(NULL, NULL);
if (*mp3 == NULL){
throw MusicException(__FILE__,__LINE__, "Could not allocate mpg handle");
}
mpg123_format_none(*mp3);
/* allegro wants unsigned samples but mpg123 can't actually provide unsigned
* samples even though it has an enum for it, MPG123_ENC_UNSIGNED_16. this
* was rectified in 1.13.0 or something, but for now signed samples are ok.
*/
int error = mpg123_format(*mp3, Sound::Info.frequency, MPG123_STEREO, MPG123_ENC_SIGNED_16);
if (error != MPG123_OK){
Global::debug(0) << "Could not set format for mpg123 handle" << std::endl;
}
/* FIXME workaround for libmpg issues with "generic" decoder frequency not being set */
error = mpg123_open(*mp3, (char*) path);
if (error == -1){
std::ostringstream error;
error << "Could not open mpg123 file " << path << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
/* reading a frame is the only surefire way to get mpg123 to set the
* sampling_frequency which it needs to set the decoder a few lines below
*/
size_t dont_care;
unsigned char tempBuffer[4096];
error = mpg123_read(*mp3, tempBuffer, sizeof(tempBuffer), &dont_care);
if (!(error == MPG123_OK || error == MPG123_NEW_FORMAT)){
std::ostringstream error;
error << "Could not read mpg123 file " << path << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
mpg123_close(*mp3);
/* stream has progressed a little bit so reset it by opening it again */
error = mpg123_open(*mp3, (char*) path);
if (error == -1){
std::ostringstream error;
error << "Could not open mpg123 file " << path << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
/* FIXME end */
/* some of the native decoders aren't stable in older versions of mpg123
* so just use generic for now. 1.13.1 should work better
*/
error = mpg123_decoder(*mp3, "generic");
if (error != MPG123_OK){
std::ostringstream error;
error << "Could not use 'generic' mpg123 decoder for " << path << " error code " << error;
throw MusicException(__FILE__,__LINE__, error.str());
}
// Global::debug(0) << "mpg support " << mpg123_format_support(mp3, Sound::FREQUENCY, MPG123_ENC_SIGNED_16) << std::endl;
/*
double base, really, rva;
mpg123_getvolume(*mp3, &base, &really, &rva);
// Global::debug(0) << "mpg volume base " << base << " really " << really << " rva " << rva << std::endl;
base_volume = base;
long rate;
int channels, encoding;
mpg123_getformat(*mp3, &rate, &channels, &encoding);
// Global::debug(0) << path << " rate " << rate << " channels " << channels << " encoding " << encoding << std::endl;
*/
} catch (const MusicException & fail){
if (*mp3 != NULL){
mpg123_close(*mp3);
mpg123_delete(*mp3);
*mp3 = NULL;
}
mpg123_exit();
throw;
}
}
static const int MPG123_BUFFER_SIZE = 1 << 11;
Mp3Player::Mp3Player(const char * path):
mp3(NULL){
initializeMpg123(&mp3, path);
long rate = 0;
int channels = 0, encoding = 0;
mpg123_getformat(mp3, &rate, &channels, &encoding);
}
void Mp3Player::render(void * data, int samples){
/* buffer * 4 for 16 bits per sample * 2 samples for stereo */
size_t out = 0;
mpg123_read(mp3, (unsigned char *) data, samples * 4, &out);
/*
long rate;
int channels, encoding;
mpg123_getformat(mp3, &rate, &channels, &encoding);
Global::debug(0) << "rate " << rate << " channels " << channels << " encoding " << encoding << std::endl;
*/
}
void Mp3Player::setVolume(double volume){
mpg123_volume(mp3, volume);
/*
this->volume = volume;
// mpg123_volume(mp3, volume * base_volume / 5000);
mpg123_volume(mp3, 0.0001);
*/
// mpg123_volume(mp3, volume);
}
Mp3Player::~Mp3Player(){
mpg123_close(mp3);
mpg123_exit();
}
#endif /* MP3_MPG123 */
#ifdef HAVE_OGG
int OGG_BUFFER_SIZE = 1024 * 32;
OggPlayer::OggPlayer(const char * path):
path(path){
file = fopen(path, "rb");
if (!file) {
throw MusicException(__FILE__, __LINE__, "Could not open file");
}
if (ov_open_callbacks(file, &ogg, 0, 0, OV_CALLBACKS_DEFAULT) != 0) {
fclose(file);
throw MusicException(__FILE__, __LINE__, "Could not open ogg");
}
vorbis_info * info = ov_info(&ogg, -1);
frequency = info->rate;
channels = info->channels;
bits = 16;
length = ov_pcm_total(&ogg, -1);
setRenderer(new MusicRenderer(info->rate, info->channels));
buffer = new OggPage();
buffer->buffer1.buffer = new char[OGG_BUFFER_SIZE];
// buffer->buffer2.buffer = new char[OGG_BUFFER_SIZE];
fillPage(&buffer->buffer1);
// fillPage(&buffer->buffer2);
// buffer->use = 0;
}
void OggPlayer::fillPage(OggPage::Page * page){
int dont_care;
page->position = 0;
page->max = 0;
while (page->max < OGG_BUFFER_SIZE){
/* ov_read might not read all available samples, I guess it stops
* reading on a page boundary. We just plow on through.
*/
int read = ov_read(&ogg, (char*) page->buffer + page->max, OGG_BUFFER_SIZE - page->max,
bigEndian(), 2, 1, &dont_care);
/* if we hit the end of the file then re-open it and keep reading */
if (read == 0){
ov_clear(&ogg);
file = fopen(path.c_str(), "rb");
if (!file){
throw MusicException(__FILE__, __LINE__, "Could not open file");
}
int ok = ov_open_callbacks(file, &ogg, 0, 0, OV_CALLBACKS_DEFAULT);
if (ok != 0){
fclose(file);
throw MusicException(__FILE__, __LINE__, "Could not open ogg");
}
} else if (read == OV_HOLE){
throw MusicException(__FILE__, __LINE__, "Garbage in ogg file");
} else if (read == OV_EBADLINK){
throw MusicException(__FILE__, __LINE__, "Invalid stream section in ogg");
} else if (read == OV_EINVAL){
throw MusicException(__FILE__, __LINE__, "File headers are corrupt in ogg");
} else {
page->max += read;
}
}
}
void OggPlayer::doRender(char * data, int bytes){
OggPage::Page & page = buffer->buffer1;
if (page.max - page.position >= bytes){
memcpy(data, page.buffer + page.position, bytes);
page.position += bytes;
} else {
/* copy the rest, fill the page, switch to the other buffer */
memcpy(data, page.buffer + page.position, page.max - page.position);
int at = page.max - page.position;
int rest = bytes - (page.max - page.position);
fillPage(&page);
doRender(data + at, rest);
}
}
void OggPlayer::render(void * data, int length){
doRender((char*) data, length * 4);
}
void OggPlayer::setVolume(double volume){
this->volume = volume;
// Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}
OggPlayer::~OggPlayer(){
/* ov_clear will close the file */
ov_clear(&ogg);
}
#endif /* OGG */
#ifdef HAVE_MP3_MAD
/* TODO */
Mp3Player::Mp3Player(const char * path){
/* TODO */
}
void Mp3Player::render(void * data, int length){
}
void Mp3Player::setVolume(double volume){
/* TODO */
}
Mp3Player::~Mp3Player(){
/* TODO */
}
#endif /* MP3_MAD */
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:20 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68369
Default Alt Text
(31 KB)

Event Timeline