import sys sys.path.append('/home/lida/Downloads/lilypond-2.24.1/python') from PyQt5.QtWidgets import * from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtGui import QPixmap from PyQt5 import uic import keyboard from ly import * import ly.document import ly.cli.command import ly.cli.main #from ly import ly.transposition ? from abjad import LilyPondFile, Pitch, Note import re class SheetMusicEditor(QDialog): class KeyboardListener(QThread): note_added = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent=parent) self.key_to_note = { "c": Pitch("c'"), "d": Pitch("d'"), "e": Pitch("e'"), "f": Pitch("f'"), "g": Pitch("g'"), "a": Pitch("a'"), "b": Pitch("b'"), } def run(self): while True: key = keyboard.read_event().name if key in self.key_to_note: note = Note.from_pitch(self.key_to_note[key]) self.note_added.emit(note.to_lilypond() + "") def __init__(self): super(SheetMusicEditor, self).__init__() uic.loadUi("qtdesigner_zkouska.ui", self) self.keyboard_listener = self.KeyboardListener() self.keyboard_listener.note_added.connect(self.add_note_to_file) self.keyboard_listener.start() self.show() self.pushButton.clicked.connect(self.transpose_up) self.pushButton_2.clicked.connect(self.transpose_down) self.krizek_button.clicked.connect(self.add_krizek_to_file) self.becko_button.clicked.connect(self.add_becko_to_file) self.treble_button.setChecked(True) self.treble_button.toggled.connect(self.clef_changed) self.alto_button.toggled.connect(self.clef_changed) self.bass_button.toggled.connect(self.clef_changed) #self.pushButton_3.clicked.connect(self.make_big) #self.pushButton_4.clicked.connect(self.make_small) self.save_button.clicked.connect(self.saveFile) self.openFile_button.clicked.connect(self.openFile) self.new_file_button.clicked.connect(self.create_new_file) self.refresh_button.clicked.connect(self.refresh_sheet) self.c_button.clicked.connect(lambda: self.add_note_to_file("c'")) self.d_button.clicked.connect(lambda: self.add_note_to_file("d'")) self.e_button.clicked.connect(lambda: self.add_note_to_file("e'")) self.f_button.clicked.connect(lambda: self.add_note_to_file("f'")) self.g_button.clicked.connect(lambda: self.add_note_to_file("g'")) self.a_button.clicked.connect(lambda: self.add_note_to_file("a'")) self.b_button.clicked.connect(lambda: self.add_note_to_file("b'")) #self.lineEdit(self.change_title) line_edit = QLineEdit() line_edit.textChanged.connect(lambda text: change_title(title=text)) #tady takové divné, ten první a třetí řádek spolu neinteragují hezky self.bpm_slider = QSlider(Qt.Horizontal) self.bpm_slider.setMinimum(1) self.bpm_slider.setMaximum(10000) self.bpm_slider.setSingleStep(5) self.bpm_slider.setValue(120) self.bpm_slider.setTickInterval(30) self.bpm_slider.setTickPosition(QSlider.TicksBelow) self.bpm_slider.valueChanged.connect(self.bpm_changed) self.horizontalLayout_2.addWidget(self.bpm_slider) self.actionClose.triggered.connect(exit) def transpose_up(self): pass #self.pitch = transposition.transpose_pitch(self.pitch, "1") def transpose_down(self): pass #self.pitch = transposition.transpose_pitch(self.pitch, "-1") def add_becko_to_file(self): # Get current text in music editor current_text = self.musicEdit.toPlainText() # Add znaminko to music editor new_text = current_text.rstrip() + "{ \flat }" + " " # Set new text in music editor self.musicEdit.setPlainText(new_text) def add_krizek_to_file(self): # Get current text in music editor current_text = self.musicEdit.toPlainText() # Add znaminko to music editor new_text = current_text.rstrip() + "{ \sharp }" + " " # Set new text in music editor self.musicEdit.setPlainText(new_text) def bpm_changed(slider_val, self): bpm = slider_val with open("test.ly", "r+") as file: data = file.read() file.seek(0) file.truncate() parameter = f"\\override Score.MetronomeMark #'stencil = ##f \\override Score.MetronomeMark #'break-visibility = ##(#f #f #f) \\tempo {bpm}" data = re.sub(r'\\override Score\.MetronomeMark #\'stencil = ##f \\override Score\.MetronomeMark #\'break-visibility = ##\(#f #f #f\) \\tempo \d+', parameter, data) file.write(data) def clef_changed(self): if self.alto_button.isChecked(): clef = 'alto' elif self.bass_button.isChecked(): clef = 'bass' else: clef = 'treble' with open("new_file.ly", "r") as f: code = f.read() # Replace the clef in the LilyPond code code = re.sub(r'\\clef\s+\w+', f'\\clef {clef}', code) # Write the modified LilyPond code to a new file with open("new_file.ly", "w") as f: f.write(code) def add_note_to_file(self, note): # Get current text in music editor current_text = self.musicEdit.toPlainText() # Add note to music editor new_text = current_text + note + " " # Set new text in music editor self.musicEdit.setPlainText(new_text) def create_new_file(self): with open("new_file.ly", "w") as f: f.write("\\version \"2.18.2\"\n\n") f.write(f'\\clef {self.clef}\n') f.write("\\header {\n") f.write("\ttitle = \"Untitled\"\n") f.write("}\n\n") f.write("\\score {\n") f.write("\t\\new Staff { }\n") f.write("\t\\layout { }\n") f.write("}\n") self.pitch = Pitch("c'") def change_title(self, new_title): new_title = self.lineEdit.text() with open("new_file.ly", "r") as f: code = f.read() # Replace the title in the LilyPond code code = re.sub("\ttitle = \"Untitled\"\n", f"\ttitle = \"{new_title}\"\n", code) # Write the modified LilyPond code to a new file with open("new_file.ly", "w") as f: f.write(code) def refresh_sheet(self): # Get current text in music editor current_text = self.musicEdit.toPlainText() # Create LilyPond file lilypond_file = LilyPondFile() lilypond_file.add_item(current_text) # Create PNG file png_filename = "sheet_music.png" lilypond_file.to_pdf(png_filename) # Load PNG file and display it in the graphics view pixmap = QPixmap(png_filename) self.graphicsView.setScene(QGraphicsScene(self)) self.graphicsView.scene().addPixmap(pixmap) self.graphicsView.fitInView(self.graphicsView.scene().sceneRect(), Qt.KeepAspectRatio) def saveFile(self): # Get filename from user filename, _ = QFileDialog.getSaveFileName(self, "Save Sheet Music", "", "Lilypond Files (*.ly)") if not filename: return # Create LilyPond file lilypond_file = LilyPondFile() lilypond_file.header_title = self.titleEdit.toPlainText() lilypond_file.add_item(self.musicEdit.toPlainText()) # Save LilyPond file with open(filename, 'w') as f: f.write(lilypond_file) def openFile(self): # Get filename from user filename, _ = QFileDialog.getOpenFileName(self, "Open Sheet Music", "", "Lilypond Files (*.ly)") if not filename: return # Load LilyPond file with open(filename, 'r') as f: lilypond_text = f.read() # Parse LilyPond file lilypond_file = LilyPondFile() lilypond_file.parse(lilypond_text) # Set widget values self.titleEdit.setPlainText(lilypond_file.header_title) self.musicEdit.setPlainText(lilypond_file.items()[0].to_lilypond()) if __name__ == '__main__': app = QApplication(sys.argv) editor = SheetMusicEditor() editor.show() sys.exit(app.exec_())