freesig / cpal

Audio player in pure Rust
0 stars 0 forks source link

Formats #4

Closed freesig closed 5 years ago

freesig commented 5 years ago

CPAL seems to support:

u16
i16
f32

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.

freesig commented 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
mitchmindtree commented 5 years ago

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

freesig commented 5 years ago

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.

freesig commented 5 years ago

Todo

freesig commented 5 years ago

U16

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.

Float Endianness

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

mitchmindtree commented 5 years ago

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?