Closed freesig closed 5 years ago
Aim is to convert all possible ASIO formats to one of these three types. We also need to think about endianness. I think CPALs buffer is Big Endian right? @mitchmindtree
Type | Description | Conversion |
---|---|---|
Big Endian | The basic types, sample data is left aligned in the data word. The most significant Byte of the data word is stored first in memory. | |
ASIOSTInt16MSB | 16 bit data word (fewer than 16 bits are not supported) | |
to u16 (sample as f32 / 2.0 - i16::MAX) as u16 |
i16 | f32 |
from u16 ((sample as u32) * 2 - i16::MAX) as i16 |
||
ASIOSTInt24MSB | This is the packed 24 bit format. 2 data words will spawn consecutive 6 bytes in memory. (Used for 18 and 20 bits as well, if they use this packed format) | |
ASIOSTInt32MSB | This format should also be used for 24 bit data, if the sample data is left aligned. Lowest 8 bit should be reset or dithered whatever the hardware/software provides. | |
ASIOSTFloat32MSB | IEEE 754 32 bit float, as found on PowerPC implementation | |
ASIOSTFloat64MSB | IEEE 754 64 bit double float, as found on PowerPC implementation | |
Right aligned variations of the ASIOSTInt32MSB data type. | These are used for 32 bit data transfers with different alignment of the sample data inside the 32 bit data word. This supports right aligned sample data in the 32-bit data word, most significant bits should be sign extended. (32 bit PCI bus systems can be more easily used with these) | |
ASIOSTInt32MSB16 | sample data fills the least significant 16 bits, the other bits are sign extended | |
ASIOSTInt32MSB18 | sample data fills the least significant 18 bits, the other bits are sign extended | |
ASIOSTInt32MSB20 | sample data fills the least significant 20 bits, the other bits are sign extended | |
ASIOSTInt32MSB24 | sample data fills the least significant 24 bits, the other bits are sign extended | |
Little Endian formats | The basic types, sample data is left aligned in the container. The least significant Byte of the data word is stored first in memory. | |
ASIOSTInt16LSB | 16 bit data word | |
ASIOSTInt24LSB | This is the packed 24 bit format. 2 data words will spawn consecutive 6 bytes in memory. (Used for 18 and 20 bits as well, if they use this packed format) | |
ASIOSTInt32LSB | This format should also be used for 24 bit data, if the sample data is left aligned. Lowest 8 bit should be reset or dithered whatever the hardware/software provides. | |
ASIOSTFloat32LSB | IEEE 754 32 bit float, as found on Intel x86 architecture | |
ASIOSTFloat64LSB | IEEE 754 64 bit double float, as found on Intel x86 architecture | |
Right aligned variations of the ASIOSTInt32LSB data type. | These are used for 32 bit data transfers with different alignment of the sample data inside the 32 bit data word. This supports right aligned sample data in the 32-bit data word, most significant bits should be sign extended. (32 bit PCI bus systems can be more easily used with these) | |
ASIOSTInt32LSB16 | 32 bit data with 16 bit sample data right aligned | |
ASIOSTInt32LSB18 | 32 bit data with 18 bit sample data right aligned | |
ASIOSTInt32LSB20 | 32 bit data with 20 bit sample data right aligned | |
ASIOSTInt32LSB24 | 32 bit data with 24 bit sample data right aligned |
I think it's fine to only directly support those formats that directly convert into a valid CPAL format for now, maybe with an unimplemented!()
or an appropriate error for the rest. I think ideally we'd work out a nicer way to support differing formats dynamically in CPAL than the crazy UnknownTypeBuffer
type.
Re endianness I don't quite recall - I think it uses "native endianness", or whatever is the native layout for the system. Might have to check this though! The byteorder crate could possibly be useful for this (but might also be unnecessary).
I'm not sure how to check what endian cpal buffer uses. I'm assuming that because its just a Vec of u16 or i16 or f32 then it would be native. So I'll just do
if cfg!(target_endian = "big"){
sample = i32::from_be(sample);
}
etc.
Todo
I'm a bit confused about the u16 type here. Nothing in ASIO maps directly to that but we can easily convert. Should I convert to / from u16? Because right now that type is not available at all. This is pretty much what we have right now:
Ok(sys::AsioSampleType::ASIOSTInt16MSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTInt32MSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTFloat32MSB) => Ok(SampleFormat::F32),
Ok(sys::AsioSampleType::ASIOSTInt16LSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTInt32LSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTFloat32LSB) => Ok(SampleFormat::F32),
_ => Err(DefaultFormatError::StreamTypeNotSupported),
Is this fine or should it be more like Ok(sys::AsioSampleType::ASIOSTInt16LSB) => Ok([SampleFormat::I16, SampleFormat::u16])
as in possible formats from a certain format.
I can't seem to get a straight answer on this. The byteorder crate will only convert a [f32] but the fact that it's a [] means they are probably using each f32 to represent some sort of binary and not actually convert the f32. Check this explanation I'm not sure if this is beyond the scope of cpal or not
Re U16
- What you've already got is fine, there's no need to arbitrarily convert to U16
if ASIO never uses that format anyways.
Float Endianness - Hmm the docs for f32::from_bits
seems to imply that the endianness of floats (and ints) is standard across all platforms anyways, so maybe we can just assume it's correct?
CPAL seems to support:
However ASIO can support any format the audio card supports. We could just give a warning if the user tries to select a stream that is not one of the supported types.