Example #1
0
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
}
Example #2
0
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();
}
Example #5
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #15
0
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 "";
}
Example #16
0
/* 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
}
Example #17
0
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;
}