void DSound::SetPrimaryBufferMode() { #ifndef _XBOX DSBUFFERDESC format; memset( &format, 0, sizeof(format) ); format.dwSize = sizeof(format); format.dwFlags = DSBCAPS_PRIMARYBUFFER; format.dwBufferBytes = 0; format.lpwfxFormat = NULL; IDirectSoundBuffer *pBuffer; HRESULT hr = this->GetDS()->CreateSoundBuffer( &format, &pBuffer, NULL ); /* hr */ if( FAILED(hr) ) { LOG->Warn(hr_ssprintf(hr, "Couldn't create primary buffer")); return; } WAVEFORMATEX waveformat; memset( &waveformat, 0, sizeof(waveformat) ); waveformat.cbSize = 0; waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.wBitsPerSample = 16; waveformat.nChannels = 2; waveformat.nSamplesPerSec = 44100; waveformat.nBlockAlign = 4; waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign; // Set the primary buffer's format hr = IDirectSoundBuffer_SetFormat( pBuffer, &waveformat ); if( FAILED(hr) ) LOG->Warn( hr_ssprintf(hr, "SetFormat on primary buffer") ); DWORD got; hr = pBuffer->GetFormat( &waveformat, sizeof(waveformat), &got ); if( FAILED(hr) ) LOG->Warn( hr_ssprintf(hr, "GetFormat on primary buffer") ); else if( waveformat.nSamplesPerSec != 44100 ) LOG->Warn( "Primary buffer set to %i instead of 44100", waveformat.nSamplesPerSec ); /* MS docs: * * When there are no sounds playing, DirectSound stops the mixer engine and halts DMA * (direct memory access) activity. If your application has frequent short intervals of * silence, the overhead of starting and stopping the mixer each time a sound is played * may be worse than the DMA overhead if you kept the mixer active. Also, some sound * hardware or drivers may produce unwanted audible artifacts from frequent starting and * stopping of playback. If your application is playing audio almost continuously with only * short breaks of silence, you can force the mixer engine to remain active by calling the * IDirectSoundBuffer::Play method for the primary buffer. The mixer will continue to run * silently. * * However, I just added the above code and I don't want to change more until it's tested. */ // pBuffer->Play( 0, 0, DSBPLAY_LOOPING ); pBuffer->Release(); #endif }
CString DSound::Init() { HRESULT hr; if( FAILED( hr = DirectSoundCreate(NULL, &m_pDS, NULL) ) ) return hr_ssprintf( hr, "DirectSoundCreate" ); #ifndef _XBOX static bool bShownInfo = false; if( !bShownInfo ) { bShownInfo = true; DirectSoundEnumerate( EnumCallback, 0 ); DSCAPS Caps; Caps.dwSize = sizeof(Caps); HRESULT hr; if( FAILED(hr = m_pDS->GetCaps(&Caps)) ) { LOG->Warn( hr_ssprintf(hr, "m_pDS->GetCaps failed") ); } else { LOG->Info( "DirectSound sample rates: %i..%i %s", Caps.dwMinSecondarySampleRate, Caps.dwMaxSecondarySampleRate, (Caps.dwFlags & DSCAPS_CONTINUOUSRATE)?"(continuous)":"" ); } } /* Try to set primary mixing privileges */ hr = m_pDS->SetCooperativeLevel( GetDesktopWindow(), DSSCL_PRIORITY ); #endif SetPrimaryBufferMode(); return ""; }
void LowLevelWindow_Win32::BeginConcurrentRendering() { if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC_Background ) ) { LOG->Warn( hr_ssprintf(GetLastError(), "wglMakeCurrent") ); FAIL_M( hr_ssprintf(GetLastError(), "wglMakeCurrent") ); } }
InputHandler_DInput::InputHandler_DInput() { LOG->Trace( "InputHandler_DInput::InputHandler_DInput()" ); CheckForDirectInputDebugMode(); shutdown = false; g_NumJoysticks = 0; AppInstance inst; HRESULT hr = DirectInputCreate(inst.Get(), DIRECTINPUT_VERSION, &dinput, NULL); if ( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: DirectInputCreate") ); LOG->Trace( "InputHandler_DInput: IDirectInput::EnumDevices(DIDEVTYPE_KEYBOARD)" ); hr = dinput->EnumDevices( DIDEVTYPE_KEYBOARD, EnumDevices, NULL, DIEDFL_ATTACHEDONLY ); if ( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: IDirectInput::EnumDevices") ); LOG->Trace( "InputHandler_DInput: IDirectInput::EnumDevices(DIDEVTYPE_JOYSTICK)" ); hr = dinput->EnumDevices( DIDEVTYPE_JOYSTICK, EnumDevices, NULL, DIEDFL_ATTACHEDONLY ); if ( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: IDirectInput::EnumDevices") ); for( unsigned i = 0; i < Devices.size(); ++i ) { if( Devices[i].Open() ) continue; Devices.erase( Devices.begin() + i ); i--; continue; } LOG->Info( "Found %u DirectInput devices:", Devices.size() ); for( unsigned i = 0; i < Devices.size(); ++i ) { LOG->Info( " %d: '%s' axes: %d, hats: %d, buttons: %d (%s)", i, Devices[i].JoystickInst.tszProductName, Devices[i].axes, Devices[i].hats, Devices[i].buttons, Devices[i].buffered? "buffered": "unbuffered" ); } m_DebugTimer.m_sName = "DirectInput"; StartThread(); }
int64_t DSoundBuf::GetPosition() const { DWORD iCursor, iJunk; HRESULT hr = m_pBuffer->GetCurrentPosition( &iCursor, &iJunk ); ASSERT_M( SUCCEEDED(hr), hr_ssprintf(hr, "GetCurrentPosition") ); /* This happens occasionally on "Realtek AC97 Audio". */ if( (int) iCursor == m_iBufferSize ) iCursor = 0; ASSERT_M( (int) iCursor < m_iBufferSize, ssprintf("%i, %i", iCursor, m_iBufferSize) ); int iCursorFrames = int(iCursor) / bytes_per_frame(); int iWriteCursorFrames = m_iWriteCursor / bytes_per_frame(); int iFramesBehind = iWriteCursorFrames - iCursorFrames; /* iFramesBehind will be 0 if we're called before the buffer starts playing: * both iWriteCursorFrames and iCursorFrames will be 0. */ if( iFramesBehind < 0 ) iFramesBehind += buffersize_frames(); /* unwrap */ int64_t iRet = m_iWriteCursorPos - iFramesBehind; /* Failsafe: never return a value smaller than we've already returned. * This can happen once in a while in underrun conditions. */ iRet = max( m_iLastPosition, iRet ); m_iLastPosition = iRet; return iRet; }
DSound::DSound() { HRESULT hr; if( FAILED( hr = CoInitialize(NULL) ) ) RageException::Throw( hr_ssprintf(hr, "CoInitialize") ); m_pDS = NULL; }
void DSoundBuf::SetVolume( float fVolume ) { if ( fVolume < 0 ) fVolume = 0; if ( fVolume > 1 ) fVolume = 1; if( fVolume == 0 ) fVolume = 0.001f; // fix log10f(0) == -INF float iVolumeLog2 = log10f(fVolume) / log10f(2); /* vol log 2 */ /* Volume is a multiplier; SetVolume wants attenuation in hundredths of a decibel. */ const int iNewVolume = max( int(1000 * iVolumeLog2), DSBVOLUME_MIN ); if( m_iVolume == iNewVolume ) return; HRESULT hr = m_pBuffer->SetVolume( iNewVolume ); if( FAILED(hr) ) { static bool bWarned = false; if( !bWarned ) LOG->Warn( hr_ssprintf(hr, "DirectSoundBuffer::SetVolume(%i) failed", iNewVolume) ); bWarned = true; return; } m_iVolume = iNewVolume; }
void DSoundBuf::SetSampleRate( int hz ) { m_iSampleRate = hz; HRESULT hr = m_pBuffer->SetFrequency( hz ); if( FAILED(hr) ) RageException::Throw( hr_ssprintf(hr, "m_pBuffer->SetFrequency(%i)", hz) ); }
CTextureRenderer::CTextureRenderer(): CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer), NAME("Texture Renderer"), NULL, &CBV_ret), m_OneFrameDecoded( "m_OneFrameDecoded", 0 ) { if( FAILED(CBV_ret) ) RageException::Throw( hr_ssprintf(CBV_ret, "Could not create texture renderer object!") ); m_pTexture = NULL; }
HRESULT GetDeviceState(LPDIRECTINPUTDEVICE2 dev, int size, void *ptr) { HRESULT hr = IDirectInputDevice2_GetDeviceState(dev, size, ptr); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) { hr = IDirectInputDevice2_Acquire(dev); if ( hr != DI_OK ) { LOG->Trace( hr_ssprintf(hr, "?") ); return hr; } hr = IDirectInputDevice2_GetDeviceState(dev, size, ptr); } return hr; }
bool DSound::IsEmulated() const { /* Don't bother wasting time trying to create buffers if we're * emulated. This also gives us better diagnostic information. */ DSCAPS Caps; Caps.dwSize = sizeof(Caps); HRESULT hr; if( FAILED(hr = m_pDS->GetCaps(&Caps)) ) { LOG->Warn( hr_ssprintf(hr, "m_pDS->GetCaps failed") ); /* This is strange, so let's be conservative. */ return true; } return !!(Caps.dwFlags & DSCAPS_EMULDRIVER); }
void InputHandler_DInput::UpdateBuffered(DIDevice &device, const RageTimer &tm) { DWORD numevents; DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; numevents = INPUT_QSIZE; HRESULT hr = IDirectInputDevice2_GetDeviceData( device.Device, sizeof(DIDEVICEOBJECTDATA), evtbuf, &numevents, 0); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; /* Handle the events */ if ( hr != DI_OK ) { LOG->Trace( hr_ssprintf(hr, "UpdateBuffered: IDirectInputDevice2_GetDeviceData") ); return; } /* XXX: We should check GetConsoleWindow(), to allow input while the console window * is focused. */ if( GetForegroundWindow() != GraphicsWindow::GetHwnd() ) return; for(int i = 0; i < (int) numevents; ++i) { for(unsigned j = 0; j < device.Inputs.size(); ++j) { const input_t &in = device.Inputs[j]; const InputDevice dev = device.dev; if(evtbuf[i].dwOfs != in.ofs) continue; switch(in.type) { case in.KEY: ButtonPressed(DeviceInput(dev, in.num, -1, tm), !!(evtbuf[i].dwData & 0x80)); break; case in.BUTTON: ButtonPressed(DeviceInput(dev, JOY_1 + in.num, -1, tm), !!evtbuf[i].dwData); break; case in.AXIS: { int up = 0, down = 0; switch(in.ofs) { case DIJOFS_X: up = JOY_LEFT; down = JOY_RIGHT; break; case DIJOFS_Y: up = JOY_UP; down = JOY_DOWN; break; case DIJOFS_Z: up = JOY_Z_UP; down = JOY_Z_DOWN; break; case DIJOFS_RX: up = JOY_ROT_UP; down = JOY_ROT_DOWN; break; case DIJOFS_RY: up = JOY_ROT_LEFT; down = JOY_ROT_RIGHT; break; case DIJOFS_RZ: up = JOY_ROT_Z_UP; down = JOY_ROT_Z_DOWN; break; case DIJOFS_SLIDER(0): up = JOY_AUX_1; down = JOY_AUX_2; break; case DIJOFS_SLIDER(1): up = JOY_AUX_3; down = JOY_AUX_4; break; default: LOG->MapLog("unknown input", "Controller '%s' is returning an unknown joystick offset, %i", device.JoystickInst.tszProductName, in.ofs ); continue; } float l = SCALE( int(evtbuf[i].dwData), 0.0f, 100.0f, 0.0f, 1.0f ); ButtonPressed(DeviceInput(dev, up, max(-l,0), tm), int(evtbuf[i].dwData) < -50); ButtonPressed(DeviceInput(dev, down, max(+l,0), tm), int(evtbuf[i].dwData) > 50); break; } case in.HAT: { const int pos = TranslatePOV(evtbuf[i].dwData); ButtonPressed(DeviceInput(dev, JOY_HAT_UP, -1, tm), !!(pos & HAT_UP_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_DOWN, -1, tm), !!(pos & HAT_DOWN_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_LEFT, -1, tm), !!(pos & HAT_LEFT_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_RIGHT, -1, tm), !!(pos & HAT_RIGHT_MASK)); } } } } }
/* This doesn't take a timestamp; instead, we let InputHandler::ButtonPressed figure * it out. Be sure to call InputHandler::Update() between each poll. */ void InputHandler_DInput::UpdatePolled(DIDevice &device, const RageTimer &tm) { if( device.type == device.KEYBOARD ) { unsigned char keys[256]; HRESULT hr = GetDeviceState(device.Device, 256, keys); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; if ( hr != DI_OK ) { LOG->MapLog( "UpdatePolled", hr_ssprintf(hr, "Failures on polled keyboard update") ); return; } for( int k = 0; k < 256; ++k ) { const int key = device.Inputs[k].num; ButtonPressed(DeviceInput(device.dev, key), !!(keys[k] & 0x80)); } return; } DIJOYSTATE state; HRESULT hr = GetDeviceState(device.Device, sizeof(state), &state); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; /* Set each known axis, button and POV. */ for(unsigned i = 0; i < device.Inputs.size(); ++i) { const input_t &in = device.Inputs[i]; const InputDevice dev = device.dev; switch(in.type) { case in.BUTTON: { DeviceInput di(dev, JOY_1 + in.num, -1, tm); ButtonPressed(di, !!state.rgbButtons[in.ofs - DIJOFS_BUTTON0]); break; } case in.AXIS: { JoystickButton neg = NUM_JOYSTICK_BUTTONS, pos = NUM_JOYSTICK_BUTTONS; int val = 0; switch(in.ofs) { case DIJOFS_X: neg = JOY_LEFT; pos = JOY_RIGHT; val = state.lX; break; case DIJOFS_Y: neg = JOY_UP; pos = JOY_DOWN; val = state.lY; break; case DIJOFS_Z: neg = JOY_Z_UP; pos = JOY_Z_DOWN; val = state.lZ; break; case DIJOFS_RX: neg = JOY_ROT_LEFT; pos = JOY_ROT_RIGHT; val = state.lRx; break; case DIJOFS_RY: neg = JOY_ROT_UP; pos = JOY_ROT_DOWN; val = state.lRy; break; case DIJOFS_RZ: neg = JOY_ROT_Z_UP; pos = JOY_ROT_Z_DOWN; val = state.lRz; break; case DIJOFS_SLIDER(0): neg = JOY_AUX_1; pos = JOY_AUX_2; val = state.rglSlider[0]; break; case DIJOFS_SLIDER(1): neg = JOY_AUX_3; pos = JOY_AUX_4; val = state.rglSlider[1]; break; default: LOG->MapLog("unknown input", "Controller '%s' is returning an unknown joystick offset, %i", device.JoystickInst.tszProductName, in.ofs ); continue; } if( neg != NUM_JOYSTICK_BUTTONS ) { float l = SCALE( int(val), 0.0f, 100.0f, 0.0f, 1.0f ); ButtonPressed(DeviceInput(dev, neg, max(-l,0), tm), val < -50); ButtonPressed(DeviceInput(dev, pos, max(+l,0), tm), val > 50); } break; } case in.HAT: if( in.num == 0 ) { const int pos = TranslatePOV(state.rgdwPOV[in.ofs - DIJOFS_POV(0)]); ButtonPressed(DeviceInput(dev, JOY_HAT_UP, -1, tm), !!(pos & HAT_UP_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_DOWN, -1, tm), !!(pos & HAT_DOWN_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_LEFT, -1, tm), !!(pos & HAT_LEFT_MASK)); ButtonPressed(DeviceInput(dev, JOY_HAT_RIGHT, -1, tm), !!(pos & HAT_RIGHT_MASK)); } break; } } }
bool DIDevice::Open() { m_sName = ConvertACPToUTF8( JoystickInst.tszProductName ); LOG->Trace( "Opening device '%s'", m_sName.c_str() ); buffered = true; LPDIRECTINPUTDEVICE8 tmpdevice; // load joystick HRESULT hr = g_dinput->CreateDevice( JoystickInst.guidInstance, &tmpdevice, NULL ); if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") ); return false; } hr = tmpdevice->QueryInterface( IID_IDirectInputDevice8, (LPVOID *) &Device ); tmpdevice->Release(); if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice::QueryInterface", m_sName.c_str()) ); return false; } int coop = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; if( type == KEYBOARD ) coop = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND; hr = Device->SetCooperativeLevel( GraphicsWindow::GetHwnd(), coop ); if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetCooperativeLevel", m_sName.c_str()) ); return false; } switch(type) { case KEYBOARD: hr = Device->SetDataFormat( &c_dfDIKeyboard ); break; case JOYSTICK: hr = Device->SetDataFormat( &c_dfDIJoystick ); break; case MOUSE: hr = Device->SetDataFormat( &c_dfDIMouse ); break; } if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetDataFormat", m_sName.c_str()) ); return false; } switch( type ) { case JOYSTICK: Device->EnumObjects( DIJoystick_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); break; case KEYBOARD: // Always 256-button. for( int b = 0; b < 256; ++b ) { input_t in; in.type = in.KEY; in.num = ConvertScancodeToKey(b); in.ofs = b; buttons++; Inputs.push_back(in); } break; case MOUSE: Device->EnumObjects( DIMouse_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_ANYINSTANCE ); break; } { DIPROPDWORD dipdw; memset(&dipdw, 0, sizeof(dipdw)); dipdw.diph.dwSize = sizeof(dipdw); dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = INPUT_QSIZE; hr = Device->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ); if ( hr == DI_POLLEDDEVICE ) { /* This device doesn't support buffering, so we're forced * to use less reliable polling. */ buffered = false; } else if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetProperty", m_sName.c_str()) ); return false; } } return true; }
CString DSoundBuf::Init( DSound &ds, DSoundBuf::hw hardware, int iChannels, int iSampleRate, int iSampleBits, int iWriteAhead ) { m_iChannels = iChannels; m_iSampleRate = iSampleRate; m_iSampleBits = iSampleBits; m_iWriteAhead = iWriteAhead * bytes_per_frame(); m_iVolume = -1; /* unset */ m_bBufferLocked = false; m_iWriteCursorPos = m_iWriteCursor = m_iBufferBytesFilled = 0; m_iExtraWriteahead = 0; m_iLastPosition = 0; m_bPlaying = false; ZERO( m_iLastCursors ); /* The size of the actual DSound buffer. This can be large; we generally * won't fill it completely. */ m_iBufferSize = 1024*64; m_iBufferSize = max( m_iBufferSize, m_iWriteAhead ); WAVEFORMATEX waveformat; memset( &waveformat, 0, sizeof(waveformat) ); waveformat.cbSize = 0; waveformat.wFormatTag = WAVE_FORMAT_PCM; bool NeedCtrlFrequency = false; if( m_iSampleRate == DYNAMIC_SAMPLERATE ) { m_iSampleRate = 44100; NeedCtrlFrequency = true; } int bytes = m_iSampleBits / 8; waveformat.wBitsPerSample = WORD(m_iSampleBits); waveformat.nChannels = WORD(m_iChannels); waveformat.nSamplesPerSec = DWORD(m_iSampleRate); waveformat.nBlockAlign = WORD(bytes*m_iChannels); waveformat.nAvgBytesPerSec = m_iSampleRate * bytes*m_iChannels; /* Try to create the secondary buffer */ DSBUFFERDESC format; memset( &format, 0, sizeof(format) ); format.dwSize = sizeof(format); #ifdef _XBOX format.dwFlags = 0; #else format.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME; #endif #ifndef _XBOX /* Don't use DSBCAPS_STATIC. It's meant for static buffers, and we * only use streaming buffers. */ if( hardware == HW_HARDWARE ) format.dwFlags |= DSBCAPS_LOCHARDWARE; else format.dwFlags |= DSBCAPS_LOCSOFTWARE; #endif if( NeedCtrlFrequency ) format.dwFlags |= DSBCAPS_CTRLFREQUENCY; format.dwBufferBytes = m_iBufferSize; #ifndef _XBOX format.dwReserved = 0; #else DSMIXBINVOLUMEPAIR dsmbvp[8] = { { DSMIXBIN_FRONT_LEFT, DSBVOLUME_MAX }, // left channel { DSMIXBIN_FRONT_RIGHT, DSBVOLUME_MAX }, // right channel { DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX }, // left channel { DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX }, // right channel { DSMIXBIN_BACK_LEFT, DSBVOLUME_MAX }, // left channel { DSMIXBIN_BACK_RIGHT, DSBVOLUME_MAX }, // right channel { DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX }, // left channel { DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX } // right channel }; DSMIXBINS dsmb; dsmb.dwMixBinCount = 8; dsmb.lpMixBinVolumePairs = dsmbvp; format.lpMixBins = &dsmb; #endif format.lpwfxFormat = &waveformat; HRESULT hr = ds.GetDS()->CreateSoundBuffer( &format, &m_pBuffer, NULL ); if( FAILED(hr) ) return hr_ssprintf( hr, "CreateSoundBuffer failed" ); #ifndef _XBOX /* I'm not sure this should ever be needed, but ... */ DSBCAPS bcaps; bcaps.dwSize=sizeof(bcaps); hr = m_pBuffer->GetCaps( &bcaps ); if( FAILED(hr) ) return hr_ssprintf( hr, "m_pBuffer->GetCaps" ); if( int(bcaps.dwBufferBytes) != m_iBufferSize ) { LOG->Warn( "bcaps.dwBufferBytes (%i) != m_iBufferSize(%i); adjusting", bcaps.dwBufferBytes, m_iBufferSize ); m_iBufferSize = bcaps.dwBufferBytes; m_iWriteAhead = min( m_iWriteAhead, m_iBufferSize ); } if( !(bcaps.dwFlags & DSBCAPS_CTRLVOLUME) ) LOG->Warn( "Sound channel missing DSBCAPS_CTRLVOLUME" ); if( !(bcaps.dwFlags & DSBCAPS_GETCURRENTPOSITION2) ) LOG->Warn( "Sound channel missing DSBCAPS_GETCURRENTPOSITION2" ); DWORD got; hr = m_pBuffer->GetFormat( &waveformat, sizeof(waveformat), &got ); if( FAILED(hr) ) LOG->Warn( hr_ssprintf(hr, "GetFormat on secondary buffer") ); else if( (int) waveformat.nSamplesPerSec != m_iSampleRate ) LOG->Warn( "Secondary buffer set to %i instead of %i", waveformat.nSamplesPerSec, m_iSampleRate ); #endif m_pTempBuffer = new char[m_iBufferSize]; return ""; }
/* This function does not reset the video mode if it fails, because we might be trying * yet another video mode, so we'd just thrash the display. On fatal error, * LowLevelWindow_Win32::~LowLevelWindow_Win32 will call Shutdown(). */ CString LowLevelWindow_Win32::TryVideoMode( RageDisplay::VideoModeParams p, bool &bNewDeviceOut ) { ASSERT_M( p.bpp == 16 || p.bpp == 32, ssprintf("%i", p.bpp) ); bNewDeviceOut = false; /* We're only allowed to change the pixel format of a window exactly once. */ bool bCanSetPixelFormat = true; /* Do we have an old window? */ if( GraphicsWindow::GetHwnd() == NULL ) { /* No. Always create and show the window before changing the video mode. * Otherwise, some other window may have focus, and changing the video mode will * cause that window to be resized. */ GraphicsWindow::CreateGraphicsWindow( p ); GraphicsWindow::ConfigureGraphicsWindow( p ); } else { /* We already have a window. Assume that it's pixel format has already been * set. */ LOG->Trace("Setting new window, can't reuse old"); bCanSetPixelFormat = false; } ASSERT( GraphicsWindow::GetHwnd() ); /* Set the display mode: switch to a fullscreen mode or revert to windowed mode. */ LOG->Trace("SetScreenMode ..."); CString sErr = GraphicsWindow::SetScreenMode( p ); if( !sErr.empty() ) return sErr; PIXELFORMATDESCRIPTOR PixelFormat; int iPixelFormat = ChooseWindowPixelFormat( p, &PixelFormat ); if( iPixelFormat == 0 ) { /* Destroy the window. */ DestroyGraphicsWindowAndOpenGLContext(); return "Pixel format not found"; } bool bNeedToSetPixelFormat = false; { /* We'll need to recreate it if the pixel format is going to change. We * aren't allowed to change the pixel format twice. */ PIXELFORMATDESCRIPTOR DestPixelFormat; ZERO( DestPixelFormat ); DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &DestPixelFormat ); if( memcmp( &DestPixelFormat, &g_CurrentPixelFormat, sizeof(PIXELFORMATDESCRIPTOR) ) ) { LOG->Trace("Reset: pixel format changing" ); bNeedToSetPixelFormat = true; } } if( bNeedToSetPixelFormat && !bCanSetPixelFormat ) { /* * The screen mode has changed, so we need to set the pixel format. If we're * not allowed to do so, destroy the window and make a new one. * * For some reason, if we destroy the old window before creating the new one, * the "fullscreen apps go under the taskbar" glitch will happen when we quit. * We have to create the new window first. */ LOG->Trace( "Mode requires new pixel format, and we've already set one; resetting OpenGL context" ); if( g_HGLRC != NULL ) { wglMakeCurrent( NULL, NULL ); wglDeleteContext( g_HGLRC ); g_HGLRC = NULL; } GraphicsWindow::RecreateGraphicsWindow(p); // DestroyGraphicsWindowAndOpenGLContext(); // GraphicsWindow::CreateGraphicsWindow( p ); bNewDeviceOut = true; } GraphicsWindow::ConfigureGraphicsWindow( p ); GraphicsWindow::SetVideoModeParams( p ); if( bNeedToSetPixelFormat ) { /* Set the pixel format. */ if( !SetPixelFormat(GraphicsWindow::GetHDC(), iPixelFormat, &PixelFormat) ) { /* Destroy the window. */ DestroyGraphicsWindowAndOpenGLContext(); return werr_ssprintf( GetLastError(), "Pixel format failed" ); } DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(g_CurrentPixelFormat), &g_CurrentPixelFormat ); DumpPixelFormat( g_CurrentPixelFormat ); } if( g_HGLRC == NULL ) { g_HGLRC = wglCreateContext( GraphicsWindow::GetHDC() ); if ( g_HGLRC == NULL ) { DestroyGraphicsWindowAndOpenGLContext(); return hr_ssprintf( GetLastError(), "wglCreateContext" ); } if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC ) ) { DestroyGraphicsWindowAndOpenGLContext(); return hr_ssprintf( GetLastError(), "wglCreateContext" ); } } return ""; // we set the video mode successfully }
bool DSoundBuf::get_output_buf( char **pBuffer, unsigned *pBufferSize, int iChunksize ) { ASSERT( !m_bBufferLocked ); iChunksize *= bytes_per_frame(); DWORD iCursorStart, iCursorEnd; HRESULT result; /* It's easiest to think of the cursor as a block, starting and ending at * the two values returned by GetCurrentPosition, that we can't write to. */ result = m_pBuffer->GetCurrentPosition( &iCursorStart, &iCursorEnd ); #ifndef _XBOX if( result == DSERR_BUFFERLOST ) { m_pBuffer->Restore(); result = m_pBuffer->GetCurrentPosition( &iCursorStart, &iCursorEnd ); } if( result != DS_OK ) { LOG->Warn( hr_ssprintf(result, "DirectSound::GetCurrentPosition failed") ); return false; } #endif memmove( &m_iLastCursors[0][0], &m_iLastCursors[1][0], sizeof(int)*6 ); m_iLastCursors[3][0] = iCursorStart; m_iLastCursors[3][1] = iCursorEnd; /* Some cards (Creative AudioPCI) have a no-write area even when not playing. I'm not * sure what that means, but it breaks the assumption that we can fill the whole writeahead * when prebuffering. */ if( !m_bPlaying ) iCursorEnd = iCursorStart; /* * Some cards (Game Theater XP 7.1 hercwdm.sys 5.12.01.4101 [466688b, 01-10-2003]) * have odd behavior when starting a sound: the start/end cursors go: * * 0,0 end cursor forced equal to start above (normal) * 4608, 1764 end cursor trailing the write cursor; except with old emulated * WaveOut devices, this shouldn't happen; it indicates that the * driver expects almost the whole buffer to be filled. Also, the * play cursor is too far ahead from the last call for the amount * of actual time passed. * 704, XXX start cursor moves back to where it should be. I don't have an exact * end cursor position, but in general from now on it stays about 5kb * ahead of start (which is where it should be). * * The second call is completely wrong; both the start and end cursors are meaningless. * Detect this: if the end cursor is close behind the start cursor, don't do anything. * (We can't; we have no idea what the cursors actually are.) */ { int iPrefetch = iCursorEnd - iCursorStart; wrap( iPrefetch, m_iBufferSize ); if( m_iBufferSize - iPrefetch < 1024*4 ) { LOG->Trace( "Strange DirectSound cursor ignored: %i..%i", iCursorStart, iCursorEnd ); return false; } } /* Update m_iBufferBytesFilled. */ { int iFirstByteFilled = m_iWriteCursor - m_iBufferBytesFilled; wrap( iFirstByteFilled, m_iBufferSize ); /* The number of bytes that have been played since the last time we got here: */ int bytes_played = iCursorStart - iFirstByteFilled; wrap( bytes_played, m_iBufferSize ); m_iBufferBytesFilled -= bytes_played; m_iBufferBytesFilled = max( 0, m_iBufferBytesFilled ); if( m_iExtraWriteahead ) { int used = min( m_iExtraWriteahead, bytes_played ); CString s = ssprintf("used %i of %i (%i..%i)", used, m_iExtraWriteahead, iCursorStart, iCursorEnd ); s += "; last: "; for( int i = 0; i < 4; ++i ) s += ssprintf( "%i, %i; ", m_iLastCursors[i][0], m_iLastCursors[i][1] ); LOG->Trace("%s", s.c_str()); m_iWriteAhead -= used; m_iExtraWriteahead -= used; } } CheckWriteahead( iCursorStart, iCursorEnd ); CheckUnderrun( iCursorStart, iCursorEnd ); /* If we already have enough bytes written ahead, stop. */ if( m_iBufferBytesFilled > m_iWriteAhead ) return false; int iNumBytesEmpty = m_iWriteAhead - m_iBufferBytesFilled; /* num_bytes_empty is the amount of free buffer space. If it's * too small, come back later. */ if( iNumBytesEmpty < iChunksize ) return false; // LOG->Trace("gave %i at %i (%i, %i) %i filled", iNumBytesEmpty, m_iWriteCursor, cursor, write, m_iBufferBytesFilled); /* Lock the audio buffer. */ result = m_pBuffer->Lock( m_iWriteCursor, iNumBytesEmpty, (LPVOID *) &m_pLockedBuf1, (DWORD *) &m_iLockedSize1, (LPVOID *) &m_pLockedBuf2, (DWORD *) &m_iLockedSize2, 0 ); #ifndef _XBOX if( result == DSERR_BUFFERLOST ) { m_pBuffer->Restore(); result = m_pBuffer->Lock( m_iWriteCursor, iNumBytesEmpty, (LPVOID *) &m_pLockedBuf1, (DWORD *) &m_iLockedSize1, (LPVOID *) &m_pLockedBuf2, (DWORD *) &m_iLockedSize2, 0 ); } #endif if( result != DS_OK ) { LOG->Warn( hr_ssprintf(result, "Couldn't lock the DirectSound buffer.") ); return false; } *pBuffer = m_pTempBuffer; *pBufferSize = m_iLockedSize1 + m_iLockedSize2; m_iWriteCursor += iNumBytesEmpty; if( m_iWriteCursor >= m_iBufferSize ) m_iWriteCursor -= m_iBufferSize; m_iBufferBytesFilled += iNumBytesEmpty; m_iWriteCursorPos += iNumBytesEmpty / bytes_per_frame(); m_bBufferLocked = true; return true; }