Python实现简易小钢琴

本文介绍了使用Python的Tkinter和winsound库以及pygame和numpy库实现的简易小钢琴,包括基本原理、代码示例和两者之间的区别,强调了Tkinter实现的简洁性与pygame在音质和交互上的优势。
摘要由CSDN通过智能技术生成

Python实现简易小钢琴

使用Python实现的简单小钢琴,给出了两种实现。

实现一

使用Python和内带的Tkinter库、winsound 模块实现的简单小钢琴。

Tkinter库和winsound模块不需要额外安装就可以使用,因为它们是Python的标准库之一,已经随着Python的安装包一起提供。标准库是Python官方提供的一组核心模块和工具,它们被视为Python语言的一部分,因此在安装Python解释器时就会自动包含这些标准库。

Tkinter库是Python的标准图形用户界面(GUI)工具包,它提供了创建和管理GUI应用程序所需的组件和功能。Tkinter基于Tcl/Tk工具包,是Python内置的库,因此无需额外安装。

winsound模块是Python的标准库之一,用于在Windows操作系统中播放声音。它提供了简单的接口,它提供了一些用于控制Windows系统声音的函数,比如播放声音、发出蜂鸣声等,可以用于播放系统提供的声音文件或者自定义的声音。

我对乐理了解几乎为零,相关音高(pitch)可以参考这里https://www.autopiano.cn/toolbox/pitch

以下是一个使用Python和内带的Tkinter库、winsound 模块实现的简单钢琴程序的源码:

import tkinter as tk
import winsound  # 注意:winsound 模块只在 Windows 上可用

# 定义一个播放声音的函数
def play_sound(frequency):
    winsound.Beep(frequency, 500)  # 播放500毫秒的声音

# 创建主窗口
root = tk.Tk()
root.title("The Little Piano")

# 定义音符和对应的频率
notes = {
    'a': 261,
    's': 294,
    'd': 329,
    'f': 349,
    'g': 392,
    'h': 440,
    'j': 494,
    'k': 523
}

# 创建一个函数来生成钢琴键
def create_key(note):
    def on_click(e=None):
        play_sound(notes[note])
        # 按下键的视觉反馈
        button.config(relief=tk.SUNKEN)
        button.after(100, lambda: button.config(relief=tk.RAISED))
    
    button = tk.Button(root, text=note, width=5, height=5, command=on_click)
    button.pack(side=tk.LEFT, padx=5, pady=5)
    root.bind(note.lower(), on_click)  # 绑定按键事件

# 为每个音符创建一个钢琴键
for note in notes:
    create_key(note)

# 启动Tkinter事件循环
root.mainloop()

运行效果如下:

你可以用英文状态下按下琴键上的字符,或用鼠标单击琴键试试了。

需要注意的是,用Tkinter库、winsound 模块实现小钢琴只能实现基本功能,由于其局限性,音质较差,要实现鼠标滑动时连续播放音符的效果等是很困难的。可能更适合使用如 Pygame库来实现,见下面的实现。

实现二

下面示例假设你已经安装了pygame和numpy库。如果还没有安装,请先使用pip install pygame numpy进行安装。源码如下:

import pygame
import numpy as np

# 初始化pygame
pygame.init()

# 创建窗口
screen = pygame.display.set_mode((640, 240))
pygame.display.set_caption("简易钢琴")

# 设置颜色
white = (255, 255, 255)
black = (0, 0, 0)
gray = (200, 200, 200)

# 初始化字体模块
pygame.font.init()
font = pygame.font.Font(None, 36)

# 音符频率映射
notes = {
    'A': 261.63,
    'S': 293.66,
    'D': 329.63,
    'F': 349.23,
    'G': 392.00,
    'H': 440.00,
    'J': 493.88,
    'K': 523.25
}

# 键盘按键到音符的映射
key_to_note = {
    pygame.K_a: 'A',
    pygame.K_s: 'S',
    pygame.K_d: 'D',
    pygame.K_f: 'F',
    pygame.K_g: 'G',
    pygame.K_h: 'H',
    pygame.K_j: 'J',
    pygame.K_k: 'K'
}

# 音符是否被按下
note_pressed = {note: False for note in notes}

def play_sound(frequency):
    duration = 1  # 持续时间为1秒
    sample_rate = 44100  # 采样率
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    wave = np.sin(2 * np.pi * frequency * t)
    # 确保数组是C-连续的
    sound_array = np.ascontiguousarray(np.array([32767 * wave, 32767 * wave]).T.astype(np.int16))
    sound = pygame.sndarray.make_sound(sound_array)
    sound.play()

def draw_piano_keys():
    for i, note in enumerate(notes):
        x = i * 80
        y = 100
        width = 79
        height = 100
        color = gray if note_pressed[note] else black
        pygame.draw.rect(screen, color, pygame.Rect(x, y, width, height))
        text_surface = font.render(note, True, white)
        screen.blit(text_surface, (x + (width - text_surface.get_width()) / 2, y + (height - text_surface.get_height()) / 2))

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key in key_to_note:
                note = key_to_note[event.key]
                note_pressed[note] = True
                play_sound(notes[note])
        elif event.type == pygame.KEYUP:
            if event.key in key_to_note:
                note = key_to_note[event.key]
                note_pressed[note] = False
        elif event.type == pygame.MOUSEBUTTONDOWN or (event.type == pygame.MOUSEMOTION and pygame.mouse.get_pressed()[0]):
            x, y = pygame.mouse.get_pos()
            if 100 <= y <= 200:
                key_index = x // 80
                if 0 <= key_index < len(notes):
                    note = list(notes.keys())[key_index]
                    if not note_pressed[note]:  # 防止重复播放
                        note_pressed[note] = True
                        play_sound(notes[note])
        elif event.type == pygame.MOUSEBUTTONUP:
            for note in note_pressed:
                note_pressed[note] = False

    screen.fill(white)
    draw_piano_keys()
    pygame.display.flip()

pygame.quit()

运行效果如下:

你可以用英文状态下按下琴键上的字符,或用鼠标单击琴键试试了,效果好些了,你可以继续改进。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值