hedgewars/uSound.pas
changeset 7110 c91d33837b0d
parent 7061 4e0fc59ab1ce
child 7151 ec15d9e1a7e3
--- a/hedgewars/uSound.pas	Thu May 03 22:48:02 2012 +0200
+++ b/hedgewars/uSound.pas	Tue May 22 11:19:32 2012 +0200
@@ -33,27 +33,26 @@
  *                   The channel id can be used to stop a specific sound loop.
  *)
 interface
-uses SDLh, uConsts, uTypes, sysutils;
-
-var MusicFN: shortstring; // music file name
-    previousVolume: LongInt; // cached volume value
+uses SDLh, uConsts, uTypes, SysUtils;
 
 procedure initModule;
 procedure freeModule;
 
-procedure InitSound; // Initiates sound-system if isSoundEnabled.
-procedure ReleaseSound(complete: boolean); // Releases sound-system and used resources.
-procedure SoundLoad; // Preloads some sounds for performance reasons.
-
+procedure InitSound;                            // Initiates sound-system if isSoundEnabled.
+procedure ReleaseSound(complete: boolean);      // Releases sound-system and used resources.
+procedure ResetSound;                           // Reset sound state to the previous state.
+procedure SetSound(enabled: boolean);           // Enable/disable sound-system and backup status.
 
 // MUSIC
 
-// Obvious music commands for music track specified in MusicFN.
-procedure PlayMusic;
-procedure PauseMusic;
-procedure ResumeMusic;
-procedure ChangeMusic; // Replaces music track with current MusicFN and plays it.
-procedure StopMusic; // Stops and releases the current track
+// Obvious music commands for music track
+procedure SetMusic(enabled: boolean);           // Enable/disable music.
+procedure SetMusicName(musicname: shortstring);     // Enable/disable music and set name of musicfile to play.
+procedure PlayMusic;                            // Play music from the start.
+procedure PauseMusic;                           // Pause music.
+procedure ResumeMusic;                          // Resume music from pause point.
+procedure ChangeMusic(musicname: shortstring);  // Replaces music track with musicname and plays it.
+procedure StopMusic;                            // Stops and releases the current track.
 
 
 // SOUNDS
@@ -63,21 +62,21 @@
 // then the sound's playback won't be interrupted if asked to play again.
 procedure PlaySound(snd: TSound);
 procedure PlaySound(snd: TSound; keepPlaying: boolean);
