Search code examples
javascripthtmlreactjsrangevolume

React input range slider for volume isn't working


Hello fellow programmers, I am making a simple drum machine, and am trying to implement volume control, everything "works" and I don't get any errors, the slider slides, but for some reason the volume doesn't change, when I console.log the volumeVal and the display, they both change correctly, except, the volume on the page isn't affected, so maybe I'm asking how do I override my computer's volume control? please help geniuses of stackoverflow, here's my code:

class DrumMachine extends React.Component {
  constructor(props) {
    super(props)
        this.state = {
            power: false,
            volumeVal: 0.5,
            display: String.fromCharCode(160)
        }
        this.onKeyPress = this.onKeyPress.bind(this);
        this.powerButton = this.powerButton.bind(this);
        this.handleVolume = this.handleVolume.bind(this);
  };    
      componentDidMount() {
            document.addEventListener('keydown', this.onKeyPress)       
  }
      componentWillUnmount() {
            document.removeEventListener('keydown', this.onKeyPress)
  }

    onKeyPress(e) {
    if (e.keyCode === 86) { 
       document.getElementById('bassdrum').play();
             document.getElementById('bassdrum').currentTime = 0;
        }; 
        if (e.keyCode === 71) { 
       document.getElementById('hihat').play();
             document.getElementById('hihat').currentTime = 0;
        }; 
        if (e.keyCode === 88) { 
       document.getElementById('snaredrum').play();
             document.getElementById('snaredrum').currentTime = 0;
      }; 
        if (e.keyCode === 89) { 
       document.getElementById('tom1').play();
             document.getElementById('tom1').currentTime = 0;
        }; 
        if (e.keyCode === 85) { 
       document.getElementById('tom2').play();
             document.getElementById('tom2').currentTime = 0;
        };
        if (e.keyCode === 56) { 
       document.getElementById('crashcymbal').play();
             document.getElementById('crashcymbal').currentTime = 0; 
        };
    }

    powerButton() {
        if (this.state.power) {
            this.setState({ power: false })
        } else {
            this.setState({ power: true })
        }
    };

    handleVolume(e) {
        if (this.state.power) {
            this.setState({
                volumeVal: e.target.value,
                display: "Volume: " + Math.round(e.target.value * 100)
            });
      setTimeout(() => this.clearDisplay(), 1000);          
        }
    }

  clearDisplay() {
    this.setState({
      display: String.fromCharCode(160)
    });
  }

  render() {
        var buttonClass = ['power'];

        if (this.state.power) {
      buttonClass.push('On');
    } else {
            buttonClass.push('Off')
        }    

    return (
      <div id='container' className='container'>
                <div id='drumkeycontainer'>
                    <div className='row'>
                        <h6>ReactJS Drum Machine</h6>
                        <button className={buttonClass.join(' ')} onClick={this.powerButton}>Power</button>
                    </div>
                    <div className='row'>
            <div keyCode='86' className='key' onClick={() => {document.getElementById('bassdrum').play(); document.getElementById('bassdrum').currentTime = 0;}}>
                            <kbd><b>V</b></kbd>
                            <br />
                <span className='sound'>Bass Drum</span>
                </div>
                        <div keyCode='71' className='key' onClick={() => {document.getElementById('hihat').play(); document.getElementById('hihat').currentTime = 0;}}>
                            <kbd><b>G</b></kbd>
                            <br />
                            <span className='sound'>Hi-Hat</span>
                        </div>
                        <div keyCode='88' className='key' onClick={() => {document.getElementById('snaredrum').play(); document.getElementById('snaredrum').currentTime = 0;}}>
                            <kbd><b>X</b></kbd>
                            <br />
                            <span className='sound'>Snare</span>
                        </div>
                    </div>
                    <div className='row'>
                        <div keyCode='89' className='key' onClick={() => {document.getElementById('tom1').play(); document.getElementById('tom1').currentTime = 0;}}>
                            <kbd><b>Y</b></kbd>
                            <br />
                            <span className='sound'>Tom 1</span>
                        </div>
                        <div keyCode='85' className='key' onClick={() => {document.getElementById('tom2').play(); document.getElementById('tom2').currentTime = 0;}}>
                            <kbd><b>U</b></kbd>
                            <br />
                            <span className='sound'>Tom 2</span>
                        </div>
                        <div keyCode='56' className='key' onClick={() => {document.getElementById('crashcymbal').play(); document.getElementById('crashcymbal').currentTime = 0;}}>
                            <kbd><b>8</b></kbd>
                            <br />
                            <span className='sound'>Crash</span>
                        </div>                      
                    </div>
                    <div className='row'>
                        <div className='slider-wrapper'>
                            <label>Volume
                            <input type="range" min='0' max='1' value={this.state.volumeVal} onChange={this.handleVolume} step='0.01' />
                            </label>
                        </div>  
                    </div>
                </div>
                {/*links for audio elements obtained from www.findsounds.com */}
                {this.state.power && <div id='audiocontainer'>
                    <audio id='bassdrum' keyCode='86' src='https://www.myinstants.com/media/sounds/bass-drum.mp3'></audio>
                    <audio id='hihat' keyCode='71' src='http://dight310.byu.edu/media/audio/FreeLoops.com/1/1/Alchemist%20HiHat%203-1788-Free-Loops.com.mp3'></audio>
                    <audio id='snaredrum' keyCode='88' src='https://www.myinstants.com/media/sounds/snare.mp3'></audio>
                    <audio id='tom1' keyCode='89' src='http://www.denhaku.com/r_box/sr16/sr16tom/loelectm.wav'></audio>
                    <audio id='tom2' keyCode='85' src='http://dight310.byu.edu/media/audio/FreeLoops.com/1/1/909%20Tom%20Low%2001-5859-Free-Loops.com.mp3'></audio>
                    <audio id='crashcymbal' keyCode='56' src='http://dight310.byu.edu/media/audio/FreeLoops.com/1/1/AT%20B%20Crash-1026-Free-Loops.com.mp3'></audio>
                </div>}
      </div>
    );
  };
}

ReactDOM.render(<DrumMachine />, document.getElementById('app'))

Solution

  • Inside the state object you set up a key called volumeVal which stores a float ranging from 0 to 1, controllable using the slider.

    Unfortunately though you didn't use that value anywhere in your code except for the slider thus you don't hear a change in volume.

    The volume of a HTML <audio> element - which is what you're using for your individual sounds - can be controlled by it's .volume property. So all you have to do is assigning this property the value of this.state.volumeVal prior playback.

    For example the keyCode event for the hihat needs to be changed to this:

    if (e.keyCode === 71) {
         document.getElementById('hihat').volume=this.state.volumeVal;   
         document.getElementById('hihat').currentTime = 0;
         document.getElementById('hihat').play();
    };