Skip to main content

reaper_medium/
recording_input.rs

1use crate::{MidiInputDeviceId, TryFromRawError};
2
3use helgoboss_midi::Channel;
4use std::convert::TryInto;
5
6/// Recording input of a track.
7#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
8pub enum RecordingInput {
9    /// Index refers to a single mono channel.
10    Mono(u32),
11    /// Index refers to a single ReaRoute mono channel.
12    MonoReaRoute(u32),
13    /// Index refers to the first of two channels in a stereo channel pair.
14    Stereo(u32),
15    /// Index refers to the first of two channels in a ReaRoute stereo channel pair.
16    StereoReaRoute(u32),
17    Midi {
18        device_id: Option<MidiInputDeviceId>,
19        channel: Option<Channel>,
20    },
21}
22
23impl RecordingInput {
24    /// Converts an integer as returned by the low-level API to a recording input.
25    ///
26    /// # Errors
27    ///
28    /// Fails if the given integer is not a valid recording input index.
29    pub fn try_from_raw(rec_input_index: i32) -> Result<RecordingInput, TryFromRawError<i32>> {
30        use RecordingInput::*;
31        let v: u32 = rec_input_index.try_into().map_err(|_| {
32            TryFromRawError::new("couldn't convert to recording input", rec_input_index)
33        })?;
34        match v {
35            0..=511 => Ok(Mono(v)),
36            512..=1023 => Ok(MonoReaRoute(v - 512)),
37            1024..=1535 => Ok(Stereo(v - 1024)),
38            1536..=2047 => Ok(StereoReaRoute(v - 1536)),
39            2048..=4095 => Err(TryFromRawError::new(
40                "couldn't convert to recording input",
41                rec_input_index,
42            )),
43            4096..=6128 => {
44                let midi_index = v - 4096;
45                Ok(Midi {
46                    device_id: {
47                        let raw_device_id = midi_index / 32;
48                        if raw_device_id == ALL_MIDI_DEVICES_FACTOR {
49                            None
50                        } else {
51                            Some(MidiInputDeviceId::new(raw_device_id as u8))
52                        }
53                    },
54                    channel: {
55                        let channel_id = midi_index % 32;
56                        if channel_id == 0 {
57                            None
58                        } else {
59                            let ch = channel_id - 1;
60                            ch.try_into().ok()
61                        }
62                    },
63                })
64            }
65            _ => Err(TryFromRawError::new(
66                "couldn't convert to recording input",
67                rec_input_index,
68            )),
69        }
70    }
71
72    /// Converts this value to an integer as expected by the low-level API.
73    pub fn to_raw(&self) -> i32 {
74        use RecordingInput::*;
75        let result = match *self {
76            Mono(i) => i,
77            MonoReaRoute(i) => 512 + i,
78            Stereo(i) => 1024 + i,
79            StereoReaRoute(i) => 1536 + i,
80            Midi { device_id, channel } => {
81                let device_high = match device_id {
82                    None => ALL_MIDI_DEVICES_FACTOR,
83                    Some(id) => id.get() as u32,
84                };
85                let channel_low = match channel {
86                    None => 0,
87                    Some(ch) => u32::from(ch) + 1,
88                };
89                4096 + (device_high * 32 + channel_low)
90            }
91        };
92        result as i32
93    }
94}
95
96const ALL_MIDI_DEVICES_FACTOR: u32 = 63;