Skip to content

Commit ec22de1

Browse files
committed
Intial support for 24 bits sample format (24bit stored on 4 bytes)
There are two common ways of storing 24 bits samples: - on 4 bytes (called 24, most common) - on 3 bytes (called 24_3) With the current code, 3 bytes seems difficult to implement and would require a larger code refactoring. That being said, having at least '24' helps to work with hardware that only offer it.
1 parent eb3d445 commit ec22de1

File tree

4 files changed

+82
-22
lines changed

4 files changed

+82
-22
lines changed

examples/synth_tones.rs

+4
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,14 @@ where
9898
match config.sample_format() {
9999
cpal::SampleFormat::I8 => make_stream::<i8>(&device, &config.into()),
100100
cpal::SampleFormat::I16 => make_stream::<i16>(&device, &config.into()),
101+
cpal::SampleFormat::I24 => make_stream::<i32>(&device, &config.into()),
102+
// cpal::SampleFormat::I24_3 => make_stream::<[i8; 3]>(&device, &config.into()),
101103
cpal::SampleFormat::I32 => make_stream::<i32>(&device, &config.into()),
102104
cpal::SampleFormat::I64 => make_stream::<i64>(&device, &config.into()),
103105
cpal::SampleFormat::U8 => make_stream::<u8>(&device, &config.into()),
104106
cpal::SampleFormat::U16 => make_stream::<u16>(&device, &config.into()),
107+
cpal::SampleFormat::U24 => make_stream::<u32>(&device, &config.into()),
108+
// cpal::SampleFormat::U24_3 => make_stream::<[i8; 3]>(&device, &config.into()),
105109
cpal::SampleFormat::U32 => make_stream::<u32>(&device, &config.into()),
106110
cpal::SampleFormat::U64 => make_stream::<u64>(&device, &config.into()),
107111
cpal::SampleFormat::F32 => make_stream::<f32>(&device, &config.into()),

src/host/alsa/mod.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -323,16 +323,17 @@ impl Device {
323323
let hw_params = alsa::pcm::HwParams::any(handle)?;
324324

325325
// TODO: check endianness
326-
const FORMATS: [(SampleFormat, alsa::pcm::Format); 8] = [
326+
const FORMATS: [(SampleFormat, alsa::pcm::Format); 10] = [
327327
(SampleFormat::I8, alsa::pcm::Format::S8),
328328
(SampleFormat::U8, alsa::pcm::Format::U8),
329329
(SampleFormat::I16, alsa::pcm::Format::S16LE),
330330
//SND_PCM_FORMAT_S16_BE,
331331
(SampleFormat::U16, alsa::pcm::Format::U16LE),
332332
//SND_PCM_FORMAT_U16_BE,
333333
//SND_PCM_FORMAT_S24_LE,
334+
(SampleFormat::I24, alsa::pcm::Format::S24LE),
334335
//SND_PCM_FORMAT_S24_BE,
335-
//SND_PCM_FORMAT_U24_LE,
336+
(SampleFormat::U24, alsa::pcm::Format::U24LE),
336337
//SND_PCM_FORMAT_U24_BE,
337338
(SampleFormat::I32, alsa::pcm::Format::S32LE),
338339
//SND_PCM_FORMAT_S32_BE,
@@ -350,9 +351,9 @@ impl Device {
350351
//SND_PCM_FORMAT_MPEG,
351352
//SND_PCM_FORMAT_GSM,
352353
//SND_PCM_FORMAT_SPECIAL,
353-
//SND_PCM_FORMAT_S24_3LE,
354+
//(SampleFormat::I24_3, alsa::pcm::Format::S243LE),
354355
//SND_PCM_FORMAT_S24_3BE,
355-
//SND_PCM_FORMAT_U24_3LE,
356+
//(SampleFormat::U24_3, alsa::pcm::Format::U243LE),
356357
//SND_PCM_FORMAT_U24_3BE,
357358
//SND_PCM_FORMAT_S20_3LE,
358359
//SND_PCM_FORMAT_S20_3BE,
@@ -1009,13 +1010,15 @@ fn set_hw_params_from_format(
10091010
match sample_format {
10101011
SampleFormat::I8 => alsa::pcm::Format::S8,
10111012
SampleFormat::I16 => alsa::pcm::Format::S16BE,
1012-
// SampleFormat::I24 => alsa::pcm::Format::S24BE,
1013+
SampleFormat::I24 => alsa::pcm::Format::S24BE,
1014+
// SampleFormat::I24_3 => alsa::pcm::Format::S243BE,
10131015
SampleFormat::I32 => alsa::pcm::Format::S32BE,
10141016
// SampleFormat::I48 => alsa::pcm::Format::S48BE,
10151017
// SampleFormat::I64 => alsa::pcm::Format::S64BE,
10161018
SampleFormat::U8 => alsa::pcm::Format::U8,
10171019
SampleFormat::U16 => alsa::pcm::Format::U16BE,
1018-
// SampleFormat::U24 => alsa::pcm::Format::U24BE,
1020+
SampleFormat::U24 => alsa::pcm::Format::U24BE,
1021+
// SampleFormat::U24_3 => alsa::pcm::Format::U243BE,
10191022
SampleFormat::U32 => alsa::pcm::Format::U32BE,
10201023
// SampleFormat::U48 => alsa::pcm::Format::U48BE,
10211024
// SampleFormat::U64 => alsa::pcm::Format::U64BE,
@@ -1034,13 +1037,15 @@ fn set_hw_params_from_format(
10341037
match sample_format {
10351038
SampleFormat::I8 => alsa::pcm::Format::S8,
10361039
SampleFormat::I16 => alsa::pcm::Format::S16LE,
1037-
// SampleFormat::I24 => alsa::pcm::Format::S24LE,
1040+
SampleFormat::I24 => alsa::pcm::Format::S24LE,
1041+
// SampleFormat::I24_3 => alsa::pcm::Format::S243LE,
10381042
SampleFormat::I32 => alsa::pcm::Format::S32LE,
10391043
// SampleFormat::I48 => alsa::pcm::Format::S48LE,
10401044
// SampleFormat::I64 => alsa::pcm::Format::S64LE,
10411045
SampleFormat::U8 => alsa::pcm::Format::U8,
10421046
SampleFormat::U16 => alsa::pcm::Format::U16LE,
1043-
// SampleFormat::U24 => alsa::pcm::Format::U24LE,
1047+
SampleFormat::U24 => alsa::pcm::Format::U24LE,
1048+
// SampleFormat::U24_3 => alsa::pcm::Format::U243LE,
10441049
SampleFormat::U32 => alsa::pcm::Format::U32LE,
10451050
// SampleFormat::U48 => alsa::pcm::Format::U48LE,
10461051
// SampleFormat::U64 => alsa::pcm::Format::U64LE,

src/lib.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
//! ```
3434
//!
3535
//! Before we can create a stream, we must decide what the configuration of the audio stream is
36-
//! going to be.
36+
//! going to be.
3737
//! You can query all the supported configurations with the
3838
//! [`supported_input_configs()`] and [`supported_output_configs()`] methods.
3939
//! These produce a list of [`SupportedStreamConfigRange`] structs which can later be turned into
@@ -225,7 +225,7 @@ pub type FrameCount = u32;
225225
/// behavior of the given host. Note, the default buffer size may be surprisingly
226226
/// large, leading to latency issues. If low latency is desired, [`Fixed(FrameCount)`]
227227
/// should be used in accordance with the [`SupportedBufferSize`] range produced by
228-
/// the [`SupportedStreamConfig`] API.
228+
/// the [`SupportedStreamConfig`] API.
229229
///
230230
/// [`Default`]: BufferSize::Default
231231
/// [`Fixed(FrameCount)`]: BufferSize::Fixed
@@ -695,7 +695,7 @@ impl SupportedStreamConfigRange {
695695
/// - Max sample rate
696696
pub fn cmp_default_heuristics(&self, other: &Self) -> std::cmp::Ordering {
697697
use std::cmp::Ordering::Equal;
698-
use SampleFormat::{F32, I16, U16};
698+
use SampleFormat::{F32, I16, I24, I32, U16, U24, U32};
699699

700700
let cmp_stereo = (self.channels == 2).cmp(&(other.channels == 2));
701701
if cmp_stereo != Equal {
@@ -717,6 +717,36 @@ impl SupportedStreamConfigRange {
717717
return cmp_f32;
718718
}
719719

720+
let cmp_i32 = (self.sample_format == I32).cmp(&(other.sample_format == I32));
721+
if cmp_i32 != Equal {
722+
return cmp_i32;
723+
}
724+
725+
let cmp_u32 = (self.sample_format == U32).cmp(&(other.sample_format == U32));
726+
if cmp_u32 != Equal {
727+
return cmp_u32;
728+
}
729+
730+
let cmp_i24 = (self.sample_format == I24).cmp(&(other.sample_format == I24));
731+
if cmp_i24 != Equal {
732+
return cmp_i24;
733+
}
734+
735+
let cmp_u24 = (self.sample_format == U24).cmp(&(other.sample_format == U24));
736+
if cmp_u24 != Equal {
737+
return cmp_u24;
738+
}
739+
740+
// let cmp_i24_3 = (self.sample_format == I24_3).cmp(&(other.sample_format == I24_3));
741+
// if cmp_i24_3 != Equal {
742+
// return cmp_i24_3;
743+
// }
744+
745+
// let cmp_u24_3 = (self.sample_format == U24_3).cmp(&(other.sample_format == U24_3));
746+
// if cmp_u24_3 != Equal {
747+
// return cmp_u24_3;
748+
// }
749+
720750
let cmp_i16 = (self.sample_format == I16).cmp(&(other.sample_format == I16));
721751
if cmp_i16 != Equal {
722752
return cmp_i16;

src/samples_formats.rs

+32-11
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ pub enum SampleFormat {
2929
/// `i16` with a valid range of `i16::MIN..=i16::MAX` with `0` being the origin.
3030
I16,
3131

32+
/// `I24` with a valid range of '-(1 << 23)..(1 << 23)' with `0` being the origin
33+
I24,
34+
3235
// /// `I24` with a valid range of '-(1 << 23)..(1 << 23)' with `0` being the origin
33-
// I24,
36+
// I24_3,
3437
/// `i32` with a valid range of `i32::MIN..=i32::MAX` with `0` being the origin.
3538
I32,
3639

37-
// /// `I24` with a valid range of '-(1 << 47)..(1 << 47)' with `0` being the origin
40+
// /// `I48` with a valid range of '-(1 << 47)..(1 << 47)' with `0` being the origin
3841
// I48,
3942
/// `i64` with a valid range of `i64::MIN..=i64::MAX` with `0` being the origin.
4043
I64,
@@ -45,8 +48,11 @@ pub enum SampleFormat {
4548
/// `u16` with a valid range of `u16::MIN..=u16::MAX` with `1 << 15 == 32768` being the origin.
4649
U16,
4750

48-
// /// `U24` with a valid range of '0..16777216' with `1 << 23 == 8388608` being the origin
49-
// U24,
51+
/// `U24` with a valid range of '0..16777216' with `1 << 23 == 8388608` being the origin
52+
U24,
53+
54+
// /// `U24_3` with a valid range of '0..16777216' with `1 << 23 == 8388608` being the origin
55+
// U24_3,
5056
/// `u32` with a valid range of `u32::MIN..=u32::MAX` with `1 << 31` being the origin.
5157
U32,
5258

@@ -70,7 +76,8 @@ impl SampleFormat {
7076
match *self {
7177
SampleFormat::I8 | SampleFormat::U8 => mem::size_of::<i8>(),
7278
SampleFormat::I16 | SampleFormat::U16 => mem::size_of::<i16>(),
73-
// SampleFormat::I24 | SampleFormat::U24 => 3,
79+
// SampleFormat::I24_3 | SampleFormat::U24_3 => 3,
80+
SampleFormat::I24 | SampleFormat::U24 => 4,
7481
SampleFormat::I32 | SampleFormat::U32 => mem::size_of::<i32>(),
7582
// SampleFormat::I48 | SampleFormat::U48 => 6,
7683
SampleFormat::I64 | SampleFormat::U64 => mem::size_of::<i64>(),
@@ -85,7 +92,11 @@ impl SampleFormat {
8592
//matches!(*self, SampleFormat::I8 | SampleFormat::I16 | SampleFormat::I24 | SampleFormat::I32 | SampleFormat::I48 | SampleFormat::I64)
8693
matches!(
8794
*self,
88-
SampleFormat::I8 | SampleFormat::I16 | SampleFormat::I32 | SampleFormat::I64
95+
SampleFormat::I8
96+
| SampleFormat::I16
97+
| SampleFormat::I24
98+
| SampleFormat::I32
99+
| SampleFormat::I64
89100
)
90101
}
91102

@@ -95,7 +106,11 @@ impl SampleFormat {
95106
//matches!(*self, SampleFormat::U8 | SampleFormat::U16 | SampleFormat::U24 | SampleFormat::U32 | SampleFormat::U48 | SampleFormat::U64)
96107
matches!(
97108
*self,
98-
SampleFormat::U8 | SampleFormat::U16 | SampleFormat::U32 | SampleFormat::U64
109+
SampleFormat::U8
110+
| SampleFormat::U16
111+
| SampleFormat::U24
112+
| SampleFormat::U32
113+
| SampleFormat::U64
99114
)
100115
}
101116

@@ -111,13 +126,15 @@ impl Display for SampleFormat {
111126
match *self {
112127
SampleFormat::I8 => "i8",
113128
SampleFormat::I16 => "i16",
114-
// SampleFormat::I24 => "i24",
129+
SampleFormat::I24 => "i24",
130+
// SampleFormat::I24_3 => "i24_3",
115131
SampleFormat::I32 => "i32",
116132
// SampleFormat::I48 => "i48",
117133
SampleFormat::I64 => "i64",
118134
SampleFormat::U8 => "u8",
119135
SampleFormat::U16 => "u16",
120-
// SampleFormat::U24 => "u24",
136+
SampleFormat::U24 => "u24",
137+
// SampleFormat::U24_3 => "u24_3",
121138
SampleFormat::U32 => "u32",
122139
// SampleFormat::U48 => "u48",
123140
SampleFormat::U64 => "u64",
@@ -140,7 +157,9 @@ impl SizedSample for i16 {
140157
const FORMAT: SampleFormat = SampleFormat::I16;
141158
}
142159

143-
// impl SizedSample for I24 { const FORMAT: SampleFormat = SampleFormat::I24; }
160+
impl SizedSample for I24 {
161+
const FORMAT: SampleFormat = SampleFormat::I24;
162+
}
144163

145164
impl SizedSample for i32 {
146165
const FORMAT: SampleFormat = SampleFormat::I32;
@@ -160,7 +179,9 @@ impl SizedSample for u16 {
160179
const FORMAT: SampleFormat = SampleFormat::U16;
161180
}
162181

163-
// impl SizedSample for U24 { const FORMAT: SampleFormat = SampleFormat::U24; }
182+
impl SizedSample for U24 {
183+
const FORMAT: SampleFormat = SampleFormat::U24;
184+
}
164185

165186
impl SizedSample for u32 {
166187
const FORMAT: SampleFormat = SampleFormat::U32;

0 commit comments

Comments
 (0)