This repository has no description
1#!/usr/bin/env python
2"""
3Usage: flp_to_json.py <input_flp_file> <output_json_file>
4"""
5
6from pathlib import Path
7from docopt import docopt
8import pyflp
9import json
10
11
12def clip_type(clip) -> str:
13 if hasattr(clip, "pattern"):
14 return "pattern"
15 elif hasattr(clip, "channel"):
16 return "channel"
17
18
19def clip_name(clip) -> str:
20 if clip_type(clip) == "pattern":
21 return clip.pattern.name
22 elif clip_type(clip) == "channel":
23 return clip.channel.name
24 else:
25 return ""
26
27
28def key_to_midi_pitch(note: str) -> int:
29 letter = note[0]
30 if len(note) == 3:
31 sharp = True
32 octave = int(note[2])
33 else:
34 sharp = False
35 octave = int(note[1])
36
37 letter_delta = {"C": -9, "D": -7, "E": -5, "F": -4, "G": -2, "A": 0, "B": 2}.get(
38 letter, 0
39 )
40 return 81 + 12 * (octave - 4) + letter_delta + int(sharp)
41
42
43def note_data(note):
44 return {
45 "key": note.key,
46 "pitch": key_to_midi_pitch(note.key),
47 "length": note.length,
48 "velocity": note.velocity,
49 }
50
51
52def clip_data(clip):
53 if clip_type(clip) == "pattern":
54 pat = clip.pattern
55 return {
56 "notes": {note.position: note_data(note) for note in pat.notes},
57 "values": {},
58 "length": pat.length,
59 }
60 elif clip_type(clip) == "channel":
61 chan = clip.channel
62 if isinstance(chan, pyflp.channel.Automation):
63 return {
64 "notes": {},
65 "values": {point.position: point.value for point in chan},
66 "length": chan.length,
67 }
68 return {
69 "notes": {},
70 "values": {},
71 "length": chan.length,
72 }
73 return {
74 "notes": {},
75 "values": {},
76 "length": 0,
77 }
78
79
80def track_name(track) -> str:
81 if track.name:
82 return track.name
83
84 clips_names = [clip_name(clip) for clip in track if clip_name(clip)]
85 if not clips_names:
86 return ""
87
88 return clips_names[0]
89
90
91def serialize_track(track):
92 out = {}
93 for clip in track:
94 out[clip.position] = {
95 "length": clip.length,
96 "name": clip_name(clip),
97 "data": clip_data(clip),
98 }
99
100 return out
101
102
103def main():
104 args = docopt(__doc__)
105 project = pyflp.parse(args["<input_flp_file>"])
106
107 out = {
108 "info": {"name": project.title, "bpm": project.tempo},
109 "arrangements": {},
110 }
111
112 for a in project.arrangements:
113 out["arrangements"][a.name] = {
114 "tracks": {
115 track_name(track): serialize_track(track) for track in a.tracks
116 },
117 "markers": {
118 marker.position: marker.name for marker in a.timemarkers
119 },
120 }
121
122 Path(args["<output_json_file>"]).write_text(json.dumps(out, indent=4))
123
124
125# end
126
127
128if __name__ == "__main__":
129 main()