Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!-- App -->
<div id="app" class="my-5 text-center"></div>

<!-- Explanation -->
<div class="container mb-5">
  <p class="lead font-italic">
    View this app's source on
    <a
      href="https://github.com/tywmick/drum-machine"
      target="_blank"
      rel="noopener"
      >GitHub</a
    >
    or
    <a
      href="https://codepen.io/tywmick/pen/zYOaPyW"
      target="_blank"
      rel="noopener"
      >CodePen</a
    >.
  </p>

  <h1>Drum machine</h1>

  <p>
    Not pretty, but the design's functional. The application logic is the fun
    part, anyway, and it's where my talents are better directed.
  </p>

  <p>
    I created this app as a requirement for
    <a
      href="https://www.freecodecamp.org/certification/tywmick/front-end-libraries"
      target="_blank"
      rel="noopener"
      >my freeCodeCamp Front End Libraries Certification</a
    >, using
    <a href="https://reactjs.org/" target="_blank" rel="noopener">React</a>,
    <a href="https://getbootstrap.com/" target="_blank" rel="noopener"
      >Bootstrap</a
    >, and
    <a
      href="https://codepen.io/freeCodeCamp/pen/MJyNMd?editors=0010"
      target="_blank"
      rel="noopener"
      >freeCodeCamp's drum sounds</a
    >. It fulfills the following user stories:
  </p>

  <ol>
    <li>
      I should be able to see an outer container with a corresponding
      <code>id="drum-machine"</code> that contains all other elements.
    </li>
    <li>
      Within <code>#drum-machine</code> I can see an element with a
      corresponding <code>id="display"</code>.
    </li>
    <li>
      Within <code>#drum-machine</code> I can see 9 clickable drum pad elements,
      each with a class name of <code>drum-pad</code>, a unique id that
      describes the audio clip the drum pad will be set up to trigger, and an
      inner text that corresponds to one of the following keys on the keyboard:
      Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order.
    </li>
    <li>
      Within each <code>.drum-pad</code>, there should be an HTML5
      <code>audio</code> element which has a <code>src</code> attribute pointing
      to an audio clip, a class name of <code>clip</code>, and an id
      corresponding to the inner text of its parent <code>.drum-pad</code> (e.g.
      <code>id="Q"</code>, <code>id="W"</code>, <code>id="E"</code> etc.).
    </li>
    <li>
      When I click on a <code>.drum-pad</code> element, the audio clip contained
      in its child <code>audio</code> element should be triggered.
    </li>
    <li>
      When I press the trigger key associated with each <code>.drum-pad</code>,
      the audio clip contained in its child <code>audio</code> element should be
      triggered (e.g. pressing the Q key should trigger the drum pad which
      contains the string "Q", pressing the W key should trigger the drum pad
      which contains the string "W", etc.).
    </li>
    <li>
      When a <code>.drum-pad</code> is triggered, a string describing the
      associated audio clip is displayed as the inner text of the
      <code>#display</code> element (each string must be unique).
    </li>
  </ol>
</div>

              
            
!

CSS

              
                body {
  background-color: #dee2e6;
}

button {
  width: 3.5rem
}

#display {
  width: 11rem;
}

              
            
!

JS

              
                // Drum machine wrapper
class DrumMachine extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lastDrum: ""
    };
    this.updateDisplay = this.updateDisplay.bind(this);
  }

  // Update display from drum press
  updateDisplay(msg) {
    this.setState({
      lastDrum: msg
    });
  }

  // 3x3 set of drum pads, display below
  render() {
    return (
      <div id="drum-machine" className="d-inline-block">
        <div className="mb-1">
          <Drum
            keyb="Q"
            name="Chord 1"
            fileName="Chord_1.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="W"
            name="Chord 2"
            fileName="Chord_2.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="E"
            name="Chord 3"
            fileName="Chord_3.mp3"
            display={this.updateDisplay}
          />
        </div>
        <div className="mb-1">
          <Drum
            keyb="A"
            name="Shaker"
            fileName="Give_us_a_light.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="S"
            name="Open HH"
            fileName="Dry_Ohh.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="D"
            name="Closed HH"
            fileName="Bld_H1.mp3"
            display={this.updateDisplay}
          />
        </div>
        <div className="mb-2">
          <Drum
            keyb="Z"
            name="Punchy Kick"
            fileName="punchy_kick_1.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="X"
            name="Side Stick"
            fileName="side_stick_1.mp3"
            display={this.updateDisplay}
          />
          <Drum
            keyb="C"
            name="Snare"
            fileName="Brk_Snr.mp3"
            display={this.updateDisplay}
          />
        </div>
        <Display msg={this.state.lastDrum} />
      </div>
    );
  }
}

// Individual drum button and audio clip
class Drum extends React.Component {
  constructor(props) {
    super(props);
    this.state = { active: false };
    this.playDrum = this.playDrum.bind(this);
    this.componentDidMount = this.componentDidMount.bind(this);
    this.componentWillUnmount = this.componentWillUnmount.bind(this);
    this.handleKey = this.handleKey.bind(this);
    this.buttonRef = React.createRef();
  }

  // Just play the sound
  playDrum(e) {
    const sound = document.getElementById(this.props.keyb);
    sound.currentTime = 0;
    sound.play();
    this.props.display(this.props.name);
  }

  // On key press, play sound and visually simulate button click
  componentDidMount() {
    document.addEventListener("keydown", this.handleKey);
  }
  componentWillUnmount() {
    document.removeEventListener("keydown", this.handleKey);
  }
  handleKey(e) {
    if (e.keyCode == this.props.keyb.charCodeAt(0)) {
      this.buttonRef.current.click();
      this.buttonRef.current.focus();
      this.setState({ active: true });
      setTimeout(() => {
        this.setState({ active: false });
      }, 150);
    }
  }

  render() {
    return (
      <button
        type="button"
        id={this.props.name.replace(/ /g, "-")}
        onClick={this.playDrum}
        ref={this.buttonRef}
        aria-pressed={this.state.active}
        className={
          "drum-pad btn btn-secondary btn-lg mr-1" +
          (this.state.active ? " active" : "")
        }
      >
        {this.props.keyb}
        <audio
          className="clip"
          id={this.props.keyb}
          src={
            "https://s3.amazonaws.com/freecodecamp/drums/" + this.props.fileName
          }
        />
      </button>
    );
  }
}

// Drum display
class Display extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div id="display" className="card py-2 px-3">
        <samp>
          {this.props.msg ? this.props.msg : String.fromCharCode(160)}
        </samp>
      </div>
    );
  }
}

// Render to #app
ReactDOM.render(<DrumMachine />, document.getElementById("app"));

              
            
!
999px

Console