Set channel labels from WFX channel masks

This commit is contained in:
Chris Robinson
2020-06-15 18:50:59 -07:00
parent c142b49981
commit bd0144065a
5 changed files with 129 additions and 118 deletions
+55
View File
@@ -6,12 +6,20 @@
#include <atomic>
#include <thread>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmreg.h>
#endif
#include "AL/al.h"
#include "alcmain.h"
#include "alexcpt.h"
#include "alnumeric.h"
#include "aloptional.h"
#include "atomic.h"
#include "logging.h"
bool BackendBase::reset()
@@ -140,3 +148,50 @@ void BackendBase::setDefaultChannelOrder()
break;
}
}
#ifdef _WIN32
void BackendBase::setChannelOrderFromWFXMask(ALuint chanmask)
{
auto get_channel = [](const DWORD chanbit) noexcept -> al::optional<Channel>
{
switch(chanbit)
{
case SPEAKER_FRONT_LEFT: return al::make_optional(FrontLeft);
case SPEAKER_FRONT_RIGHT: return al::make_optional(FrontRight);
case SPEAKER_FRONT_CENTER: return al::make_optional(FrontCenter);
case SPEAKER_LOW_FREQUENCY: return al::make_optional(LFE);
case SPEAKER_BACK_LEFT: return al::make_optional(BackLeft);
case SPEAKER_BACK_RIGHT: return al::make_optional(BackRight);
case SPEAKER_FRONT_LEFT_OF_CENTER: break;
case SPEAKER_FRONT_RIGHT_OF_CENTER: break;
case SPEAKER_BACK_CENTER: return al::make_optional(BackCenter);
case SPEAKER_SIDE_LEFT: return al::make_optional(SideLeft);
case SPEAKER_SIDE_RIGHT: return al::make_optional(SideRight);
case SPEAKER_TOP_CENTER: return al::make_optional(TopCenter);
case SPEAKER_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft);
case SPEAKER_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter);
case SPEAKER_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight);
case SPEAKER_TOP_BACK_LEFT: return al::make_optional(TopBackLeft);
case SPEAKER_TOP_BACK_CENTER: return al::make_optional(TopBackCenter);
case SPEAKER_TOP_BACK_RIGHT: return al::make_optional(TopBackRight);
}
WARN("Unhandled WFX channel bit 0x%lx\n", chanbit);
return al::nullopt;
};
const ALuint numchans{mDevice->channelsFromFmt()};
ALuint idx{0};
while(chanmask)
{
const int bit{CTZ32(chanmask)};
const ALuint mask{1u << bit};
chanmask &= ~mask;
if(auto label = get_channel(mask))
{
mDevice->RealOut.ChannelIndex[*label] = idx;
if(++idx == numchans) break;
}
}
}
#endif
+5
View File
@@ -40,6 +40,11 @@ protected:
void setDefaultChannelOrder();
/** Sets the default channel order used by WaveFormatEx. */
void setDefaultWFXChannelOrder();
#ifdef _WIN32
/** Sets the channel order given the WaveFormatEx mask. */
void setChannelOrderFromWFXMask(ALuint chanmask);
#endif
};
using BackendPtr = std::unique_ptr<BackendBase>;
+48 -103
View File
@@ -108,6 +108,14 @@ HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallbac
#endif
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define MAX_UPDATES 128
struct DevMap {
@@ -358,23 +366,23 @@ bool DSoundPlayback::reset()
switch(mDevice->FmtType)
{
case DevFmtByte:
mDevice->FmtType = DevFmtUByte;
break;
case DevFmtFloat:
if(mDevice->Flags.get<SampleTypeRequest>())
break;
/* fall-through */
case DevFmtUShort:
mDevice->FmtType = DevFmtShort;
break;
case DevFmtUInt:
mDevice->FmtType = DevFmtInt;
break;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtByte:
mDevice->FmtType = DevFmtUByte;
break;
case DevFmtFloat:
if(mDevice->Flags.get<SampleTypeRequest>())
break;
/* fall-through */
case DevFmtUShort:
mDevice->FmtType = DevFmtShort;
break;
case DevFmtUInt:
mDevice->FmtType = DevFmtInt;
break;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
break;
}
WAVEFORMATEXTENSIBLE OutputType{};
@@ -400,62 +408,20 @@ bool DSoundPlayback::reset()
else
ERR("Unknown system speaker config: 0x%lx\n", speakers);
}
mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo &&
speakers == DSSPEAKER_HEADPHONE);
mDevice->IsHeadphones = mDevice->FmtChans == DevFmtStereo
&& speakers == DSSPEAKER_HEADPHONE;
switch(mDevice->FmtChans)
{
case DevFmtMono:
OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
case DevFmtAmbi3D:
mDevice->FmtChans = DevFmtStereo;
/*fall-through*/
case DevFmtStereo:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT;
break;
case DevFmtQuad:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX51:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX51Rear:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_CENTER |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX71:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtMono: OutputType.dwChannelMask = MONO; break;
case DevFmtAmbi3D: mDevice->FmtChans = DevFmtStereo;
/*fall-through*/
case DevFmtStereo: OutputType.dwChannelMask = STEREO; break;
case DevFmtQuad: OutputType.dwChannelMask = QUAD; break;
case DevFmtX51: OutputType.dwChannelMask = X5DOT1; break;
case DevFmtX51Rear: OutputType.dwChannelMask = X5DOT1REAR; break;
case DevFmtX61: OutputType.dwChannelMask = X6DOT1; break;
case DevFmtX71: OutputType.dwChannelMask = X7DOT1; break;
}
retry_open:
@@ -507,8 +473,8 @@ retry_open:
DSBUFFERDESC DSBDescription{};
DSBDescription.dwSize = sizeof(DSBDescription);
DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_GLOBALFOCUS;
DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2
| DSBCAPS_GLOBALFOCUS;
DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign;
DSBDescription.lpwfxFormat = &OutputType.Format;
@@ -526,8 +492,7 @@ retry_open:
hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr);
if(SUCCEEDED(hr))
{
auto Notifies = static_cast<IDirectSoundNotify*>(ptr);
mNotifies = Notifies;
mNotifies = static_cast<IDirectSoundNotify*>(ptr);
ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
assert(num_updates <= MAX_UPDATES);
@@ -538,7 +503,7 @@ retry_open:
nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign;
nots[i].hEventNotify = mNotifyEvent;
}
if(Notifies->SetNotificationPositions(num_updates, nots.data()) != DS_OK)
if(mNotifies->SetNotificationPositions(num_updates, nots.data()) != DS_OK)
hr = E_FAIL;
}
}
@@ -558,7 +523,7 @@ retry_open:
}
ResetEvent(mNotifyEvent);
setDefaultWFXChannelOrder();
setChannelOrderFromWFXMask(OutputType.dwChannelMask);
return true;
}
@@ -670,33 +635,13 @@ void DSoundCapture::open(const ALCchar *name)
WAVEFORMATEXTENSIBLE InputType{};
switch(mDevice->FmtChans)
{
case DevFmtMono:
InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
case DevFmtStereo:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
case DevFmtQuad:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX51:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
break;
case DevFmtX51Rear:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
break;
case DevFmtX71:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtMono: InputType.dwChannelMask = MONO; break;
case DevFmtStereo: InputType.dwChannelMask = STEREO; break;
case DevFmtQuad: InputType.dwChannelMask = QUAD; break;
case DevFmtX51: InputType.dwChannelMask = X5DOT1; break;
case DevFmtX51Rear: InputType.dwChannelMask = X5DOT1REAR; break;
case DevFmtX61: InputType.dwChannelMask = X6DOT1; break;
case DevFmtX71: InputType.dwChannelMask = X7DOT1; break;
case DevFmtAmbi3D:
WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans));
throw al::backend_exception{ALC_INVALID_VALUE, "%s capture not supported",
@@ -754,7 +699,7 @@ void DSoundCapture::open(const ALCchar *name)
}
mBufferBytes = DSCBDescription.dwBufferBytes;
setDefaultWFXChannelOrder();
setChannelOrderFromWFXMask(InputType.dwChannelMask);
mDevice->DeviceName = name;
}
+11 -13
View File
@@ -100,9 +100,8 @@ inline constexpr ReferenceTime operator "" _reftime(unsigned long long int n) no
#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER)
constexpr inline uint32_t MaskFromTopBits(uint32_t b) noexcept
constexpr inline DWORD MaskFromTopBits(DWORD b) noexcept
{
b |= b>>1;
b |= b>>2;
@@ -111,14 +110,13 @@ constexpr inline uint32_t MaskFromTopBits(uint32_t b) noexcept
b |= b>>16;
return b;
}
constexpr uint32_t MonoMask{MaskFromTopBits(MONO)};
constexpr uint32_t StereoMask{MaskFromTopBits(STEREO)};
constexpr uint32_t QuadMask{MaskFromTopBits(QUAD)};
constexpr uint32_t X51Mask{MaskFromTopBits(X5DOT1)};
constexpr uint32_t X51RearMask{MaskFromTopBits(X5DOT1REAR)};
constexpr uint32_t X61Mask{MaskFromTopBits(X6DOT1)};
constexpr uint32_t X71Mask{MaskFromTopBits(X7DOT1)};
constexpr uint32_t X71WideMask{MaskFromTopBits(X7DOT1_WIDE)};
constexpr DWORD MonoMask{MaskFromTopBits(MONO)};
constexpr DWORD StereoMask{MaskFromTopBits(STEREO)};
constexpr DWORD QuadMask{MaskFromTopBits(QUAD)};
constexpr DWORD X51Mask{MaskFromTopBits(X5DOT1)};
constexpr DWORD X51RearMask{MaskFromTopBits(X5DOT1REAR)};
constexpr DWORD X61Mask{MaskFromTopBits(X6DOT1)};
constexpr DWORD X71Mask{MaskFromTopBits(X7DOT1)};
#define DEVNAME_HEAD "OpenAL Soft on "
@@ -891,7 +889,7 @@ HRESULT WasapiPlayback::resetProxy()
{
const uint32_t chancount{OutputType.Format.nChannels};
const DWORD chanmask{OutputType.dwChannelMask};
if(chancount >= 8 && ((chanmask&X71Mask)==X7DOT1 || (chanmask&X71WideMask)==X7DOT1_WIDE))
if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1)
mDevice->FmtChans = DevFmtX71;
else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1)
mDevice->FmtChans = DevFmtX61;
@@ -1010,7 +1008,7 @@ HRESULT WasapiPlayback::resetProxy()
mDevice->Frequency = OutputType.Format.nSamplesPerSec;
const uint32_t chancount{OutputType.Format.nChannels};
const DWORD chanmask{OutputType.dwChannelMask};
if(chancount >= 8 && ((chanmask&X71Mask)==X7DOT1 || (chanmask&X71WideMask)==X7DOT1_WIDE))
if(chancount >= 8 && (chanmask&X71Mask) == X7DOT1)
mDevice->FmtChans = DevFmtX71;
else if(chancount >= 7 && (chanmask&X61Mask) == X6DOT1)
mDevice->FmtChans = DevFmtX61;
@@ -1070,7 +1068,7 @@ HRESULT WasapiPlayback::resetProxy()
mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo
&& (formfactor == Headphones || formfactor == Headset));
setDefaultWFXChannelOrder();
setChannelOrderFromWFXMask(OutputType.dwChannelMask);
hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buf_time.count(), 0, &OutputType.Format, nullptr);
+10 -2
View File
@@ -28,6 +28,7 @@
#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <array>
#include <atomic>
@@ -263,7 +264,7 @@ bool WinMMPlayback::reset()
{
mDevice->BufferSize = static_cast<ALuint>(uint64_t{mDevice->BufferSize} *
mFormat.nSamplesPerSec / mDevice->Frequency);
mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3;
mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3u;
mDevice->UpdateSize = mDevice->BufferSize / 4;
mDevice->Frequency = mFormat.nSamplesPerSec;
@@ -295,16 +296,23 @@ bool WinMMPlayback::reset()
return false;
}
ALuint chanmask{};
if(mFormat.nChannels == 2)
{
mDevice->FmtChans = DevFmtStereo;
chanmask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
else if(mFormat.nChannels == 1)
{
mDevice->FmtChans = DevFmtMono;
chanmask = SPEAKER_FRONT_CENTER;
}
else
{
ERR("Unhandled channel count: %d\n", mFormat.nChannels);
return false;
}
setDefaultWFXChannelOrder();
setChannelOrderFromWFXMask(chanmask);
ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()};