00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "eSound.h"
00029 #include "config.h"
00030 #include "tMemManager.h"
00031 #include "tDirectories.h"
00032 #include "tRandom.h"
00033 #include "tError.h"
00034 #include <string>
00035 #include "tConfiguration.h"
00036 #include "uMenu.h"
00037 #include "eCamera.h"
00038
00039 #include <iostream>
00040 #include <stdlib.h>
00041 #include "eGrid.h"
00042 #include "tException.h"
00043
00044
00045
00046 #ifdef WIN32
00047 #define HAVE_LIBSDL_MIXER 1
00048 #endif
00049
00050 #ifndef DEDICATED
00051 #ifdef HAVE_LIBSDL_MIXER
00052 #include <SDL_mixer.h>
00053 static Mix_Music* music = NULL;
00054 #endif
00055
00056 static SDL_AudioSpec audio;
00057 static bool sound_is_there=false;
00058 static bool uses_sdl_mixer=false;
00059 #endif
00060
00061
00062
00063 #define SOUND_OFF 0
00064 #define SOUND_LOW 1
00065 #define SOUND_MED 2
00066 #define SOUND_HIGH 3
00067
00068 #ifdef WIN32
00069 static int buffer_shift=1;
00070 #else
00071 static int buffer_shift=0;
00072 #endif
00073
00074 static tConfItem<int> bs("SOUND_BUFFER_SHIFT",buffer_shift);
00075
00076 int sound_quality=SOUND_MED;
00077 static tConfItem<int> sq("SOUND_QUALITY",sound_quality);
00078
00079 static int sound_sources=10;
00080 static tConfItem<int> ss("SOUND_SOURCES",sound_sources);
00081 static REAL loudness_thresh=0;
00082 static int real_sound_sources=0;
00083
00084 static tList<eSoundPlayer> se_globalPlayers;
00085
00086
00087 void fill_audio(void *udata, Uint8 *stream, int len)
00088 {
00089 #ifndef DEDICATED
00090 real_sound_sources=0;
00091 int i;
00092 if (eGrid::CurrentGrid())
00093 for(i=eGrid::CurrentGrid()->Cameras().Len()-1;i>=0;i--)
00094 eGrid::CurrentGrid()->Cameras()(i)->SoundMix(stream,len);
00095
00096 for(i=se_globalPlayers.Len()-1;i>=0;i--)
00097 se_globalPlayers(i)->Mix(stream,len,0,1,1);
00098
00099 if (real_sound_sources>sound_sources+4)
00100 loudness_thresh+=.01;
00101 if (real_sound_sources>sound_sources+1)
00102 loudness_thresh+=.001;
00103 if (real_sound_sources<sound_sources-4)
00104 loudness_thresh-=.001;
00105 if (real_sound_sources<sound_sources-1)
00106 loudness_thresh-=.0001;
00107 if (loudness_thresh<0)
00108 loudness_thresh=0;
00109 #endif
00110 }
00111
00112 #ifndef DEDICATED
00113 #ifdef DEFAULT_SDL_AUDIODRIVER
00114
00115
00116 #define XSTRING(s) #s
00117 #define STRING(s) XSTRING(s)
00118
00119
00120 static bool se_SoundInitPrepare()
00121 {
00122
00123 if ( ! getenv("SDL_AUDIODRIVER") ) {
00124 char * arg = "SDL_AUDIODRIVER=" STRING(DEFAULT_SDL_AUDIODRIVER);
00125 putenv(arg);
00126
00127 if ( SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0 )
00128 return true;
00129
00130 putenv("SDL_AUDIODRIVER=");
00131 }
00132
00133
00134 return ( SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0 );
00135 }
00136 #endif
00137 #endif
00138
00139 void se_SoundInit()
00140 {
00141 #ifndef DEDICATED
00142
00143 bool needSave = false;
00144 static bool firstRun = true;
00145 if ( st_FirstUse )
00146 {
00147 needSave = true;
00148 int sound_quality_back = sound_quality;
00149 sound_quality = SOUND_OFF;
00150 st_SaveConfig();
00151 if ( firstRun )
00152 con << tOutput("$sound_firstinit");
00153 sound_quality=sound_quality_back;
00154 }
00155
00156 if ( sound_quality != SOUND_OFF )
00157 {
00158 #ifdef DEFAULT_SDL_AUDIODRIVER
00159 static bool init = se_SoundInitPrepare();
00160 if ( !init )
00161 return;
00162 #endif
00163 if ( firstRun && !SDL_WasInit( SDL_INIT_AUDIO ) )
00164 return;
00165 firstRun = false;
00166 }
00167
00168 if (!sound_is_there && sound_quality!=SOUND_OFF)
00169 {
00170 SDL_AudioSpec desired;
00171
00172 switch (sound_quality)
00173 {
00174 case SOUND_LOW:
00175 desired.freq=11025; break;
00176 case SOUND_MED:
00177 desired.freq=22050; break;
00178 case SOUND_HIGH:
00179 desired.freq=44100; break;
00180 default:
00181 desired.freq=22050;
00182 }
00183
00184 desired.format=AUDIO_S16SYS;
00185 desired.samples=128;
00186 while (desired.samples <= desired.freq >> (6-buffer_shift))
00187 desired.samples <<= 1;
00188 desired.channels = 2;
00189 desired.callback = fill_audio;
00190 desired.userdata = NULL;
00191
00192 #ifdef HAVE_LIBSDL_MIXER
00193 uses_sdl_mixer=true;
00194
00195
00196 sound_is_there=(Mix_OpenAudio(desired.freq, desired.format, desired.channels, desired.samples)>=0);
00197
00198 if ( sound_is_there )
00199 {
00200
00201 audio = desired;
00202 int channels;
00203 Mix_QuerySpec( &audio.freq, &audio.format, &channels );
00204 audio.channels = channels;
00205
00206
00207 Mix_SetPostMix( &fill_audio, NULL );
00208
00209 const tPath& vpath = tDirectories::Data();
00210 tString musFile = vpath.GetReadPath( "music/fire.xm" );
00211
00212 music = Mix_LoadMUS( musFile );
00213
00214 if ( music )
00215 Mix_FadeInMusic( music, -1, 2000 );
00216
00217 }
00218 #else
00219
00220 uses_sdl_mixer=false;
00221 sound_is_there=(SDL_OpenAudio(&desired,&audio)>=0);
00222 #endif
00223 if (sound_is_there && (audio.format!=AUDIO_S16SYS || audio.channels!=2))
00224 {
00225 uses_sdl_mixer=false;
00226 se_SoundExit();
00227
00228 audio.format=AUDIO_S16SYS;
00229 audio.channels=2;
00230 sound_is_there=(SDL_OpenAudio(&audio,NULL)>=0);
00231 con << tOutput("$sound_error_no16bit");
00232 }
00233 if (!sound_is_there)
00234 con << tOutput("$sound_error_initfailed");
00235 else
00236 {
00237
00238
00239 #ifdef DEBUG
00240 tOutput o;
00241 o.SetTemplateParameter(1,audio.freq);
00242 o.SetTemplateParameter(2,audio.samples);
00243 o << "$sound_inited";
00244 con << o;
00245 #endif
00246 }
00247 }
00248
00249
00250 if ( needSave )
00251 {
00252 st_SaveConfig();
00253 }
00254 #endif
00255 }
00256
00257 void se_SoundExit(){
00258 #ifndef DEDICATED
00259 se_SoundLock();
00260
00261 eWavData::UnloadAll();
00262 se_SoundPause(true);
00263
00264 se_SoundUnlock();
00265
00266 if (sound_is_there){
00267 #ifdef DEBUG
00268 con << tOutput("$sound_disabling");
00269 #endif
00270
00271
00272
00273
00274 #ifdef HAVE_LIBSDL_MIXER
00275 if ( music )
00276 {
00277 if( Mix_PlayingMusic() )
00278 {
00279 Mix_FadeOutMusic(100);
00280 SDL_Delay(100);
00281 }
00282 Mix_FreeMusic( music );
00283 music = NULL;
00284 }
00285
00286 se_SoundPause(true);
00287
00288 if ( uses_sdl_mixer )
00289 Mix_CloseAudio();
00290 else
00291 #endif
00292 SDL_CloseAudio();
00293
00294 #ifdef DEBUG
00295 con << tOutput("$sound_disabling_done");
00296 #endif
00297 }
00298 sound_is_there=false;
00299 #endif
00300 }
00301
00302 #ifndef DEDICATED
00303 static unsigned int locks;
00304 #endif
00305
00306 void se_SoundLock(){
00307 #ifndef DEDICATED
00308 if (!locks)
00309 SDL_LockAudio();
00310 locks++;
00311 #endif
00312 }
00313
00314 void se_SoundUnlock(){
00315 #ifndef DEDICATED
00316 locks--;
00317 if (!locks)
00318 SDL_UnlockAudio();
00319 #endif
00320 }
00321
00322 void se_SoundPause(bool p){
00323 #ifndef DEDICATED
00324 SDL_PauseAudio(p);
00325 #endif
00326 }
00327
00328
00329
00330 eWavData* eWavData::s_anchor = NULL;
00331
00332 eWavData::eWavData(const char * fileName,const char *alternative)
00333 :tListItem<eWavData>(s_anchor),data(NULL),len(0),freeData(false){
00334
00335 filename = fileName;
00336 filename_alt = alternative;
00337
00338 }
00339
00340 void eWavData::Load(){
00341
00342
00343 if (data)
00344 return;
00345
00346 #ifndef DEDICATED
00347
00348 static char const * errorName = "Sound Error";
00349
00350 freeData = false;
00351
00352 alt=false;
00353
00354 const tPath& path = tDirectories::Data();
00355
00356 SDL_AudioSpec *result=SDL_LoadWAV( path.GetReadPath( filename ) ,&spec,&data,&len);
00357 if (result!=&spec || !data){
00358 if (filename_alt.Len()>1){
00359 result=SDL_LoadWAV( path.GetReadPath( filename_alt ),&spec,&data,&len);
00360 if (result!=&spec || !data)
00361 {
00362 tOutput err;
00363 err.SetTemplateParameter(1, filename);
00364 err << "$sound_error_filenotfound";
00365 throw tGenericException(err, errorName);
00366 }
00367 else
00368 alt=true;
00369 }
00370 else{
00371 result=SDL_LoadWAV( path.GetReadPath( "sound/expl.wav" ) ,&spec,&data,&len);
00372 if (result!=&spec || !data)
00373 {
00374 tOutput err;
00375 err.SetTemplateParameter(1, "sound/expl.waw");
00376 err << "$sound_error_filenotfount";
00377 throw tGenericException(err, errorName);
00378 }
00379 else
00380 len=0;
00381 }
00382
00383
00384
00385 }
00386
00387 if (spec.format==AUDIO_S16SYS)
00388 samples=len>>1;
00389
00390
00391 else
00392 {
00393
00394 tOutput err;
00395 err.SetTemplateParameter(1, filename);
00396 err << "$sound_error_unsupported";
00397
00398
00399 SDL_AudioCVT cvt;
00400 if ( -1 == SDL_BuildAudioCVT( &cvt, spec.format, spec.channels, spec.freq, AUDIO_S16SYS, spec.channels, spec.freq ) )
00401 {
00402 throw tGenericException(err, errorName);
00403 }
00404
00405 cvt.buf=reinterpret_cast<Uint8 *>( malloc( len * cvt.len_mult ) );
00406 cvt.len=len;
00407 memcpy(cvt.buf, data, len);
00408 freeData = true;
00409
00410
00411 if ( -1 == SDL_ConvertAudio( &cvt ) )
00412 {
00413 throw tGenericException(err, errorName);
00414 }
00415
00416 SDL_FreeWAV( data );
00417 data = cvt.buf;
00418 spec.format = AUDIO_S16SYS;
00419 len = len * cvt.len_mult;
00420
00421 samples = len >> 1;
00422 }
00423
00424 samples/=spec.channels;
00425
00426 #ifdef DEBUG
00427 #ifdef LINUX
00428 con << "Sound file " << filename << " loaded: ";
00429 switch (spec.format){
00430 case AUDIO_S16SYS: con << "16 bit "; break;
00431 case AUDIO_U8: con << "8 bit "; break;
00432 default: con << "unknown "; break;
00433 }
00434 if (spec.channels==2)
00435 con << "stereo ";
00436 else
00437 con << "mono ";
00438
00439 con << "at " << spec.freq << " Hz,\n";
00440
00441 con << samples << " samples in " << len << " bytes.\n";
00442 #endif
00443 #endif
00444 #endif
00445 }
00446
00447 void eWavData::Unload(){
00448 #ifndef DEDICATED
00449
00450 if (data){
00451 se_SoundLock();
00452 if ( freeData )
00453 {
00454
00455 free(data);
00456
00457 }
00458
00459 else
00460
00461 {
00462
00463 SDL_FreeWAV(data);
00464
00465 }
00466
00467
00468
00469 data=NULL;
00470 len=0;
00471 se_SoundUnlock();
00472 }
00473 #endif
00474 }
00475
00476 void eWavData::UnloadAll(){
00477
00478 eWavData* wav = s_anchor;
00479 while ( wav )
00480 {
00481 wav->Unload();
00482 wav = wav->Next();
00483 }
00484
00485 }
00486
00487 eWavData::~eWavData(){
00488 #ifndef DEDICATED
00489 Unload();
00490 #endif
00491 }
00492
00493 bool eWavData::Mix(Uint8 *dest,Uint32 playlen,eAudioPos &pos,
00494 REAL Rvol,REAL Lvol,REAL Speed,bool loop){
00495 #ifndef DEDICATED
00496 if ( !data )
00497 {
00498 return false;
00499 }
00500
00501 playlen/=4;
00502
00503
00504
00505
00506 const REAL thresh = .25;
00507
00508 if ( Rvol > thresh )
00509 {
00510 Rvol = thresh;
00511 }
00512
00513 if ( Lvol > thresh )
00514 {
00515 Lvol = thresh;
00516 }
00517
00518 #define SPEED_FRACTION (1<<20)
00519
00520 #define VOL_SHIFT 16
00521 #define VOL_FRACTION (1<<VOL_SHIFT)
00522
00523 #define MAX_VAL ((1<<16)-1)
00524 #define MIN_VAL -(1<<16)
00525
00526
00527 if (Speed<0) Speed=0;
00528
00529
00530 Speed*=spec.freq;
00531 Speed/=audio.freq;
00532
00533 int speed=int(floor(Speed));
00534 int speed_fraction=int(SPEED_FRACTION*(Speed-speed));
00535
00536
00537 int rvol=int(Rvol*VOL_FRACTION);
00538 int lvol=int(Lvol*VOL_FRACTION);
00539
00540
00541 bool goon=true;
00542
00543 while (goon){
00544 if (spec.channels==2){
00545 if (spec.format==AUDIO_U8)
00546 while (playlen>0 && pos.pos<samples){
00547
00548
00549 int l=((short *)dest)[0];
00550 int r=((short *)dest)[1];
00551 r += (rvol*(data[(pos.pos<<1) ]-128)) >> (VOL_SHIFT-8);
00552 l += (lvol*(data[(pos.pos<<1)+1]-128)) >> (VOL_SHIFT-8);
00553 if (r>MAX_VAL) r=MAX_VAL;
00554 if (l>MAX_VAL) l=MAX_VAL;
00555 if (r<MIN_VAL) r=MIN_VAL;
00556 if (l<MIN_VAL) l=MIN_VAL;
00557
00558 ((short *)dest)[0]=l;
00559 ((short *)dest)[1]=r;
00560
00561 dest+=4;
00562
00563 pos.pos+=speed;
00564
00565 pos.fraction+=speed_fraction;
00566 while (pos.fraction>=SPEED_FRACTION){
00567 pos.fraction-=SPEED_FRACTION;
00568 pos.pos++;
00569 }
00570
00571 playlen--;
00572 }
00573 else{
00574 while (playlen>0 && pos.pos<samples){
00575 int l=((short *)dest)[0];
00576 int r=((short *)dest)[1];
00577 r += (rvol*(((short *)data)[(pos.pos<<1) ])) >> VOL_SHIFT;
00578 l += (lvol*(((short *)data)[(pos.pos<<1)+1])) >> VOL_SHIFT;
00579 if (r>MAX_VAL) r=MAX_VAL;
00580 if (l>MAX_VAL) l=MAX_VAL;
00581 if (r<MIN_VAL) r=MIN_VAL;
00582 if (l<MIN_VAL) l=MIN_VAL;
00583
00584 ((short *)dest)[0]=l;
00585 ((short *)dest)[1]=r;
00586
00587 dest+=4;
00588
00589 pos.pos+=speed;
00590
00591 pos.fraction+=speed_fraction;
00592 while (pos.fraction>=SPEED_FRACTION){
00593 pos.fraction-=SPEED_FRACTION;
00594 pos.pos++;
00595 }
00596 playlen--;
00597 }
00598 }
00599 }
00600 else{
00601 if (spec.format==AUDIO_U8){
00602 while (playlen>0 && pos.pos<samples){
00603
00604
00605 int l=((short *)dest)[0];
00606 int r=((short *)dest)[1];
00607 int d=data[pos.pos]-128;
00608 l += (lvol*d) >> (VOL_SHIFT-8);
00609 r += (rvol*d) >> (VOL_SHIFT-8);
00610 if (r>MAX_VAL) r=MAX_VAL;
00611 if (l>MAX_VAL) l=MAX_VAL;
00612 if (r<MIN_VAL) r=MIN_VAL;
00613 if (l<MIN_VAL) l=MIN_VAL;
00614
00615 ((short *)dest)[0]=l;
00616 ((short *)dest)[1]=r;
00617
00618 dest+=4;
00619
00620 pos.pos+=speed;
00621
00622 pos.fraction+=speed_fraction;
00623 while (pos.fraction>=SPEED_FRACTION){
00624 pos.fraction-=SPEED_FRACTION;
00625 pos.pos++;
00626 }
00627
00628 playlen--;
00629 }
00630 }
00631 else
00632 while (playlen>0 && pos.pos<samples){
00633 int l=((short *)dest)[0];
00634 int r=((short *)dest)[1];
00635 int d=((short *)data)[pos.pos];
00636 l += (lvol*d) >> VOL_SHIFT;
00637 r += (rvol*d) >> VOL_SHIFT;
00638 if (r>MAX_VAL) r=MAX_VAL;
00639 if (l>MAX_VAL) l=MAX_VAL;
00640 if (r<MIN_VAL) r=MIN_VAL;
00641 if (l<MIN_VAL) l=MIN_VAL;
00642
00643 ((short *)dest)[0]=l;
00644 ((short *)dest)[1]=r;
00645
00646 dest+=4;
00647
00648 pos.pos+=speed;
00649
00650 pos.fraction+=speed_fraction;
00651 while (pos.fraction>=SPEED_FRACTION){
00652 pos.fraction-=SPEED_FRACTION;
00653 pos.pos++;
00654 }
00655 playlen--;
00656 }
00657 }
00658
00659 if (loop && pos.pos>=samples)
00660 pos.pos-=samples;
00661 else
00662 goon=false;
00663 }
00664 #endif
00665 return (playlen>0);
00666
00667 }
00668
00669 void eWavData::Loop(){
00670 #ifndef DEDICATED
00671 Uint8 *buff2=tNEW(Uint8) [len];
00672
00673 if (buff2){
00674 memcpy(buff2,data,len);
00675 Uint32 samples;
00676
00677 if (spec.format==AUDIO_U8){
00678 samples=len;
00679 for(int i=samples-1;i>=0;i--){
00680 Uint32 j=i+((len>>2)<<1);
00681 if (j>=len) j-=len;
00682
00683 REAL a=fabs(100*(j/REAL(samples)-.5));
00684 if (a>1) a=1;
00685 REAL b=1-a;
00686
00687 data[i]=int(a*buff2[i]+b*buff2[j]);
00688 }
00689 }
00690 else if (spec.format==AUDIO_S16SYS){
00691 samples=len>>1;
00692 for(int i=samples-1;i>=0;i--){
00693
00694
00695
00696
00697
00698
00699
00700
00701 Uint32 j=i+((samples>>2)<<1);
00702 while (j>=samples) j-=samples;
00703
00704 REAL a=fabs(100*(j/REAL(samples)-.5));
00705 if (a>1) a=1;
00706 REAL b=1-a;
00707
00708
00709 ((short *)data)[i]=int(a*((short *)buff2)[i]+b*((short *)buff2)[j]);
00710 }
00711 }
00712 delete[] buff2;
00713 }
00714
00715 #endif
00716 }
00717
00718
00719
00720
00721 void eAudioPos::Reset(int randomize){
00722 #ifndef DEDICATED
00723 if (randomize){
00724 tRandomizer & randomizer = tRandomizer::GetInstance();
00725 fraction = randomizer.Get( SPEED_FRACTION );
00726
00727 pos=randomizer.Get( randomize );
00728
00729 }
00730 else
00731 fraction=pos=0;
00732 #endif
00733 }
00734
00735
00736
00737 eSoundPlayer::eSoundPlayer(eWavData &w,bool l)
00738 :id(-1),wav(&w),loop(l){
00739 if (l)
00740 wav->Load();
00741
00742 for(int i=MAX_VIEWERS-1;i>=0;i--)
00743 goon[i]=true;
00744 }
00745
00746 eSoundPlayer::~eSoundPlayer(){}
00747
00748 bool eSoundPlayer::Mix(Uint8 *dest,
00749 Uint32 len,
00750 int viewer,
00751 REAL rvol,
00752 REAL lvol,
00753 REAL speed){
00754
00755 if (goon[viewer]){
00756 if (rvol+lvol>loudness_thresh){
00757 real_sound_sources++;
00758 return goon[viewer]=!wav->Mix(dest,len,pos[viewer],rvol,lvol,speed,loop);
00759 }
00760 else
00761 return true;
00762 }
00763 else
00764 return false;
00765 }
00766
00767 void eSoundPlayer::Reset(int randomize){
00768 wav->Load();
00769
00770 for(int i=MAX_VIEWERS-1;i>=0;i--){
00771 pos[i].Reset(randomize);
00772 goon[i]=true;
00773 }
00774 }
00775
00776 void eSoundPlayer::End(){
00777 for(int i=MAX_VIEWERS-1;i>=0;i--){
00778 goon[i]=false;
00779 }
00780 }
00781
00782
00783 void eSoundPlayer::MakeGlobal(){
00784 wav->Load();
00785
00786 se_SoundLock();
00787 se_globalPlayers.Add(this,id);
00788 se_SoundUnlock();
00789 }
00790
00791
00792
00793
00794 uMenu Sound_menu("$sound_menu_text");
00795
00796 static uMenuItemInt sources_men
00797 (&Sound_menu,"$sound_menu_sources_text",
00798 "$sound_menu_sources_help",
00799 sound_sources,2,20,2);
00800
00801 static uMenuItemSelection<int> sq_men
00802 (&Sound_menu,"$sound_menu_quality_text",
00803 "$sound_menu_quality_help",
00804 sound_quality);
00805
00806
00807 static uSelectEntry<int> a(sq_men,
00808 "$sound_menu_quality_off_text",
00809 "$sound_menu_quality_off_help",
00810 SOUND_OFF);
00811 static uSelectEntry<int> b(sq_men,
00812 "$sound_menu_quality_low_text",
00813 "$sound_menu_quality_low_help",
00814 SOUND_LOW);
00815 static uSelectEntry<int> c(sq_men,
00816 "$sound_menu_quality_medium_text",
00817 "$sound_menu_quality_medium_help",
00818 SOUND_MED);
00819 static uSelectEntry<int> d(sq_men,
00820 "$sound_menu_quality_high_text",
00821 "$sound_menu_quality_high_help",
00822 SOUND_HIGH);
00823
00824 static uMenuItemSelection<int> bm_men
00825 (&Sound_menu,
00826 "$sound_menu_buffer_text",
00827 "$sound_menu_buffer_help",
00828 buffer_shift);
00829
00830 static uSelectEntry<int> ba(bm_men,
00831 "$sound_menu_buffer_vsmall_text",
00832 "$sound_menu_buffer_vsmall_help",
00833 -2);
00834
00835 static uSelectEntry<int> bb(bm_men,
00836 "$sound_menu_buffer_small_text",
00837 "$sound_menu_buffer_small_help",
00838 -1);
00839
00840 static uSelectEntry<int> bc(bm_men,
00841 "$sound_menu_buffer_med_text",
00842 "$sound_menu_buffer_med_help",
00843 0);
00844
00845 static uSelectEntry<int> bd(bm_men,
00846 "$sound_menu_buffer_high_text",
00847 "$sound_menu_buffer_high_help",
00848 1);
00849
00850 static uSelectEntry<int> be(bm_men,
00851 "$sound_menu_buffer_vhigh_text",
00852 "$sound_menu_buffer_vhigh_help",
00853 2);
00854
00855
00856 void se_SoundMenu(){
00857
00858
00859 int oldsettings=sound_quality;
00860 int oldshift=buffer_shift;
00861 Sound_menu.Enter();
00862 if (oldsettings!=sound_quality || oldshift!=buffer_shift){
00863 se_SoundExit();
00864 se_SoundInit();
00865 }
00866
00867
00868 }
00869