Skip to content

Instantly share code, notes, and snippets.

@haseeb-heaven
Last active January 7, 2025 11:47
Show Gist options
  • Save haseeb-heaven/3aa86e25a6e3be9ff0b1d8a38f3c22d5 to your computer and use it in GitHub Desktop.
Save haseeb-heaven/3aa86e25a6e3be9ff0b1d8a38f3c22d5 to your computer and use it in GitHub Desktop.
Turn your keyboard to Piano using Python.

PyPiano

This Python program uses several libraries to generate and play sine wave tones based on keyboard input.

Libraries Used

  • io: This is a built-in Python library for handling streams of data. It's included with Python, so you don't need to install it separately.

  • pydub: This is a simple and easy-to-use library to manipulate audio files. It can be installed with pip using pip install pydub. It's used in this code to generate a sine wave tone and play it.

  • pynput: This library allows you to control and monitor input devices. It can be installed with pip using pip install pynput. In this code, it's used to listen for key presses and releases.

  • threading: This is a built-in Python library for running multiple threads of execution in your program. It's included with Python, so you don't need to install it separately. In this code, it's used to play the tone in a separate thread so that the program can continue listening for key presses.

Functionality

The program listens for key presses and releases. When a key is pressed, the program generates a sine wave tone corresponding to a piano note and plays it. The tone is played in a separate thread so that the program can continue listening for key presses.

import io
from pydub import AudioSegment
from pydub.generators import Sine
from pydub.playback import play
from pynput.keyboard import Key, Listener
import threading
from math import log2
# Function to generate a sine wave tone
def generate_tone(frequency, duration=500):
tone = Sine(frequency).to_audio_segment(duration=duration)
return tone
# Function to play the generated tone
def play_tone(tone):
try:
play(tone) # play the audio using pydub.playback.play
except Exception as error:
print(f"Error in playing tone: {error}")
# Mapping keyboard keys to piano notes (simplified)
key_to_note = {
'a': 261.63, # C4
'w': 277.18, # C#4/Db4
's': 293.66, # D4
'e': 311.13, # D#4/Eb4
'd': 329.63, # E4
'f': 349.23, # F4
't': 369.99, # F#4/Gb4
'g': 392.00, # G4
'y': 415.30, # G#4/Ab4
'h': 440.00, # A4
'u': 466.16, # A#4/Bb4
'j': 493.88, # B4
'k': 523.25, # C5
'o': 554.37, # C#5/Db5
'l': 587.33, # D5
'p': 622.25, # D#5/Eb5
';': 659.25, # E5
'\'': 698.46, # F5
']': 739.99, # F#5/Gb5
'\\': 783.99, # G5
'z': 830.61, # G#5/Ab5
'x': 880.00, # A5
'c': 932.33, # A#5/Bb5
'v': 987.77, # B5
'b': 1046.50, # C6
}
# Function to handle key press
def on_press(key):
try:
if hasattr(key, 'char') and key.char in key_to_note:
frequency = key_to_note[key.char]
tone = generate_tone(frequency)
threading.Thread(target=play_tone, args=(tone,)).start()
except Exception as error:
print(f"Error in key press handler: {error}")
# Function to handle key release
def on_release(key):
if key == Key.esc:
return False # Stop listener
# Main function to start the keyboard listener
def start_keyboard_piano():
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
def frequency_to_note(frequency):
note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
octave = 4
index = int(round(12 * log2(frequency / 440.0))) + 49
return note_names[index % 12] + str(octave + index // 12)
if __name__ == "__main__":
try:
print("Key Note")
sharp_keys = [key for key, frequency in key_to_note.items() if '#' in frequency_to_note(frequency)]
natural_keys = [key for key, frequency in key_to_note.items() if '#' not in frequency_to_note(frequency)]
print(' '.join([frequency_to_note(key_to_note[key]) for key in sharp_keys]))
print(' '.join([frequency_to_note(key_to_note[key]) for key in natural_keys]))
start_keyboard_piano()
except Exception as error:
print(f"Error in main function: {error}")
@jerzyorlowskimim
Copy link

Your code works nice with one tone, but with multiple tones played at the same time you get problems:

  1. The sound starts to buzz, there is something wrong with the sinusoids theselves
  2. There are long delays when pressing, releasing keys.

@haseeb-heaven
Copy link
Author

Your code works nice with one tone, but with multiple tones played at the same time you get problems:

  1. The sound starts to buzz, there is something wrong with the sinusoids theselves
  2. There are long delays when pressing, releasing keys.

Yes it can be improved further, it was just initial project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment