1
1
module Midi.Tuning
2
2
open Midi
3
-
3
+ // based on specs from midi.org
4
+ // additional spec: http://www.somascape.org/midi/tech/spec.html#usx7E0800
4
5
type MessageId =
5
6
| DumpRequestId = 0 uy
6
7
| DumpResponseId = 1 uy
7
8
| SingleNoteTuningChangeId = 2 uy
8
9
9
10
let makeSysex deviceId ( messageId : MessageId ) data =
11
+ let requiresCheckSum =
12
+ if messageId = MessageId.DumpResponseId then true
13
+ else false
14
+
15
+ let bytesForChecksum =
16
+ [|
17
+ [|
18
+ 0x7e uy
19
+ deviceId
20
+ 0x08 uy
21
+ byte messageId
22
+ |]
23
+ data
24
+ |]
25
+ |> Array.concat
26
+
27
+ let checkSum =
28
+ if requiresCheckSum then
29
+ let mutable sum = 0 uy
30
+ for b in bytesForChecksum do
31
+ sum <- sum ^^^ b
32
+ [| sum|]
33
+ else
34
+ [||]
35
+
10
36
[|
11
37
[|
12
38
0xf0 uy
13
- 0x7e uy
14
- deviceId
15
- 0x08 uy
16
- byte messageId
17
39
|]
18
- data
40
+ bytesForChecksum
41
+ checkSum
19
42
[|
20
43
0xf7 uy
21
44
|]
@@ -28,17 +51,22 @@ type NoteTuning =
28
51
cents : decimal
29
52
}
30
53
54
+ type NoteTuningChange =
55
+ | NoFrequency
56
+ //| Hertz of hertz: decimal
57
+ | NoteAndCents of NoteTuning
58
+
31
59
type BulkTuningDumpResponse =
32
60
{
33
61
name : string
34
62
programNumber: byte
35
- tunings : NoteTuning array
63
+ tunings : NoteTuningChange array
36
64
}
37
65
38
66
type TuningMessage =
39
67
| BulkTuningDumpRequest of tuningProgramNumber : byte
40
68
| BulkTuningDump of BulkTuningDumpResponse
41
- | SingleNoteTuningChange of noteIndexAndTunings : ( byte * NoteTuning ) array
69
+ | SingleNoteTuningChange of noteIndexAndTunings : ( byte * NoteTuningChange ) array
42
70
| TuningProgramSelect of program : byte * channel : byte // + do RPNs inc/dec
43
71
with
44
72
member x.IsRealTime =
56
84
| TuningProgramSelect _ -> None
57
85
58
86
member x.SysexData =
87
+ let centIncrement = 0.0061 m
88
+ let centsAsShorts cents = int16 ( cents / centIncrement)
89
+ let centFirstByte centsAsShort = byte (( centsAsShort >>> 7 ) &&& 0b01111111 s)
90
+ let centSecondByte centsAsShort = byte ( centsAsShort &&& 0b01111111 s)
59
91
match x with
60
92
| BulkTuningDumpRequest programNumber -> Some [| programNumber|]
61
- | BulkTuningDump _ -> Some [||]
93
+ | BulkTuningDump { name= name; programNumber= programNumber; tunings= tunings} ->
94
+ Some
95
+ [|
96
+ yield programNumber
97
+ yield ! ( System.Text.Encoding.ASCII.GetBytes ( name.PadLeft 16 ))
98
+ for tuning in tunings do
99
+ match tuning with
100
+ | NoFrequency -> yield ! [| 0x7f uy; 0x7f uy; 0x7f uy |]
101
+ | NoteAndCents( tuning) ->
102
+ let centsAsShort = centsAsShorts tuning.cents
103
+ let centFirstByte = centFirstByte centsAsShort
104
+ let centSecondByte = centSecondByte centsAsShort
105
+ yield ! [| tuning.semiTone; centFirstByte; centSecondByte|]
106
+ |]
62
107
| SingleNoteTuningChange tunings ->
63
108
Some(
64
109
[|
65
110
for ( noteIndex, tuning) in tunings do
66
- let centIncrement = 0.0061 m
67
- let centsAsShort = int16 ( tuning.cents / centIncrement)
68
- let centFirstByte = byte (( centsAsShort >>> 7 ) &&& 0b01111111 s)
69
- let centSecondByte = byte ( centsAsShort &&& 0b01111111 s)
70
- yield ! [| noteIndex; tuning.semiTone; centFirstByte; centSecondByte|]
111
+ match tuning with
112
+ | NoFrequency -> yield ! [| noteIndex; 0x7f uy; 0x7f uy; 0x7f uy |]
113
+ | NoteAndCents( tuning) ->
114
+ let centsAsShort = centsAsShorts tuning.cents
115
+ let centFirstByte = centFirstByte centsAsShort
116
+ let centSecondByte = centSecondByte centsAsShort
117
+ yield ! [| noteIndex; tuning.semiTone; centFirstByte; centSecondByte|]
71
118
|]
72
119
)
73
120
| TuningProgramSelect _ -> None
74
121
75
-
76
-
77
- member x.Send ( deviceId : byte , midiOutput : IMidiOutput < _ >, nowTimestamp ) =
122
+ member x.MakeMTSSysex deviceId =
78
123
let sysex , messageId = x.SysexData, x.MessageId
79
124
match sysex, messageId with
80
- | Some ( data), Some ( messageId) ->
81
- midiOutput.WriteSysex ( nowTimestamp()) ( makeSysex deviceId messageId data)
82
- | _ -> ()
125
+ | Some data, Some messageId ->
126
+ Some ( makeSysex deviceId messageId data)
127
+ | _ -> None
128
+
129
+ member x.Send ( deviceId : byte , midiOutput : IMidiOutput < _ >, nowTimestamp ) =
130
+ match x.MakeMTSSysex deviceId with
131
+ | Some sysex -> midiOutput.WriteSysex ( nowTimestamp()) sysex
132
+ | None -> ()
83
133
84
134
match x with
85
135
| BulkTuningDumpRequest _ | BulkTuningDump _ | SingleNoteTuningChange _ -> ()
89
139
//midiOutput.WriteMessages (nowTimestamp()) messages
90
140
()
91
141
(*
92
- type NoteTuningChange =
93
- | NoFrequency
94
- | Hertz of hertz: decimal
95
- | NoteAndCents of NoteTuning
142
+
96
143
*)
0 commit comments