Skip to content

Commit 11c2c99

Browse files
* move datatypes to separate file
* add readWord14be
1 parent 0e4b35f commit 11c2c99

File tree

4 files changed

+413
-475
lines changed

4 files changed

+413
-475
lines changed

src/ZMidi/DataTypes.fs

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
namespace ZMidi.DataTypes
2+
3+
type midiportnumber = byte
4+
type word8 = byte
5+
type word16 = uint16
6+
type word32 = uint32
7+
type bits7 = byte
8+
type midichannel = byte
9+
type [<Struct>] DeltaTime(value: int32) =
10+
member x.Value = value
11+
12+
type [<Struct>] word14(value: word16) =
13+
member x.Value = value
14+
15+
16+
/// The file format - in a MIDI file this is a big-endian
17+
/// word16 with 0,1 or 2 being the only valid values.
18+
type MidiFormat =
19+
/// Format 0 file - single multi-channel track.
20+
| MidiFormat0
21+
/// Format 1 file - 1 or more tracks, played simultaneously.
22+
| MidiFormat1
23+
/// Format 2 file - 1 or more independent tracks.
24+
| MidiFormat2
25+
type MidiTimeDivision =
26+
| FPS of frame: word16
27+
| TicksPerBeat of ticks: word16
28+
29+
type MidiHeader = {
30+
format: MidiFormat
31+
trackCount: word16
32+
timeDivision: MidiTimeDivision
33+
}
34+
35+
/// Running Status.
36+
///
37+
/// MIDI allows a compact representation of voice events where
38+
/// consecutive events (same event, same channel) only need to
39+
/// include the first event-channel byte - subsequent events
40+
/// only send payload until the next event or channel change.
41+
///
42+
/// Including @MidiRunningStatus@ in the data representation is
43+
/// important for ZMidi as an aim is to allow round-tripping
44+
/// of exisiting MIDI files. However it makes MIDI generation
45+
/// more complicated (there is more scope to generate bad
46+
/// output) - if you are only generating MIDI it is wise to always
47+
/// set @MidiRunningStatus@ to @OFF@.
48+
[<RequireQualifiedAccess>]
49+
type MidiRunningStatus = ON | OFF
50+
type TagByte = word8
51+
type MidiDataOther = TagByte
52+
type MidiEvent =
53+
| MidiEventOther of MidiDataOther
54+
| VoiceEvent of MidiRunningStatus * MidiVoiceEvent
55+
| SysExEvent of MidiSysExEvent
56+
| SysCommonEvent of MidiSysCommonEvent
57+
| SysRealtimeEvent of MidiSysRealtimeEvent
58+
| MetaEvent of MidiMetaEvent
59+
60+
and MidiVoiceEvent =
61+
/// Note off.
62+
///
63+
/// > 80 to 8F (0 to F is channel number) * note * velocity
64+
///
65+
/// Turn off a sounding note.
66+
| NoteOff of status: bits7 * note: bits7 * velocity: bits7
67+
68+
/// Note on.
69+
///
70+
/// > 90 to 9F (0 to F is channel number) * note * velocity
71+
///
72+
/// Start playing a note.
73+
| NoteOn of status: bits7 * note: bits7 * velocity: bits7
74+
75+
/// Polyphonic key pressure.
76+
///
77+
/// > A0 to AF (0 to F is channel number) * note * pressure_value
78+
///
79+
/// Change of pressure applied to the synthesizer key.
80+
| NoteAfterTouch of status: bits7 * note: bits7 * pressure: bits7
81+
82+
/// Set a controller.
83+
///
84+
/// > B0 to BF (0 to F is channel number) * controller_number * value
85+
///
86+
/// Controller change, e.g. by a footswitch.
87+
| Controller of status: bits7 * controller: bits7 * value: bits7
88+
89+
/// Set the program.
90+
///
91+
/// > C0 to CF (0 to F is channel number) * program_number
92+
///
93+
/// Change the instrument
94+
/// playing on the specified channel. For playback on
95+
/// computers (rather than synthesizers) the program numbers
96+
/// will correspond to the /General MIDI/ instrument numbers.
97+
| ProgramChange of status: bits7 * programNumber: bits7
98+
99+
/// Channel pressure.
100+
///
101+
/// > D0 to DF (0 to F is channel number) * pressure_value
102+
///
103+
| ChannelAfterTouch of status: bits7 * pressure: bits7
104+
105+
/// Pitch bend
106+
///
107+
/// > E0 to EF (0 to F is channel number) * value
108+
///
109+
/// Change the pitch of a sounding note. Often used to
110+
/// approximate microtonal tunings.
111+
///
112+
/// NOTE - as of v0.9.0 the value is interpreted.
113+
/// This is a Word14 value, the range is (0..16383).
114+
| PitchBend of status: bits7 * bend: word14
115+
116+
117+
and MidiTextType =
118+
| GenericText
119+
| CopyrightNotice
120+
| SequenceName
121+
| InstrumentName
122+
| Lyrics
123+
| Marker
124+
| CuePoint
125+
126+
127+
/// Sequential messages with delta time 0 are played simultaneously.
128+
and MidiMessage = {
129+
timestamp: DeltaTime
130+
event: MidiEvent
131+
}
132+
133+
and MidiTrack = MidiMessage array
134+
135+
and MidiFile = {
136+
header : MidiHeader
137+
tracks : MidiTrack array
138+
}
139+
140+
and MidiSysExEvent =
141+
/// Single SysEx event.
142+
///
143+
/// > F0 * length * data
144+
///
145+
/// An uninterpreted sys-ex event.
146+
| SysExSingle of byte array
147+
148+
/// SysEx sent as (non-standard) multiple continuation
149+
/// packets.
150+
///
151+
/// > F0 * length * packet1 ... [SysExContPacket]
152+
///
153+
| SysExCont of byte array * MidiSysExContPacket array
154+
155+
/// Escape sequence of one-or-more SysEx events.
156+
///
157+
/// > F7 * length * data
158+
///
159+
| SysExEscape of byte array
160+
161+
/// Continuation packet for a (non-standard) multi-part SysEx
162+
/// event.
163+
///
164+
/// Apprently this format is use by Casio.
165+
and MidiSysExContPacket = MidiSysExContPacket of DeltaTime * byte array
166+
167+
168+
169+
and MidiMetaEvent =
170+
171+
/// Text / copywright etc.
172+
///
173+
/// > FF * text_type * contents
174+
///
175+
/// Free text field (e.g. copyright statement). The contents
176+
/// can notionally be any length.
177+
///
178+
| TextEvent of MidiTextType * string
179+
180+
/// Sequence Number
181+
///
182+
/// > FF 00 02 * value
183+
///
184+
/// Format 1 files - only track 1 should have a sequence
185+
/// number.
186+
///
187+
/// Format 2 files - a sequence number should identify each
188+
/// track.
189+
///
190+
/// The sequence number event should occur at the start of a
191+
/// track, before any non-zero time events.
192+
///
193+
| SequenceNumber of word16
194+
195+
/// Channel prefix
196+
///
197+
/// > FF 20 01 * channel
198+
///
199+
/// Relay all meta and sys-ex events to the given channel.
200+
///
201+
| ChannelPrefix of midichannel
202+
203+
/// Midi port
204+
///
205+
/// > FF 21 01 * port
206+
///
207+
/// Midi port number - used to workaround 16 channel limit...
208+
///
209+
| MidiPort of midiportnumber
210+
211+
/// End-of-track event.
212+
///
213+
/// > FF 2F 00
214+
///
215+
| EndOfTrack
216+
217+
/// Set tempo
218+
///
219+
/// > FF 51 03 * microseconds_per_quarter_note
220+
///
221+
| SetTempo of word32
222+
223+
/// SMPTE offest
224+
///
225+
/// > FF 54 05 * hour * minute * second * frac * subfrac
226+
///
227+
/// The SMPTE time when a track should start. This event
228+
/// should occur at the start of a track, before any non-zero
229+
/// time events.
230+
///
231+
| SMPTEOffset of word8 * word8 * word8 * word8 * word8
232+
233+
/// Time signature
234+
///
235+
/// > FF 58 04 * numerator * denominator * metro * num_32nd_notes
236+
///
237+
| TimeSignature of word8 * word8 * word8 * word8
238+
239+
/// Key signature
240+
///
241+
/// > FF 59 02 * key_type * scale_type
242+
///
243+
/// @key_type@ is the number of sharps (postive numbers) or
244+
/// flats (negative numbers), e.g. (-1) is 1 flat.
245+
///
246+
/// @scale_type@ indicates major or minor.
247+
///
248+
| KeySignature of int8 * MidiScaleType
249+
250+
/// SSME
251+
///
252+
/// > FF 7F * length * data
253+
///
254+
/// Sequencer specific meta-event - uninterpreted.
255+
///
256+
| SSME of byte array
257+
/// Unrecognized Meta Event
258+
///
259+
/// > FF * type * length * data
260+
///
261+
| MetaOther of otherType: word8 * byte array
262+
263+
264+
/// System common event.
265+
///
266+
/// Common information for all channels in a system.
267+
///
268+
/// These events may not be pertinent to MIDI files generated on a
269+
/// computer (as opposed to MIDI generated by a synthesizer or
270+
/// sequencer).
271+
///
272+
and MidiSysCommonEvent =
273+
/// Time code quarter frame.
274+
///
275+
/// > F1 * payload
276+
///
277+
/// Note the payload is really a byte split into two 4-bit
278+
/// values, however here it is uninterpreted.
279+
///
280+
| QuarterFrame of word8
281+
282+
/// Song position pointer.
283+
///
284+
/// > F2 * lsb * msb
285+
///
286+
| SongPosPointer of word8 * word8
287+
288+
/// Song number.
289+
///
290+
/// > F3 * song_number
291+
///
292+
/// Song number should be in the range 0..127.
293+
///
294+
| SongSelect of word8
295+
296+
/// Undefined system common event.
297+
///
298+
/// > F4
299+
///
300+
| UndefinedF4
301+
302+
/// Undefined system common event.
303+
///
304+
/// > F5
305+
///
306+
| UndefinedF5
307+
308+
/// Tune request.
309+
///
310+
/// > F6
311+
///
312+
/// Tune request message for analogue synthesizers.
313+
///
314+
| TuneRequest
315+
316+
/// End-of-system-exclusive message.
317+
///
318+
/// > F7
319+
///
320+
| EOX
321+
322+
/// System real-time event.
323+
///
324+
/// These events may not be pertinent to MIDI files generated on a
325+
/// computer (as opposed to MIDI generated by a synthesizer or
326+
/// sequencer).
327+
and MidiSysRealtimeEvent =
328+
/// Timing signal.
329+
///
330+
/// > F8
331+
///
332+
| TimingClock
333+
334+
/// Undefined real time event.
335+
///
336+
/// > F9
337+
///
338+
///
339+
| UndefinedF9
340+
341+
342+
/// Start playing a sequence.
343+
///
344+
/// > FA
345+
///
346+
| StartSequence
347+
348+
349+
/// Continue playing a stopped sequence.
350+
///
351+
/// > FB
352+
///
353+
| ContinueSequence
354+
355+
356+
/// Stop playing a sequence.
357+
///
358+
/// > FC
359+
///
360+
| StopSequence
361+
362+
363+
/// Undefined real time event.
364+
///
365+
/// > FD
366+
///
367+
///
368+
| UndefinedFD
369+
370+
/// Active sensing
371+
///
372+
/// > FE
373+
///
374+
/// Synchronization pulse...
375+
///
376+
| ActiveSensing
377+
378+
379+
/// Reset to power-up status.
380+
///
381+
/// > FF
382+
///
383+
| SystemReset
384+
385+
386+
387+
and [<RequireQualifiedAccess>] MidiScaleType = Major | Minor | OtherScale of word8

0 commit comments

Comments
 (0)