main_m.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import sys
  2. import os
  3. sys.path.append('/home/lida/Downloads/lilypond-2.24.1/python')
  4. from PyQt5.QtWidgets import *
  5. from PyQt5.QtCore import Qt, QThread, pyqtSignal
  6. from PyQt5.QtGui import QPixmap
  7. from PyQt5 import uic
  8. import keyboard
  9. from ly import *
  10. #import ly.document
  11. #import ly.cli.command
  12. #import ly.cli.main
  13. from ly.pitch import transpose
  14. from ly.pitch.transpose import ModalTransposer
  15. from abjad import LilyPondFile, Note
  16. from abjad.parsers import parse
  17. from abjad.pitch import NamedPitch
  18. import re
  19. class SheetMusicEditor(QDialog):
  20. class KeyboardListener(QThread):
  21. note_added = pyqtSignal(str)
  22. def __init__(self, parent=None):
  23. super().__init__(parent=parent)
  24. self.key_to_note = {
  25. "c": NamedPitch("c'"),
  26. "d": NamedPitch("d'"),
  27. "e": NamedPitch("e'"),
  28. "f": NamedPitch("f'"),
  29. "g": NamedPitch("g'"),
  30. "a": NamedPitch("a'"),
  31. "b": NamedPitch("b'"),
  32. }
  33. def run(self):
  34. while True:
  35. key = keyboard.read_event().name
  36. if key in self.key_to_note:
  37. note = Note.from_pitch(self.key_to_note[key])
  38. self.note_added.emit(note.to_lilypond() + "")
  39. def __init__(self):
  40. super(SheetMusicEditor, self).__init__()
  41. #uic.loadUi("qtdesigner_zkouska.ui", self)
  42. uic.loadUi(os.path.normpath(os.path.join(__file__, "..", "qtdesigner_zkouska.ui")), self)
  43. self.keyboard_listener = self.KeyboardListener()
  44. self.keyboard_listener.note_added.connect(self.add_note_to_file)
  45. self.keyboard_listener.start()
  46. self.show()
  47. self.pushButton.clicked.connect(self.transpose_up)
  48. self.pushButton_2.clicked.connect(self.transpose_down)
  49. self.krizek_button.clicked.connect(self.add_krizek_to_file)
  50. self.becko_button.clicked.connect(self.add_becko_to_file)
  51. self.treble_button.setChecked(True)
  52. self.treble_button.toggled.connect(self.clef_changed)
  53. self.alto_button.toggled.connect(self.clef_changed)
  54. self.bass_button.toggled.connect(self.clef_changed)
  55. #self.pushButton_3.clicked.connect(self.make_big)
  56. #self.pushButton_4.clicked.connect(self.make_small)
  57. self.save_button.clicked.connect(self.saveFile)
  58. self.openFile_button.clicked.connect(self.openFile)
  59. self.new_file_button.clicked.connect(self.create_new_file)
  60. self.c_button.clicked.connect(lambda: self.add_note_to_file("c'"))
  61. self.d_button.clicked.connect(lambda: self.add_note_to_file("d'"))
  62. self.e_button.clicked.connect(lambda: self.add_note_to_file("e'"))
  63. self.f_button.clicked.connect(lambda: self.add_note_to_file("f'"))
  64. self.g_button.clicked.connect(lambda: self.add_note_to_file("g'"))
  65. self.a_button.clicked.connect(lambda: self.add_note_to_file("a'"))
  66. self.b_button.clicked.connect(lambda: self.add_note_to_file("b'"))
  67. #self.lineEdit(self.change_title)
  68. line_edit = QLineEdit()
  69. line_edit.textChanged.connect(lambda text: change_title(title=text))
  70. #tady takové divné, ten první a třetí řádek spolu neinteragují hezky
  71. self.refresh_button.clicked.connect(self.refresh_sheet)
  72. self.bpm_slider = QSlider(Qt.Horizontal)
  73. self.bpm_slider.setMinimum(1)
  74. self.bpm_slider.setMaximum(10000)
  75. self.bpm_slider.setSingleStep(5)
  76. self.bpm_slider.setValue(120)
  77. self.bpm_slider.setTickInterval(30)
  78. self.bpm_slider.setTickPosition(QSlider.TicksBelow)
  79. self.bpm_slider.valueChanged.connect(self.bpm_changed)
  80. #self.horizontalLayout_2.addWidget(self.bpm_slider)
  81. #self.actionClose.triggered.connect(exit)
  82. def transpose_up(self):
  83. with open("new_file.ly", "r") as f:
  84. code = f.read
  85. #transponitko = ModalTransposer(7, 0)
  86. tonina = ModalTransposer.getKeyIndex(f)
  87. transpose(tonina)
  88. with open("new_file.ly", "r") as f:
  89. f.write(code)
  90. #self.pitch = transpose.transpose_pitch(self.pitch, "1")
  91. def transpose_down(self):
  92. pass
  93. #self.pitch = transpose.transpose_pitch(self.pitch, "-1")
  94. def add_becko_to_file(self):
  95. with open("new_file.ly", "r") as f:
  96. code = f.read()
  97. # Get current text in music editor
  98. current_text = self.musicEdit.toPlainText()
  99. # Add znaminko to music editor
  100. new_text = current_text.rstrip() + "{ \\flat }" + " "
  101. # Set new text in music editor
  102. self.musicEdit.setPlainText(new_text)
  103. def add_krizek_to_file(self):
  104. # Get current text in music editor
  105. current_text = self.musicEdit.toPlainText()
  106. # Add znaminko to music editor
  107. new_text = current_text.rstrip() + "{ \sharp }" + " "
  108. # Set new text in music editor
  109. self.musicEdit.setPlainText(new_text)
  110. def bpm_changed(slider_val, self):
  111. bpm = slider_val
  112. with open("new_file.ly", "r+") as file:
  113. data = file.read()
  114. file.seek(0)
  115. file.truncate()
  116. parameter = f"\\override Score.MetronomeMark #'stencil = ##f \\override Score.MetronomeMark #'break-visibility = ##(#f #f #f) \\tempo {bpm}"
  117. data = re.sub(r'\\override Score\.MetronomeMark #\'stencil = ##f \\override Score\.MetronomeMark #\'break-visibility = ##\(#f #f #f\) \\tempo \d+', parameter, data)
  118. file.write(data)
  119. def clef_changed(self):
  120. if self.alto_button.isChecked():
  121. clef = 'alto'
  122. elif self.bass_button.isChecked():
  123. clef = 'bass'
  124. else:
  125. clef = 'treble'
  126. with open("new_file.ly", "r") as f:
  127. code = f.read()
  128. # Replace the clef in the LilyPond code
  129. code = re.sub(r'\\clef\s+\w+', f'\\clef {clef}', code)
  130. # Write the modified LilyPond code to a new file
  131. with open("new_file.ly", "w") as f:
  132. f.write(code)
  133. def add_note_to_file(self, note):
  134. with open("new_file.ly", "r") as f:
  135. code = f.read()
  136. # Get current text in music editor
  137. # Add note to music editor - v pohodě, protože value tý noty potom dostane v argumetu
  138. #ale nefunguje
  139. new_text = code + note + " "
  140. # Set new text in music editor
  141. with open("new_file.ly", "w") as f:
  142. f.write(new_text)
  143. def create_new_file(self):
  144. with open("new_file.ly", "w") as f:
  145. f.write("\\version \"2.18.2\"\n\n")
  146. f.write(f"\\clef {self.clef}\n")
  147. f.write("\\header {\n")
  148. f.write("\ttitle = \"Untitled\"\n")
  149. f.write("}\n\n")
  150. f.write("\\score {\n")
  151. f.write("\t\\new Staff { }\n")
  152. f.write("\t\\layout { }\n")
  153. f.write("}\n")
  154. #self.pitch = Pitch("c'")
  155. def change_title(self, new_title):
  156. new_title = self.lineEdit.text()
  157. with open("new_file.ly", "r") as f:
  158. code = f.read()
  159. # Replace the title in the LilyPond code
  160. code = re.sub("\ttitle = \"Untitled\"\n", f"\ttitle = \"{new_title}\"\n", code)
  161. # Write the modified LilyPond code to a new file
  162. with open("new_file.ly", "w") as f:
  163. f.write(code)
  164. def refresh_sheet(self):
  165. # Get current text in music editor
  166. current_text = self.musicEdit.toPlainText()
  167. # Create LilyPond file
  168. lilypond_file = LilyPondFile()
  169. lilypond_file.add_item(current_text)
  170. # Create PNG file
  171. png_filename = "sheet_music.png"
  172. lilypond_file.to_pdf(png_filename)
  173. #tohle hodně sus
  174. # Load PNG file and display it in the graphics view
  175. pixmap = QPixmap(png_filename)
  176. self.graphicsView.setScene(QGraphicsView(self))
  177. self.graphicsView.scene().addPixmap(pixmap)
  178. self.graphicsView.fitInView(self.graphicsView.scene().sceneRect())
  179. def saveFile(self):
  180. # Get filename from user
  181. filename, _ = QFileDialog.getSaveFileName(self, "Save Sheet Music", "", "Lilypond Files (*.ly)")
  182. if not filename:
  183. return
  184. # Create LilyPond file
  185. lilypond_file = LilyPondFile()
  186. lilypond_file.header_title = self.titleEdit.toPlainText()
  187. lilypond_file.add_item(self.musicEdit.toPlainText())
  188. # Save LilyPond file
  189. with open(filename, 'w') as f:
  190. f.write(lilypond_file)
  191. def openFile(self):
  192. # Get filename from user
  193. filename, _ = QFileDialog.getOpenFileName(self, "Open Sheet Music", "", "Lilypond Files (*.ly)")
  194. if not filename:
  195. return
  196. # Load LilyPond file
  197. with open(filename, 'r') as f:
  198. lilypond_text = f.read()
  199. # Parse LilyPond file
  200. lilypond_file = LilyPondFile()
  201. lilypond_file = parse.parse(lilypond_text)
  202. # Set widget values
  203. self.titleEdit.setPlainText(lilypond_text.header_title)
  204. self.musicEdit.setPlainText(lilypond_text.items()[0].to_lilypond())
  205. if __name__ == '__main__':
  206. app = QApplication(sys.argv)
  207. editor = SheetMusicEditor()
  208. editor.show()
  209. sys.exit(app.exec())