/examples/step/step-by-section.py

http://echo-nest-remix.googlecode.com/ · Python · 101 lines · 75 code · 4 blank · 22 comment · 0 complexity · 24a070e2bfb1ac550ff21e6f931ed25b MD5 · raw file

  1. #!/usr/bin/env python
  2. # encoding: utf=8
  3. """
  4. step-by-section.py
  5. For each bar, take one of the nearest (in timbre) beats
  6. to the last beat, chosen from all of the beats that fall
  7. on the one in this section. Repeat for all the twos, etc.
  8. This version divides things by section, retaining the
  9. structure and approximate length of the original. The
  10. variation parameter, (_v_) means there's a roughly
  11. one in _v_ chance that the actual next beat is chosen. A
  12. musical M-x dissociated-press.
  13. Originally by Adam Lindsay, 2009-03-10.
  14. """
  15. import random
  16. import echonest.audio as audio
  17. from echonest.sorting import *
  18. from echonest.selection import *
  19. usage = """
  20. Usage:
  21. python step-by-section.py inputFilename outputFilename [variation]
  22. variation is the number of near candidates chosen from. [default=4]
  23. Example:
  24. python step-by-section.py Discipline.mp3 Displicine.mp3 6
  25. """
  26. def main(infile, outfile, choices=4):
  27. audiofile = audio.LocalAudioFile(infile)
  28. meter = audiofile.analysis.time_signature['value']
  29. fade_in = audiofile.analysis.end_of_fade_in
  30. fade_out = audiofile.analysis.start_of_fade_out
  31. sections = audiofile.analysis.sections.that(overlap_range(fade_in, fade_out))
  32. outchunks = audio.AudioQuantumList()
  33. for section in sections:
  34. print str(section) + ":"
  35. beats = audiofile.analysis.beats.that(are_contained_by(section))
  36. segments = audiofile.analysis.segments.that(overlap(section))
  37. num_bars = len(section.children())
  38. print "\t", len(beats), "beats,", len(segments), "segments"
  39. if len(beats) < meter:
  40. continue
  41. b = []
  42. segstarts = []
  43. for m in range(meter):
  44. b.append(beats.that(are_beat_number(m)))
  45. segstarts.append(segments.that(overlap_starts_of(b[m])))
  46. if not b:
  47. continue
  48. elif not b[0]:
  49. continue
  50. now = b[0][0]
  51. for x in range(0, num_bars * meter):
  52. beat = x % meter
  53. next_beat = (x + 1) % meter
  54. now_end_segment = segments.that(contain_point(now.end))[0]
  55. next_candidates = segstarts[next_beat].ordered_by(timbre_distance_from(now_end_segment))
  56. if not next_candidates:
  57. continue
  58. next_choice = next_candidates[random.randrange(min(choices, len(next_candidates)))]
  59. next = b[next_beat].that(start_during(next_choice))[0]
  60. outchunks.append(now)
  61. print "\t" + now.context_string()
  62. now = next
  63. out = audio.getpieces(audiofile, outchunks)
  64. out.encode(outfile)
  65. def are_beat_number(beat):
  66. def fun(x):
  67. if x.local_context()[0] == beat:
  68. return x
  69. return fun
  70. #
  71. if __name__ == '__main__':
  72. import sys
  73. try:
  74. inputFilename = sys.argv[1]
  75. outputFilename = sys.argv[2]
  76. if len(sys.argv) > 3:
  77. variation = int(sys.argv[3])
  78. else:
  79. variation = 4
  80. except:
  81. print usage
  82. sys.exit(-1)
  83. main(inputFilename, outputFilename, variation)