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
86428055
Commit
86428055
authored
Mar 30, 2018
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Early untested work on spatial blending for channel conversion.
parent
69c4a35e
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
424 additions
and
29 deletions
+424
-29
mini_al.h
mini_al.h
+424
-29
No files found.
mini_al.h
View file @
86428055
...
...
@@ -620,8 +620,9 @@ typedef enum
typedef
enum
{
mal_channel_mix_mode_basic
,
// Drop excess channels; zeroed out extra channels.
mal_channel_mix_mode_blend
,
// Blend channels based on locality.
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_spatial, // Blend channels based on spatial locality.
}
mal_channel_mix_mode
;
typedef
enum
...
...
@@ -740,11 +741,7 @@ struct mal_channel_router
mal_bool32
isPassthrough
:
1
;
mal_bool32
isSimpleShuffle
:
1
;
mal_uint8
shuffleTable
[
MAL_MAX_CHANNELS
];
struct
{
mal_uint8
iChannelOut
;
mal_uint8
volume
;
// 0..255
}
shuffleData
[
MAL_MAX_CHANNELS
][
MAL_MAX_CHANNELS
];
float
weights
[
MAL_MAX_CHANNELS
][
MAL_MAX_CHANNELS
];
};
...
...
@@ -810,6 +807,7 @@ typedef struct
mal_uint32
channelsOut
;
mal_uint32
sampleRateOut
;
mal_channel
channelMapOut
[
MAL_MAX_CHANNELS
];
mal_channel_mix_mode
channelMixMode
;
mal_uint32
cacheSizeInFrames
;
// Applications should set this to 0 for now.
}
mal_dsp_config
;
...
...
@@ -1802,11 +1800,27 @@ static inline mal_device_config mal_device_config_init_playback(mal_format forma
// Helper for retrieving a standard channel map.
void
mal_get_standard_channel_map
(
mal_standard_channel_map
standardChannelMap
,
mal_uint32
channels
,
mal_channel
channelMap
[
MAL_MAX_CHANNELS
]);
// Determines whether or not a channel map is valid.
//
// A blank channel map is valid (all channels set to MAL_CHANNEL_NONE). The way a blank channel map is handled is context specific, but
// is usually treated as a passthrough.
//
// Invalid channel maps:
// - A channel map with no channels
// - A channel map with more than one channel and a mono channel
mal_bool32
mal_channel_map_valid
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
]);
// Helper for comparing two channel maps for equality.
//
// This assumes the channel count is the same between the two.
mal_bool32
mal_channel_map_equal
(
mal_uint32
channels
,
mal_channel
channelMapA
[
MAL_MAX_CHANNELS
],
mal_channel
channelMapB
[
MAL_MAX_CHANNELS
]);
mal_bool32
mal_channel_map_equal
(
mal_uint32
channels
,
const
mal_channel
channelMapA
[
MAL_MAX_CHANNELS
],
const
mal_channel
channelMapB
[
MAL_MAX_CHANNELS
]);
// Helper for determining if a channel map is blank (all channels set to MAL_CHANNEL_NONE).
mal_bool32
mal_channel_map_blank
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
]);
// Helper for determining whether or not a channel is present in the given channel map.
mal_bool32
mal_channel_map_contains_channel_position
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
],
mal_channel
channelPosition
);
///////////////////////////////////////////////////////////////////////////////
...
...
@@ -15367,7 +15381,30 @@ void mal_get_standard_channel_map(mal_standard_channel_map standardChannelMap, m
}
}
mal_bool32
mal_channel_map_equal
(
mal_uint32
channels
,
mal_channel
channelMapA
[
MAL_MAX_CHANNELS
],
mal_channel
channelMapB
[
MAL_MAX_CHANNELS
])
mal_bool32
mal_channel_map_valid
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
])
{
if
(
channelMap
==
NULL
)
{
return
MAL_FALSE
;
}
// A channel count of 0 is invalid.
if
(
channels
==
0
)
{
return
MAL_FALSE
;
}
// It does not make sense to have a mono channel when there is more than 1 channel.
if
(
channels
>
1
)
{
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
channels
;
++
iChannel
)
{
if
(
channelMap
[
iChannel
]
==
MAL_CHANNEL_MONO
)
{
return
MAL_FALSE
;
}
}
}
return
MAL_TRUE
;
}
mal_bool32
mal_channel_map_equal
(
mal_uint32
channels
,
const
mal_channel
channelMapA
[
MAL_MAX_CHANNELS
],
const
mal_channel
channelMapB
[
MAL_MAX_CHANNELS
])
{
if
(
channelMapA
==
channelMapB
)
{
return
MAL_FALSE
;
...
...
@@ -15386,6 +15423,28 @@ mal_bool32 mal_channel_map_equal(mal_uint32 channels, mal_channel channelMapA[MA
return
MAL_TRUE
;
}
mal_bool32
mal_channel_map_blank
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
])
{
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
channels
;
++
iChannel
)
{
if
(
channelMap
[
iChannel
]
!=
MAL_CHANNEL_NONE
)
{
return
MAL_FALSE
;
}
}
return
MAL_TRUE
;
}
mal_bool32
mal_channel_map_contains_channel_position
(
mal_uint32
channels
,
const
mal_channel
channelMap
[
MAL_MAX_CHANNELS
],
mal_channel
channelPosition
)
{
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
channels
;
++
iChannel
)
{
if
(
channelMap
[
iChannel
]
==
channelPosition
)
{
return
MAL_TRUE
;
}
}
return
MAL_FALSE
;
}
...
...
@@ -17045,10 +17104,88 @@ typedef struct
float
z
;
}
mal_vec3
;
static
inline
mal_vec3
mal_vec3f
(
float
x
,
float
y
,
float
z
)
{
mal_vec3
r
;
r
.
x
=
x
;
r
.
y
=
y
;
r
.
z
=
z
;
return
r
;
}
static
inline
mal_vec3
mal_vec3_add
(
mal_vec3
a
,
mal_vec3
b
)
{
return
mal_vec3f
(
a
.
x
+
b
.
x
,
a
.
y
+
b
.
y
,
a
.
z
+
b
.
z
);
}
static
inline
mal_vec3
mal_vec3_sub
(
mal_vec3
a
,
mal_vec3
b
)
{
return
mal_vec3f
(
a
.
x
-
b
.
x
,
a
.
y
-
b
.
y
,
a
.
z
-
b
.
z
);
}
static
inline
mal_vec3
mal_vec3_mul
(
mal_vec3
a
,
mal_vec3
b
)
{
return
mal_vec3f
(
a
.
x
*
b
.
x
,
a
.
y
*
b
.
y
,
a
.
z
*
b
.
z
);
}
static
inline
mal_vec3
mal_vec3_div
(
mal_vec3
a
,
mal_vec3
b
)
{
return
mal_vec3f
(
a
.
x
/
b
.
x
,
a
.
y
/
b
.
y
,
a
.
z
/
b
.
z
);
}
static
inline
float
mal_vec3_dot
(
mal_vec3
a
,
mal_vec3
b
)
{
return
a
.
x
*
b
.
x
+
a
.
y
*
b
.
y
+
a
.
z
*
b
.
z
;
}
static
inline
float
mal_vec3_length2
(
mal_vec3
a
)
{
return
mal_vec3_dot
(
a
,
a
);
}
static
inline
float
mal_vec3_length
(
mal_vec3
a
)
{
return
(
float
)
sqrt
(
mal_vec3_length2
(
a
));
}
static
inline
mal_vec3
mal_vec3_normalize
(
mal_vec3
a
)
{
float
len
=
1
/
mal_vec3_length
(
a
);
mal_vec3
r
;
r
.
x
=
a
.
x
*
len
;
r
.
y
=
a
.
y
*
len
;
r
.
z
=
a
.
z
*
len
;
return
r
;
}
static
inline
float
mal_vec3_distance
(
mal_vec3
a
,
mal_vec3
b
)
{
return
mal_vec3_length
(
mal_vec3_sub
(
a
,
b
));
}
// TODO: Make physical channel positions configurable.
// The position of each speaker
relative to the head
.
mal_vec3
g_mal
ChannelPositionsRelativeToHead
[
MAL_CHANNEL_POSITION_COUNT
]
=
{
// The position of each speaker
in the room
.
mal_vec3
g_mal
DefaultChannelPositionsInRoom
[
MAL_CHANNEL_POSITION_COUNT
]
=
{
{
0.0
f
,
0.0
f
,
0.0
f
},
// MAL_CHANNEL_NONE
{
0.0
f
,
0.0
f
,
0.0
f
},
// MAL_CHANNEL_MONO
{
-
1.0
f
,
0.0
f
,
-
1.0
f
},
// MAL_CHANNEL_FRONT_LEFT
...
...
@@ -17103,6 +17240,134 @@ mal_vec3 g_malChannelPositionsRelativeToHead[MAL_CHANNEL_POSITION_COUNT] = {
{
0.0
f
,
0.0
f
,
0.0
f
},
// MAL_CHANNEL_AUX_31
};
float
mal_calculate_channel_position_planar_weight
(
mal_channel
channelPositionA
,
mal_channel
channelPositionB
)
{
mal_vec3
roomPosA
=
g_malDefaultChannelPositionsInRoom
[
channelPositionA
];
mal_vec3
roomPosB
=
g_malDefaultChannelPositionsInRoom
[
channelPositionB
];
mal_uint32
planeCountA
=
0
;
if
(
roomPosA
.
x
<
0
||
roomPosA
.
x
>
0
)
planeCountA
+=
1
;
if
(
roomPosA
.
y
<
0
||
roomPosA
.
y
>
0
)
planeCountA
+=
1
;
if
(
roomPosA
.
z
<
0
||
roomPosA
.
z
>
0
)
planeCountA
+=
1
;
mal_uint32
sharedPlaneCount
=
0
;
if
(
roomPosA
.
x
<
0
&&
roomPosB
.
x
<
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
x
>
0
&&
roomPosB
.
x
>
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
y
<
0
&&
roomPosB
.
y
<
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
y
>
0
&&
roomPosB
.
y
>
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
z
<
0
&&
roomPosB
.
z
<
0
)
sharedPlaneCount
+=
1
;
if
(
roomPosA
.
z
>
0
&&
roomPosB
.
z
>
0
)
sharedPlaneCount
+=
1
;
mal_assert
(
sharedPlaneCount
<=
planeCountA
);
mal_assert
(
sharedPlaneCount
<=
3
);
if
(
sharedPlaneCount
==
0
)
{
return
0
;
}
return
(
float
)
planeCountA
/
sharedPlaneCount
;
}
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.
mal_vec3
channelRoomPosA
=
g_malDefaultChannelPositionsInRoom
[
channelPositionA
];
mal_vec3
channelRoomPosB
=
g_malDefaultChannelPositionsInRoom
[
channelPositionB
];
mal_vec3
channelDirToHeadA
=
mal_vec3_normalize
(
mal_vec3_sub
(
listenerRoomPos
,
channelRoomPosA
));
mal_vec3
channelDirToHeadB
=
mal_vec3_normalize
(
mal_vec3_sub
(
listenerRoomPos
,
channelRoomPosB
));
float
weight
=
mal_vec3_dot
(
channelDirToHeadA
,
channelDirToHeadB
);
if
(
weight
<=
0
)
{
return
0
;
}
float
distA
=
mal_vec3_distance
(
channelRoomPosA
,
listenerRoomPos
);
float
distB
=
mal_vec3_distance
(
channelRoomPosB
,
listenerRoomPos
);
float
distFalloffLinear
=
distB
/
distA
;
float
distFalloffExp
=
distFalloffLinear
*
distFalloffLinear
;
weight
=
weight
*
distFalloffExp
;
return
weight
;
}
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
;
for
(
mal_uint32
iChannel
=
0
;
iChannel
<
channelCount
;
++
iChannel
)
{
mal_vec3
roomPosA
=
g_malDefaultChannelPositionsInRoom
[
channelPosition
];
mal_vec3
roomPosB
=
g_malDefaultChannelPositionsInRoom
[
channelMap
[
iChannel
]];
if
(
roomPosA
.
x
<
0
&&
roomPosB
.
x
<
0
)
{
count
+=
1
;
continue
;
}
if
(
roomPosA
.
x
>
0
&&
roomPosB
.
x
>
0
)
{
count
+=
1
;
continue
;
}
if
(
roomPosA
.
y
<
0
&&
roomPosB
.
y
<
0
)
{
count
+=
1
;
continue
;
}
if
(
roomPosA
.
y
>
0
&&
roomPosB
.
y
>
0
)
{
count
+=
1
;
continue
;
}
if
(
roomPosA
.
z
<
0
&&
roomPosB
.
z
<
0
)
{
count
+=
1
;
continue
;
}
if
(
roomPosA
.
z
>
0
&&
roomPosB
.
z
>
0
)
{
count
+=
1
;
continue
;
}
}
return
count
;
}
float
mal_channel_router__calculate_input_channel_planar_weight
(
const
mal_channel_router
*
pRouter
,
mal_channel
channelPositionIn
,
mal_channel
channelPositionOut
)
{
mal_assert
(
pRouter
!=
NULL
);
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
;
}
float
mal_channel_router__calculate_spatial_weight
(
const
mal_channel_router
*
pRouter
,
mal_channel
channelPositionA
,
mal_channel
channelPositionB
)
{
mal_assert
(
pRouter
!=
NULL
);
(
void
)
pRouter
;
return
mal_calculate_channel_position_spatial_weight
(
channelPositionA
,
channelPositionB
,
mal_vec3f
(
0
,
0
,
0
));
}
mal_bool32
mal_channel_router__is_spatial_channel_position
(
const
mal_channel_router
*
pRouter
,
mal_channel
channelPosition
)
{
mal_assert
(
pRouter
!=
NULL
);
(
void
)
pRouter
;
if
(
channelPosition
==
MAL_CHANNEL_NONE
||
channelPosition
==
MAL_CHANNEL_MONO
||
channelPosition
==
MAL_CHANNEL_LFE
)
{
return
MAL_FALSE
;
}
if
(
mal_vec3_length
(
g_malDefaultChannelPositionsInRoom
[
channelPosition
])
==
0
)
{
return
MAL_FALSE
;
}
return
MAL_TRUE
;
}
mal_result
mal_channel_router_init__common
(
const
mal_channel_router_config
*
pConfig
,
void
*
pUserData
,
mal_channel_router
*
pRouter
)
{
if
(
pRouter
==
NULL
)
{
...
...
@@ -17115,6 +17380,13 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
return
MAL_INVALID_ARGS
;
}
if
(
!
mal_channel_map_valid
(
pConfig
->
channelsIn
,
pConfig
->
channelMapIn
))
{
return
MAL_INVALID_ARGS
;
// Invalid input channel map.
}
if
(
!
mal_channel_map_valid
(
pConfig
->
channelsIn
,
pConfig
->
channelMapOut
))
{
return
MAL_INVALID_ARGS
;
// Invalid output channel map.
}
pRouter
->
config
=
*
pConfig
;
pRouter
->
pUserData
=
pUserData
;
...
...
@@ -17123,6 +17395,9 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
if
(
mal_channel_map_equal
(
pRouter
->
config
.
channelsIn
,
pRouter
->
config
.
channelMapIn
,
pRouter
->
config
.
channelMapOut
))
{
pRouter
->
isPassthrough
=
MAL_TRUE
;
}
if
(
mal_channel_map_blank
(
pRouter
->
config
.
channelsIn
,
pRouter
->
config
.
channelMapIn
)
||
mal_channel_map_blank
(
pRouter
->
config
.
channelsOut
,
pRouter
->
config
.
channelMapOut
))
{
pRouter
->
isPassthrough
=
MAL_TRUE
;
}
}
// Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules:
...
...
@@ -17130,7 +17405,7 @@ mal_result mal_channel_router_init__common(const mal_channel_router_config* pCon
// 1) If it's a passthrough, do nothing - it's just a simple memcpy().
// 2) If the channel counts are the same and every channel position in the input map is present in the output map, use a
// simple shuffle. An example might be different 5.1 channel layouts.
// 3) LFEs are treated differently. The will only receive audio data from other LFEs, or silence.
// 3) LFEs are treated differently. The
y
will only receive audio data from other LFEs, or silence.
// 4) Mono channels are distributed evenly across all channels, except LFEs.
// 5) AUX channels will receive audio data from their matching counterpart, mono channels, or silence.
// 6) All other channels will receive audio data based on their position relative to the head position.
...
...
@@ -17167,16 +17442,137 @@ 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.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
// If it's not a simple shuffle it's a bit more complicated. We route the input channels to the relevant output channels based on spacial
// locality. Special cases exist for mono and LFE positions. LFEs will only receive samples from other LFEs (there should usually be a
// maximum of 1 LFE per channel map, but there can technically be more). For mono, the sound is distributed across every other channel
// except LFEs.
if
(
!
pRouter
->
isSimpleShuffle
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
if
(
channelPosIn
==
channelPosOut
)
{
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
=
1
;
}
}
}
// The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since
// they were handled in the pass above.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
if
(
channelPosIn
==
MAL_CHANNEL_MONO
)
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
if
(
channelPosOut
!=
MAL_CHANNEL_NONE
&&
channelPosOut
!=
MAL_CHANNEL_MONO
&&
channelPosOut
!=
MAL_CHANNEL_LFE
)
{
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
=
1
;
}
}
}
}
// The output mono channel is the average of all non-none, non-mono and non-lfe input channels.
{
mal_uint32
len
=
0
;
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
if
(
channelPosIn
!=
MAL_CHANNEL_NONE
&&
channelPosIn
!=
MAL_CHANNEL_MONO
&&
channelPosIn
!=
MAL_CHANNEL_LFE
)
{
len
+=
1
;
}
}
if
(
len
>
0
)
{
float
monoWeight
=
1.0
f
/
len
;
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
if
(
channelPosOut
==
MAL_CHANNEL_MONO
)
{
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
if
(
channelPosIn
!=
MAL_CHANNEL_NONE
&&
channelPosIn
!=
MAL_CHANNEL_MONO
&&
channelPosIn
!=
MAL_CHANNEL_LFE
)
{
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
+=
monoWeight
;
}
}
}
}
}
}
// 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.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosIn
))
{
if
(
!
mal_channel_map_contains_channel_position
(
pRouter
->
config
.
channelsOut
,
pRouter
->
config
.
channelMapOut
,
channelPosIn
))
{
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosOut
))
{
float
weight
=
0
;
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_average
)
{
weight
=
mal_channel_router__calculate_input_channel_planar_weight
(
pRouter
,
channelPosIn
,
channelPosOut
);
}
#if 0
else if (pRouter->config.mixingMode == mal_channel_mix_mode_spatial) {
weight = mal_channel_router__calculate_spatial_weight(pRouter, channelPosIn, channelPosOut);
}
#endif
// Only apply the weight if we haven't already got some contribution from the respective channels.
if
(
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
==
0
)
{
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
=
weight
;
}
}
}
}
}
}
// Output channels that are not present in input channel map.
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
mal_channel
channelPosOut
=
pRouter
->
config
.
channelMapOut
[
iChannelOut
];
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosOut
))
{
if
(
!
mal_channel_map_contains_channel_position
(
pRouter
->
config
.
channelsIn
,
pRouter
->
config
.
channelMapIn
,
channelPosOut
))
{
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
mal_channel
channelPosIn
=
pRouter
->
config
.
channelMapIn
[
iChannelIn
];
if
(
mal_channel_router__is_spatial_channel_position
(
pRouter
,
channelPosIn
))
{
float
weight
=
0
;
if
(
pRouter
->
config
.
mixingMode
==
mal_channel_mix_mode_planar_average
)
{
weight
=
mal_channel_router__calculate_input_channel_planar_weight
(
pRouter
,
channelPosIn
,
channelPosOut
);
}
#if 0
else if (pRouter->config.mixingMode == mal_channel_mix_mode_spatial) {
weight = mal_channel_router__calculate_spatial_weight(pRouter, channelPosIn, channelPosOut);
}
#endif
// Only apply the weight if we haven't already got some contribution from the respective channels.
if
(
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
==
0
)
{
pRouter
->
weights
[
iChannelIn
][
iChannelOut
]
=
weight
;
}
}
}
}
}
}
}
return
MAL_SUCCESS
;
}
...
...
@@ -17218,10 +17614,9 @@ void mal_channel_router__do_routing(mal_channel_router* pRouter, mal_uint64 fram
// Accumulate.
for
(
mal_uint32
iChannelIn
=
0
;
iChannelIn
<
pRouter
->
config
.
channelsIn
;
++
iChannelIn
)
{
for
(
mal_uint64
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
for
(
mal_uint32
j
=
0
;
pRouter
->
shuffleData
[
iChannelIn
][
j
].
iChannelOut
!=
(
mal_uint8
)
-
1
;
++
j
)
{
mal_uint8
iChannelOut
=
pRouter
->
shuffleData
[
iChannelIn
][
j
].
iChannelOut
;
ppSamplesOut
[
iChannelOut
][
iFrame
]
+=
ppSamplesIn
[
iChannelIn
][
iFrame
]
*
(
pRouter
->
shuffleData
[
iChannelIn
][
j
].
volume
/
255.0
f
);
for
(
mal_uint32
iChannelOut
=
0
;
iChannelOut
<
pRouter
->
config
.
channelsOut
;
++
iChannelOut
)
{
for
(
mal_uint64
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
ppSamplesOut
[
iChannelOut
][
iFrame
]
+=
ppSamplesIn
[
iChannelIn
][
iFrame
]
*
pRouter
->
weights
[
iChannelIn
][
iChannelOut
];
}
}
}
...
...
@@ -17925,7 +18320,7 @@ void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const
(
void
)
channelMapOut
;
(
void
)
channelMapIn
;
if
(
mode
==
mal_channel_mix_mode_
basic
)
{
if
(
mode
==
mal_channel_mix_mode_
simple
)
{
// Basic mode is where we just drop excess channels.
for
(
mal_uint32
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
switch
(
channelsOut
)
{
...
...
@@ -18007,10 +18402,10 @@ void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const
}
}
else
if
(
channelsOut
==
2
)
{
// TODO: Implement proper stereo blending.
mal_dsp_mix_channels__dec
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
basic
);
mal_dsp_mix_channels__dec
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
simple
);
}
else
{
// Fall back to basic mode.
mal_dsp_mix_channels__dec
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
basic
);
mal_dsp_mix_channels__dec
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
simple
);
}
}
}
...
...
@@ -18026,7 +18421,7 @@ void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut, const
(
void
)
channelMapOut
;
(
void
)
channelMapIn
;
if
(
mode
==
mal_channel_mix_mode_
basic
)
{
if
(
mode
==
mal_channel_mix_mode_
simple
)
{
// Basic mode is where we just zero out extra channels.
for
(
mal_uint32
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
switch
(
channelsIn
)
{
...
...
@@ -18142,10 +18537,10 @@ void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut, const
}
}
else
if
(
channelsIn
==
2
)
{
// TODO: Implement an optimized stereo conversion.
mal_dsp_mix_channels__inc
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
basic
);
mal_dsp_mix_channels__inc
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
simple
);
}
else
{
// Fall back to basic mixing mode.
mal_dsp_mix_channels__inc
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
basic
);
mal_dsp_mix_channels__inc
(
pFramesOut
,
channelsOut
,
channelMapOut
,
pFramesIn
,
channelsIn
,
channelMapIn
,
frameCount
,
mal_channel_mix_mode_
simple
);
}
}
}
...
...
@@ -18415,7 +18810,7 @@ mal_uint64 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pF
pFramesFormat
[
iFrames
]
=
mal_format_f32
;
}
mal_dsp_mix_channels
((
float
*
)(
pFrames
[(
iFrames
+
1
)
%
2
]),
pDSP
->
config
.
channelsOut
,
pDSP
->
config
.
channelMapOut
,
(
const
float
*
)(
pFrames
[
iFrames
]),
pDSP
->
config
.
channelsIn
,
pDSP
->
config
.
channelMapIn
,
framesRead
,
mal_channel_mix_mode_blend
);
mal_dsp_mix_channels
((
float
*
)(
pFrames
[(
iFrames
+
1
)
%
2
]),
pDSP
->
config
.
channelsOut
,
pDSP
->
config
.
channelMapOut
,
(
const
float
*
)(
pFrames
[
iFrames
]),
pDSP
->
config
.
channelsIn
,
pDSP
->
config
.
channelMapIn
,
framesRead
,
pDSP
->
config
.
channelMixMode
);
iFrames
=
(
iFrames
+
1
)
%
2
;
pFramesFormat
[
iFrames
]
=
mal_format_f32
;
}
...
...
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