1 module midi2.types.structs;
2 
3 /**
4  * midi2 - MIDI 2.0 implementation.
5  *
6  * midi2.types.structs:
7  *
8  * Contains Universal MIDI Packets, etc.
9  */
10 
11 public import midi2.types.enums;
12 
13 /**
14  * Defines a basic Universal MIDI Packet.
15  * 
16  * Extra data (64 bit and larger) are stored in separate fields.
17  *
18  * Original format is in little endian, and the current implementation is formed around that. If you
19  * need big endian support for some MCU, then you can implement it. :)
20  */
21 struct UMP {
22 	union {
23 		uint		base;	///Value of the UMP as a single unsigned 32 bit integer
24 		ubyte[4]	bytes;	///Individual bytes of the UMP's field
25 	}
26 	@nogc @safe nothrow pure {
27 		/**
28 		 * Creates a UMP with two 8 bit fields.
29 		 */
30 		this(ubyte msgType, ubyte group, ubyte status, ubyte channel, ubyte val0 = 0, ubyte val1 = 0) {
31 			bytes[0] = cast(ubyte)((msgType<<4) | (group & 0xF));
32 			bytes[1] = cast(ubyte)((status<<4) | (channel & 0xF));
33 			bytes[2] = val0;
34 			bytes[3] = val1;
35 		}
36 		/**
37 		 * Creates a MIDI 1.0 compatible pitch-bend command.
38 		 */
39 		this(ubyte group, ubyte channel, ushort val) {
40 			bytes[0] = (MessageType.MIDI1<<4) | (group & 0xF);
41 			bytes[1] = (MIDI1_0Cmd.PitchBend<<4) | (channel & 0xF);
42 			bytes[3] = cast(ubyte)((val>>7)&0x7F);
43 			bytes[2] = cast(ubyte)(val&0x7F);
44 		}
45 		/**
46 		 * Returns the message type of the packet.
47 		 *
48 		 * This value should not be changed on the fly.
49 		 */
50 		ubyte msgType() const {
51 			return bytes[0]>>4;
52 		}
53 		/**
54 		 * Returns the group of the packet. 
55 		 */
56 		ubyte group() const {
57 			return bytes[0] & 0xF;
58 		}
59 		/**
60 		 * Sets the group of the packet.
61 		 */
62 		ubyte group(ubyte val) {
63 			bytes[0] &= 0xF0;
64 			bytes[0] |= val & 0xF;
65 			return bytes[0] & 0xF;
66 		}
67 		/**
68 		 * Returns the status value of the field, or 0 if message type hasn't defined it.
69 		 */
70 		ubyte status() const {
71 			switch (msgType) {
72 				case MessageType.MIDI2 , MessageType.MIDI1 , MessageType.Data64 , MessageType.Data128:
73 					return bytes[1]>>4;
74 				default:
75 					return bytes[1];
76 			}
77 		}
78 		/**
79 		 * Returns the note number of this packet.
80 		 */
81 		ubyte note() const {
82 			return bytes[2];
83 		}
84 		/**
85 		 * Sets the note number of this packet.
86 		 */
87 		ubyte note(ubyte val) {
88 			return bytes[2] = val;
89 		}
90 		alias index = note;
91 		alias program = note;
92 		/**
93 		 * Returns the value of this packet.
94 		 */
95 		ubyte value() const {
96 			return bytes[3];
97 		}
98 		/**
99 		 * Sets the value of this packet.
100 		 */
101 		ubyte value(ubyte val) {
102 			return bytes[3] = val;
103 		}
104 		alias velocity = value;
105 		/**
106 		 * Returns the pitch bend value of this packet.
107 		 */
108 		ushort bend() const {
109 			return (cast(ushort)bytes[3])<<7 | bytes[2];
110 		}
111 		/**
112 		 * Return the channel number of this packet.
113 		 */
114 		ubyte channel() const {
115 			return bytes[1] & 0xF;
116 		}
117 		/**
118 		 * Sets the channel number of this packet.
119 		 */
120 		ubyte channel(ubyte val) {
121 			bytes[1] &= 0xF0;
122 			bytes[1] |= val & 0xF;
123 			return bytes[1] & 0xF;
124 		}
125 	}
126 }
127 /**
128  * Defines the MIDI 2.0 note commands' data fields.
129  */
130 struct NoteVals {
131 	ushort		velocity;	///Velocity of the note
132 	ushort		attrData;	///Attribute data
133 }
134 
135 
136 unittest {
137 	assert(UMP.sizeof == 4);
138 	assert(NoteVals.sizeof == 4);
139 	
140 	UMP a = UMP(MessageType.MIDI2, 0x5, MIDI2_0Cmd.NoteOn, 0x3, 0x84, 0x35);
141 	assert(a.msgType == MessageType.MIDI2);
142 	assert(a.group == 0x5);
143 	assert(a.status == MIDI2_0Cmd.NoteOn);
144 	assert(a.channel == 0x3);
145 	assert(a.note == 0x84);
146 	assert(a.value == 0x35);
147 }