/examples/capsule/capsule.py

http://echo-nest-remix.googlecode.com/ · Python · 112 lines · 67 code · 20 blank · 25 comment · 16 complexity · e28319cf13ef732ccfc5f204747daaed MD5 · raw file

  1. #!/usr/bin/env python
  2. # encoding: utf=8
  3. """
  4. capsule.py
  5. accepts songs on the commandline, order them, beatmatch them, and output an audio file
  6. Created by Tristan Jehan and Jason Sundram.
  7. """
  8. import os
  9. import sys
  10. from optparse import OptionParser
  11. from echonest.action import render, make_stereo
  12. from echonest.audio import LocalAudioFile
  13. from pyechonest import util
  14. from capsule_support import order_tracks, equalize_tracks, resample_features, timbre_whiten, initialize, make_transition, terminate, FADE_OUT, display_actions, is_valid
  15. from utils import tuples
  16. def do_work(audio_files, options):
  17. inter = float(options.inter)
  18. trans = float(options.transition)
  19. order = bool(options.order)
  20. equal = bool(options.equalize)
  21. verbose = bool(options.verbose)
  22. # Get pyechonest/remix objects
  23. analyze = lambda x : LocalAudioFile(x, verbose=verbose)
  24. tracks = map(analyze, audio_files)
  25. # decide on an initial order for those tracks
  26. if order == True:
  27. if verbose: print "Ordering tracks..."
  28. tracks = order_tracks(tracks)
  29. if equal == True:
  30. equalize_tracks(tracks)
  31. if verbose:
  32. print
  33. for track in tracks:
  34. print "Vol = %.0f%%\t%s" % (track.gain*100.0, track.analysis.pyechonest_track.title)
  35. print
  36. valid = []
  37. # compute resampled and normalized matrices
  38. for track in tracks:
  39. if verbose: print "Resampling features for", track.analysis.pyechonest_track.title
  40. track.resampled = resample_features(track, rate='beats')
  41. track.resampled['matrix'] = timbre_whiten(track.resampled['matrix'])
  42. # remove tracks that are too small
  43. if is_valid(track, inter, trans):
  44. valid.append(track)
  45. # for compatibility, we make mono tracks stereo
  46. track = make_stereo(track)
  47. tracks = valid
  48. if len(tracks) < 1: return []
  49. # Initial transition. Should contain 2 instructions: fadein, and playback.
  50. if verbose: print "Computing transitions..."
  51. start = initialize(tracks[0], inter, trans)
  52. # Middle transitions. Should each contain 2 instructions: crossmatch, playback.
  53. middle = []
  54. [middle.extend(make_transition(t1, t2, inter, trans)) for (t1, t2) in tuples(tracks)]
  55. # Last chunk. Should contain 1 instruction: fadeout.
  56. end = terminate(tracks[-1], FADE_OUT)
  57. return start + middle + end
  58. def get_options(warn=False):
  59. usage = "usage: %s [options] <list of mp3s>" % sys.argv[0]
  60. parser = OptionParser(usage=usage)
  61. parser.add_option("-t", "--transition", default=8, help="transition (in seconds) default=8")
  62. parser.add_option("-i", "--inter", default=8, help="section that's not transitioning (in seconds) default=8")
  63. parser.add_option("-o", "--order", action="store_true", help="automatically order tracks")
  64. parser.add_option("-e", "--equalize", action="store_true", help="automatically adjust volumes")
  65. parser.add_option("-v", "--verbose", action="store_true", help="show results on screen")
  66. parser.add_option("-p", "--pdb", default=True, help="dummy; here for not crashing when using nose")
  67. (options, args) = parser.parse_args()
  68. if warn and len(args) < 2:
  69. parser.print_help()
  70. return (options, args)
  71. def main():
  72. options, args = get_options(warn=True);
  73. actions = do_work(args, options)
  74. verbose = bool(options.verbose)
  75. if verbose:
  76. display_actions(actions)
  77. print "Output Duration = %.3f sec" % sum(act.duration for act in actions)
  78. print "Rendering..."
  79. # Send to renderer
  80. render(actions, 'capsule.mp3', verbose)
  81. return 1
  82. if __name__ == "__main__":
  83. main()
  84. # for profiling, do this:
  85. #import cProfile
  86. #cProfile.run('main()', 'capsule_prof')
  87. # then in ipython:
  88. #import pstats
  89. #p = pstats.Stats('capsule_prof')
  90. #p.sort_stats('cumulative').print_stats(30)