def render(self, input_midi_filename, frame_save_dir, tracks, speed_map=[{'time':0.0,'speed':4}], dimensions=(720,480), fps=29.97, min_pitch=34, max_pitch=86, first_frame=None, last_frame=None, every_nth_frame=1, do_render=1): """Render the animation!""" print "Beginning render..." speed = speed_map[0]['speed'] if first_frame == None: first_frame = 0 if last_frame == None: last_frame = 10000000 # just a large number print "Lexing midi..." blocks = [] lexer = MidiLexer() midi_events = lexer.lex(input_midi_filename) print "Blockifying midi..." blocks = self.blockify(midi_events) # convert into list of blocks for track in tracks: if 'color' in track: base_color = colorsys.rgb_to_hls(*track['color']) track['high_color'] = colorsys.hls_to_rgb(base_color[0], 0.95, base_color[2]) track['lyrics_color'] = colorsys.hls_to_rgb(base_color[0], 0.7, base_color[2]) if 'lyrics' in track: track['lyrics'] = self.lyrics_deque(track['lyrics']) # do some useful calculations on all blocks blocks, last_block_end = self.add_block_info(blocks, tracks, fps, speed_map, dimensions, min_pitch, max_pitch) # following used for calculating percentage done to print to console original_end = last_block_end percent = 0 last_percent = -1 # sort by z-index descending blocks.sort(lambda a, b: cmp(b['z-index'], a['z-index'])) # for naming image files: frame = 0 # for keeping track of speed changes: # need to initialize time time = -dimensions[0]/(2.0*fps*speed_map[0]['speed']) if not do_render: print "Skipping render pass, Done!" return print "Rendering frames..." # generate frames while there are blocks on the screen: while last_block_end > (0 - speed): # code only for rendering blocks if frame >= first_frame and frame <= last_frame and frame % every_nth_frame == 0: # cairo setup stuff filename = frame_save_dir + ("frame%05i.png" % frame) surface = cairo.ImageSurface(cairo.FORMAT_RGB24, *dimensions) #surface = cairo.SVGSurface(filename, *dimensions) cr = cairo.Context(surface) cr.set_antialias(cairo.ANTIALIAS_GRAY) cr.select_font_face("Garamond", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) cr.set_font_size(19) # add black background cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, *dimensions) cr.fill() # need to do two passes of drawing blocks, once in reverse order # in full opacity, and a second time in ascending order in half- # opacityto get fully-colored bars that blend together when # overlapping # get list of blocks that are on screen on_screen_blocks = [block for block in blocks if block['start_x'] < dimensions[0] and block['end_x'] > 0] on_screen_layers = list(set([block['layer'] for block in on_screen_blocks])) for layer in on_screen_layers: layer_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *dimensions) layer_context = cairo.Context(layer_surface) in_layer_blocks = [block for block in on_screen_blocks if block['layer'] == layer] # do first drawing pass for block in in_layer_blocks: self.draw_block_cairo(block, tracks, dimensions, layer_context) # do second drawing pass on_screen_blocks.reverse() for block in in_layer_blocks: self.draw_block_cairo(block, tracks, dimensions, layer_context, transparent=True) cr.set_source_surface(layer_surface) cr.paint() # do lyrics pass, sort by start x so starts of words are on top on_screen_blocks.sort(lambda a, b: cmp(a['start_x'], b['start_x'])) for block in on_screen_blocks: if ('lyrics' in block): self.draw_lyrics_cairo(block, tracks, dimensions, cr) #cr.save() surface.write_to_png(filename) # other code needed to advance animation frame += 1 # need to set speed speed = self.get_speed(speed_map, time) for block in blocks: # move blocks to left block['start_x'] -= speed block['end_x'] -= speed if 'lyrics_end_x' in block: block['lyrics_end_x'] -= speed last_block_end -= speed # move video endpoint left as well percent = int(min((original_end - last_block_end) * 100.0 / original_end, 100)) if percent != last_percent: print percent, "% done" last_percent = percent time += (1/fps) print "Done!"
def render(self, input_midi_filename, frame_save_dir, tracks, speed_map=speed_map, dimensions=(width, height), fps=fps, min_pitch=min_pitch, max_pitch=max_pitch, first_frame=first_frame, last_frame=last_frame, every_nth_frame=every_nth_frame, do_render=do_render, dynamicmode=False): self.dynamicmode = dynamicmode """Render the animation!""" print "Beginning render..." speed = speed_map[0]['speed'] if first_frame == None: first_frame = 0 if last_frame == None: last_frame = 10000000 # just a large number print "Lexing midi..." blocks = [] lexer = MidiLexer() midi_events = lexer.lex(input_midi_filename) print "Blockifying midi..." blocks = self.blockify(midi_events) # convert into list of blocks print str(len(blocks)) + " blocks" for track in tracks: if 'color' in track: base_color = colorsys.rgb_to_hls(*track['color']) track['high_color'] = colorsys.hls_to_rgb( base_color[0], 0.95, base_color[2]) track['lyrics_color'] = colorsys.hls_to_rgb( base_color[0], 0.7, base_color[2]) if 'lyrics' in track: track['lyrics'] = self.lyrics_deque(track['lyrics']) # do some useful calculations on all blocks blocks, last_block_end = self.add_block_info(blocks, tracks, fps, speed_map, dimensions, min_pitch, max_pitch) # following used for calculating percentage done to print to console original_end = last_block_end percent = 0 last_percent = -1 # sort by z-index descending blocks.sort(lambda a, b: cmp(b['z-index'], a['z-index'])) # for naming image files: frame = 0 framefile = 0 # for keeping track of speed changes: # need to initialize time time = -dimensions[0] / (2.0 * fps * speed_map[0]['speed']) if not do_render: print "Skipping render pass, Done!" return print "Rendering frames..." # generate frames while there are blocks on the screen: while last_block_end > -speed: # code only for rendering blocks if first_frame < frame and frame <= last_frame and frame % every_nth_frame == 0: # cairo setup stuff filename = frame_save_dir + ("frame%05i.png" % framefile) surface = cairo.ImageSurface(cairo.FORMAT_RGB24, *dimensions) cr = cairo.Context(surface) cr.set_antialias(cairo.ANTIALIAS_GRAY) cr.select_font_face("Garamond", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) cr.set_font_size(19) # add black background cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, *dimensions) cr.fill() '''need to do two passes of drawing blocks, once in reverse order in full opacity, and a second time in ascending order in half-opacity to get fully-colored bars that blend together when overlapping''' # get list of blocks that are on screen on_screen_blocks = [ block for block in blocks if block['start_x'] < dimensions[0] ] for layer in set( [block['layer'] for block in on_screen_blocks]): layer_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *dimensions) layer_context = cairo.Context(layer_surface) in_layer_blocks = [ block for block in on_screen_blocks if block['layer'] == layer ] # do first drawing pass for block in in_layer_blocks: block = self.makedynamic(block, dimensions) if block == None: continue self.draw_block_cairo(block, tracks, dimensions, layer_context) # do second drawing pass on_screen_blocks.reverse() for block in in_layer_blocks: block = self.makedynamic(block, dimensions) if block == None: continue self.draw_block_cairo(block, tracks, dimensions, layer_context, transparent=True) cr.set_source_surface(layer_surface) cr.paint() # do lyrics pass, sort by start x so starts of words are on top on_screen_blocks.sort( lambda a, b: cmp(a['start_x'], b['start_x'])) for block in on_screen_blocks: if ('lyrics' in block): self.draw_lyrics_cairo(block, tracks, dimensions, cr) if self.introduction or self.first_highlight: framefile += 1 surface.write_to_png(filename) # other code needed to advance animation frame += 1 # need to set speed speed = self.get_speed(speed_map, time) for block in list(blocks): # move blocks to left end = block['end_x'] - speed if end < 0: '''trash blocks no longer needed. benchmark shows this causes a 2% increase in processing time in medium-sized files (~1000 blocks) but up to 15% redution in big files (~10000 blocks)''' blocks.remove(block) continue block['end_x'] = end block['start_x'] -= speed if 'lyrics_end_x' in block: block['lyrics_end_x'] -= speed last_block_end -= speed # move video endpoint left as well percent = min( int((original_end - last_block_end) * 100.0 / original_end), 100) if percent != last_percent: print percent, "% done" last_percent = percent time += (1 / fps) print "Done!"
def render(self, input_midi_filename, frame_save_dir, tracks, speed_map=[{ 'time': 0.0, 'speed': 4 }], dimensions=(720, 480), fps=29.97, min_pitch=34, max_pitch=86, first_frame=None, last_frame=None, every_nth_frame=1, do_render=1): """Render the animation!""" print "Beginning render..." speed = speed_map[0]['speed'] if first_frame == None: first_frame = 0 if last_frame == None: last_frame = 10000000 # just a large number print "Lexing midi..." blocks = [] lexer = MidiLexer() midi_events = lexer.lex(input_midi_filename) print "Blockifying midi..." blocks = self.blockify(midi_events) # convert into list of blocks for track in tracks: if 'color' in track: base_color = colorsys.rgb_to_hls(*track['color']) track['high_color'] = colorsys.hls_to_rgb( base_color[0], 0.95, base_color[2]) track['lyrics_color'] = colorsys.hls_to_rgb( base_color[0], 0.7, base_color[2]) if 'lyrics' in track: track['lyrics'] = self.lyrics_deque(track['lyrics']) # do some useful calculations on all blocks blocks, last_block_end = self.add_block_info(blocks, tracks, fps, speed_map, dimensions, min_pitch, max_pitch) # following used for calculating percentage done to print to console original_end = last_block_end percent = 0 last_percent = -1 # sort by z-index descending blocks.sort(lambda a, b: cmp(b['z-index'], a['z-index'])) # for naming image files: frame = 0 # for keeping track of speed changes: # need to initialize time time = -dimensions[0] / (2.0 * fps * speed_map[0]['speed']) if not do_render: print "Skipping render pass, Done!" return print "Rendering frames..." # generate frames while there are blocks on the screen: while last_block_end > (0 - speed): # code only for rendering blocks if frame >= first_frame and frame <= last_frame and frame % every_nth_frame == 0: # cairo setup stuff filename = frame_save_dir + ("frame%05i.png" % frame) surface = cairo.ImageSurface(cairo.FORMAT_RGB24, *dimensions) #surface = cairo.SVGSurface(filename, *dimensions) cr = cairo.Context(surface) cr.set_antialias(cairo.ANTIALIAS_GRAY) cr.select_font_face("Garamond", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) cr.set_font_size(19) # add black background cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, *dimensions) cr.fill() # need to do two passes of drawing blocks, once in reverse order # in full opacity, and a second time in ascending order in half- # opacityto get fully-colored bars that blend together when # overlapping # get list of blocks that are on screen on_screen_blocks = [ block for block in blocks if block['start_x'] < dimensions[0] and block['end_x'] > 0 ] on_screen_layers = list( set([block['layer'] for block in on_screen_blocks])) for layer in on_screen_layers: layer_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *dimensions) layer_context = cairo.Context(layer_surface) in_layer_blocks = [ block for block in on_screen_blocks if block['layer'] == layer ] # do first drawing pass for block in in_layer_blocks: self.draw_block_cairo(block, tracks, dimensions, layer_context) # do second drawing pass on_screen_blocks.reverse() for block in in_layer_blocks: self.draw_block_cairo(block, tracks, dimensions, layer_context, transparent=True) cr.set_source_surface(layer_surface) cr.paint() # do lyrics pass, sort by start x so starts of words are on top on_screen_blocks.sort( lambda a, b: cmp(a['start_x'], b['start_x'])) for block in on_screen_blocks: if ('lyrics' in block): self.draw_lyrics_cairo(block, tracks, dimensions, cr) #cr.save() surface.write_to_png(filename) # other code needed to advance animation frame += 1 # need to set speed speed = self.get_speed(speed_map, time) for block in blocks: # move blocks to left block['start_x'] -= speed block['end_x'] -= speed if 'lyrics_end_x' in block: block['lyrics_end_x'] -= speed last_block_end -= speed # move video endpoint left as well percent = int( min((original_end - last_block_end) * 100.0 / original_end, 100)) if percent != last_percent: print percent, "% done" last_percent = percent time += (1 / fps) print "Done!"
def main(): tracks = [ { 'name': "track0", 'color': (0.000, 0.996, 0.000), 'width': TRACK_WIDTH, 'z-index': 0 }, { 'name': "track1", 'color': (0.996, 0.000, 0.000), 'width': TRACK_WIDTH, 'z-index': 1 }, { 'name': "track2", 'color': (0.004, 0.996, 0.992), 'width': TRACK_WIDTH, 'z-index': 2 }, { 'name': "track3", 'color': (0.996, 0.855, 0.398), 'width': TRACK_WIDTH, 'z-index': 3 }, { 'name': "track4", 'color': (0.563, 0.980, 0.570), 'width': TRACK_WIDTH, 'z-index': 4 }, { 'name': "track5", 'color': (0.000, 0.461, 0.996), 'width': TRACK_WIDTH, 'z-index': 5 }, { 'name': "track6", 'color': (0.832, 0.996, 0.000), 'width': TRACK_WIDTH, 'z-index': 6 }, { 'name': "track7", 'color': (0.996, 0.574, 0.492), 'width': TRACK_WIDTH, 'z-index': 7 }, { 'name': "track8", 'color': (0.992, 0.535, 0.000), 'width': TRACK_WIDTH, 'z-index': 8 }, { 'name': "track9", 'color': (0.520, 0.660, 0.000), 'width': TRACK_WIDTH, 'z-index': 9 }, { 'name': "track10", 'color': (0.000, 0.680, 0.492), 'width': TRACK_WIDTH, 'z-index': 10 }, { 'name': "track11", 'color': (0.738, 0.773, 0.996), 'width': TRACK_WIDTH, 'z-index': 11 }, { 'name': "track12", 'color': (0.738, 0.824, 0.574), 'width': TRACK_WIDTH, 'z-index': 12 }, { 'name': "track13", 'color': (0.000, 0.723, 0.090), 'width': TRACK_WIDTH, 'z-index': 13 }, { 'name': "track14", 'color': (0.004, 0.813, 0.996), 'width': TRACK_WIDTH, 'z-index': 14 }, { 'name': "track15", 'color': (0.566, 0.813, 0.793), 'width': TRACK_WIDTH, 'z-index': 15 }, { 'name': "track16", 'color': (0.730, 0.531, 0.000), 'width': TRACK_WIDTH, 'z-index': 16 }, { 'name': "track17", 'color': (0.867, 0.996, 0.453), 'width': TRACK_WIDTH, 'z-index': 17 }, { 'name': "track18", 'color': (0.000, 0.996, 0.773), 'width': TRACK_WIDTH, 'z-index': 18 }, { 'name': "track19", 'color': (0.996, 0.895, 0.008), 'width': TRACK_WIDTH, 'z-index': 19 }, { 'name': "track20", 'color': (0.594, 0.996, 0.320), 'width': TRACK_WIDTH, 'z-index': 20 }, { 'name': "track21", 'color': (0.000, 0.996, 0.469), 'width': TRACK_WIDTH, 'z-index': 21 }, { 'name': "track22", 'color': (0.996, 0.430, 0.254), 'width': TRACK_WIDTH, 'z-index': 22 }, { 'name': "track23", 'color': (0.645, 0.996, 0.820), 'width': TRACK_WIDTH, 'z-index': 23 }, { 'name': "track24", 'color': (0.996, 0.691, 0.402), 'width': TRACK_WIDTH, 'z-index': 24 }, { 'name': "track25", 'color': (0.000, 0.605, 0.996), 'width': TRACK_WIDTH, 'z-index': 25 }, ] if len(sys.argv) < 3: print( "Usage: python MusAnimLauncher.py input.mid outputDirectory [--dynamic]" ) sys.exit(1) return mid = sys.argv[1] lexer = MidiLexer() lexer.lex(mid) frames_dir = sys.argv[2] + os.sep os.makedirs(frames_dir) dynamic = len(sys.argv) >= 4 and sys.argv[3] == '--dynamic' speed_map = [{'time': 0.0, 'speed': 4}] #dimensions = 426, 240 dimensions = 720, 480 #dimensions = 1920, 1080 fps = 25 #fps = 29.97 renderer = MusAnimRenderer() renderer.introduction = False renderer.render(mid, frames_dir, tracks, speed_map=speed_map, dimensions=dimensions, min_pitch=lexer.minPitch - PITCH_GRACE, max_pitch=lexer.maxPitch + PITCH_GRACE, fps=fps, dynamicmode=dynamic)
def main(): tracks = [ { 'name': "track0", 'color': (0.000, 0.996, 0.000), 'width': TRACK_WIDTH, 'z-index': 0 }, { 'name': "track1", 'color': (0.996, 0.000, 0.000), 'width': TRACK_WIDTH, 'z-index': 1 }, { 'name': "track2", 'color': (0.004, 0.996, 0.992), 'width': TRACK_WIDTH, 'z-index': 2 }, { 'name': "track3", 'color': (0.996, 0.855, 0.398), 'width': TRACK_WIDTH, 'z-index': 3 }, { 'name': "track4", 'color': (0.563, 0.980, 0.570), 'width': TRACK_WIDTH, 'z-index': 4 }, { 'name': "track5", 'color': (0.000, 0.461, 0.996), 'width': TRACK_WIDTH, 'z-index': 5 }, { 'name': "track6", 'color': (0.832, 0.996, 0.000), 'width': TRACK_WIDTH, 'z-index': 6 }, { 'name': "track7", 'color': (0.996, 0.574, 0.492), 'width': TRACK_WIDTH, 'z-index': 7 }, { 'name': "track8", 'color': (0.992, 0.535, 0.000), 'width': TRACK_WIDTH, 'z-index': 8 }, { 'name': "track9", 'color': (0.520, 0.660, 0.000), 'width': TRACK_WIDTH, 'z-index': 9 }, { 'name': "track10", 'color': (0.000, 0.680, 0.492), 'width': TRACK_WIDTH, 'z-index': 10 }, { 'name': "track11", 'color': (0.738, 0.773, 0.996), 'width': TRACK_WIDTH, 'z-index': 11 }, { 'name': "track12", 'color': (0.738, 0.824, 0.574), 'width': TRACK_WIDTH, 'z-index': 12 }, { 'name': "track13", 'color': (0.000, 0.723, 0.090), 'width': TRACK_WIDTH, 'z-index': 13 }, { 'name': "track14", 'color': (0.004, 0.813, 0.996), 'width': TRACK_WIDTH, 'z-index': 14 }, { 'name': "track15", 'color': (0.566, 0.813, 0.793), 'width': TRACK_WIDTH, 'z-index': 15 }, { 'name': "track16", 'color': (0.730, 0.531, 0.000), 'width': TRACK_WIDTH, 'z-index': 16 }, { 'name': "track17", 'color': (0.867, 0.996, 0.453), 'width': TRACK_WIDTH, 'z-index': 17 }, { 'name': "track18", 'color': (0.000, 0.996, 0.773), 'width': TRACK_WIDTH, 'z-index': 18 }, { 'name': "track19", 'color': (0.996, 0.895, 0.008), 'width': TRACK_WIDTH, 'z-index': 19 }, { 'name': "track20", 'color': (0.594, 0.996, 0.320), 'width': TRACK_WIDTH, 'z-index': 20 }, { 'name': "track21", 'color': (0.000, 0.996, 0.469), 'width': TRACK_WIDTH, 'z-index': 21 }, { 'name': "track22", 'color': (0.996, 0.430, 0.254), 'width': TRACK_WIDTH, 'z-index': 22 }, { 'name': "track23", 'color': (0.645, 0.996, 0.820), 'width': TRACK_WIDTH, 'z-index': 23 }, { 'name': "track24", 'color': (0.996, 0.691, 0.402), 'width': TRACK_WIDTH, 'z-index': 24 }, { 'name': "track25", 'color': (0.000, 0.605, 0.996), 'width': TRACK_WIDTH, 'z-index': 25 }, ] if len(sys.argv)<3: print("Usage: python MusAnimLauncher.py input.mid outputDirectory") sys.exit(1) return mid=sys.argv[1] lexer = MidiLexer() lexer.lex(mid) frames_dir = sys.argv[2]+os.sep os.makedirs(frames_dir) speed_map = [{'time': 0.0, 'speed': 4}] #dimensions = 426, 240 dimensions = 720, 480 #dimensions = 1920, 1080 fps = 25 #fps = 29.97 renderer=MusAnimRenderer() renderer.introduction=False renderer.render(mid, frames_dir, tracks, speed_map=speed_map, dimensions=dimensions, min_pitch=lexer.minPitch-PITCH_GRACE, max_pitch=lexer.maxPitch+PITCH_GRACE, fps=fps)