钢琴模拟器

news2025/7/13 19:09:42

在这里插入图片描述
在这里插入图片描述

文章目录

    • 钢琴模拟器
        • 代码结构
            • HTML结构
            • CSS样式
            • JavaScript功能
        • 源码
        • 效果图

钢琴模拟器

代码结构
HTML结构

<html>: HTML文档的根元素。
<head>: 包含文档的元数据。
<base>: 指定相对URL的基准。
<title>: 指定页面的标题。
<style>: 包含嵌入的CSS样式。
<body>: 包含文档的内容。
<div class=“container”>: 容器元素,包含主要内容。
<div class=“controls”>: 控件区域,包含选择框、按钮和移调控制。
<select id=“instrument-select”>: 乐器选择框。
<button id=“record”>: 录音按钮。
<button id=“play”>: 播放按钮。
<button id=“stop”>: 停止按钮。
<div class=“transpose-controls”>: 移调控制区域。
<button id=“transpose-down”>: 移调降低按钮。
<input type=“text” id=“transpose-value” readonly>: 显示当前移调值。
<button id=“transpose-up”>: 移调升高按钮。
<div id=“current-instrument”>: 当前乐器显示区域。
<div id=“keyboard”>: 键盘区域。
<div id=“chord-pads”>: 和弦按钮区域。
<div id=“loading”>: 加载提示。

CSS样式

body, html: 设置页面的基本样式。
.container: 设置容器的样式。
.controls: 设置控件区域的样式。
select, button, input: 设置选择框、按钮和输入框的样式。
#instrument-select: 设置乐器选择框的样式。
#current-instrument, #transpose-value: 设置当前乐器和移调值的样式。
.transpose-controls: 设置移调控制区域的样式。
#keyboard: 设置键盘区域的样式。
.key: 设置键的样式。
.key.black: 设置黑键的样式。
#loading: 设置加载提示的样式。
#chord-pads: 设置和弦按钮区域的样式。
.chord-pad: 设置和弦按钮的样式。

JavaScript功能

时钟更新:
updateClock: 更新时钟的时间和日期。
setInterval(updateClock, 1000): 每秒更新一次时钟。
updateClock(): 初次加载时立即更新时钟。
点击事件:
监听乐器选择框、录音按钮、播放按钮和停止按钮的点击事件。
根据点击的元素执行相应的操作(如录音、播放、停止等)。
键盘功能:
createKeyboard: 创建键盘。
createChordPads: 创建和弦按钮。
loadSoundFonts: 加载SoundFont。
loadSoundFont: 加载指定的SoundFont。
transposeNote: 移调音符。
playNote: 播放音符。
releaseNote: 释放音符。
playChord: 播放和弦。
releaseChord: 释放和弦。
startRecording: 开始录音。
stopRecording: 停止录音。
playRecording: 播放录音。
stopPlayback: 停止播放。
updateTransposeDisplay: 更新移调显示。

源码
<html><head><base href="https://websim.ai/app/soundfont-keyboard"/><title>SoundFont Keyboard: Interactive Musical Experience with Chords</title>
<style>
  body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    font-family: 'Arial', sans-serif;
    background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
    color: #fff;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
  }
  .container {
    background: rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    padding: 30px;
    box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.18);
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 20px;
  }
  .controls {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    margin-bottom: 20px;
  }
  select, button, input {
    margin: 5px;
    padding: 10px 15px;
    font-size: 14px;
    background-color: rgba(255, 255, 255, 0.2);
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
  }
  select:hover, button:hover {
    background-color: rgba(255, 255, 255, 0.3);
  }
  #instrument-select {
    width: 200px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url('data:image/svg+xml;utf8,<svg fill="%23ffffff" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
    background-repeat: no-repeat;
    background-position-x: 95%;
    background-position-y: 50%;
  }
  #instrument-select option {
    background-color: #2a2a2a;
    color: #fff;
  }
  #current-instrument, #transpose-value {
    margin-top: 10px;
    font-style: italic;
  }
  .transpose-controls {
    display: flex;
    align-items: center;
    margin-top: 10px;
  }
  .transpose-controls button {
    width: 30px;
    height: 30px;
    padding: 0;
    font-size: 18px;
    line-height: 1;
  }
  #transpose-value {
    margin: 0 10px;
    width: 40px;
    text-align: center;
    background-color: rgba(255, 255, 255, 0.1);
  }
  #keyboard {
    display: flex;
    justify-content: center;
    background: linear-gradient(to bottom, #4a4a4a, #2a2a2a);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);
  }
  .key {
    width: 40px;
    height: 150px;
    background-color: #f0f0f0;
    border: 1px solid #000;
    margin: 0 2px;
    cursor: pointer;
    border-radius: 0 0 5px 5px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    transition: background-color 0.1s ease;
  }
  .key.black {
    width: 30px;
    height: 100px;
    background-color: #000;
    margin-left: -15px;
    margin-right: -15px;
    z-index: 1;
  }
  .key:active, .key.active {
    background-color: #ddd;
  }
  .key.black:active, .key.black.active {
    background-color: #333;
  }
  #loading {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 24px;
    background: rgba(0, 0, 0, 0.7);
    padding: 20px;
    border-radius: 10px;
    z-index: 20;
  }
  #chord-pads {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    max-width: 600px;
    margin-top: 20px;
  }
  .chord-pad {
    width: 60px;
    height: 60px;
    margin: 5px;
    font-size: 16px;
    font-weight: bold;
    background-color: rgba(255, 255, 255, 0.2);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    transition: background-color 0.3s ease, transform 0.1s ease;
  }
  .chord-pad:hover {
    background-color: rgba(255, 255, 255, 0.3);
  }
  .chord-pad:active {
    transform: scale(0.95);
  }
