def main(): parser = argparse.ArgumentParser(description="Reorder MIDI tracks.") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('midi_out_file', help='midi filename to export') parser.add_argument('track_order', type=int, nargs='*', help='new order (first track is track 1)') args = parser.parse_args() if not (args.midi_in_file.lower().endswith(r'.mid') or args.midi_in_file.lower().endswith(r'.midi')): parser.error(r'Expecting input filename that ends in ".mid"') if not os.path.exists(args.midi_in_file): parser.error('Cannot find "%s"' % args.midi_in_file) song = midi.MIDI().to_chirp(args.midi_in_file) if max(args.track_order) > len(song.tracks): raise ChiptuneSAKValueError( "Illegal track specified: only %d tracks in song" % len(song.tracks)) old_tracks = copy.deepcopy(song.tracks) new_tracks = [old_tracks[it - 1] for it in args.track_order] song.tracks = new_tracks print("New track order:") print("\n".join(t.name for t in song.tracks)) print("Writing to midi file %s" % args.midi_out_file) midi.MIDI().to_file(song, args.midi_out_file)
def main(): parser = argparse.ArgumentParser( description="Convert song into Lilypond score") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('out_folder', help='output folder') parser.add_argument('-a', '--autosort', action="store_true", help='automatically sort staves by average note') args = parser.parse_args() lp = Lilypond() if args.autosort: lp.set_options(autosort="True") print("Reading %s" % args.midi_in_file) chirp_song = midi.MIDI().to_chirp(args.midi_in_file, quantization='auto', polyphony=False) print('Converting to measures...') mchirp_song = chirp_song.to_mchirp() print('Generating lilypond...') ly_name = args.midi_in_file.replace('.mid', '.ly') lp.to_file(mchirp_song, ly_name) subprocess.call('lilypond -o %s %s' % (args.out_folder, ly_name), shell=True) print("\ndone")
def main(): parser = argparse.ArgumentParser(description="Explode MIDI track.") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('midi_out_file', help='midi filename to export') track_group = parser.add_mutually_exclusive_group(required=False) track_group.add_argument('-n', '--tracknumber', type=int, help='track number (first track is 1)') track_group.add_argument('-t', '--trackname', type=str, help='track name') args = parser.parse_args() if not (args.midi_in_file.lower().endswith(r'.mid') or args.midi_in_file.lower().endswith(r'.midi')): parser.error(r'Expecting input filename that ends in ".mid"') if not os.path.exists(args.midi_in_file): parser.error('Cannot find "%s"' % args.midi_in_file) song = midi.MIDI().to_chirp(args.midi_in_file) if args.tracknumber: print("Exploding track number %d" % args.tracknumber) song.explode_polyphony(args.tracknumber - 1) elif args.trackname: it = next( (it for it, t in enumerate(song.tracks) if t.name == args.trackname), None) if it is None: print("Track %s not found" % args.trackname) exit(1) else: print("Exploding track %s" % song.tracks[it].name) song.explode_polyphony(it) else: print("No track specified") exit(1) midi.MIDI().to_file(song, args.midi_out_file)
def main(): parser = argparse.ArgumentParser(description="Convert a GoatTracker2 sng file to a midi file.") parser.add_argument('sng_in_file', help='sng filename to import') parser.add_argument('midi_out_file', help='midi filename to export') parser.add_argument( '-s', '--subtune_number', type=int, default=0, help='subtune number (default: 0)' ) args = parser.parse_args() rchirp_song = goat_tracker.GoatTracker().to_rchirp(args.sng_in_file, subtune=args.subtune_number) """ cvs_filename = '%s.csv' % (args.sng_in_file.split('.')[0]) with open(cvs_filename, 'w') as out_file: out_file.write(rchirp_song.note_time_data_str()) """ chirp_song = rchirp_song.to_chirp() # TODO: Allow time signature to be set here? midi.MIDI().to_file(chirp_song, args.midi_out_file) print("\ndone")
def main(): parser = argparse.ArgumentParser( description="Perform transformations on MIDI files.", epilog="Operations are performed in the order given in this help." ) parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('midi_out_file', help='midi filename to export') parser.add_argument('-n', '--name', type=str, help='set name of song') parser.add_argument('-z', '--removekeyswitchnotes', action="store_true", help='remove keyswitch notes') parser.add_argument('-s', '--scaleticks', type=float, help='scale ticks') parser.add_argument('-x', '--moveticks', type=str, help='move ticks lXXXX for left and rXXXX for right') parser.add_argument('-p', '--ppq', type=int, help='set ppq') parser.add_argument('-m', '--modulate', type=str, help='modulate by n/d') parser.add_argument('-t', '--transpose', type=str, help='transpose by semitones (uXX or dXX for up or down XX semitones)') quant_group = parser.add_mutually_exclusive_group(required=False) quant_group.add_argument('-a', '--quantizeauto', action="store_true", help='Auto-quantize') quant_group.add_argument('-q', '--quantizenote', type=str, help='quantize to a note value') quant_group.add_argument('-c', '--quantizeticks', type=int, help='quantize to ticks') parser.add_argument('-r', '--removepolyphony', action="store_true", help='remove polyphony') parser.add_argument('-b', '--qpm', type=int, help='set qpm') parser.add_argument('-j', '--timesignature', type=str, help='set time signature e.g. 3/4') parser.add_argument('-k', '--keysignature', type=str, help='set key signature, e.g. D, F#m') args = parser.parse_args() if not (args.midi_in_file.lower().endswith(r'.mid') or args.midi_in_file.lower().endswith(r'.midi')): parser.error(r'Expecting input filename that ends in ".mid"') if not path.exists(args.midi_in_file): parser.error('Cannot find "%s"' % args.midi_in_file) song = midi.MIDI().to_chirp(args.midi_in_file) # Print stats print('%d notes' % (sum(len(t.notes) for t in song.tracks))) print('PPQ = %d' % (song.metadata.ppq)) q_state = "" if song.is_quantized() else "not" p_state = "" if song.is_polyphonic() else "not" print("Input midi is %s quantized and is %s polyphonic" % (q_state, p_state)) if args.name: print("Renaming song to %s" % args.name) song.metadata.name = args.name if args.removekeyswitchnotes: print("Removing control notes...") song.remove_keyswitches() if args.scaleticks: print("Scaling by %lf" % args.scaleticks) song.scale_ticks(args.scaleticks) if args.moveticks: move = args.moveticks if move[0] == 'l': v = -int(move[1:]) elif move[0].isdigit(): v = int(move) else: v = int(move[1:]) print("Moving by %d" % v) song.move_ticks(v) if args.ppq: print("setting ppq to %d" % args.ppq) song.metadata.ppq = args.ppq if args.modulate: num, denom = (int(n) for n in args.modulate.split('/')) print("modulating by %d/%d" % (num, denom)) song.modulate(num, denom) if args.transpose: if args.transpose[0] == 'd': transpose = -int(args.transpose[1:]) else: transpose = int(args.transpose[1:]) print("transposing by %d" % transpose) song.transpose(transpose) if args.quantizenote: print("Quantizing...") print("to note value %s" % args.quantizenote) song.quantize_from_note_name(args.quantizenote) elif args.quantizeticks: print("Quantizing...") print('to %d ticks' % args.quantizeticks) song.quantize(args.quantizeticks, args.quantizeticks) elif args.quantizeauto: print("Quantizing...") qticks_n, qticks_d = song.estimate_quantization() print('to estimated quantization: %d, %d ticks' % (qticks_n, qticks_d)) song.quantize(qticks_n, qticks_d) if args.removepolyphony: print("Eliminating polyphony...") song.remove_polyphony() if args.qpm: print("Setting qpm to %d" % args.qpm) song.set_qpm(args.qpm) if args.timesignature: num, denom = (int(x) for x in args.timesignature.split('/')) if num > 0 and denom > 0: print('Setting time signature to %d/%d' % (num, denom)) song.set_time_signature(num, denom) if args.keysignature: print('Setting key signature to %s' % args.keysignature) song.set_key_signature(args.keysignature) q_state = "" if song.is_quantized() else "not" p_state = "" if song.is_polyphonic() else "not" print("Output ChirpSong is %s quantized and %s polyphonic" % (q_state, p_state)) print("Exporting to MIDI...") midi.MIDI().to_file(song, args.midi_out_file)
def main(): parser = argparse.ArgumentParser( description="Convert a midi file into a C128 BASIC program.") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('basic_out_file', help='filename to export') parser.add_argument('-t', '--type', choices=['bas', 'prg'], help='basic output file type (default: prg)') parser.add_argument('-i', '--instruments', nargs=3, help="instrument names (3 required)") parser.add_argument('-a', '--arch', default=constants.DEFAULT_ARCH, help="architecture (NTSC or PAL)") args = parser.parse_args() if not (args.midi_in_file.lower().endswith(r'.mid') or args.midi_in_file.lower().endswith(r'.midi')): parser.error(r'Expecting input filename that ends in ".mid"') if not os.path.exists(args.midi_in_file): parser.error('Cannot find "%s"' % args.midi_in_file) # midi -> mchirp song = midi.MIDI().to_chirp(args.midi_in_file) song.remove_keyswitches(8) song.quantize_from_note_name('16') # transformMidi.py -q 32 -k Am ..\test\BWV_799.mid ..\test\BWV_799_q.mid # song.quantize_from_note_name('32') song.remove_polyphony() c128_basic.trim_note_lengths(song) if len(song.metadata.name) == 0: song.metadata.name = args.midi_in_file.split(os.sep)[-1].lower() # chirp -> mchirp mchirp_song = song.to_mchirp() # mchirp -> C128 Basic instruments = ('piano', 'piano', 'piano') if args.instruments: instruments = (i.lower() for i in args.instruments) # if -t flag not used, look at output filename extension if args.type is None: if args.basic_out_file.lower().endswith('.bas'): args.type = 'bas' else: args.type = 'prg' basic_converter = c128_basic.C128Basic() basic_converter.set_options(arch=args.arch, format=args.type, instruments=instruments) basic_converter.to_file(mchirp_song, args.basic_out_file) print("\ndone")
def main(): parser = argparse.ArgumentParser( description="Fit best PPQ value for MIDI files.") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('midi_out_file', help='midi filename to export') parser.add_argument('-p', '--ppq', type=int, default=DEFAULT_MIDI_PPQN, nargs='?', help='preferred PPQ (default = DEFAULT_MIDI_PPQN)') parser.add_argument('-m', '--minnote', type=str, default='16', nargs='?', help='minimum interval name (default = 16)') parser.add_argument('-s', '--scalefactor', type=float, help='estimated scale factor') parser.add_argument('-o', '--offset', type=int, help='estimated offset in original ticks') args = parser.parse_args() desired_ppq = args.ppq desired_q = desired_ppq * DURATION_STR[args.minnote] print("Reading file %s" % args.midi_in_file) song = midi.MIDI().to_chirp(args.midi_in_file) notes = [n for t in song.tracks for n in t.notes] f_min = round(desired_ppq / song.metadata.ppq / 2, 3) f_max = f_min * 8. if args.scalefactor: f_min = args.scalefactor * .9 f_max = args.scalefactor * 1.1 else: if f_min < 1.: f_min = 1. if f_max > 12.: f_max = 12. f_step = .01 offset_est = min(n.start_time for n in notes) if args.offset: offset_est = args.offset last_min_e = 1.e9 get_best_f = functools.partial(find_best_f, notes, desired_q) get_best_offset = functools.partial(find_best_offset, notes, desired_q, offset_est - 20, offset_est + 20) print('Finding initial parameters...') # Do wide-range search for best scale factor and offset. best_f, min_e = get_best_f(f_min, f_max, f_step, offset_est) best_offset, min_e = get_best_offset(best_f) # Now refine the scale factor and offset iteratively until they converge print('Refining...') while min_e < last_min_e: last_min_e = min_e f_step /= 10. f_min = best_f - (f_step * 200) if (f_min < 1.0): f_min = 1.0 f_max = f_min + (f_step * 200) best_f, min_e = get_best_f(f_min, f_max, f_step, best_offset) best_offset, min_e = get_best_offset(best_f) # Average error in new ticks tick_error = min_e / len(notes) * best_f print( "scale_factor = %.7lf, offset = %d, total error = %.1lf ticks (%.2lf ticks/note for ppq = %d)" % (best_f, best_offset, min_e, tick_error, desired_ppq)) song.move_ticks(-best_offset) song.scale_ticks(best_f) song.metadata.ppq = desired_ppq # song.quantize_from_note_name('16') print("Writing file %s" % args.midi_out_file) midi.MIDI().to_file(song, args.midi_out_file) print("\ndone")
def main(): parser = argparse.ArgumentParser( description="Perform operations on individual tracks of MIDI files.", epilog="Operations are performed in the order given in this help.") parser.add_argument('midi_in_file', help='midi filename to import') parser.add_argument('midi_out_file', help='midi filename to export') parser.add_argument('track', type=str, help='Track either number (starting with 1) or name') parser.add_argument('-n', '--name', type=str, help='Set track name') quant_group = parser.add_mutually_exclusive_group(required=False) quant_group.add_argument('-a', '--quantizeauto', action="store_true", help='Auto-quantize') quant_group.add_argument('-q', '--quantizenote', type=str, help='quantize to a note value') quant_group.add_argument('-c', '--quantizeticks', type=int, help='quantize to ticks') quant_group.add_argument('-d', '--quantizelongticks', type=int, help='quantize long notes to ticks') parser.add_argument('-m', '--merge', type=int, help='merge track (max num ticks to merge)') short_note_group = parser.add_mutually_exclusive_group(required=False) short_note_group.add_argument('-r', '--removeshort', type=int, help='remove notes <= tick value') short_note_group.add_argument( '-l', '--setminnotelen', type=int, help='set the minimum note length to tick value,' ' possibly consuming portion of ' 'following note') args = parser.parse_args() if not (args.midi_in_file.lower().endswith(r'.mid') or args.midi_in_file.lower().endswith(r'.midi')): parser.error('Expecting input filename that ends in ".mid"') if not path.exists(args.midi_in_file): parser.error('Cannot find "%s"' % args.midi_in_file) song = midi.MIDI().to_chirp(args.midi_in_file) track = None if all(t.isdigit() for t in args.track): track = song.tracks[int(args.track) - 1] print("Editing track %d" % int(args.track)) else: for t in song.tracks: if t.name == args.track: track = t if track is None: print('Track %s not found. Available tracks:') for t in song.tracks: print(t.name) parser.error('No track named %s found.' % args.track) if args.name: track.name = args.name if args.quantizelongticks: print("Quantizing long notes to %d" % args.quantizelongticks) track.quantize_long(args.quantizelongticks) if args.removeshort: print("Removing notes under %d ticks" % args.removeshort) track.remove_short_notes(args.removeshort) if args.setminnotelen: print("Setting minimum note length to %d" % args.setminnotelen) track.set_min_note_len(args.setminnotelen) if args.merge: print("Merging notes under %d" % args.merge) track.merge_notes(args.merge) print("Exporting to MIDI...") midi.MIDI().to_file(song, args.midi_out_file)