0

I am trying to load a *.wav file that is a microsoft wav/8bit pcm file. I am using the following code to load the data:

class WavFile : public AudioSource, public LoadableObject
{
public:
    WavFile( void )
        : AudioSource()
        , LoadableObject()
    { }

    virtual concurrency::task<void> Load( Platform::String^ path )
    {
        buffer = nullptr;

        BasicReaderWriter^ rw = ref new BasicReaderWriter();
        return rw->ReadDataAsync( path ).then([this, path]( const Platform::Array<byte>^ arr ){

            DWORD chunkId = 0, fileSize = 0, chunkSize = 0, extra = 0;

            ByteStream stream( arr );

            stream.ReadData( &chunkId, sizeof( chunkId ) );
            //chunkId = stream.ReadDWORD();
            char test[4];
            for(unsigned int i=0; i <4; i++)
                test[i] = ((char *)&chunkId)[i];
            if ( chunkId != 'FFIR' ) throw ref new Platform::FailureException( L"Could not get RIFF chunk in file " + path + L", chunkId=" + chunkId.ToString() );

            fileSize = stream.ReadDWORD();
            if ( fileSize <= 16 ) throw ref new Platform::FailureException( L"Wave file size is too small; " + path );

            extra = stream.ReadDWORD();
            for(unsigned int i=0; i <4; i++)
                test[i] = ((char *)&extra)[i];
            if ( extra != 'EVAW' ) throw ref new Platform::FailureException( L"Could not get WAVE chunk in file " + path + L", chunkId=" + chunkId.ToString() );

            bool formatChunk = false;
            for(unsigned int i = 12; i < fileSize; )
            {
                stream.Seek( i, true );
                chunkId = stream.ReadDWORD();
                stream.Seek( i + 4, true );
                chunkSize = stream.ReadDWORD();
                if ( chunkId = ' tmf' )
                {
                    stream.Seek( i + 8, true );
                    stream.ReadData( &waveFormat, sizeof( WAVEFORMATEX ) );
                    formatChunk = true;
                    break;
                }

                chunkSize += 8 + 1;
                chunkSize &= 0xfffffffe;
                stream.Seek( chunkSize, false );
                i += chunkSize;
            }
            if ( !formatChunk ) throw ref new Platform::FailureException( L"Could not get fmt chunk in file " + path );

            bool filledData = false;
            for(unsigned int j=12; j < fileSize; )
            {
                stream.Seek( j, true );
                chunkId = stream.ReadDWORD();
                for(unsigned int i=0; i <4; i++)
                    test[i] = ((char *)&chunkId)[i];
                stream.Seek( j + 4, true );
                chunkSize = stream.ReadDWORD();
                if ( chunkId == 'atad' )
                {
                    byte *bufferData = new byte[chunkSize];
                    stream.Seek( j + 8, true );
                    stream.ReadData( bufferData, chunkSize );
                    buffer = ref new Platform::Array<byte>( bufferData, (unsigned int)chunkSize );
                    delete bufferData;

                    xbuffer.AudioBytes = chunkSize;
                    xbuffer.pAudioData = buffer->Data;
                    xbuffer.PlayBegin = 0;
                    xbuffer.PlayLength = 0;

                    filledData = true;
                    break;
                }
                chunkSize += 8 + 1;
                chunkSize &= 0xfffffffe;
                j += chunkSize;
            }
            if ( !filledData ) throw ref new Platform::FailureException( L"Could not find data chunk in file " + path );

        });
    }
};

It parses the wav file properly, and here is what the WAVEFORMATEX data looks like:

{ wFormatTag=1, nChannels=2, nSamplesPerSec=22050, nAvgBytesPerSec=44100, nBlockAlign=2, wBitsPerSample=8, cbSize=24932 }

When I call instance->CreateSourceVoice( &voice, wave->GetWaveFormat(), 0, XAUDIO2_DEFAULT_FREQ_RATIO, reinterpret_cast<IXAudio2VoiceCallback*>( &voiceIn[id]->callbacks ) ), I get HRESULT=0x88960001, where instance is of the type IXAudio2*, which I encompass in a class where it is statically shared in the class and initialized/destroyed with my class constructor/destructor:

AudioManager::AudioManager(void)
{
    instance_count++;
    if ( instance == nullptr )
    {
        DX::ThrowIfFailed( XAudio2Create( &instance, 0 ) );
    }
}


AudioManager::~AudioManager(void)
{
    /* Remove all the voices that were added in this audio manager */

    instance_count--;
    if ( instance_count == 0 )
    {
        HaltAudio();
        instance->Release();
        instance = nullptr;
    }
}

I have read in multiple places that this HRESULT is some sort of Windows 8 bug which has not been fixed for more than a year. I can't accept that this is an ongoing bug and more inclined to think this is an issue with my code. You can check out my full implemention for XAudio2 in this gist.

OzBarry
  • 1,098
  • 1
  • 17
  • 44
  • That's XAUDIO2_E_INVALID_CALL, it doesn't like an argument value you passed. – Hans Passant Mar 01 '13 at 02:06
  • Ah, so I wasn't creating a mastering voice first, which apparently needs to be in place. I'm surprised there isn't a better HRESULT value to describe this situation. – OzBarry Mar 01 '13 at 14:34

1 Answers1

1

When setting the sendList of an XAudio2SourceVoice* to NULL, the IXAudio2 interface must have at least one mastering voice already set.

OzBarry
  • 1,098
  • 1
  • 17
  • 44