2016-06-09 15:55:09 +00:00
|
|
|
#! /usr/bin/env python
|
2016-05-20 09:10:07 +00:00
|
|
|
# -*- coding: utf-8
|
2016-06-09 19:31:46 +00:00
|
|
|
"""
|
|
|
|
Generate sound for Git repositories
|
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import print_function
|
2016-05-20 09:10:07 +00:00
|
|
|
|
|
|
|
import argparse
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
|
2016-06-09 19:31:46 +00:00
|
|
|
try:
|
2016-06-09 22:31:40 +00:00
|
|
|
from git_sound.gui import GitSoundWindow
|
|
|
|
GUI_AVAILABLE = True
|
2016-06-09 19:31:46 +00:00
|
|
|
except ImportError:
|
2016-06-09 22:31:40 +00:00
|
|
|
GUI_AVAILABLE = False
|
2016-06-09 19:31:46 +00:00
|
|
|
|
2016-05-20 09:10:07 +00:00
|
|
|
from git.exc import InvalidGitRepositoryError
|
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
from git_sound.gitmidi import GitMIDI
|
|
|
|
|
2016-06-09 19:31:46 +00:00
|
|
|
SCALES = {
|
2016-06-09 10:12:49 +00:00
|
|
|
'c-major': ('C Major', [60, 62, 64, 65, 67, 69, 71]),
|
|
|
|
'a-harmonic-minor': ('A Harmonic Minor', [68, 69, 71, 72, 74, 76, 77]),
|
|
|
|
'chromatic': ('Chromatic', [60, 61, 62, 63, 64, 65, 66, 67, 68, 69]),
|
|
|
|
'pentatonic': ('Pentatonic', [54, 64, 72, 81, 96, 108]),
|
2016-06-09 15:53:44 +00:00
|
|
|
'd-major': ('D Major', [62, 64, 65, 67, 69, 71, 72]),
|
2016-05-24 11:02:11 +00:00
|
|
|
}
|
2016-05-20 09:10:07 +00:00
|
|
|
|
2016-06-09 19:31:46 +00:00
|
|
|
PROGRAMS = {
|
2016-05-24 11:02:11 +00:00
|
|
|
'sitar-tablah': {
|
2016-06-09 10:12:49 +00:00
|
|
|
'name': 'Sitar and Tablah',
|
2016-05-24 11:02:11 +00:00
|
|
|
'commit': {
|
|
|
|
'program': 104,
|
|
|
|
'octave': -2,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': 115,
|
|
|
|
'octave': -1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
'bells': {
|
2016-06-09 10:12:49 +00:00
|
|
|
'name': 'Bells',
|
2016-05-24 11:02:11 +00:00
|
|
|
'commit': {
|
|
|
|
'program': 14,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': 9,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
},
|
2016-05-26 15:29:47 +00:00
|
|
|
'metal': {
|
2016-06-09 10:12:49 +00:00
|
|
|
'name': 'Metal',
|
2016-05-26 15:29:47 +00:00
|
|
|
'commit': {
|
2016-06-09 08:58:36 +00:00
|
|
|
'program': 29,
|
2016-05-26 15:29:47 +00:00
|
|
|
'octave': -1,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': 33,
|
|
|
|
'octave': -3,
|
|
|
|
},
|
|
|
|
},
|
2016-05-26 17:32:03 +00:00
|
|
|
'pure-violin': {
|
2016-06-09 10:12:49 +00:00
|
|
|
'name': 'Violin',
|
2016-05-26 17:32:03 +00:00
|
|
|
'commit': {
|
|
|
|
'program': 40,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': None,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
},
|
2016-06-09 09:01:27 +00:00
|
|
|
'space': {
|
2016-06-09 10:12:49 +00:00
|
|
|
'name': 'Space',
|
2016-06-09 09:01:27 +00:00
|
|
|
'commit': {
|
|
|
|
'program': 94,
|
|
|
|
'octave': 1,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': 80,
|
|
|
|
'octave': 1,
|
|
|
|
'volume': -30,
|
|
|
|
},
|
|
|
|
},
|
2016-06-09 15:34:38 +00:00
|
|
|
'sea-copter': {
|
|
|
|
'name': 'Helicopter on the shore',
|
|
|
|
'commit': {
|
|
|
|
'program': 125,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
'file': {
|
|
|
|
'program': 122,
|
|
|
|
'octave': 0,
|
|
|
|
},
|
|
|
|
},
|
2016-05-24 11:02:11 +00:00
|
|
|
}
|
|
|
|
|
2016-05-20 09:10:07 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
parser = argparse.ArgumentParser(description='Voice of a Repo',
|
|
|
|
epilog='Use the special value list for ' +
|
|
|
|
'scale and program to list the ' +
|
|
|
|
'available program combinations')
|
|
|
|
|
|
|
|
parser.add_argument('repository', type=str, nargs='?', default='.')
|
|
|
|
parser.add_argument('--branch',
|
|
|
|
type=str,
|
|
|
|
default='master',
|
|
|
|
help="The branch to generate sound for [master]")
|
|
|
|
parser.add_argument('--file',
|
|
|
|
type=str,
|
|
|
|
default=None,
|
|
|
|
help="Save the generated MIDI sequence to this file")
|
|
|
|
parser.add_argument('--play',
|
|
|
|
action='store_true',
|
|
|
|
default=False,
|
|
|
|
help="Play the generated file (requires pygame with " +
|
|
|
|
"MIDI support)")
|
|
|
|
parser.add_argument('--verbose',
|
|
|
|
action='store_true',
|
|
|
|
default=False,
|
|
|
|
help="Print messages during execution")
|
|
|
|
parser.add_argument('--scale',
|
|
|
|
type=str,
|
|
|
|
default=None,
|
|
|
|
help="Scale to use in the generated track")
|
|
|
|
parser.add_argument('--program',
|
|
|
|
type=str,
|
|
|
|
default=None,
|
|
|
|
help="Program setting to use in the generated track")
|
|
|
|
parser.add_argument('--volume-range',
|
|
|
|
type=int,
|
|
|
|
default=100,
|
|
|
|
help="The volume range to use.")
|
|
|
|
parser.add_argument('--skip',
|
|
|
|
type=int,
|
|
|
|
default=0,
|
|
|
|
metavar='N',
|
|
|
|
help="Skip the first N commits " +
|
|
|
|
"(comes in handy if the repo started " +
|
|
|
|
"with some huge commits)")
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
if args.scale is None and args.program is None and GUI_AVAILABLE:
|
|
|
|
GitSoundWindow(PROGRAMS, SCALES).start()
|
|
|
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if args.scale is None and args.program != 'list':
|
|
|
|
print("Please specify a scale!")
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if args.program is None and args.scale != 'list':
|
|
|
|
print("Please specify a program!")
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if args.scale == 'list':
|
|
|
|
for scale in SCALES.keys():
|
|
|
|
print(scale)
|
|
|
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if args.program == 'list':
|
|
|
|
for program in PROGRAMS.keys():
|
|
|
|
print(program)
|
|
|
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if args.scale not in SCALES:
|
|
|
|
print("{} is an unknown scale.".format(args.scale))
|
|
|
|
print("Use 'list' to list the available scales.")
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if args.program not in PROGRAMS:
|
|
|
|
print("{} is an unknown program.".format(args.program))
|
|
|
|
print("Use 'list' to list the available programs.")
|
|
|
|
|
|
|
|
sys.exit(1)
|
2016-05-24 10:12:15 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
try:
|
|
|
|
repo_midi = GitMIDI(repository=args.repository,
|
|
|
|
branch=args.branch,
|
|
|
|
verbose=args.verbose,
|
|
|
|
scale=SCALES[args.scale][1],
|
|
|
|
program=PROGRAMS[args.program],
|
|
|
|
volume_range=args.volume_range,
|
|
|
|
skip=args.skip)
|
2016-05-26 17:28:47 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
except InvalidGitRepositoryError:
|
|
|
|
print("{} is not a valid Git repository"
|
|
|
|
.format(os.path.abspath(args.repository)))
|
2016-06-09 15:35:26 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
sys.exit(1)
|
2016-05-26 17:28:47 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
except IndexError:
|
|
|
|
print("Branch '{}' does not exist in this repo".format(args.branch))
|
2016-06-09 15:35:26 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
sys.exit(1)
|
2016-05-20 09:10:07 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
repo_midi.gen_repo_data()
|
|
|
|
repo_midi.generate_midi()
|
|
|
|
repo_midi.write_mem()
|
2016-06-09 15:54:09 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
if args.file:
|
|
|
|
if args.verbose:
|
|
|
|
print("Saving file to {}".format(args.file))
|
2016-05-26 17:48:13 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
repo_midi.export_file(args.file)
|
2016-06-09 19:31:46 +00:00
|
|
|
|
2016-06-09 22:31:40 +00:00
|
|
|
if args.play:
|
|
|
|
repo_midi.play()
|