</style>
</head>
<body>
  <div class="container">
    <div class="controls">
      <select id="instrument-select">
        <option value="">Select an instrument...</option>
      </select>
      <button id="record">Record</button>
      <button id="play">Play</button>
      <button id="stop">Stop</button>
      <div class="transpose-controls">
        <button id="transpose-down">-</button>
        <input type="text" id="transpose-value" value="0" readonly>
        <button id="transpose-up">+</button>
      </div>
    </div>
    <div id="current-instrument"></div>
    <div id="keyboard"></div>
  </div>
  <div id="chord-pads"></div>
  <div id="loading">Loading SoundFonts...</div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js"></script>

  <script>
    const keys = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
    const keyMapping = {
      'z': 'C3', 's': 'C#3', 'x': 'D3', 'd': 'D#3', 'c': 'E3', 'v': 'F3', 'g': 'F#3',
      'b': 'G3', 'h': 'G#3', 'n': 'A3', 'j': 'A#3', 'm': 'B3',
      'q': 'C4', '2': 'C#4', 'w': 'D4', '3': 'D#4', 'e': 'E4', 'r': 'F4', '5': 'F#4',
      't': 'G4', '6': 'G#4', 'y': 'A4', '7': 'A#4', 'u': 'B4',
      'i': 'C5', '9': 'C#5', 'o': 'D5', '0': 'D#5', 'p': 'E5', '[': 'F5', '=': 'F#5',
      ']': 'G5'
    };
    const octaves = 3;
    let currentInstrument = 'acoustic_grand_piano';
    let soundFont;
    let recording = false;
    let recordedNotes = [];
    let startTime;
    let playbackTimeouts = [];
    let transposeValue = 0;

    const pressedKeys = new Set();

    const chords = {
      'E': ['E4', 'G#4', 'B4'],
      'A': ['A3', 'C#4', 'E4'],
      'F': ['F3', 'A3', 'C4'],
      'D': ['D4', 'F#4', 'A4'],
      'G': ['G3', 'B3', 'D4'],
      'C': ['C4', 'E4', 'G4'],
      'B': ['B3', 'D#4', 'F#4'],
      'Em': ['E4', 'G4', 'B4'],
      'Am': ['A3', 'C4', 'E4'],
      'Dm': ['D4', 'F4', 'A4'],
      'Bm': ['B3', 'D4', 'F#4'],
      'Cm': ['C4', 'D#4', 'G4'],
      'Fm': ['F3', 'G#3', 'C4'],
      'E7': ['E4', 'G#4', 'B4', 'D5'],
      'A7': ['A3', 'C#4', 'E4', 'G4'],
      'D7': ['D4', 'F#4', 'A4', 'C5'],
      'G7': ['G3', 'B3', 'D4', 'F4'],
      'C7': ['C4', 'E4', 'G4', 'A#4']
    };

    function createKeyboard() {
      const keyboard = document.getElementById('keyboard');
      for (let octave = 3; octave < 3 + octaves; octave++) {
        keys.forEach((note) => {
          const key = document.createElement('div');
          key.className = `key ${note.includes('#') ? 'black' : 'white'}`;
          key.dataset.note = `${note}${octave}`;
          key.addEventListener('mousedown', () => playNote(`${note}${octave}`));
          key.addEventListener('mouseup', () => releaseNote(`${note}${octave}`));
          key.addEventListener('mouseleave', () => releaseNote(`${note}${octave}`));
          keyboard.appendChild(key);
        });
      }
    }

    function createChordPads() {
      const chordPads = document.getElementById('chord-pads');
      Object.keys(chords).forEach(chordName => {
        const pad = document.createElement('button');
        pad.className = 'chord-pad';
        pad.textContent = chordName;
        pad.addEventListener('mousedown', () => playChord(chordName));
        pad.addEventListener('mouseup', () => releaseChord(chordName));
        pad.addEventListener('mouseleave', () => releaseChord(chordName));
        chordPads.appendChild(pad);
      });
    }

    createKeyboard();
    createChordPads();

    async function loadSoundFonts() {
      const response = await fetch('https://gleitz.github.io/midi-js-soundfonts/MusyngKite/names.json');
      const instruments = await response.json();
      const select = document.getElementById('instrument-select');
      instruments.forEach(instrument => {
        const option = document.createElement('option');
        option.value = instrument;
        option.textContent = instrument.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
        select.appendChild(option);
      });
      loadSoundFont('acoustic_grand_piano');
    }

    async function loadSoundFont(instrument) {
      document.getElementById('loading').style.display = 'block';
      currentInstrument = instrument;
      const response = await fetch(`https://gleitz.github.io/midi-js-soundfonts/MusyngKite/${instrument}-mp3.js`);
      const soundFontData = await response.text();
      eval(soundFontData);
      soundFont = MIDI.Soundfont[instrument];
      document.getElementById('loading').style.display = 'none';
      document.getElementById('current-instrument').textContent = `Current Instrument: ${instrument.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}`;
    }

    function transposeNote(note) {
      const [noteName, octave] = [note.slice(0, -1), parseInt(note.slice(-1))];
      let noteIndex = keys.indexOf(noteName);
      noteIndex += transposeValue;

      let newOctave = octave + Math.floor(noteIndex / 12);
      noteIndex = (noteIndex + 12) % 12; // Ensure positive index

      return `${keys[noteIndex]}${newOctave}`;
    }

    function playNote(note) {
      if (!soundFont) return;
      
      const transposedNote = transposeNote(note);
      let sound = new Howl({
        src: [soundFont[transposedNote]],
        format: ['mp3']
      });
      
      sound.play();
      
      if (recording) {
        const time = Date.now() - startTime;
        recordedNotes.push({ note, time });
      }

      // Highlight the key
      const key = document.querySelector(`.key[data-note="${note}"]`);
      if (key) {
        key.classList.add('active');
      }
    }

    function releaseNote(note) {
      // Remove highlight from the key
      const key = document.querySelector(`.key[data-note="${note}"]`);
      if (key) {
        key.classList.remove('active');
      }
    }

    function playChord(chordName) {
      if (!soundFont) return;
      
      chords[chordName].forEach(note => {
        playNote(note);
      });

      if (recording) {
        const time = Date.now() - startTime;
        recordedNotes.push({ chord: chordName, time });
      }
    }

    function releaseChord(chordName) {
      chords[chordName].forEach(note => {
        releaseNote(note);
      });
    }

    function startRecording() {
      recording = true;
      recordedNotes = [];
      startTime = Date.now();
      document.getElementById('record').textContent = 'Stop Recording';
    }

    function stopRecording() {
      recording = false;
      document.getElementById('record').textContent = 'Record';
    }

    function playRecording() {
      if (recordedNotes.length === 0) return;
      stopPlayback(); // Stop any ongoing playback
      const playbackStartTime = Date.now();
      recordedNotes.forEach(({ note, chord, time }) => {
        const timeout = setTimeout(() => {
          if (note) {
            playNote(note);
            setTimeout(() => releaseNote(note), 200);
          } else if (chord) {
            playChord(chord);
            setTimeout(() => releaseChord(chord), 200);
          }
        }, time);
        playbackTimeouts.push(timeout);
      });
    }

    function stopPlayback() {
      // Clear all scheduled playback timeouts
      playbackTimeouts.forEach(timeout => clearTimeout(timeout));
      playbackTimeouts = [];
""
      
      // Stop all currently playing sounds
      Howler.stop();
      
      // Reset all key colors
      document.querySelectorAll('.key').forEach(key => {
        key.classList.remove('active');
      });
    }

    function updateTransposeDisplay() {
      const transposeInput = document.getElementById('transpose-value');
      transposeInput.value = transposeValue >= 0 ? `+${transposeValue}` : transposeValue;
    }

    loadSoundFonts();

    document.getElementById('instrument-select').addEventListener('change', (e) => loadSoundFont(e.target.value));
    document.getElementById('record').addEventListener('click', () => {
      if (recording) {
        stopRecording();
      } else {
        startRecording();
      }
    });
    document.getElementById('play').addEventListener('click', playRecording);
    document.getElementById('stop').addEventListener('click', stopPlayback);

    document.getElementById('transpose-down').addEventListener('click', () => {
      transposeValue = Math.max(transposeValue - 1, -12);
      updateTransposeDisplay();
    });

    document.getElementById('transpose-up').addEventListener('click', () => {
      transposeValue = Math.min(transposeValue + 1, 12);
      updateTransposeDisplay();
    });

    window.addEventListener('keydown', (e) => {
      const note = keyMapping[e.key.toLowerCase()];
      if (note && !pressedKeys.has(note)) {
        pressedKeys.add(note);
        playNote(note);
      }
    });

    window.addEventListener('keyup', (e) => {
      const note = keyMapping[e.key.toLowerCase()];
      if (note) {
        pressedKeys.delete(note);
        releaseNote(note);
      }
    });

    // Initialize transpose display
    updateTransposeDisplay();
  </script>
