commit b5a838bbd7bf5f10bf5d344bd6f8fb64a18d7777 Author: Saman Date: Wed May 20 02:41:15 2026 +0330 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c0a376 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +bmm_0.1/ +env/ +ENV/ +.venv/ +__pycache__/ +*.py[cod] +*.pyo +*.so +*.egg-info/ +*.egg +dist/ +build/ +*.tmp +*.temp +Thumbs.db +*.log +*.db +*.sqlite +.vscode/ +.idea/ +*.swp +*.swo \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..8a9f1f5 --- /dev/null +++ b/__init__.py @@ -0,0 +1,2 @@ +from .basic_converter import media_to_notes +__all__=["media_to_notes"] diff --git a/basic_converter.py b/basic_converter.py new file mode 100644 index 0000000..f6762ee --- /dev/null +++ b/basic_converter.py @@ -0,0 +1,73 @@ +#Importing Libraries +from imageio_ffmpeg import get_ffmpeg_exe +from subprocess import run +from librosa import load +from noisereduce import reduce_noise +from soundfile import write +from basic_pitch.inference import predict_and_save, ICASSP_2022_MODEL_PATH +from music21.midi import MidiFile, translate, environment +from os.path import splitext, basename, join, dirname +from os import makedirs +from lilypond import executable +from tempfile import TemporaryDirectory +from shutil import copy2 +from platform import system +lilypond_path=str(executable()) +if system()=="Windows" and not lilypond_path.lower().endswith('.exe'): + lilypond_path+='.exe' +us=environment.UserSettings() +us['lilypondPath']=lilypond_path + +#Main Function +def media_to_notes(input_path,output_path,lilypond_path=lilypond_path): + makedirs(dirname(output_path),exist_ok=True) + file_extension=splitext(input_path)[1] + file_name=splitext(basename(input_path))[0] + + #Saving Between Files in Temp Directory + with TemporaryDirectory() as tmp: + #Correcting File Format + if file_extension.lower()!='.wav': + run([get_ffmpeg_exe(),'-y','-i',input_path,join(tmp,file_name+'.wav')],check=True) + wav_path=join(tmp,file_name+'.wav') + else: + wav_path=input_path + #Noise Reduction + y,sr=load(wav_path,sr=None,mono=True) + noise_reduced_music=reduce_noise(y=y,sr=sr,stationary=True,prop_decrease=0.6) + write(join(tmp,file_name+'_denoised.wav'),noise_reduced_music,sr) + + #Making The MIDI + predict_and_save( + audio_path_list=[join(tmp,file_name+'_denoised.wav')], + output_directory=tmp, + save_midi=True, + sonify_midi=False, + save_model_outputs=False, + save_notes=True, + model_or_model_path=ICASSP_2022_MODEL_PATH) + + #Making The Ly + mf=MidiFile() + mf.open(join(tmp,file_name+'_denoised_basic_pitch.mid')) + mf.read() + mf.close() + s=translate.midiFileToStream(mf) + s.write('lily', fp=join(tmp,file_name+'.ly')) + + #Correcting The Layout + with open(join(tmp,file_name+'.ly'),'r',encoding='utf-8') as f: + ly=f.read() + if r'\include "lilypond-book-preamble.ly"' in ly: + ly=ly.replace(r'\include "lilypond-book-preamble.ly"',rf'\include "{file_name}_wrapper.ly"') + else: + ly=rf'\include "{file_name}_wrapper.ly"'+'\n'+ly + with open(join(tmp,file_name+'_wrapper.ly'),'w',encoding='utf-8') as f: + f.write(r'\header { tagline = ##f }') + with open(join(tmp,file_name+'.ly'),'w',encoding='utf-8') as f: + f.write(ly) + + #Making The PDF + run([lilypond_path,"-I",tmp,"-o",join(tmp,file_name),join(tmp,file_name+'.ly')],check=True) + copy2(join(tmp,file_name+'.pdf'),output_path) + print(f"Notes PDF saved to {output_path}.") diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..18670c0 --- /dev/null +++ b/setup.py @@ -0,0 +1,20 @@ +from setuptools import setup,find_packages +setup( + name="Music_Mate", + version="0.1.0", + packages=find_packages(), + install_requires=[ + "imageio-ffmpeg==0.6.0", + "lilypond==2.24.3", + "librosa==0.11.0", + "noisereduce==3.0.3", + "soundfile==0.13.1", + "basic-pitch==0.4.0", + "music21==9.9.1", + ], + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + ], + python_requires="==3.11.*", +)