#!/usr/bin/env python3 # # vidi-player - generate GStreamer Editing Services timelines from midi # # Copyright (C) 2016 Antonio Ospite # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys import mido import vidi def is_note(msg): return msg.type == 'note_on' or msg.type == 'note_off' def is_note_on(msg): return msg.type == 'note_on' and msg.velocity > 0 def is_note_off(msg): return ((msg.type == 'note_on' and msg.velocity == 0) or (msg.type == 'note_off')) def check_overlapping_notes(midi_file): previous_note_on = False for msg in midi_file: if is_note_on(msg) and msg.channel == 0: if previous_note_on: return True previous_note_on = True elif is_note_off(msg) and msg.channel == 0: previous_note_on = False return False def timeline_from_midi(midi_file, video_font_path): timeline = vidi.Timeline() elapsed_time = 0 start_time = 0 for msg in midi_file: elapsed_time += msg.time if is_note_on(msg) and msg.channel == 0: start_time = elapsed_time elif is_note_off(msg) and msg.channel == 0: note = vidi.MidiNote(msg.note) duration = elapsed_time - start_time print("Note name: %s start_time: %f duration: %f" % (note.name, start_time, duration)) video_sample_path = "%s/sample_%s.mkv" % (video_font_path, note.name) timeline.add_clip(video_sample_path, start_time, duration) return timeline def usage(): print("usage: %s []" % os.path.basename(sys.argv[0])) def main(): if len(sys.argv) > 1 and sys.argv[1] in ["-h", "--help"]: usage() return 0 if len(sys.argv) < 3: usage() return 1 if not os.path.isdir(sys.argv[2]): sys.stderr.write("The second argument must be the path of the videofont directory\n") usage() return 1 if len(sys.argv) > 3 and os.path.exists(sys.argv[3]): sys.stderr.write("File '%s' exists, exiting!\n" % sys.argv[3]) return 1 midi_file = mido.MidiFile(sys.argv[1]) overlapping_notes = check_overlapping_notes(midi_file, 0) if overlapping_notes: sys.stderr.write("Sorry, supporting only midi file with no overlapping notes on channel 0\n") return 1 video_font_path = os.path.realpath(sys.argv[2]) timeline = timeline_from_midi(midi_file, video_font_path) if len(sys.argv) > 3: timeline.save(sys.argv[3]) else: try: timeline.play() except KeyboardInterrupt: timeline.stop() return 1 if __name__ == "__main__": sys.exit(main())