Skip to content

Instantly share code, notes, and snippets.

@tundeiness
Last active June 19, 2019 08:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tundeiness/031f11e91ee2b4b9c79d2bb79d9fe7d1 to your computer and use it in GitHub Desktop.
Save tundeiness/031f11e91ee2b4b9c79d2bb79d9fe7d1 to your computer and use it in GitHub Desktop.
Drum-Machine
<div id="root"></div>
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
childDisplay: "",
recorder: [],
data: [],
drumTime: null,
sounds: null,
recordTime: null
};
this.handleDisplay = this.handleDisplay.bind(this);
this.onRecord = this.onRecord.bind(this);
this.drumEventTime = this.drumEventTime.bind(this);
this.recordSound = this.recordSound.bind(this);
}
handleDisplay(data) {
this.setState({
childDisplay: data
});
}
getData = refData => {
this.setState(
{
data: refData
},
() => this.state.data
);
};
drumEventTime(keyTime) {
const drumTiming = this.state.drumTime;
this.setState(
{
drumTime: keyTime
},
() => this.state.drumTime
);
}
recordSound(clickData) {
this.setState(
{
recorder: [...this.state.recorder, clickData]
},
() => this.state.recorder
);
}
onReset = () => {
this.setState({
recorder: []
});
};
onRecord(recordStartTime) {
this.setState(
{
recordTime: recordStartTime
},
() => this.state.recordTime
);
}
getSoundFile = soundData => {
this.setState(
{
sounds: soundData
},
() => this.state.sounds
);
};
togglePlay = () => {
const copyRecords = this.state.recorder;
const sounds = copyRecords.map((val, i) => {
return new Audio(val.link);
})
copyRecords.map((arr, idx)=>{
if (idx === 0) {
sounds[idx].play();
}else{
setTimeout(() => {
sounds[idx].play();
}, arr.time - copyRecords[0].time);
}
});
}
render() {
return (
<div id="drum-machine">
<Display
childDisplay={this.state.childDisplay}
displayRecord={this.onRecord}
reset={this.onReset}
onClickPlay={this.togglePlay}
soundData={this.state.sounds}
soundRecord={this.recordSound}
/>
<Drums
handleDisplay={this.handleDisplay}
handleRecord={this.onRecord}
getData={this.getData}
padEvent={this.drumEventTime}
getSoundFile={this.getSoundFile}
soundRecord={this.recordSound}
/>
</div>
);
}
}
class Display extends React.Component {
constructor(props) {
super(props);
this.state = {
showIcons: false,
defaultColor: "gray85"
};
}
handleClickRecord = event => {
// reset recorder in App to empty
this.props.reset();
let date = new Date();
let recordStart = date.getTime();
this.props.displayRecord(recordStart);
this.setState({
showIcons: !this.state.showIcons
});
};
pressPlay = () => {
this.props.onClickPlay();
if(this.props.soundData.length > 0){
this.setState({
defaultColor: "red"
});
}else{
this.setState({
defaultColor: "Gray85"
});
}
};
render() {
return (
<div id="dis-controls">
<div id="display">{this.props.childDisplay}</div>
<div id="controls">
<div id="play" style={{background: this.state.defaultColor}} onClick={this.pressPlay} >
<i class="fas fa-play" />
</div>
<div id="record" onClick={this.handleClickRecord}>
<span className="fas fa-circle" />
</div>
</div>
</div>
);
}
}
class Drums extends React.Component {
constructor(props) {
super(props);
this.state = {
soundFile: [
{
key: "Q",
url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3",
name: "Heater 1",
code: 81
},
{
key: "W",
url: "https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3",
name: "Kick n Hat",
code: 87
},
{
key: "E",
url: "https://s3.amazonaws.com/freecodecamp/drums/Brk_Snr.mp3",
name: "Snare",
code: 69
},
{
key: "A",
url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3",
name: "Heater 4",
code: 65
},
{
key: "S",
url: "https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3",
name: "Clap",
code: 83
},
{
key: "D",
url: "https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3",
name: "Open HH",
code: 68
},
{
key: "Z",
url: "https://s3.amazonaws.com/freecodecamp/drums/punchy_kick_1.mp3",
name: "Punchy Kick",
code: 90
},
{
key: "X",
url: "https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3",
name: "Kick",
code: 88
},
{
key: "C",
url: "https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3",
name: "Closed HH",
code: 67
}
]
};
this.myRef = [];
this.focusPad = this.focusPad.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
focusPad(event) {
let date = new Date();
let keyTime = date.getTime();
this.props.handleDisplay(event.currentTarget.id);
const datam = this.myRef;
const data = this.state.soundFile;
this.props.getData(datam);
// this.props.handleRecord(datam)
this.props.padEvent(keyTime);
this.props.getSoundFile(data);
datam.map((el, idx) => {
if (event.target.id == data[idx].name) {
const clickData = {
time: keyTime,
id: data[idx].key,
link: data[idx].url
};
this.props.soundRecord(clickData);
return this.myRef[idx].play();
}
});
}
handleKeyPress(event) {
const refData = this.myRef;
const data = this.state.soundFile;
let date = new Date();
let keyPressTime = date.getTime();
refData.map((ele, indx) => {
if (event.keyCode == data[indx].code) {
const clickData = {
time: keyPressTime,
id: data[indx].key,
link: data[indx].url
};
this.props.soundRecord(clickData);
this.props.handleDisplay(data[indx].name);
return this.myRef[indx].play();
}
});
}
componentDidMount() {
document.addEventListener("keydown", this.handleKeyPress, false);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleKeyPress, false);
}
render() {
const soundData = this.state.soundFile;
return (
<div id="drums">
{soundData.map((index, droms) => {
return (
<div
key={droms}
className="drum-pad"
id={index.name}
onClick={this.focusPad}
>
<p>{index.key}</p>
<audio
src={index.url}
type="audio/mpeg"
className="clip"
id={index.key}
ref={ref => (this.myRef[droms] = ref)}
/>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css"></script>
<script src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js"></script>
@import url('https://fonts.googleapis.com/css?family=Roboto:700|Press+Start+2P');
*{
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
#root{
background-color: #FFDEE9;
background-image: linear-gradient(0deg, #FFDEE9 0%, #B5FFFC 100%);
height: 100vh;
overflow: hidden;
}
#drum-machine{
border: 4px solid black;
border-radius: 3%;
width: 57%;
height: 65%;
margin: 8em auto;
display: flex;
flex-direction: column;
align-items: center;
}
#dis-controls{
display: flex;
flex-direction: row;
width: 98%;
height: 25%;
margin: 5px 2px;
#display{
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid rgba(0,0,255, 0.1);
border-radius: 1.5%;
height: 92%;
margin-top: 0.5%;
margin-left: 1%;
font-family: 'Press Start 2P', cursive;
background-color: rgba(0,0,255, 0.1);
#icons{
display: flex;
flex-direction: row;
justify-content: space-around;
height: 22%;
margin-top: -40px;
margin-bottom: 32px;
margin-left: 100px;
#rectext{
display: flex;
flex-direction: row;
font-size: 20%;
margin-top: 7px;
margin-left: 3px;
height: 8px;
width: 19px;
}
.rec{
display: flex;
flex-direction: row;
font-size: 20%;
margin-top: 5px;
margin-left: 3px;
height: 8px;
width: 19px;
height: 8px;
width: 8px;
border-radius: 50%;
-webkit-animation: rec 0.8s ease-in-out infinite both;
animation: rec 0.8s ease-in-out infinite both;
@-webkit-keyframes rec {
0% {
-webkit-transform: scale(0.2);
transform: scale(0.2);
opacity: 0.8;
}
80% {
-webkit-transform: scale(1.2);
transform: scale(1.2);
opacity: 0;
}
100% {
-webkit-transform: scale(2.2);
transform: scale(2.2);
opacity: 0;
}
}
@keyframes rec {
0% {
-webkit-transform: scale(0.2);
transform: scale(0.2);
opacity: 0.8;
}
80% {
-webkit-transform: scale(1.2);
transform: scale(1.2);
opacity: 0;
}
100% {
-webkit-transform: scale(2.2);
transform: scale(2.2);
opacity: 0;
}
}
}
.play{
display: flex;
flex-direction: row;
font-size: 20%;
margin-top: 5px;
margin-left: 3px;
height: 8px;
width: 19px;
}
}
}
#controls{
display: flex;
flex-direction: row;
width: 30%;
margin-left: 1.3%;
#play{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid gray;
width: 45%;
margin-left: 2%;
margin-right: 1%;
margin-top: 2%;
border-radius: 10%;
height: 92%;
background-color: #d9d9d9;
background-image: linear-gradient(315deg, #d9d9d9 0%, #f6f2f2 74%);
-webkit-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
-moz-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
}
.switch{
background-color: red;
}
.normal{
background-color: gray85;
}
#record{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid gray;
width: 45%;
margin-left: 2%;
margin-top: 2%;
border-radius: 10%;
height: 92%;
background-color: #d9d9d9;
background-image: linear-gradient(315deg, #d9d9d9 0%, #f6f2f2 74%);
-webkit-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
-moz-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
.fa-circle{
color: red;
}
}
}
}
#drums{
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
width: 98%;
height: 70%;
#drums > .drum-pad{
}
.drum-pad{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1px solid red;
width: 30.33%;
margin-right: 1%;
margin-left: 1%;
margin-top: 0.7%;
margin-bottom: 0.7%;
border-radius: 4%;
background-color: #d9d9d9;
background-image: linear-gradient(315deg, #d9d9d9 0%, #f6f2f2 74%);
font-family: 'Roboto', sans-serif;
-webkit-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
-moz-box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
box-shadow: 3px 4px 13px -4px rgba(0,0,0,0.7);
}
.drum-pad:hover{
border: 2px solid gray;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment