/* ============ Cbuf_ExecuteText ============ */ void Cbuf_ExecuteText (int exec_when, const char *text) { switch (exec_when) { case EXEC_NOW: Sys_EnterCriticalSection(CRIT_CBUF); if (text && strlen(text) > 0) { Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", text); Cmd_ExecuteString (text); } else { Cbuf_Execute(); Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", cmd_text.data); } Sys_LeaveCriticalSection(CRIT_CBUF); break; case EXEC_INSERT: Cbuf_InsertText (text); break; case EXEC_APPEND: Cbuf_AddText (text); break; default: Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); } }
/* ================== Sys_DestroyThread ================== */ void Sys_DestroyThread(xthreadInfo& info) { assert(info.threadHandle); SDL_WaitThread(info.threadHandle, NULL); info.name = NULL; info.threadHandle = NULL; info.threadId = 0; Sys_EnterCriticalSection(); for (int i = 0; i < thread_count; i++) { if (&info == thread[i]) { thread[i] = NULL; int j; for (j = i + 1; j < thread_count; j++) thread[j - 1] = thread[j]; thread[j - 1] = NULL; thread_count--; break; } } Sys_LeaveCriticalSection( ); }
/* =================== idSoundEmitterLocal::StopSound can pass SCHANNEL_ANY =================== */ void idSoundEmitterLocal::StopSound( const s_channelType channel ) { int i; if( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "StopSound(%i,%i)\n", index, channel ); } if( soundWorld && soundWorld->writeDemo ) { soundWorld->writeDemo->WriteInt( DS_SOUND ); soundWorld->writeDemo->WriteInt( SCMD_STOP ); soundWorld->writeDemo->WriteInt( index ); soundWorld->writeDemo->WriteInt( channel ); } Sys_EnterCriticalSection(); for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { idSoundChannel *chan = &channels[i]; if( !chan->triggerState ) { continue; } if( channel != SCHANNEL_ANY && chan->triggerChannel != channel ) { continue; } // stop it chan->Stop(); // free hardware resources chan->ALStop(); // if this was an onDemand sound, purge the sample now if( chan->leadinSample->onDemand ) { chan->leadinSample->PurgeSoundSample(); } chan->leadinSample = NULL; chan->soundShader = NULL; } Sys_LeaveCriticalSection(); }
void Com_PrintLogfile( const char *msg ) { Sys_EnterCriticalSection(5); if ( com_logfile && com_logfile->integer ) { // TTimo: only open the qconsole.log if the filesystem is in an initialized state // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on) if ( !logfile && FS_Initialized()) { struct tm *newtime; time_t aclock; time( &aclock ); newtime = localtime( &aclock ); logfile = FS_FOpenFileWrite( "qconsole.log" ); if ( com_logfile->integer > 1 && logfile ) { // force it to not buffer so we get valid // data even if we are crashing FS_ForceFlush(logfile); } if ( logfile ) FS_Write(va("\nLogfile opened on %s\n", asctime( newtime )), strlen(va("\nLogfile opened on %s\n", asctime( newtime ))), logfile); } if ( logfile && FS_Initialized()) { FS_Write(msg, strlen(msg), logfile); } } Sys_LeaveCriticalSection(5); }
/* ================== Sys_GetThreadName find the name of the calling thread ================== */ const char* Sys_GetThreadName( int *index ) { Sys_EnterCriticalSection( ); pthread_t thread = pthread_self(); for( int i = 0 ; i < g_thread_count ; i++ ) { if ( thread == (pthread_t)g_threads[ i ]->threadHandle ) { if ( index ) { *index = i; } Sys_LeaveCriticalSection( ); return g_threads[ i ]->name; } } if ( index ) { *index = -1; } Sys_LeaveCriticalSection( ); return "main"; }
/* ================= Sys_Print ================= */ void Sys_Print( const char *msg ) { Sys_EnterCriticalSection(CRIT_CONSOLE); // CON_LogWrite( msg ); CON_Print( msg ); Sys_LeaveCriticalSection(CRIT_CONSOLE); }
/* ================== Sys_TriggerEvent ================== */ void Sys_TriggerEvent( int index ) { assert( index >= 0 && index < MAX_TRIGGER_EVENTS ); Sys_EnterCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 ); if ( waiting[ index ] ) { pthread_cond_signal( &event_cond[ index ] ); } else { // emulate windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going signaled[ index ] = true; } Sys_LeaveCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 ); }
/* ================== Sys_CreateThread ================== */ void Sys_CreateThread(xthread_t function, void *parms, xthreadInfo& info, const char *name) { Sys_EnterCriticalSection(); SDL_Thread *t = SDL_CreateThread(function, parms); if (!t) { common->Error("ERROR: SDL_thread for '%s' failed\n", name); Sys_LeaveCriticalSection(); return; } info.name = name; info.threadHandle = t; info.threadId = SDL_GetThreadID(t); if (thread_count < MAX_THREADS) thread[thread_count++] = &info; else common->DPrintf("WARNING: MAX_THREADS reached\n"); Sys_LeaveCriticalSection(); }
/* ==================== idWaveFile::CloseOGG ==================== */ int idWaveFile::CloseOGG( void ) { OggVorbis_File *ov = (OggVorbis_File *) ogg; if ( ov != NULL ) { Sys_EnterCriticalSection( CRITICAL_SECTION_ONE ); ov_clear( ov ); delete ov; Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE ); fileSystem->CloseFile( mhmmio ); mhmmio = NULL; ogg = NULL; return 0; } return -1; }
/* ================== Sys_WaitForEvent ================== */ void Sys_WaitForEvent( int index ) { assert( index >= 0 && index < MAX_TRIGGER_EVENTS ); Sys_EnterCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 ); assert( !waiting[ index ] ); // WaitForEvent from multiple threads? that wouldn't be good if ( signaled[ index ] ) { // emulate windows behaviour: signal has been raised already. clear and keep going signaled[ index ] = false; } else { waiting[ index ] = true; pthread_cond_wait( &event_cond[ index ], &global_lock[ MAX_LOCAL_CRITICAL_SECTIONS - 1 ] ); waiting[ index ] = false; } Sys_LeaveCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 ); }
/* ========== idAudioHardwareOSX::DeviceIOProc ========== */ OSStatus idAudioHardwareOSX::DeviceIOProc( AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData ) { // setup similar to async thread Sys_EnterCriticalSection(); soundSystem->AsyncMix( ( int )inOutputTime->mSampleTime, ( float * )outOutputData->mBuffers[ 0 ].mData ); Sys_LeaveCriticalSection(); // doom mixes sound to -32768.0f 32768.0f range, scale down to -1.0f 1.0f SIMDProcessor->Mul( ( Float32 * )outOutputData->mBuffers[ 0 ].mData, 1.0f / 32768.0f, ( Float32 * )outOutputData->mBuffers[ 0 ].mData, MIXBUFFER_SAMPLES * 2 ); return kAudioHardwareNoError; }
/* ============ Cbuf_AddText Adds command text at the end of the buffer, does NOT add a final \n ============ */ void Cbuf_AddText( const char *text ) { int len; byte* new_buf; len = strlen (text) +1; Sys_EnterCriticalSection(CRIT_CBUF); if ( len + cmd_text.cursize > cmd_text.maxsize ) { if(cmd_text.data == cmd_text_buf) { new_buf = realloc(NULL, len + cmd_text.cursize); if(new_buf != NULL) { Com_Memcpy(new_buf, cmd_text_buf, len + cmd_text.cursize); } }else{ new_buf = realloc(cmd_text.data, len + cmd_text.cursize); } if(new_buf == NULL) { Com_PrintError( "Cbuf_AddText overflowed ; realloc failed\n" ); Sys_LeaveCriticalSection(CRIT_CBUF); return; } cmd_text.data = new_buf; cmd_text.maxsize = len + cmd_text.cursize; } Com_Memcpy(&cmd_text.data[cmd_text.cursize], text, len -1); cmd_text.cursize += len -1; Sys_LeaveCriticalSection(CRIT_CBUF); }
/* ================== Sys_TriggerEvent ================== */ void Sys_TriggerEvent(int index) { assert(index >= 0 && index < MAX_TRIGGER_EVENTS); Sys_EnterCriticalSection(CRITICAL_SECTION_SYS); if (waiting[index]) { if (SDL_CondSignal(cond[index]) != 0) common->Error("ERROR: SDL_CondSignal failed\n"); } else { // emulate windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going signaled[index] = true; } Sys_LeaveCriticalSection(CRITICAL_SECTION_SYS); }
/* ================== Sys_WaitForEvent ================== */ void Sys_WaitForEvent(int index) { assert(index >= 0 && index < MAX_TRIGGER_EVENTS); Sys_EnterCriticalSection(CRITICAL_SECTION_SYS); assert(!waiting[index]); // WaitForEvent from multiple threads? that wouldn't be good if (signaled[index]) { // emulate windows behaviour: signal has been raised already. clear and keep going signaled[index] = false; } else { waiting[index] = true; if (SDL_CondWait(cond[index], mutex[CRITICAL_SECTION_SYS]) != 0) common->Error("ERROR: SDL_CondWait failed\n"); waiting[index] = false; } Sys_LeaveCriticalSection(CRITICAL_SECTION_SYS); }
/* ==================== idSampleDecoderLocal::ClearDecoder ==================== */ void idSampleDecoderLocal::ClearDecoder( void ) { Sys_EnterCriticalSection( CRITICAL_SECTION_ONE ); switch( lastFormat ) { case WAVE_FORMAT_TAG_PCM: { break; } case WAVE_FORMAT_TAG_OGG: { ov_clear( &ogg ); memset( &ogg, 0, sizeof( ogg ) ); break; } } Clear(); Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE ); }
void QDECL SV_EnterLeaveLog( const char *fmt, ... ) { Sys_EnterCriticalSection(5); va_list argptr; char msg[MAXPRINTMSG]; char inputmsg[MAXPRINTMSG]; struct tm *newtime; char* ltime; time_t realtime; // logfile if ( com_logfile && com_logfile->integer ) { // TTimo: only open the qconsole.log if the filesystem is in an initialized state // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on) va_start (argptr,fmt); Q_vsnprintf (inputmsg, sizeof(inputmsg), fmt, argptr); va_end (argptr); Com_UpdateRealtime(); realtime = Com_GetRealtime(); newtime = localtime( &realtime ); ltime = asctime( newtime ); ltime[strlen(ltime)-1] = 0; if ( !enterleavelogfile && FS_Initialized()) { enterleavelogfile = FS_FOpenFileAppend( "enterleave.log" ); // force it to not buffer so we get valid if ( enterleavelogfile ){ FS_ForceFlush(enterleavelogfile); FS_Write(va("\nLogfile opened on %s\n\n", ltime), strlen(va("\nLogfile opened on %s\n\n", ltime)), enterleavelogfile); } } if ( enterleavelogfile && FS_Initialized()) { Com_sprintf(msg, sizeof(msg), "%s: %s\n", ltime, inputmsg); FS_Write(msg, strlen(msg), enterleavelogfile); } } Sys_LeaveCriticalSection(5); }
/* ================== Sys_CreateThread ================== */ void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo& info, const char *name, xthreadInfo **threads, int *thread_count ) { Sys_EnterCriticalSection( ); pthread_attr_t attr; pthread_attr_init( &attr ); if ( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) != 0 ) { common->Error( "ERROR: pthread_attr_setdetachstate %s failed\n", name ); } if ( pthread_create( ( pthread_t* )&info.threadHandle, &attr, ( pthread_function_t )function, parms ) != 0 ) { common->Error( "ERROR: pthread_create %s failed\n", name ); } pthread_attr_destroy( &attr ); info.name = name; if ( *thread_count < MAX_THREADS ) { threads[ ( *thread_count )++ ] = &info; } else { common->DPrintf( "WARNING: MAX_THREADS reached\n" ); } Sys_LeaveCriticalSection( ); }
void QDECL Com_PrintAdministrativeLog( const char *msg ) { Sys_EnterCriticalSection(5); struct tm *newtime; char* ltime; time_t realtime; // logfile if ( com_logfile && com_logfile->integer ) { // TTimo: only open the qconsole.log if the filesystem is in an initialized state // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on) if ( !adminlogfile && FS_Initialized()) { Com_UpdateRealtime(); realtime = Com_GetRealtime(); newtime = localtime( &realtime ); ltime = asctime( newtime ); ltime[strlen(ltime)-1] = 0; adminlogfile = FS_FOpenFileAppend( "adminactions.log" ); // force it to not buffer so we get valid if ( adminlogfile ){ FS_ForceFlush(adminlogfile); FS_Write(va("\nLogfile opened on %s\n\n", ltime), strlen(va("\nLogfile opened on %s\n\n", ltime)), adminlogfile); } } if ( adminlogfile && FS_Initialized()) { FS_Write(msg, strlen(msg), adminlogfile); } } Sys_LeaveCriticalSection(5); }
/* ==================== idSampleDecoderLocal::Decode ==================== */ void idSampleDecoderLocal::Decode( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest ) { int readSamples44k; if ( sample->objectInfo.wFormatTag != lastFormat || sample != lastSample ) { ClearDecoder(); } lastDecodeTime = soundSystemLocal.CurrentSoundTime; if ( failed ) { memset( dest, 0, sampleCount44k * sizeof( dest[0] ) ); return; } // samples can be decoded both from the sound thread and the main thread for shakes Sys_EnterCriticalSection( CRITICAL_SECTION_ONE ); switch( sample->objectInfo.wFormatTag ) { case WAVE_FORMAT_TAG_PCM: { readSamples44k = DecodePCM( sample, sampleOffset44k, sampleCount44k, dest ); break; } case WAVE_FORMAT_TAG_OGG: { readSamples44k = DecodeOGG( sample, sampleOffset44k, sampleCount44k, dest ); break; } default: { readSamples44k = 0; break; } } Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE ); if ( readSamples44k < sampleCount44k ) { memset( dest + readSamples44k, 0, ( sampleCount44k - readSamples44k ) * sizeof( dest[0] ) ); } }
/* ===================== idSoundEmitterLocal::StartSound returns the length of the started sound in msec ===================== */ int idSoundEmitterLocal::StartSound( const idSoundShader *shader, const s_channelType channel, float diversity, int soundShaderFlags, bool allowSlow ) { int i; if ( !shader ) { return 0; } if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "StartSound %ims (%i,%i,%s) = ", soundWorld->gameMsec, index, (int)channel, shader->GetName() ); } if ( soundWorld && soundWorld->writeDemo ) { soundWorld->writeDemo->WriteInt( DS_SOUND ); soundWorld->writeDemo->WriteInt( SCMD_START ); soundWorld->writeDemo->WriteInt( index ); soundWorld->writeDemo->WriteHashString( shader->GetName() ); soundWorld->writeDemo->WriteInt( channel ); soundWorld->writeDemo->WriteFloat( diversity ); soundWorld->writeDemo->WriteInt( soundShaderFlags ); } // build the channel parameters by taking the shader parms and optionally overriding soundShaderParms_t chanParms; chanParms = shader->parms; OverrideParms( &chanParms, &this->parms, &chanParms ); chanParms.soundShaderFlags |= soundShaderFlags; if ( chanParms.shakes > 0.0f ) { shader->CheckShakesAndOgg(); } // this is the sample time it will be first mixed int start44kHz; if ( soundWorld->fpa[0] ) { // if we are recording an AVI demo, don't use hardware time start44kHz = soundWorld->lastAVI44kHz + MIXBUFFER_SAMPLES; } else { start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES; } // // pick which sound to play from the shader // if ( !shader->numEntries ) { if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "no samples in sound shader\n" ); } return 0; // no sounds } int choice; // pick a sound from the list based on the passed diversity choice = (int)(diversity * shader->numEntries); if ( choice < 0 || choice >= shader->numEntries ) { choice = 0; } // bump the choice if the exact sound was just played and we are NO_DUPS if ( chanParms.soundShaderFlags & SSF_NO_DUPS ) { idSoundSample *sample; if ( shader->leadins[ choice ] ) { sample = shader->leadins[ choice ]; } else { sample = shader->entries[ choice ]; } for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { idSoundChannel *chan = &channels[i]; if ( chan->leadinSample == sample ) { choice = ( choice + 1 ) % shader->numEntries; break; } } } // PLAY_ONCE sounds will never be restarted while they are running if ( chanParms.soundShaderFlags & SSF_PLAY_ONCE ) { for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { idSoundChannel *chan = &channels[i]; if ( chan->triggerState && chan->soundShader == shader ) { if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "PLAY_ONCE not restarting\n" ); } return 0; } } } // never play the same sound twice with the same starting time, even // if they are on different channels for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { idSoundChannel *chan = &channels[i]; if ( chan->triggerState && chan->soundShader == shader && chan->trigger44kHzTime == start44kHz ) { if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "already started this frame\n" ); } return 0; } } Sys_EnterCriticalSection(); // kill any sound that is currently playing on this channel if ( channel != SCHANNEL_ANY ) { for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { idSoundChannel *chan = &channels[i]; if ( chan->triggerState && chan->soundShader && chan->triggerChannel == channel ) { if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "(override %s)", chan->soundShader->base->GetName() ); } chan->Stop(); // if this was an onDemand sound, purge the sample now if ( chan->leadinSample->onDemand ) { chan->ALStop(); chan->leadinSample->PurgeSoundSample(); } break; } } } // find a free channel to play the sound on idSoundChannel *chan; for( i = 0; i < SOUND_MAX_CHANNELS; i++ ) { chan = &channels[i]; if ( !chan->triggerState ) { break; } } if ( i == SOUND_MAX_CHANNELS ) { // we couldn't find a channel for it Sys_LeaveCriticalSection(); if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "no channels available\n" ); } return 0; } chan = &channels[i]; if ( shader->leadins[ choice ] ) { chan->leadinSample = shader->leadins[ choice ]; } else { chan->leadinSample = shader->entries[ choice ]; } // if the sample is onDemand (voice mails, etc), load it now if ( chan->leadinSample->purged ) { int start = Sys_Milliseconds(); chan->leadinSample->Load(); int end = Sys_Milliseconds(); session->TimeHitch( end - start ); // recalculate start44kHz, because loading may have taken a fair amount of time if ( !soundWorld->fpa[0] ) { start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES; } } if ( idSoundSystemLocal::s_showStartSound.GetInteger() ) { common->Printf( "'%s'\n", chan->leadinSample->name.c_str() ); } if ( idSoundSystemLocal::s_skipHelltimeFX.GetBool() ) { chan->disallowSlow = true; } else { chan->disallowSlow = !allowSlow; } ResetSlowChannel( chan ); // the sound will start mixing in the next async mix block chan->triggered = true; chan->openalStreamingOffset = 0; chan->trigger44kHzTime = start44kHz; chan->parms = chanParms; chan->triggerGame44kHzTime = soundWorld->game44kHz; chan->soundShader = shader; chan->triggerChannel = channel; chan->Start(); // we need to start updating the def and mixing it in playing = true; // spatialize it immediately, so it will start the next mix block // even if that happens before the next PlaceOrigin() Spatialize( soundWorld->listenerPos, soundWorld->listenerArea, soundWorld->rw ); // return length of sound in milliseconds int length = chan->leadinSample->LengthIn44kHzSamples(); if ( chan->leadinSample->objectInfo.nChannels == 2 ) { length /= 2; // stereo samples } // adjust the start time based on diversity for looping sounds, so they don't all start // at the same point if ( chan->parms.soundShaderFlags & SSF_LOOPING && !chan->leadinSample->LengthIn44kHzSamples() ) { chan->trigger44kHzTime -= diversity * length; chan->trigger44kHzTime &= ~7; // so we don't have to worry about the 22kHz and 11kHz expansions // starting in fractional samples chan->triggerGame44kHzTime -= diversity * length; chan->triggerGame44kHzTime &= ~7; } length *= 1000 / (float)PRIMARYFREQ; Sys_LeaveCriticalSection(); return length; }