//-------------------------------------------------------------------------------------- // Name: ReadSample() // Desc: Reads data from the audio file. //-------------------------------------------------------------------------------------- HRESULT WaveFile::ReadSample( DWORD dwPosition, VOID* pBuffer, DWORD dwBufferSize, DWORD* pdwRead ) const { HRESULT hr = S_OK; hr = ReadSampleRaw(dwPosition, pBuffer, dwBufferSize, pdwRead); if (FAILED( hr )) { return hr; } // Check bit size for endianness conversion. WAVEFORMATEXTENSIBLE wfxFormat; GetFormat( &wfxFormat ); //Endianness conversion switch( wfxFormat.Format.wFormatTag ) { case WAVE_FORMAT_PCM: if( wfxFormat.Format.wBitsPerSample == 16 ) { SHORT* pBufferShort = ( SHORT* )pBuffer; for( DWORD i = 0; i < dwBufferSize / sizeof( SHORT ); i++ ) pBufferShort[i] = __loadshortbytereverse( 0, &pBufferShort[i] ); } break; case WAVE_FORMAT_EXTENSIBLE: if( wfxFormat.Format.wBitsPerSample == 16 ) { SHORT* pBufferShort = ( SHORT* )pBuffer; for( DWORD i = 0; i < dwBufferSize / sizeof( SHORT ); i++ ) pBufferShort[i] = __loadshortbytereverse( 0, &pBufferShort[i] ); } else if( wfxFormat.Format.wBitsPerSample == 32 ) { DWORD* pBufferDWord = ( DWORD* )pBuffer; for( DWORD i = 0; i < dwBufferSize / sizeof( DWORD ); i++ ) pBufferDWord[i] = __loadwordbytereverse( 0, &pBufferDWord[i] ); } // 24 doesn't need converted... break; } return hr; }
//-------------------------------------------------------------------------------------- // Name: Open() // Desc: Opens an existing chunk //-------------------------------------------------------------------------------------- HRESULT RiffChunk::Open() { LONG lOffset = 0; // Seek to the first byte of the parent chunk's data section if( m_pParentChunk ) { lOffset = m_pParentChunk->m_dwDataOffset; // Special case the RIFF chunk if( ATG_FOURCC_RIFF == m_pParentChunk->m_fccChunkId ) lOffset += sizeof( FOURCC ); } // Read each child chunk header until we find the one we're looking for for(; ; ) { if( INVALID_SET_FILE_POINTER == SetFilePointer( m_hFile, lOffset, NULL, FILE_BEGIN ) ) return HRESULT_FROM_WIN32( GetLastError() ); RIFFHEADER rhRiffHeader; DWORD dwRead; if( 0 == ReadFile( m_hFile, &rhRiffHeader, sizeof( rhRiffHeader ), &dwRead, NULL ) ) return HRESULT_FROM_WIN32( GetLastError() ); rhRiffHeader.dwDataSize = __loadwordbytereverse( 0, &rhRiffHeader.dwDataSize ); // Hit EOF without finding it if( 0 == dwRead ) return E_FAIL; // Check if we found the one we're looking for if( m_fccChunkId == rhRiffHeader.fccChunkId ) { // Save the chunk size and data offset m_dwDataOffset = lOffset + sizeof( rhRiffHeader ); m_dwDataSize = rhRiffHeader.dwDataSize; // Success m_dwFlags |= RIFFCHUNK_FLAGS_VALID; return S_OK; } lOffset += sizeof( rhRiffHeader ) + rhRiffHeader.dwDataSize; } }
int LoadZIMPtr(uint8_t *zim, int datasize, int *width, int *height, int *flags, uint8 **image) { if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') { ELOG("Not a ZIM file"); return 0; } #ifndef _XBOX memcpy(width, zim + 4, 4); memcpy(height, zim + 8, 4); memcpy(flags, zim + 12, 4); #else *width = __loadwordbytereverse(4, zim); *height = __loadwordbytereverse(8, zim); *flags = __loadwordbytereverse(12, zim); #endif int num_levels = 1; int image_data_size[ZIM_MAX_MIP_LEVELS]; if (*flags & ZIM_HAS_MIPS) { num_levels = log2i(*width < *height ? *width : *height) + 1; } int total_data_size = 0; for (int i = 0; i < num_levels; i++) { if (i > 0) { width[i] = width[i-1] / 2; height[i] = height[i-1] / 2; } switch (*flags & ZIM_FORMAT_MASK) { case ZIM_RGBA8888: image_data_size[i] = width[i] * height[i] * 4; break; case ZIM_RGBA4444: case ZIM_RGB565: image_data_size[i] = width[i] * height[i] * 2; break; case ZIM_ETC1: { int data_width = width[i]; int data_height = height[i]; if (data_width < 4) data_width = 4; if (data_height < 4) data_height = 4; image_data_size[i] = data_width * data_height / 2; break; } default: ELOG("Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK); return 0; } total_data_size += image_data_size[i]; } if (total_data_size == 0) { ELOG("Invalid ZIM data size 0"); return 0; } image[0] = (uint8 *)malloc(total_data_size); for (int i = 1; i < num_levels; i++) { image[i] = image[i-1] + image_data_size[i-1]; } if (*flags & ZIM_ZLIB_COMPRESSED) { long outlen = total_data_size; if (Z_OK != ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), datasize - 16)) { free(*image); *image = 0; return 0; } if (outlen != total_data_size) { ELOG("Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size); } } else { memcpy(*image, zim + 16, datasize - 16); if (datasize - 16 != total_data_size) { ELOG("Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size); } } return num_levels; }
//-------------------------------------------------------------------------------------- // Name: GetLoopRegion() // Desc: Gets the loop region, in terms of samples //-------------------------------------------------------------------------------------- HRESULT WaveFile::GetLoopRegion( DWORD* pdwStart, DWORD* pdwLength ) const { assert( pdwStart != NULL ); assert( pdwLength != NULL ); HRESULT hr = S_OK; *pdwStart = 0; *pdwLength = 0; // First, look for a MIDI-style SMPL chunk, then for a DLS-style WSMP chunk. BOOL bGotLoopRegion = FALSE; if( !bGotLoopRegion && m_SamplerChunk.IsValid() ) { // Read the SAMPLER struct from the chunk SAMPLER smpl; hr = m_SamplerChunk.ReadData( 0, &smpl, sizeof( SAMPLER ), NULL ); if( FAILED( hr ) ) return hr; //Endianness conversion LONG* pLong = ( LONG* )&smpl; for( INT i = 0; i < sizeof( SAMPLER ) / sizeof( LONG ); i++ ) *pLong++ = __loadwordbytereverse( i, &smpl ); // Check if the chunk contains any loop regions if( smpl.dwNumSampleLoops > 0 ) { SAMPLER_LOOP smpl_loop; hr = m_SamplerChunk.ReadData( sizeof( SAMPLER ), &smpl_loop, sizeof( SAMPLER_LOOP ), NULL ); if( FAILED( hr ) ) return E_FAIL; //Endianness conversion pLong = ( LONG* )&smpl_loop; for( INT i = 0; i < sizeof( SAMPLER_LOOP ) / sizeof( LONG ); i++ ) *pLong++ = __loadwordbytereverse( i, &smpl_loop ); // Documentation on the SMPL chunk indicates that dwStart and // dwEnd are stored as byte-offsets, rather than sample counts, // but SoundForge stores sample counts, so we'll go with that. *pdwStart = smpl_loop.dwStart; *pdwLength = smpl_loop.dwEnd - smpl_loop.dwStart + 1; bGotLoopRegion = TRUE; } } if( !bGotLoopRegion && m_WaveSampleChunk.IsValid() ) { // Read the WAVESAMPLE struct from the chunk WAVESAMPLE ws; hr = m_WaveSampleChunk.ReadData( 0, &ws, sizeof( WAVESAMPLE ), NULL ); if( FAILED( hr ) ) return hr; // Endianness conversion ws.dwSize = __loadwordbytereverse( 0, &ws.dwSize ); ws.UnityNote = __loadshortbytereverse( 0, &ws.UnityNote ); ws.FineTune = __loadshortbytereverse( 0, &ws.FineTune ); ws.Gain = __loadwordbytereverse( 0, &ws.Gain ); ws.dwOptions = __loadwordbytereverse( 0, &ws.dwOptions ); ws.dwSampleLoops = __loadwordbytereverse( 0, &ws.dwSampleLoops ); // Check if the chunk contains any loop regions if( ws.dwSampleLoops > 0 ) { // Read the loop region WAVESAMPLE_LOOP wsl; hr = m_WaveSampleChunk.ReadData( ws.dwSize, &wsl, sizeof( WAVESAMPLE_LOOP ), NULL ); if( FAILED( hr ) ) return hr; //Endianness conversion LONG* l = ( LONG* )&wsl; for( INT i = 0; i < sizeof( WAVESAMPLE_LOOP ) / sizeof( LONG ); i++ ) *l++ = __loadwordbytereverse( i, &wsl ); // Fill output vars with the loop region *pdwStart = wsl.dwLoopStart; *pdwLength = wsl.dwLoopLength; bGotLoopRegion = TRUE; } } // Couldn't find either chunk, or they didn't contain loop points if( !bGotLoopRegion ) return E_FAIL; return S_OK; }
//-------------------------------------------------------------------------------------- // Name: GetFormat() // Desc: Gets the wave file format. //-------------------------------------------------------------------------------------- HRESULT WaveFile::GetFormat( WAVEFORMATEXTENSIBLE* pwfxFormat, XMA2WAVEFORMATEX* pXma2Format ) const { assert( pwfxFormat ); DWORD dwValidSize = m_FormatChunk.GetDataSize(); // Must be at least as large as a WAVEFORMAT to be valid if( dwValidSize < sizeof( WAVEFORMAT ) ) return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); // Read the format chunk into the buffer HRESULT hr = m_FormatChunk.ReadData( 0, pwfxFormat, min( dwValidSize, sizeof( WAVEFORMATEXTENSIBLE ) ), NULL ); if( FAILED( hr ) ) return hr; // Endian conversion for WAVEFORMAT base structure pwfxFormat->Format.wFormatTag = __loadshortbytereverse( 0, &pwfxFormat->Format.wFormatTag ); pwfxFormat->Format.nChannels = __loadshortbytereverse( 0, &pwfxFormat->Format.nChannels ); pwfxFormat->Format.nSamplesPerSec = __loadwordbytereverse( 0, &pwfxFormat->Format.nSamplesPerSec ); pwfxFormat->Format.nAvgBytesPerSec = __loadwordbytereverse( 0, &pwfxFormat->Format.nAvgBytesPerSec ); pwfxFormat->Format.nBlockAlign = __loadshortbytereverse( 0, &pwfxFormat->Format.nBlockAlign ); switch( pwfxFormat->Format.wFormatTag ) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_WMAUDIO3: case WAVE_FORMAT_WMAUDIO2: if( dwValidSize < sizeof( PCMWAVEFORMAT ) ) return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); pwfxFormat->Format.wBitsPerSample = __loadshortbytereverse( 0, &pwfxFormat->Format.wBitsPerSample ); break; case WAVE_FORMAT_EXTENSIBLE: if( dwValidSize < sizeof( WAVEFORMATEXTENSIBLE ) ) return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); // Endianness conversion pwfxFormat->Format.wBitsPerSample = __loadshortbytereverse( 0, &pwfxFormat->Format.wBitsPerSample ); pwfxFormat->Format.cbSize = __loadshortbytereverse( 0, &pwfxFormat->Format.cbSize ); pwfxFormat->Samples.wReserved = __loadshortbytereverse( 0, &pwfxFormat->Samples.wReserved ); pwfxFormat->dwChannelMask = __loadwordbytereverse( 0, &pwfxFormat->dwChannelMask ); pwfxFormat->SubFormat.Data1 = __loadwordbytereverse( 0, &pwfxFormat->SubFormat.Data1 ); pwfxFormat->SubFormat.Data2 = __loadshortbytereverse( 0, &pwfxFormat->SubFormat.Data2 ); pwfxFormat->SubFormat.Data3 = __loadshortbytereverse( 0, &pwfxFormat->SubFormat.Data3 ); // Data4 is a array of char, not needed to convert break; case WAVE_FORMAT_XMA2: if( dwValidSize != sizeof( XMA2WAVEFORMATEX ) ) return HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); // Need second structure to store the result if( !pXma2Format ) return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); hr = m_FormatChunk.ReadData( 0, pXma2Format, sizeof( XMA2WAVEFORMATEX ), NULL ); if( FAILED( hr ) ) return hr; // Endian conversion { pwfxFormat->Format.wBitsPerSample = __loadshortbytereverse( 0, &pwfxFormat->Format.wBitsPerSample ); pwfxFormat->Format.cbSize = __loadshortbytereverse( 0, &pwfxFormat->Format.cbSize ); pXma2Format->wfx = pwfxFormat->Format; pXma2Format->NumStreams = __loadshortbytereverse( 0, &pXma2Format->NumStreams ); pXma2Format->ChannelMask = __loadwordbytereverse( 0, &pXma2Format->ChannelMask ); pXma2Format->SamplesEncoded = __loadwordbytereverse( 0, &pXma2Format->SamplesEncoded ); pXma2Format->BytesPerBlock = __loadwordbytereverse( 0, &pXma2Format->BytesPerBlock ); pXma2Format->PlayBegin = __loadwordbytereverse( 0, &pXma2Format->PlayBegin ); pXma2Format->PlayLength = __loadwordbytereverse( 0, &pXma2Format->PlayLength ); pXma2Format->LoopBegin = __loadwordbytereverse( 0, &pXma2Format->LoopBegin ); pXma2Format->LoopLength = __loadwordbytereverse( 0, &pXma2Format->LoopLength ); pXma2Format->BlockCount = __loadshortbytereverse( 0, &pXma2Format->BlockCount ); } break; default: // Unsupported! return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } // Zero out remaining bytes, in case enough bytes were not read if( dwValidSize < sizeof( WAVEFORMATEXTENSIBLE ) ) ZeroMemory( ( BYTE* )pwfxFormat + dwValidSize, sizeof( WAVEFORMATEXTENSIBLE ) - dwValidSize ); return S_OK; }