1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 
8 **************************************************************************
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 ***************************************************************************
25 
26 */
27 
28 #include "eSound.h"
29 #include "config.h"
30 #include "tMemManager.h"
31 #include "tDirectories.h"
32 #include "tRandom.h"
33 #include "tError.h"
34 #include <string>
35 #include "tConfiguration.h"
36 #include "uMenu.h"
37 #include "eCamera.h"
38 //#include "tList.h"
39 #include <iostream>
40 #include <stdlib.h>
41 #include "eGrid.h"
42 #include "tException.h"
43 
44 //eGrid* eSoundPlayer::S_Grid = NULL;
45 
46 #ifdef WIN32
47 #define HAVE_LIBSDL_MIXER 1
48 #endif
49 
50 #ifndef DEDICATED
51 #ifdef  HAVE_LIBSDL_MIXER
52 #include <SDL_mixer.h>
53 static Mix_Music* music = NULL;
54 #endif
55 
56 static SDL_AudioSpec audio;
57 static bool sound_is_there=false;
58 static bool uses_sdl_mixer=false;
59 #endif
60 
61 // sound quality
62 
63 #define SOUND_OFF 0
64 #define SOUND_LOW 1
65 #define SOUND_MED 2
66 #define SOUND_HIGH 3
67 
68 #ifdef WIN32
69 static int buffer_shift=1;
70 #else
71 static int buffer_shift=0;
72 #endif
73 
74 static tConfItem<int> bs("SOUND_BUFFER_SHIFT",buffer_shift);
75 
76 static int sound_quality=SOUND_MED;
77 static tConfItem<int> sq("SOUND_QUALITY",sound_quality);
78 
79 static int sound_sources=10;
80 static tConfItem<int> ss("SOUND_SOURCES",sound_sources);
81 static REAL loudness_thresh=0;
82 static int real_sound_sources=0;
83 
84 static tList<eSoundPlayer> se_globalPlayers;
85 
86 
fill_audio(void * udata,Uint8 * stream,int len)87 void fill_audio(void *udata, Uint8 *stream, int len)
88 {
89 #ifndef DEDICATED
90     real_sound_sources=0;
91     int i;
92     if (eGrid::CurrentGrid())
93         for(i=eGrid::CurrentGrid()->Cameras().Len()-1;i>=0;i--)
94         {
95             eCamera *pCam = eGrid::CurrentGrid()->Cameras()(i);
96             if(pCam)
97                 pCam->SoundMix(stream,len);
98         }
99 
100     for(i=se_globalPlayers.Len()-1;i>=0;i--)
101         se_globalPlayers(i)->Mix(stream,len,0,1,1);
102 
103     if (real_sound_sources>sound_sources+4)
104         loudness_thresh+=.01;
105     if (real_sound_sources>sound_sources+1)
106         loudness_thresh+=.001;
107     if (real_sound_sources<sound_sources-4)
108         loudness_thresh-=.001;
109     if (real_sound_sources<sound_sources-1)
110         loudness_thresh-=.0001;
111     if (loudness_thresh<0)
112         loudness_thresh=0;
113 #endif
114 }
115 
116 #ifndef DEDICATED
117 #ifdef DEFAULT_SDL_AUDIODRIVER
118 
119 // stringification, yep, two levels required
120 #define XSTRING(s) #s
121 #define STRING(s) XSTRING(s)
122 
123 // call once to initialize SDL sound subsystem
se_SoundInitPrepare()124 static bool se_SoundInitPrepare()
125 {
126     // initialize audio subsystem with predefined, hopefully good, driver
127     if ( ! getenv("SDL_AUDIODRIVER") ) {
128         char * arg = "SDL_AUDIODRIVER=" STRING(DEFAULT_SDL_AUDIODRIVER);
129         putenv(arg);
130 
131         if ( SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0 )
132             return true;
133 
134         putenv("SDL_AUDIODRIVER=");
135     }
136 
137     // if that fails, try what the user wanted
138     return ( SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0 );
139 }
140 #endif
141 #endif
142 
se_SoundInit()143 void se_SoundInit()
144 {
145 #ifndef DEDICATED
146     // save configuration file with sound disabled on first use so we don't try again
147     bool needSave = false;
148     static bool firstRun = true;
149     if ( st_FirstUse )
150     {
151         needSave = true;
152         int sound_quality_back = sound_quality;
153         sound_quality = SOUND_OFF;
154         st_SaveConfig();
155         if ( firstRun )
156             con << tOutput("$sound_firstinit");
157         sound_quality=sound_quality_back;
158     }
159 
160     if ( sound_quality != SOUND_OFF )
161     {
162 #ifdef DEFAULT_SDL_AUDIODRIVER
163         static bool init = se_SoundInitPrepare();
164         if ( !init )
165             return;
166 #endif
167         if ( firstRun && !SDL_WasInit( SDL_INIT_AUDIO ) )
168             return;
169         firstRun = false;
170     }
171 
172     if (!sound_is_there && sound_quality!=SOUND_OFF)
173     {
174         SDL_AudioSpec desired;
175 
176         switch (sound_quality)
177         {
178         case SOUND_LOW:
179             desired.freq=11025; break;
180         case SOUND_MED:
181             desired.freq=22050; break;
182         case SOUND_HIGH:
183             desired.freq=44100; break;
184         default:
185             desired.freq=22050;
186         }
187 
188         desired.format=AUDIO_S16SYS;
189         desired.samples=128;
190         while (desired.samples <= desired.freq >> (6-buffer_shift))
191             desired.samples <<= 1;
192         desired.channels = 2;
193         desired.callback = fill_audio;
194         desired.userdata = NULL;
195 
196 #ifdef HAVE_LIBSDL_MIXER
197         uses_sdl_mixer=true;
198 
199         // init using SDL_Mixer
200         sound_is_there=(Mix_OpenAudio(desired.freq, desired.format, desired.channels, desired.samples)>=0);
201 
202         if ( sound_is_there )
203         {
204             // query actual sound info
205             audio = desired;
206             int channels;
207             Mix_QuerySpec( &audio.freq, &audio.format, &channels );
208             audio.channels = channels;
209 
210             // register callback
211             Mix_SetPostMix( &fill_audio, NULL );
212 
213             const tPath& vpath = tDirectories::Data();
214             tString musFile = vpath.GetReadPath( "music/fire.xm" );
215 
216             music = Mix_LoadMUS( musFile );
217 
218             if ( music )
219                 Mix_FadeInMusic( music, -1, 2000 );
220 
221         }
222 #else
223         // just use SDL to init sound
224         uses_sdl_mixer=false;
225         sound_is_there=(SDL_OpenAudio(&desired,&audio)>=0);
226 #endif
227         if (sound_is_there && (audio.format!=AUDIO_S16SYS || audio.channels!=2))
228         {
229             uses_sdl_mixer=false;
230             se_SoundExit();
231             // force emulation of 16 bit stereo; sadly, this cannot use SDL_Mixer :-(
232             audio.format=AUDIO_S16SYS;
233             audio.channels=2;
234             sound_is_there=(SDL_OpenAudio(&audio,NULL)>=0);
235             con << tOutput("$sound_error_no16bit");
236         }
237         if (!sound_is_there)
238             con << tOutput("$sound_error_initfailed");
239         else
240         {
241             //for(int i=wavs.Len()-1;i>=0;i--)
242             //wavs(i)->Init();
243 #ifdef DEBUG
244             tOutput o;
245             o.SetTemplateParameter(1,audio.freq);
246             o.SetTemplateParameter(2,audio.samples);
247             o << "$sound_inited";
248             con << o;
249 #endif
250             se_SoundPause(false);
251         }
252     }
253 
254     // save sound settings, they appear to work
255     if ( needSave )
256     {
257         st_SaveConfig();
258     }
259 #endif
260 }
261 
se_SoundExit()262 void se_SoundExit(){
263 #ifndef DEDICATED
264     eSoundLocker locker;
265 
266     eWavData::UnloadAll();
267     se_SoundPause(true);
268 
269     if (sound_is_there){
270 #ifdef DEBUG
271         con << tOutput("$sound_disabling");
272 #endif
273         //		se_SoundPause(false);
274         //    for(int i=wavs.Len()-1;i>=0;i--)
275         //wavs(i)->Exit();
276 
277 #ifdef HAVE_LIBSDL_MIXER
278         if ( music )
279         {
280             if( Mix_PlayingMusic() )
281             {
282                 Mix_FadeOutMusic(100);
283                 SDL_Delay(100);
284             }
285             Mix_FreeMusic( music );
286             music = NULL;
287         }
288 
289         se_SoundPause(true);
290 
291         if ( uses_sdl_mixer )
292             Mix_CloseAudio();
293         else
294 #endif
295             SDL_CloseAudio();
296 
297 #ifdef DEBUG
298         con << tOutput("$sound_disabling_done");
299 #endif
300     }
301     sound_is_there=false;
302 #endif
303 }
304 
305 #ifndef DEDICATED
306 static unsigned int locks;
307 #endif
308 
se_SoundLock()309 void se_SoundLock(){
310 #ifndef DEDICATED
311     if (!locks)
312         SDL_LockAudio();
313     locks++;
314 #endif
315 }
316 
se_SoundUnlock()317 void se_SoundUnlock(){
318 #ifndef DEDICATED
319     locks--;
320     if (!locks)
321         SDL_UnlockAudio();
322 #endif
323 }
324 
se_SoundPause(bool p)325 void se_SoundPause(bool p){
326 #ifndef DEDICATED
327     SDL_PauseAudio(p);
328 #endif
329 }
330 
331 // ***********************************************************
332 
333 eWavData* eWavData::s_anchor = NULL;
334 
eWavData(const char * fileName,const char * alternative)335 eWavData::eWavData(const char * fileName,const char *alternative)
336         :tListItem<eWavData>(s_anchor),data(NULL),len(0),freeData(false), loadError(false){
337     //wavs.Add(this,id);
338     filename     = fileName;
339     filename_alt = alternative;
340 
341 }
342 
Load()343 void eWavData::Load(){
344     //wavs.Add(this,id);
345 
346     if (data)
347     {
348         loadError = false;
349         return;
350     }
351 
352 #ifndef DEDICATED
353 
354     static char const * errorName = "Sound Error";
355 
356     freeData = false;
357 
358     loadError = true;
359 
360     alt=false;
361 
362     const tPath& path = tDirectories::Data();
363 
364     SDL_AudioSpec *result=SDL_LoadWAV( path.GetReadPath( filename ) ,&spec,&data,&len);
365     if (result!=&spec || !data){
366         if (filename_alt.Len()>1){
367             result=SDL_LoadWAV( path.GetReadPath( filename_alt ),&spec,&data,&len);
368             if (result!=&spec || !data)
369             {
370                 tOutput err;
371                 err.SetTemplateParameter(1, filename);
372                 err << "$sound_error_filenotfound";
373                 throw tGenericException(err, errorName);
374             }
375             else
376                 alt=true;
377         }
378         else{
379             result=SDL_LoadWAV( path.GetReadPath( "sound/expl.wav" ) ,&spec,&data,&len);
380             if (result!=&spec || !data)
381             {
382                 tOutput err;
383                 err.SetTemplateParameter(1, "sound/expl.waw");
384                 err << "$sound_error_filenotfount";
385                 throw tGenericException(err, errorName);
386             }
387             else
388                 len=0;
389         }
390         /*
391           tERR_ERROR("Sound file " << fileName << " not found. Have you called "
392           "Armagetron from the right directory?"); */
393     }
394 
395     if (spec.format==AUDIO_S16SYS)
396         samples=len>>1;
397     //	else if(spec.format==AUDIO_U8)
398     //		samples=len;
399     else
400     {
401         // prepare error message
402         tOutput err;
403         err.SetTemplateParameter(1, filename);
404         err << "$sound_error_unsupported";
405 
406         // convert to 16 bit system format
407         SDL_AudioCVT cvt;
408         if ( -1 == SDL_BuildAudioCVT( &cvt, spec.format, spec.channels, spec.freq, AUDIO_S16SYS, spec.channels, spec.freq ) )
409         {
410             throw tGenericException(err, errorName);
411         }
412 
413         cvt.buf=reinterpret_cast<Uint8 *>( malloc( len * cvt.len_mult ) );
414         cvt.len=len;
415         memcpy(cvt.buf, data, len);
416         freeData = true;
417 
418 
419         if ( -1 == SDL_ConvertAudio( &cvt ) )
420         {
421             throw tGenericException(err, errorName);
422         }
423 
424         SDL_FreeWAV( data );
425         data = cvt.buf;
426         spec.format = AUDIO_S16SYS;
427         len    = len * cvt.len_mult;
428 
429         samples = len >> 1;
430     }
431 
432     samples/=spec.channels;
433 
434 #ifdef DEBUG
435 #ifdef LINUX
436     con << "Sound file " << filename << " loaded: ";
437     switch (spec.format){
438     case AUDIO_S16SYS: con << "16 bit "; break;
439     case AUDIO_U8: con << "8 bit "; break;
440     default: con << "unknown "; break;
441     }
442     if (spec.channels==2)
443         con << "stereo ";
444     else
445         con << "mono ";
446 
447     con << "at " << spec.freq << " Hz,\n";
448 
449     con << samples << " samples in " << len << " bytes.\n";
450 
451     loadError = false;
452 #endif
453 #endif
454 #endif
455 }
456 
Unload()457 void eWavData::Unload(){
458 #ifndef DEDICATED
459     loadError = false;
460 
461     //wavs.Add(this,id);
462     if (data){
463         eSoundLocker locker;
464         if ( freeData )
465         {
466 
467             free(data);
468 
469         }
470 
471         else
472 
473         {
474 
475             SDL_FreeWAV(data);
476 
477         }
478 
479 
480 
481         data=NULL;
482         len=0;
483     }
484 #endif
485 }
486 
UnloadAll()487 void eWavData::UnloadAll(){
488     //wavs.Add(this,id);
489     eWavData* wav = s_anchor;
490     while ( wav )
491     {
492         wav->Unload();
493         wav = wav->Next();
494     }
495 
496 }
497 
~eWavData()498 eWavData::~eWavData(){
499 #ifndef DEDICATED
500     Unload();
501 #endif
502 }
503 
Mix(Uint8 * dest,Uint32 playlen,eAudioPos & pos,REAL Rvol,REAL Lvol,REAL Speed,bool loop)504 bool eWavData::Mix(Uint8 *dest,Uint32 playlen,eAudioPos &pos,
505                    REAL Rvol,REAL Lvol,REAL Speed,bool loop){
506 #ifndef DEDICATED
507     if ( !data )
508     {
509         if( !loadError )
510         {
511             Load();
512         }
513         if ( !data )
514         {
515             return false;
516         }
517     }
518 
519     playlen/=4;
520 
521     //	Rvol *= 4;
522     //	Lvol *= 4;
523 
524     const REAL thresh = .25;
525 
526     if ( Rvol > thresh )
527     {
528         Rvol = thresh;
529     }
530 
531     if ( Lvol > thresh )
532     {
533         Lvol = thresh;
534     }
535 
536 #define SPEED_FRACTION (1<<20)
537 
538 #define VOL_SHIFT 16
539 #define VOL_FRACTION (1<<VOL_SHIFT)
540 
541 #define MAX_VAL ((1<<16)-1)
542 #define MIN_VAL -(1<<16)
543 
544     // first, split the speed into the part before and after the decimal:
545     if (Speed<0) Speed=0;
546 
547     // adjust for different sample rates:
548     Speed*=spec.freq;
549     Speed/=audio.freq;
550 
551     int speed=int(floor(Speed));
552     int speed_fraction=int(SPEED_FRACTION*(Speed-speed));
553 
554     // secondly, make integers out of the volumes:
555     int rvol=int(Rvol*VOL_FRACTION);
556     int lvol=int(Lvol*VOL_FRACTION);
557 
558 
559     bool goon=true;
560 
561     while (goon){
562         if (spec.channels==2){
563             if (spec.format==AUDIO_U8)
564                 while (playlen>0 && pos.pos<samples){
565                     // fix endian problems for the Mac port, as well as support for other
566                     // formats than  stereo...
567                     int l=((short *)dest)[0];
568                     int r=((short *)dest)[1];
569                     r += (rvol*(data[(pos.pos<<1)  ]-128)) >> (VOL_SHIFT-8);
570                     l += (lvol*(data[(pos.pos<<1)+1]-128)) >> (VOL_SHIFT-8);
571                     if (r>MAX_VAL) r=MAX_VAL;
572                     if (l>MAX_VAL) l=MAX_VAL;
573                     if (r<MIN_VAL) r=MIN_VAL;
574                     if (l<MIN_VAL) l=MIN_VAL;
575 
576                     ((short *)dest)[0]=l;
577                     ((short *)dest)[1]=r;
578 
579                     dest+=4;
580 
581                     pos.pos+=speed;
582 
583                     pos.fraction+=speed_fraction;
584                     while (pos.fraction>=SPEED_FRACTION){
585                         pos.fraction-=SPEED_FRACTION;
586                         pos.pos++;
587                     }
588 
589                     playlen--;
590                 }
591             else{
592                 while (playlen>0 && pos.pos<samples){
593                     int l=((short *)dest)[0];
594                     int r=((short *)dest)[1];
595                     r += (rvol*(((short *)data)[(pos.pos<<1)  ])) >> VOL_SHIFT;
596                     l += (lvol*(((short *)data)[(pos.pos<<1)+1])) >> VOL_SHIFT;
597                     if (r>MAX_VAL) r=MAX_VAL;
598                     if (l>MAX_VAL) l=MAX_VAL;
599                     if (r<MIN_VAL) r=MIN_VAL;
600                     if (l<MIN_VAL) l=MIN_VAL;
601 
602                     ((short *)dest)[0]=l;
603                     ((short *)dest)[1]=r;
604 
605                     dest+=4;
606 
607                     pos.pos+=speed;
608 
609                     pos.fraction+=speed_fraction;
610                     while (pos.fraction>=SPEED_FRACTION){
611                         pos.fraction-=SPEED_FRACTION;
612                         pos.pos++;
613                     }
614                     playlen--;
615                 }
616             }
617         }
618         else{
619             if (spec.format==AUDIO_U8){
620                 while (playlen>0 && pos.pos<samples){
621                     // fix endian problems for the Mac port, as well as support for other
622                     // formats than  stereo...
623                     int l=((short *)dest)[0];
624                     int r=((short *)dest)[1];
625                     int d=data[pos.pos]-128;
626                     l += (lvol*d) >> (VOL_SHIFT-8);
627                     r += (rvol*d) >> (VOL_SHIFT-8);
628                     if (r>MAX_VAL) r=MAX_VAL;
629                     if (l>MAX_VAL) l=MAX_VAL;
630                     if (r<MIN_VAL) r=MIN_VAL;
631                     if (l<MIN_VAL) l=MIN_VAL;
632 
633                     ((short *)dest)[0]=l;
634                     ((short *)dest)[1]=r;
635 
636                     dest+=4;
637 
638                     pos.pos+=speed;
639 
640                     pos.fraction+=speed_fraction;
641                     while (pos.fraction>=SPEED_FRACTION){
642                         pos.fraction-=SPEED_FRACTION;
643                         pos.pos++;
644                     }
645 
646                     playlen--;
647                 }
648             }
649             else
650                 while (playlen>0 && pos.pos<samples){
651                     int l=((short *)dest)[0];
652                     int r=((short *)dest)[1];
653                     int d=((short *)data)[pos.pos];
654                     l += (lvol*d) >> VOL_SHIFT;
655                     r += (rvol*d) >> VOL_SHIFT;
656                     if (r>MAX_VAL) r=MAX_VAL;
657                     if (l>MAX_VAL) l=MAX_VAL;
658                     if (r<MIN_VAL) r=MIN_VAL;
659                     if (l<MIN_VAL) l=MIN_VAL;
660 
661                     ((short *)dest)[0]=l;
662                     ((short *)dest)[1]=r;
663 
664                     dest+=4;
665 
666                     pos.pos+=speed;
667 
668                     pos.fraction+=speed_fraction;
669                     while (pos.fraction>=SPEED_FRACTION){
670                         pos.fraction-=SPEED_FRACTION;
671                         pos.pos++;
672                     }
673                     playlen--;
674                 }
675         }
676 
677         if (loop && pos.pos>=samples)
678             pos.pos-=samples;
679         else
680             goon=false;
681     }
682 #endif
683     return (playlen>0);
684 
685 }
686 
Loop()687 void eWavData::Loop(){
688 #ifndef DEDICATED
689     Uint8 *buff2=tNEW(Uint8) [len];
690 
691     if (buff2){
692         memcpy(buff2,data,len);
693         Uint32 samples;
694 
695         if (spec.format==AUDIO_U8){
696             samples=len;
697             for(int i=samples-1;i>=0;i--){
698                 Uint32 j=i+((len>>2)<<1);
699                 if (j>=len) j-=len;
700 
701                 REAL a=fabs(100*(j/REAL(samples)-.5));
702                 if (a>1) a=1;
703                 REAL b=1-a;
704 
705                 data[i]=int(a*buff2[i]+b*buff2[j]);
706             }
707         }
708         else if (spec.format==AUDIO_S16SYS){
709             samples=len>>1;
710             for(int i=samples-1;i>=0;i--){
711 
712                 /*
713                   REAL a=2*i/REAL(samples);
714                   if (a>1) a=2-a;
715                   REAL b=1-a;
716                 */
717 
718 
719                 Uint32 j=i+((samples>>2)<<1);
720                 while (j>=samples) j-=samples;
721 
722                 REAL a=fabs(100*(j/REAL(samples)-.5));
723                 if (a>1) a=1;
724                 REAL b=1-a;
725 
726 
727                 ((short *)data)[i]=int(a*((short *)buff2)[i]+b*((short *)buff2)[j]);
728             }
729         }
730         delete[] buff2;
731     }
732 
733 #endif
734 }
735 
736 
737 // ******************************************************************
738 
Reset(int randomize)739 void eAudioPos::Reset(int randomize){
740 #ifndef DEDICATED
741     if (randomize){
742         tRandomizer & randomizer = tRandomizer::GetInstance();
743         fraction = randomizer.Get( SPEED_FRACTION );
744         // fraction=int(SPEED_FRACTION*(rand()/float(RAND_MAX)));
745         pos=randomizer.Get( randomize );
746         // pos=int(randomize*(rand()/float(RAND_MAX)));
747     }
748     else
749         fraction=pos=0;
750 #endif
751 }
752 
753 
754 
eSoundPlayer(eWavData & w,bool l)755 eSoundPlayer::eSoundPlayer(eWavData &w,bool l)
756         :id(-1),wav(&w),loop(l){
757     if (l)
758         wav->Load();
759 
760     for(int i=MAX_VIEWERS-1;i>=0;i--)
761         goon[i]=true;
762 }
763 
~eSoundPlayer()764 eSoundPlayer::~eSoundPlayer()
765 {
766     eSoundLocker locker;
767     se_globalPlayers.Remove(this,id);
768 }
769 
Mix(Uint8 * dest,Uint32 len,int viewer,REAL rvol,REAL lvol,REAL speed)770 bool eSoundPlayer::Mix(Uint8 *dest,
771                        Uint32 len,
772                        int viewer,
773                        REAL rvol,
774                        REAL lvol,
775                        REAL speed){
776 
777     if (goon[viewer]){
778         if (rvol+lvol>loudness_thresh){
779             real_sound_sources++;
780             return goon[viewer]=!wav->Mix(dest,len,pos[viewer],rvol,lvol,speed,loop);
781         }
782         else
783             return true;
784     }
785     else
786         return false;
787 }
788 
Reset(int randomize)789 void eSoundPlayer::Reset(int randomize){
790     wav->Load();
791 
792     for(int i=MAX_VIEWERS-1;i>=0;i--){
793         pos[i].Reset(randomize);
794         goon[i]=true;
795     }
796 }
797 
End()798 void eSoundPlayer::End(){
799     for(int i=MAX_VIEWERS-1;i>=0;i--){
800         goon[i]=false;
801     }
802 }
803 
804 
MakeGlobal()805 void eSoundPlayer::MakeGlobal(){
806     wav->Load();
807 
808     eSoundLocker locker;
809     se_globalPlayers.Add(this,id);
810 }
811 
812 
813 // ***************************************************************
814 
815 uMenu Sound_menu("$sound_menu_text");
816 
817 static uMenuItemInt sources_men
818 (&Sound_menu,"$sound_menu_sources_text",
819  "$sound_menu_sources_help",
820  sound_sources,2,20,2);
821 
822 static uMenuItemSelection<int> sq_men
823 (&Sound_menu,"$sound_menu_quality_text",
824  "$sound_menu_quality_help",
825  sound_quality);
826 
827 
828 static uSelectEntry<int> a(sq_men,
829                            "$sound_menu_quality_off_text",
830                            "$sound_menu_quality_off_help",
831                            SOUND_OFF);
832 static uSelectEntry<int> b(sq_men,
833                            "$sound_menu_quality_low_text",
834                            "$sound_menu_quality_low_help",
835                            SOUND_LOW);
836 static uSelectEntry<int> c(sq_men,
837                            "$sound_menu_quality_medium_text",
838                            "$sound_menu_quality_medium_help",
839                            SOUND_MED);
840 static uSelectEntry<int> d(sq_men,
841                            "$sound_menu_quality_high_text",
842                            "$sound_menu_quality_high_help",
843                            SOUND_HIGH);
844 
845 static uMenuItemSelection<int> bm_men
846 (&Sound_menu,
847  "$sound_menu_buffer_text",
848  "$sound_menu_buffer_help",
849  buffer_shift);
850 
851 static uSelectEntry<int> ba(bm_men,
852                             "$sound_menu_buffer_vsmall_text",
853                             "$sound_menu_buffer_vsmall_help",
854                             -2);
855 
856 static uSelectEntry<int> bb(bm_men,
857                             "$sound_menu_buffer_small_text",
858                             "$sound_menu_buffer_small_help",
859                             -1);
860 
861 static uSelectEntry<int> bc(bm_men,
862                             "$sound_menu_buffer_med_text",
863                             "$sound_menu_buffer_med_help",
864                             0);
865 
866 static uSelectEntry<int> bd(bm_men,
867                             "$sound_menu_buffer_high_text",
868                             "$sound_menu_buffer_high_help",
869                             1);
870 
871 static uSelectEntry<int> be(bm_men,
872                             "$sound_menu_buffer_vhigh_text",
873                             "$sound_menu_buffer_vhigh_help",
874                             2);
875 
876 
se_SoundMenu()877 void se_SoundMenu(){
878     //	se_SoundPause(true);
879     //	se_SoundLock();
880     int oldsettings=sound_quality;
881     int oldshift=buffer_shift;
882     Sound_menu.Enter();
883     if (oldsettings!=sound_quality || oldshift!=buffer_shift){
884         se_SoundExit();
885         se_SoundInit();
886     }
887     //	se_SoundUnlock();
888     //  se_SoundPause(false);
889 }
890 
eSoundLocker()891 eSoundLocker::eSoundLocker()
892 {
893     se_SoundLock();
894 }
895 
~eSoundLocker()896 eSoundLocker::~eSoundLocker()
897 {
898     se_SoundUnlock();
899 }
900 
901