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
//! Level and midi related functions
//!
//! # Functions
//!
//! * [`get_level`](VoicemeeterRemote::get_level)
//! * [`get_midi_message`](VoicemeeterRemote::get_midi_message)
//! * [`get_midi_message_buff`](VoicemeeterRemote::get_midi_message_buff)
use std::ptr;

pub use crate::types::{Device, LevelType};

use super::VoicemeeterRemote;

impl VoicemeeterRemote {
    // TODO: one thread only
    /// Get the level of a channel on a device
    pub fn get_level(
        &self,
        level_type: LevelType,
        device: Device,
        channel: usize,
    ) -> Result<Option<f32>, GetLevelError> {
        let mut f = std::f32::NAN;
        let dev_num =
            if let Some(dev_num) = device.as_level_device_num(&self.program, level_type, channel) {
                dev_num as i32
            } else {
                return Ok(None);
            };
        let res = unsafe { self.raw.VBVMR_GetLevel(level_type as i32, dev_num, &mut f) };
        match res {
            0 => Ok(Some(f)),
            -1 => Err(GetLevelError::CannotGetClient),
            -2 => Err(GetLevelError::NoServer),
            -3 => Err(GetLevelError::NoLevel),
            -4 => Err(GetLevelError::OutOfRange),
            s => Err(GetLevelError::Other(s)),
        }
    }

    // TODO: one thread only
    /// Get a midi message.
    pub fn get_midi_message(&self) -> Result<Vec<u8>, GetMidiMessageError> {
        let mut v = vec![0; 1024];
        let len = self.get_midi_message_buff(&mut v)?;
        v.truncate(len);
        Ok(v)
    }

    // TODO: one thread only
    /// Get a midi message with a set buffer.
    #[inline]
    pub fn get_midi_message_buff(&self, buffer: &mut [u8]) -> Result<usize, GetMidiMessageError> {
        let res = unsafe {
            self.raw
                .VBVMR_GetMidiMessage(ptr::addr_of_mut!(buffer[0]), buffer.len() as _)
        };
        match res {
            res if res >= 0 => Ok(res as usize),
            -1 => Err(GetMidiMessageError::CannotGetClient),
            -2 => Err(GetMidiMessageError::NoServer),
            v @ -5 | v @ -6 => Err(GetMidiMessageError::NoMidiData(v)),
            s => Err(GetMidiMessageError::Other(s)),
        }
    }
}

/// Errors that can happen when querying levels from Voicemeeter.
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum GetLevelError {
    /// Cannot get client.
    #[error("cannot get client (unexpected)")]
    CannotGetClient,
    /// No server found.
    #[error("no server")]
    NoServer,
    /// No level found.
    #[error("no level available")]
    NoLevel,
    /// Level is out of range.
    #[error("out of range")]
    OutOfRange,
    /// An unexpected error code occured.
    #[error("unexpected error occurred: error code {0}")]
    Other(i32),
}

/// Errors that can happen when querying midi messages from Voicemeeter.
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum GetMidiMessageError {
    /// Cannot get client.
    #[error("cannot get client (unexpected)")]
    CannotGetClient,
    /// No server found.
    #[error("no server")]
    NoServer,
    /// No midi data found.
    #[error("no level available")]
    NoMidiData(i32),
    /// An unexpected error code occured.
    #[error("unexpected error occurred: error code {0}")]
    Other(i32),
}