hedgewars/uSound.pas
changeset 7021 0c75512a8920
parent 6990 40e5af28d026
child 7024 3e1cca870090
equal deleted inserted replaced
7019:333afe233886 7021:0c75512a8920
    33  *                   The channel id can be used to stop a specific sound loop.
    33  *                   The channel id can be used to stop a specific sound loop.
    34  *)
    34  *)
    35 interface
    35 interface
    36 uses SDLh, uConsts, uTypes, sysutils;
    36 uses SDLh, uConsts, uTypes, sysutils;
    37 
    37 
    38 var MusicFN: shortstring; // music file name
       
    39     previousVolume: LongInt; // cached volume value
       
    40 
       
    41 procedure initModule;
    38 procedure initModule;
    42 procedure freeModule;
    39 procedure freeModule;
    43 
    40 
    44 procedure InitSound; // Initiates sound-system if isSoundEnabled.
    41 procedure InitSound;                            // Initiates sound-system if isSoundEnabled.
    45 procedure ReleaseSound(complete: boolean); // Releases sound-system and used resources.
    42 procedure ReleaseSound(complete: boolean);      // Releases sound-system and used resources.
    46 procedure SoundLoad; // Preloads some sounds for performance reasons.
    43 procedure SetSound;                             // Reset sound state to the previous state.
    47 
    44 procedure SetSound(enabled: boolean);           // Enable/disable sound-system and backup status.
    48 
    45 
    49 // MUSIC
    46 // MUSIC
    50 
    47 
    51 // Obvious music commands for music track specified in MusicFN.
    48 // Obvious music commands for music track
    52 procedure PlayMusic;
    49 procedure SetMusic(enabled: boolean);           // Enable/disable music.
    53 procedure PauseMusic;
    50 procedure SetMusic(musicname: shortstring);     // Enable/disable music and set name of musicfile to play.
    54 procedure ResumeMusic;
    51 procedure PlayMusic;                            // Play music from the start.
    55 procedure ChangeMusic; // Replaces music track with current MusicFN and plays it.
    52 procedure PauseMusic;                           // Pause music.
    56 procedure StopMusic; // Stops and releases the current track
    53 procedure ResumeMusic;                          // Resume music from pause point.
       
    54 procedure ChangeMusic(musicname: shortstring);  // Replaces music track with musicname and plays it.
       
    55 procedure StopMusic;                            // Stops and releases the current track.
    57 
    56 
    58 
    57 
    59 // SOUNDS
    58 // SOUNDS
    60 
    59 
    61 // Plays the sound snd [from a given voicepack],
    60 // Plays the sound snd [from a given voicepack],
    83 procedure PlayNextVoice;
    82 procedure PlayNextVoice;
    84 
    83 
    85 
    84 
    86 // MISC
    85 // MISC
    87 
    86 
       
    87 // Set the initial volume
       
    88 procedure SetVolume(volume: LongInt);
       
    89 
    88 // Modifies the sound volume of the game by voldelta and returns the new volume level.
    90 // Modifies the sound volume of the game by voldelta and returns the new volume level.
    89 function  ChangeVolume(voldelta: LongInt): LongInt;
    91 function  ChangeVolume(voldelta: LongInt): LongInt;
    90 
    92 
    91 // Returns a pointer to the voicepack with the given name.
    93 // Returns a pointer to the voicepack with the given name.
    92 function  AskForVoicepack(name: shortstring): Pointer;
    94 function  AskForVoicepack(name: shortstring): Pointer;
    93 
    95 
    94 // Drastically lower the volume when we lose focus (and restore the previous value)
    96 // Drastically lower the volume when we lose focus (and restore the previous value).
    95 procedure DampenAudio;
    97 procedure DampenAudio;
    96 procedure UndampenAudio;
    98 procedure UndampenAudio;
    97 
    99 
    98 implementation
   100 implementation
    99 uses uVariables, uConsole, uUtils, uCommands, uDebug;
   101 uses uVariables, uConsole, uUtils, uCommands, uDebug;
   102 var Volume: LongInt;
   104 var Volume: LongInt;
   103     lastChan: array [TSound] of LongInt;
   105     lastChan: array [TSound] of LongInt;
   104     voicepacks: array[0..cMaxTeams] of TVoicepack;
   106     voicepacks: array[0..cMaxTeams] of TVoicepack;
   105     defVoicepack: PVoicepack;
   107     defVoicepack: PVoicepack;
   106     Mus: PMixMusic = nil;
   108     Mus: PMixMusic = nil;
       
   109     MusicFN: shortstring; // music file name
       
   110     previousVolume: LongInt; // cached volume value
       
   111     isMusicEnabled: boolean;
       
   112     isSoundEnabled: boolean;
       
   113     isSEBackup: boolean;
       
   114     cInitVolume: LongInt;
       
   115 
   107 
   116 
   108 function  AskForVoicepack(name: shortstring): Pointer;
   117 function  AskForVoicepack(name: shortstring): Pointer;
   109 var i: Longword;
   118 var i: Longword;
   110     locName, path: shortstring;
   119     locName, path: shortstring;
   111 begin
   120 begin
   149     voicepacks[i].name:= name;
   158     voicepacks[i].name:= name;
   150     AskForVoicepack:= @voicepacks[i]
   159     AskForVoicepack:= @voicepacks[i]
   151 end;
   160 end;
   152 
   161 
   153 procedure InitSound;
   162 procedure InitSound;
   154 var i: TSound;
   163 const channels: LongInt = {$IFDEF MOBILE}1{$ELSE}2{$ENDIF};
   155     channels: LongInt;
       
   156 begin
   164 begin
   157     if not isSoundEnabled then
   165     if not isSoundEnabled then
   158         exit;
   166         exit;
   159     WriteToConsole('Init sound...');
   167     WriteToConsole('Init sound...');
   160     isSoundEnabled:= SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0;
   168     isSoundEnabled:= SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0;
   161 
   169 
   162 {$IFDEF MOBILE}
       
   163     channels:= 1;
       
   164 {$ELSE}
       
   165     channels:= 2;
       
   166 {$ENDIF}
       
   167 
       
   168     if isSoundEnabled then
   170     if isSoundEnabled then
   169         isSoundEnabled:= Mix_OpenAudio(44100, $8010, channels, 1024) = 0;
   171         isSoundEnabled:= Mix_OpenAudio(44100, $8010, channels, 1024) = 0;
   170 
       
   171     WriteToConsole('Init SDL_mixer... ');
       
   172     SDLTry(Mix_Init(MIX_INIT_OGG) <> 0, true);
       
   173     WriteLnToConsole(msgOK);
       
   174 
   172 
   175     if isSoundEnabled then
   173     if isSoundEnabled then
   176         WriteLnToConsole(msgOK)
   174         WriteLnToConsole(msgOK)
   177     else
   175     else
   178         WriteLnToConsole(msgFailed);
   176         WriteLnToConsole(msgFailed);
   179 
   177 
       
   178     WriteToConsole('Init SDL_mixer... ');
       
   179     SDLTry(Mix_Init(MIX_INIT_OGG) <> 0, true);
       
   180     WriteLnToConsole(msgOK);
       
   181 
   180     Mix_AllocateChannels(Succ(chanTPU));
   182     Mix_AllocateChannels(Succ(chanTPU));
   181     if isMusicEnabled then
   183     ChangeVolume(cInitVolume);
   182         Mix_VolumeMusic(50);
   184     defVoicepack:= AskForVoicepack('Default');
   183     for i:= Low(TSound) to High(TSound) do
   185 end;
   184         lastChan[i]:= -1;
   186 
   185 
   187 procedure SetSound;
   186     Volume:= 0;
   188 begin
   187     ChangeVolume(cInitVolume)
   189     isSoundEnabled:= isSEBackup;
       
   190 end;
       
   191 
       
   192 procedure SetSound(enabled: boolean);
       
   193 begin
       
   194     isSEBackup:= isSoundEnabled;
       
   195     isSoundEnabled:= enabled;
   188 end;
   196 end;
   189 
   197 
   190 // when complete is false, this procedure just releases some of the chucks on inactive channels
   198 // when complete is false, this procedure just releases some of the chucks on inactive channels
   191 // this way music is not stopped, nor are chucks currently being plauyed
   199 // in this way music is not stopped, nor are chucks currently being played
   192 procedure ReleaseSound(complete: boolean);
   200 procedure ReleaseSound(complete: boolean);
   193 var i: TSound;
   201 var i: TSound;
   194     t: Longword;
   202     t: Longword;
   195 begin
   203 begin
   196     // release and nil all sounds
   204     // release and nil all sounds
   220         while Mix_Init(0) <> 0 do
   228         while Mix_Init(0) <> 0 do
   221             Mix_Quit();
   229             Mix_Quit();
   222 
   230 
   223         Mix_CloseAudio();
   231         Mix_CloseAudio();
   224         end;
   232         end;
   225 end;
       
   226 
       
   227 procedure SoundLoad;
       
   228 var i: TSound;
       
   229     t: Longword;
       
   230 begin
       
   231     if not isSoundEnabled then
       
   232         exit;
       
   233 
       
   234     defVoicepack:= AskForVoicepack('Default');
       
   235 
       
   236     // initialize all voices to nil so that they can be loaded when needed
       
   237     for t:= 0 to cMaxTeams do
       
   238         if voicepacks[t].name <> '' then
       
   239             for i:= Low(TSound) to High(TSound) do
       
   240                 voicepacks[t].chunks[i]:= nil;
       
   241 
       
   242     for i:= Low(TSound) to High(TSound) do
       
   243     begin
       
   244         defVoicepack^.chunks[i]:= nil;
       
   245         (* this is not necessary when SDL_mixer is compiled with USE_OGG_TREMOR
       
   246         // preload all the big sound files (>32k) that would otherwise lockup the game
       
   247         if (i in [sndBeeWater, sndBee, sndCake, sndHellishImpact1, sndHellish, sndHomerun,
       
   248                   sndMolotov, sndMortar, sndRideOfTheValkyries, sndYoohoo])
       
   249             and (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
       
   250         begin
       
   251             s:= UserPathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
       
   252             if not FileExists(s) then s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
       
   253             WriteToConsole(msgLoading + s + ' ');
       
   254             defVoicepack^.chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
       
   255             SDLTry(defVoicepack^.chunks[i] <> nil, true);
       
   256             WriteLnToConsole(msgOK);
       
   257         end;*)
       
   258     end;
       
   259 
       
   260 end;
   233 end;
   261 
   234 
   262 procedure PlaySound(snd: TSound);
   235 procedure PlaySound(snd: TSound);
   263 begin
   236 begin
   264     PlaySound(snd, nil, false);
   237     PlaySound(snd, nil, false);
   464     WriteLnToConsole(msgOK);
   437     WriteLnToConsole(msgOK);
   465 
   438 
   466     SDLTry(Mix_FadeInMusic(Mus, -1, 3000) <> -1, false)
   439     SDLTry(Mix_FadeInMusic(Mus, -1, 3000) <> -1, false)
   467 end;
   440 end;
   468 
   441 
       
   442 procedure SetVolume(volume: LongInt);
       
   443 begin
       
   444     cInitVolume:= volume;
       
   445 end;
       
   446 
   469 function ChangeVolume(voldelta: LongInt): LongInt;
   447 function ChangeVolume(voldelta: LongInt): LongInt;
   470 begin
   448 begin
   471     ChangeVolume:= 0;
   449     ChangeVolume:= 0;
   472     if not isSoundEnabled then
   450     if not isSoundEnabled then
   473         exit;
   451         exit;
   474 
   452 
   475     inc(Volume, voldelta);
   453     inc(Volume, voldelta);
   476     if Volume < 0 then
   454     if Volume < 0 then
   477         Volume:= 0;
   455         Volume:= 0;
       
   456     // apply Volume to all channels
   478     Mix_Volume(-1, Volume);
   457     Mix_Volume(-1, Volume);
       
   458     // get assigned Volume
   479     Volume:= Mix_Volume(-1, -1);
   459     Volume:= Mix_Volume(-1, -1);
   480     if isMusicEnabled then
   460     if isMusicEnabled then
   481         Mix_VolumeMusic(Volume * 4 div 8);
   461         Mix_VolumeMusic(Volume * 4 div 8);
   482     ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME
   462     ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME
   483 end;
   463 end;
   488     ChangeVolume(-Volume * 7 div 9);
   468     ChangeVolume(-Volume * 7 div 9);
   489 end;
   469 end;
   490 
   470 
   491 procedure UndampenAudio;
   471 procedure UndampenAudio;
   492 begin
   472 begin
   493 ChangeVolume(previousVolume - Volume);
   473     ChangeVolume(previousVolume - Volume);
       
   474 end;
       
   475 
       
   476 procedure SetMusic(enabled: boolean);
       
   477 begin
       
   478     isMusicEnabled:= enabled;
       
   479     MusicFN:= '';
       
   480 end;
       
   481 
       
   482 procedure SetMusic(musicname: shortstring);
       
   483 begin
       
   484     isMusicEnabled:= not (musicname = '');    
       
   485     MusicFN:= musicname;
   494 end;
   486 end;
   495 
   487 
   496 procedure PauseMusic;
   488 procedure PauseMusic;
   497 begin
   489 begin
   498     if (MusicFN = '') or (not isMusicEnabled) then
   490     if (MusicFN = '') or (not isMusicEnabled) then
   509 
   501 
   510     if Mus <> nil then
   502     if Mus <> nil then
   511         Mix_ResumeMusic(Mus);
   503         Mix_ResumeMusic(Mus);
   512 end;
   504 end;
   513 
   505 
   514 procedure ChangeMusic;
   506 procedure ChangeMusic(musicname: shortstring);
   515 begin
   507 begin
       
   508     MusicFN:= musicname;
   516     if (MusicFN = '') or (not isMusicEnabled) then
   509     if (MusicFN = '') or (not isMusicEnabled) then
   517         exit;
   510         exit;
   518 
   511 
   519     StopMusic;
   512     StopMusic;
   520     PlayMusic;
   513     PlayMusic;
   541         Delete(s, byte(s[0]), 1);
   534         Delete(s, byte(s[0]), 1);
   542     CurrentTeam^.voicepack:= AskForVoicepack(s)
   535     CurrentTeam^.voicepack:= AskForVoicepack(s)
   543 end;
   536 end;
   544 
   537 
   545 procedure initModule;
   538 procedure initModule;
       
   539 var t: LongInt;
       
   540     i: TSound;
   546 begin
   541 begin
   547     RegisterVariable('voicepack', @chVoicepack, false);
   542     RegisterVariable('voicepack', @chVoicepack, false);
       
   543 
   548     MusicFN:='';
   544     MusicFN:='';
       
   545     isMusicEnabled:= true;
       
   546     isSoundEnabled:= true;
       
   547     isSEBackup:= isSoundEnabled;
       
   548     cInitVolume:= 100;
       
   549     Volume:= 0;
       
   550 
       
   551     for i:= Low(TSound) to High(TSound) do
       
   552         lastChan[i]:= -1;
       
   553 
       
   554     // initialize all voices to nil so that they can be loaded lazily
       
   555     for t:= 0 to cMaxTeams do
       
   556         if voicepacks[t].name <> '' then
       
   557             for i:= Low(TSound) to High(TSound) do
       
   558                 voicepacks[t].chunks[i]:= nil;
       
   559 
       
   560     (* on MOBILE SDL_mixer has to be compiled against Tremor (USE_OGG_TREMOR)
       
   561        or sound files bigger than 32k will lockup the game*)
       
   562     for i:= Low(TSound) to High(TSound) do
       
   563         defVoicepack^.chunks[i]:= nil;
       
   564 
   549 end;
   565 end;
   550 
   566 
   551 procedure freeModule;
   567 procedure freeModule;
   552 begin
   568 begin
   553     if isSoundEnabled then
   569     if isSoundEnabled then