WMADecoder now supports multichannel audio

Better WAVE_FORMAT_EXTENSIBLE & channelMask support in WMA & WAV
This commit is contained in:
Grigory Chudov
2013-04-14 16:54:19 -04:00
parent 40f6482077
commit 563f066646
9 changed files with 159 additions and 87 deletions

View File

@@ -24,6 +24,7 @@
SPEAKER_TOP_BACK_CENTER = 0x10000,
SPEAKER_TOP_BACK_RIGHT = 0x20000,
DIRECTOUT = 0,
KSAUDIO_SPEAKER_MONO = (SPEAKER_FRONT_CENTER),
KSAUDIO_SPEAKER_STEREO = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT),
KSAUDIO_SPEAKER_QUAD = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT),
@@ -45,9 +46,9 @@
public int BlockAlign { get { return _channelCount * ((_bitsPerSample + 7) / 8); } }
public SpeakerConfig ChannelMask { get { return _channelMask; } }
public bool IsRedBook { get { return _bitsPerSample == 16 && _channelCount == 2 && _sampleRate == 44100; } }
public SpeakerConfig GetDefaultChannelMask()
public static SpeakerConfig GetDefaultChannelMask(int channelCount)
{
switch (_channelCount)
switch (channelCount)
{
case 1:
return SpeakerConfig.KSAUDIO_SPEAKER_MONO;
@@ -68,15 +69,15 @@
case 8:
return SpeakerConfig.KSAUDIO_SPEAKER_7POINT1_SURROUND;
}
return (SpeakerConfig)((1 << _channelCount) - 1);
return (SpeakerConfig)((1 << channelCount) - 1);
}
public AudioPCMConfig(int bitsPerSample, int channelCount, int sampleRate)
public AudioPCMConfig(int bitsPerSample, int channelCount, int sampleRate, SpeakerConfig channelMask = SpeakerConfig.DIRECTOUT)
{
_bitsPerSample = bitsPerSample;
_channelCount = channelCount;
_sampleRate = sampleRate;
_channelMask = GetDefaultChannelMask();
_channelMask = channelMask == 0 ? GetDefaultChannelMask(channelCount) : channelMask;
}
}
}

View File

@@ -177,13 +177,14 @@ namespace CUETools.Codecs
_br.ReadInt32(); // bytes per second
int _blockAlign = _br.ReadInt16();
int _bitsPerSample = _br.ReadInt16();
int _channelMask = 0;
pos += 16;
if (fmtTag == 0xFFFEU && ckSize >= 34) // WAVE_FORMAT_EXTENSIBLE
{
_br.ReadInt16(); // CbSize
_br.ReadInt16(); // ValidBitsPerSample
int channelMask = _br.ReadInt32();
_channelMask = _br.ReadInt32();
fmtTag = _br.ReadUInt16();
pos += 10;
}
@@ -191,7 +192,7 @@ namespace CUETools.Codecs
if (fmtTag != 1) // WAVE_FORMAT_PCM
throw new Exception("WAVE format tag not WAVE_FORMAT_PCM.");
pcm = new AudioPCMConfig(_bitsPerSample, _channelCount, _sampleRate);
pcm = new AudioPCMConfig(_bitsPerSample, _channelCount, _sampleRate, (AudioPCMConfig.SpeakerConfig)_channelMask);
if (pcm.BlockAlign != _blockAlign)
throw new Exception("WAVE has strange BlockAlign");
}

View File

@@ -75,7 +75,7 @@ namespace CUETools.Codecs
const uint fccFormat = 0x20746D66;
const uint fccData = 0x61746164;
bool wavex = Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24;
bool wavex = (Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24) || Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount);
hdrLen += 36 + (wavex ? 24 : 0) + 8;
@@ -83,7 +83,10 @@ namespace CUETools.Codecs
uint dataLenPadded = dataLen + (dataLen & 1);
_bw.Write(fccRIFF);
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
if (_finalSampleCount <= 0)
_bw.Write((uint)0xffffffff);
else
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
_bw.Write(fccWAVE);
_bw.Write(fccFormat);
if (wavex)
@@ -105,8 +108,8 @@ namespace CUETools.Codecs
{
_bw.Write((ushort)22); // length of WAVEX structure
_bw.Write((ushort)Settings.PCM.BitsPerSample);
_bw.Write((uint)3); // speaker positions (3 == stereo)
_bw.Write((ushort)1); // PCM
_bw.Write((uint)Settings.PCM.ChannelMask);
_bw.Write((ushort)1); // PCM Guid
_bw.Write((ushort)0);
_bw.Write((ushort)0);
_bw.Write((ushort)0x10);
@@ -130,7 +133,10 @@ namespace CUETools.Codecs
}
_bw.Write(fccData);
_bw.Write(dataLen);
if (_finalSampleCount <= 0)
_bw.Write((uint)0xffffffff);
else
_bw.Write(dataLen);
_headersWritten = true;
}
@@ -139,19 +145,19 @@ namespace CUETools.Codecs
{
if (_finalSampleCount <= 0)
{
const long maxFileSize = 0x7FFFFFFEL;
long dataLen = _sampleLen * Settings.PCM.BlockAlign;
if ((dataLen & 1) == 1)
_bw.Write((byte)0);
if (dataLen + hdrLen > maxFileSize)
dataLen = ((maxFileSize - hdrLen) / Settings.PCM.BlockAlign) * Settings.PCM.BlockAlign;
long dataLenPadded = dataLen + (dataLen & 1);
if (dataLenPadded + hdrLen - 8 < 0xffffffff)
{
if ((dataLen & 1) == 1)
_bw.Write((byte)0);
_bw.Seek(4, SeekOrigin.Begin);
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
_bw.Seek(4, SeekOrigin.Begin);
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
_bw.Seek((int)hdrLen - 4, SeekOrigin.Begin);
_bw.Write((uint)dataLen);
_bw.Seek((int)hdrLen - 4, SeekOrigin.Begin);
_bw.Write((uint)dataLen);
}
}
_bw.Close();