hedgewars/uSound.pas
changeset 14058 bf8b7c166b3c
parent 14057 bf14c7c1be02
child 14062 44f20c9e6861
equal deleted inserted replaced
14057:bf14c7c1be02 14058:bf8b7c166b3c
    60 // SOUNDS
    60 // SOUNDS
    61 
    61 
    62 // Plays the sound snd [from a given voicepack],
    62 // Plays the sound snd [from a given voicepack],
    63 // if keepPlaying is given and true,
    63 // if keepPlaying is given and true,
    64 // then the sound's playback won't be interrupted if asked to play again.
    64 // then the sound's playback won't be interrupted if asked to play again.
    65 procedure PlaySound(snd: TSound);
    65 // Returns true if sound was found and is played, false otherwise.
    66 procedure PlaySound(snd: TSound; keepPlaying: boolean);
    66 function PlaySound(snd: TSound): boolean;
    67 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
    67 function PlaySound(snd: TSound; keepPlaying: boolean): boolean;
    68 procedure PlaySound(snd: TSound; keepPlaying, ignoreMask, soundAsMusic: boolean);
    68 function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean): boolean;
    69 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
    69 function PlaySound(snd: TSound; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
    70 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
    70 function PlaySoundV(snd: TSound; voicepack: PVoicepack): boolean;
    71 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean);
    71 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean): boolean;
    72 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean);
    72 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean): boolean;
       
    73 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
    73 
    74 
    74 // Plays/stops a sound to replace the main background music temporarily.
    75 // Plays/stops a sound to replace the main background music temporarily.
    75 procedure PlayMusicSound(snd: TSound);
    76 procedure PlayMusicSound(snd: TSound);
    76 procedure StopMusicSound(snd: TSound);
    77 procedure StopMusicSound(snd: TSound);
    77 
    78 
    87 procedure StopSound(snd: TSound);
    88 procedure StopSound(snd: TSound);
    88 procedure StopSound(snd: TSound; soundAsMusic: boolean);
    89 procedure StopSound(snd: TSound; soundAsMusic: boolean);
    89 procedure StopSoundChan(chn: LongInt);
    90 procedure StopSoundChan(chn: LongInt);
    90 procedure StopSoundChan(chn, fadems: LongInt);
    91 procedure StopSoundChan(chn, fadems: LongInt);
    91 
    92 
       
    93 // Add voice to the voice queue
    92 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
    94 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
    93 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
    95 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask, isFallback: boolean);
       
    96 
       
    97 // Actually play next voice
    94 procedure PlayNextVoice;
    98 procedure PlayNextVoice;
    95 
    99 
    96 
   100 
    97 // GLOBAL FUNCTIONS
   101 // GLOBAL FUNCTIONS
    98 
   102 
   123     FallbackMusicFN: shortstring; // fallback music file name
   127     FallbackMusicFN: shortstring; // fallback music file name
   124     FallbackSDMusicFN: shortstring; // fallback SD music fille name
   128     FallbackSDMusicFN: shortstring; // fallback SD music fille name
   125 
   129 
   126 var Volume: LongInt;
   130 var Volume: LongInt;
   127     SoundTimerTicks: Longword;
   131     SoundTimerTicks: Longword;
       
   132     LastVoiceFailed: boolean;
   128 implementation
   133 implementation
   129 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
   134 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
   130 
   135 
   131 const chanTPU = 32;
   136 const chanTPU = 32;
   132 var cInitVolume: LongInt;
   137 var cInitVolume: LongInt;
   138     isMusicEnabled: boolean;
   143     isMusicEnabled: boolean;
   139     isSoundEnabled: boolean;
   144     isSoundEnabled: boolean;
   140     isAutoDampening: boolean;
   145     isAutoDampening: boolean;
   141     isSEBackup: boolean;
   146     isSEBackup: boolean;
   142     VoiceList : array[0..7] of TVoice =  (
   147     VoiceList : array[0..7] of TVoice =  (
   143                     ( snd: sndNone; voicepack: nil),
   148                     ( snd: sndNone; voicepack: nil; isFallback: false),
   144                     ( snd: sndNone; voicepack: nil),
   149                     ( snd: sndNone; voicepack: nil; isFallback: false),
   145                     ( snd: sndNone; voicepack: nil),
   150                     ( snd: sndNone; voicepack: nil; isFallback: false),
   146                     ( snd: sndNone; voicepack: nil),
   151                     ( snd: sndNone; voicepack: nil; isFallback: false),
   147                     ( snd: sndNone; voicepack: nil),
   152                     ( snd: sndNone; voicepack: nil; isFallback: false),
   148                     ( snd: sndNone; voicepack: nil),
   153                     ( snd: sndNone; voicepack: nil; isFallback: false),
   149                     ( snd: sndNone; voicepack: nil),
   154                     ( snd: sndNone; voicepack: nil; isFallback: false),
   150                     ( snd: sndNone; voicepack: nil));
   155                     ( snd: sndNone; voicepack: nil; isFallback: false));
   151     Soundz: array[TSound] of record
   156     Soundz: array[TSound] of record
   152             FileName: string[31];
   157             FileName: string[31];
   153             Path, AltPath    : TPathType;
   158             Path, AltPath    : TPathType;
   154             end = (
   159             end = (
   155             (FileName:                         ''; Path: ptNone; AltPath: ptNone),// sndNone
   160             (FileName:                         ''; Path: ptNone; AltPath: ptNone),// sndNone
   497         GetFallbackV := sndEnemyDown
   502         GetFallbackV := sndEnemyDown
   498     else
   503     else
   499         GetFallbackV := sndNone;
   504         GetFallbackV := sndNone;
   500 end;
   505 end;
   501 
   506 
   502 procedure PlaySound(snd: TSound);
   507 function PlaySound(snd: TSound): boolean;
   503 begin
   508 begin
   504     PlaySoundV(snd, nil, false, false, false);
   509     PlaySound:= PlaySoundV(snd, nil, false, false, false);
   505 end;
   510 end;
   506 
   511 
   507 procedure PlaySound(snd: TSound; keepPlaying: boolean);
   512 function PlaySound(snd: TSound; keepPlaying: boolean): boolean;
   508 begin
   513 begin
   509     PlaySoundV(snd, nil, keepPlaying, false, false);
   514     PlaySound:= PlaySoundV(snd, nil, keepPlaying, false, false);
   510 end;
   515 end;
   511 
   516 
   512 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
   517 function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean): boolean;
   513 begin
   518 begin
   514     PlaySoundV(snd, nil, keepPlaying, ignoreMask, false);
   519     PlaySound:= PlaySoundV(snd, nil, keepPlaying, ignoreMask, false);
   515 end;
   520 end;
   516 
   521 
   517 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask, soundAsMusic: boolean);
   522 function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask, soundAsMusic: boolean): boolean;
   518 begin
   523 begin
   519     PlaySoundV(snd, nil, keepPlaying, ignoreMask, soundAsMusic);
   524     PlaySound:= PlaySoundV(snd, nil, keepPlaying, ignoreMask, soundAsMusic);
   520 end;
   525 end;
   521 
   526 
   522 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
   527 function PlaySoundV(snd: TSound; voicepack: PVoicepack): boolean;
   523 begin
   528 begin
   524     PlaySoundV(snd, voicepack, false, false, false);
   529     PlaySoundV:= PlaySoundV(snd, voicepack, false, false, false);
   525 end;
   530 end;
   526 
   531 
   527 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
   532 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean): boolean;
   528 begin
   533 begin
   529     PlaySoundV(snd, voicepack, keepPlaying, false, false);
   534     PlaySoundV:= PlaySoundV(snd, voicepack, keepPlaying, false, false);
   530 end;
   535 end;
   531 
   536 
   532 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean);
   537 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean): boolean;
   533 begin
   538 begin
   534     PlaySoundV(snd, voicepack, keepPlaying, ignoreMask, false);
   539     PlaySoundV:= PlaySoundV(snd, voicepack, keepPlaying, ignoreMask, false);
   535 end;
   540 end;
   536 
   541 
   537 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean);
   542 function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
   538 var s:shortstring;
   543 var s:shortstring;
   539 rwops: PSDL_RWops;
   544 rwops: PSDL_RWops;
   540 begin
   545 begin
       
   546     s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
       
   547     PlaySoundV:= false;
   541     if ((not isSoundEnabled) and (not (soundAsMusic and isMusicEnabled))) or fastUntilLag then
   548     if ((not isSoundEnabled) and (not (soundAsMusic and isMusicEnabled))) or fastUntilLag then
   542         exit;
   549         exit;
   543 
   550 
   544     if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
   551     if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
   545         exit;
   552         exit;
   574             if voicepack^.chunks[snd] = nil then
   581             if voicepack^.chunks[snd] = nil then
   575                 WriteLnToConsole(msgFailed)
   582                 WriteLnToConsole(msgFailed)
   576             else
   583             else
   577                 WriteLnToConsole(msgOK)
   584                 WriteLnToConsole(msgOK)
   578             end;
   585             end;
   579         lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
   586         lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1);
       
   587         PlaySoundV:= true;
   580         end
   588         end
   581     else
   589     else
   582         begin
   590         begin
   583         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
   591         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
   584             begin
   592             begin
   595 
   603 
   596             defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwops, 1);
   604             defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwops, 1);
   597             if SDLCheck(defVoicepack^.chunks[snd] <> nil, 'Mix_LoadWAV_RW', true) then exit;
   605             if SDLCheck(defVoicepack^.chunks[snd] <> nil, 'Mix_LoadWAV_RW', true) then exit;
   598             WriteLnToConsole(msgOK);
   606             WriteLnToConsole(msgOK);
   599             end;
   607             end;
   600         lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
   608         lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1);
       
   609         PlaySoundV:= true;
   601         end;
   610         end;
   602 end;
   611 end;
   603 
   612 
   604 procedure PlayMusicSound(snd: TSound);
   613 procedure PlayMusicSound(snd: TSound);
   605 begin
   614 begin
   613     ResumeMusic;
   622     ResumeMusic;
   614 end;
   623 end;
   615 
   624 
   616 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
   625 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
   617 begin
   626 begin
   618     AddVoice(snd, voicepack, false);
   627     AddVoice(snd, voicepack, false, false);
   619 end;
   628 end;
   620 
   629 
   621 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
   630 {
       
   631 AddVoice: Add a voice to the voice queue.
       
   632 * snd: Sound ID
       
   633 * voicepack: Hedgehog voicepack
       
   634 * ignoreMask: If true, the sound will be played anyway if masked by Lua
       
   635 * isFallback: If true, this sound is added as fallback if the sound previously added to the
       
   636              queue was not found. Useful to make sure a voice is always played, even if
       
   637              a voicepack is incomplete.
       
   638              Example:
       
   639                  AddVoice(sndRevenge, voiceAttacker);
       
   640                  AddVoice(sndRegret, voiceVictim, false, true);
       
   641              --> plays sndRegret if sndRevenge could not be played.
       
   642 }
       
   643 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask, isFallback: boolean);
   622 var i : LongInt;
   644 var i : LongInt;
   623 begin
   645 begin
   624 
   646 
   625     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and  (LastVoice.voicepack = voicepack)) then
   647     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and  (LastVoice.voicepack = voicepack)) then
   626         exit;
   648         exit;
   644         exit;
   666         exit;
   645     if(i <= High(VoiceList)) then
   667     if(i <= High(VoiceList)) then
   646         begin
   668         begin
   647         VoiceList[i].snd:= snd;
   669         VoiceList[i].snd:= snd;
   648         VoiceList[i].voicepack:= voicepack;
   670         VoiceList[i].voicepack:= voicepack;
       
   671         VoiceList[i].isFallback:= isFallback;
   649         end
   672         end
   650 end;
   673 end;
   651 
   674 
   652 procedure PlayNextVoice;
   675 procedure PlayNextVoice;
   653 var i : LongInt;
   676 var i : LongInt;
       
   677     played : boolean;
   654 begin
   678 begin
   655     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd <> sndNone) and (lastChan[LastVoice.snd] <> -1) and (Mix_Playing(lastChan[LastVoice.snd]) <> 0)) then
   679     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd <> sndNone) and (lastChan[LastVoice.snd] <> -1) and (Mix_Playing(lastChan[LastVoice.snd]) <> 0)) then
   656         exit;
   680         exit;
   657     i:= 0;
   681     i:= 0;
   658     while (i<High(VoiceList)) and (VoiceList[i].snd = sndNone) do
   682     while (i<High(VoiceList)) and (VoiceList[i].snd = sndNone) do
   659         inc(i);
   683         inc(i);
   660 
   684 
   661     if (VoiceList[i].snd <> sndNone) then
   685     played:= false;
       
   686     if (VoiceList[i].snd <> sndNone) and ((not VoiceList[i].isFallback) or LastVoiceFailed) then
   662         begin
   687         begin
   663         LastVoice.snd:= VoiceList[i].snd;
   688         LastVoice.snd:= VoiceList[i].snd;
   664         LastVoice.voicepack:= VoiceList[i].voicepack;
   689         LastVoice.voicepack:= VoiceList[i].voicepack;
       
   690         LastVoice.isFallback:= VoiceList[i].isFallback;
   665         VoiceList[i].snd:= sndNone;
   691         VoiceList[i].snd:= sndNone;
   666         PlaySoundV(LastVoice.snd, LastVoice.voicepack)
   692         played:= PlaySoundV(LastVoice.snd, LastVoice.voicepack);
       
   693         // Remember if sound was not played.
       
   694         LastVoiceFailed:= (not played);
   667         end
   695         end
   668     else LastVoice.snd:= sndNone;
   696     else
       
   697         LastVoice.snd:= sndNone;
   669 end;
   698 end;
   670 
   699 
   671 function LoopSound(snd: TSound): LongInt;
   700 function LoopSound(snd: TSound): LongInt;
   672 begin
   701 begin
   673     LoopSound:= LoopSoundV(snd, nil)
   702     LoopSound:= LoopSoundV(snd, nil)
   963     isAudioMuted:= false;
   992     isAudioMuted:= false;
   964     isSEBackup:= isSoundEnabled;
   993     isSEBackup:= isSoundEnabled;
   965     Volume:= 0;
   994     Volume:= 0;
   966     SoundTimerTicks:= 0;
   995     SoundTimerTicks:= 0;
   967     defVoicepack:= AskForVoicepack('Default');
   996     defVoicepack:= AskForVoicepack('Default');
       
   997     LastVoiceFailed:= false;
   968 
   998 
   969     for i:= Low(TSound) to High(TSound) do
   999     for i:= Low(TSound) to High(TSound) do
   970         lastChan[i]:= -1;
  1000         lastChan[i]:= -1;
   971 
  1001 
   972     // initialize all voices to nil so that they can be loaded lazily
  1002     // initialize all voices to nil so that they can be loaded lazily