Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
45588009
Commit
45588009
authored
Mar 31, 2018
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improvements to blended channel mixing.
parent
86428055
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
456 additions
and
17 deletions
+456
-17
mini_al.h
mini_al.h
+82
-17
tests/mal_test_0.c
tests/mal_test_0.c
+374
-0
No files found.
mini_al.h
View file @
45588009
...
...
@@ -621,7 +621,7 @@ typedef enum
typedef
enum
{
mal_channel_mix_mode_simple
=
0
,
// Drop excess channels; zeroed out extra channels.
mal_channel_mix_mode_planar_
average
,
// Simple averaging based on the plane(s) the channel is sitting on.
mal_channel_mix_mode_planar_
blend
,
// Simple averaging based on the plane(s) the channel is sitting on.
//mal_channel_mix_mode_spatial, // Blend channels based on spatial locality.
}
mal_channel_mix_mode
;
...
...
@@ -17243,6 +17243,56 @@ mal_vec3 g_malDefaultChannelPositionsInRoom[MAL_CHANNEL_POSITION_COUNT] = {
float
mal_calculate_channel_position_planar_weight
(
mal_channel
channelPositionA
,
mal_channel
channelPositionB
)
{
// Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to
// the following output configuration:
//
// - front/left
// - side/left
// - back/left
//
// The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount
// of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated.
//
// Imagine the front/left speaker as emitting audio from two planes - the front plane and the left plane. You can think of the front/left
// speaker emitting half of it's total volume from the front, and the other half from the left. Since part of it's volume is being emitted
// from the left side, and the side/left and back/left channels also emit audio from the left plane, one would expect that they would
// receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between
// the two speakers. Note that in the examples below I've added a top/front/left speaker as an example just to show how the math works
// across 3 spatial dimensions.
//
// The first thing to do is figure out how each speaker's volume is spread over each of plane:
// - front/left: 2 planes (front and left) = 1/2 = half it's total volume on each plane
// - side/left: 1 plane (left only) = 1/1 = entire volume from left plane
// - back/left: 2 planes (back and left) = 1/2 = half it's total volume on each plane
// - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane
//
// Now that we know how much volume each speaker emits for each of the planes it emits audio from we need to know how many planes are shared
// between the two speakers:
// - front/left (in) and front/left (out): 2 shared planes (front and left)
// - front/left (in) and side/left (out): 1 shared plane (left)
// - front/left (in) and back/left (out): 1 shared plane (left)
// - front/left (in) and top/front/left (out): 2 shared planes (front and left)
//
// We now have enough information to know how much audio the input speaker gives to each of it's output:
//
// volumeToGive = volumePerInputSpeakerPlane * sharedPlaneCount
//
// We can also determine how much volume an output speaker should take:
//
// volumeToTake = volumePerOutputSpeakerPlane * sharedPlaneCount
//
// Thus, the final contribution is:
//
// contribution = volumeToGive * volumeToTake
//
// Contributions for each of our examples:
//
// front/left to front/left = (1/2 * 2) * (1/2 * 2) = 0.5*2.0 * 0.5*2.0 = 1.0*1.0 = 1.0
// front/left to side/left = (1/2 * 1) * (1/1 * 1) = 0.5*1.0 * 1.0*1.0 = 0.5*1.0 = 0.5
// front/left to back/left = (1/2 * 1) * (1/2 * 1) = 0.5*1.0 * 0.5*1.0 = 0.5*0.5 = 0.25
// front/left to top/front/left = (1/2 * 2) * (1/3 * 2) = 0.5*2.0 * 0.33*2.0 = 1.0*0.66 = 0.66
mal_vec3
roomPosA
=
g_malDefaultChannelPositionsInRoom
[
channelPositionA
];
mal_vec3
roomPosB
=
g_malDefaultChannelPositionsInRoom
[
channelPositionB
];
...
...
@@ -17251,6 +17301,11 @@ float mal_calculate_channel_position_planar_weight(mal_channel channelPositionA,
if
(
roomPosA
.
y
<
0
||
roomPosA
.
y
>
0
)
planeCountA
+=
1
;
if
(
roomPosA
.
z
<
0
||
roomPosA
.
z
>
0
)
planeCountA
+=
1
;
mal_uint32
planeCountB
=
0
;
if
(
roomPosB
.
x
<
0
||
roomPosB
.
x
>
0
)
planeCountB
+=
1
;
if
(
roomPosB
.
y
<
0
||
roomPosB
.
y
>
0
)
planeCountB
+=
1
;
if
(
roomPosB
.
z
<
0
||
roomPosB
.
z
>
0
)
planeCountB
+=
1
;
mal_uint32
sharedPlaneCount
=
0
;
if
(
roomPosA
.
x
<
0
&&
roomPosB
.
x
<
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
x
>
0
&&
roomPosB
.
x
>
0
)
sharedPlaneCount
+=
1
;
...
...
@@ -17266,9 +17321,16 @@ float mal_calculate_channel_position_planar_weight(mal_channel channelPositionA,
return
0
;
}
return
(
float
)
planeCountA
/
sharedPlaneCount
;
mal_assert
(
planeCountA
>
0
);
mal_assert
(
planeCountB
>
0
);
float
contributionA
=
1.0
f
/
planeCountA
*
sharedPlaneCount
;
float
contributionB
=
1.0
f
/
planeCountB
*
sharedPlaneCount
;
return
contributionA
*
contributionB
;
}
#if 0
float mal_calculate_channel_position_spatial_weight(mal_channel channelPositionA, mal_channel channelPositionB, mal_vec3 listenerRoomPos)
{
// The weight between two channel positions is determined by the orientation and position relative to the virtual listener.
...
...
@@ -17291,7 +17353,9 @@ float mal_calculate_channel_position_spatial_weight(mal_channel channelPositionA
weight = weight * distFalloffExp;
return weight;
}
#endif
#if 0
mal_uint32 mal_channel_router__get_number_of_channels_on_same_planes(mal_channel channelPosition, mal_uint32 channelCount, const mal_channel channelMap[MAL_MAX_CHANNELS])
{
mal_uint32 count = 0;
...
...
@@ -17330,20 +17394,17 @@ mal_uint32 mal_channel_router__get_number_of_channels_on_same_planes(mal_channel
return count;
}
#endif
float
mal_channel_router__calculate_input_channel_planar_weight
(
const
mal_channel_router
*
pRouter
,
mal_channel
channelPositionIn
,
mal_channel
channelPositionOut
)
{
mal_assert
(
pRouter
!=
NULL
);
(
void
)
pRouter
;
float
weight
=
mal_calculate_channel_position_planar_weight
(
channelPositionIn
,
channelPositionOut
);
// At this point the weight will be 0/3, 1/3, 2/3 or 3/3, depending on how many planes are shared between the two channels. Now
// we need to find out how many input channels are sitting on the planes that channelPosIn is sitting on, then divide the weight
// by that number to find the average.
weight
=
weight
/
mal_channel_router__get_number_of_channels_on_same_planes
(
channelPositionIn
,
pRouter
->
config
.
channelsIn
,
pRouter
->
config
.
channelMapIn
);
return
weight
;
return
mal_calculate_channel_position_planar_weight
(
channelPositionIn
,
channelPositionOut
);
}
#if 0
float mal_channel_router__calculate_spatial_weight(const mal_channel_router* pRouter, mal_channel channelPositionA, mal_channel channelPositionB)
{
mal_assert(pRouter != NULL);
...
...
@@ -17351,6 +17412,7 @@ float mal_channel_router__calculate_spatial_weight(const mal_channel_router* pRo
return mal_calculate_channel_position_spatial_weight(channelPositionA, channelPositionB, mal_vec3f(0, 0, 0));
}
#endif
mal_bool32
mal_channel_router__is_spatial_channel_position
(
const
mal_channel_router
*
pRouter
,
mal_channel
channelPosition
)
{
...
...
@@ -17446,9 +17508,13 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
// Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple
// simple shuffling because we want the client to have the ability to freely modify the weights.
// The first step is to map 1:1 matching channels.
// shuffling. We use different algorithms for calculating weights depending on our mixing mode.
//
// In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just
// map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel
// map, nothing will be heard!
// In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
...
...
@@ -17510,7 +17576,7 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
// Input and output channels that are not present on the other side need to be blended in based on spatial locality.
if
(
pRouter
->
config
.
mixingMode
!=
mal_channel_mix_mode_simple
)
{
//
Input channels that are not present in output channel map
.
//
Unmapped input channels
.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
...
...
@@ -17521,7 +17587,7 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosOut
))
{
float
weight
=
0
;
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_
average
)
{
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_
blend
)
{
weight
=
mal_channel_router__calculate_input_channel_planar_weight
(
pRouter
,
channelPosIn
,
channelPosOut
);
}
#if 0
...
...
@@ -17540,8 +17606,7 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
}
}
// Output channels that are not present in input channel map.
// Unmapped output channels.
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
...
...
@@ -17552,7 +17617,7 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosIn
))
{
float
weight
=
0
;
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_
average
)
{
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_
blend
)
{
weight
=
mal_channel_router__calculate_input_channel_planar_weight
(
pRouter
,
channelPosIn
,
channelPosOut
);
}
#if 0
...
...
tests/mal_test_0.c
View file @
45588009
...
...
@@ -1261,6 +1261,365 @@ int do_format_converter_tests()
}
mal_uint32
channel_router_callback__passthrough_test
(
mal_channel_router
*
pRouter
,
mal_uint32
frameCount
,
void
**
ppSamplesOut
,
void
*
pUserData
)
{
(
void
)
pUserData
;
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
pRouter
->
config
.
channelsIn
;
++
iChannel
)
{
mal_zero_memory
(
ppSamplesOut
[
iChannel
],
sizeof
(
float
)
*
frameCount
);
}
return
frameCount
;
}
int
do_channel_routing_tests
()
{
mal_bool32
hasError
=
MAL_FALSE
;
printf
(
"Passthrough... "
);
{
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_planar_blend
;
routerConfig
.
channelsIn
=
6
;
routerConfig
.
channelsOut
=
6
;
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsIn
,
routerConfig
.
channelMapIn
);
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsOut
,
routerConfig
.
channelMapOut
);
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a passthrough.
if
(
!
router
.
isPassthrough
)
{
printf
(
"Failed to init router as passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
// Expecting the weights to all be equal to 1 for each channel.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
float
expectedWeight
=
0
;
if
(
iChannelIn
==
iChannelOut
)
{
expectedWeight
=
1
;
}
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeight
)
{
printf
(
"Failed. Channel weight incorrect: %f
\n
"
,
expectedWeight
);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
printf
(
"Shuffle... "
);
{
// The shuffle is tested by simply reversing the order of the channels. Doing a reversal just makes it easier to
// check that everything is working.
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_planar_blend
;
routerConfig
.
channelsIn
=
6
;
routerConfig
.
channelsOut
=
routerConfig
.
channelsIn
;
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsIn
,
routerConfig
.
channelMapIn
);
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
routerConfig
.
channelsIn
;
++
iChannel
)
{
routerConfig
.
channelMapOut
[
iChannel
]
=
routerConfig
.
channelMapIn
[
routerConfig
.
channelsIn
-
iChannel
-
1
];
}
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a shuffle, but not a passthrough.
if
(
router
.
isPassthrough
)
{
printf
(
"Router incorrectly configured as a passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
router
.
isSimpleShuffle
)
{
printf
(
"Router not configured as a simple shuffle.
\n
"
);
hasError
=
MAL_TRUE
;
}
// Expecting the weights to all be equal to 1 for each channel.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
float
expectedWeight
=
0
;
if
(
iChannelIn
==
(
routerConfig
.
channelsOut
-
iChannelOut
-
1
))
{
expectedWeight
=
1
;
}
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeight
)
{
printf
(
"Failed. Channel weight incorrect: %f
\n
"
,
expectedWeight
);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
printf
(
"Simple Conversion (Stereo -> 5.1)... "
);
{
// This tests takes a Stereo to 5.1 conversion using the simple mixing mode. We should expect 0 and 1 (front/left, front/right) to have
// weights of 1, and the others to have a weight of 0.
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_simple
;
routerConfig
.
channelsIn
=
2
;
routerConfig
.
channelsOut
=
6
;
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsIn
,
routerConfig
.
channelMapIn
);
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsOut
,
routerConfig
.
channelMapOut
);
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a shuffle, but not a passthrough.
if
(
router
.
isPassthrough
)
{
printf
(
"Router incorrectly configured as a passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
router
.
isSimpleShuffle
)
{
printf
(
"Router incorrectly configured as a simple shuffle.
\n
"
);
hasError
=
MAL_TRUE
;
}
// Expecting the weights to all be equal to 1 for each channel.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
float
expectedWeight
=
0
;
if
(
routerConfig
.
channelMapIn
[
iChannelIn
]
==
routerConfig
.
channelMapOut
[
iChannelOut
])
{
expectedWeight
=
1
;
}
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeight
)
{
printf
(
"Failed. Channel weight incorrect: %f
\n
"
,
expectedWeight
);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
printf
(
"Simple Conversion (5.1 -> Stereo)... "
);
{
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_simple
;
routerConfig
.
channelsIn
=
6
;
routerConfig
.
channelsOut
=
2
;
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsIn
,
routerConfig
.
channelMapIn
);
mal_get_standard_channel_map
(
mal_standard_channel_map_microsoft
,
routerConfig
.
channelsOut
,
routerConfig
.
channelMapOut
);
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a shuffle, but not a passthrough.
if
(
router
.
isPassthrough
)
{
printf
(
"Router incorrectly configured as a passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
router
.
isSimpleShuffle
)
{
printf
(
"Router incorrectly configured as a simple shuffle.
\n
"
);
hasError
=
MAL_TRUE
;
}
// Expecting the weights to all be equal to 1 for each channel.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
float
expectedWeight
=
0
;
if
(
routerConfig
.
channelMapIn
[
iChannelIn
]
==
routerConfig
.
channelMapOut
[
iChannelOut
])
{
expectedWeight
=
1
;
}
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeight
)
{
printf
(
"Failed. Channel weight incorrect: %f
\n
"
,
expectedWeight
);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
printf
(
"Planar Blend Conversion (Stereo -> 5.1)... "
);
{
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_planar_blend
;
// Use very specific mappings for this test.
routerConfig
.
channelsIn
=
2
;
routerConfig
.
channelMapIn
[
0
]
=
MAL_CHANNEL_FRONT_LEFT
;
routerConfig
.
channelMapIn
[
1
]
=
MAL_CHANNEL_FRONT_RIGHT
;
routerConfig
.
channelsOut
=
8
;
routerConfig
.
channelMapOut
[
0
]
=
MAL_CHANNEL_FRONT_LEFT
;
routerConfig
.
channelMapOut
[
1
]
=
MAL_CHANNEL_FRONT_RIGHT
;
routerConfig
.
channelMapOut
[
2
]
=
MAL_CHANNEL_FRONT_CENTER
;
routerConfig
.
channelMapOut
[
3
]
=
MAL_CHANNEL_LFE
;
routerConfig
.
channelMapOut
[
4
]
=
MAL_CHANNEL_BACK_LEFT
;
routerConfig
.
channelMapOut
[
5
]
=
MAL_CHANNEL_BACK_RIGHT
;
routerConfig
.
channelMapOut
[
6
]
=
MAL_CHANNEL_SIDE_LEFT
;
routerConfig
.
channelMapOut
[
7
]
=
MAL_CHANNEL_SIDE_RIGHT
;
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a shuffle, but not a passthrough.
if
(
router
.
isPassthrough
)
{
printf
(
"Router incorrectly configured as a passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
router
.
isSimpleShuffle
)
{
printf
(
"Router incorrectly configured as a simple shuffle.
\n
"
);
hasError
=
MAL_TRUE
;
}
float
expectedWeights
[
MAL_MAX_CHANNELS
][
MAL_MAX_CHANNELS
];
mal_zero_memory
(
expectedWeights
,
sizeof
(
expectedWeights
));
expectedWeights
[
0
][
0
]
=
1
.
0
f
;
// FRONT_LEFT -> FRONT_LEFT
expectedWeights
[
0
][
1
]
=
0
.
0
f
;
// FRONT_LEFT -> FRONT_RIGHT
expectedWeights
[
0
][
2
]
=
0
.
5
f
;
// FRONT_LEFT -> FRONT_CENTER
expectedWeights
[
0
][
3
]
=
0
.
0
f
;
// FRONT_LEFT -> LFE
expectedWeights
[
0
][
4
]
=
0
.
25
f
;
// FRONT_LEFT -> BACK_LEFT
expectedWeights
[
0
][
5
]
=
0
.
0
f
;
// FRONT_LEFT -> BACK_RIGHT
expectedWeights
[
0
][
6
]
=
0
.
5
f
;
// FRONT_LEFT -> SIDE_LEFT
expectedWeights
[
0
][
7
]
=
0
.
0
f
;
// FRONT_LEFT -> SIDE_RIGHT
expectedWeights
[
1
][
0
]
=
0
.
0
f
;
// FRONT_RIGHT -> FRONT_LEFT
expectedWeights
[
1
][
1
]
=
1
.
0
f
;
// FRONT_RIGHT -> FRONT_RIGHT
expectedWeights
[
1
][
2
]
=
0
.
5
f
;
// FRONT_RIGHT -> FRONT_CENTER
expectedWeights
[
1
][
3
]
=
0
.
0
f
;
// FRONT_RIGHT -> LFE
expectedWeights
[
1
][
4
]
=
0
.
0
f
;
// FRONT_RIGHT -> BACK_LEFT
expectedWeights
[
1
][
5
]
=
0
.
25
f
;
// FRONT_RIGHT -> BACK_RIGHT
expectedWeights
[
1
][
6
]
=
0
.
0
f
;
// FRONT_RIGHT -> SIDE_LEFT
expectedWeights
[
1
][
7
]
=
0
.
5
f
;
// FRONT_RIGHT -> SIDE_RIGHT
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeights
[
iChannelIn
][
iChannelOut
])
{
printf
(
"Failed. Channel weight incorrect for [%d][%d]. Expected %f, got %f
\n
"
,
iChannelIn
,
iChannelOut
,
expectedWeights
[
iChannelIn
][
iChannelOut
],
router
.
weights
[
iChannelIn
][
iChannelOut
]);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
printf
(
"Planar Blend Conversion (5.1 -> Stereo)... "
);
{
mal_channel_router_config
routerConfig
;
mal_zero_object
(
&
routerConfig
);
routerConfig
.
mixingMode
=
mal_channel_mix_mode_planar_blend
;
// Use very specific mappings for this test.
routerConfig
.
channelsIn
=
8
;
routerConfig
.
channelMapIn
[
0
]
=
MAL_CHANNEL_FRONT_LEFT
;
routerConfig
.
channelMapIn
[
1
]
=
MAL_CHANNEL_FRONT_RIGHT
;
routerConfig
.
channelMapIn
[
2
]
=
MAL_CHANNEL_FRONT_CENTER
;
routerConfig
.
channelMapIn
[
3
]
=
MAL_CHANNEL_LFE
;
routerConfig
.
channelMapIn
[
4
]
=
MAL_CHANNEL_BACK_LEFT
;
routerConfig
.
channelMapIn
[
5
]
=
MAL_CHANNEL_BACK_RIGHT
;
routerConfig
.
channelMapIn
[
6
]
=
MAL_CHANNEL_SIDE_LEFT
;
routerConfig
.
channelMapIn
[
7
]
=
MAL_CHANNEL_SIDE_RIGHT
;
routerConfig
.
channelsOut
=
2
;
routerConfig
.
channelMapOut
[
0
]
=
MAL_CHANNEL_FRONT_LEFT
;
routerConfig
.
channelMapOut
[
1
]
=
MAL_CHANNEL_FRONT_RIGHT
;
mal_channel_router
router
;
mal_result
result
=
mal_channel_router_init_separated
(
&
routerConfig
,
channel_router_callback__passthrough_test
,
NULL
,
&
router
);
if
(
result
==
MAL_SUCCESS
)
{
// Expecing a shuffle, but not a passthrough.
if
(
router
.
isPassthrough
)
{
printf
(
"Router incorrectly configured as a passthrough.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
router
.
isSimpleShuffle
)
{
printf
(
"Router incorrectly configured as a simple shuffle.
\n
"
);
hasError
=
MAL_TRUE
;
}
float
expectedWeights
[
MAL_MAX_CHANNELS
][
MAL_MAX_CHANNELS
];
mal_zero_memory
(
expectedWeights
,
sizeof
(
expectedWeights
));
expectedWeights
[
0
][
0
]
=
1
.
0
f
;
// FRONT_LEFT -> FRONT_LEFT
expectedWeights
[
1
][
0
]
=
0
.
0
f
;
// FRONT_RIGHT -> FRONT_LEFT
expectedWeights
[
2
][
0
]
=
0
.
5
f
;
// FRONT_CENTER -> FRONT_LEFT
expectedWeights
[
3
][
0
]
=
0
.
0
f
;
// LFE -> FRONT_LEFT
expectedWeights
[
4
][
0
]
=
0
.
25
f
;
// BACK_LEFT -> FRONT_LEFT
expectedWeights
[
5
][
0
]
=
0
.
0
f
;
// BACK_RIGHT -> FRONT_LEFT
expectedWeights
[
6
][
0
]
=
0
.
5
f
;
// SIDE_LEFT -> FRONT_LEFT
expectedWeights
[
7
][
0
]
=
0
.
0
f
;
// SIDE_RIGHT -> FRONT_LEFT
expectedWeights
[
0
][
1
]
=
0
.
0
f
;
// FRONT_LEFT -> FRONT_RIGHT
expectedWeights
[
1
][
1
]
=
1
.
0
f
;
// FRONT_RIGHT -> FRONT_RIGHT
expectedWeights
[
2
][
1
]
=
0
.
5
f
;
// FRONT_CENTER -> FRONT_RIGHT
expectedWeights
[
3
][
1
]
=
0
.
0
f
;
// LFE -> FRONT_RIGHT
expectedWeights
[
4
][
1
]
=
0
.
0
f
;
// BACK_LEFT -> FRONT_RIGHT
expectedWeights
[
5
][
1
]
=
0
.
25
f
;
// BACK_RIGHT -> FRONT_RIGHT
expectedWeights
[
6
][
1
]
=
0
.
0
f
;
// SIDE_LEFT -> FRONT_RIGHT
expectedWeights
[
7
][
1
]
=
0
.
5
f
;
// SIDE_RIGHT -> FRONT_RIGHT
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
routerConfig
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
routerConfig
.
channelsOut
;
++
iChannelOut
)
{
if
(
router
.
weights
[
iChannelIn
][
iChannelOut
]
!=
expectedWeights
[
iChannelIn
][
iChannelOut
])
{
printf
(
"Failed. Channel weight incorrect for [%d][%d]. Expected %f, got %f
\n
"
,
iChannelIn
,
iChannelOut
,
expectedWeights
[
iChannelIn
][
iChannelOut
],
router
.
weights
[
iChannelIn
][
iChannelOut
]);
hasError
=
MAL_TRUE
;
}
}
}
}
else
{
printf
(
"Failed to init router.
\n
"
);
hasError
=
MAL_TRUE
;
}
if
(
!
hasError
)
{
printf
(
"PASSED
\n
"
);
}
}
if
(
hasError
)
{
return
-
1
;
}
else
{
return
0
;
}
}
int
do_backend_test
(
mal_backend
backend
)
{
mal_result
result
=
MAL_SUCCESS
;
...
...
@@ -1491,6 +1850,7 @@ int main(int argc, char** argv)
mal_bool32
hasErrorOccurred
=
MAL_FALSE
;
int
result
=
0
;
// Format Conversion
printf
(
"=== TESTING FORMAT CONVERSION ===
\n
"
);
result
=
do_format_conversion_tests
();
if
(
result
<
0
)
{
...
...
@@ -1500,6 +1860,7 @@ int main(int argc, char** argv)
printf
(
"
\n
"
);
// Interleaving / Deinterleaving
printf
(
"=== TESTING INTERLEAVING/DEINTERLEAVING ===
\n
"
);
result
=
do_interleaving_tests
();
if
(
result
<
0
)
{
...
...
@@ -1509,6 +1870,7 @@ int main(int argc, char** argv)
printf
(
"
\n
"
);
// mal_format_convert
printf
(
"=== TESTING FORMAT CONVERTER ===
\n
"
);
result
=
do_format_converter_tests
();
if
(
result
<
0
)
{
...
...
@@ -1516,8 +1878,19 @@ int main(int argc, char** argv)
}
printf
(
"=== END TESTING FORMAT CONVERTER ===
\n
"
);
printf
(
"
\n
"
);
// Channel Routing
printf
(
"=== TESTING CHANNEL ROUTING ===
\n
"
);
result
=
do_channel_routing_tests
();
if
(
result
<
0
)
{
hasErrorOccurred
=
MAL_TRUE
;
}
printf
(
"=== END TESTING CHANNEL ROUTING ===
\n
"
);
printf
(
"
\n
"
);
// Backends
printf
(
"=== TESTING BACKENDS ===
\n
"
);
result
=
do_backend_tests
();
if
(
result
<
0
)
{
...
...
@@ -1527,6 +1900,7 @@ int main(int argc, char** argv)
printf
(
"
\n
"
);
// Default Playback Devices
printf
(
"=== TESTING DEFAULT PLAYBACK DEVICES ===
\n
"
);
result
=
do_playback_tests
();
if
(
result
<
0
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment