2022-07-28 来源:华纳网 责任编辑:Sunny 人气:
核心提示:大家好,欢迎来到谷雨课堂

本课内容:

大家好,欢迎来到谷雨课堂

本节我们继续进阶,
我们来实现实时的检测音乐的音符,
根据十二平均律,
每个音符都对应一个振动的频率,

 
那么根据前几天我们获得到的频谱数据,
稍加过滤就知道当前声音主要的音符了,
当然,本节也没有实际泛音等情况,
更强大的功能,
欢迎同学们一起去探索
 
主要源代码如下:
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
const Application = function() {this.initA4()this.tuner = new Tuner(this.a4)this.notes = new Notes('.notes', this.tuner)this.meter = new Meter('.meter')this.frequencyBars = new FrequencyBars('.frequency-bars')this.update({ name: 'A', frequency: this.a4, octave: 4, value: 69, cents: 0 })}
Application.prototype.initA4 = function () {this.$a4 = document.querySelector('.a4 span')this.a4 = parseInt(localStorage.getItem('a4')) || 440this.$a4.innerHTML = this.a4}
Application.prototype.start = function() {const self = this
this.tuner.onNoteDetected = function(note) {if (self.notes.isAutoMode) {if (self.lastNote === note.name) {        self.update(note)      } else {        self.lastNote = note.name      }    }  }
  swal.fire('Welcome online tuner!').then(function() {    self.tuner.init()    self.frequencyData = new Uint8Array(self.tuner.analyser.frequencyBinCount)  })
this.$a4.addEventListener('click', function () {    swal.fire({input: 'number',inputValue: self.a4,    }).then(function ({ value: a4 }) {if (!parseInt(a4) || a4 === self.a4) {return      }      self.a4 = a4      self.$a4.innerHTML = a4      self.tuner.middleA = a4      self.notes.createNotes()      self.update({ name: 'A', frequency: self.a4, octave: 4, value: 69, cents: 0 })      localStorage.setItem('a4', a4)    })  })
this.updateFrequencyBars()}
Application.prototype.updateFrequencyBars = function() {if (this.tuner.analyser) {this.tuner.analyser.getByteFrequencyData(this.frequencyData)this.frequencyBars.update(this.frequencyData)  }  requestAnimationFrame(this.updateFrequencyBars.bind(this))}
Application.prototype.update = function(note) {this.notes.update(note)this.meter.update((note.cents / 50) * 45)}
// noinspection JSUnusedGlobalSymbolsApplication.prototype.toggleAutoMode = function() {this.notes.toggleAutoMode()}
const app = new Application()app.start()
 
 
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
const Tuner = function(a4{this.middleA = a4 || 440this.semitone = 69this.bufferSize = 4096this.noteStrings = ['C','C♯','D','D♯','E','F','F♯','G','G♯','A','A♯','B'  ]
this.initGetUserMedia()}
Tuner.prototype.initGetUserMedia = function() {window.AudioContext = window.AudioContext || window.webkitAudioContextif (!window.AudioContext) {return alert('AudioContext not supported')  }
// Older browsers might not implement mediaDevices at all, so we set an empty object firstif (navigator.mediaDevices === undefined) {    navigator.mediaDevices = {}  }
// Some browsers partially implement mediaDevices. We can't just assign an object// with getUserMedia as it would overwrite existing properties.// Here, we will just add the getUserMedia property if it's missing.if (navigator.mediaDevices.getUserMedia === undefined) {    navigator.mediaDevices.getUserMedia = function(constraints) {// First get ahold of the legacy getUserMedia, if presentconst getUserMedia =        navigator.webkitGetUserMedia || navigator.mozGetUserMedia
// Some browsers just don't implement it - return a rejected promise with an error// to keep a consistent interfaceif (!getUserMedia) {        alert('getUserMedia is not implemented in this browser')      }
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promisereturn new Promise(function(resolve, reject) {        getUserMedia.call(navigator, constraints, resolve, reject)      })    }  }}
Tuner.prototype.startRecord = function () {const self = this  navigator.mediaDevices    .getUserMedia({ audio: true })    .then(function(stream) {      self.audioContext.createMediaStreamSource(stream).connect(self.analyser)      self.analyser.connect(self.scriptProcessor)      self.scriptProcessor.connect(self.audioContext.destination)      self.scriptProcessor.addEventListener('audioprocess', function(event) {const frequency = self.pitchDetector.do(          event.inputBuffer.getChannelData(0)        )if (frequency && self.onNoteDetected) {const note = self.getNote(frequency)          self.onNoteDetected({name: self.noteStrings[note % 12],value: note,cents: self.getCents(frequency, note),octave: parseInt(note / 12) - 1,frequency: frequency          })        }      })    })    .catch(function(error) {      alert(error.name + ': ' + error.message)    })}
Tuner.prototype.init = function() {this.audioContext = new window.AudioContext()this.analyser = this.audioContext.createAnalyser()this.scriptProcessor = this.audioContext.createScriptProcessor(this.bufferSize,1,1  )
const self = this
  aubio().then(function(aubio) {    self.pitchDetector = new aubio.Pitch('default',      self.bufferSize,1,      self.audioContext.sampleRate    )    self.startRecord()  })}
/** * get musical note from frequency * * @param {number} frequency * @returns {number} */Tuner.prototype.getNote = function(frequency) {const note = 12 * (Math.log(frequency / this.middleA) / Math.log(2))return Math.round(note) + this.semitone}
/** * get the musical note's standard frequency * * @param note * @returns {number} */Tuner.prototype.getStandardFrequency = function(note) {return this.middleA * Math.pow(2, (note - this.semitone) / 12)}
/** * get cents difference between given frequency and musical note's standard frequency * * @param {number} frequency * @param {number} note * @returns {number} */Tuner.prototype.getCents = function(frequency, note) {return Math.floor(    (1200 * Math.log(frequency / this.getStandardFrequency(note))) / Math.log(2)  )}
/** * play the musical note * * @param {number} frequency */Tuner.prototype.play = function(frequency) {if (!this.oscillator) {this.oscillator = this.audioContext.createOscillator()this.oscillator.connect(this.audioContext.destination)this.oscillator.start()  }this.oscillator.frequency.value = frequency}
Tuner.prototype.stop = function() {this.oscillator.stop()this.oscillator = null}

 

 

完整的源代码可以登录【华纳网】下载。

https://www.worldwarner.com/






 

 





免责声明:本文仅代表作者个人观点,与华纳网无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。