방법: XAudio2에 오디오 데이터 파일 로드

참고

이 콘텐츠는 데스크톱 앱에만 적용되며 Windows 스토어 앱에서 작동하려면 수정 버전이 필요합니다. CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerExGetOverlappedResultEx에 대한 설명서를 참조하세요. Windows SDK 샘플 갤러리의 BasicSound Windows 8 샘플에서 SoundFileReader.h/.cpp를 참조하세요.

 

이 항목에서는 XAudio2에서 오디오 데이터를 재생하는 데 필요한 구조를 채우는 단계를 설명합니다. 다음 단계에서는 오디오 파일의 'fmt' 및 'data' 청크를 로드하고 이를 사용하여 WAVEFORMATEXTENSIBLE 구조체와 XAUDIO2_BUFFER 구조를 채웁니다.

오디오 파일 구문 분석 준비

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(리소스 교환 파일 형식)에 설명된 대로 추가 청크 형식이 포함될 수 있습니다.

  1. WAVEFORMATEXTENSIBLEXAUDIO2_BUFFER 구조체를 선언합니다.

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. 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() );
    
  3. 오디오 파일에서 '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;
    
  4. 'fmt' 청크를 찾아 해당 내용을 WAVEFORMATEXTENSIBLE 구조체로 복사합니다.

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. '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);
    
  6. 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
    

시작

방법: XAudio2를 사용한 소리 재생

XAudio2 프로그래밍 참조