|
|
@@ -1,17 +1,235 @@
|
|
|
+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 *
|
|
|
+from ly import transposition
|
|
|
+from abjad import *
|
|
|
+
|
|
|
+class SheetMusicEditor(QMainWindow):
|
|
|
+ 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() + "")
|
|
|
|
|
|
-class qtdesigner_zkouska(QDialog):
|
|
|
-
|
|
|
def __init__(self):
|
|
|
- super(qtdesigner_zkouska, self).__init__()
|
|
|
+ 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):
|
|
|
+ self.pitch = transposition.transpose_pitch(self.pitch, "1")
|
|
|
+
|
|
|
+ def transpose_down(self):
|
|
|
+ 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
|
|
|
+ lilypond_format = LilyPondFormat()
|
|
|
+ with open(filename, 'w') as f:
|
|
|
+ f.write(lilypond_format(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)
|
|
|
|
|
|
-def main():
|
|
|
- app = QApplication([])
|
|
|
- window = qtdesigner_zkouska()
|
|
|
- app.exec_()
|
|
|
+ # Set widget values
|
|
|
+ self.titleEdit.setPlainText(lilypond_file.header_title)
|
|
|
+ self.musicEdit.setPlainText(lilypond_file.items()[0].to_lilypond())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
- main()
|
|
|
+ app = QApplication(sys.argv)
|
|
|
+ editor = SheetMusicEditor()
|
|
|
+ editor.show()
|
|
|
+ sys.exit(app.exec_())
|