rea_rs/
hardware_functions.rs

1use std::mem::MaybeUninit;
2
3use log::debug;
4
5use crate::{
6    utils::{as_string, as_string_mut, make_c_string_buf},
7    HardwareSocket, Reaper, SampleAmount,
8};
9
10impl Reaper {
11    /// Get latency in samples.
12    ///
13    /// Returns `(input, output)` latency.
14    pub fn get_latency(&self) -> (SampleAmount, SampleAmount) {
15        unsafe {
16            let (mut input, mut output) =
17                (MaybeUninit::new(0), MaybeUninit::new(0));
18            self.low().GetInputOutputLatency(
19                input.as_mut_ptr(),
20                output.as_mut_ptr(),
21            );
22            (
23                SampleAmount::new(input.assume_init() as u32),
24                SampleAmount::new(output.assume_init() as u32),
25            )
26        }
27    }
28
29    /// Try to evaluate samplerate from the latency parameters.
30    ///
31    /// Not stable, and can be not precise.
32    pub fn get_approximate_samplerate(&self) -> u32 {
33        let secs_raw = self.low().GetOutputLatency();
34        let (_, samples) = self.get_latency();
35        debug!(
36            "latency in samples: {:?}, latency in seconds: {:?}",
37            samples, secs_raw
38        );
39        let rate = samples.get() as f64 / secs_raw;
40        rate as u32
41    }
42
43    /// Open all audio and MIDI devices (if not opened).
44    pub fn audio_init(&self) {
45        self.low().Audio_Init()
46    }
47
48    /// Reset all MIDI devices.
49    pub fn midi_reinit(&self) {
50        self.low().midi_reinit()
51    }
52
53    /// Return whether audio is in pre-buffer (thread safe).
54    pub fn audio_is_pre_buffer(&self) -> bool {
55        self.low().Audio_IsPreBuffer() != 0
56    }
57
58    /// Return whether audio is running (thread safe).
59    pub fn audio_is_running(&self) -> bool {
60        self.low().Audio_IsRunning() != 0
61    }
62
63    pub fn get_n_audio_inputs(&self) -> usize {
64        self.low().GetNumAudioInputs() as usize
65    }
66
67    pub fn get_n_audio_outputs(&self) -> usize {
68        self.low().GetNumAudioOutputs() as usize
69    }
70
71    pub fn iter_audio_inputs(&self) -> AudioInputsIterator {
72        AudioInputsIterator::new(self.get_n_audio_inputs())
73    }
74
75    pub fn iter_audio_outputs(&self) -> AudioOutputsIterator {
76        AudioOutputsIterator::new(self.get_n_audio_outputs())
77    }
78
79    pub fn get_max_midi_inputs(&self) -> usize {
80        self.low().GetMaxMidiInputs() as usize
81    }
82
83    pub fn get_midi_input(&self, index: usize) -> Option<HardwareSocket> {
84        let size = 256;
85        let buf = make_c_string_buf(size).into_raw();
86        let status = unsafe {
87            self.low().GetMIDIInputName(index as i32, buf, size as i32)
88        };
89        match status {
90            false => None,
91            true => HardwareSocket::new(
92                index as u32,
93                as_string_mut(buf).expect("Can not convert name to String."),
94            )
95            .into(),
96        }
97    }
98
99    pub fn get_max_midi_outputs(&self) -> usize {
100        self.low().GetMaxMidiOutputs() as usize
101    }
102
103    pub fn get_midi_output(&self, index: usize) -> Option<HardwareSocket> {
104        let size = 256;
105        let buf = make_c_string_buf(size).into_raw();
106        let status = unsafe {
107            self.low().GetMIDIOutputName(index as i32, buf, size as i32)
108        };
109        match status {
110            false => None,
111            true => HardwareSocket::new(
112                index as u32,
113                as_string_mut(buf).expect("Can not convert name to String."),
114            )
115            .into(),
116        }
117    }
118
119    pub fn get_audio_input(&self, index: usize) -> Option<HardwareSocket> {
120        let result = self.low().GetInputChannelName(index as i32);
121        match as_string(result) {
122            Err(_) => None,
123            Ok(name) => {
124                if &name == "" {
125                    return None;
126                }
127                HardwareSocket::new(index as u32, name).into()
128            }
129        }
130    }
131
132    pub fn get_audio_output(&self, index: usize) -> Option<HardwareSocket> {
133        let result = self.low().GetOutputChannelName(index as i32);
134        match as_string(result) {
135            Err(_) => None,
136            Ok(name) => {
137                if &name == "" {
138                    return None;
139                }
140                HardwareSocket::new(index as u32, name).into()
141            }
142        }
143    }
144
145    pub fn get_n_midi_inputs(&self) -> usize {
146        self.low().GetNumMIDIInputs() as usize
147    }
148
149    pub fn get_n_midi_outputs(&self) -> usize {
150        self.low().GetNumMIDIOutputs() as usize
151    }
152
153    pub fn iter_midi_inputs(&self) -> MidiInputsIterator {
154        MidiInputsIterator::new(self.get_n_midi_inputs())
155    }
156
157    pub fn iter_midi_outputs(&self) -> MidiOutputsIterator {
158        MidiOutputsIterator::new(self.get_n_midi_outputs())
159    }
160}
161
162pub struct AudioInputsIterator {
163    index: usize,
164    amount: usize,
165}
166impl AudioInputsIterator {
167    pub fn new(num_inputs: usize) -> Self {
168        Self {
169            index: 0,
170            amount: num_inputs,
171        }
172    }
173}
174impl Iterator for AudioInputsIterator {
175    type Item = HardwareSocket;
176    fn next(&mut self) -> Option<Self::Item> {
177        if self.index >= self.amount {
178            return None;
179        }
180        self.index += 1;
181        Reaper::get().get_audio_input(self.index - 1)
182    }
183}
184
185pub struct AudioOutputsIterator {
186    index: usize,
187    amount: usize,
188}
189impl AudioOutputsIterator {
190    pub fn new(num_outputs: usize) -> Self {
191        Self {
192            index: 0,
193            amount: num_outputs,
194        }
195    }
196}
197impl Iterator for AudioOutputsIterator {
198    type Item = HardwareSocket;
199    fn next(&mut self) -> Option<Self::Item> {
200        if self.index >= self.amount {
201            return None;
202        }
203        self.index += 1;
204        Reaper::get().get_audio_output(self.index - 1)
205    }
206}
207
208pub struct MidiInputsIterator {
209    index: usize,
210    amount: usize,
211}
212impl MidiInputsIterator {
213    pub fn new(num_inputs: usize) -> Self {
214        Self {
215            index: 0,
216            amount: num_inputs,
217        }
218    }
219}
220impl Iterator for MidiInputsIterator {
221    type Item = HardwareSocket;
222    fn next(&mut self) -> Option<Self::Item> {
223        if self.index >= self.amount {
224            return None;
225        }
226        self.index += 1;
227        Reaper::get().get_midi_input(self.index - 1)
228    }
229}
230
231pub struct MidiOutputsIterator {
232    index: usize,
233    amount: usize,
234}
235impl MidiOutputsIterator {
236    pub fn new(num_outputs: usize) -> Self {
237        Self {
238            index: 0,
239            amount: num_outputs,
240        }
241    }
242}
243impl Iterator for MidiOutputsIterator {
244    type Item = HardwareSocket;
245    fn next(&mut self) -> Option<Self::Item> {
246        if self.index >= self.amount {
247            return None;
248        }
249        self.index += 1;
250        Reaper::get().get_midi_output(self.index - 1)
251    }
252}