1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use crate::Windows::{
Win32::Media::Audio::CoreAudio::WAVE_FORMAT_EXTENSIBLE,
Win32::Media::Multimedia::{
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, KSDATAFORMAT_SUBTYPE_PCM, WAVEFORMATEX,
WAVEFORMATEXTENSIBLE, WAVEFORMATEXTENSIBLE_0, WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_PCM,
},
};
use std::error;
use std::fmt;
use crate::{SampleType, WasapiError};
pub(crate) type WasapiRes<T> = Result<T, Box<dyn error::Error>>;
#[derive(Clone)]
pub struct WaveFormat {
pub wave_fmt: WAVEFORMATEXTENSIBLE,
}
impl fmt::Debug for WaveFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WaveFormat")
.field("nAvgBytesPerSec", &{ self.wave_fmt.Format.nAvgBytesPerSec })
.field("cbSize", &{ self.wave_fmt.Format.cbSize })
.field("nBlockAlign", &{ self.wave_fmt.Format.nBlockAlign })
.field("wBitsPerSample", &{ self.wave_fmt.Format.wBitsPerSample })
.field("nSamplesPerSec", &{ self.wave_fmt.Format.nSamplesPerSec })
.field("wFormatTag", &{ self.wave_fmt.Format.wFormatTag })
.field("wValidBitsPerSample", &unsafe {
self.wave_fmt.Samples.wValidBitsPerSample
})
.field("SubFormat", &{ self.wave_fmt.SubFormat })
.field("nChannel", &{ self.wave_fmt.Format.nChannels })
.field("dwChannelMask", &{ self.wave_fmt.dwChannelMask })
.finish()
}
}
impl WaveFormat {
pub fn new(
storebits: usize,
validbits: usize,
sample_type: &SampleType,
samplerate: usize,
channels: usize,
) -> Self {
let blockalign = channels * storebits / 8;
let byterate = samplerate * blockalign;
let wave_format = WAVEFORMATEX {
cbSize: 22,
nAvgBytesPerSec: byterate as u32,
nBlockAlign: blockalign as u16,
nChannels: channels as u16,
nSamplesPerSec: samplerate as u32,
wBitsPerSample: storebits as u16,
wFormatTag: WAVE_FORMAT_EXTENSIBLE as u16,
};
let sample = WAVEFORMATEXTENSIBLE_0 {
wValidBitsPerSample: validbits as u16,
};
let subformat = match sample_type {
SampleType::Float => KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
SampleType::Int => KSDATAFORMAT_SUBTYPE_PCM,
};
let mut mask = 0;
for n in 0..channels {
mask += 1 << n;
}
let wave_fmt = WAVEFORMATEXTENSIBLE {
Format: wave_format,
Samples: sample,
SubFormat: subformat,
dwChannelMask: mask,
};
WaveFormat { wave_fmt }
}
pub fn from_waveformatex(wavefmt: WAVEFORMATEX) -> WasapiRes<Self> {
let validbits = wavefmt.wBitsPerSample as usize;
let blockalign = wavefmt.nBlockAlign as usize;
let samplerate = wavefmt.nSamplesPerSec as usize;
let formattag = wavefmt.wFormatTag;
let channels = wavefmt.nChannels as usize;
let sample_type = match formattag as u32 {
WAVE_FORMAT_PCM => SampleType::Int,
WAVE_FORMAT_IEEE_FLOAT => SampleType::Float,
_ => {
return Err(WasapiError::new("Unsupported format").into());
}
};
let storebits = 8 * blockalign / channels;
Ok(WaveFormat::new(
storebits,
validbits,
&sample_type,
samplerate,
channels,
))
}
pub fn as_waveformatex_ptr(&self) -> *const WAVEFORMATEX {
&self.wave_fmt as *const _ as *const WAVEFORMATEX
}
pub fn get_blockalign(&self) -> u32 {
self.wave_fmt.Format.nBlockAlign as u32
}
pub fn get_avgbytespersec(&self) -> u32 {
self.wave_fmt.Format.nAvgBytesPerSec
}
pub fn get_bitspersample(&self) -> u16 {
self.wave_fmt.Format.wBitsPerSample
}
pub fn get_validbitspersample(&self) -> u16 {
unsafe { self.wave_fmt.Samples.wValidBitsPerSample }
}
pub fn get_samplespersec(&self) -> u32 {
self.wave_fmt.Format.nSamplesPerSec
}
pub fn get_nchannels(&self) -> u16 {
self.wave_fmt.Format.nChannels
}
pub fn get_dwchannelmask(&self) -> u32 {
self.wave_fmt.dwChannelMask
}
pub fn get_subformat(&self) -> WasapiRes<SampleType> {
let subfmt = match self.wave_fmt.SubFormat {
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT => SampleType::Float,
KSDATAFORMAT_SUBTYPE_PCM => SampleType::Int,
_ => {
return Err(WasapiError::new(
format!("Unknown subformat {:?}", { self.wave_fmt.SubFormat }).as_str(),
)
.into());
}
};
Ok(subfmt)
}
}