방법: XAudio2에서 오디오 데이터 파일 로드
참고 항목
이 콘텐츠는 데스크톱 앱에만 적용되며 UWP 앱에서 작동하려면 수정이 필요합니다. CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx 및 GetOverlappedResultEx에 대한 설명서를 참조하세요. .cpp
현재 보관된 Windows SDK 샘플 갤러리의 BasicSound Windows 8 샘플 앱을 참조 SoundFileReader.h
하세요.
XAudio2에서 오디오 데이터를 재생하는 데 필요한 구조를 채우려면 다음을 수행합니다.
- 오디오 파일을 로드하거나 스트리밍할 수 있습니다.
- 또는 고유한 파형을 생성하고 해당 파형을 버퍼의 샘플로 나타낼 수 있습니다(전체의 간단한 XAudio2 프로젝트 참조).
이 항목에서는 오디오 파일을 로드하는 방법에 중점을 둡니다. 다음 단계에서는 오디오 파일의 청크 및 청크를 로드 fmt
하고 이를 사용하여 WAVEFORMATEXTENSIBLE 구조체와 XAUDIO2_BUFFER 구조를 채웁니다.data
오디오 파일 구문 분석 준비
XAudio2에서 지원하는 오디오 파일은 RIFF(리소스 교환 파일 형식)로 형식이 지정됩니다. RIFF는 RIFF(리소스 교환 파일 형식) 항목 에 설명되어 있습니다. RIFF 파일의 오디오 데이터는 RIFF 청크를 찾은 다음 청크를 반복하여 RIFF 청크에 포함된 개별 청크를 찾아 로드됩니다. 다음 함수는 청크를 찾고 청크에 포함된 데이터를 로드하는 코드의 예입니다.
RIFF 파일에서 청크를 찾으려면 다음을 수행합니다.
#ifdef _XBOX //Big-Endian #define fourccRIFF 'RIFF' #define fourccDATA 'data' #define fourccFMT 'fmt ' #define fourccWAVE 'WAVE' #define fourccXWMA 'XWMA' #define fourccDPDS 'dpds' #endif #ifndef _XBOX //Little-Endian #define fourccRIFF 'FFIR' #define fourccDATA 'atad' #define fourccFMT ' tmf' #define fourccWAVE 'EVAW' #define fourccXWMA 'AMWX' #define fourccDPDS 'sdpd' #endif HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD & dwChunkSize, DWORD & dwChunkDataPosition) { HRESULT hr = S_OK; if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ) ) return HRESULT_FROM_WIN32( GetLastError() ); DWORD dwChunkType; DWORD dwChunkDataSize; DWORD dwRIFFDataSize = 0; DWORD dwFileType; DWORD bytesRead = 0; DWORD dwOffset = 0; while (hr == S_OK) { DWORD dwRead; if( 0 == ReadFile( hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); if( 0 == ReadFile( hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); switch (dwChunkType) { case fourccRIFF: dwRIFFDataSize = dwChunkDataSize; dwChunkDataSize = 4; if( 0 == ReadFile( hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); break; default: if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, dwChunkDataSize, NULL, FILE_CURRENT ) ) return HRESULT_FROM_WIN32( GetLastError() ); } dwOffset += sizeof(DWORD) * 2; if (dwChunkType == fourcc) { dwChunkSize = dwChunkDataSize; dwChunkDataPosition = dwOffset; return S_OK; } dwOffset += dwChunkDataSize; if (bytesRead >= dwRIFFDataSize) return S_FALSE; } return S_OK; }
청크가 배치된 후 청크에서 데이터를 읽으려면
원하는 청크가 발견되면 청크의 데이터 섹션 시작 부분에 대한 파일 포인터를 조정하여 해당 데이터를 읽을 수 있습니다. 청크가 발견되면 청크에서 데이터를 읽는 함수는 다음과 같습니다.
HRESULT ReadChunkData(HANDLE hFile, void * buffer, DWORD buffersize, DWORD bufferoffset) { HRESULT hr = S_OK; if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, bufferoffset, NULL, FILE_BEGIN ) ) return HRESULT_FROM_WIN32( GetLastError() ); DWORD dwRead; if( 0 == ReadFile( hFile, buffer, buffersize, &dwRead, NULL ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); return hr; }
RIFF 청크의 내용으로 XAudio2 구조체 채우기
XAudio2가 원본 음성으로 오디오를 재생하려면 WAVEFORMATEX 구조와 XAUDIO2_BUFFER 구조가 필요합니다. WAVEFORMATEX 구조체는 WAVEFORMATEX 구조체를 첫 번째 멤버로 포함하는 WAVEFORMATEXTENSIBLE과 같은 더 큰 구조체일 수 있습니다. 자세한 내용은 WAVEFORMATEX 참조 페이지를 참조하세요.
이 예제 에서는 WAVEFORMATEXTENSIBLE 을 사용하여 두 개 이상의 채널이 있는 PCM 오디오 파일을 로드할 수 있습니다.
다음 단계에서는 위에서 설명한 함수를 사용하여 WAVEFORMATEXTENSIBLE 구조체 및 XAUDIO2_BUFFER 구조를 채우는 방법을 보여 줍니다. 이 경우 로드되는 오디오 파일에는 PCM 데이터가 포함되며 'RIFF', 'fmt' 및 'data' 청크만 포함됩니다. 다른 형식은 RIFF(리소스 교환 파일 형식)에 설명된 대로 추가 청크 형식을 포함할 수 있습니다.
WAVEFORMATEXTENSIBLE 및 XAUDIO2_BUFFER 구조를 선언합니다.
WAVEFORMATEXTENSIBLE wfx = {0}; XAUDIO2_BUFFER buffer = {0};
CreateFile을 사용하여 오디오 파일을 엽니다.
#ifdef _XBOX char * strFileName = "game:\\media\\MusicMono.wav"; #else TCHAR * strFileName = _TEXT("media\\MusicMono.wav"); #endif // Open the file HANDLE hFile = CreateFile( strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if( INVALID_HANDLE_VALUE == hFile ) return HRESULT_FROM_WIN32( GetLastError() ); if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ) ) return HRESULT_FROM_WIN32( GetLastError() );
오디오 파일에서 'RIFF' 청크를 찾아 파일 형식을 확인합니다.
DWORD dwChunkSize; DWORD dwChunkPosition; //check the file type, should be fourccWAVE or 'XWMA' FindChunk(hFile,fourccRIFF,dwChunkSize, dwChunkPosition ); DWORD filetype; ReadChunkData(hFile,&filetype,sizeof(DWORD),dwChunkPosition); if (filetype != fourccWAVE) return S_FALSE;
'fmt' 청크를 찾아 해당 내용을 WAVEFORMATEXTENSIBLE 구조체로 복사합니다.
FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition ); ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
'data' 청크를 찾아 해당 내용을 버퍼로 읽습니다.
//fill out the audio data buffer with the contents of the fourccDATA chunk FindChunk(hFile,fourccDATA,dwChunkSize, dwChunkPosition ); BYTE * pDataBuffer = new BYTE[dwChunkSize]; ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);
XAUDIO2_BUFFER 구조를 채웁다.
buffer.AudioBytes = dwChunkSize; //size of the audio buffer in bytes buffer.pAudioData = pDataBuffer; //buffer containing audio data buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer