retrait TODO.
[minwii.git] / src / mxmMidi / DataTypeConverters.py
1 # -*- coding: ISO-8859-1 -*-
2
3 from struct import pack, unpack
4
5 """
6 This module contains functions for reading and writing the special data types
7 that a midi file contains.
8 """
9
10 """
11 nibbles are four bits. A byte consists of two nibles.
12 hiBits==0xF0, loBits==0x0F Especially used for setting
13 channel and event in 1. byte of musical midi events
14 """
15
16
17
18 def getNibbles(byte):
19 """
20 Returns hi and lo bits in a byte as a tuple
21 >>> getNibbles(142)
22 (8, 14)
23
24 Asserts byte value in byte range
25 >>> getNibbles(256)
26 Traceback (most recent call last):
27 ...
28 ValueError: Byte value out of range 0-255: 256
29 """
30 if not 0 <= byte <= 255:
31 raise ValueError('Byte value out of range 0-255: %s' % byte)
32 return (byte >> 4 & 0xF, byte & 0xF)
33
34
35 def setNibbles(hiNibble, loNibble):
36 """
37 Returns byte with value set according to hi and lo bits
38 Asserts hiNibble and loNibble in range(16)
39 >>> setNibbles(8, 14)
40 142
41
42 >>> setNibbles(8, 16)
43 Traceback (most recent call last):
44 ...
45 ValueError: Nible value out of range 0-15: (8, 16)
46 """
47 if not (0 <= hiNibble <= 15) or not (0 <= loNibble <= 15):
48 raise ValueError('Nible value out of range 0-15: (%s, %s)' % (hiNibble, loNibble))
49 return (hiNibble << 4) + loNibble
50
51
52
53 def readBew(value):
54 """
55 Reads string as big endian word, (asserts len(value) in [1,2,4])
56 >>> readBew('aáâã')
57 1642193635L
58 >>> readBew('aá')
59 25057
60 """
61 return unpack('>%s' % {1:'B', 2:'H', 4:'L'}[len(value)], value)[0]
62
63
64 def writeBew(value, length):
65 """
66 Write int as big endian formatted string, (asserts length in [1,2,4])
67 Difficult to print the result in doctest, so I do a simple roundabout test.
68 >>> readBew(writeBew(25057, 2))
69 25057
70 >>> readBew(writeBew(1642193635L, 4))
71 1642193635L
72 """
73 return pack('>%s' % {1:'B', 2:'H', 4:'L'}[length], value)
74
75
76
77 """
78 Variable Length Data (varlen) is a data format sprayed liberally throughout
79 a midi file. It can be anywhere from 1 to 4 bytes long.
80 If the 8'th bit is set in a byte another byte follows. The value is stored
81 in the lowest 7 bits of each byte. So max value is 4x7 bits = 28 bits.
82 """
83
84
85 def readVar(value):
86 """
87 Converts varlength format to integer. Just pass it 0 or more chars that
88 might be a varlen and it will only use the relevant chars.
89 use varLen(readVar(value)) to see how many bytes the integer value takes.
90 asserts len(value) >= 0
91 >>> readVar('\80@')
92 64
93 >>> readVar('áâãa')
94 205042145
95 """
96 sum = 0
97 for byte in unpack('%sB' % len(value), value):
98 sum = (sum << 7) + (byte & 0x7F)
99 if not 0x80 & byte: break # stop after last byte
100 return sum
101
102
103
104 def varLen(value):
105 """
106 Returns the the number of bytes an integer will be when
107 converted to varlength
108 """
109 if value <= 127:
110 return 1
111 elif value <= 16383:
112 return 2
113 elif value <= 2097151:
114 return 3
115 else:
116 return 4
117
118
119 def writeVar(value):
120 "Converts an integer to varlength format"
121 sevens = to_n_bits(value, varLen(value))
122 for i in range(len(sevens)-1):
123 sevens[i] = sevens[i] | 0x80
124 return fromBytes(sevens)
125
126
127 def to_n_bits(value, length=1, nbits=7):
128 "returns the integer value as a sequence of nbits bytes"
129 bytes = [(value >> (i*nbits)) & 0x7F for i in range(length)]
130 bytes.reverse()
131 return bytes
132
133
134 def toBytes(value):
135 "Turns a string into a list of byte values"
136 return unpack('%sB' % len(value), value)
137
138
139 def fromBytes(value):
140 "Turns a list of bytes into a string"
141 if not value:
142 return ''
143 return pack('%sB' % len(value), *value)
144
145
146
147 if __name__ == '__main__':
148
149 # print to7bits(0, 3)
150 # print to7bits(127, 3)
151 # print to7bits(255, 3)
152 # print to7bits(65536, 3)
153
154 # simple test cases
155
156 # print 'getHiLoHex', getNibbles(16)
157 # print 'setHiLoHex', setNibbles(1,0)
158 #
159 # print 'readBew', readBew('aáâã')
160 # print 'writeBew', writeBew(1642193635, 4)
161 #
162 # print 'varLen', varLen(1)
163 #
164 print 'readVar', readVar('\80@')
165 print 'writeVar', writeVar(8192)
166
167 print 'readVar', readVar('áâãa')
168 print 'writeVar', writeVar(205058401)
169 #
170 # vartest = '\x82\xF7\x80\x00'
171 # print 'toBytes', toBytes(vartest)
172 # print 'fromBytes', fromBytes([48, 49, 50,])
173
174
175 # instr = '\xFF\xFF\xFF\x00'
176 # print 'readVar', readVar(instr)
177 # inst2 = 268435455
178 # print inst2
179 # print writeVar(inst2)
180 # print writeVar(readVar(instr))
181
182 s1 = 0x00000000
183 print '%08X -' % s1, '00', writeVar(s1)
184 s2 = 0x00000040
185 print '%08X -' % s2, '40', writeVar(s2)
186 s3 = 0x0000007F
187 print '%08X -' % s3, '7F', writeVar(s3)
188 s4 = 0x00000080
189 print '%08X -' % s4, '81 00', writeVar(s4)
190 s5 = 0x00002000
191 print '%08X -' % s5, 'C0 00', writeVar(s5)
192 s6 = 0x00003FFF
193 print '%08X -' % s6, 'FF 7F', writeVar(s6)
194 s7 = 0x00004000
195 print '%08X -' % s7, '81 80 00', writeVar(s7)
196 s8 = 0x00100000
197 print '%08X -' % s8, 'C0 80 00', writeVar(s8)
198 s9 = 0x001FFFFF
199 print '%08X -' % s9, 'FF FF 7F', writeVar(s9)
200 s10 = 0x00200000
201 print '%08X -' % s10, '81 80 80 00', writeVar(s10)
202 s11 = 0x08000000
203 print '%08X -' % s11, 'C0 80 80 00', writeVar(s11)
204 s12 = 0x0FFFFFFF
205 print '%08X -' % s12, 'FF FF FF 7F', writeVar(s12)
206
207
208
209
210
211
212
213
214
215
216
217