/src/echonest/support/midi/DataTypeConverters.py

http://echo-nest-remix.googlecode.com/ · Python · 217 lines · 165 code · 11 blank · 41 comment · 5 complexity · 4d51c29891211e9fac996a64988221d7 MD5 · raw file

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