snduser: Improve MIX functions

Fixes distorted sound in ZombiU
This commit is contained in:
Exzap
2026-06-05 02:25:42 +02:00
parent d20d701ef0
commit c2d428e5b5
2 changed files with 370 additions and 248 deletions
+353 -242
View File
@@ -12,7 +12,8 @@ namespace snd_user
#define AX_MAX_NUM_DRC (2)
#define AX_MAX_NUM_RMT (4)
#define AX_UPDATE_MODE_10000000 (0x10000000)
#define AX_UPDATE_MODE_8 (0x8)
#define AX_UPDATE_MODE_10000000_INPUT_LEVEL (0x10000000)
#define AX_UPDATE_MODE_20000000 (0x20000000)
#define AX_UPDATE_MODE_40000000_VOLUME (0x40000000)
#define AX_UPDATE_MODE_50000000 (0x50000000)
@@ -21,18 +22,18 @@ namespace snd_user
struct VolumeData
{
sint16 volume; // 0x00
sint16 volume_target; // 0x02
uint16 volume; // 0x00
uint16 volume_target; // 0x02
};
static_assert(sizeof(VolumeData) == 0x4, "sizeof(VolumeData)");
struct MixControl
{
sint16 aux[AX_AUX_BUS_COUNT];
sint16 pan;
sint16 span;
sint16 fader;
sint16 lfe;
sint16be aux[AX_AUX_BUS_COUNT];
sint16be pan;
sint16be span;
sint16be fader;
sint16be lfe;
};
static_assert(sizeof(MixControl) == 0xE, "sizeof(MixControl)");
@@ -131,9 +132,9 @@ namespace snd_user
struct DeviceInfo
{
uint32 tv_sound_mode; // 0x00
uint32 drc_sound_mode; // 0x04
uint32 rmt_sound_mode; // 0x08
MixSoundMode tv_sound_mode;
MixSoundMode drc_sound_mode;
MixSoundMode rmt_sound_mode;
};
struct snd_user_data_t
@@ -147,6 +148,7 @@ namespace snd_user
const uint16 volume[0x388 + 0x3C + 1] =
{
// (uint16)(0x8000 * pow(10.0,(i - 0x388) / 200.0))
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xC,
@@ -175,36 +177,39 @@ namespace snd_user
0xDE70, 0xE103, 0xE39E, 0xE641, 0xE8EB, 0xEB9E, 0xEE58, 0xF11B, 0xF3E6, 0xF6B9, 0xF994, 0xFC78, 0xFF64
};
const uint32 pan_values[128] =
const sint16 pan_values[128] =
{
00, 00,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFC, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFB, 0xFFFFFFFB,
0xFFFFFFFA, 0xFFFFFFFA, 0xFFFFFFF9, 0xFFFFFFF9, 0xFFFFFFF9, 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF7, 0xFFFFFFF7, 0xFFFFFFF6, 0xFFFFFFF6, 0xFFFFFFF6, 0xFFFFFFF5, 0xFFFFFFF5,
0xFFFFFFF4, 0xFFFFFFF4, 0xFFFFFFF3, 0xFFFFFFF3, 0xFFFFFFF2, 0xFFFFFFF2, 0xFFFFFFF2, 0xFFFFFFF1, 0xFFFFFFF1, 0xFFFFFFF0, 0xFFFFFFF0, 0xFFFFFFEF, 0xFFFFFFEF, 0xFFFFFFEE,
0xFFFFFFEE, 0xFFFFFFED, 0xFFFFFFEC, 0xFFFFFFEC, 0xFFFFFFEB, 0xFFFFFFEB, 0xFFFFFFEA, 0xFFFFFFEA, 0xFFFFFFE9, 0xFFFFFFE9, 0xFFFFFFE8, 0xFFFFFFE7, 0xFFFFFFE7, 0xFFFFFFE6,
0xFFFFFFE6, 0xFFFFFFE5, 0xFFFFFFE4, 0xFFFFFFE4, 0xFFFFFFE3, 0xFFFFFFE2, 0xFFFFFFE2, 0xFFFFFFE1, 0xFFFFFFE0, 0xFFFFFFDF, 0xFFFFFFDF, 0xFFFFFFDE, 0xFFFFFFDD, 0xFFFFFFDC,
0xFFFFFFDC, 0xFFFFFFDB, 0xFFFFFFDA, 0xFFFFFFD9, 0xFFFFFFD8, 0xFFFFFFD8, 0xFFFFFFD7, 0xFFFFFFD6, 0xFFFFFFD5, 0xFFFFFFD4, 0xFFFFFFD3, 0xFFFFFFD2, 0xFFFFFFD1, 0xFFFFFFD0,
0xFFFFFFCF, 0xFFFFFFCE, 0xFFFFFFCD, 0xFFFFFFCC, 0xFFFFFFCA, 0xFFFFFFC9, 0xFFFFFFC8, 0xFFFFFFC7, 0xFFFFFFC5, 0xFFFFFFC4, 0xFFFFFFC3, 0xFFFFFFC1, 0xFFFFFFC0, 0xFFFFFFBE,
0xFFFFFFBD, 0xFFFFFFBB, 0xFFFFFFB9, 0xFFFFFFB8, 0xFFFFFFB6, 0xFFFFFFB4, 0xFFFFFFB2, 0xFFFFFFB0, 0xFFFFFFAD, 0xFFFFFFAB, 0xFFFFFFA9, 0xFFFFFFA6, 0xFFFFFFA3, 0xFFFFFFA0,
0xFFFFFF9D, 0xFFFFFF9A, 0xFFFFFF96, 0xFFFFFF92, 0xFFFFFF8D, 0xFFFFFF88, 0xFFFFFF82, 0xFFFFFF7B, 0xFFFFFF74, 0xFFFFFF6A, 0xFFFFFF5D, 0xFFFFFF4C, 0xFFFFFF2E, 0xFFFFFC78
// round(100 * log10((127 - index) / 127.0))
0, 0,
-1, -1, -1, -2, -2, -2, -3, -3, -4, -4, -4, -5, -5, -5,
-6, -6, -7, -7, -7, -8, -8, -9, -9, -10, -10, -10, -11, -11,
-12, -12, -13, -13, -14, -14, -14, -15, -15, -16, -16, -17, -17, -18,
-18, -19, -20, -20, -21, -21, -22, -22, -23, -23, -24, -25, -25, -26,
-26, -27, -28, -28, -29, -30, -30, -31, -32, -33, -33, -34, -35, -36,
-36, -37, -38, -39, -40, -40, -41, -42, -43, -44, -45, -46, -47, -48,
-49, -50, -51, -52, -54, -55, -56, -57, -59, -60, -61, -63, -64, -66,
-67, -69, -71, -72, -74, -76, -78, -80, -83, -85, -87, -90, -93, -96,
-99, -102, -106, -110, -115, -120, -126, -133, -140, -150, -163, -180, -210, -904
};
const uint16 pan_values_low[128] =
const sint16 pan_values_low[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFF9, 0xFFF9, 0xFFF8, 0xFFF8,
0xFFF7, 0xFFF7, 0xFFF6, 0xFFF5, 0xFFF5, 0xFFF4, 0xFFF4, 0xFFF3, 0xFFF2, 0xFFF2, 0xFFF1, 0xFFF0, 0xFFEF, 0xFFEF, 0xFFEE, 0xFFED, 0xFFEC, 0xFFEB, 0xFFEB, 0xFFEA, 0xFFE9, 0xFFE8, 0xFFE7, 0xFFE6, 0xFFE5, 0xFFE4, 0xFFE3, 0xFFE2, 0xFFE1,
0xFFE0, 0xFFDE, 0xFFDD, 0xFFDC, 0xFFDB, 0xFFDA, 0xFFD8, 0xFFD7, 0xFFD6, 0xFFD4, 0xFFD3, 0xFFD1, 0xFFD0, 0xFFCE, 0xFFCC, 0xFFCB, 0xFFC9, 0xFFC7, 0xFFC6, 0xFFC4, 0xFFC2, 0xFFC0, 0xFFBE, 0xFFBC, 0xFFBA, 0xFFB7, 0xFFB5, 0xFFB3, 0xFFB0,
0xFFAE, 0xFFAB, 0xFFA8, 0xFFA6, 0xFFA3, 0xFFA0, 0xFF9C, 0xFF99, 0xFF96, 0xFF92, 0xFF8E, 0xFF8A, 0xFF86, 0xFF82, 0xFF7D, 0xFF78, 0xFF73, 0xFF6E, 0xFF68, 0xFF61, 0xFF5A, 0xFF53, 0xFF4B, 0xFF42, 0xFF37, 0xFF2C, 0xFF1F, 0xFF0F, 0xFEFB,
0xFEE2, 0xFEBF, 0xFE83, 0xFC40
};
// (200.0 * log10(cos((i * M_PI) / 254.0)))
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -5, -5, -6, -6, -6, -7, -7, -8, -8,
-9, -9, -10, -11, -11, -12, -12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -20, -21, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31,
-32, -34, -35, -36, -37, -38, -40, -41, -42, -44, -45, -47, -48, -50, -52, -53, -55, -57, -58, -60, -62, -64, -66, -68, -70, -73, -75, -77, -80,
-82, -85, -88, -90, -93, -96, -100, -103, -106, -110, -114, -118, -122, -126, -131, -136, -141, -146, -152, -159, -166, -173, -181, -190, -201, -212, -225, -241, -261,
-286, -321, -381, -960
};
const uint16 pan_values_high[128] =
const sint16 pan_values_high[128] =
{
0xFFC3, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC5, 0xFFC6, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC8, 0xFFC9, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCB, 0xFFCC, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCE, 0xFFCF, 0xFFCF, 0xFFD0, 0xFFD0, 0xFFD1, 0xFFD1, 0xFFD2, 0xFFD2, 0xFFD3,
0xFFD3, 0xFFD4, 0xFFD4, 0xFFD5, 0xFFD5, 0xFFD6, 0xFFD6, 0xFFD7, 0xFFD7, 0xFFD8, 0xFFD8, 0xFFD9, 0xFFD9, 0xFFDA, 0xFFDA, 0xFFDA, 0xFFDB, 0xFFDB, 0xFFDC, 0xFFDC, 0xFFDD, 0xFFDD, 0xFFDD, 0xFFDE, 0xFFDE, 0xFFDF, 0xFFDF, 0xFFE0, 0xFFE0,
0xFFE0, 0xFFE1, 0xFFE1, 0xFFE1, 0xFFE2, 0xFFE2, 0xFFE3, 0xFFE3, 0xFFE3, 0xFFE4, 0xFFE4, 0xFFE4, 0xFFE5, 0xFFE5, 0xFFE5, 0xFFE6, 0xFFE6, 0xFFE6, 0xFFE7, 0xFFE7, 0xFFE7, 0xFFE8, 0xFFE8, 0xFFE8, 0xFFE9, 0xFFE9, 0xFFE9, 0xFFEA, 0xFFEA,
0xFFEA, 0xFFEB, 0xFFEB, 0xFFEB, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFED, 0xFFED, 0xFFED, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEF, 0xFFEF, 0xFFEF, 0xFFEF, 0xFFF0, 0xFFF0, 0xFFF0, 0xFFF0, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF2, 0xFFF2,
0xFFF2, 0xFFF2, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF4, 0xFFF4, 0xFFF4, 0xFFF4, 0xFFF5
// (sint16)(200.0 * log10(sin((M_PI / 4.0) + (((double)i - 63.5) * M_PI / 730.0))))
-61, -61, -60, -59, -59, -58, -58, -57, -56, -56, -55, -55, -54, -53, -53, -52, -52, -51, -50, -50, -49, -49, -48, -48, -47, -47, -46, -46, -45,
-45, -44, -44, -43, -43, -42, -42, -41, -41, -40, -40, -39, -39, -38, -38, -38, -37, -37, -36, -36, -35, -35, -35, -34, -34, -33, -33, -32, -32,
-32, -31, -31, -31, -30, -30, -29, -29, -29, -28, -28, -28, -27, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -24, -23, -23, -23, -22, -22,
-22, -21, -21, -21, -20, -20, -20, -20, -19, -19, -19, -18, -18, -18, -18, -17, -17, -17, -17, -16, -16, -16, -16, -15, -15, -15, -15, -14, -14,
-14, -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -11
};
} g_snd_user_data{};
@@ -215,15 +220,13 @@ namespace snd_user
channel->tv_mode = 0;
channel->tv_control.pan = 0x40;
channel->tv_control.span = 0x7F;
channel->tv_control.pan = 64;
channel->tv_control.span = 127;
channel->tv_control.fader = 0;
channel->tv_control.lfe = -960;
// channel->tv_control.lfe = -960; seems to accidentally set rmt[0] lfe instead of TV? -> Investigate
for (size_t i = 0; i < AX_AUX_BUS_COUNT; ++i)
{
channel->tv_control.aux[i] = -960;
}
for (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)
{
@@ -308,17 +311,41 @@ namespace snd_user
if (device_type == AX_DEV_TV)
{
const uint32 sound_mode = g_snd_user_data.device_info.tv_sound_mode;
if (sound_mode == 3)
const auto soundMode = g_snd_user_data.device_info.tv_sound_mode;
if (soundMode == MixSoundMode::SurroundDPL2)
{
channels[0] = g_snd_user_data.pan_values_low[control->pan];
channels[1] = g_snd_user_data.pan_values_low[pandiff];
channels[2] = g_snd_user_data.pan_values_high[pandiff];
channels[3] = g_snd_user_data.pan_values_high[control->pan];
channels[4] = g_snd_user_data.pan_values_high[spandiff];
channels[5] = g_snd_user_data.pan_values_high[control->span];
channels[4] = g_snd_user_data.pan_values_low[spandiff];
channels[5] = g_snd_user_data.pan_values_low[control->span];
}
else if (sound_mode != 4)
else if (soundMode == MixSoundMode::Surround6CH)
{
uint32 pan = control->pan * 2;
pan = std::min<uint32>(pan, 0x7F);
channels[0] = g_snd_user_data.pan_values[pan] + g_snd_user_data.pan_values[spandiff];
uint32 span = pandiff * 2;
if (span >= 0x7E) // 0x7E clamps to 0x7F
span = 0x7F;
channels[1] = g_snd_user_data.pan_values[span] + g_snd_user_data.pan_values[spandiff];
uint32 surroundPan;
if (control->pan < 64)
surroundPan = (64 - control->pan) * 2;
else
surroundPan = (control->pan - 64) * 2;
surroundPan = std::min<uint32>(surroundPan, 0x7F);
channels[2] = g_snd_user_data.pan_values[control->span] + g_snd_user_data.pan_values[control->pan];
channels[3] = g_snd_user_data.pan_values[control->span] + g_snd_user_data.pan_values[pandiff];
channels[4] = g_snd_user_data.pan_values[surroundPan] + g_snd_user_data.pan_values[spandiff];
channels[5] = 0;
}
else // stereo fallback
{
channels[0] = g_snd_user_data.pan_values[control->pan];
channels[1] = g_snd_user_data.pan_values[pandiff];
@@ -327,22 +354,6 @@ namespace snd_user
channels[4] = g_snd_user_data.pan_values[spandiff];
channels[5] = g_snd_user_data.pan_values[control->span];
}
else
{
uint32 pan = 0x7F;
if (((uint32)control->pan >> 1) < 0x7F)
pan = (uint32)control->pan >> 1;
channels[0] = g_snd_user_data.pan_values[pan] + g_snd_user_data.pan_values[spandiff];
uint32 span = 0x7F;
if (((uint32)pandiff >> 1) < 0x7E)
span = (uint32)pandiff >> 1;
channels[1] = g_snd_user_data.pan_values[span] + g_snd_user_data.pan_values[spandiff];
// TODO
}
}
else if (device_type == AX_DEV_DRC)
{
@@ -350,19 +361,31 @@ namespace snd_user
}
}
sint16 __MIXTranslateVolume(sint16 input)
uint16 __MIXTranslateVolume(sint32 input)
{
if (input <= -904)
return 0;
if (input > 0x3C)
return -156;
return (sint16)g_snd_user_data.volume[input + 903];
if (input >= 0x3C)
return 0xFF64;
return g_snd_user_data.volume[input + 904];
}
void AXFXInitDefaultHooks();
static void CheckVoice(AXVPB* voice)
{
if (!voice)
{
cemuLog_log(LogType::APIErrors, "Voice 0x{:08x} nullptr passed to MIX function", MEMPTR<void>(voice).GetMPTR());
cemu_assert(false);
}
if (voice->index < 0 || voice->index >= AX_MAX_VOICES)
{
cemuLog_log(LogType::APIErrors, "Voice 0x{:08x} passed to MIX function has invalid index (0x{:08x})", MEMPTR<void>(voice).GetMPTR(), (uint32)voice->index);
cemu_assert(false);
}
}
void MIXInit()
{
cemuLog_log(LogType::SoundAPI, "MIXInit()");
@@ -377,33 +400,103 @@ namespace snd_user
}
g_snd_user_data.initialized = true;
g_snd_user_data.device_info.tv_sound_mode = 1;
g_snd_user_data.device_info.drc_sound_mode = 1;
g_snd_user_data.device_info.rmt_sound_mode = 0;
g_snd_user_data.device_info.tv_sound_mode = MixSoundMode::Stereo;
g_snd_user_data.device_info.drc_sound_mode = MixSoundMode::Stereo;
g_snd_user_data.device_info.rmt_sound_mode = MixSoundMode::Mono;
AXFXInitDefaultHooks();
}
void MIXSetSoundMode(uint32 sound_mode)
void MIXSetSoundMode(MixSoundMode soundMode)
{
cemuLog_log(LogType::SoundAPI, "MIXSetSoundMode(0x{:x})", sound_mode);
cemuLog_log(LogType::SoundAPI, "MIXSetSoundMode(0x{:x})", (uint32)soundMode);
if (soundMode == MixSoundMode::Surround || soundMode == MixSoundMode::SurroundDPL2)
soundMode = MixSoundMode::Stereo;
if (sound_mode >= 2)
sound_mode = 1;
g_snd_user_data.device_info.tv_sound_mode = sound_mode;
if (soundMode != MixSoundMode::Mono && soundMode != MixSoundMode::Stereo)
{
cemuLog_log(LogType::APIErrors, "MIXSetSoundMode() invalid sound mode");
soundMode = MixSoundMode::Stereo;
}
g_snd_user_data.device_info.tv_sound_mode = soundMode;
}
uint32 MIXGetSoundMode()
MixSoundMode MIXGetSoundMode()
{
cemuLog_log(LogType::SoundAPI, "MIXGetSoundMode()");
return g_snd_user_data.device_info.tv_sound_mode;
}
void _MIXUpdateTV(MixChannel* channel, sint32 index)
void MIXSetDeviceSoundMode(uint32 device, MixSoundMode mode)
{
assert(index == 0);
cemuLog_log(LogType::SoundAPI, "MIXSetDeviceSoundMode(0x{:x}, {:})", device, (uint32)mode);
cemu_assert_debug(device < AX_DEV_COUNT);
bool is_tv_device = false;
bool is_drc_device = false;
if (device == AX_DEV_TV)
{
if (mode != MixSoundMode::Mono && mode != MixSoundMode::Stereo && mode != MixSoundMode::Surround && mode != MixSoundMode::SurroundDPL2 && mode != MixSoundMode::Surround6CH)
{
cemuLog_log(LogType::APIErrors, "MIXSetDeviceSoundMode(): Invalid mode");
mode = MixSoundMode::Stereo;
}
g_snd_user_data.device_info.tv_sound_mode = mode;
is_tv_device = true;
}
else if (device == AX_DEV_DRC)
{
if (mode != MixSoundMode::Mono && mode != MixSoundMode::Stereo && mode != MixSoundMode::Surround)
{
cemuLog_log(LogType::APIErrors, "MIXSetDeviceSoundMode(): Invalid mode");
mode = MixSoundMode::Stereo;
}
g_snd_user_data.device_info.drc_sound_mode = mode;
is_drc_device = true;
}
else if (device == AX_DEV_RMT)
{
if (mode != MixSoundMode::Mono)
{
cemuLog_log(LogType::APIErrors, "MIXSetDeviceSoundMode(): Invalid mode");
mode = MixSoundMode::Mono;
}
g_snd_user_data.device_info.rmt_sound_mode = mode;
}
else
{
cemuLog_log(LogType::SoundAPI, "ERROR: MIXSetDeviceSoundMode(0x{:x}, 0x{:x}) -> wrong device", device, mode);
}
for (sint32 i = 0; i < g_snd_user_data.max_voices; ++i)
{
auto& channel = g_snd_user_data.mix_channel[i];
if (!channel.voice)
continue;
const auto voice = channel.voice.GetPtr();
AXVoiceBegin(voice);
if (is_tv_device)
{
channel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXControl_SetDevicePan(&channel.tv_control, AX_DEV_TV, channel.tv_channels);
}
if (is_drc_device)
{
for (sint32 j = 0; j < AX_MAX_NUM_DRC; ++j)
{
channel.drc_mode[j] |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXControl_SetDevicePan(&channel.drc_control[j], AX_DEV_DRC, channel.drc_channels[j]);
}
}
AXVoiceEnd(voice);
}
}
void _MIXUpdateTV(MixChannel* channel)
{
bool updated_volume = false;
if ((channel->tv_mode & AX_UPDATE_MODE_80000000) != 0)
{
@@ -426,7 +519,7 @@ namespace snd_user
}
else
{
if (g_snd_user_data.device_info.tv_sound_mode == 0)
if (g_snd_user_data.device_info.tv_sound_mode == MixSoundMode::Mono)
{
sint32 chan4 = channel->tv_channels[4];
if (chan4 < -0x78)
@@ -464,7 +557,7 @@ namespace snd_user
channel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;
channel->tv_mode |= AX_UPDATE_MODE_80000000;
}
else if (g_snd_user_data.device_info.tv_sound_mode < 3)
else if (g_snd_user_data.device_info.tv_sound_mode == MixSoundMode::Stereo || g_snd_user_data.device_info.tv_sound_mode == MixSoundMode::Surround)
{
sint32 chan4 = channel->tv_channels[4];
if (chan4 < -0x78)
@@ -504,13 +597,70 @@ namespace snd_user
channel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;
channel->tv_mode |= AX_UPDATE_MODE_80000000;
}
else if (g_snd_user_data.device_info.tv_sound_mode == 3)
else if (g_snd_user_data.device_info.tv_sound_mode == MixSoundMode::SurroundDPL2)
{
// TODO
const sint32 fader = channel->tv_control.fader;
const sint32 chan0 = channel->tv_channels[0];
const sint32 chan1 = channel->tv_channels[1];
const sint32 chan2 = channel->tv_channels[2];
const sint32 chan3 = channel->tv_channels[3];
const sint32 chan4 = channel->tv_channels[4];
const sint32 chan5 = channel->tv_channels[5];
channel->tv_volume[0][0].volume_target = __MIXTranslateVolume(fader + chan4 + chan0);
channel->tv_volume[0][1].volume_target = __MIXTranslateVolume(fader + chan4 + chan1);
channel->tv_volume[0][2].volume_target = __MIXTranslateVolume(fader + chan5);
channel->tv_volume[0][3].volume_target = __MIXTranslateVolume(fader + chan3 + chan5);
channel->tv_volume[0][4].volume_target = 0;
channel->tv_volume[0][0].volume_target = 0;
for (int i = 0; i < 2; ++i)
{
const sint32 aux = channel->tv_control.aux[i];
const sint32 base = ((channel->tv_mode & (1 << i)) != 0) ? aux : fader + aux;
channel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(base + chan4 + chan0);
channel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(base + chan4 + chan1);
channel->tv_volume[1 + i][2].volume_target = __MIXTranslateVolume(base + chan5 + chan2);
channel->tv_volume[1 + i][3].volume_target = __MIXTranslateVolume(base + chan5 + chan3);
channel->tv_volume[1 + i][0].volume_target = 0;
channel->tv_volume[1 + i][4].volume_target = 0;
}
channel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;
channel->tv_mode |= AX_UPDATE_MODE_80000000;
}
else if (g_snd_user_data.device_info.tv_sound_mode == 4)
else if (g_snd_user_data.device_info.tv_sound_mode == MixSoundMode::Surround6CH)
{
// TODO
const sint32 fader = channel->tv_control.fader;
const sint32 lfe = channel->tv_control.lfe;
const sint32 chan0 = channel->tv_channels[0];
const sint32 chan1 = channel->tv_channels[1];
const sint32 chan2 = channel->tv_channels[2];
const sint32 chan3 = channel->tv_channels[3];
const sint32 chan4 = channel->tv_channels[4];
channel->tv_volume[0][0].volume_target = __MIXTranslateVolume(fader + chan0);
channel->tv_volume[0][1].volume_target = __MIXTranslateVolume(fader + chan1);
channel->tv_volume[0][4].volume_target = __MIXTranslateVolume(fader + chan4);
channel->tv_volume[0][2].volume_target = __MIXTranslateVolume(fader + chan2);
channel->tv_volume[0][3].volume_target = __MIXTranslateVolume(fader + chan3);
channel->tv_volume[0][5].volume_target = __MIXTranslateVolume(fader + lfe);
for (int i = 0; i < 3; ++i)
{
const sint32 aux = channel->tv_control.aux[i];
const sint32 base = ((channel->tv_mode & (1 << i)) != 0) ? aux : fader + aux;
channel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(base + chan0);
channel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(base + chan1);
channel->tv_volume[1 + i][4].volume_target = __MIXTranslateVolume(base + chan4);
channel->tv_volume[1 + i][2].volume_target = __MIXTranslateVolume(base + chan2);
channel->tv_volume[1 + i][3].volume_target = __MIXTranslateVolume(base + chan3);
channel->tv_volume[0][5].volume_target = __MIXTranslateVolume(base + lfe);
}
channel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;
channel->tv_mode |= AX_UPDATE_MODE_80000000;
}
else
{
@@ -524,14 +674,14 @@ namespace snd_user
{
for (size_t j = 0; j < AX_TV_CHANNEL_COUNT; ++j)
{
const sint16 target = channel->tv_volume[i][j].volume_target;
const sint16 volume = channel->tv_volume[i][j].volume;
const uint16 target = channel->tv_volume[i][j].volume_target;
const uint16 volume = channel->tv_volume[i][j].volume;
mix[j][i].vol = volume;
mix[j][i].delta = (target - volume) / 96; // 32000HZ SAMPLES_3MS
mix[j][i].delta = (sint16)(target - volume) / 96; // 32000HZ SAMPLES_3MS
}
}
AXSetVoiceDeviceMix(channel->voice.GetPtr(), AX_DEV_TV, index, (snd_core::AXCHMIX_DEPR*)&mix[0][0]);
AXSetVoiceDeviceMix(channel->voice.GetPtr(), AX_DEV_TV, 0, (snd_core::AXCHMIX_DEPR*)&mix[0][0]);
}
void _MIXUpdateDRC(MixChannel* channel, sint32 index)
@@ -544,15 +694,14 @@ namespace snd_user
// todo
}
void MIXInitChannel(AXVPB* voice, uint16 mode, uint16 input, uint16 aux1, uint16 aux2, uint16 aux3, uint16 pan, uint16 span, uint16 fader)
void MIXInitChannel(AXVPB* voice, uint32 flags, sint16 input, sint16 aux1, sint16 aux2, sint16 aux3, sint16 pan, sint16 span, sint16 fader)
{
cemuLog_log(LogType::SoundAPI, "MIXInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})", MEMPTR(voice).GetMPTR(), mode, input, aux1, aux2, aux3, pan, span, fader);
cemu_assert_debug(voice);
cemuLog_log(LogType::SoundAPI, "MIXInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})", MEMPTR(voice).GetMPTR(), flags, input, aux1, aux2, aux3, pan, span, fader);
CheckVoice(voice);
AXVoiceBegin(voice);
MIXAssignChannel(voice);
MIXInitInputControl(voice, input, mode);
MIXInitInputControl(voice, input, flags);
const uint32 index = voice->index;
auto& channel = g_snd_user_data.mix_channel[index];
@@ -564,49 +713,51 @@ namespace snd_user
channel.tv_control.pan = pan;
channel.tv_control.span = span;
channel.tv_control.fader = fader;
// channel.tv_control.lfe = lfe; // 0x1A -> not set?
// .lfe is not updated
channel.tv_mode = AX_UPDATE_MODE_40000007 & mode;
channel.tv_mode = flags & AX_UPDATE_MODE_40000007;
_MIXControl_SetDevicePan(&channel.tv_control, AX_DEV_TV, channel.tv_channels);
channel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXUpdateTV(&channel, 0);
_MIXUpdateTV(&channel);
AXVoiceEnd(voice);
}
void MIXReleaseChannel(AXVPB* voice)
{
CheckVoice(voice);
AXVoiceBegin(voice);
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
channel.voice = nullptr;
AXVoiceEnd(voice);
}
void MIXAssignChannel(AXVPB* voice)
{
cemuLog_log(LogType::SoundAPI, "MIXAssignChannel(0x{:x})", MEMPTR(voice).GetMPTR());
cemu_assert_debug(voice);
CheckVoice(voice);
AXVoiceBegin(voice);
const uint32 voice_index = voice->index;
auto channel = &g_snd_user_data.mix_channel[voice_index];
MIXResetChannelData(channel);
channel->voice = voice;
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
MIXResetChannelData(&channel);
channel.voice = voice;
AXVoiceEnd(voice);
}
void MIXDRCInitChannel(AXVPB* voice, uint16 mode, uint16 vol1, uint16 vol2, uint16 vol3)
void MIXDRCInitChannel(AXVPB* voice, uint32 flags, uint16 aux, uint16 pan, uint16 fader)
{
cemuLog_log(LogType::SoundAPI, "MIXDRCInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})", MEMPTR(voice).GetMPTR(), mode, vol1, vol2, vol3);
cemu_assert_debug(voice);
cemuLog_log(LogType::SoundAPI, "MIXDRCInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})", MEMPTR(voice).GetMPTR(), flags, aux, pan, fader);
CheckVoice(voice);
AXVoiceBegin(voice);
const uint32 index = voice->index;
auto& channel = g_snd_user_data.mix_channel[index];
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
_MIXChannelResetDRC(&channel, 0);
channel.drc_volume[1][1][1].volume = vol1;
channel.drc_volume[1][1][2].volume_target = vol2;
channel.drc_volume[1][1][3].volume_target = vol3;
channel.drc_control[0].aux[0] = aux;
channel.drc_control[0].pan = pan;
channel.drc_control[0].fader = fader;
channel.drc_mode[0] = AX_UPDATE_MODE_40000007 & mode;
channel.drc_mode[0] = flags & AX_UPDATE_MODE_40000007;
_MIXControl_SetDevicePan(&channel.drc_control[0], AX_DEV_DRC, &channel.drc_channels[0][0]);
channel.drc_mode[0] |= AX_UPDATE_MODE_40000000_VOLUME;
@@ -618,13 +769,10 @@ namespace snd_user
void MIXSetInput(AXVPB* voice, uint16 input)
{
cemuLog_log(LogType::SoundAPI, "MIXSetInput(0x{:x}, 0x{:x})", MEMPTR(voice).GetMPTR(), input);
const uint32 voice_index = voice->index;
const auto channel = &g_snd_user_data.mix_channel[voice_index];
channel->input_level = input;
channel->update_mode |= AX_UPDATE_MODE_10000000;
CheckVoice(voice);
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
channel.input_level = input;
channel.update_mode |= AX_UPDATE_MODE_10000000_INPUT_LEVEL;
}
void MIXUpdateSettings()
@@ -646,7 +794,6 @@ namespace snd_user
const auto voice = channel.voice.GetPtr();
AXVoiceBegin(voice);
bool volume_updated = false;
if ((channel.update_mode & AX_UPDATE_MODE_20000000) != 0)
{
@@ -655,45 +802,40 @@ namespace snd_user
volume_updated = true;
}
if ((channel.update_mode & AX_UPDATE_MODE_10000000) == 0)
if ((channel.update_mode & AX_UPDATE_MODE_10000000_INPUT_LEVEL) == 0)
{
if (volume_updated)
{
AXPBVE ve;
ve.currentVolume = channel.volume.volume;
ve.currentDelta = (channel.volume.volume_target - channel.volume.volume) / 96;
ve.currentDelta = (sint32(channel.volume.volume_target) - sint32(channel.volume.volume)) / 96;
AXSetVoiceVe(voice, &ve);
}
}
else
{
sint32 volume = 0;
uint16 volume = 0;
if ((channel.update_mode & 8) == 0)
volume = __MIXTranslateVolume(channel.input_level);
channel.volume.volume_target = volume;
channel.update_mode &= ~AX_UPDATE_MODE_10000000;
channel.update_mode &= ~AX_UPDATE_MODE_10000000_INPUT_LEVEL;
channel.update_mode |= AX_UPDATE_MODE_20000000;
AXPBVE ve;
ve.currentVolume = channel.volume.volume;
ve.currentDelta = (channel.volume.volume_target - channel.volume.volume) / 96;
ve.currentDelta = (sint32(channel.volume.volume_target) - sint32(channel.volume.volume)) / 96;
AXSetVoiceVe(voice, &ve);
}
_MIXUpdateTV(&channel, 0);
_MIXUpdateTV(&channel);
for (int i = 0; i < 2; ++i)
_MIXUpdateDRC(&channel, i);
// TODO remote mix
AXCHMIX2 mix[4];
for (int j = 0; j < 4; ++j)
{
AXSetVoiceDeviceMix(voice, AX_DEV_RMT, i, (snd_core::AXCHMIX_DEPR*)mix);
}
for (int j = 0; j < AX_MAX_NUM_RMT; ++j)
_MIXUpdateRmt(&channel, j);
AXVoiceEnd(voice);
}
@@ -701,110 +843,63 @@ namespace snd_user
// TODO
}
void MIXSetDeviceSoundMode(uint32 device, uint32 mode)
void MIXInitDeviceControl(AXVPB* voice, uint32 device, uint32 deviceSubIndex, MixControl* control, uint32 mode)
{
cemuLog_log(LogType::SoundAPI, "MIXSetDeviceSoundMode(0x{:x}, 0x{:x})", device, mode);
// note - lfe is not copied from control
cemuLog_log(LogType::SoundAPI, "MIXInitDeviceControl(0x{:0x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x} )", MEMPTR(voice).GetMPTR(), device, deviceSubIndex, MEMPTR(control).GetMPTR(), mode);
CheckVoice(voice);
cemu_assert_debug(device < AX_DEV_COUNT);
cemu_assert_debug(mode <= 4);
bool is_tv_device = false;
bool is_drc_device = false;
if (device == AX_DEV_TV)
{
g_snd_user_data.device_info.tv_sound_mode = mode;
is_tv_device = true;
}
else if (device == AX_DEV_DRC)
{
cemu_assert_debug(mode <= 2);
g_snd_user_data.device_info.drc_sound_mode = mode;
is_drc_device = true;
}
else if (device == AX_DEV_RMT)
{
cemu_assert_debug(mode == 0);
g_snd_user_data.device_info.rmt_sound_mode = mode;
}
else
{
cemuLog_log(LogType::SoundAPI, "ERROR: MIXSetDeviceSoundMode(0x{:x}, 0x{:x}) -> wrong device", device, mode);
}
for (sint32 i = 0; i < g_snd_user_data.max_voices; ++i)
{
auto& channel = g_snd_user_data.mix_channel[i];
if (!channel.voice)
continue;
const auto voice = channel.voice.GetPtr();
AXVoiceBegin(voice);
if (is_tv_device)
{
channel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXControl_SetDevicePan(&channel.tv_control, AX_DEV_TV, channel.tv_channels);
}
if (is_drc_device)
{
for (sint32 j = 0; j < AX_MAX_NUM_DRC; ++j)
{
channel.drc_mode[j] |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXControl_SetDevicePan(&channel.drc_control[j], AX_DEV_DRC, channel.drc_channels[j]);
}
}
AXVoiceEnd(voice);
}
}
void MIXInitDeviceControl(AXVPB* voice, uint32 device_type, uint32 index, MixControl* control, uint32 mode)
{
cemuLog_log(LogType::SoundAPI, "MIXInitDeviceControl(0x{:0x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x} )", MEMPTR(voice).GetMPTR(), device_type, index, MEMPTR(control).GetMPTR(), mode);
cemu_assert_debug(device_type < AX_DEV_COUNT);
cemu_assert_debug(voice);
cemu_assert_debug(control);
AXVoiceBegin(voice);
const uint32 voice_index = voice->index;
auto& channel = g_snd_user_data.mix_channel[voice_index];
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
channel.voice = voice;
if (device_type == AX_DEV_TV)
if (device == AX_DEV_TV)
{
cemu_assert_debug(index == 0);
_MIXChannelResetTV(&channel, index);
memcpy(&channel.tv_control, control, sizeof(MixControl));
_MIXControl_SetDevicePan(&channel.tv_control, device_type, channel.tv_channels);
channel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXUpdateTV(&channel, index);
cemu_assert_debug(deviceSubIndex == 0);
_MIXChannelResetTV(&channel, deviceSubIndex);
channel.tv_control.pan = control->pan;
channel.tv_control.span = control->span;
channel.tv_control.fader = control->fader;
for (sint32 i=0; i<AX_AUX_BUS_COUNT; i++)
channel.tv_control.aux[i] = control->aux[i];
_MIXControl_SetDevicePan(&channel.tv_control, device, channel.tv_channels);
channel.tv_mode = (mode & 0xF) | AX_UPDATE_MODE_40000000_VOLUME;
_MIXUpdateTV(&channel);
}
else if (device_type == AX_DEV_DRC)
else if (device == AX_DEV_DRC)
{
cemu_assert_debug(index < 2);
_MIXChannelResetDRC(&channel, index);
cemu_assert_debug(deviceSubIndex < 2);
_MIXChannelResetDRC(&channel, deviceSubIndex);
memcpy(&channel.drc_control[index], control, sizeof(MixControl));
_MIXControl_SetDevicePan(&channel.drc_control[index], device_type, channel.drc_channels[index]);
channel.drc_control[deviceSubIndex].pan = control->pan;
channel.drc_control[deviceSubIndex].span = control->span;
channel.drc_control[deviceSubIndex].fader = control->fader;
for (sint32 i=0; i<AX_AUX_BUS_COUNT; i++)
channel.drc_control[deviceSubIndex].aux[i] = control->aux[i];
_MIXControl_SetDevicePan(&channel.drc_control[deviceSubIndex], device, channel.drc_channels[deviceSubIndex]);
channel.drc_mode[index] |= AX_UPDATE_MODE_40000000_VOLUME;
_MIXUpdateDRC(&channel, index);
channel.drc_mode[deviceSubIndex] = (mode & 0xF) | AX_UPDATE_MODE_40000000_VOLUME;
_MIXUpdateDRC(&channel, deviceSubIndex);
}
else if (device_type == AX_DEV_RMT)
else if (device == AX_DEV_RMT)
{
cemu_assert_debug(index < 4);
_MIXChannelResetRmt(&channel, index);
cemu_assert_debug(deviceSubIndex < 4);
_MIXChannelResetRmt(&channel, deviceSubIndex);
memcpy(&channel.rmt_control[index], control, sizeof(MixControl));
_MIXControl_SetDevicePan(&channel.rmt_control[index], device_type, channel.rmt_channels[index]);
channel.rmt_control[deviceSubIndex].pan = control->pan;
channel.rmt_control[deviceSubIndex].span = control->span;
channel.rmt_control[deviceSubIndex].fader = control->fader;
for (sint32 i=0; i<AX_AUX_BUS_COUNT; i++)
channel.rmt_control[deviceSubIndex].aux[i] = control->aux[i];
channel.rmt_mode[index] = mode & 0xf;
_MIXUpdateRmt(&channel, index);
_MIXControl_SetDevicePan(&channel.rmt_control[deviceSubIndex], device, channel.rmt_channels[deviceSubIndex]);
channel.rmt_mode[deviceSubIndex] = (mode & 0xF);
_MIXUpdateRmt(&channel, deviceSubIndex);
}
AXVoiceEnd(voice);
@@ -814,17 +909,11 @@ namespace snd_user
void MIXInitInputControl(AXVPB* voice, uint16 input, uint32 mode)
{
cemuLog_log(LogType::SoundAPI, "MIXInitInputControl(0x{:x}, 0x{:x}, 0x{:x} )", MEMPTR(voice).GetMPTR(), input, mode);
cemu_assert_debug(voice);
CheckVoice(voice);
AXVoiceBegin(voice);
const uint32 voice_index = voice->index;
auto& channel = g_snd_user_data.mix_channel[voice_index];
mode &= 8;
mode |= AX_UPDATE_MODE_10000000;
channel.update_mode = mode;
MixChannel& channel = g_snd_user_data.mix_channel[voice->index];
channel.update_mode = (mode & AX_UPDATE_MODE_8) | AX_UPDATE_MODE_10000000_INPUT_LEVEL;
channel.input_level = input;
AXVoiceEnd(voice);
@@ -832,21 +921,18 @@ namespace snd_user
void MIXSetDeviceFader(AXVPB* vpb, uint32 device, uint32 deviceIndex, sint16 newFader)
{
// not well tested
CheckVoice(vpb);
cemu_assert(device < AX_DEV_COUNT);
MixChannel& mixChannel = g_snd_user_data.mix_channel[vpb->index];
AXVoiceBegin(vpb);
MixControl& mixControl = mixChannel.GetMixControl(device, deviceIndex);
MixMode& mixMode = mixChannel.GetMode(device, deviceIndex);
if (mixControl.fader == newFader)
{
AXVoiceEnd(vpb);
return;
}
mixControl.fader = newFader;
mixMode |= AX_UPDATE_MODE_40000000_VOLUME;
AXVoiceEnd(vpb);
@@ -854,25 +940,46 @@ namespace snd_user
void MIXSetDevicePan(AXVPB* vpb, uint32 device, uint32 deviceIndex, sint16 newPan)
{
// not well tested
CheckVoice(vpb);
cemu_assert(device < AX_DEV_COUNT);
MixChannel& mixChannel = g_snd_user_data.mix_channel[vpb->index];
AXVoiceBegin(vpb);
MixControl& mixControl = mixChannel.GetMixControl(device, deviceIndex);
MixMode& mixMode = mixChannel.GetMode(device, deviceIndex);
sint16* deviceChannels = mixChannel.GetChannels(device, deviceIndex);
if (mixControl.pan == newPan)
{
AXVoiceEnd(vpb);
return;
}
mixControl.pan = newPan;
_MIXControl_SetDevicePan(&mixControl, device, deviceChannels);
mixMode |= AX_UPDATE_MODE_40000000_VOLUME;
AXVoiceEnd(vpb);
}
if (mixControl.fader == newPan)
void MIXSetDeviceAux(AXVPB* vpb, uint32 device, uint32 deviceIndex, uint32 aux, sint16 newAux)
{
CheckVoice(vpb);
cemu_assert(device < AX_DEV_COUNT);
cemu_assert(aux < AX_AUX_BUS_COUNT);
MixChannel& mixChannel = g_snd_user_data.mix_channel[vpb->index];
AXVoiceBegin(vpb);
MixControl& mixControl = mixChannel.GetMixControl(device, deviceIndex);
MixMode& mixMode = mixChannel.GetMode(device, deviceIndex);
if (mixControl.aux[aux] == newAux)
{
AXVoiceEnd(vpb);
return;
}
mixControl.pan = newPan;
_MIXControl_SetDevicePan(&mixControl, device, deviceChannels);
mixControl.aux[aux] = newAux;
mixMode |= AX_UPDATE_MODE_40000000_VOLUME;
AXVoiceEnd(vpb);
}
@@ -1193,6 +1300,7 @@ namespace snd_user
cafeExportRegister("snd_user", MIXSetSoundMode, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXGetSoundMode, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXInitChannel, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXReleaseChannel, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXAssignChannel, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXDRCInitChannel, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXSetInput, LogType::SoundAPI);
@@ -1200,6 +1308,7 @@ namespace snd_user
cafeExportRegister("snd_user", MIXSetDeviceSoundMode, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXSetDeviceFader, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXSetDevicePan, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXSetDeviceAux, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXInitDeviceControl, LogType::SoundAPI);
cafeExportRegister("snd_user", MIXInitInputControl, LogType::SoundAPI);
@@ -1237,6 +1346,7 @@ namespace snd_user
cafeExportRegister("snduser2", MIXSetSoundMode, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXGetSoundMode, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXInitChannel, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXReleaseChannel, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXAssignChannel, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXDRCInitChannel, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXSetInput, LogType::SoundAPI);
@@ -1244,6 +1354,7 @@ namespace snd_user
cafeExportRegister("snduser2", MIXSetDeviceSoundMode, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXSetDeviceFader, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXSetDevicePan, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXSetDeviceAux, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXInitDeviceControl, LogType::SoundAPI);
cafeExportRegister("snduser2", MIXInitInputControl, LogType::SoundAPI);
+17 -6
View File
@@ -7,17 +7,28 @@ namespace snd_user
{
struct MixControl;
enum class MixSoundMode : uint32
{
Mono = 0,
Stereo = 1,
Surround = 2,
SurroundDPL2 = 3,
Surround6CH = 4
};
void MIXInit();
void MIXInitInputControl(snd_core::AXVPB* voice, uint16 input, uint32 mode);
void MIXInitDeviceControl(snd_core::AXVPB* voice, uint32 device_type, uint32 index, MixControl* control, uint32 mode);
void MIXSetDeviceSoundMode(uint32 device, uint32 mode);
void MIXInitDeviceControl(snd_core::AXVPB* voice, uint32 device, uint32 deviceSubIndex, MixControl* control, uint32 mode);
void MIXSetSoundMode(MixSoundMode soundMode);
void MIXSetDeviceSoundMode(uint32 device, MixSoundMode mode);
void MIXUpdateSettings();
void MIXSetInput(snd_core::AXVPB* voice, uint16 input);
void MIXDRCInitChannel(snd_core::AXVPB* voice, uint16 mode, uint16 vol1, uint16 vol2, uint16 vol3);
void MIXDRCInitChannel(snd_core::AXVPB* voice, uint32 flags, uint16 aux, uint16 pan, uint16 fader);
void MIXAssignChannel(snd_core::AXVPB* voice);
void MIXInitChannel(snd_core::AXVPB* voice, uint16 mode, uint16 input, uint16 aux1, uint16 aux2, uint16 aux3, uint16 pan, uint16 span, uint16 fader);
uint32 MIXGetSoundMode();
void MIXSetSoundMode(uint32 sound_mode);
void MIXInitChannel(snd_core::AXVPB* voice, uint32 flags, sint16 input, sint16 aux1, sint16 aux2, sint16 aux3, sint16 pan, sint16 span, sint16 fader);
void MIXReleaseChannel(snd_core::AXVPB* voice);
MixSoundMode MIXGetSoundMode();
COSModule* GetModuleSndUser1();
COSModule* GetModuleSndUser2();