From d37536edf4660f3c46e4876b6d72e9a200549ffe Mon Sep 17 00:00:00 2001 From: tma Date: Wed, 5 Sep 2007 18:17:46 +0000 Subject: * Merge unified-sdl to trunk * Bump Q3_VERSION to 1.35 git-svn-id: svn://svn.icculus.org/quake3/trunk@1161 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/client/cl_cgame.c | 32 +++++++++-- code/client/cl_cin.c | 12 +--- code/client/cl_console.c | 7 +-- code/client/cl_curl.c | 44 +++------------ code/client/cl_keys.c | 29 +++++----- code/client/cl_main.c | 140 +++++++++++++++++++++++++++++++++++++---------- code/client/cl_scrn.c | 7 +-- code/client/cl_ui.c | 2 + code/client/client.h | 7 ++- code/client/qal.c | 43 +++------------ code/client/snd_dma.c | 6 +- code/client/snd_main.c | 7 +++ code/client/snd_mix.c | 1 - 13 files changed, 188 insertions(+), 149 deletions(-) (limited to 'code/client') diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 810f738..b53e304 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -697,7 +697,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { return re.inPVS( VMA(1), VMA(2) ); default: - assert(0); // bk010102 + assert(0); Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] ); } return 0; @@ -906,8 +906,6 @@ void CL_FirstSnapshot( void ) { Cbuf_AddText( cl_activeAction->string ); Cvar_Set( "activeAction", "" ); } - - Sys_BeginProfiling(); } /* @@ -1010,9 +1008,35 @@ void CL_SetCGameTime( void ) { // while a normal demo may have different time samples // each time it is played back if ( cl_timedemo->integer ) { + int now = Sys_Milliseconds( ); + int frameDuration; + if (!clc.timeDemoStart) { - clc.timeDemoStart = Sys_Milliseconds(); + clc.timeDemoStart = clc.timeDemoLastFrame = now; + clc.timeDemoMinDuration = INT_MAX; + clc.timeDemoMaxDuration = 0; + } + + frameDuration = now - clc.timeDemoLastFrame; + clc.timeDemoLastFrame = now; + + // Ignore the first measurement as it'll always be 0 + if( clc.timeDemoFrames > 0 ) + { + if( frameDuration > clc.timeDemoMaxDuration ) + clc.timeDemoMaxDuration = frameDuration; + + if( frameDuration < clc.timeDemoMinDuration ) + clc.timeDemoMinDuration = frameDuration; + + // 255 ms = about 4fps + if( frameDuration > UCHAR_MAX ) + frameDuration = UCHAR_MAX; + + clc.timeDemoDurations[ ( clc.timeDemoFrames - 1 ) % + MAX_TIMEDEMO_DURATIONS ] = frameDuration; } + clc.timeDemoFrames++; cl.serverTime = clc.timeDemoBaseTime + clc.timeDemoFrames * 50; } diff --git a/code/client/cl_cin.c b/code/client/cl_cin.c index 7d19ff3..0e44eee 100644 --- a/code/client/cl_cin.c +++ b/code/client/cl_cin.c @@ -1072,12 +1072,10 @@ static void RoQReset( void ) { if (currentHandle < 0) return; - Sys_EndStreamedFile(cinTable[currentHandle].iFile); FS_FCloseFile( cinTable[currentHandle].iFile ); FS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue); // let the background thread start reading ahead - Sys_BeginStreamedFile( cinTable[currentHandle].iFile, 0x10000 ); - Sys_StreamedRead (cin.file, 16, 1, cinTable[currentHandle].iFile); + FS_Read (cin.file, 16, cinTable[currentHandle].iFile); RoQ_init(); cinTable[currentHandle].status = FMV_LOOPED; } @@ -1098,7 +1096,7 @@ static void RoQInterrupt(void) if (currentHandle < 0) return; - Sys_StreamedRead( cin.file, cinTable[currentHandle].RoQFrameSize+8, 1, cinTable[currentHandle].iFile ); + FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile ); if ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) { if (cinTable[currentHandle].holdAtEnd==qfalse) { if (cinTable[currentHandle].looping) { @@ -1214,7 +1212,7 @@ redump: // one more frame hits the dust // // assert(cinTable[currentHandle].RoQFrameSize <= 65536); -// r = Sys_StreamedRead( cin.file, cinTable[currentHandle].RoQFrameSize+8, 1, cinTable[currentHandle].iFile ); +// r = FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile ); cinTable[currentHandle].RoQPlayed += cinTable[currentHandle].RoQFrameSize+8; } @@ -1272,7 +1270,6 @@ static void RoQShutdown( void ) { cinTable[currentHandle].status = FMV_IDLE; if (cinTable[currentHandle].iFile) { - Sys_EndStreamedFile( cinTable[currentHandle].iFile ); FS_FCloseFile( cinTable[currentHandle].iFile ); cinTable[currentHandle].iFile = 0; } @@ -1332,7 +1329,6 @@ Fetch and decompress the pending frame e_status CIN_RunCinematic (int handle) { - // bk001204 - init int start = 0; int thisTime = 0; @@ -1472,8 +1468,6 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi { RoQ_init(); // FS_Read (cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile); - // let the background thread start reading ahead - Sys_BeginStreamedFile( cinTable[currentHandle].iFile, 0x10000 ); cinTable[currentHandle].status = FMV_PLAY; Com_DPrintf("trFMV::play(), playing %s\n", arg); diff --git a/code/client/cl_console.c b/code/client/cl_console.c index b8f5f90..9db8c4d 100644 --- a/code/client/cl_console.c +++ b/code/client/cl_console.c @@ -71,9 +71,8 @@ Con_ToggleConsole_f ================ */ void Con_ToggleConsole_f (void) { - // closing a full screen console restarts the demo loop + // Can't toggle the console when it's the only thing available if ( cls.state == CA_DISCONNECTED && cls.keyCatchers == KEYCATCH_CONSOLE ) { - CL_StartDemoLoop(); return; } @@ -619,13 +618,13 @@ void Con_DrawSolidConsole( float frac ) { re.SetColor( g_color_table[ColorIndex(COLOR_RED)] ); - i = strlen( SVN_VERSION ); + i = strlen( Q3_VERSION ); for (x=0 ; x -#define OBJTYPE HMODULE -#define OBJLOAD(x) LoadLibrary(x) -#define SYMLOAD(x,y) GetProcAddress(x,y) -#define OBJFREE(x) FreeLibrary(x) - -#elif defined __linux__ || defined __FreeBSD__ || defined MACOS_X || defined __sun -#include -#define OBJTYPE void * -#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL) -#define SYMLOAD(x,y) dlsym(x,y) -#define OBJFREE(x) dlclose(x) -#else - -#error "Your platform has no lib loading code or it is disabled" -#endif - -#if defined __linux__ || defined __FreeBSD__ || defined MACOS_X -#include -#include -#endif +#include "../sys/sys_loadlib.h" char* (*qcurl_version)(void); @@ -85,7 +55,7 @@ CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle, int *msgs_in_queue); const char *(*qcurl_multi_strerror)(CURLMcode); -static OBJTYPE cURLLib = NULL; +static void *cURLLib = NULL; /* ================= @@ -96,7 +66,7 @@ static void *GPA(char *str) { void *rv; - rv = SYMLOAD(cURLLib, str); + rv = Sys_LoadFunction(cURLLib, str); if(!rv) { Com_Printf("Can't load symbol %s\n", str); @@ -124,17 +94,17 @@ qboolean CL_cURL_Init() Com_Printf("Loading \"%s\"...", cl_cURLLib->string); - if( (cURLLib = OBJLOAD(cl_cURLLib->string)) == 0 ) + if( (cURLLib = Sys_LoadLibrary(cl_cURLLib->string)) == 0 ) { #ifdef _WIN32 return qfalse; #else char fn[1024]; - getcwd(fn, sizeof(fn)); + Q_strncpyz( fn, Sys_Cwd( ), sizeof( fn ) ); strncat(fn, "/", sizeof(fn)-strlen(fn)-1); strncat(fn, cl_cURLLib->string, sizeof(fn)-strlen(fn)-1); - if( (cURLLib = OBJLOAD(fn)) == 0 ) + if( (cURLLib = Sys_LoadLibrary(fn)) == 0 ) { return qfalse; } @@ -189,7 +159,7 @@ void CL_cURL_Shutdown( void ) #if USE_CURL_DLOPEN if(cURLLib) { - OBJFREE(cURLLib); + Sys_UnloadLibrary(cURLLib); cURLLib = NULL; } qcurl_easy_init = NULL; diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index 1c254db..11354d2 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -1147,7 +1147,6 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { } } -#ifndef _WIN32 if (key == K_ENTER) { if (down) @@ -1157,14 +1156,10 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { Key_ClearStates(); Cvar_SetValue( "r_fullscreen", !Cvar_VariableIntegerValue( "r_fullscreen" ) ); -#if !USE_SDL_VIDEO // This is handled in sdl_glimp.c/GLimp_EndFrame - Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n"); -#endif return; } } } -#endif // console key is hardcoded, so the user can never unbind it if (key == '`' || key == '~' || @@ -1207,7 +1202,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { if ( cls.state == CA_ACTIVE && !clc.demoplaying ) { VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME ); } - else { + else if ( cls.state != CA_DISCONNECTED ) { CL_Disconnect_f(); S_StopAllSounds(); VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN ); @@ -1222,19 +1217,21 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { // // key up events only perform actions if the game key binding is // a button command (leading + sign). These will be processed even in - // console mode and menu mode, to keep the character from continuing + // console mode and menu mode, to keep the character from continuing // an action started before a mode switch. // - if (!down) { - kb = keys[key].binding; + if (!down ) { + if ( cls.state != CA_DISCONNECTED ) { + kb = keys[key].binding; - CL_AddKeyUpCommands( key, kb, time ); + CL_AddKeyUpCommands( key, kb, time ); - if ( cls.keyCatchers & KEYCATCH_UI && uivm ) { - VM_Call( uivm, UI_KEY_EVENT, key, down ); - } else if ( cls.keyCatchers & KEYCATCH_CGAME && cgvm ) { - VM_Call( cgvm, CG_KEY_EVENT, key, down ); - } + if ( cls.keyCatchers & KEYCATCH_UI && uivm ) { + VM_Call( uivm, UI_KEY_EVENT, key, down ); + } else if ( cls.keyCatchers & KEYCATCH_CGAME && cgvm ) { + VM_Call( cgvm, CG_KEY_EVENT, key, down ); + } + } return; } @@ -1263,7 +1260,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { Com_Printf ("%s is unbound, use controls menu to set.\n" , Key_KeynumToString( key ) ); } - } else if (kb[0] == '+') { + } else if (kb[0] == '+') { int i; char button[1024], *buttonPtr; buttonPtr = button; diff --git a/code/client/cl_main.c b/code/client/cl_main.c index c235a21..fb830ef 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -43,6 +43,7 @@ cvar_t *cl_freezeDemo; cvar_t *cl_shownet; cvar_t *cl_showSend; cvar_t *cl_timedemo; +cvar_t *cl_timedemoLog; cvar_t *cl_autoRecordDemo; cvar_t *cl_aviFrameRate; cvar_t *cl_aviMotionJpeg; @@ -391,19 +392,96 @@ CLIENT SIDE DEMO PLAYBACK ======================================================================= */ +/* +================= +CL_DemoFrameDurationSDev +================= +*/ +static float CL_DemoFrameDurationSDev( void ) +{ + int i; + int numFrames; + float mean = 0.0f; + float variance = 0.0f; + + if( ( clc.timeDemoFrames - 1 ) > MAX_TIMEDEMO_DURATIONS ) + numFrames = MAX_TIMEDEMO_DURATIONS; + else + numFrames = clc.timeDemoFrames - 1; + + for( i = 0; i < numFrames; i++ ) + mean += clc.timeDemoDurations[ i ]; + mean /= numFrames; + + for( i = 0; i < numFrames; i++ ) + { + float x = clc.timeDemoDurations[ i ]; + + variance += ( ( x - mean ) * ( x - mean ) ); + } + variance /= numFrames; + + return sqrt( variance ); +} + /* ================= CL_DemoCompleted ================= */ -void CL_DemoCompleted( void ) { - if (cl_timedemo && cl_timedemo->integer) { +void CL_DemoCompleted( void ) +{ + char buffer[ MAX_STRING_CHARS ]; + + if( cl_timedemo && cl_timedemo->integer ) + { int time; time = Sys_Milliseconds() - clc.timeDemoStart; - if ( time > 0 ) { - Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", clc.timeDemoFrames, - time/1000.0, clc.timeDemoFrames*1000.0 / time); + if( time > 0 ) + { + // Millisecond times are frame durations: + // minimum/average/maximum/std deviation + Com_sprintf( buffer, sizeof( buffer ), + "%i frames %3.1f seconds %3.1f fps %d.0/%.1f/%d.0/%.1f ms\n", + clc.timeDemoFrames, + time/1000.0, + clc.timeDemoFrames*1000.0 / time, + clc.timeDemoMinDuration, + time / (float)clc.timeDemoFrames, + clc.timeDemoMaxDuration, + CL_DemoFrameDurationSDev( ) ); + Com_Printf( buffer ); + + // Write a log of all the frame durations + if( cl_timedemoLog && strlen( cl_timedemoLog->string ) > 0 ) + { + int i; + int numFrames; + fileHandle_t f; + + if( ( clc.timeDemoFrames - 1 ) > MAX_TIMEDEMO_DURATIONS ) + numFrames = MAX_TIMEDEMO_DURATIONS; + else + numFrames = clc.timeDemoFrames - 1; + + f = FS_FOpenFileWrite( cl_timedemoLog->string ); + if( f ) + { + FS_Printf( f, "# %s", buffer ); + + for( i = 0; i < numFrames; i++ ) + FS_Printf( f, "%d\n", clc.timeDemoDurations[ i ] ); + + FS_FCloseFile( f ); + Com_Printf( "%s written\n", cl_timedemoLog->string ); + } + else + { + Com_Printf( "Couldn't open %s for writing\n", + cl_timedemoLog->string ); + } + } } } @@ -658,7 +736,7 @@ void CL_FlushMemory( void ) { Hunk_ClearToMark(); } - CL_StartHunkUsers(); + CL_StartHunkUsers( qfalse ); } /* @@ -671,6 +749,12 @@ memory on the hunk from cgame, ui, and renderer ===================== */ void CL_MapLoading( void ) { + if ( com_dedicated->integer ) { + cls.state = CA_DISCONNECTED; + cls.keyCatchers = KEYCATCH_CONSOLE; + return; + } + if ( !com_cl_running->integer ) { return; } @@ -830,7 +914,7 @@ void CL_ForwardCommandToServer( const char *string ) { } if ( clc.demoplaying || cls.state < CA_CONNECTED || cmd[0] == '+' ) { - Com_Printf ("Unknown command \"%s\"\n", cmd); + Com_Printf ("Unknown command \"%s" S_COLOR_WHITE "\"\n", cmd); return; } @@ -939,26 +1023,22 @@ void CL_RequestAuthorization( void ) { return; } - if ( Cvar_VariableValue( "fs_restrict" ) ) { - Q_strncpyz( nums, "demota", sizeof( nums ) ); - } else { - // only grab the alphanumeric values from the cdkey, to avoid any dashes or spaces - j = 0; - l = strlen( cl_cdkey ); - if ( l > 32 ) { - l = 32; - } - for ( i = 0 ; i < l ; i++ ) { - if ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' ) + // only grab the alphanumeric values from the cdkey, to avoid any dashes or spaces + j = 0; + l = strlen( cl_cdkey ); + if ( l > 32 ) { + l = 32; + } + for ( i = 0 ; i < l ; i++ ) { + if ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' ) || ( cl_cdkey[i] >= 'a' && cl_cdkey[i] <= 'z' ) || ( cl_cdkey[i] >= 'A' && cl_cdkey[i] <= 'Z' ) - ) { - nums[j] = cl_cdkey[i]; - j++; - } + ) { + nums[j] = cl_cdkey[i]; + j++; } - nums[j] = 0; } + nums[j] = 0; fs = Cvar_Get ("cl_anonymous", "0", CVAR_INIT|CVAR_SYSTEMINFO ); @@ -1276,7 +1356,7 @@ void CL_Vid_Restart_f( void ) { CL_InitRef(); // startup all the client stuff - CL_StartHunkUsers(); + CL_StartHunkUsers( qfalse ); // start the cgame if connected if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) { @@ -2316,7 +2396,7 @@ After the server has cleared the hunk, these will need to be restarted This is the only place that any of these functions are called from ============================ */ -void CL_StartHunkUsers( void ) { +void CL_StartHunkUsers( qboolean rendererOnly ) { if (!com_cl_running) { return; } @@ -2330,6 +2410,10 @@ void CL_StartHunkUsers( void ) { CL_InitRenderer(); } + if ( rendererOnly ) { + return; + } + if ( !cls.soundStarted ) { cls.soundStarted = qtrue; S_Init(); @@ -2590,6 +2674,7 @@ void CL_Init( void ) { cl_activeAction = Cvar_Get( "activeAction", "", CVAR_TEMP ); cl_timedemo = Cvar_Get ("timedemo", "0", 0); + cl_timedemoLog = Cvar_Get ("cl_timedemoLog", "", CVAR_ARCHIVE); cl_autoRecordDemo = Cvar_Get ("cl_autoRecordDemo", "0", CVAR_ARCHIVE); cl_aviFrameRate = Cvar_Get ("cl_aviFrameRate", "25", CVAR_ARCHIVE); cl_aviMotionJpeg = Cvar_Get ("cl_aviMotionJpeg", "1", CVAR_ARCHIVE); @@ -3203,11 +3288,6 @@ void CL_GlobalServers_f( void ) { for (i=3; i -#define OBJTYPE HMODULE -#define OBJLOAD(x) LoadLibrary(x) -#define SYMLOAD(x,y) GetProcAddress(x,y) -#define OBJFREE(x) FreeLibrary(x) - -#elif defined __linux__ || defined __FreeBSD__ || defined MACOS_X || defined __sun -#include -#define OBJTYPE void * -#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL) -#define SYMLOAD(x,y) dlsym(x,y) -#define OBJFREE(x) dlclose(x) -#else - -#error "Your platform has no lib loading code or it is disabled" -#endif - -#if defined __linux__ || defined __FreeBSD__ || defined MACOS_X -#include -#include -#endif +#include "../sys/sys_loadlib.h" LPALENABLE qalEnable; LPALDISABLE qalDisable; @@ -131,7 +102,7 @@ LPALCGETENUMVALUE qalcGetEnumValue; LPALCGETSTRING qalcGetString; LPALCGETINTEGERV qalcGetIntegerv; -static OBJTYPE OpenALLib = NULL; +static void *OpenALLib = NULL; static qboolean alinit_fail = qfalse; @@ -144,7 +115,7 @@ static void *GPA(char *str) { void *rv; - rv = SYMLOAD(OpenALLib, str); + rv = Sys_LoadFunction(OpenALLib, str); if(!rv) { Com_Printf( " Can't load symbol %s\n", str); @@ -169,17 +140,17 @@ qboolean QAL_Init(const char *libname) return qtrue; Com_Printf( "Loading \"%s\"...\n", libname); - if( (OpenALLib = OBJLOAD(libname)) == 0 ) + if( (OpenALLib = Sys_LoadLibrary(libname)) == 0 ) { #ifdef _WIN32 return qfalse; #else char fn[1024]; - getcwd(fn, sizeof(fn)); + Q_strncpyz( fn, Sys_Cwd( ), sizeof( fn ) ); strncat(fn, "/", sizeof(fn) - strlen(fn) - 1); strncat(fn, libname, sizeof(fn) - strlen(fn) - 1); - if( (OpenALLib = OBJLOAD(fn)) == 0 ) + if( (OpenALLib = Sys_LoadLibrary(fn)) == 0 ) { return qfalse; } @@ -278,7 +249,7 @@ void QAL_Shutdown( void ) { if(OpenALLib) { - OBJFREE(OpenALLib); + Sys_UnloadLibrary(OpenALLib); OpenALLib = NULL; } diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 0b6b56d..e1164a7 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -616,11 +616,7 @@ void S_Base_ClearSoundBuffer( void ) { SNDDMA_BeginPainting (); if (dma.buffer) - // TTimo: due to a particular bug workaround in linux sound code, - // have to optionally use a custom C implementation of Com_Memset - // not affecting win32, we have #define Snd_Memset Com_Memset - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371 - Snd_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8); + Com_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8); SNDDMA_Submit (); } diff --git a/code/client/snd_main.c b/code/client/snd_main.c index ea6bbeb..2526336 100644 --- a/code/client/snd_main.c +++ b/code/client/snd_main.c @@ -30,6 +30,7 @@ cvar_t *s_volume; cvar_t *s_musicVolume; cvar_t *s_doppler; cvar_t *s_backend; +cvar_t *s_muteWhenMinimized; static soundInterface_t si; @@ -219,6 +220,11 @@ S_Update */ void S_Update( void ) { + if( s_muteWhenMinimized->integer && com_minimized->integer ) { + S_StopAllSounds( ); + return; + } + if( si.Update ) { si.Update( ); } @@ -372,6 +378,7 @@ void S_Init( void ) s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE ); s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE ); s_backend = Cvar_Get( "s_backend", "", CVAR_ROM ); + s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE ); cv = Cvar_Get( "s_initsound", "1", 0 ); if( !cv->integer ) { diff --git a/code/client/snd_mix.c b/code/client/snd_mix.c index 47d5ba5..62e6841 100644 --- a/code/client/snd_mix.c +++ b/code/client/snd_mix.c @@ -30,7 +30,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; static int snd_vol; -// bk001119 - these not static, required by unix/snd_mixa.s int* snd_p; int snd_linear_count; short* snd_out; -- cgit v1.2.3