</body></html>
效果图

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1960223.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于用log提高排查问题的设置

今天在了解项目业务的时候&#xff0c;想搞清楚执行顺序&#xff0c;加了很多打印&#xff0c;类似console.log(1111,xxxx) console.log(2222,xxxx)&#xff0c;有时候断点没开sourcemap不是源码所以我更喜欢打印&#xff0c;然后就导致打印比较紊乱&#xff0c;而且前面的1111…

sql截取时间数据方法函数之截取时间的年月

sql截取时间数据方法函数之截取时间的年月 方法一&#xff1a;DATE_FORMAT() 函数 select trans_date,date_format(trans_date,%Y-%m) month from Transactions;方法二&#xff1a;left(str, length)函数 #从左边开始截取 select trans_date,left(trans_date, 7) month fro…

中国高新科技杂志中国高新科技杂志社中国高新科技编辑部2024年第10期目录

科研达人 互联网领域资深工程师陈晔 技术引领 创新赋能 以IT技术推动行业转型升级 宋丽君; 5-6 中国科学院过程工程研究所副研究员武春晓 助跑科研“马拉松”共圆创新中国梦 周玮 ;杨烁; 7-8 中国科学院大学资源与环境学院副教授蔡晓琳 生物治理重金属 土壤焕发新生…

