Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update/rewrite of SDLx::Sound #286

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 86 additions & 37 deletions lib/SDLx/Sound.pm
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package SDLx::Sound;

use strict;
use warnings;
use Carp;
Expand All @@ -16,19 +17,19 @@ use SDL::Mixer::Music;
my $audioInited = undef;

sub new {
my $class = shift;
my $self = {@_};
bless ($self, $class);
_initAudio() unless $audioInited;
$self->{supported} = _initMixer();
return $self;
my $class = shift;
my $self = {@_};
bless ($self, $class);
_initAudio() unless $audioInited; # only once per module load
$self->{supported} = _initMixer();
return $self;
}

sub _initAudio {
SDL::Mixer::open_audio( 44100, AUDIO_S16SYS, 2, 4096 );
my ($status, $freq, $format, $channels) = @{ SDL::Mixer::query_spec() };
$audioInited = 1 if $status == 1;
return ($status, $freq, $format, $channels); #TODO: Save this information in $self;
return ($status, $freq, $format, $channels); # being passed back to $self
}

sub _initMixer {
Expand All @@ -48,8 +49,33 @@ sub _initMixer {
}

sub load {
my $self = shift;
$self->{files} = {@_};
my $self = shift;
$self->{files} = { @_ }; # user passes key/value pairs

for my $name (keys %{ $self->{files} }){
my $obj = {};
# allow user to pass hash-refs
unless( ref($self->{files}->{$name}) ){
# print "load: preparing sound object: $name \n";
$obj = {
file => $self->{files}->{$name},
volume => 100,
loops => 1,
};
$self->{files}->{$name} = $obj;


}

if (-e $obj->{file}){
$obj->{load_ref} = SDL::Mixer::Music::load_MUS($obj->{file}) or Carp::croak "Sound file $obj->{file} not found: " . SDL::get_error();
$obj->{is_loaded} = 1;
}else{
carp("Sound file ".$obj->{file}." not found\n");
next;
}
}

}

sub unload {
Expand All @@ -58,49 +84,72 @@ sub unload {
}

sub play {
my $self = shift;
$self->{files} = {@_} if $#_ > 0 && @_;
my $play = 1;
if (-e $_[0]) {
my $music = SDL::Mixer::Music::load_MUS($_[0])
or Carp::croak 'Sound file not found: ' . SDL::get_error();
SDL::Mixer::Music::volume_music(85);
if (SDL::Mixer::Music::play_music($music, -1)<0) {
print("Can't play!\n". SDL::get_error()."\n");
$play = 0;
}
} else {
carp("No newline ".$self->{files}."\n".$_[0]."\n");
$play = 0;
}
return $play;
my $self = shift;
# $self->{files} = {@_} if $#_ > 0 && @_;

my ($name, %override) = @_;

my $obj;
if($name){
unless( exists($self->{files}->{$name}) && $self->{files}->{$name}->{is_loaded} ){
carp("Sound file with name $name not loaded, autoload with name = path (which is $name) \n");

$self->load( $name => $name );
}
$obj = $self->{files}->{$name};
}else{
# if user calls play() do something
($name, $obj) = each %{ $self->{files} };

unless( $name ){
carp("No sound file loaded, either call load() first or pass a file-path to play()\n");
return 0;
}
}

## execute play
SDL::Mixer::Music::volume_music( (defined($override{volume}) ? $override{volume} : $obj->{volume}) );

if( SDL::Mixer::Music::play_music(
$obj->{load_ref},
( defined($override{loops}) ? $override{loops} : $obj->{loops} )
) < 0
){
carp("Error calling play_music: ". SDL::get_error()."\n");
return 0;
}

return 1;
}

sub loud {
sub playing {
return SDL::Mixer::Music::playing_music();
}
sub is_playing {
return SDL::Mixer::Music::playing_music();
}

sub pause {
my $self = shift;
SDL::Mixer::Music::pause_music();

my $self = shift;
SDL::Mixer::Music::pause_music();
}

sub resume {
my $self = shift;
SDL::Mixer::Music::resume_music();

my $self = shift;
SDL::Mixer::Music::resume_music();
}


sub stop {
my $self = shift;
SDL::Mixer::Music::halt_music();
#SDL::Mixer::quit();
my $self = shift;
SDL::Mixer::Music::halt_music();
#SDL::Mixer::quit();
}

sub fade {
sub loud {
}


sub fade {
}

1; # End of SDLx::Sound
116 changes: 43 additions & 73 deletions lib/pods/SDLx/Sound.pod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

=head1 NAME

SDLx::Sound
SDLx::Sound - Simple audio interface

=head1 CATEGORY

Expand All @@ -10,108 +10,78 @@ Extension
=head1 SYNOPSIS

use SDLx::Sound;

my $snd = SDLx::Sound->new();

# loads and plays a single sound now
$snd->play('myfile.wav');

# load a single file
$snd->load('theSound.aif');

# plays it or all loaded files
$snd->play();

# more sounds
my %files = (
channel_01 => "/my_sound1.wav",
channel_02 => "/my_sound2.ogg"
);

# times sounds bangs
my %times = (
channel_01 => 0, # start
channel_01 => 1256, # milliseconds
channel_02 => 2345
$snd->load(
arbitrary_name => 'some_sound.wav',
);

# Load files in channels for realtime play
$snd->load(%files);

# sets sound channel_01 loudness
$snd->loud('channel_01', 80); # loud at 80%
$snd->play(%times); # play loaded files at times
$snd->play; # play again

# plays sound channel_01 at 578 milliseconds from now
$snd->play('channel_01', 578);

# fades sound
$snd->fade('channel_02', 2345, 3456, -20);

# in a single act do the whole Sound
my $snd = SDLx::Sound->new(
files => (
channel_01 => "/my_sound1.wav",
channel_02 => "/my_sound2.ogg"

),
loud => (
channel_01 => 80,
channel_02 => 75
),
times => (
channel_01 => 0, # start
channel_01 => 1256, # milliseconds
channel_02 => 2345
),
fade => (
channel_02 => [2345, 3456, -20]
)
)->play();

=head1 DESCRIPTION


You can think about the SDLx::Sound at 2 approaches.

=over 4
$snd->play('arbitrary_name');

=item * A simple sound or
$snd->play('arbitrary_name', loops => -1); # loop .wav infinitely (default is play once, 1)

=item * The sound of your game or app.
$snd->play('arbitrary_name', loops => 3, volume => 50); # play 3x with volume lowered to 50%

=back
$snd->stop();

Your application will say what the best approach.
=head1 DESCRIPTION

In a taste that resembles to perl and to SDL, our SDLx:Sound hooks at SDL::Audio and SDL::Mixer with a graceful and simple interface that can offer to monks a modern perlish way to manage sounds.
You may use this module to emit audio / sound / music from your SDL / SDLx application or game.

An SDLx::Sound object can load sounds from filesystem, play it, adjust this loudness level or stops the sound.
It's a thin interface to L<SDL::Mixer::Music>, which it wraps/ uses internally, merely rounding off the edges of init,
pre-loading and playback.

Each sound will play in the next available channel, so it can be handled isolately.
Calls to play() are not blocking, each sound will play in the next available channel. That's how SDL::Mixer::Music works.

=head1 METHODS

=head2 new

Returns a new instance of SDLx::Sound
Returns a new instance of SDLx::Sound, initiating sound with C<SDL::Mixer::open_audio( 44100, AUDIO_S16SYS, 2, 4096 )>

=head2 load

Processes the passed sound files, checks for existence, and pre-loads the files via SDL::Mixer::Music::load_MUS,
throwing errors if anything fails. In contrast to earlier versions of SDLx::Sound, this version here actually does a
pre-load and keeps files in memory, while play() will rely on this memory structure being prepared and ready to play.

Each sound file will be prepared with I<volume> = 100 and I<loops> = 1, one-shot play. That's how this sound will be played
when you call it with -E<gt>play('some_sound').

=head2 play

$sdlx_sound->play('file.wav');
Doing something like C<$audio-E<gt>play('sound_name');> will fetch the prepared sound from the internal C<-E<gt>{files}> hash
and play it via C<SDL::Mixer::Music::play_music>. As previous versions of SDLx::Sound were able to autoload via play(), this
updated version here does something similar: passing it a file_path will trigger the internal load() routine and the given
file will be loaded with the name representing it being the path you passed in to play/load a sound.

Play a file
You may pass additional key/value pairs to override settings from -E<gt>load(), see SYNOPSIS.

=head2 pause

SDL::Mixer::Music::pause_music()

=head2 resume

SDL::Mixer::Music::resume_music()

=head2 stop

SDL::Mixer::Music::halt_music()

=head2 playing() and is_playing()

Both call SDL::Mixer::Music::playing_music(), returning a true value if the mixer is playing any sound.

=head1 SEE ALSO

This here is a simple interface to L<SDL::Mixer::Music>, which you may also call directly for additional
bells and whistles.

And then there's L<SDLx::Music>. While the bundled example C<examples/SDLx/music.pl> is able to
play something with it, the POD is out of sync with the actual internals. L<SDLx::Music> behaves like this module here
as it prepares defaults for every file, which you may then overrride upon calling play() - nice inspiration. But then
it has a somewhat IMHO convoluted way of loading/managing loaded files and has a less convenient play() method.

=head1 AUTHORS

Expand Down