// 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.