hedgewars/uSound.pas
branchios-develop
changeset 13418 ba39a1d396c0
parent 13293 ee8c6eb0ab47
child 13496 f725701ca529
equal deleted inserted replaced
13416:6e8b807bda4b 13418:ba39a1d396c0
    61 // Plays the sound snd [from a given voicepack],
    61 // Plays the sound snd [from a given voicepack],
    62 // if keepPlaying is given and true,
    62 // if keepPlaying is given and true,
    63 // then the sound's playback won't be interrupted if asked to play again.
    63 // then the sound's playback won't be interrupted if asked to play again.
    64 procedure PlaySound(snd: TSound);
    64 procedure PlaySound(snd: TSound);
    65 procedure PlaySound(snd: TSound; keepPlaying: boolean);
    65 procedure PlaySound(snd: TSound; keepPlaying: boolean);
       
    66 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
    66 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
    67 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
    67 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
    68 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
       
    69 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean);
    68 
    70 
    69 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in.
    71 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in.
    70 // Returns sound channel of the looped sound.
    72 // Returns sound channel of the looped sound.
    71 function  LoopSound(snd: TSound): LongInt;
    73 function  LoopSound(snd: TSound): LongInt;
    72 function  LoopSound(snd: TSound; fadems: LongInt): LongInt;
    74 function  LoopSound(snd: TSound; fadems: LongInt): LongInt;
    78 procedure StopSound(snd: TSound);
    80 procedure StopSound(snd: TSound);
    79 procedure StopSoundChan(chn: LongInt);
    81 procedure StopSoundChan(chn: LongInt);
    80 procedure StopSoundChan(chn, fadems: LongInt);
    82 procedure StopSoundChan(chn, fadems: LongInt);
    81 
    83 
    82 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
    84 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
       
    85 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
    83 procedure PlayNextVoice;
    86 procedure PlayNextVoice;
    84 
    87 
    85 
    88 
    86 // GLOBAL FUNCTIONS
    89 // GLOBAL FUNCTIONS
    87 
    90 
    99 procedure SetVolume(vol: LongInt);
   102 procedure SetVolume(vol: LongInt);
   100 
   103 
   101 // Modifies the sound volume of the game by voldelta and returns the new volume level.
   104 // Modifies the sound volume of the game by voldelta and returns the new volume level.
   102 function  ChangeVolume(voldelta: LongInt): LongInt;
   105 function  ChangeVolume(voldelta: LongInt): LongInt;
   103 
   106 
       
   107 // Returns the current volume in percent
       
   108 function  GetVolumePercent(): LongInt;
       
   109 
   104 // Returns a pointer to the voicepack with the given name.
   110 // Returns a pointer to the voicepack with the given name.
   105 function  AskForVoicepack(name: shortstring): Pointer;
   111 function  AskForVoicepack(name: shortstring): Pointer;
   106 
   112 
   107 var MusicFN: shortstring; // music file name
   113 var MusicFN: shortstring; // music file name
   108     SDMusicFN: shortstring; // SD music file name
   114     SDMusicFN: shortstring; // SD music file name
       
   115     FallbackMusicFN: shortstring; // fallback music file name
       
   116     FallbackSDMusicFN: shortstring; // fallback SD music fille name
   109 
   117 
   110 var Volume: LongInt;
   118 var Volume: LongInt;
   111     SoundTimerTicks: Longword;
   119     SoundTimerTicks: Longword;
   112 implementation
   120 implementation
   113 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
   121 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
   176             (FileName:                'cake2.ogg'; Path: ptSounds; AltPath: ptNone),// sndCake
   184             (FileName:                'cake2.ogg'; Path: ptSounds; AltPath: ptNone),// sndCake
   177             (FileName:                  'Ow1.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw1
   185             (FileName:                  'Ow1.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw1
   178             (FileName:                  'Ow2.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw2
   186             (FileName:                  'Ow2.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw2
   179             (FileName:                  'Ow3.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw3
   187             (FileName:                  'Ow3.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw3
   180             (FileName:                  'Ow4.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw4
   188             (FileName:                  'Ow4.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw4
   181             (FileName:           'Firepunch1.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch1
   189             (FileName:           'Firepunch1.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch1
   182             (FileName:           'Firepunch2.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch2
   190             (FileName:           'Firepunch2.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch2
   183             (FileName:           'Firepunch3.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch3
   191             (FileName:           'Firepunch3.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch3
   184             (FileName:           'Firepunch4.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch4
   192             (FileName:           'Firepunch4.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch4
   185             (FileName:           'Firepunch5.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch5
   193             (FileName:           'Firepunch5.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch5
   186             (FileName:           'Firepunch6.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch6
   194             (FileName:           'Firepunch6.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch6
   187             (FileName:                'Melon.ogg'; Path: ptVoices; AltPath: ptNone),// sndMelon
   195             (FileName:                'Melon.ogg'; Path: ptVoices; AltPath: ptNone),// sndMelon
   188             (FileName:              'Hellish.ogg'; Path: ptSounds; AltPath: ptNone),// sndHellish
   196             (FileName:              'Hellish.ogg'; Path: ptSounds; AltPath: ptNone),// sndHellish
   189             (FileName:               'Yoohoo.ogg'; Path: ptSounds; AltPath: ptNone),// sndYoohoo
   197             (FileName:               'Yoohoo.ogg'; Path: ptSounds; AltPath: ptNone),// sndYoohoo
   190             (FileName:              'rcplane.ogg'; Path: ptSounds; AltPath: ptNone),// sndRCPlane
   198             (FileName:              'rcplane.ogg'; Path: ptSounds; AltPath: ptNone),// sndRCPlane
   191             (FileName:            'whipcrack.ogg'; Path: ptSounds; AltPath: ptNone),// sndWhipCrack
   199             (FileName:            'whipcrack.ogg'; Path: ptSounds; AltPath: ptNone),// sndWhipCrack
   276             (FileName:              'custom3.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom3
   284             (FileName:              'custom3.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom3
   277             (FileName:              'custom4.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom4
   285             (FileName:              'custom4.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom4
   278             (FileName:              'custom5.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom5
   286             (FileName:              'custom5.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom5
   279             (FileName:              'custom6.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom6
   287             (FileName:              'custom6.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom6
   280             (FileName:              'custom7.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom7
   288             (FileName:              'custom7.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom7
   281             (FileName:              'custom8.ogg'; Path: ptSounds; AltPath: ptNone) // sndCustom8
   289             (FileName:              'custom8.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom8
       
   290             (FileName:              'minigun.ogg'; Path: ptSounds; AltPath: ptNone) // sndMinigun
   282             );
   291             );
   283 
   292 
   284 
   293 
   285 function  AskForVoicepack(name: shortstring): Pointer;
   294 function  AskForVoicepack(name: shortstring): Pointer;
   286 var i: Longword;
   295 var i: Longword;
   407         end;
   416         end;
   408 end;
   417 end;
   409 
   418 
   410 procedure PlaySound(snd: TSound);
   419 procedure PlaySound(snd: TSound);
   411 begin
   420 begin
   412     PlaySoundV(snd, nil, false);
   421     PlaySoundV(snd, nil, false, false);
   413 end;
   422 end;
   414 
   423 
   415 procedure PlaySound(snd: TSound; keepPlaying: boolean);
   424 procedure PlaySound(snd: TSound; keepPlaying: boolean);
   416 begin
   425 begin
   417     PlaySoundV(snd, nil, keepPlaying);
   426     PlaySoundV(snd, nil, keepPlaying, false);
       
   427 end;
       
   428 
       
   429 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
       
   430 begin
       
   431     PlaySoundV(snd, nil, keepPlaying, ignoreMask);
   418 end;
   432 end;
   419 
   433 
   420 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
   434 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
   421 begin
   435 begin
   422     PlaySoundV(snd, voicepack, false);
   436     PlaySoundV(snd, voicepack, false, false);
   423 end;
   437 end;
   424 
   438 
   425 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
   439 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
       
   440 begin
       
   441     PlaySoundV(snd, voicepack, keepPlaying, false);
       
   442 end;
       
   443 
       
   444 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean);
   426 var s:shortstring;
   445 var s:shortstring;
   427 rwops: PSDL_RWops;
   446 rwops: PSDL_RWops;
   428 begin
   447 begin
   429     if (not isSoundEnabled) or fastUntilLag then
   448     if (not isSoundEnabled) or fastUntilLag then
   430         exit;
   449         exit;
   431 
   450 
   432     if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
   451     if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
       
   452         exit;
       
   453 
       
   454     if (ignoreMask = false) and (MaskedSounds[snd] = true) then
   433         exit;
   455         exit;
   434 
   456 
   435     if (voicepack <> nil) then
   457     if (voicepack <> nil) then
   436         begin
   458         begin
   437         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
   459         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
   438             begin
   460             begin
   439             s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
   461             s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
   440             if (not pfsExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then
   462             // Fallback to sndFirePunch1 / sndOw1 / sndOoff1 if a “higher-numbered” sound is missing
   441                 s:= cPathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
   463             if (not pfsExists(s)) then
       
   464                 begin
       
   465                 if (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then
       
   466                     snd := sndFirePunch1
       
   467                 else if (snd in [sndOw2, sndOw3, sndOw4]) then
       
   468                     snd := sndOw1
       
   469                 else if (snd in [sndOoff2, sndOoff3]) then
       
   470                     snd := sndOoff1;
       
   471                 s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
       
   472                 end;
   442             WriteToConsole(msgLoading + s + ' ');
   473             WriteToConsole(msgLoading + s + ' ');
   443             rwops := rwopsOpenRead(s);
   474             rwops := rwopsOpenRead(s);
   444 
   475 
   445             if rwops = nil then
   476             if rwops = nil then
   446                 begin
   477                 begin
   479         lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
   510         lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
   480         end;
   511         end;
   481 end;
   512 end;
   482 
   513 
   483 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
   514 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
       
   515 begin
       
   516     AddVoice(snd, voicepack, false);
       
   517 end;
       
   518 
       
   519 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
   484 var i : LongInt;
   520 var i : LongInt;
   485 begin
   521 begin
       
   522 
   486     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and  (LastVoice.voicepack = voicepack)) then
   523     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and  (LastVoice.voicepack = voicepack)) then
   487         exit;
   524         exit;
       
   525     if (ignoreMask = false) and (MaskedSounds[snd] = true) then
       
   526         exit;
       
   527 
   488     if (snd = sndVictory) or (snd = sndFlawless) then
   528     if (snd = sndVictory) or (snd = sndFlawless) then
   489         begin
   529         begin
   490         Mix_FadeOutChannel(-1, 800);
   530         Mix_FadeOutChannel(-1, 800);
   491         for i:= 0 to High(VoiceList) do
   531         for i:= 0 to High(VoiceList) do
   492             VoiceList[i].snd:= sndNone;
   532             VoiceList[i].snd:= sndNone;
   630     if SuddenDeath and (SDMusicFN <> '') then
   670     if SuddenDeath and (SDMusicFN <> '') then
   631          s:= '/Music/' + SDMusicFN
   671          s:= '/Music/' + SDMusicFN
   632     else s:= '/Music/' + MusicFN;
   672     else s:= '/Music/' + MusicFN;
   633     WriteToConsole(msgLoading + s + ' ');
   673     WriteToConsole(msgLoading + s + ' ');
   634 
   674 
       
   675     // Load normal music
   635     Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s));
   676     Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s));
   636     SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false);
   677     SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false);
   637     WriteLnToConsole(msgOK);
   678     if Mus <> nil then
       
   679         WriteLnToConsole(msgOK);
       
   680 
       
   681     // If normal music failed, try to get fallback music
       
   682     if Mus = nil then
       
   683        begin
       
   684        WriteLnToConsole('Music not found. Trying fallback music.');
       
   685        if SuddenDeath and (FallbackSDMusicFN <> '') then
       
   686            s:= '/Music/' + FallbackSDMusicFN
       
   687        else if (not SuddenDeath) and (FallbackMusicFN <> '') then
       
   688            s:= '/Music/' + FallbackMusicFN
       
   689        else
       
   690            begin
       
   691            WriteLnToConsole('No fallback music configured!');
       
   692            s:= ''
       
   693            end;
       
   694 
       
   695        if (s <> '') then
       
   696            begin
       
   697            WriteLnToConsole(msgLoading + s + ' ');
       
   698            Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s));
       
   699            SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false);
       
   700            if Mus <> nil then
       
   701                WriteLnToConsole(msgOK)
       
   702            end;
       
   703        end;
   638 
   704 
   639     SDLCheck(Mix_FadeInMusic(Mus, -1, 3000) <> -1, 'Mix_FadeInMusic', false)
   705     SDLCheck(Mix_FadeInMusic(Mus, -1, 3000) <> -1, 'Mix_FadeInMusic', false)
   640 end;
   706 end;
   641 
   707 
   642 procedure SetVolume(vol: LongInt);
   708 procedure SetVolume(vol: LongInt);
   643 begin
   709 begin
   644     cInitVolume:= vol;
   710     cInitVolume:= vol;
       
   711 end;
       
   712 
       
   713 function GetVolumePercent(): LongInt;
       
   714 begin
       
   715     GetVolumePercent:= Volume * 100 div MIX_MAX_VOLUME;
   645 end;
   716 end;
   646 
   717 
   647 function ChangeVolume(voldelta: LongInt): LongInt;
   718 function ChangeVolume(voldelta: LongInt): LongInt;
   648 begin
   719 begin
   649     ChangeVolume:= 0;
   720     ChangeVolume:= 0;
   657     Mix_Volume(-1, Volume);
   728     Mix_Volume(-1, Volume);
   658     // get assigned Volume
   729     // get assigned Volume
   659     Volume:= Mix_Volume(-1, -1);
   730     Volume:= Mix_Volume(-1, -1);
   660     if isMusicEnabled then
   731     if isMusicEnabled then
   661         Mix_VolumeMusic(Volume * 4 div 8);
   732         Mix_VolumeMusic(Volume * 4 div 8);
   662     ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME;
   733     ChangeVolume:= GetVolumePercent();
   663 
   734 
   664     if (isMusicEnabled) then
   735     if (isMusicEnabled) then
   665         if (Volume = 0) then
   736         if (Volume = 0) then
   666             PauseMusic
   737             PauseMusic
   667             else
   738             else
   763     if s[byte(s[0])]='"' then
   834     if s[byte(s[0])]='"' then
   764         Delete(s, byte(s[0]), 1);
   835         Delete(s, byte(s[0]), 1);
   765     CurrentTeam^.voicepack:= AskForVoicepack(s)
   836     CurrentTeam^.voicepack:= AskForVoicepack(s)
   766 end;
   837 end;
   767 
   838 
   768 procedure chMute(var s: shortstring);
       
   769 begin
       
   770     s:= s; // avoid compiler hint
       
   771     MuteAudio;
       
   772 end;
       
   773 
       
   774 procedure preInitModule;
   839 procedure preInitModule;
   775 begin
   840 begin
   776     isMusicEnabled:= true;
   841     isMusicEnabled:= true;
   777     isSoundEnabled:= true;
   842     isSoundEnabled:= true;
   778     cInitVolume:= 100;
   843     cInitVolume:= 100;
   781 procedure initModule;
   846 procedure initModule;
   782 var t: LongInt;
   847 var t: LongInt;
   783     i: TSound;
   848     i: TSound;
   784 begin
   849 begin
   785     RegisterVariable('voicepack', @chVoicepack, false);
   850     RegisterVariable('voicepack', @chVoicepack, false);
   786     RegisterVariable('mute'     , @chMute     , true );
       
   787 
   851 
   788     MusicFN:='';
   852     MusicFN:='';
   789     SDMusicFN:= 'sdmusic.ogg';
   853     SDMusicFN:= 'sdmusic.ogg';
   790     Mus:= nil;
   854     Mus:= nil;
   791     isAudioMuted:= false;
   855     isAudioMuted:= false;