/*
Ruby/SDL Ruby extension library for SDL
Copyright (C) 2001-2007 Ohbayashi Ippei
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_SDL_MIXER
#include "rubysdl.h"
#define USE_RWOPS
#include <SDL_mixer.h>
static int mix_opened=0;
static int mix_closed=0;
static VALUE playing_wave = Qnil;
static VALUE playing_music=Qnil;
static void mix_FreeChunk(Mix_Chunk *chunk)
{
if( ! mix_closed ){
Mix_FreeChunk( chunk );
}
}
static void mix_FreeMusic(Mix_Music *music)
{
if( !mix_closed ){
Mix_FreeMusic( music );
}
}
static VALUE mix_audioDriverName(VALUE mod)
{
char driver_name[512];
if(SDL_AudioDriverName(driver_name, sizeof(driver_name)) == NULL)
rb_raise(eSDLError, "No driver has been initialized: %s", SDL_GetError());
return rb_str_new2(driver_name);
}
static VALUE mix_openAudio(VALUE mod,VALUE frequency,VALUE format,
VALUE channels,VALUE chunksize)
{
if( mix_opened ){
rb_raise(eSDLError,"already initialize SDL::Mixer");
}
if( Mix_OpenAudio( NUM2INT(frequency),NUM2UINT(format),NUM2INT(channels),
NUM2INT(chunksize) ) < 0 ){
rb_raise(eSDLError,"Couldn't open audio: %s",SDL_GetError());
}
mix_opened = 1;
return Qnil;
}
static VALUE mix_querySpec(VALUE mod)
{
int rate;
Uint16 format;
int channels;
if( !Mix_QuerySpec(&rate,&format,&channels) )
rb_raise(eSDLError,"audio have not been opened yet: %s", Mix_GetError());
return rb_ary_new3( 3,INT2NUM(rate),UINT2NUM(format),INT2NUM(channels) );
}
static VALUE mix_allocateChannels(VALUE mod,VALUE numchannels)
{
return INT2FIX( Mix_AllocateChannels(NUM2INT(numchannels)) );
}
/* Returns which channel was used to play the sound. */
static VALUE mix_playChannel(VALUE mod,VALUE channel,VALUE wave,VALUE loops)
{
Mix_Chunk *chunk;
int playing_channel;
if( ! rb_obj_is_kind_of(wave,cWave) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Wave is expected");
Data_Get_Struct(wave,Mix_Chunk,chunk);
playing_channel = Mix_PlayChannel(NUM2INT(channel),chunk,NUM2INT(loops) );
if( playing_channel == -1 ){
rb_raise( eSDLError, "couldn't play wave: %s", Mix_GetError() );
}
rb_ary_store(playing_wave,playing_channel,wave);/* to avoid gc problem */
return INT2FIX(playing_channel);
}
static VALUE mix_playChannelTimed(VALUE mod,VALUE channel,VALUE wave,VALUE loops,
VALUE ticks)
{
Mix_Chunk *chunk;
int playing_channel;
if( ! rb_obj_is_kind_of(wave,cWave) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Wave is expected");
Data_Get_Struct(wave,Mix_Chunk,chunk);
playing_channel = Mix_PlayChannelTimed(NUM2INT(channel),chunk,NUM2INT(loops),
NUM2INT(ticks));
if( playing_channel == -1 ){
rb_raise( eSDLError, "couldn't play wave: %s", Mix_GetError() );
}
rb_ary_store(playing_wave,playing_channel,wave);/* to avoid gc problem */
return INT2FIX(playing_channel);
}
static VALUE mix_fadeInChannel(VALUE mod,VALUE channel,VALUE wave,VALUE loops,
VALUE ms)
{
Mix_Chunk *chunk;
int playing_channel;
if( ! rb_obj_is_kind_of(wave,cWave) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Wave is expected");
Data_Get_Struct(wave,Mix_Chunk,chunk);
playing_channel = Mix_FadeInChannel(NUM2INT(channel),chunk,NUM2INT(loops),
NUM2INT(ms));
if( playing_channel == -1 ){
rb_raise( eSDLError, "couldn't play wave: %s", Mix_GetError() );
}
rb_ary_store(playing_wave,playing_channel,wave);/* to avoid gc problem */
return INT2FIX(playing_channel);
}
static VALUE mix_fadeInChannelTimed(VALUE mod,VALUE channel,VALUE wave,VALUE loops,
VALUE ms, VALUE ticks)
{
Mix_Chunk *chunk;
int playing_channel;
if( ! rb_obj_is_kind_of(wave,cWave) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Wave is expected");
Data_Get_Struct(wave,Mix_Chunk,chunk);
playing_channel = Mix_FadeInChannelTimed(NUM2INT(channel),chunk,NUM2INT(loops),
NUM2INT(ms), NUM2INT(ticks));
if( playing_channel == -1 ){
rb_raise( eSDLError, "couldn't play wave: %s", Mix_GetError() );
}
rb_ary_store(playing_wave,playing_channel,wave);/* to avoid gc problem */
return INT2FIX(playing_channel);
}
static VALUE mix_playing(VALUE mod,VALUE channel)
{
if( Mix_Playing( NUM2INT(channel) ) ){
return Qtrue;
}else{
return Qfalse;
}
}
static VALUE mix_loadWav(VALUE class,VALUE filename)
{
Mix_Chunk *wave;
Check_Type(filename,T_STRING);
wave = Mix_LoadWAV( GETCSTR(filename) );
if( wave == NULL ){
rb_raise( eSDLError,"Couldn't load wave file %s: %s",
GETCSTR(filename), Mix_GetError() );
}
return Data_Wrap_Struct(class,0,mix_FreeChunk,wave);
}
static VALUE mix_loadWavFromIO(VALUE class, VALUE io)
{
Mix_Chunk *wave;
wave = Mix_LoadWAV_RW(rubysdl_RWops_from_ruby_obj(io), 1);
if( wave == NULL ){
rb_raise(eSDLError,"Couldn't load wave file from IO: %s",
Mix_GetError());
}
return Data_Wrap_Struct(class,0,mix_FreeChunk,wave);
}
/* Volume setting functions and methods : volume in 0..128 */
static VALUE mix_volume(VALUE mod,VALUE channel,VALUE volume)
{
return INT2FIX( Mix_Volume( NUM2INT(channel),NUM2INT(volume) ) );
}
static VALUE mix_wave_volume(VALUE obj,VALUE volume)
{
Mix_Chunk *chunk;
Data_Get_Struct(obj,Mix_Chunk,chunk);
return INT2FIX( Mix_VolumeChunk( chunk,NUM2INT(volume) ) );
}
/* Halt,Pause function */
static VALUE mix_halt(VALUE mod,VALUE channel)
{
Mix_HaltChannel(NUM2INT(channel));
return Qnil;
}
static VALUE mix_pause(VALUE mod,VALUE channel)
{
Mix_Pause(NUM2INT(channel));
return Qnil;
}
static VALUE mix_resume(VALUE mod,VALUE channel)
{
Mix_Resume(NUM2INT(channel));
return Qnil;
}
static VALUE mix_paused(VALUE mod,VALUE channel)
{
return INT2FIX(Mix_Paused(NUM2INT(channel)));
}
static VALUE mix_fadeOut(VALUE mod,VALUE channel,VALUE ms)
{
return INT2FIX(Mix_FadeOutChannel(NUM2INT(channel), NUM2INT(ms)));
}
static VALUE mix_expire(VALUE mod, VALUE channel, VALUE ticks)
{
return INT2FIX(Mix_ExpireChannel(NUM2INT(channel),NUM2INT(ticks)));
}
static VALUE mix_fading(VALUE mod, VALUE which)
{
if( NUM2INT(which) < 0 || Mix_AllocateChannels(-1) <= NUM2INT(which))
rb_raise(eSDLError, "channel %d out of range", NUM2INT(which));
return INT2FIX(Mix_FadingChannel(which));
}
/* music functions */
#define MakeSimpleRubyFunc(rubyFunc,sdlFunc) \
static VALUE rubyFunc(VALUE mod) \
{ \
sdlFunc(); \
return Qnil; \
} \
static VALUE mix_playMusic(VALUE mod,VALUE music,VALUE loops)
{
Mix_Music *mus;
if( ! rb_obj_is_kind_of(music,cMusic) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Music is expected");
Data_Get_Struct(music,Mix_Music,mus);
playing_music=music; /* to avoid gc problem */
Mix_PlayMusic(mus,NUM2INT(loops));
return Qnil;
}
static VALUE mix_fadeInMusic(VALUE mod,VALUE music,VALUE loops,VALUE ms)
{
Mix_Music *mus;
if( ! rb_obj_is_kind_of(music,cMusic) )
rb_raise(rb_eArgError,"type mismatch: SDL::Mixer::Music is expected");
Data_Get_Struct(music,Mix_Music,mus);
Mix_FadeInMusic(mus,NUM2INT(loops),NUM2INT(ms));
return Qnil;
}
static VALUE mix_setVolumeMusic(VALUE mod,VALUE volume)
{
Mix_VolumeMusic( NUM2INT(volume) );
return Qnil;
}
static VALUE mix_fadeOutMusic(VALUE mod,VALUE ms)
{
Mix_FadeOutMusic(NUM2INT(ms));
return Qnil;
}
MakeSimpleRubyFunc(mix_haltMusic,Mix_HaltMusic)
MakeSimpleRubyFunc(mix_pauseMusic,Mix_PauseMusic)
MakeSimpleRubyFunc(mix_resumeMusic,Mix_ResumeMusic)
MakeSimpleRubyFunc(mix_rewindMusic,Mix_RewindMusic)
static VALUE mix_pausedMusic(VALUE mod)
{
return BOOL(Mix_PausedMusic());
}
static VALUE mix_playingMusic(VALUE mod)
{
return BOOL(Mix_PlayingMusic());
}
static VALUE mix_fadingMusic(VALUE mod)
{
return INT2FIX(Mix_FadingMusic());
}
static VALUE mix_loadMus(VALUE class,VALUE filename)
{
Mix_Music* music;
music = Mix_LoadMUS(GETCSTR(filename));
if( music == NULL )
rb_raise(eSDLError,
"Couldn't load %s: %s",GETCSTR(filename),SDL_GetError());
return Data_Wrap_Struct(class,0,mix_FreeMusic,music);
}
#ifdef HAVE_MIX_LOADMUS_RW
static VALUE mix_loadMusFromString(VALUE class,VALUE str)
{
Mix_Music* music;
volatile VALUE result;
volatile VALUE buf;
StringValue(str);
buf = rb_str_dup(str);
music = Mix_LoadMUS_RW(SDL_RWFromConstMem(RSTRING(buf)->ptr,
RSTRING(buf)->len));
if( music == NULL )
rb_raise(eSDLError,
"Couldn't load from String: %s",Mix_GetError());
result = Data_Wrap_Struct(class,0,mix_FreeMusic,music);
rb_iv_set(result, "buf", buf);
return result;
}
#endif
static void defineConstForAudio()
{
rb_define_const(mMixer,"FORMAT_U8",UINT2NUM(AUDIO_U8));
rb_define_const(mMixer,"FORMAT_S8",UINT2NUM(AUDIO_S8));
rb_define_const(mMixer,"FORMAT_U16LSB",UINT2NUM(AUDIO_U16LSB));
rb_define_const(mMixer,"FORMAT_S16LSB",UINT2NUM(AUDIO_S16LSB));
rb_define_const(mMixer,"FORMAT_U16MSB",UINT2NUM(AUDIO_U16MSB));
rb_define_const(mMixer,"FORMAT_S16MSB",UINT2NUM(AUDIO_S16MSB));
rb_define_const(mMixer,"FORMAT_U16",UINT2NUM(AUDIO_U16));
rb_define_const(mMixer,"FORMAT_S16",UINT2NUM(AUDIO_S16));
rb_define_const(mMixer,"FORMAT_U16SYS",UINT2NUM(AUDIO_U16SYS));
rb_define_const(mMixer,"FORMAT_S16SYS",UINT2NUM(AUDIO_S16SYS));
rb_define_const(mMixer,"CHANNELS",INT2NUM(MIX_CHANNELS));
rb_define_const(mMixer,"DEFAULT_FREQUENCY",INT2NUM(MIX_DEFAULT_FREQUENCY));
rb_define_const(mMixer,"DEFAULT_FORMAT",UINT2NUM(MIX_DEFAULT_FORMAT));
rb_define_const(mMixer,"DEFAULT_CHANNELS",UINT2NUM(MIX_DEFAULT_CHANNELS));
rb_define_const(mMixer,"MAX_VOLUME",INT2NUM(MIX_MAX_VOLUME));
rb_define_const(mMixer,"NO_FADING", INT2NUM(MIX_NO_FADING));
rb_define_const(mMixer,"FADING_OUT", INT2NUM(MIX_FADING_OUT));
rb_define_const(mMixer,"FADING_IN", INT2NUM(MIX_FADING_IN));
}
void init_mixer()
{
mMixer = rb_define_module_under(mSDL,"Mixer");
rb_define_module_function(mMixer,"open",mix_openAudio,4);
rb_define_module_function(mMixer,"spec",mix_querySpec,0);
rb_define_module_function(mMixer,"driverName", mix_audioDriverName, 0);
rb_define_module_function(mMixer,"playChannel",mix_playChannel,3);
rb_define_module_function(mMixer,"playChannelTimed", mix_playChannelTimed, 4);
rb_define_module_function(mMixer,"fadeInChannel", mix_fadeInChannel, 4);
rb_define_module_function(mMixer,"fadeInChannelTimed", mix_fadeInChannelTimed, 5);
rb_define_module_function(mMixer,"play?",mix_playing,1);
rb_define_module_function(mMixer,"setVolume",mix_volume,2);
rb_define_module_function(mMixer,"allocateChannels",mix_allocateChannels,1);
rb_define_module_function(mMixer,"halt",mix_halt,1);
rb_define_module_function(mMixer,"pause",mix_pause,1);
rb_define_module_function(mMixer,"resume",mix_resume,1);
rb_define_module_function(mMixer,"pause?",mix_paused,1);
rb_define_module_function(mMixer,"expire",mix_expire,2);
rb_define_module_function(mMixer,"fading",mix_fading,1);
rb_define_module_function(mMixer,"fadeOut",mix_fadeOut,2);
rb_define_module_function(mMixer,"playMusic",mix_playMusic,2);
rb_define_module_function(mMixer,"fadeInMusic",mix_fadeInMusic,3);
rb_define_module_function(mMixer,"setVolumeMusic",mix_setVolumeMusic,1);
rb_define_module_function(mMixer,"haltMusic",mix_haltMusic,0);
rb_define_module_function(mMixer,"fadeOutMusic",mix_fadeOutMusic,1);
rb_define_module_function(mMixer,"pauseMusic",mix_pauseMusic,0);
rb_define_module_function(mMixer,"resumeMusic",mix_resumeMusic,0);
rb_define_module_function(mMixer,"rewindMusic",mix_rewindMusic,0);
rb_define_module_function(mMixer,"pauseMusic?",mix_pausedMusic,0);
rb_define_module_function(mMixer,"playMusic?",mix_playingMusic,0);
rb_define_module_function(mMixer,"fadingMusic",mix_fadingMusic,0);
cWave = rb_define_class_under(mMixer,"Wave",rb_cObject);
rb_define_singleton_method(cWave,"load",mix_loadWav,1);
rb_define_singleton_method(cWave,"loadFromIO",mix_loadWavFromIO,1);
rb_define_method(cWave,"setVolume",mix_wave_volume,1);
cMusic = rb_define_class_under(mMixer,"Music",rb_cObject);
rb_define_singleton_method(cMusic,"load",mix_loadMus,1);
#ifdef HAVE_MIX_LOADMUS_RW
rb_define_singleton_method(cMusic,"loadFromString",mix_loadMusFromString,1);
#endif
/* to avoid to do garbage collect when playing */
playing_wave = rb_ary_new();
rb_global_variable( &playing_wave );
rb_global_variable( &playing_music );
defineConstForAudio();
return ;
}
void quit_mixer()
{
if( mix_opened ){
Mix_CloseAudio();
mix_closed = 1;
}
}
#endif /* HAVE_SDL_MIXER */
syntax highlighted by Code2HTML, v. 0.9.1