//typedef mal_uint32 (* mal_src_read_proc)(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read.
typedef mal_uint32 (* mal_src_read_deinterleaved_proc)(mal_src* pSRC, mal_uint32 frameCount, void** ppSamplesOut, void* pUserData); // Returns the number of frames that were read.
mal_uint32 inputFrameCount; // The number of frames sitting in the input buffer, not including the first half of the window.
mal_uint32 windowPosInSamples; // An offset of <input>.
int _unused;
float table[MAL_SRC_SINC_MAX_WINDOW_WIDTH*1 * MAL_SRC_SINC_LOOKUP_TABLE_RESOLUTION]; // Precomputed lookup table. The +1 is used to avoid the need for an overflow check.
// 1) Conversion between data formats (u8 to f32, etc.)
// 2) Interleaving and deinterleaving
//
// When initializing a converter, you specify the input and output formats (u8, s16, etc.) and read callbacks. There are two read callbacks - one for
// interleaved input data (onRead) and another for deinterleaved input data (onReadDeinterleaved). You implement whichever is most convenient for you. You
// can implement both, but it's not recommended as it just introduces unnecessary complexity.
//
// To read data as interleaved samples, use mal_format_converter_read(). Otherwise use mal_format_converter_read_deinterleaved().
//
// Dithering
// ---------
// The format converter also supports dithering. Dithering can be set using ditherMode variable in the config, like so.
// The different dithering modes include the following, in order of efficiency:
// - None: mal_dither_mode_none
// - Rectangle: mal_dither_mode_rectangle
// - Triangle: mal_dither_mode_triangle
//
// Note that even if the dither mode is set to something other than mal_dither_mode_none, it will be ignored for conversions where dithering is not needed.
// Dithering is available for the following conversions:
// - s16 -> u8
// - s24 -> u8
// - s32 -> u8
// - f32 -> u8
// - s24 -> s16
// - s32 -> s16
// - f32 -> s16
//
// Note that it is not an error to pass something other than mal_dither_mode_none for conversions where dither is not used. It will just be ignored.
// There are two main things you can do with the channel router:
// 1) Rearrange channels
// 2) Convert from one channel count to another
//
// Channel Rearrangement
// ---------------------
// A simple example of channel rearrangement may be swapping the left and right channels in a stereo stream. To do this you just pass in the same channel
// count for both the input and output with channel maps that contain the same channels (in a different order).
//
// Channel Conversion
// ------------------
// The channel router can also convert from one channel count to another, such as converting a 5.1 stream to stero. When changing the channel count, the
// router will first perform a 1:1 mapping of channel positions that are present in both the input and output channel maps. The second thing it will do
// is distribute the input mono channel (if any) across all output channels, excluding any None and LFE channels. If there is an output mono channel, all
// input channels will be averaged, excluding any None and LFE channels.
//
// The last case to consider is when a channel position in the input channel map is not present in the output channel map, and vice versa. In this case the
// channel router will perform a blend of other related channels to produce an audible channel. There are several blending modes.
// 1) Simple
// Unmatched channels are silenced.
// 2) Planar Blending
// Channels are blended based on a set of planes that each speaker emits audio from.
//
// Planar Blending
// ---------------
// In this mode, channel positions are associated with a set of planes where the channel conceptually emits audio from. An example is the front/left speaker.
// This speaker is positioned to the front of the listener, so you can think of it as emitting audio from the front plane. It is also positioned to the left
// of the listener so you can think of it as also emitting audio from the left plane. Now consider the (unrealistic) situation where the input channel map
// contains only the front/left channel position, but the output channel map contains both the front/left and front/center channel. When deciding on the audio
// data to send to the front/center speaker (which has no 1:1 mapping with an input channel) we need to use some logic based on our available input channel
// positions.
//
// As mentioned earlier, our front/left speaker is, conceptually speaking, emitting audio from the front _and_ the left planes. Similarly, the front/center
// speaker is emitting audio from _only_ the front plane. What these two channels have in common is that they are both emitting audio from the front plane.
// Thus, it makes sense that the front/center speaker should receive some contribution from the front/left channel. How much contribution depends on their
// planar relationship (thus the name of this blending technique).
//
// Because the front/left channel is emitting audio from two planes (front and left), you can think of it as though it's willing to dedicate 50% of it's total
// volume to each of it's planes (a channel position emitting from 1 plane would be willing to given 100% of it's total volume to that plane, and a channel
// position emitting from 3 planes would be willing to given 33% of it's total volume to each plane). Similarly, the front/center speaker is emitting audio
// from only one plane so you can think of it as though it's willing to _take_ 100% of it's volume from front plane emissions. Now, since the front/left
// channel is willing to _give_ 50% of it's total volume to the front plane, and the front/center speaker is willing to _take_ 100% of it's total volume
// from the front, you can imagine that 50% of the front/left speaker will be given to the front/center speaker.
//
// Usage
// -----
// To use the channel router you need to specify three things:
// 1) The input channel count and channel map
// 2) The output channel count and channel map
// 3) The mixing mode to use in the case where a 1:1 mapping is unavailable
//
// Note that input and output data is always deinterleaved 32-bit floating point.
//
// Initialize the channel router with mal_channel_router_init(). You will need to pass in a config object which specifies the input and output configuration,
// mixing mode and a callback for sending data to the router. This callback will be called when input data needs to be sent to the router for processing.
//
// Read data from the channel router with mal_channel_router_read_deinterleaved(). Output data is always 32-bit floating point.
//typedef mal_uint32 (* mal_src_read_proc)(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read.
typedef mal_uint32 (* mal_src_read_deinterleaved_proc)(mal_src* pSRC, mal_uint32 frameCount, void** ppSamplesOut, void* pUserData); // Returns the number of frames that were read.
mal_uint32 inputFrameCount; // The number of frames sitting in the input buffer, not including the first half of the window.
mal_uint32 windowPosInSamples; // An offset of <input>.
float table[MAL_SRC_SINC_MAX_WINDOW_WIDTH*1 * MAL_SRC_SINC_LOOKUP_TABLE_RESOLUTION]; // Precomputed lookup table. The +1 is used to avoid the need for an overflow check.
// 1) Conversion between data formats (u8 to f32, etc.)
// 2) Interleaving and deinterleaving
//
// When initializing a converter, you specify the input and output formats (u8, s16, etc.) and read callbacks. There are two read callbacks - one for
// interleaved input data (onRead) and another for deinterleaved input data (onReadDeinterleaved). You implement whichever is most convenient for you. You
// can implement both, but it's not recommended as it just introduces unnecessary complexity.
//
// To read data as interleaved samples, use mal_format_converter_read(). Otherwise use mal_format_converter_read_deinterleaved().
//
// Dithering
// ---------
// The format converter also supports dithering. Dithering can be set using ditherMode variable in the config, like so.
// The different dithering modes include the following, in order of efficiency:
// - None: mal_dither_mode_none
// - Rectangle: mal_dither_mode_rectangle
// - Triangle: mal_dither_mode_triangle
//
// Note that even if the dither mode is set to something other than mal_dither_mode_none, it will be ignored for conversions where dithering is not needed.
// Dithering is available for the following conversions:
// - s16 -> u8
// - s24 -> u8
// - s32 -> u8
// - f32 -> u8
// - s24 -> s16
// - s32 -> s16
// - f32 -> s16
//
// Note that it is not an error to pass something other than mal_dither_mode_none for conversions where dither is not used. It will just be ignored.
// There are two main things you can do with the channel router:
// 1) Rearrange channels
// 2) Convert from one channel count to another
//
// Channel Rearrangement
// ---------------------
// A simple example of channel rearrangement may be swapping the left and right channels in a stereo stream. To do this you just pass in the same channel
// count for both the input and output with channel maps that contain the same channels (in a different order).
//
// Channel Conversion
// ------------------
// The channel router can also convert from one channel count to another, such as converting a 5.1 stream to stero. When changing the channel count, the
// router will first perform a 1:1 mapping of channel positions that are present in both the input and output channel maps. The second thing it will do
// is distribute the input mono channel (if any) across all output channels, excluding any None and LFE channels. If there is an output mono channel, all
// input channels will be averaged, excluding any None and LFE channels.
//
// The last case to consider is when a channel position in the input channel map is not present in the output channel map, and vice versa. In this case the
// channel router will perform a blend of other related channels to produce an audible channel. There are several blending modes.
// 1) Simple
// Unmatched channels are silenced.
// 2) Planar Blending
// Channels are blended based on a set of planes that each speaker emits audio from.
//
// Planar Blending
// ---------------
// In this mode, channel positions are associated with a set of planes where the channel conceptually emits audio from. An example is the front/left speaker.
// This speaker is positioned to the front of the listener, so you can think of it as emitting audio from the front plane. It is also positioned to the left
// of the listener so you can think of it as also emitting audio from the left plane. Now consider the (unrealistic) situation where the input channel map
// contains only the front/left channel position, but the output channel map contains both the front/left and front/center channel. When deciding on the audio
// data to send to the front/center speaker (which has no 1:1 mapping with an input channel) we need to use some logic based on our available input channel
// positions.
//
// As mentioned earlier, our front/left speaker is, conceptually speaking, emitting audio from the front _and_ the left planes. Similarly, the front/center
// speaker is emitting audio from _only_ the front plane. What these two channels have in common is that they are both emitting audio from the front plane.
// Thus, it makes sense that the front/center speaker should receive some contribution from the front/left channel. How much contribution depends on their
// planar relationship (thus the name of this blending technique).
//
// Because the front/left channel is emitting audio from two planes (front and left), you can think of it as though it's willing to dedicate 50% of it's total
// volume to each of it's planes (a channel position emitting from 1 plane would be willing to given 100% of it's total volume to that plane, and a channel
// position emitting from 3 planes would be willing to given 33% of it's total volume to each plane). Similarly, the front/center speaker is emitting audio
// from only one plane so you can think of it as though it's willing to _take_ 100% of it's volume from front plane emissions. Now, since the front/left
// channel is willing to _give_ 50% of it's total volume to the front plane, and the front/center speaker is willing to _take_ 100% of it's total volume
// from the front, you can imagine that 50% of the front/left speaker will be given to the front/center speaker.
//
// Usage
// -----
// To use the channel router you need to specify three things:
// 1) The input channel count and channel map
// 2) The output channel count and channel map
// 3) The mixing mode to use in the case where a 1:1 mapping is unavailable
//
// Note that input and output data is always deinterleaved 32-bit floating point.
//
// Initialize the channel router with mal_channel_router_init(). You will need to pass in a config object which specifies the input and output configuration,
// mixing mode and a callback for sending data to the router. This callback will be called when input data needs to be sent to the router for processing.
//
// Read data from the channel router with mal_channel_router_read_deinterleaved(). Output data is always 32-bit floating point.