--- deliantra/Deliantra-Client/bin/cfplus 2007/07/12 17:56:51 1.163 +++ deliantra/Deliantra-Client/bin/cfplus 2007/07/14 12:05:53 1.168 @@ -163,8 +163,10 @@ our $SDL_MIXER; our $MUSIC_DEFAULT = "in_a_heartbeat.ogg"; our @MUSIC_WANT; +our $MUSIC_START; our $MUSIC_PLAYING; our $MUSIC_PLAYER; +our $MUSIC_RESUME = 30; # resume music when players less than these many seconds before our @SOUNDS; # event => file mapping our %AUDIO_CHUNKS; # audio files @@ -504,6 +506,8 @@ $SPELL_LIST->clear_spells; $CFPlus::UI::ROOT->emit (stop_game => ! ! $CONN); + &audio_music_set ([]); + return unless $CONN; status "connection closed"; @@ -2017,50 +2021,72 @@ sub audio_music_set { my ($songs) = @_; - my $count = @$songs; - my @meta; + my @want = + grep $_, + map $CONN->{music_meta}{$_}, + @$songs; + + if (@want) { + @MUSIC_WANT = @want; + &audio_music_changed (); + } +} - for my $name (@$songs) { - CFPlus::DB::get resmap => $name, sub { - my ($data) = @_; - - if ($data) { - $data = JSON::XS->new->utf8->decode ($data); - $data->{path} = CFPlus::DB::path_of $name; - push @meta, $data; - } +sub audio_music_start { + my $path = $MUSIC_PLAYING->{path} + or return; + + CFPlus::DB::prefetch_file $path, 1024_000, sub { + # music might have changed... + $path eq $MUSIC_PLAYING->{path} + or return &audio_music_start (); + + $MUSIC_PLAYER = new_from_file CFPlus::MixMusic $path; + + my $NOW = time; + + if ($MUSIC_PLAYING->{stop_time} > $NOW - $MUSIC_RESUME) { + my $pos = $MUSIC_PLAYING->{stop_pos}; + $MUSIC_PLAYER->fade_in_pos (0, 1000, $pos); + $MUSIC_START = time - $pos; + } else { + $MUSIC_PLAYER->play (0); + $MUSIC_START = time; + } - unless (--$count) { - if (@meta) { - @MUSIC_WANT = @meta; - &audio_music_changed (); - } - } - }; + delete $MUSIC_PLAYING->{stop_time}; + delete $MUSIC_PLAYING->{stop_pos}; } } sub audio_music_changed { return unless $CFG->{bgm_enable}; - # default MUSIC_WANT, undef/0 == MUSIC_DEFAULT + # default MUSIC_WANT == MUSIC_DEFAULT @MUSIC_WANT = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_WANT; # if the currently playing song is acceptable, let it continue - return if grep $MUSIC_PLAYING eq $_->{path}, @MUSIC_WANT; + return if $MUSIC_PLAYING + && grep $MUSIC_PLAYING->{path} eq $_->{path}, @MUSIC_WANT; - if (defined $MUSIC_PLAYING) { - warn "fade out"; - CFPlus::MixMusic::fade_out 2000; - } else { - warn "new music\n"; + my $NOW = time; - my $music = $MUSIC_WANT [rand @MUSIC_WANT]; + if ($MUSIC_PLAYING) { + $MUSIC_PLAYING->{stop_time} = $NOW; + $MUSIC_PLAYING->{stop_pos} = $NOW - $MUSIC_START; + CFPlus::MixMusic::fade_out 1000; + } else { + # sort by stop time, oldest first + @MUSIC_WANT = sort { $a->{stop_time} <=> $b->{stop_time} } @MUSIC_WANT; - $MUSIC_PLAYING = $music->{path}; + # if the most recently-played piece played very recently, + # resume it, else choose the oldest piece for rotation. + $MUSIC_PLAYING = + $MUSIC_WANT[-1]{stop_time} > $NOW - $MUSIC_RESUME + ? $MUSIC_WANT[-1] + : $MUSIC_WANT[0]; - $MUSIC_PLAYER = new_from_file CFPlus::MixMusic $music->{path}; - $MUSIC_PLAYER->play (0); + audio_music_start; } }