diff --git a/bindings/ruby/sfml-audio/audio/Music.cpp b/bindings/ruby/sfml-audio/audio/Music.cpp new file mode 100644 index 000000000..33e3ad860 --- /dev/null +++ b/bindings/ruby/sfml-audio/audio/Music.cpp @@ -0,0 +1,125 @@ +/* rbSFML - Copyright (c) 2010 Henrik Valter Vogelius Hansson - groogy@groogy.se + * This software is provided 'as-is', without any express or + * implied warranty. In no event will the authors be held + * liable for any damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; + * you must not claim that you wrote the original software. + * If you use this software in a product, an acknowledgment + * in the product documentation would be appreciated but + * is not required. + * + * 2. Altered source versions must be plainly marked as such, + * and must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any + * source distribution. + */ + +#include "Music.hpp" +#include "main.hpp" +#include + +VALUE globalMusicClass; + +/* External classes */ +extern VALUE globalSoundStreamClass; + +static VALUE Music_Free( sf::Music *anObject ) +{ + delete anObject; +} + +static VALUE Music_Initialize( int argc, VALUE *args, VALUE self ) +{ + return self; +} + +static VALUE Music_OpenFromFile( VALUE self, VALUE aFilename ) +{ + sf::Music *object = NULL; + Data_Get_Struct( self, sf::Music, object ); + if( object->OpenFromFile( rb_string_value_cstr( &aFilename ) ) == true ) + { + return Qtrue; + } + else + { + return Qfalse; + } +} + +static VALUE Music_GetDuration( VALUE self ) +{ + sf::Music *object = NULL; + Data_Get_Struct( self, sf::Music, object ); + return rb_float_new( object->GetDuration() ); +} + +static VALUE Music_New( int argc, VALUE *args, VALUE aKlass ) +{ + sf::Music *object = new sf::Music(); + VALUE rbData = Data_Wrap_Struct( aKlass, 0, Music_Free, object ); + rb_obj_call_init( rbData, argc, args ); + return rbData; +} + +void Init_Music( void ) +{ +/* SFML namespace which contains the classes of this module. */ + VALUE sfml = rb_define_module( "SFML" ); +/* Streamed music played from an audio file. + * + * Musics are sounds that are streamed rather than completely loaded in memory. + * + * This is especially useful for compressed musics that usually take hundreds of MB when they are uncompressed: by + * streaming it instead of loading it entirely, you avoid saturating the memory and have almost no loading delay. + * + * Apart from that, a sf::Music has almost the same features as the sf::SoundBuffer / sf::Sound pair: you can + * play/pause/stop it, request its parameters (channels, sample rate), change the way it is played (pitch, volume, + * 3D position, ...), etc. + * + * As a sound stream, a music is played in its own thread in order not to block the rest of the program. This means + * that you can leave the music alone after calling Play(), it will manage itself very well. + * + * Usage example: + * + * # Declare a new music + * music = SFML::Music.new + * + * # Open it from an audio file + * if music.openFromFile( "music.ogg" ) == false + * # error... + * end + * + * # Change some parameters + * music.setPosition( 0, 1, 10 ) # change its 3D position + * music.setPitch( 2 ) # increase the pitch + * music.setVolume( 50 ) # reduce the volume + * music.setLoop( true ) # make it loop + * + * # Play it + * music.play() + */ + globalMusicClass = rb_define_class_under( sfml, "Music", globalSoundStreamClass ); + + // Class methods + rb_define_singleton_method( globalMusicClass, "new", Music_New, -1 ); + + // Instance methods + rb_define_method( globalMusicClass, "initialize", Music_Initialize, -1 ); + rb_define_method( globalMusicClass, "openFromFile", Music_OpenFromFile, 1 ); + rb_define_method( globalMusicClass, "getDuration", Music_GetDuration, 0 ); + + // Instance Aliases + rb_define_alias( globalMusicClass, "open_from_file", "openFromFile" ); + rb_define_alias( globalMusicClass, "openFile", "openFromFile" ); + rb_define_alias( globalMusicClass, "open_file", "openFromFile" ); + + rb_define_alias( globalMusicClass, "get_duration", "getDuration" ); + rb_define_alias( globalMusicClass, "duration", "getDuration" ); +} diff --git a/bindings/ruby/sfml-audio/audio/Music.hpp b/bindings/ruby/sfml-audio/audio/Music.hpp new file mode 100644 index 000000000..92745a5d0 --- /dev/null +++ b/bindings/ruby/sfml-audio/audio/Music.hpp @@ -0,0 +1,31 @@ +/* rbSFML - Copyright (c) 2010 Henrik Valter Vogelius Hansson - groogy@groogy.se + * This software is provided 'as-is', without any express or + * implied warranty. In no event will the authors be held + * liable for any damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; + * you must not claim that you wrote the original software. + * If you use this software in a product, an acknowledgment + * in the product documentation would be appreciated but + * is not required. + * + * 2. Altered source versions must be plainly marked as such, + * and must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any + * source distribution. + */ + +#ifndef SFML_RUBYEXT_MUSIC_HEADER_ +#define SFML_RUBYEXT_MUSIC_HEADER_ + +#include "ruby.h" + +// Ruby initiation function +void Init_Music( void ); + +#endif // SFML_RUBYEXT_MUSIC_HEADER_ diff --git a/bindings/ruby/sfml-audio/audio/SoundRecorder.cpp b/bindings/ruby/sfml-audio/audio/SoundRecorder.cpp index d8ed2344e..1f480de3e 100644 --- a/bindings/ruby/sfml-audio/audio/SoundRecorder.cpp +++ b/bindings/ruby/sfml-audio/audio/SoundRecorder.cpp @@ -93,7 +93,6 @@ protected: ID myOnProcessSamplesID; }; - static void SoundRecorder_Free( rbSoundRecorder * anObject ) { delete anObject; diff --git a/bindings/ruby/sfml-audio/audio/SoundStream.cpp b/bindings/ruby/sfml-audio/audio/SoundStream.cpp index 4c2538380..286c733cf 100644 --- a/bindings/ruby/sfml-audio/audio/SoundStream.cpp +++ b/bindings/ruby/sfml-audio/audio/SoundStream.cpp @@ -26,11 +26,108 @@ VALUE globalSoundStreamClass; -static VALUE SoundStream_GetAttenuation( VALUE self ) +/* External classes */ +extern VALUE globalSoundSourceClass; + +class rbSoundStream : public sf::SoundStream +{ +public: + rbSoundStream() + { + } + + ~rbSoundStream() + { + if( myData != NULL ) + { + delete[] myData; + } + } + + void Init( VALUE rubySelf ) + { + mySelf = rubySelf; + myOnGetDataID = rb_intern( "onGetData" ); + myOnSeekID = rb_intern( "onSeek" ); + + myData = NULL; + } + + void Initialize ( unsigned int channelsCount, unsigned int sampleRate ) + { + sf::SoundStream::Initialize( channelsCount, sampleRate ); + } + +protected: + virtual bool OnGetData( Chunk& aData ) + { + if( myData != NULL ) + { + delete[] myData; + myData = NULL; + } + + VALUE chunk = rb_funcall( mySelf, myOnGetDataID, 0 ); + if( chunk == Qnil ) + { + return false; + } + else + { + VALIDATE_CLASS( chunk, rb_cArray, "chunk" ); + const unsigned int rawSamplesCount = FIX2UINT( rb_funcall( chunk, rb_intern( "size" ), 0 ) ); + myData = new sf::Int16[rawSamplesCount]; + VALUE samples = rb_ary_entry( chunk, 0 ); + for(unsigned long index = 0; index < rawSamplesCount; index++) + { + const sf::Int16 val = NUM2INT( rb_ary_entry( samples, index ) ); + myData[index] = val; + } + aData.Samples = myData; + aData.NbSamples = rawSamplesCount; + return true; + } + } + + virtual void OnSeek( float anOffset ) + { + rb_funcall( mySelf, myOnSeekID, 1, rb_float_new( anOffset ) ); + } + + VALUE mySelf; + ID myOnGetDataID; + ID myOnSeekID; + + sf::Int16 *myData; +}; + +static VALUE SoundStream_Free( rbSoundStream *anObject ) +{ + delete anObject; +} + +static VALUE SoundStream_Play( VALUE self ) { sf::SoundStream *object = NULL; Data_Get_Struct( self, sf::SoundStream, object ); - return rb_float_new( object->GetAttenuation() ); + object->Play(); + return Qnil; +} + +static VALUE SoundStream_Pause( VALUE self ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + object->Pause(); + return Qnil; +} + +static VALUE SoundStream_Stop( VALUE self ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + object->Stop(); + return Qnil; } static VALUE SoundStream_GetChannelsCount( VALUE self ) @@ -40,33 +137,83 @@ static VALUE SoundStream_GetChannelsCount( VALUE self ) return INT2FIX( object->GetChannelsCount() ); } +static VALUE SoundStream_GetSampleRate( VALUE self ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + return INT2FIX( object->GetSampleRate() ); +} + +static VALUE SoundStream_GetStatus( VALUE self ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + return INT2FIX( static_cast< int >( object->GetStatus() ) ); +} + +static VALUE SoundStream_SetPlayingOffset( VALUE self, VALUE anOffset ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + object->SetPlayingOffset( NUM2DBL( anOffset ) ); + return Qnil; +} + +static VALUE SoundStream_GetPlayingOffset( VALUE self, VALUE anOffset ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + return rb_float_new( object->GetPlayingOffset() ); +} + +static VALUE SoundStream_SetLoop( VALUE self, VALUE aLoop ) +{ + sf::SoundStream *object = NULL; + Data_Get_Struct( self, sf::SoundStream, object ); + if( aLoop == Qtrue ) + { + object->SetLoop( true ); + } + else if( aLoop == Qfalse ) + { + object->SetLoop( false ); + } + else + { + VALIDATE_CLASS( aLoop, rb_cTrueClass, "loop" ); + } + return Qnil; +} + static VALUE SoundStream_GetLoop( VALUE self ) { sf::SoundStream *object = NULL; Data_Get_Struct( self, sf::SoundStream, object ); - return ( object->GetLoop() == true ? Qtrue : Qfalse ); + if( object->GetLoop() == true ) + { + return Qtrue; + } + else + { + return Qfalse; + } } -static VALUE SoundStream_GetMinDistance( VALUE self ) +static VALUE SoundStream_Initialize( VALUE self, VALUE channelsCount, VALUE sampleRate ) { - sf::SoundStream *object = NULL; - Data_Get_Struct( self, sf::SoundStream, object ); - return rb_float_new( object->GetMinDistance() ); + rbSoundStream *object = NULL; + Data_Get_Struct( self, rbSoundStream, object ); + object->Initialize( FIX2UINT( channelsCount ), FIX2UINT( sampleRate ) ); + return self; } -static VALUE SoundStream_GetPitch( VALUE self ) +static VALUE SoundStream_New( int argc, VALUE *args, VALUE aKlass ) { - sf::SoundStream *object = NULL; - Data_Get_Struct( self, sf::SoundStream, object ); - return rb_float_new( object->GetPitch() ); -} - - -static void DefineStatusEnum( void ) -{ - rb_define_const( globalSoundStreamClass, "Stopped", INT2FIX( sf::SoundStream::Stopped ) ); - rb_define_const( globalSoundStreamClass, "Paused", INT2FIX( sf::SoundStream::Paused ) ); - rb_define_const( globalSoundStreamClass, "Playing", INT2FIX( sf::SoundStream::Playing ) ); + rbSoundStream *object = new rbSoundStream(); + VALUE rbData = Data_Wrap_Struct( aKlass, 0, SoundStream_Free, object ); + object->Init( rbData ); + rb_obj_call_init( rbData, argc, args ); + return rbData; } void Init_SoundStream( void ) @@ -130,12 +277,43 @@ void Init_SoundStream( void ) * stream.open( "path/to/stream" ) * stream.play */ - globalSoundStreamClass = rb_define_class_under( sfml, "SoundStream", rb_cObject ); - DefineStatusEnum(); - + globalSoundStreamClass = rb_define_class_under( sfml, "SoundStream", globalSoundSourceClass ); + // Class methods + rb_define_singleton_method( globalSoundStreamClass, "new", SoundStream_New, -1 ); // Instance methods + rb_define_method( globalSoundStreamClass, "initialize", SoundStream_Initialize, 2 ); + rb_define_method( globalSoundStreamClass, "play", SoundStream_Play, 0 ); + rb_define_method( globalSoundStreamClass, "pause", SoundStream_Pause, 0 ); + rb_define_method( globalSoundStreamClass, "stop", SoundStream_Stop, 0 ); + rb_define_method( globalSoundStreamClass, "getChannelsCount", SoundStream_GetChannelsCount, 0 ); + rb_define_method( globalSoundStreamClass, "getSampleRate", SoundStream_GetSampleRate, 0 ); + rb_define_method( globalSoundStreamClass, "getStatus", SoundStream_GetStatus, 0 ); + rb_define_method( globalSoundStreamClass, "setPlayingOffset", SoundStream_SetPlayingOffset, 1 ); + rb_define_method( globalSoundStreamClass, "getPlayingOffset", SoundStream_GetPlayingOffset, 0 ); + rb_define_method( globalSoundStreamClass, "setLoop", SoundStream_SetLoop, 1 ); + rb_define_method( globalSoundStreamClass, "getLoop", SoundStream_GetLoop, 0 ); - // Aliases + // Instance Aliases + rb_define_alias( globalSoundStreamClass, "get_channels_count", "getChannelsCount" ); + rb_define_alias( globalSoundStreamClass, "channelsCount", "getChannelsCount" ); + rb_define_alias( globalSoundStreamClass, "channels_count", "getChannelsCount" ); + + rb_define_alias( globalSoundStreamClass, "get_sample_rate", "getSampleRate" ); + rb_define_alias( globalSoundStreamClass, "sampleRate", "getSampleRate" ); + rb_define_alias( globalSoundStreamClass, "sample_rate", "getSampleRate" ); + + rb_define_alias( globalSoundStreamClass, "status", "getStatus" ); + + rb_define_alias( globalSoundStreamClass, "get_playing_offset", "getPlayingOffset" ); + rb_define_alias( globalSoundStreamClass, "playingOffset", "getPlayingOffset" ); + rb_define_alias( globalSoundStreamClass, "playing_offset", "getPlayingOffset" ); + + rb_define_alias( globalSoundStreamClass, "set_playing_offset", "setPlayingOffset" ); + rb_define_alias( globalSoundStreamClass, "playingOffset=", "setPlayingOffset" ); + rb_define_alias( globalSoundStreamClass, "playing_offset=", "setPlayingOffset" ); + + rb_define_alias( globalSoundStreamClass, "loop", "getPlayingOffset" ); + rb_define_alias( globalSoundStreamClass, "loop=", "setPlayingOffset" ); }