「安当产品应用案例100集」004-国密UKEY增强软件授权安全

国密UKEY在软件授权方案中的应用主要体现在增强软件授权的安全性、实现更严格的访问控制以及满足特定行业或领域的安全要求等方面。以下是安当的客户在软件授权方面的应用案例概述。 一、安当UKEY软件授权案例 国密UKEY&#xff0c;即采用国家密码管理局认证的密码算法的USB安全…

Spring源码解析(25)之AOP的BeanDefinitiion准备

一、AOP代码准备 aop.xml文件准备&#xff0c;代码如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance…

【轻松拿捏】Java-List、Set、Map 之间的区别是什么?

List、Set、Map 之间的区别是什么&#xff1f; 一、List 二、Set 三、Map &#x1f388;边走、边悟&#x1f388;迟早会好 一、List 有序性&#xff1a;List 保持元素的插入顺序&#xff0c;即元素按添加的顺序存储和访问。允许重复&#xff1a;List 可以包含重复的元素。…

docker compose 安装 kafka

一 前置准备 创建 /data/kafkadata /data/zookeeper-1用于保存kafka和zookeeper的配置文件 kafkadata中创建三个文件夹 /kafka1 /kafka2 /kafka3&#xff0c;用于存放三个kafka节点的配置文件 zookeeper-1文件夹中创建 /conf /data /logs /datalog四个文件夹&#xff0c;用于…

AI时代,让文献主动找上门——揭开文本和数据挖掘的变革性力量

文本和数据挖掘&#xff08;text and data mining, TDM&#xff09;使用计算工具和技术来分析大型文本数据集&#xff0c;从学术论文、期刊和其他科学出版物中的大量科学数据里提取有价值的见解&#xff0c;旨在识别通过传统人工分析难以或无法发现的模式、关联和趋势&#xff…

