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 |
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 |