From 2780f9db87ca6f82d325aabe88fa0e8ba14f3817 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 5 Dec 2016 15:40:29 +0100 Subject: [PATCH] Rename vidi-player.py to vidi-timeline.py The name vidi-timeline.py reflect better what the program actually does: generate GES timelines. This also frees the spot for a possible future vidi-player program, based on GStreamer, which plays midi files live without having to generate the GES pipeline beforehand. --- README.md | 8 ++-- vidi-player.py | 127 ------------------------------------------------------- vidi-timeline.py | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 131 deletions(-) delete mode 100755 vidi-player.py create mode 100755 vidi-timeline.py diff --git a/README.md b/README.md index 322615a..7f8c3db 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -vidi-player creates a video timeline starting from a MIDI file. +vidi-timeline creates a video timeline starting from a MIDI file. The video clips are taken from a "VideoFont" in which each sample clip corresponds to a note. The samples are arranged following the time and value of the notes in the MIDI file. -vidi-player allows to create more easily videos like these: +vidi-timeline allows to create more easily videos like these: * Lasse Gjertsen - Hyperactive - https://youtu.be/o9698TqtY4A * Vittorio Saggiomo - Mario Bros Column Chromatography - https://youtu.be/mxi3z2vDV_0 @@ -20,12 +20,12 @@ Create a synthetinc VideoFont: Play the timeline from a MIDI file using the samples from the VideoFont: - $ ./vidi-player.py examples/Beyer\ Op.\ 101\ -\ Exercise\ 008.midi videofont + $ ./vidi-timeline.py examples/Beyer\ Op.\ 101\ -\ Exercise\ 008.midi videofont Save the timeline to be edited somewhere else (e.g. in PiTiVi): - $ ./vidi-player.py examples/Beyer\ Op.\ 101\ -\ Exercise\ 008.midi videofont/ Beyer_008.xges + $ ./vidi-timeline.py examples/Beyer\ Op.\ 101\ -\ Exercise\ 008.midi videofont/ Beyer_008.xges Render the timeline to a video file: diff --git a/vidi-player.py b/vidi-player.py deleted file mode 100755 index 4ac51a6..0000000 --- a/vidi-player.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/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 - -# TODO: turn that into a command line option -ADD_REST_BACKGROUND = True - - -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: %3s start_time: %f duration: %f" % - (note.name, start_time, duration)) - - video_sample_path = "%s/sample_%s.webm" % (video_font_path, note.name) - - timeline.add_clip(video_sample_path, start_time, duration) - - if ADD_REST_BACKGROUND: - rest_sample_path = "%s/sample_rest.png" % video_font_path - timeline.add_layer_clip(rest_sample_path, 0, elapsed_time) - - 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) - 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()) diff --git a/vidi-timeline.py b/vidi-timeline.py new file mode 100755 index 0000000..1068545 --- /dev/null +++ b/vidi-timeline.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# +# vidi-timeline - 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 + +# TODO: turn that into a command line option +ADD_REST_BACKGROUND = True + + +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: %3s start_time: %f duration: %f" % + (note.name, start_time, duration)) + + video_sample_path = "%s/sample_%s.webm" % (video_font_path, note.name) + + timeline.add_clip(video_sample_path, start_time, duration) + + if ADD_REST_BACKGROUND: + rest_sample_path = "%s/sample_rest.png" % video_font_path + timeline.add_layer_clip(rest_sample_path, 0, elapsed_time) + + 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) + 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()) -- 2.1.4