计算机网络HTTP全讲解,让你透彻掌握HTTP协议(三)http长短连接/代理/网关/缓存/内容协商机制/断点续传

HTTP HTTP的长连接与短连接短链接长链接HTTP代理代理的作用HTTP网关web网关常见的网关类型HTTP缓存HTTP缓存头部字段HTTP缓存工作方式缓存改进方案cdn缓存工作方式浏览器操作对http缓存的影响HTTP内容协商机制客户端驱动服务器驱动请求首部集近似匹配透明协商断点续传和多线程下…

类和对象的深入了解4

1.析构函数 1.1析构函数概念 与构造函数功能相反&#xff0c;析构函数不是完成对对象本身的销毁&#xff0c;局部对象销毁工作是由编译器完成 的。而对象在销毁时会自动调用析构函数&#xff0c;完成对象中资源的清理工作。它的名字与类名相同&#xff0c;前面加上一个波浪号…

LLM大模型:十大人工智能大模型技术介绍

十大人工智能大模型技术的简介&#xff1a; 深度学习模型 深度学习是人工智能领域中一种重要的机器学习技术&#xff0c;通过构建深度神经网络来模拟人脑的认知过程。深度学习模型能够自动提取数据的特征&#xff0c;并在海量数据中进行学习和优化&#xff0c;从而在语音识别…

79.WEB渗透测试-信息收集-框架组件识别利用(3)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;78.WEB渗透测试-信息收集-框架组件识别利用&#xff08;2&#xff09;-CSDN博客 struts2…

长面板数据实证模型及 Stata 具体操作步骤

目录 一、文献综述 二、理论原理 三、实证模型 四、稳健性检验 五、程序代码及解释 六、代码运行结果 一、文献综述 长面板数据在经济学、金融学、社会学等领域的研究中得到了广泛应用。许多学者通过构建长面板数据模型来研究各种经济现象和社会问题。例如&#xff0c;在研…

乌班图下的vscode粘贴代码后一直在输入CTRLV命令

最近在VMware中使用vscode开发c程序中&#xff0c;拷贝一段代码后&#xff0c;代码界面一直输入CTRLV命令&#xff0c;导致乌班图桌面死掉&#xff0c;无法操作、 解决方法&#xff1a; 1、强制重启。长按电源按钮强制关机&#xff0c;然后再次开机。 2、使用命令行界面。同时…

电测量数据交换DLMS_COSEM组件第47部分:基于IP网络的DLMS_COSEM传输层

1.范围 本部分规定了面向无连接和连接的在IP网络中所使用的DLMS/COSEM通信协议集的传输层(TL)。 这些传输层为用户DLMS/COSEM的应用层提供OSI式服务。面向无连接的传输层基于互联网标准用户数据报协议(UDP)。面向连接的传输层基于互联网标准传输控制协议(TCP)。 DLMS/CO…

C++:map和set

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;map和set》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xff01;…

redis的代码开发

redis是什么? 前提:官网地址https://redis.io 1.Redis是一个开源的,key,value格式的,内存型数据结构存储系统;它可用作数据库、缓存和消息中间件。 value支持多种类型的数据结构如strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglo…

亚马逊测评自养号有什么优势?

在当今竞争激烈的电商市场中&#xff0c;若想实现销量的显著增长&#xff0c;测评策略已成为不可或缺的一环&#xff0c;尤其是对于新入驻平台的店铺及推出的创新产品而言&#xff0c;仅凭初期的自然流量难以迅速脱颖而出&#xff0c;因此众多跨境卖家纷纷采用测评手段&#xf…

微信小程序教程002:代码结构介绍和新建小程序页面

文章目录 代码介绍1、小程序代码构成2、小程序页面组成部分3、JSON配置文件的作用3.1 app.json文件3.2 project.config.json文件3.3 sitemap.json文件3.4 页面的.json文件新建小程序页面WXML和WXSS介绍1、什么是WXML2、什么是WXSS小程序的JS文件1、JS文件2、小程序中JS文件分类…

【机器学习】探索图神经网络 (GNNs): 揭秘图结构数据处理的未来

&#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ ​ &#x1f48e;1. 引言 图结构数据在现实世界中无处不在&#xff0c;从社交网络中的用户关系&#xff0c;到推荐系统中的用户-物品交互&#xff0c;再到生物信息学中的分子结构。传统的机器学习模型在处理这些数据时常常力…