MonoGame XACT crashes with a SharpDX Exception when ADPCM compression is enabled - Csharp

When using XACT with monogame I expected to not be able to use xWMA (sadly) and I can live with the massive files of ADPCM for the most part with disk streaming. But when I change from PCM to ADPCM my game crashes when trying to play a Cue. With the following exception.

{SharpDX.SharpDXException: HRESULT: [0x88960001], Module: [SharpDX.XAudio2], ApiCode: [XAUDIO2_E_INVALID_CALL/InvalidCall], Message: Unknown
   at SharpDX.XAudio2.XAudio2.CreateSourceVoice_(SourceVoice sourceVoiceOut, IntPtr sourceFormatRef, VoiceFlags flags, Single maxFrequencyRatio, IntPtr callbackRef, Nullable`1 sendListRef, Nullable`1 effectChainRef)
   at SharpDX.XAudio2.SourceVoice.CreateSourceVoice(XAudio2 device, WaveFormat sourceFormat, VoiceFlags flags, Single maxFrequencyRatio, IntPtr callback, EffectDescriptor[] effectDescriptors)
   at SharpDX.XAudio2.SourceVoice..ctor(XAudio2 device, WaveFormat sourceFormat, VoiceFlags flags, Single maxFrequencyRatio)
   at Microsoft.Xna.Framework.Audio.SoundEffect.PlatformSetupInstance(SoundEffectInstance inst)}

My platform is UWP, running on the latest windows 10, fast ring.

I would expect this to be supported, and unlike xWMA it doesn't throw a not supported exception. So I assume it is either a bug or I am doing something wrong somehow.

Asked Oct 23 '21 15:10
avatar SirDragonClaw
SirDragonClaw

9 Answer:

I think i may have figured this out.

Anyone have a moment to test this code change to SoundEffect.XAudio.cs:

private void PlatformInitializeXact(MiniFormatTag codec, byte[] buffer, int channels, int sampleRate, int blockAlignment, int loopStart, int loopLength, out TimeSpan duration)
{
  if (codec == MiniFormatTag.Adpcm)
  {
    duration = TimeSpan.FromSeconds((float)loopLength / sampleRate);

    CreateBuffers(  new WaveFormatAdpcm(sampleRate, channels, (blockAlignment + 22) * channels), // CHANGED!
      ToDataStream(0, buffer, buffer.Length),
      loopStart,
      loopLength);

    return;
  }

  throw new NotSupportedException("Unsupported sound format!");
}

Then try to play some XACT sounds that have been generated with ADPCM compression.

I suspect this fixes things.

@SeriousMartin @Danthekilla ?

1
Answered Aug 05 '18 at 00:32
avatar  of tomspilman
tomspilman

Took me a while to compile ffmpeg on my windows system. MSYS2 did the trick, but it some dependencies wont be included in the compiled exe. Still ok for testing.

I changed the BLKSIZE constant in ffmpeg's adpcm.h to 512 and it still didn't work with XAudio.

