兔兔牌电脑乐器🪕

143 阅读2分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

本文技术栈:React + Antd

布局随便写的,主要是咱不是 UI,就随便整一点居中布局就行。

Button 按钮 + Select 下拉选择框

声音的播放

声音这块主要是通过 AudioContext 来实现的。

AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。在做任何其他操作之前,您需要创建一个AudioContext对象,因为所有事情都是在上下文中发生的。建议创建一个AudioContext对象并复用它,而不是每次初始化一个新的AudioContext对象,并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。

网上搜索钢琴 1234567 对应的频率为

[261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88]

吉他对应的频率为

[329.6276, 246.9417, 195.9977, 146.8324, 110.0000, 82.4069]

获取用户按下按钮对应的按键数字

useEffect(() => {
  document.addEventListener("keydown", (e) => {
    if (e.key.match(/^\+?[0-6]\d*$/)) {
      handleCreate(parseInt(e.key))
    }
  })
}, [])

handleCreate 是程序的主要处理函数,将获取的 index 传入该函数。

const handleCreate = (index) => {
  // 创建音频上下文
  const audioCtx = new AudioContext()
  // 创建音调控制对象  
  const oscillator = audioCtx.createOscillator();
  // 创建音量控制对象  
  const gainNode = audioCtx.createGain();
  // 音调音量关联
  oscillator.connect(gainNode);
  // 音量和设备关联
  gainNode.connect(audioCtx.destination);
  // 音调类型指定为正弦波  
  oscillator.type = audioTypeList[index.current];
  // 设置音调频率
  oscillator.frequency.value = audioDataList.current[index];
  // 先把当前音量设为0
  gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
  // 0.01秒时间内音量从刚刚的0变成1,线性变化
  gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
  // 声音走起 
  oscillator.start(audioCtx.currentTime);
  // 1秒时间内音量从刚刚的1变成0.001,指数变化
  gainNode.gain.exponentialRampToValueAtTime(0.1, audioCtx.currentTime + 1);
  // 1秒后停止声音
  oscillator.stop(audioCtx.currentTime + 1)
}

屏幕录音

这个主要通过 mediaDevices.getDisplayMedia 来实现。

MediaDevices.getUserMedia()  会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其它轨道类型。

MediaRecorder 是 MediaStream Recording API 提供的用来进行媒体轻松录制的接口,他需要通过调用 MediaRecorder() 构造方法进行实例化。

if (navigator.mediaDevices.getDisplayMedia) {
  let chunks = []
  const constraints = {
    audio: true
  }
  navigator.mediaDevices.getUserMedia(constraints).then(stream => {
    const mediaRecorder = new MediaRecorder(stream)
    mediaRecorderData.current = mediaRecorder
    mediaRecorder.ondataavailable = (e) => {
      chunks.push(e.data)
    }
    mediaRecorder.onstop = (e) => {
      const blob = new Blob(chunks, { type: "audio/mp4; codecs=opus" })
      chunks = []
      const audioURL = window.URL.createObjectURL(blob)
      player.current.src = audioURL
    }
  }, () => {
    alert('授权失败!')
  })
} else {
  alert('浏览器不支持 getUserMedia')
}

这样,点击录音,在键盘⌨️上面按住 0123456,就会发出声音。

参考文章:gitee.com/qxscj/js-de…