I am trying to make a simple synthesizer with React and the Web Audio API and having trouble with some methods. Here is my code:
import * as React from "react"
class Synth extends React.Component {
constructor(props) {
super(props);
this.state = {value: 0.5};
this.handleChange = this.handleChange.bind(this);
this.setup = this.setup.bind(this);
this.createKey = this.createKey.bind(this);
this.componentDidMount = this.componentDidMount.bind(this);
this.audioContext = null;
this.oscList = [];
this.mainGainNode = null;
this.wavePicker = document.querySelector("select[name='waveform']");
this.volumeControl = document.querySelector("input[name='volume']");
this.noteFreq = null;
this.customWaveform = null;
this.sineTerms = null;
this.cosineTerms = null;
}
componentDidMount(){
this.setup();
}
handleChange(event) {
this.setState({
value: event.target.value
});
}
createNoteTable(){
let noteFreq = [];
for (let i=0; i< 9; i++) {
noteFreq[i] = [];
}
noteFreq[3]["C"] = 130.81;
noteFreq[3]["C#"] = 138.59;
noteFreq[3]["D"] = 146.83;
noteFreq[3]["D#"] = 155.56;
noteFreq[3]["E"] = 164.81;
noteFreq[3]["F"] = 174.61;
noteFreq[3]["F#"] = 185.00;
noteFreq[3]["G"] = 196.00;
noteFreq[3]["G#"] = 207.65;
//etc...
return noteFreq;
}
createKey(note, octave, freq){
console.log("createKey() is firing");
let keyElement = document.createElement("li");
switch (freq) {
case 130.81:
keyElement.className = "white c1"
break;
case 146.83:
keyElement.className = "black cs1"
break;
case 164.81:
keyElement.className = "white c1"
break;
case 174.61:
keyElement.className = "white d1"
break;
//etc...
default:
break;
}
keyElement.dataset["freq"] = freq;
keyElement.dataset["note"] = note;
keyElement.dataset["octave"] = octave;
keyElement.addEventListener("mousedown", this.notePressed, false);
keyElement.addEventListener("mouseup", this.noteReleased, false);
keyElement.addEventListener("mouseover", this.notePressed, false);
keyElement.addEventListener("mouseleave", this.noteReleased, false);
return keyElement;
}
setup(){
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.noteFreq = this.createNoteTable();
this.mainGainNode = this.audioContext.createGain();
this.mainGainNode.connect(this.audioContext.destination);
this.mainGainNode.gain.value = this.state.value;
this.noteFreq.forEach(function(keys, idx) {
let keyList = Object.entries(keys);
let octaveElem = document.createElement("div");
keyList.forEach(function(key){
console.log("key[0] = " + key[0]);
console.log("idx = " + idx);
console.log("key[1] = " + key[1]);
try {
octaveElem.appendChild(this.createKey(key[0], idx, key[1]));
} catch(error){
console.log("Cannot create key... " + error);
}
});
});
this.sineTerms = new Float32Array([0, 0, 1, 0, 1]);
this.cosineTerms = new Float32Array(this.sineTerms.length);
this.customWaveform = this.audioContext.createPeriodicWave(this.cosineTerms, this.sineTerms);
for (let i=0; i<9; i++) {
this.oscList[i] = {};
}
}
then I have the notePressed() and noteReleased() functions but these seem to work fine.
The problem is when this.createKey() is called I get this error : TypeError: Cannot read properties of undefined (reading 'createKey')
As you can see, I tried binding pretty much every method I have to see if it would help but it didn't. Any help will be greatly appreciated.