/examples/midi/enToMIDI.py

http://echo-nest-remix.googlecode.com/ · Python · 106 lines · 63 code · 18 blank · 25 comment · 14 complexity · d84f7c7faeb17603c67ba78b156d571b MD5 · raw file

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. """
  4. enToMIDI.py
  5. Created by Brian Whitman on 2008-11-25.
  6. Copyright (c) 2008 __MyCompanyName__. All rights reserved.
  7. """
  8. import sys
  9. import os
  10. import echonest.audio as audio
  11. from copy import copy
  12. from echonest.support import midi
  13. from echonest.support.midi.MidiOutFile import MidiOutFile
  14. from math import pow
  15. def main():
  16. # Examples:
  17. # TRLYNOP11DE633DD31 church bells
  18. # TRWMWTX11DE6393849 a7 unt by lithops
  19. # TRMTWYL11DD5A1D829 valley hi by stereolab
  20. #a = audio.ExistingTrack("TRMTWYL11DD5A1D829").analysis
  21. a = audio.LocalAudioFile(sys.argv[1]).analysis
  22. midi = MidiOutFile('output.mid')
  23. midi.header()
  24. midi.start_of_track()
  25. midi.tempo(int(60000000.00 / 60.0)) # 60 BPM, one Q per second, 96 ticks per Q, 96 ticks per second.)
  26. BOOST = 30 # Boost volumes if you want
  27. # Do you want the channels to be split by timbre or no?
  28. splitChannels = True
  29. for seg_index in xrange(len(a.segments)):
  30. s = a.segments[seg_index]
  31. if(splitChannels):
  32. # Figure out a channel to assign this segment to. Let PCA do the work here... we'll just take the sign of coeffs 1->5 as a 4-bit #
  33. bits = [0,0,0,0]
  34. for i in xrange(4):
  35. # Can't use the first coeff because it's (always?) positive.
  36. if(s.timbre[i+1]>=0): bits[i] =1
  37. channel = bits[0]*8 + bits[1]*4 + bits[2]*2 + bits[3]*1
  38. else:
  39. channel = 0
  40. # Get the loudnesses in MIDI cc #7 vals for the start of the segment, the loudest part, and the start of the next segment.
  41. # db -> voltage ratio http://www.mogami.com/e/cad/db.html
  42. linearMaxVolume = int(pow(10.0,s.loudness_max/20.0)*127.0)+BOOST
  43. linearStartVolume = int(pow(10.0,s.loudness_begin/20.0)*127.0)+BOOST
  44. if(seg_index == len(a.segments)-1): # if this is the last segment
  45. linearNextStartVolume = 0
  46. else:
  47. linearNextStartVolume = int(pow(10.0,a.segments[seg_index+1].loudness_begin/20.0)*127.0)+BOOST
  48. whenMaxVolume = s.time_loudness_max
  49. # Count the # of ticks I wait in doing the volume ramp so I can fix up rounding errors later.
  50. tt = 0
  51. # take pitch vector and hit a note on for each pitch at its relative volume. That's 12 notes per segment.
  52. for note in xrange(12):
  53. volume = int(s.pitches[note]*127.0)
  54. midi.update_time(0)
  55. midi.note_on(channel=channel, note=0x3C+note, velocity=volume)
  56. midi.update_time(0)
  57. # Set volume of this segment. Start at the start volume, ramp up to the max volume , then ramp back down to the next start volume.
  58. curVol = float(linearStartVolume)
  59. # Do the ramp up to max from start
  60. ticksToMaxLoudnessFromHere = int(96.0 * whenMaxVolume)
  61. if(ticksToMaxLoudnessFromHere > 0):
  62. howMuchVolumeToIncreasePerTick = float(linearMaxVolume - linearStartVolume)/float(ticksToMaxLoudnessFromHere)
  63. for ticks in xrange(ticksToMaxLoudnessFromHere):
  64. midi.continuous_controller(channel,7,int(curVol))
  65. curVol = curVol + howMuchVolumeToIncreasePerTick
  66. tt = tt + 1
  67. midi.update_time(1)
  68. # Now ramp down from max to start of next seg
  69. ticksToNextSegmentFromHere = int(96.0 * (s.duration-whenMaxVolume))
  70. if(ticksToNextSegmentFromHere > 0):
  71. howMuchVolumeToDecreasePerTick = float(linearMaxVolume - linearNextStartVolume)/float(ticksToNextSegmentFromHere)
  72. for ticks in xrange(ticksToNextSegmentFromHere):
  73. curVol = curVol - howMuchVolumeToDecreasePerTick
  74. midi.continuous_controller(channel,7,int(curVol))
  75. tt = tt + 1
  76. midi.update_time(1)
  77. # Account for rounding error if any
  78. midi.update_time(int(96.0*s.duration)-tt)
  79. # Send the note off
  80. for note in xrange(12):
  81. midi.note_off(channel=channel, note=0x3C+note)
  82. midi.update_time(0)
  83. midi.update_time(0)
  84. midi.end_of_track()
  85. midi.eof()
  86. if __name__ == '__main__':
  87. main()