locked
Audio Files

    Question

  • I've got a somewhat simple problem.  I'm trying to play audio files through a DirectX game using XAudio2.  Because this is a Windows Store app, I'm using the SoundFileReader downloaded from here, in order to read the wave files.  Although, for some reason some the waves seam to cause an exception at this line of code:

    // Find, read and validate the format chunk (a child within the RIFF chunk).
        uint64 formatLoc = FindChunk(riffFile, FOURCC_FORMAT_TAG, riffChildrenStart, riffChildrenEnd);
        ReadHeader(riffFile, formatLoc, chunkHeader);
        if (chunkHeader.size < sizeof(WAVEFORMATEX))
        {
            // Format data of unsupported size; must be unsupported format.
            throw ref new Platform::FailureException();
        }

    I've used these waves in other projects.  If the problem is with the waves, could someone tell me how to format them into something acceptable.

    Thanks.

    Monday, October 15, 2012 4:43 PM

Answers

  • You need to provide the full details on the WAVEFORMAT you are actually using in these .WAVs.

    Here's a little command-line utility you can build and use to dump out the details for debugging...

    #include <windows.h>
    
    #include <stdio.h>
    #include <mmsystem.h>
    #include <mmreg.h>
    #include <ks.h>
    #include <ksmedia.h>
    
    #pragma comment(lib,"winmm.lib")
    
    class ScopedMMHandle
    {
    public:
        explicit ScopedMMHandle( HMMIO handle ) : _handle(handle) {}
        ~ScopedMMHandle()
        {
            if ( _handle != 0 )
            {
                mmioClose( _handle, 0 );
                _handle = 0;
            }
        }
    
        bool IsValid() const { return (_handle != 0); }
        HMMIO Get() const { return _handle; }
    
    private:
        HMMIO _handle;
    };
    
    template<class T> class ScopedArray
    {
    public:
        explicit ScopedArray( T *p = 0 ) : _pointer(p) {}
        ~ScopedArray()
        {
            delete [] _pointer;
            _pointer = nullptr;
        }
    
        bool IsNull() const { return (!_pointer); }
    
        T& operator[]( ptrdiff_t i ) const { return _pointer[i]; }
    
        void Reset(T *p = 0) { delete[] _pointer; _pointer = p; }
    
        T* Get() const { return _pointer; }
    
    private:
        ScopedArray(const ScopedArray&);
        ScopedArray& operator=(const ScopedArray&);
            
        T* _pointer;
    };
    
    int main(int argc, const char** argv)
    {
        if ( argc < 2 || argc > 2 )
        {
            printf("Usage: wavdump <filename.wav>\n");
            return 0;
        }
    
        ScopedMMHandle h( mmioOpen( (LPSTR)argv[1], NULL, MMIO_ALLOCBUF | MMIO_READ ) );
        if ( !h.IsValid() )
        {
            printf("Failed opening %s\n", argv[1] );
            return 1;
        }
    
        // Validate file is a WAVE
        MMCKINFO riff;
        memset( &riff, 0, sizeof(riff) );
    
        if ( mmioDescend( h.Get(), &riff, NULL, 0 ) != 0 )
        {
            printf("Failed validating file %s\n", argv[1] );
            return 1;
        }
    
        if ( (riff.ckid != FOURCC_RIFF) || ( riff.fccType != mmioFOURCC( 'W', 'A', 'V','E' ) ) )
        {
            printf("Not a wave file: %s\n", argv[1] );
            return 1;
        }
    
        // find 'fmt ' chunk
        MMCKINFO c;
        memset( &c, 0, sizeof(c) );
    
        c.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
        if ( mmioDescend( h.Get(), &c, &riff, MMIO_FINDCHUNK ) != 0 )
        {
            printf("Failed to find 'fmt ' chunk in wave file %s\n", argv[1] );
            return 1;
        }
    
        if ( c.cksize < sizeof( WAVEFORMAT ) )
        {
            printf("Header size is only %d bytes for wave file %s\n", c.cksize, argv[1] );
            return 1;
        }
    
        ScopedArray<BYTE> chunk( new BYTE[c.cksize] );
        if ( chunk.IsNull () )
        {
            printf("Out of memory loading %d bytes", c.cksize);
            return 1;
        }
    
        if ( (ULONG)mmioRead( h.Get(), (HPSTR)chunk.Get(), c.cksize ) != c.cksize )
        {
            printf("Failed reading %d header bytes from wave file %s\n", c.cksize, argv[1] );
            return 1;
        }
    
        printf("riff 'WAVE', chunk 'fmt ', %d bytes\n", c.cksize);
    
        const WAVEFORMAT* header = reinterpret_cast<const WAVEFORMAT*>( chunk.Get() );
    
        switch( header->wFormatTag )
        {
        case WAVE_FORMAT_PCM:
            printf("format tag %d (PCM)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_ADPCM:
            printf("format tag %d (MS ADPCM)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_EXTENSIBLE:
            printf("format tag %d (EXTENSIBLE)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_IEEE_FLOAT:
            printf("format tag %d (IEEE float)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_MPEGLAYER3:
            printf("format tag %d (ISO/MPEG Layer3)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_DOLBY_AC3_SPDIF:
            printf("format tag %d (Dolby Audio Codec 3 over S/PDIF)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMAUDIO2:
            printf("format tag %d (Windows Media Audio)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMAUDIO3:
            printf("format tag %d (Windows Media Audio Pro)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMASPDIF:
            printf("format tag %d (Windows Media Audio over S/PDIF)\n", header->wFormatTag );
            break;
    
        case 0x165: /*WAVE_FORMAT_XMA*/
            printf("format tag %d (Xbox 360 XMA)\n", header->wFormatTag );
            break;
    
        case 0x166: /*WAVE_FORMAT_XMA2*/
            printf("format tag %d (Xbox 360 XMA2)\n", header->wFormatTag );
            break;
    
        default:
            printf("format tag %d\n", header->wFormatTag );
            break;
        }
    
        printf("number of channels %d\n", header->nChannels );
        if ( header->nChannels < 1 || header->nChannels > 64 )
            printf("ERROR: Expected between 1..64 channels\n");
    
        printf("samples per second %d\n", header->nSamplesPerSec );
        if ( header->nSamplesPerSec < 1000 || header->nSamplesPerSec > 200000 )
            printf("ERROR: Expected between 1..200kHZ\n");
    
        printf("avg bytes per second %d\n", header->nAvgBytesPerSec );
        printf("sample block size %d bytes\n", header->nBlockAlign );
    
        switch( header->wFormatTag )
        {
        case WAVE_FORMAT_PCM:
        case WAVE_FORMAT_IEEE_FLOAT:
            if ( c.cksize < sizeof(PCMWAVEFORMAT) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const PCMWAVEFORMAT* pcm = reinterpret_cast<const PCMWAVEFORMAT*>( chunk.Get() );
                printf("bits per sample %d\n", pcm->wBitsPerSample );
            }
            break;
    
        case WAVE_FORMAT_ADPCM:
            if ( c.cksize < sizeof(ADPCMWAVEFORMAT) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const ADPCMWAVEFORMAT* adpcm = reinterpret_cast<const ADPCMWAVEFORMAT*>( chunk.Get() );
                printf("bits per sample %d\n", adpcm->wfx.wBitsPerSample );
                printf("extra bytes %d\n", adpcm->wfx.cbSize );
                printf("samples per block %d\n", adpcm->wSamplesPerBlock );
                printf("number of coefficients %d\n", adpcm->wNumCoef );
                if ( adpcm->wNumCoef != 7 )
                   printf("ERROR: MS ADPCM expected to have 7 coefficients\n");
            }
            break;
    
        case WAVE_FORMAT_EXTENSIBLE:
            if ( c.cksize < sizeof(WAVEFORMATEXTENSIBLE) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const WAVEFORMATEXTENSIBLE* ext = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>( chunk.Get() );
                printf("bits per sample %d\n", ext->Format.wBitsPerSample );
                printf("extra bytes %d\n", ext->Format.cbSize );
                printf("valid bits-per-sample / samples per block / reserved %d\n", ext->Samples.wReserved );
                printf("channel mask %08X\n", ext->dwChannelMask );
                printf("Subformat GUID %08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X", ext->SubFormat.Data1, ext->SubFormat.Data2, ext->SubFormat.Data3, 
                       ext->SubFormat.Data4[0], ext->SubFormat.Data4[1], ext->SubFormat.Data4[2], ext->SubFormat.Data4[3], 
                       ext->SubFormat.Data4[4], ext->SubFormat.Data4[5], ext->SubFormat.Data4[6], ext->SubFormat.Data4[7] );
                if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0 )
                    printf(" (PCM)\n");
                else if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0 )
                    printf(" (IEEE float)\n");
                else if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_ADPCM, sizeof(GUID) ) == 0 )
                    printf(" (MS ADPCM)\n");
                else
                    printf("\n");
            }
            break;
        }
    }

    NOTE: This is a Win32 desktop program, so you need VS 2012 Pro+, VS 2012 for Desktop, or VS 2010 to build it.
    Monday, October 15, 2012 9:06 PM

All replies

  • You need to provide the full details on the WAVEFORMAT you are actually using in these .WAVs.

    Here's a little command-line utility you can build and use to dump out the details for debugging...

    #include <windows.h>
    
    #include <stdio.h>
    #include <mmsystem.h>
    #include <mmreg.h>
    #include <ks.h>
    #include <ksmedia.h>
    
    #pragma comment(lib,"winmm.lib")
    
    class ScopedMMHandle
    {
    public:
        explicit ScopedMMHandle( HMMIO handle ) : _handle(handle) {}
        ~ScopedMMHandle()
        {
            if ( _handle != 0 )
            {
                mmioClose( _handle, 0 );
                _handle = 0;
            }
        }
    
        bool IsValid() const { return (_handle != 0); }
        HMMIO Get() const { return _handle; }
    
    private:
        HMMIO _handle;
    };
    
    template<class T> class ScopedArray
    {
    public:
        explicit ScopedArray( T *p = 0 ) : _pointer(p) {}
        ~ScopedArray()
        {
            delete [] _pointer;
            _pointer = nullptr;
        }
    
        bool IsNull() const { return (!_pointer); }
    
        T& operator[]( ptrdiff_t i ) const { return _pointer[i]; }
    
        void Reset(T *p = 0) { delete[] _pointer; _pointer = p; }
    
        T* Get() const { return _pointer; }
    
    private:
        ScopedArray(const ScopedArray&);
        ScopedArray& operator=(const ScopedArray&);
            
        T* _pointer;
    };
    
    int main(int argc, const char** argv)
    {
        if ( argc < 2 || argc > 2 )
        {
            printf("Usage: wavdump <filename.wav>\n");
            return 0;
        }
    
        ScopedMMHandle h( mmioOpen( (LPSTR)argv[1], NULL, MMIO_ALLOCBUF | MMIO_READ ) );
        if ( !h.IsValid() )
        {
            printf("Failed opening %s\n", argv[1] );
            return 1;
        }
    
        // Validate file is a WAVE
        MMCKINFO riff;
        memset( &riff, 0, sizeof(riff) );
    
        if ( mmioDescend( h.Get(), &riff, NULL, 0 ) != 0 )
        {
            printf("Failed validating file %s\n", argv[1] );
            return 1;
        }
    
        if ( (riff.ckid != FOURCC_RIFF) || ( riff.fccType != mmioFOURCC( 'W', 'A', 'V','E' ) ) )
        {
            printf("Not a wave file: %s\n", argv[1] );
            return 1;
        }
    
        // find 'fmt ' chunk
        MMCKINFO c;
        memset( &c, 0, sizeof(c) );
    
        c.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
        if ( mmioDescend( h.Get(), &c, &riff, MMIO_FINDCHUNK ) != 0 )
        {
            printf("Failed to find 'fmt ' chunk in wave file %s\n", argv[1] );
            return 1;
        }
    
        if ( c.cksize < sizeof( WAVEFORMAT ) )
        {
            printf("Header size is only %d bytes for wave file %s\n", c.cksize, argv[1] );
            return 1;
        }
    
        ScopedArray<BYTE> chunk( new BYTE[c.cksize] );
        if ( chunk.IsNull () )
        {
            printf("Out of memory loading %d bytes", c.cksize);
            return 1;
        }
    
        if ( (ULONG)mmioRead( h.Get(), (HPSTR)chunk.Get(), c.cksize ) != c.cksize )
        {
            printf("Failed reading %d header bytes from wave file %s\n", c.cksize, argv[1] );
            return 1;
        }
    
        printf("riff 'WAVE', chunk 'fmt ', %d bytes\n", c.cksize);
    
        const WAVEFORMAT* header = reinterpret_cast<const WAVEFORMAT*>( chunk.Get() );
    
        switch( header->wFormatTag )
        {
        case WAVE_FORMAT_PCM:
            printf("format tag %d (PCM)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_ADPCM:
            printf("format tag %d (MS ADPCM)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_EXTENSIBLE:
            printf("format tag %d (EXTENSIBLE)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_IEEE_FLOAT:
            printf("format tag %d (IEEE float)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_MPEGLAYER3:
            printf("format tag %d (ISO/MPEG Layer3)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_DOLBY_AC3_SPDIF:
            printf("format tag %d (Dolby Audio Codec 3 over S/PDIF)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMAUDIO2:
            printf("format tag %d (Windows Media Audio)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMAUDIO3:
            printf("format tag %d (Windows Media Audio Pro)\n", header->wFormatTag );
            break;
    
        case WAVE_FORMAT_WMASPDIF:
            printf("format tag %d (Windows Media Audio over S/PDIF)\n", header->wFormatTag );
            break;
    
        case 0x165: /*WAVE_FORMAT_XMA*/
            printf("format tag %d (Xbox 360 XMA)\n", header->wFormatTag );
            break;
    
        case 0x166: /*WAVE_FORMAT_XMA2*/
            printf("format tag %d (Xbox 360 XMA2)\n", header->wFormatTag );
            break;
    
        default:
            printf("format tag %d\n", header->wFormatTag );
            break;
        }
    
        printf("number of channels %d\n", header->nChannels );
        if ( header->nChannels < 1 || header->nChannels > 64 )
            printf("ERROR: Expected between 1..64 channels\n");
    
        printf("samples per second %d\n", header->nSamplesPerSec );
        if ( header->nSamplesPerSec < 1000 || header->nSamplesPerSec > 200000 )
            printf("ERROR: Expected between 1..200kHZ\n");
    
        printf("avg bytes per second %d\n", header->nAvgBytesPerSec );
        printf("sample block size %d bytes\n", header->nBlockAlign );
    
        switch( header->wFormatTag )
        {
        case WAVE_FORMAT_PCM:
        case WAVE_FORMAT_IEEE_FLOAT:
            if ( c.cksize < sizeof(PCMWAVEFORMAT) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const PCMWAVEFORMAT* pcm = reinterpret_cast<const PCMWAVEFORMAT*>( chunk.Get() );
                printf("bits per sample %d\n", pcm->wBitsPerSample );
            }
            break;
    
        case WAVE_FORMAT_ADPCM:
            if ( c.cksize < sizeof(ADPCMWAVEFORMAT) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const ADPCMWAVEFORMAT* adpcm = reinterpret_cast<const ADPCMWAVEFORMAT*>( chunk.Get() );
                printf("bits per sample %d\n", adpcm->wfx.wBitsPerSample );
                printf("extra bytes %d\n", adpcm->wfx.cbSize );
                printf("samples per block %d\n", adpcm->wSamplesPerBlock );
                printf("number of coefficients %d\n", adpcm->wNumCoef );
                if ( adpcm->wNumCoef != 7 )
                   printf("ERROR: MS ADPCM expected to have 7 coefficients\n");
            }
            break;
    
        case WAVE_FORMAT_EXTENSIBLE:
            if ( c.cksize < sizeof(WAVEFORMATEXTENSIBLE) )
            {
                printf("Header is too small to be valid in wave file %s\n", argv[1] );
                return 1;
            }
            else
            {
                const WAVEFORMATEXTENSIBLE* ext = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>( chunk.Get() );
                printf("bits per sample %d\n", ext->Format.wBitsPerSample );
                printf("extra bytes %d\n", ext->Format.cbSize );
                printf("valid bits-per-sample / samples per block / reserved %d\n", ext->Samples.wReserved );
                printf("channel mask %08X\n", ext->dwChannelMask );
                printf("Subformat GUID %08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X", ext->SubFormat.Data1, ext->SubFormat.Data2, ext->SubFormat.Data3, 
                       ext->SubFormat.Data4[0], ext->SubFormat.Data4[1], ext->SubFormat.Data4[2], ext->SubFormat.Data4[3], 
                       ext->SubFormat.Data4[4], ext->SubFormat.Data4[5], ext->SubFormat.Data4[6], ext->SubFormat.Data4[7] );
                if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0 )
                    printf(" (PCM)\n");
                else if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0 )
                    printf(" (IEEE float)\n");
                else if ( memcmp( &ext->SubFormat, &KSDATAFORMAT_SUBTYPE_ADPCM, sizeof(GUID) ) == 0 )
                    printf(" (MS ADPCM)\n");
                else
                    printf("\n");
            }
            break;
        }
    }

    NOTE: This is a Win32 desktop program, so you need VS 2012 Pro+, VS 2012 for Desktop, or VS 2010 to build it.
    Monday, October 15, 2012 9:06 PM
  • I fixed the problem by changing the wav files to 32 bit.
    Friday, October 26, 2012 4:52 PM