-procedure PlaySound(snd: TSound; voicepack: PVoicepack);
-procedure PlaySound(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
 
 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in.
 // Returns sound channel of the looped sound.
 function  LoopSound(snd: TSound): LongInt;
 function  LoopSound(snd: TSound; fadems: LongInt): LongInt;
-function  LoopSound(snd: TSound; voicepack: PVoicepack): LongInt; // WTF?
-function  LoopSound(snd: TSound; voicepack: PVoicepack; fadems: LongInt): LongInt;
+function  LoopSoundV(snd: TSound; voicepack: PVoicepack): LongInt; // WTF?
+function  LoopSoundV(snd: TSound; voicepack: PVoicepack; fadems: LongInt): LongInt;
 
 // Stops the normal/looped sound of the given type/in the given channel
 // [with a fade-out effect for fadems milliseconds].
 procedure StopSound(snd: TSound);
-procedure StopSound(chn: LongInt);
-procedure StopSound(chn, fadems: LongInt);
+procedure StopSoundChan(chn: LongInt);
+procedure StopSoundChan(chn, fadems: LongInt);
 
 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
 procedure PlayNextVoice;
@@ -85,13 +84,16 @@
 
 // MISC
 
+// Set the initial volume
+procedure SetVolume(volume: LongInt);
+
 // Modifies the sound volume of the game by voldelta and returns the new volume level.
 function  ChangeVolume(voldelta: LongInt): LongInt;
 
 // Returns a pointer to the voicepack with the given name.
 function  AskForVoicepack(name: shortstring): Pointer;
 
-// Drastically lower the volume when we lose focus (and restore the previous value)
+// Drastically lower the volume when we lose focus (and restore the previous value).
 procedure DampenAudio;
 procedure UndampenAudio;
 
@@ -104,6 +106,13 @@
     voicepacks: array[0..cMaxTeams] of TVoicepack;
     defVoicepack: PVoicepack;
     Mus: PMixMusic = nil;
+    MusicFN: shortstring; // music file name
+    previousVolume: LongInt; // cached volume value
+    isMusicEnabled: boolean;
+    isSoundEnabled: boolean;
+    isSEBackup: boolean;
+    cInitVolume: LongInt;
+
 
 function  AskForVoicepack(name: shortstring): Pointer;
 var i: Longword;
@@ -151,44 +160,42 @@
 end;
 
 procedure InitSound;
-var i: TSound;
-    channels: LongInt;
+const channels: LongInt = {$IFDEF MOBILE}1{$ELSE}2{$ENDIF};
 begin
     if not isSoundEnabled then
         exit;
     WriteToConsole('Init sound...');
     isSoundEnabled:= SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0;
 
-{$IFDEF MOBILE}
-    channels:= 1;
-{$ELSE}
-    channels:= 2;
-{$ENDIF}
-
     if isSoundEnabled then
         isSoundEnabled:= Mix_OpenAudio(44100, $8010, channels, 1024) = 0;
 
-    WriteToConsole('Init SDL_mixer... ');
-    SDLTry(Mix_Init(MIX_INIT_OGG) <> 0, true);
-    WriteLnToConsole(msgOK);
-
     if isSoundEnabled then
         WriteLnToConsole(msgOK)
     else
         WriteLnToConsole(msgFailed);
 
+    WriteToConsole('Init SDL_mixer... ');
+    SDLTry(Mix_Init(MIX_INIT_OGG) <> 0, true);
+    WriteLnToConsole(msgOK);
+
     Mix_AllocateChannels(Succ(chanTPU));
-    if isMusicEnabled then
-        Mix_VolumeMusic(50);
-    for i:= Low(TSound) to High(TSound) do
-        lastChan[i]:= -1;
+    ChangeVolume(cInitVolume);
+end;
 
-    Volume:= 0;
-    ChangeVolume(cInitVolume)
+procedure ResetSound;
+begin
+    isSoundEnabled:= isSEBackup;
+end;
+
+procedure SetSound(enabled: boolean);
+begin
+    isSEBackup:= isSoundEnabled;
+    isSoundEnabled:= enabled;
 end;
 
 // when complete is false, this procedure just releases some of the chucks on inactive channels
-// this way music is not stopped, nor are chucks currently being plauyed
+// in this way music is not stopped, nor are chucks currently being played
 procedure ReleaseSound(complete: boolean);
 var i: TSound;
     t: Longword;
@@ -224,57 +231,22 @@
         end;
 end;
 
-procedure SoundLoad;
-var i: TSound;
-    t: Longword;
-begin
-    if not isSoundEnabled then
-        exit;
-
-    defVoicepack:= AskForVoicepack('Default');
-
-    // initialize all voices to nil so that they can be loaded when needed
-    for t:= 0 to cMaxTeams do
-        if voicepacks[t].name <> '' then
-            for i:= Low(TSound) to High(TSound) do
-                voicepacks[t].chunks[i]:= nil;
-
-    for i:= Low(TSound) to High(TSound) do
-    begin
-        defVoicepack^.chunks[i]:= nil;
-        (* this is not necessary when SDL_mixer is compiled with USE_OGG_TREMOR
-        // preload all the big sound files (>32k) that would otherwise lockup the game
-        if (i in [sndBeeWater, sndBee, sndCake, sndHellishImpact1, sndHellish, sndHomerun,
-                  sndMolotov, sndMortar, sndRideOfTheValkyries, sndYoohoo])
-            and (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
-        begin
-            s:= UserPathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
-            if not FileExists(s) then s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
-            WriteToConsole(msgLoading + s + ' ');
-            defVoicepack^.chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
-            SDLTry(defVoicepack^.chunks[i] <> nil, true);
-            WriteLnToConsole(msgOK);
-        end;*)
-    end;
-
-end;
-
 procedure PlaySound(snd: TSound);
 begin
-    PlaySound(snd, nil, false);
+    PlaySoundV(snd, nil, false);
 end;
 
 procedure PlaySound(snd: TSound; keepPlaying: boolean);
 begin
-    PlaySound(snd, nil, keepPlaying);
+    PlaySoundV(snd, nil, keepPlaying);
 end;
 
-procedure PlaySound(snd: TSound; voicepack: PVoicepack);
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
 begin
-    PlaySound(snd, voicepack, false);
+    PlaySoundV(snd, voicepack, false);
 end;
 
-procedure PlaySound(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
 var s:shortstring;
 begin
     if (not isSoundEnabled) or fastUntilLag then
@@ -353,33 +325,33 @@
         LastVoice.snd:= VoiceList[i].snd;
         LastVoice.voicepack:= VoiceList[i].voicepack;
         VoiceList[i].snd:= sndNone;
-        PlaySound(LastVoice.snd, LastVoice.voicepack)
+        PlaySoundV(LastVoice.snd, LastVoice.voicepack)
         end
     else LastVoice.snd:= sndNone;
 end;
 
 function LoopSound(snd: TSound): LongInt;
 begin
-    LoopSound:= LoopSound(snd, nil)
+    LoopSound:= LoopSoundV(snd, nil)
 end;
 
 function LoopSound(snd: TSound; fadems: LongInt): LongInt;
 begin
-    LoopSound:= LoopSound(snd, nil, fadems)
+    LoopSound:= LoopSoundV(snd, nil, fadems)
 end;
 
-function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
+function LoopSoundV(snd: TSound; voicepack: PVoicepack): LongInt;
 begin
     voicepack:= voicepack;    // avoid compiler hint
-    LoopSound:= LoopSound(snd, nil, 0)
+    LoopSoundV:= LoopSoundV(snd, nil, 0)
 end;
 
-function LoopSound(snd: TSound; voicepack: PVoicepack; fadems: LongInt): LongInt;
+function LoopSoundV(snd: TSound; voicepack: PVoicepack; fadems: LongInt): LongInt;
 var s: shortstring;
 begin
     if (not isSoundEnabled) or fastUntilLag then
         begin
-        LoopSound:= -1;
+        LoopSoundV:= -1;
         exit
         end;
 
@@ -397,7 +369,7 @@
             else
                 WriteLnToConsole(msgOK)
             end;
-        LoopSound:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
+        LoopSoundV:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
         end
     else
         begin
@@ -412,9 +384,9 @@
             WriteLnToConsole(msgOK);
             end;
         if fadems > 0 then
-            LoopSound:= Mix_FadeInChannelTimed(-1, defVoicepack^.chunks[snd], -1, fadems, -1)
+            LoopSoundV:= Mix_FadeInChannelTimed(-1, defVoicepack^.chunks[snd], -1, fadems, -1)
         else
-            LoopSound:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1);
+            LoopSoundV:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1);
         end;
 end;
 
@@ -430,7 +402,7 @@
         end;
 end;
 
-procedure StopSound(chn: LongInt);
+procedure StopSoundChan(chn: LongInt);
 begin
     if not isSoundEnabled then
         exit;
@@ -439,7 +411,7 @@
         Mix_HaltChannel(chn);
 end;
 
-procedure StopSound(chn, fadems: LongInt);
+procedure StopSoundChan(chn, fadems: LongInt);
 begin
     if not isSoundEnabled then
         exit;
@@ -466,6 +438,11 @@
     SDLTry(Mix_FadeInMusic(Mus, -1, 3000) <> -1, false)
 end;
 
+procedure SetVolume(volume: LongInt);
+begin
+    cInitVolume:= volume;
+end;
+
 function ChangeVolume(voldelta: LongInt): LongInt;
 begin
     ChangeVolume:= 0;
@@ -475,7 +452,9 @@
     inc(Volume, voldelta);
     if Volume < 0 then
         Volume:= 0;
+    // apply Volume to all channels
     Mix_Volume(-1, Volume);
+    // get assigned Volume
     Volume:= Mix_Volume(-1, -1);
     if isMusicEnabled then
         Mix_VolumeMusic(Volume * 4 div 8);
@@ -490,7 +469,19 @@
 
 procedure UndampenAudio;
 begin
-ChangeVolume(previousVolume - Volume);
+    ChangeVolume(previousVolume - Volume);
+end;
+
+procedure SetMusic(enabled: boolean);
+begin
+    isMusicEnabled:= enabled;
+    MusicFN:= '';
+end;
+
+procedure SetMusicName(musicname: shortstring);
+begin
+    isMusicEnabled:= not (musicname = '');    
+    MusicFN:= musicname;
 end;
 
 procedure PauseMusic;
@@ -511,8 +502,9 @@
         Mix_ResumeMusic(Mus);
 end;
 
-procedure ChangeMusic;
+procedure ChangeMusic(musicname: shortstring);
 begin
+    MusicFN:= musicname;
     if (MusicFN = '') or (not isMusicEnabled) then
         exit;
 
@@ -543,9 +535,33 @@
 end;
 
 procedure initModule;
+var t: LongInt;
+    i: TSound;
 begin
     RegisterVariable('voicepack', @chVoicepack, false);
+
     MusicFN:='';
+    isMusicEnabled:= true;
+    isSoundEnabled:= true;
+    isSEBackup:= isSoundEnabled;
+    cInitVolume:= 100;
+    Volume:= 0;
+    defVoicepack:= AskForVoicepack('Default');
+
+    for i:= Low(TSound) to High(TSound) do
+        lastChan[i]:= -1;
+
+    // initialize all voices to nil so that they can be loaded lazily
+    for t:= 0 to cMaxTeams do
+        if voicepacks[t].name <> '' then
+            for i:= Low(TSound) to High(TSound) do
+                voicepacks[t].chunks[i]:= nil;
+
+    (* on MOBILE SDL_mixer has to be compiled against Tremor (USE_OGG_TREMOR)
+       or sound files bigger than 32k will lockup the game*)
+    for i:= Low(TSound) to High(TSound) do
+        defVoicepack^.chunks[i]:= nil;
+
 end;
 
 procedure freeModule;