admin commited on
Commit
16c3fe2
·
0 Parent(s):

Initial commit

Browse files
Files changed (8) hide show
  1. .gitattributes +35 -0
  2. .gitignore +5 -0
  3. README.md +12 -0
  4. app.py +102 -0
  5. convert.py +124 -0
  6. requirements.txt +6 -0
  7. test.sh +10 -0
  8. xml2abc.py +0 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bin.* filter=lfs diff=lfs merge=lfs -text
5
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.model filter=lfs diff=lfs merge=lfs -text
12
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
13
+ *.onnx filter=lfs diff=lfs merge=lfs -text
14
+ *.ot filter=lfs diff=lfs merge=lfs -text
15
+ *.parquet filter=lfs diff=lfs merge=lfs -text
16
+ *.pb filter=lfs diff=lfs merge=lfs -text
17
+ *.pt filter=lfs diff=lfs merge=lfs -text
18
+ *.pth filter=lfs diff=lfs merge=lfs -text
19
+ *.rar filter=lfs diff=lfs merge=lfs -text
20
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
21
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
22
+ *.tflite filter=lfs diff=lfs merge=lfs -text
23
+ *.tgz filter=lfs diff=lfs merge=lfs -text
24
+ *.xz filter=lfs diff=lfs merge=lfs -text
25
+ *.zip filter=lfs diff=lfs merge=lfs -text
26
+ *.zstandard filter=lfs diff=lfs merge=lfs -text
27
+ *.tfevents* filter=lfs diff=lfs merge=lfs -text
28
+ *.db* filter=lfs diff=lfs merge=lfs -text
29
+ *.ark* filter=lfs diff=lfs merge=lfs -text
30
+ **/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
31
+ **/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
32
+ **/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
33
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
34
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
35
+ *.AppImage filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ example/*
2
+ *__pycache__*
3
+ test.py
4
+ rename.sh
5
+ flagged/*
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Piano Transcriptor
3
+ emoji: 🎹
4
+ colorFrom: yellow
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 5.22.0
8
+ app_file: app.py
9
+ pinned: true
10
+ license: mit
11
+ short_description: Piano transcription tool
12
+ ---
app.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import shutil
4
+ import gradio as gr
5
+ from piano_transcription_inference import PianoTranscription, load_audio, sample_rate
6
+ from convert import midi2xml, xml2abc, xml2mxl, xml2jpg
7
+
8
+ EN_US = os.getenv("LANG") != "zh_CN.UTF-8"
9
+
10
+ if EN_US:
11
+ import huggingface_hub
12
+
13
+ MODEL_PATH = huggingface_hub.snapshot_download(
14
+ "Genius-Society/piano_trans",
15
+ cache_dir="./__pycache__",
16
+ )
17
+
18
+ else:
19
+ import modelscope
20
+
21
+ MODEL_PATH = modelscope.snapshot_download(
22
+ "Genius-Society/piano_trans",
23
+ cache_dir="./__pycache__",
24
+ )
25
+
26
+
27
+ ZH2EN = {
28
+ "五线谱": "Staff",
29
+ "状态栏": "Status",
30
+ "下载 MXL": "Download MXL",
31
+ "ABC 记谱": "ABC notation",
32
+ "上传音频": "Upload an audio",
33
+ "下载 MIDI": "Download MIDI",
34
+ "下载 PDF 乐谱": "Download PDF score",
35
+ "下载 MusicXML": "Download MusicXML",
36
+ "钢琴转谱工具": "Piano Transcription Tool",
37
+ "请上传音频 100% 后再点提交": "Please make sure the audio is completely uploaded before clicking Submit",
38
+ }
39
+
40
+
41
+ def _L(zh_txt: str):
42
+ return ZH2EN[zh_txt] if EN_US else zh_txt
43
+
44
+
45
+ def clean_cache(cache_dir):
46
+ if os.path.exists(cache_dir):
47
+ shutil.rmtree(cache_dir)
48
+
49
+ os.mkdir(cache_dir)
50
+
51
+
52
+ def audio2midi(audio_path: str, cache_dir: str):
53
+ audio, _ = load_audio(audio_path, sr=sample_rate, mono=True)
54
+ transcriptor = PianoTranscription(
55
+ device="cuda" if torch.cuda.is_available() else "cpu",
56
+ checkpoint_path=f"{MODEL_PATH}/CRNN_note_F1=0.9677_pedal_F1=0.9186.pth",
57
+ )
58
+ midi_path = f"{cache_dir}/output.mid"
59
+ transcriptor.transcribe(audio, midi_path)
60
+ return midi_path, os.path.splitext(os.path.basename(audio_path))[0].capitalize()
61
+
62
+
63
+ def upl_infer(audio_path: str, cache_dir="./__pycache__/cache"):
64
+ status = "Success"
65
+ midi = pdf = xml = mxl = abc = jpg = None
66
+ try:
67
+ clean_cache(cache_dir)
68
+ midi, title = audio2midi(audio_path, cache_dir)
69
+ xml = midi2xml(midi, title)
70
+ abc = xml2abc(xml)
71
+ mxl = xml2mxl(xml)
72
+ pdf, jpg = xml2jpg(xml)
73
+
74
+ except Exception as e:
75
+ status = f"{e}"
76
+
77
+ return status, midi, pdf, xml, mxl, abc, jpg
78
+
79
+
80
+ if __name__ == "__main__":
81
+ gr.Interface(
82
+ fn=upl_infer,
83
+ inputs=gr.Audio(label=_L("上传音频"), type="filepath"),
84
+ outputs=[
85
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
86
+ gr.File(label=_L("下载 MIDI")),
87
+ gr.File(label=_L("下载 PDF 乐谱")),
88
+ gr.File(label=_L("下载 MusicXML")),
89
+ gr.File(label=_L("下载 MXL")),
90
+ gr.Textbox(label=_L("ABC 记谱"), show_copy_button=True),
91
+ gr.Image(label=_L("五线谱"), type="filepath", show_share_button=False),
92
+ ],
93
+ title=_L("钢琴转谱工具"),
94
+ description=_L("请上传音频 100% 后再点提交"),
95
+ flagging_mode="never",
96
+ cache_examples=False,
97
+ examples=[
98
+ f"{MODEL_PATH}/examples/1945798894.mp3",
99
+ f"{MODEL_PATH}/examples/1945798973.mp3",
100
+ f"{MODEL_PATH}/examples/1946098771.mp3",
101
+ ],
102
+ ).launch()
convert.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import fitz
4
+ import requests
5
+ import subprocess
6
+ from PIL import Image
7
+ from music21 import converter
8
+
9
+
10
+ def download(url: str, directory: str, filename: str):
11
+ if directory != "" and not os.path.exists(directory):
12
+ os.makedirs(directory)
13
+ # Create the full path for the file to be saved
14
+ file_path = os.path.join(directory, filename)
15
+ # Send a GET request to the URL
16
+ response = requests.get(url, stream=True)
17
+ # Check if the request was successful
18
+ if response.status_code == 200:
19
+ # Open the file in write-binary mode
20
+ with open(file_path, "wb") as file:
21
+ # Write the contents of the response to the file
22
+ for chunk in response.iter_content(chunk_size=1024):
23
+ if chunk: # Filter out keep-alive new chunks
24
+ file.write(chunk)
25
+
26
+ print(f"The file has been downloaded and saved to {file_path}")
27
+
28
+ else:
29
+ print(f"Failed to download the file. Status code: {response.status_code}")
30
+
31
+ return os.path.join(directory, filename)
32
+
33
+
34
+ if sys.platform.startswith("linux"):
35
+ apkname = "MuseScore.AppImage"
36
+ extra_dir = "squashfs-root"
37
+ if not os.path.exists(apkname):
38
+ download(url=os.getenv("mscore"), directory="./", filename=apkname)
39
+
40
+ if not os.path.exists(extra_dir):
41
+ subprocess.run(["chmod", "+x", f"./{apkname}"])
42
+ subprocess.run([f"./{apkname}", "--appimage-extract"])
43
+
44
+ MSCORE = f"./{extra_dir}/AppRun"
45
+ os.environ["QT_QPA_PLATFORM"] = "offscreen"
46
+
47
+ else:
48
+ MSCORE = os.getenv("mscore")
49
+ if not MSCORE:
50
+ raise EnvironmentError("Please add musescore environment var!")
51
+
52
+
53
+ def add_title_to_xml(xml_path: str, title: str):
54
+ midi_data = converter.parse(xml_path)
55
+ midi_data.metadata.movementName = title
56
+ midi_data.metadata.composer = "Transcripted by AI"
57
+ midi_data.write("musicxml", fp=xml_path)
58
+
59
+
60
+ def xml2abc(xml_path: str):
61
+ result = subprocess.run(
62
+ ["python", "xml2abc.py", xml_path], stdout=subprocess.PIPE, text=True
63
+ )
64
+ if result.returncode == 0:
65
+ return result.stdout
66
+
67
+ return ""
68
+
69
+
70
+ def xml2mxl(xml_path: str):
71
+ mxl_file = xml_path.replace(".musicxml", ".mxl")
72
+ command = [MSCORE, "-o", mxl_file, xml_path]
73
+ result = subprocess.run(command)
74
+ print(result)
75
+ return mxl_file
76
+
77
+
78
+ def midi2xml(mid_file: str, title: str):
79
+ xml_file = mid_file.replace(".mid", ".musicxml")
80
+ command = [MSCORE, "-o", xml_file, mid_file]
81
+ result = subprocess.run(command)
82
+ add_title_to_xml(xml_file, title)
83
+ print(result)
84
+ return xml_file
85
+
86
+
87
+ def xml2midi(xml_file: str):
88
+ midi_file = xml_file.replace(".musicxml", ".mid")
89
+ command = [MSCORE, "-o", midi_file, xml_file]
90
+ result = subprocess.run(command)
91
+ print(result)
92
+ return midi_file
93
+
94
+
95
+ def pdf2img(pdf_path: str):
96
+ output_path = pdf_path.replace(".pdf", ".jpg")
97
+ doc = fitz.open(pdf_path)
98
+ images = []
99
+ for page_number in range(doc.page_count):
100
+ page = doc[page_number]
101
+ image = page.get_pixmap()
102
+ images.append(
103
+ Image.frombytes("RGB", [image.width, image.height], image.samples)
104
+ )
105
+
106
+ merged_image = Image.new(
107
+ "RGB", (images[0].width, sum(image.height for image in images))
108
+ )
109
+ y_offset = 0
110
+ for image in images:
111
+ merged_image.paste(image, (0, y_offset))
112
+ y_offset += image.height
113
+
114
+ merged_image.save(output_path, "JPEG")
115
+ doc.close()
116
+ return output_path
117
+
118
+
119
+ def xml2jpg(xml_file: str):
120
+ pdf_score = xml_file.replace(".musicxml", ".pdf")
121
+ command = [MSCORE, "-o", pdf_score, xml_file]
122
+ result = subprocess.run(command)
123
+ print(result)
124
+ return pdf_score, pdf2img(pdf_score)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ -f https://download.pytorch.org/whl/torch
2
+ librosa==0.9.2
3
+ music21
4
+ piano_transcription_inference
5
+ pymupdf
6
+ torch==2.6.0+cu118
test.sh ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ MOD_BRANCH="main"
4
+
5
+ git checkout --orphan latest_branch
6
+ git add -A
7
+ git commit -m "Initial commit"
8
+ git branch -D "$MOD_BRANCH"
9
+ git branch -m latest_branch "$MOD_BRANCH"
10
+ git push -u origin "$MOD_BRANCH" -f
xml2abc.py ADDED
The diff for this file is too large to render. See raw diff