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