Python语言beep简谱播放器程序代码QZQ


#pip install pygame
#pip install numpy


import pygame
import numpy as np
from collections import deque
from pygame.locals import QUIT, KEYDOWN, K_RETURN, MOUSEBUTTONDOWN
import threading

# 初始化pygame
pygame.init()
pygame.mixer.init()

# 窗口设置
WIDTH, HEIGHT = 800, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("数字音符播放器")

# 颜色定义(略,与原代码一致)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
GREEN = (0, 200, 80)
BLUE = (50, 150, 250)

# 字体设置(略,与原代码一致)
font = pygame.font.Font(None, 36)
small_font = pygame.font.Font(None, 24)

# 修正后的音符频率映射(支持多字符键名,音区划分清晰)
NOTE_FREQS = {
    # 低音区(键名以 . 结尾,如1. 表示低音1)
    '1.': 261.63 / 2,  # 低音1(C3)
    '2.': 293.66 / 2,  # 低音2(D3)
    '3.': 329.63 / 2,  # 低音3(E3)
    '4.': 349.23 / 2,  # 低音4(F3)
    '5.': 392.00 / 2,  # 低音5(G3)
    '6.': 440.00 / 2,  # 低音6(A3)
    '7.': 493.88 / 2,  # 低音7(B3)

    # 中音区(默认无后缀,如1 表示中音1)
    '1': 261.63,  # 中音1(C4)
    '2': 293.66,  # 中音2(D4)
    '3': 329.63,  # 中音3(E4)
    '4': 349.23,  # 中音4(F4)
    '5': 392.00,  # 中音5(G4)
    '6': 440.00,  # 中音6(A4)
    '7': 493.88,  # 中音7(B4)

    # 高音区(键名以 * 结尾,如1* 表示高音1)
    '1*': 261.63 * 2,  # 高音1(C5)
    '2*': 293.66 * 2,  # 高音2(D5)
    '3*': 329.63 * 2,  # 高音3(E5)
    '4*': 349.23 * 2,  # 高音4(F5)
    '5*': 392.00 * 2,  # 高音5(G5)
    '6*': 440.00 * 2,  # 高音6(A5)
    '7*': 493.88 * 2,  # 高音7(B5)

    '-': 0,  # 休止符(用 - 表示更清晰)
}

# 界面元素位置(略,与原代码一致)
INPUT_RECT = pygame.Rect(50, 50, 800, 200)
BUTTON_RECT = pygame.Rect(150, 130, 200, 60)
input_text = "6.3.6.3212--1-6.2116.5.---1-6.53322----1-6.2116.5.----5.-6.1--1-6.12---1-6.2116.5.---1--6.53322----1-6.2116.5.----5.-6.1--1-6.12--1-6.2116.1---1--6.53322--1-6.2116.5.----5.-6.1--1-6.12--1-6.2116.5.---1--6.53322----1-6.2116.5.----5.-6.1--1-6.12--1-6.2116.1---3353124321-5.6.1235-561*7654543453--217126.7.15.---1--6.53322--1-6.2116.5.---5.-6.1--1-6.12---1-6.2116.5.---1-6.53322----1-6.2116.5.----5.-6.1--1-6.12--1-6.2116.1------"  # 测试输入:低音1-3 → 中音1-3 → 高音1-3
play_queue = deque()
is_playing = False
input_box_active = False


# 播放音符函数(修正振幅限制)
def play_note(freq, duration=0.3):
    if freq == 0:
        pygame.time.wait(int(duration * 1000))
        return
    sample_rate = 44100
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    wave = np.sin(2 * np.pi * freq * t) * 32767  # 限制振幅在[-32767, 32767]
    stereo_wave = np.column_stack((wave, wave)).astype(np.int16)  # 直接生成int16类型
    sound = pygame.sndarray.make_sound(stereo_wave)
    sound.play()
    pygame.time.wait(int(duration * 1000))


# 解析输入文本(支持多字符键名,如'1.'、'1*')
def parse_input(text):
    queue = deque()
    i = 0
    while i < len(text):
        char = text[i]
        # 检查当前字符是否为数字,且后续有 . 或 *(处理多字符键名)
        if char in '1234567' and i + 1 < len(text) and text[i + 1] in ('.', '*'):
            key = text[i:i + 2]
            i += 2
        else:
            key = char  # 单字符(如休止符'-')
            i += 1
        queue.append(NOTE_FREQS.get(key, 0))  # 匹配频率,默认休止符
    return queue


# 播放线程(略,与原代码一致)
def play_thread():
    global is_playing
    is_playing = True
    try:
        while play_queue and is_playing:
            freq = play_queue.popleft()
            play_note(freq)
    except Exception as e:
        print(f"播放错误: {e}")
    finally:
        is_playing = False


# 绘制函数(略,与原代码一致)
def draw_input_box():
    pygame.draw.rect(screen, GRAY if input_box_active else WHITE, INPUT_RECT, 2)
    text_surface = font.render(input_text, True, BLACK)
    screen.blit(text_surface, (INPUT_RECT.x + 10, INPUT_RECT.y + 10))


def draw_play_button():
    color = BLUE if is_playing else GREEN
    pygame.draw.rect(screen, color, BUTTON_RECT, 0)
    pygame.draw.rect(screen, BLACK, BUTTON_RECT, 2)
    text_surface = font.render("播放音符", True, BLACK)
    screen.blit(text_surface, (BUTTON_RECT.x + 30, BUTTON_RECT.y + 10))


# 主循环
running = True
while running:
    screen.fill(WHITE)
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        if event.type == MOUSEBUTTONDOWN:
            # 鼠标点击处理(缩进保持一致)
            if BUTTON_RECT.collidepoint(event.pos):
                play_queue = parse_input(input_text)
                if play_queue:
                    threading.Thread(target=play_thread, daemon=True).start()
            elif INPUT_RECT.collidepoint(event.pos):
                input_box_active = True
            else:
                input_box_active = False
        if event.type == KEYDOWN:  # 修正后的缩进,与鼠标事件同级
            if input_box_active:  # 内层判断,缩进4空格
                if event.key == K_RETURN:
                    play_queue = parse_input(input_text)
                    if play_queue:
                        threading.Thread(target=play_thread, daemon=True).start()
                elif event.key == pygame.K_BACKSPACE:
                    input_text = input_text[:-1]
                else:
                    char = event.unicode
                    if char in '1234567.-*' and len(input_text) < 50:
                        input_text += char
    # 绘制界面元素(缩进与for循环同级)
    draw_input_box()
    draw_play_button()
    text_surface = small_font.render("输入格式:低音1. 中音1 高音1*,-=休止符,最多50位", True, BLACK)
    screen.blit(text_surface, (150, 710))
    pygame.display.flip()
    pygame.time.Clock().tick(30)

pygame.quit()




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

EasySoft易软

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

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

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

打赏作者

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

抵扣说明:

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

余额充值