Пример #1
0
	int Read(float* buf, int iFrames)
	{
		int iBytesPerSample = QuantizeUp(m_WavData.m_iBitsPerSample, 8) / 8;
		int len = iFrames * m_WavData.m_iChannels;
		len *= iBytesPerSample;

		const int iBytesLeftInDataChunk = m_WavData.m_iDataChunkSize - (m_File.Tell() - m_WavData.m_iDataChunkPos);
		if (!iBytesLeftInDataChunk)
			return RageSoundReader::END_OF_FILE;

		len = min(len, iBytesLeftInDataChunk);
		int iGot = m_File.Read(buf, len);

		int iGotSample = iGot / iBytesPerSample;
		if (m_WavData.m_iFormatTag == 1)
		{
			switch(iBytesPerSample)
			{
			case 1:
				Convert8bitToFloat(buf, iGotSamples);
				break;
			case 2:
				ConvertLittleEndian16BitToFloat(buf, iGotSamples);
				break;
			case 3:
				ConvertLittleEndian24BitToFloat(buf, iGotSamples);
				break;
			case 4:
				ConvertLittleEndian32BitToFloat(buf, iGotSamples);
				break;
			}
		}

		return iGotSamples / m_WavData.m_iChannels;
	}
Пример #2
0
	bool Init()
	{
		if (QuantizeUp(m_WavData.m_iBitsPerSample, 8) < 8 ||
			QuantizeUp(m_WavData.m_iBitsPerSample, 8) > 32)
		{
			m_sError = ssprintf("Unsupported sample size %i", m_WavData.m_iBitsPerSample);
			return false;
		}

		if (m_WavData.m_iFormatTag == 3 && m_WavData.m_iBitsPerSample != 32)
		{
			m_sError = ssprintf("Unsupported float sample size %i", m_WavData.m_iBitsPerSample);
			return false;
		}

		m_File.Seek(m_WavData.m_iDataChunkPos);
		return true;
	}
Пример #3
0
void BitmapText::BuildChars()
{
	// If we don't have a font yet, we'll do this when it loads.
	if( m_pFont == NULL )
		return;

	// calculate line lengths and widths
	m_size.x = 0;

	m_iLineWidths.clear();
	for( unsigned l=0; l<m_wTextLines.size(); l++ ) // for each line
	{
		m_iLineWidths.push_back(m_pFont->GetLineWidthInSourcePixels( m_wTextLines[l] ));
		m_size.x = max( m_size.x, m_iLineWidths.back() );
	}

	/* Ensure that the width is always even. This maintains pixel alignment;
	 * fX below will always be an integer. */
	m_size.x = QuantizeUp( m_size.x, 2.0f );

	m_aVertices.clear();
	m_vpFontPageTextures.clear();

	if( m_wTextLines.empty() )
		return;

	m_size.y = float(m_pFont->GetHeight() * m_wTextLines.size());

	// The height (from the origin to the baseline):
	int iPadding = m_pFont->GetLineSpacing() - m_pFont->GetHeight();
	iPadding += m_iVertSpacing;

	// There's padding between every line:
	m_size.y += iPadding * int(m_wTextLines.size()-1);

	// the top position of the first row of characters
	int iY = lrintf(-m_size.y/2.0f);

	for( unsigned i=0; i<m_wTextLines.size(); i++ ) // foreach line
	{
		iY += m_pFont->GetHeight();

		wstring sLine = m_wTextLines[i];
		if( m_pFont->IsRightToLeft() )
			reverse( sLine.begin(), sLine.end() );
		const int iLineWidth = m_iLineWidths[i];

		float fX = SCALE( m_fHorizAlign, 0.0f, 1.0f, -m_size.x/2.0f, +m_size.x/2.0f - iLineWidth );
		int iX = lrintf( fX );

		for( unsigned j = 0; j < sLine.size(); ++j )
		{
			RageSpriteVertex v[4];
			const glyph &g = m_pFont->GetGlyph( sLine[j] );

			if( m_pFont->IsRightToLeft() )
				iX -= g.m_iHadvance;

			// set vertex positions
			v[0].p = RageVector3( iX+g.m_fHshift,			iY+g.m_pPage->m_fVshift,		0 );	// top left
			v[1].p = RageVector3( iX+g.m_fHshift,			iY+g.m_pPage->m_fVshift+g.m_fHeight,	0 );	// bottom left
			v[2].p = RageVector3( iX+g.m_fHshift+g.m_fWidth,	iY+g.m_pPage->m_fVshift+g.m_fHeight,	0 );	// bottom right
			v[3].p = RageVector3( iX+g.m_fHshift+g.m_fWidth,	iY+g.m_pPage->m_fVshift,		0 );	// top right

			// Advance the cursor.
			iX += g.m_iHadvance;

			// set texture coordinates
			v[0].t = RageVector2( g.m_TexRect.left,	g.m_TexRect.top );
			v[1].t = RageVector2( g.m_TexRect.left,	g.m_TexRect.bottom );
			v[2].t = RageVector2( g.m_TexRect.right,	g.m_TexRect.bottom );
			v[3].t = RageVector2( g.m_TexRect.right,	g.m_TexRect.top );

			m_aVertices.insert( m_aVertices.end(), &v[0], &v[4] );
			m_vpFontPageTextures.push_back( g.GetFontPageTextures() );
		}

		// The amount of padding a line needs:
		iY += iPadding;
	}

	if( m_bUsingDistortion )
	{
		int iSeed = lrintf( RageTimer::GetTimeSinceStartFast()*500000.0f );
		RandomGen rnd( iSeed );
		for(unsigned int i= 0; i < m_aVertices.size(); i+=4)
		{
			float w= m_aVertices[i+2].p.x - m_aVertices[i].p.x;
			float h= m_aVertices[i+2].p.y - m_aVertices[i].p.y;
			for(unsigned int ioff= 0; ioff < 4; ++ioff)
			{
				m_aVertices[i+ioff].p.x += ((rnd()%9) / 8.0f - .5f) * m_fDistortion * w;
				m_aVertices[i+ioff].p.y += ((rnd()%9) / 8.0f - .5f) * m_fDistortion * h;
			}
		}
	}
}
Пример #4
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 );
	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;
	}

	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 );
			RString 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;

	/* If we don't have enough free space in the buffer to fill a whole chunk, stop. */
	if( m_iBufferSize - m_iBufferBytesFilled < iChunksize )
		return false;

	int iNumBytesEmpty = m_iWriteAhead - m_iBufferBytesFilled;
	iNumBytesEmpty = QuantizeUp( iNumBytesEmpty, iChunksize );

//	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 );

	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 );
	}

	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;
}