user12714126
user12714126

Reputation:

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'))

Upvotes: 2

Views: 4553

Answers (2)

Hao-Cher Hong
Hao-Cher Hong

Reputation: 230

You only create and display a volume state, so it should not affect your actual volume.

how do I override my computer's volume control?

Actually you can't, you can't manipulate your computer's volume. However, you can control the volume of sound played by your web page.

Here are two ways:

1. Use volume property of <audio>

By setting the volume of the DOM element before you play or in handleVolume function:

document.getElementById('audio-element-id').volume = this.state.volumeVal;

Many browser compatibility of this API is unknown, please check https://caniuse.com/#feat=mdn-html_elements_audio_volume

2. Use Web Audio API to play the audio

This is more complex but you get more controls.

Please check: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API

And by the way. The way you access your elements are not very React-ish. Consider using ref to access your actual elements:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.audioRef1 = React.createRef();
  }

  //...

  playAudio1() {
    this.audioRef1.current.play();
  }

  //...

  render() {
    return (
      //...
      <audio ref={this.audioRef1} />;
      //...
    );
  }
}

Upvotes: 2

obscure
obscure

Reputation: 12891

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();
};

Upvotes: 2

Related Questions