|
| 1 | +// updated version of https://github.com/magicmonty/fable-import-webmidi |
| 2 | +module Fable.WebMIDI |
| 3 | + |
| 4 | +open Fable.Core |
| 5 | +open Fable.Core.JS |
| 6 | +open Browser |
| 7 | +type MIDIOptions = |
| 8 | + | Sysex of bool |
| 9 | + |
| 10 | +[<StringEnum>] |
| 11 | +type MIDIPortType = |
| 12 | + | Input |
| 13 | + | Output |
| 14 | + |
| 15 | +[<StringEnum>] |
| 16 | +type MIDIPortDeviceState = |
| 17 | + | Disconnected |
| 18 | + | Connected |
| 19 | + |
| 20 | +[<StringEnum>] |
| 21 | +type MIDIPortConnectionState = |
| 22 | + | Open |
| 23 | + | Closed |
| 24 | + | Pending |
| 25 | + |
| 26 | +type IMIDIPort = |
| 27 | + [<Emit("$0.id")>] |
| 28 | + abstract Id: string with get |
| 29 | + [<Emit("$0.manufacturer")>] |
| 30 | + abstract Manufacturer: string option with get |
| 31 | + [<Emit("$0.name")>] |
| 32 | + abstract Name: string option with get |
| 33 | + [<Emit("$0.type")>] |
| 34 | + abstract Type: MIDIPortType with get |
| 35 | + [<Emit("$0.version")>] |
| 36 | + abstract Version: string option with get |
| 37 | + [<Emit("$0.state")>] |
| 38 | + abstract State: MIDIPortDeviceState with get |
| 39 | + [<Emit("$0.connection")>] |
| 40 | + abstract Connection: MIDIPortConnectionState with get |
| 41 | + [<Emit("$0.onstatechange=$1")>] |
| 42 | + abstract OnStateChange: (IMIDIConnectionEvent -> unit) with set |
| 43 | + [<Emit("$0.open")>] |
| 44 | + abstract Open: (unit -> Promise<IMIDIPort>) |
| 45 | + [<Emit("$0.close")>] |
| 46 | + abstract Close: (unit -> Promise<IMIDIPort>) |
| 47 | + |
| 48 | +and IMIDIConnectionEvent = |
| 49 | + inherit Browser.Types.EventType |
| 50 | + [<Emit("$0.port")>] |
| 51 | + abstract Port: IMIDIPort with get |
| 52 | + |
| 53 | +type IMIDIMessageEvent = |
| 54 | + inherit Browser.Types.EventType |
| 55 | + [<Emit("$0.receivedTime")>] |
| 56 | + abstract member ReceivedTime: double with get |
| 57 | + [<Emit("$0.data")>] |
| 58 | + abstract member Data: byte array with get |
| 59 | + |
| 60 | +type IMIDIInput = |
| 61 | + inherit IMIDIPort |
| 62 | + [<Emit("$0.onmidimessage=$1")>] |
| 63 | + abstract OnMidiMessage: (IMIDIMessageEvent -> unit) with set |
| 64 | + |
| 65 | +type IMIDIInputMap = JS.Map<string, IMIDIInput> |
| 66 | + |
| 67 | +type IMIDIOutput = |
| 68 | + inherit IMIDIPort |
| 69 | + [<Emit("$0.send")>] |
| 70 | + abstract Send: (byte array -> unit) |
| 71 | + [<Emit("$0.send($2, $1)")>] |
| 72 | + abstract SendAt: (float -> byte array -> unit) |
| 73 | + [<Emit("$0.clear")>] |
| 74 | + abstract Clear: (unit -> unit) |
| 75 | + |
| 76 | +type IMIDIOutputMap = JS.Map<string, IMIDIOutput> |
| 77 | + |
| 78 | +type IMIDIAccess = |
| 79 | + [<Emit("$0.inputs")>] |
| 80 | + abstract Inputs: IMIDIInputMap with get |
| 81 | + [<Emit("$0.outputs")>] |
| 82 | + abstract Outputs: IMIDIOutputMap with get |
| 83 | + [<Emit("$0.onstatechange=$1")>] |
| 84 | + abstract OnStateChange: (IMIDIConnectionEvent -> unit) with set |
| 85 | + [<Emit("$0.sysexEnabled")>] |
| 86 | + abstract SysexEnabled: bool with get, set |
| 87 | + |
| 88 | +module internal Intern = |
| 89 | + |
| 90 | + [<Emit("navigator.requestMIDIAccess($0)")>] |
| 91 | + let requestAccess (options: obj) : Promise<IMIDIAccess> = jsNative |
| 92 | + |
| 93 | +module Map = |
| 94 | + let toList (m: JS.Map<'a,'b>): ('a*'b) list = |
| 95 | + let mutable result : ('a*'b) list = [] |
| 96 | + m.forEach (fun b a _ -> result <- (a, b) :: result) |
| 97 | + result |> List.ofSeq |
| 98 | + |
| 99 | +module ArrayBuffer = |
| 100 | + let toArray (m: ArrayBuffer) : byte array = |
| 101 | + let c = JS.Constructors.Uint8ClampedArray.Create(m) |
| 102 | + let mutable result : byte list = [] |
| 103 | + c.forEach (fun a _ _ -> result <- (byte a) :: result; true) |
| 104 | + result |> List.rev |> List.toArray |
| 105 | + |
| 106 | +[<RequireQualifiedAccess>] |
| 107 | +module MIDI = |
| 108 | + let requestAccess (options: MIDIOptions list) = |
| 109 | + Intern.requestAccess (JsInterop.keyValueList CaseRules.LowerFirst options) |
| 110 | + |
| 111 | + let send (output: IMIDIOutput) (data : byte array) = |
| 112 | + promise { |
| 113 | + output.Send data |
| 114 | + } |
| 115 | + let sendAt (output: IMIDIOutput) (sendTime: float) (data : byte array) = |
| 116 | + promise { |
| 117 | + data |> output.SendAt sendTime |
| 118 | + } |
| 119 | + |
0 commit comments