So I took a closer look at the code. Turns out that the BLKSIZE constant is actually used to set the blockalign value. Microsoft measues the size of a block in samples (https://msdn.microsoft.com/de-de/library/windows/desktop/ee415711(v=vs.85).aspx). This seems to be different from the blockalign used in adpcmenc.c. My impression is that frame_size is instead what has to be between 32 and 512.

I tested this by setting BLKSIZE to 70. With my mono wave file this resulted in a frame_size of 128 = (BLKSIZE - 7 * avctx->channels) * 2 / avctx->channels + 2.

The resulting compressed file is working with XAudio.

I am very unsure if this is the right thing to do.

1
Answered Jan 27 '18 at 14:14
avatar  of SeriousMartin
SeriousMartin

I ran into the same problem, updating to build 1041 from 362.

Might have something to do with the state of the device.

In addition I wonder whether this has something to do with the SamplesPerBlock value that is not between 32 and 512 as stated here: https://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.xaudio2.adpcmwaveformat(v=vs.85).aspx

Here is a an example of a values that go into the SourceVoice constructor when the crash happens

adpcmformat

Any suggestions on this one?

1
Answered Nov 09 '17 at 09:29
avatar  of SeriousMartin
SeriousMartin

@SeriousMartin

In addition I wonder whether this has something to do with the SamplesPerBlock value that is not between 32 and 512

Indeed, the ADPCM generated by ffmpeg are unuseable by XAudio. I posted an enhancement request about that here https://trac.ffmpeg.org/ticket/6585 It will probably take years until someone look at it. Meanwhile we need an alternative.

1
Answered Nov 09 '17 at 11:31
avatar  of nkast
nkast

@nkast Do you know how this worked before? The used ffmpeg version hasn't changed for years. Did microsoft change the xaudio2 adpcm requirement?

Looks like AdpcmEncode is a suitable commandline tool to do the job: https://msdn.microsoft.com/de-de/library/windows/desktop/ee415711(v=vs.85).aspx.

This means for the purpose of Adpcm encoding it would be necessary to let the processor decode to wave first and then use AdpcmEncode.

1
Answered Nov 10 '17 at 07:33
avatar  of SeriousMartin
SeriousMartin

FFMPEG is unfortunately hard-coded to that sample block size. I wrote MS-ADPCM and IMA/ADPCM decompression for platforms that don't support one or either of those formats. It may probably be more reliable to write our own compressors for those formats as well. The AdpcmEncode tool is only in the DirectX SDK on Windows.

1
Answered Nov 10 '17 at 14:33
avatar  of KonajuGames
KonajuGames

I am confused here.

We have been using FFMPEG to convert PCM to MSADPCM since 2014. Any games built in that time using compressed audio have used MSADPCM audio compressed by FFMPEG.

So how is it that suddenly FFMPEG doesn't work for MSADPCM used by XAudio2?

What has changed?

1
Answered Nov 10 '17 at 14:38
avatar  of tomspilman
tomspilman

Previously, our XACT support always decompressed ADPCM at load. A quick fix to this for now would be to always make it decompress ADPCM on DirectX platforms if the SampleBlockSize is greater than 512. Then we do our own MS-ADPCM compression and re-enable it.

When I did that last major update to audio, I extensively tested every format on both DirectX and OpenAL. Running it now, it fails with this SharpDX exception straight up. FFMPEG's hard-coded sample block size (during that audio update I even checked FFMPEG's source code to see if the sample block size could be specified) is outside the range specified in the MS documentation for XAudio2.

I also realised that while we import, process and load a range of audio formats in our tests, we don't actually play any of them. This would have shown the error sooner. I can add that too with the changes mentioned above.

1
Answered Nov 10 '17 at 15:24
avatar  of KonajuGames
KonajuGames

Previously, our XACT support always decompressed ADPCM at load.

What is the time period on this "previously"? We have been using compressed MSADPCM with XAct for years now.

But actually... the original issue has nothing to do with FFMEPG now that i think of it. @Danthekilla was using XACT and MonoGame does not process XACT audio in any way. We use XACT content built from the official Microsoft XACT tool which does not use FFMPEG and hasn't changed for over 6 years now.

@SeriousMartin - Was your issue with a sound from XACT? Or was it from a sound assets generated by the MG content pipeline?

make it decompress ADPCM on DirectX platforms if the SampleBlockSize is greater than 512. Then we do our own MS-ADPCM compression and re-enable it.

That could add minutes of startup time to some projects... that really isn't a good runtime solution for us.

When I did that last major update to audio,

That was merged only 2 months ago https://github.com/MonoGame/MonoGame/pull/5750 .... so why does it fail now and not 2 months ago?

1
Answered Nov 10 '17 at 15:42
avatar  of tomspilman
tomspilman