1 use std::fmt;
2 use webcore::try_from::{TryInto, TryFrom};
3 use webcore::value::{Value, Reference};
4 use webapi::event_target::{IEventTarget, EventTarget};
5 use webapi::dom_exception::{
6 SecurityError,
7 InvalidStateError,
8 NotSupportedError,
9 AbortError
10 };
11
12 #[cfg(feature = "experimental_features_which_may_break_on_minor_version_bumps")]
13 use webcore::promise::{Promise, TypedPromise};
14
15 /// This structure contains optional settings that may be provided
16 /// when requesting MIDI access.
17 // https://webaudio.github.io/web-midi-api/#dom-midioptions
18 #[derive(Clone, PartialEq, Debug, Default)]
19 pub struct MidiOptions {
20 /// This member informs the system whether the ability to send and receive
21 /// system exclusive messages is requested or allowed. If this member is
22 /// set to true, but system exclusive support is denied (either by policy
23 /// or by user action), the access request will fail with a `SecurityError`
24 /// error. If this support is not requested (and allowed), the system will
25 /// throw exceptions if the user tries to send system exclusive messages,
26 /// and will silently mask out any system exclusive messages received on
27 /// the port.
28 request_sysex: bool,
29
30 /// This member informs the system whether the ability to utilize any software
31 /// synthesizers installed in the host system is requested or allowed. If this
32 /// member is set to true, but software synthesizer support is denied (either
33 /// by policy or by user action), the access request will fail with a `SecurityError`
34 /// error.
35 ///
36 /// Note that may result in a two-step request procedure if software synthesizer
37 /// support is desired but not required - software synthesizers may be disabled
38 /// when MIDI hardware device access is allowed.
39 request_software_synth: bool,
40
41 #[doc(hidden)]
42 __non_exhaustive: ()
43 }
44
45 error_enum_boilerplate! {
46 MidiAccessError,
47 SecurityError, AbortError, InvalidStateError, NotSupportedError
48 }
49
50 /// This object provides the methods to list MIDI input and output devices,
51 /// and obtain access to an individual device.
52 // https://webaudio.github.io/web-midi-api/#dom-midiaccess
53 #[derive(Clone, Debug, Eq, PartialEq, ReferenceType)]
54 #[reference(instance_of = "MIDIAccess")]
55 #[reference(subclass_of(EventTarget))]
56 pub struct MidiAccess( Reference );
57
58 impl MidiAccess {
59 /// Requests access to MIDI devices.
60 // https://webaudio.github.io/web-midi-api/#dom-navigator-requestmidiaccess
61 #[cfg(feature = "experimental_features_which_may_break_on_minor_version_bumps")]
new_with_options( options: &MidiOptions ) -> TypedPromise< MidiAccess, MidiAccessError >62 pub fn new_with_options( options: &MidiOptions ) -> TypedPromise< MidiAccess, MidiAccessError > {
63 let promise: Promise = js!(
64 if( !navigator.requestMIDIAccess ) {
65 return new Promise( function( resolve, reject ) {
66 reject( new DOMException( "WebMIDI is not supported by your browser!", "NotSupportedError" ) );
67 });
68 }
69
70 return navigator.requestMIDIAccess({
71 sysex: @{options.request_sysex},
72 software: @{options.request_software_synth}
73 });
74 ).try_into().unwrap();
75
76 TypedPromise::new( promise )
77 }
78
79 /// Requests access to MIDI devices with default options.
80 // https://webaudio.github.io/web-midi-api/#dom-navigator-requestmidiaccess
81 #[cfg(feature = "experimental_features_which_may_break_on_minor_version_bumps")]
new() -> TypedPromise< MidiAccess, MidiAccessError >82 pub fn new() -> TypedPromise< MidiAccess, MidiAccessError > {
83 Self::new_with_options( &MidiOptions::default() )
84 }
85
86 /// The MIDI input ports available to the system.
87 // https://webaudio.github.io/web-midi-api/#dom-midiaccess-inputs
inputs( &self ) -> MidiInputMap88 pub fn inputs( &self ) -> MidiInputMap {
89 return js!(
90 return @{self}.inputs;
91 ).try_into().unwrap()
92 }
93
94 /// The MIDI output ports available to the system.
95 // https://webaudio.github.io/web-midi-api/#dom-midiaccess-outputs
outputs( &self ) -> MidiOutputMap96 pub fn outputs( &self ) -> MidiOutputMap {
97 return js!(
98 return @{self}.outputs;
99 ).try_into().unwrap()
100 }
101
102 /// This attribute informs the user whether system exclusive support is enabled.
103 // https://webaudio.github.io/web-midi-api/#dom-midiaccess-sysexenabled
sysex_enabled( &self ) -> bool104 pub fn sysex_enabled( &self ) -> bool {
105 return js!(
106 return @{self}.sysexEnabled;
107 ).try_into().unwrap()
108 }
109 }
110
map_iter_next< K, V >( iter: &Value ) -> Option< (K, V) > where K: TryFrom< Value >, V: TryFrom< Value >, K::Error: fmt::Debug, V::Error: fmt::Debug111 fn map_iter_next< K, V >( iter: &Value ) -> Option< (K, V) >
112 where K: TryFrom< Value >,
113 V: TryFrom< Value >,
114 K::Error: fmt::Debug,
115 V::Error: fmt::Debug
116 {
117 let entry = js!( return @{&iter}.next(); );
118 let is_done: bool = js!( return @{&entry}.done; ).try_into().unwrap();
119 if is_done {
120 return None;
121 }
122
123 let key = js!( return @{&entry}.value[0] ).try_into().unwrap();
124 let value = js!( return @{&entry}.value[1] ).try_into().unwrap();
125 Some( (key, value) )
126 }
127
128 /// This type is used to represent all the currently available MIDI input ports.
129 // https://webaudio.github.io/web-midi-api/#dom-midiinputmap
130 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
131 #[reference(instance_of = "MIDIInputMap")]
132 pub struct MidiInputMap( Reference );
133
134 macro_rules! define_map {
135 ($map_name:ident, $item_name:ident, $iter_name:ident) => {
136 impl $map_name {
137 /// Returns the number of elements in this map.
138 pub fn len( &self ) -> u32 {
139 js!( return @{self}.size; ).try_into().unwrap()
140 }
141
142 /// Returns an iterator over the map.
143 pub fn iter( &self ) -> $iter_name {
144 self.into_iter()
145 }
146 }
147
148 #[derive(Debug)]
149 pub struct $iter_name {
150 iter: Value
151 }
152
153 impl Iterator for $iter_name {
154 type Item = (String, $item_name);
155 fn next( &mut self ) -> Option< Self::Item > {
156 map_iter_next( &self.iter )
157 }
158 }
159
160 impl IntoIterator for $map_name {
161 type Item = (String, $item_name);
162 type IntoIter = $iter_name;
163
164 #[inline]
165 fn into_iter( self ) -> Self::IntoIter {
166 $iter_name {
167 iter: js!( return @{self}.entries(); )
168 }
169 }
170 }
171
172 impl< 'a > IntoIterator for &'a $map_name {
173 type Item = (String, $item_name);
174 type IntoIter = $iter_name;
175
176 #[inline]
177 fn into_iter( self ) -> Self::IntoIter {
178 self.clone().into_iter()
179 }
180 }
181 }
182 }
183
184 /// This interface represents a MIDI input or output port.
185 pub trait IMidiPort: IEventTarget {
186 /// A unique ID of the port.
187 ///
188 /// This can be used by developers to remember ports the user
189 /// has chosen for their application.
190 // https://webaudio.github.io/web-midi-api/#dom-midiport-id
id( &self ) -> String191 fn id( &self ) -> String {
192 return js!( return @{self.as_ref()}.id; ).try_into().unwrap();
193 }
194
195 /// The system name of the port.
196 // https://webaudio.github.io/web-midi-api/#dom-midiport-name
name( &self ) -> Option< String >197 fn name( &self ) -> Option< String > {
198 return js!( return @{self.as_ref()}.name; ).try_into().unwrap();
199 }
200 }
201
202 /// This object represents a MIDI input or output port.
203 // https://webaudio.github.io/web-midi-api/#dom-midiport
204 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
205 #[reference(instance_of = "MIDIPort")]
206 #[reference(subclass_of(EventTarget))]
207 pub struct MidiPort( Reference );
208
209 impl IEventTarget for MidiPort {}
210 impl IMidiPort for MidiPort {}
211
212 /// This type is used to represent all the currently available MIDI output ports.
213 // https://webaudio.github.io/web-midi-api/#dom-midioutputmap
214 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
215 #[reference(instance_of = "MIDIOutputMap")]
216 pub struct MidiOutputMap( Reference );
217
218 define_map!( MidiInputMap, MidiInput, MidiInputMapIter );
219 define_map!( MidiOutputMap, MidiOutput, MidiOutputMapIter );
220
221 /// A MIDI input port.
222 // https://webaudio.github.io/web-midi-api/#dom-midiinput
223 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
224 #[reference(instance_of = "MIDIInput")]
225 #[reference(subclass_of(EventTarget, MidiPort))]
226 pub struct MidiInput( Reference );
227
228 impl IEventTarget for MidiInput {}
229 impl IMidiPort for MidiInput {}
230
231 /// A MIDI output port.
232 // https://webaudio.github.io/web-midi-api/#dom-midioutput
233 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
234 #[reference(instance_of = "MIDIOutput")]
235 #[reference(subclass_of(EventTarget, MidiPort))]
236 pub struct MidiOutput( Reference );
237
238 impl IEventTarget for MidiOutput {}
239 impl IMidiPort for MidiOutput {}
240