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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
use jack_sys;

use std::ffi::CStr;
use std::marker::PhantomData;
use std::slice;
use std::str::FromStr;
use num;

use midi::*;
use types::*;
use callbackhandler::*;

type Jackptr = *mut jack_sys::jack_port_t;

/// Ports are the means by which jack clients communicate with each other.
///
/// The port wrappers in `easyjack` have slightly confusing type definitions due to the behavior of
/// the underlying JACK C API. The interface they expose is also much more "C" like than rust like.
///
/// Each of the Port structs defined implement the `Port` trait, which should be sufficient for use
/// in many situations, however, occasionally, we may want to access pieces of data which are only
/// available on specific types of ports.
///
/// Because the JACK C api handles all ports with a jack_port_t structure, we are limited in our
/// ability to determine the exact properties of a port at compile time. For example, if you ask
/// the JACK API to give you a port, by name, you cannot know all of the various properties of the
/// port without additional inspection. This additional inspection will incur additional costs, so
/// we have chosen to make all additional inspection optional.
///
/// This means that many of the `easyjack` API methods will return an `UnknownPortHandle`, and
/// users of the API methods will have the option to attempt to promote this `UnknownPortHandle` to
/// ports of different types. These attempts at conversion will perform additional inspection of
/// the port's flags (unless the unsafe versions are used)
///
/// One additional note about Port types.
/// All of these port types are only handles to underlying ports (think of them as an index into a
/// vector).
/// All of these port types implement `Copy`.
/// This means that a Port "handle" may become invalid if the port becomes invalid.
/// Using a port after it has become invalid is undefined behavior and may cause all sorts of
/// strange things to occur.
pub trait Port {
    #[doc(hidden)]
    fn new(c_port: Jackptr) -> Self;

    #[doc(hidden)]
    unsafe fn get_raw(&self) -> Jackptr;

    /// Gets the port's assigned full name (including the client name and the colon)
    fn get_name(&self) -> String {
        unsafe {
            let raw = self.get_raw();
            let cstr = jack_sys::jack_port_name(raw);

            // do a little dance to alleviate ownership pains
            String::from_str(CStr::from_ptr(cstr).to_str().unwrap()).unwrap()
        }
    }

    // TODO many other functions

    /// Get the flags used to construct this port
    fn get_port_flags(&self) -> port_flags::PortFlags {
        let rawbits = unsafe { jack_sys::jack_port_flags(self.get_raw()) };
        port_flags::PortFlags::from_bits(rawbits as u32).unwrap()
    }
}

#[derive(Debug, Clone, Copy)]
pub struct UnknownPortHandle {
    c_port: Jackptr
}

impl UnknownPortHandle {
    /// Attempts to coerce the port into an input port
    /// This function will test the port's flags to ensure that it is actually an input port
    pub fn as_input<SampleType>(self) -> Option<InputPortHandle<SampleType>> {
        let flags = self.get_port_flags();
        if flags.contains(port_flags::PORT_IS_INPUT) {
            Some(InputPortHandle::<SampleType>::new(self.c_port))
        } else {
            None
        }
    }

    /// Attempts to coerce the port into an output port
    /// This function will test the port's flags to ensure that it is actually an output port
    pub fn as_output<SampleType>(self) -> Option<OutputPortHandle<SampleType>> {
        let flags = self.get_port_flags();
        if flags.contains(port_flags::PORT_IS_OUTPUT) {
            Some(OutputPortHandle::<SampleType>::new(self.c_port))
        } else {
            None
        }
    }

    /// Forces coercion to an input port
    /// This is marked unsafe because it DOES NOT check the port flags before coercing it to the
    /// new type.
    /// If you are 100% sure your port is an input port, this call can save you some extra
    /// operations. If not, use the safe version!
    pub unsafe fn force_as_input<SampleType>(self) -> InputPortHandle<SampleType> {
        InputPortHandle::<SampleType>::new(self.c_port)
    }

    /// Forces coercion to an output port
    /// This is marked unsafe because it DOES NOT check the port flags before coercing it to the
    /// new type.
    /// If you are 100% sure your port is an output port, this call can save you some extra
    /// operations. If not, use the safe version!
    pub unsafe fn force_as_output<SampleType>(self) -> OutputPortHandle<SampleType> {
        OutputPortHandle::<SampleType>::new(self.c_port)
    }
}

impl Port for UnknownPortHandle {
    #[doc(hidden)]
    fn new(c_port: Jackptr) -> Self {
        UnknownPortHandle { c_port: c_port }
    }

    #[doc(hidden)]
    unsafe fn get_raw(&self) -> Jackptr { self.c_port }
}

#[derive(Debug, Clone, Copy)]
pub struct InputPortHandle<SampleType> {
    c_port: Jackptr,
    phantom: PhantomData<SampleType>,
}

impl<SampleType> Port for InputPortHandle<SampleType> {
    #[doc(hidden)]
    fn new(c_port: Jackptr) -> Self {
        InputPortHandle {
            c_port: c_port,
            phantom: PhantomData,
        }
    }

    #[doc(hidden)]
    unsafe fn get_raw(&self) -> Jackptr { self.c_port }
}

impl<SampleType: num::Num> InputPortHandle<SampleType> {
    /// Get the input port's readable buffer
    pub fn get_read_buffer<'a>(&self, nframes: NumFrames, _ctx: &'a CallbackContext)
        -> &'a [SampleType]
    {
        unsafe {
            let ptr = jack_sys::jack_port_get_buffer(self.c_port, nframes);
            let ptr = ptr as *mut SampleType;
            slice::from_raw_parts_mut(ptr, nframes as usize)
        }
    }
}

impl InputPortHandle<MidiEvent> {
    /// returns a vector of midi events
    /// Note that this returns by value (we are not returning by reference, like we have in the
    /// other `get_read_buffer` methods)
    pub fn get_read_buffer<'a>(&self, nframes:NumFrames, _ctx: &'a CallbackContext)
        -> MidiEventBuf<'a>
    {
        // getting a buffer of midi events is much harder than getting a buffer of audio events,
        // but it's okay, we can make it work!
        unsafe {
            // first, get the raw event port from jack
            let ptr = jack_sys::jack_port_get_buffer(self.c_port, nframes);
            MidiEventBuf::new(ptr)
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OutputPortHandle<SampleType> {
    c_port: Jackptr,
    phantom: PhantomData<SampleType>
}

impl<SampleType> Port for OutputPortHandle<SampleType> {
    #[doc(hidden)]
    fn new(c_port: Jackptr) -> Self {
        OutputPortHandle {
            c_port: c_port,
            phantom: PhantomData,
        }
    }

    #[doc(hidden)]
    unsafe fn get_raw(&self) -> Jackptr { self.c_port }
}

impl<SampleType> OutputPortHandle<SampleType> {
    /// Get the input port's readable buffer
    pub fn get_write_buffer<'a>(&self, nframes: NumFrames, _ctx: &'a CallbackContext)
        -> &'a mut [SampleType]
    {
        unsafe {
            let ptr = jack_sys::jack_port_get_buffer(self.c_port, nframes);
            let ptr = ptr as *mut SampleType;
            slice::from_raw_parts_mut(ptr, nframes as usize)
        }
    }
}

// TODO some nice type aliases to hide all this magic and craziness