piano.gd 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. extends Control
  2. # A standard piano with 88 keys has keys from 21 to 108.
  3. # To get a different set of keys, modify these numbers.
  4. # A maximally extended 108-key piano goes from 12 to 119.
  5. # A 76-key piano goes from 23 to 98, 61-key from 36 to 96,
  6. # 49-key from 36 to 84, 37-key from 41 to 77, and 25-key
  7. # from 48 to 72. Middle C is pitch number 60, A440 is 69.
  8. const START_KEY = 21
  9. const END_KEY = 108
  10. const WhiteKeyScene = preload("res://piano_keys/white_piano_key.tscn")
  11. const BlackKeyScene = preload("res://piano_keys/black_piano_key.tscn")
  12. var piano_key_dict := Dictionary()
  13. @onready var white_keys = $WhiteKeys
  14. @onready var black_keys = $BlackKeys
  15. func _ready():
  16. # Sanity checks.
  17. if _is_note_index_sharp(_pitch_index_to_note_index(START_KEY)):
  18. printerr("The start key can't be a sharp note (limitation of this piano-generating algorithm). Try 21.")
  19. return
  20. for i in range(START_KEY, END_KEY + 1):
  21. piano_key_dict[i] = _create_piano_key(i)
  22. if white_keys.get_child_count() != black_keys.get_child_count():
  23. _add_placeholder_key(black_keys)
  24. OS.open_midi_inputs()
  25. print(OS.get_connected_midi_inputs())
  26. func _input(input_event):
  27. if not (input_event is InputEventMIDI):
  28. return
  29. var midi_event: InputEventMIDI = input_event
  30. if midi_event.pitch < START_KEY or midi_event.pitch > END_KEY:
  31. # The given pitch isn't on the on-screen keyboard, so return.
  32. return
  33. _print_midi_info(midi_event)
  34. var key: PianoKey = piano_key_dict[midi_event.pitch]
  35. if midi_event.message == MIDI_MESSAGE_NOTE_ON:
  36. key.activate()
  37. else:
  38. key.deactivate()
  39. func _add_placeholder_key(container):
  40. var placeholder = Control.new()
  41. placeholder.size_flags_horizontal = SIZE_EXPAND_FILL
  42. placeholder.mouse_filter = Control.MOUSE_FILTER_IGNORE
  43. placeholder.name = &"Placeholder"
  44. container.add_child(placeholder)
  45. func _create_piano_key(pitch_index):
  46. var note_index = _pitch_index_to_note_index(pitch_index)
  47. var piano_key: PianoKey
  48. if _is_note_index_sharp(note_index):
  49. piano_key = BlackKeyScene.instantiate()
  50. black_keys.add_child(piano_key)
  51. else:
  52. piano_key = WhiteKeyScene.instantiate()
  53. white_keys.add_child(piano_key)
  54. if _is_note_index_lacking_sharp(note_index):
  55. _add_placeholder_key(black_keys)
  56. piano_key.setup(pitch_index)
  57. return piano_key
  58. func _is_note_index_lacking_sharp(note_index: int):
  59. # B and E, because no B# or E#
  60. return note_index in [2, 7]
  61. func _is_note_index_sharp(note_index: int):
  62. # A#, C#, D#, F#, and G#
  63. return note_index in [1, 4, 6, 9, 11]
  64. func _pitch_index_to_note_index(pitch: int):
  65. pitch += 3
  66. return pitch % 12
  67. func _print_midi_info(midi_event: InputEventMIDI):
  68. print(midi_event)
  69. print("Channel: " + str(midi_event.channel))
  70. print("Message: " + str(midi_event.message))
  71. print("Pitch: " + str(midi_event.pitch))
  72. print("Velocity: " + str(midi_event.velocity))
  73. print("Instrument: " + str(midi_event.instrument))
  74. print("Pressure: " + str(midi_event.pressure))
  75. print("Controller number: " + str(midi_event.controller_number))
  76. print("Controller value: " + str(midi_event.controller_value))