ebiten 学习(13)-piano, 9白键7黑键

2021SC@SDUSC


一、前言

1.说明

audio 说明文档地址

audio package - github.com/hajimehoshi/ebiten/v2/audio - pkg.go.dev

本文中所有截图和代码均来自说明文档或 ebiten 源文件

笔者负责 audio 音频相关的代码分析

2.梗概

解析 examples 包下的 piano 中的例子。
手动生成钢琴音色。


二、界面以及音乐效果

界面包含A - L 9个白键,音调递增,还有7个黑键。
右上角是帧数。

按压键盘对应按键,会有钢琴声音播放。

在这里插入图片描述

三、实现

1.画面实现

一个 main 方法前可以有多个 init 初始化方法,这个初始化方法是用来限制文字大小和格式。

在这里插入图片描述

这里规定了窗口大小、采样频率、基频。

在这里插入图片描述

这里创建一张和窗口大小相当的图片,然后构造这个静态图片。

在这里插入图片描述

展示。

在这里插入图片描述

2.钢琴声音生成**

钢琴的声音是手动模拟生成的。

首先是三个变量,分别是钢琴按键与音频流对应关系、状态码、通讯队列。

在这里插入图片描述

然后键盘值。
和上面 pianoNoteSamples 一一对应。

在这里插入图片描述

pianoAt 生成给定频率的第 i 个钢琴音频样本。
用多个正弦波模拟钢琴的波。

在这里插入图片描述

toBytes 返回具有给定左/右序列的 2ch 小端16位字节序列。

在这里插入图片描述

初始化钢琴数据。
通过上述几个方法,填充 pianoNoteSamples。

在这里插入图片描述

3.game

在这里插入图片描述

4.出声逻辑

首先初始化数据,然后循环检测按键,在 pianoNoteSamples 中索引对应音频。

在这里插入图片描述

然后根据字节流创建播放器播放。
playNote 以给定的频率播放钢琴声音。
在这里插入图片描述

5.main

没有变化。
在这里插入图片描述

好的,以下是一个简单的网页钢琴代码,包括8个白键和5个黑键,鼠标点击键有声音,具有录制模式和回放功能,回放功能下可播放录制模式录下来的声音: HTML代码: ``` <!DOCTYPE html> <html> <head> <title>网页钢琴</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div class="piano"> <div class="white-key" id="C"></div> <div class="black-key" id="C-sharp"></div> <div class="white-key" id="D"></div> <div class="black-key" id="D-sharp"></div> <div class="white-key" id="E"></div> <div class="white-key" id="F"></div> <div class="black-key" id="F-sharp"></div> <div class="white-key" id="G"></div> <div class="black-key" id="G-sharp"></div> <div class="white-key" id="A"></div> <div class="black-key" id="A-sharp"></div> <div class="white-key" id="B"></div> </div> <div class="controls"> <button id="record">录制</button> <button id="play">播放</button> </div> <audio id="C-note" src="C.mp3"></audio> <audio id="C-sharp-note" src="C-sharp.mp3"></audio> <audio id="D-note" src="D.mp3"></audio> <audio id="D-sharp-note" src="D-sharp.mp3"></audio> <audio id="E-note" src="E.mp3"></audio> <audio id="F-note" src="F.mp3"></audio> <audio id="F-sharp-note" src="F-sharp.mp3"></audio> <audio id="G-note" src="G.mp3"></audio> <audio id="G-sharp-note" src="G-sharp.mp3"></audio> <audio id="A-note" src="A.mp3"></audio> <audio id="A-sharp-note" src="A-sharp.mp3"></audio> <audio id="B-note" src="B.mp3"></audio> <script src="script.js"></script> </body> </html> ``` CSS代码: ``` body { background-color: #f2f2f2; } .piano { display: flex; justify-content: center; align-items: flex-end; height: 400px; } .white-key { width: 50px; height: 200px; background-color: white; border: 1px solid black; border-radius: 5px 5px 0 0; margin-right: -1px; position: relative; } .black-key { width: 30px; height: 120px; background-color: black; border: 1px solid black; border-radius: 5px 5px 0 0; margin-right: -15px; position: relative; z-index: 1; } #C-sharp, #D-sharp, #F-sharp, #G-sharp, #A-sharp { margin-left: -15px; } .controls { display: flex; justify-content: center; margin-top: 20px; } button { margin: 0 10px; padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #3e8e41; } button:active { background-color: #3e8e41; box-shadow: 0 5px #666; transform: translateY(4px); } button:focus { outline: none; } button:disabled { background-color: #cccccc; color: #666666; cursor: not-allowed; } button:disabled:hover { background-color: #cccccc; } audio { display: none; } ``` JS代码: ``` var keys = document.querySelectorAll('.white-key, .black-key'); var recordButton = document.getElementById('record'); var playButton = document.getElementById('play'); var recordedNotes = []; var playbackIndex = 0; var isRecording = false; var isPlayingBack = false; keys.forEach(function(key) { key.addEventListener('mousedown', function() { playSound(key.id); if (isRecording) { recordedNotes.push(key.id); } }); }); recordButton.addEventListener('click', function() { if (!isRecording) { recordedNotes = []; isRecording = true; recordButton.innerHTML = '停止录制'; playButton.disabled = true; } else { isRecording = false; recordButton.innerHTML = '录制'; playButton.disabled = false; } }); playButton.addEventListener('click', function() { if (!isPlayingBack) { isPlayingBack = true; playButton.innerHTML = '停止播放'; recordButton.disabled = true; playbackIndex = 0; playbackInterval = setInterval(function() { if (playbackIndex < recordedNotes.length) { playSound(recordedNotes[playbackIndex]); playbackIndex++; } else { isPlayingBack = false; playButton.innerHTML = '播放'; recordButton.disabled = false; clearInterval(playbackInterval); } }, 500); } else { isPlayingBack = false; playButton.innerHTML = '播放'; recordButton.disabled = false; clearInterval(playbackInterval); } }); function playSound(id) { var note = document.getElementById(id + '-note'); note.currentTime = 0; note.play(); } ``` 注意:以上代码只是一个简单的示例,实际应用中可能需要更多的功能和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值