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
//! Interfaces to VST events.
// TODO: Update and explain both host and plugin events

use std::{mem, slice};

use crate::api;

/// A VST event.
#[derive(Copy, Clone)]
pub enum Event<'a> {
    /// A midi event.
    ///
    /// These are sent to the plugin before `Plugin::processing()` or `Plugin::processing_f64()` is
    /// called.
    Midi(MidiEvent),

    /// A system exclusive event.
    ///
    /// This is just a block of data and it is up to the plugin to interpret this. Generally used
    /// by midi controllers.
    SysEx(SysExEvent<'a>),

    /// A deprecated event.
    ///
    /// Passes the raw midi event structure along with this so that implementors can handle
    /// optionally handle this event.
    Deprecated(api::Event),
}

/// A midi event.
///
/// These are sent to the plugin before `Plugin::processing()` or `Plugin::processing_f64()` is
/// called.
#[derive(Copy, Clone)]
pub struct MidiEvent {
    /// The raw midi data associated with this event.
    pub data: [u8; 3],

    /// Number of samples into the current processing block that this event occurs on.
    ///
    /// E.g. if the block size is 512 and this value is 123, the event will occur on sample
    /// `samples[123]`.
    // TODO: Don't repeat this value in all event types
    pub delta_frames: i32,

    /// This midi event was created live as opposed to being played back in the sequencer.
    ///
    /// This can give the plugin priority over this event if it introduces a lot of latency.
    pub live: bool,

    /// The length of the midi note associated with this event, if available.
    pub note_length: Option<i32>,

    /// Offset in samples into note from note start, if available.
    pub note_offset: Option<i32>,

    /// Detuning between -63 and +64 cents.
    pub detune: i8,

    /// Note off velocity between 0 and 127.
    pub note_off_velocity: u8,
}

/// A system exclusive event.
///
/// This is just a block of data and it is up to the plugin to interpret this. Generally used
/// by midi controllers.
#[derive(Copy, Clone)]
pub struct SysExEvent<'a> {
    /// The SysEx payload.
    pub payload: &'a [u8],

    /// Number of samples into the current processing block that this event occurs on.
    ///
    /// E.g. if the block size is 512 and this value is 123, the event will occur on sample
    /// `samples[123]`.
    pub delta_frames: i32,
}

impl<'a> Event<'a> {
    /// Creates a high-level event from the given low-level API event.
    ///
    /// # Safety
    ///
    /// You must ensure that the given pointer refers to a valid event of the correct event type.
    /// For example, if the event type is [`api::EventType::SysEx`], it should point to a
    /// [`SysExEvent`]. In case of a [`SysExEvent`], `system_data` and `data_size` must be correct.
    pub unsafe fn from_raw_event(event: *const api::Event) -> Event<'a> {
        use api::EventType::*;
        let event = &*event;
        match event.event_type {
            Midi => {
                let event: api::MidiEvent = mem::transmute(*event);

                let length = if event.note_length > 0 {
                    Some(event.note_length)
                } else {
                    None
                };
                let offset = if event.note_offset > 0 {
                    Some(event.note_offset)
                } else {
                    None
                };
                let flags = api::MidiEventFlags::from_bits(event.flags).unwrap();

                Event::Midi(MidiEvent {
                    data: event.midi_data,
                    delta_frames: event.delta_frames,
                    live: flags.intersects(api::MidiEventFlags::REALTIME_EVENT),
                    note_length: length,
                    note_offset: offset,
                    detune: event.detune,
                    note_off_velocity: event.note_off_velocity,
                })
            }

            SysEx => Event::SysEx(SysExEvent {
                payload: {
                    // We can safely cast the event pointer to a `SysExEvent` pointer as
                    // event_type refers to a `SysEx` type.
                    #[allow(clippy::cast_ptr_alignment)]
                    let event: &api::SysExEvent = &*(event as *const api::Event as *const api::SysExEvent);
                    slice::from_raw_parts(event.system_data, event.data_size as usize)
                },

                delta_frames: event.delta_frames,
            }),

            _ => Event::Deprecated(*event),
        }
    }
}