Giter VIP home page Giter VIP logo

drumpad's Introduction

📑 Table of Contents

📈 Purpose 🔝

This was a project required to complete the Front End Development Libraries certification on freeCodeCamp. I found it to be an enjoyable and challenging project to work on. It taught me a lot about controlling state and passing props between components in React.

I decided on Chakra UI as the styling framework. It saved me some time that would have been spent worrying about the design, and I found it quite easy to work with.

🔎 Project Setup 🔝

I started out by creating my folders and component files, and linking them all together.

📦src
 ┣ 📂components
 ┃ ┣ 📜ButtonList.js
 ┃ ┣ 📜Display.js
 ┃ ┣ 📜DrumPad.js
 ┃ ┗ 📜Pad.js
 ┣ 📜App.js
 ┗ 📜index.js

I then installed my dependencies:

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
npm install react-icons

The icon package was needed for the "GraphicEQ" icon on the volume slider.

🌈 Setting Up a Theme 🔝

Following the documentation found on Chakra UI's Customize Theme page, I installed my needed fonts and created the colors for my theme.

npm install @fontsource/open-sans @fontsource/raleway
import * as React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ChakraProvider, extendTheme } from '@chakra-ui/react';

const theme = extendTheme({
	fonts: {
		heading: `'Open Sans', sans-serif`,
		body: `'Raleway', sans-serif`
	},
	colors: {
		light: {
			100: 'rgba(247, 247, 248, 1)',
			200: 'rgba(228, 227, 238, 1)'
		},
		pink: {
			100: 'rgba(245, 188, 219, 1)',
			200: 'rgba(253, 181, 161, 1)'
		},

		purple: {
			100: 'rgba(180, 175, 220, 1)',
			200: 'rgba(116, 9, 66, 1)',
			300: 'rgba(98, 44, 111, 1)',
			400: 'rgb(38, 0, 39)'
		},
		blue: {
			100: 'rgba(175, 220, 217, 1)',
			200: 'rgba(1, 143, 204, 1)',
			300: 'rgba(36, 61, 135, 1)',
			400: 'rgba(18, 27, 59, 1)'
		}
	}
});

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
	<ChakraProvider theme={theme}>
		<App />
	</ChakraProvider>
);

Now I was ready to start working on the components.

📐 Building the Components 🔝

I usually start big and work smaller as I go along, so my first step was adding the wrapper to my App.js file. Using Chakra's documentation, I imported the elements I needed and got my container in the center of the screen. Then to finish up, I added a heading:

import { Center, Heading, Box } from '@chakra-ui/react';

function App() {
	return (
		<Center bg="purple.400" h="100vh" id="drum-machine">
			<Box bg="purple.200" p={{ base: '5', md: '10' }} w={{ base: '95vw', md: '80vw' }} borderRadius="1rem">
                <Heading>DRUM MACHINE</Heading>
            </Box>
		</Center>
	);
}

export default App;
Now the easy part is done!
heading

I set up the grid for the buttons using Chakra's grid system.

import { Grid } from '@chakra-ui/react';

const DrumPad = () => {
	return (
		<Grid templateColumns="repeat(6, 1fr)" templateRows="repeat(3, 1fr)" gap={{ base: '3', md: '6' }}>
			<Pad code="Q" />
			<Pad code="W" />
			<Pad code="E" />
			<Display />

			<Pad code="A" />
			<Pad code="S" />
			<Pad code="D" />

			<Pad code="Z" />
			<Pad code="X" />
			<Pad code="C" />
		</Grid>
	);
};

export default DrumPad;

I can now add the DrumPad component to my App.js file. Of course, I now need to make and import the Pad and Display components. Once I've created those components and added some basic styling, the UI looks like this:

ui

All of those buttons on the left were made using just one component. The Pad component is passed a prop called "code" and given a value from its parent, DrumPad. It can then display that value.

🎧 Creating the Audio Files 🔝

Since I'm a musician, I knew of several options for being able to sample drum sounds. In the end, I decided to go with Soundtrap. I settled on the 80s Drum Machine preset, and went to work creating the sounds I would need:

soundtrap

For each sound, I got an mp3 by clicking Save, then File -> Export -> Export project to mp3 file. The mixing process takes a while, so I had multiple tabs open to speed things up.

Once I was done, I trimmed up the audio using Audacity and saved everything in my public folder under a subfolder called sfx.

💭 Logic 🔝

I first needed a place to store all of the data related to each key. I did that in an object called ButtonList:

export const ButtonList = [
	{
		key: 'Q',
		sound: `${process.env.PUBLIC_URL}/sfx/tom.mp3`,
		desc: 'Tom'
	},
	{
		key: 'W',
		sound: `${process.env.PUBLIC_URL}/sfx/hh-closed.mp3`,
		desc: 'Closed HH'
	},
	{
		key: 'E',
		sound: `${process.env.PUBLIC_URL}/sfx/hh-open.mp3`,
		desc: 'Open HH'
	},
	{
		key: 'A',
		sound: `${process.env.PUBLIC_URL}/sfx/snare.mp3`,
		desc: 'Snare'
	},
	{
		key: 'S',
		sound: `${process.env.PUBLIC_URL}/sfx/rim.mp3`,
		desc: 'Rimshot'
	},
	{
		key: 'D',
		sound: `${process.env.PUBLIC_URL}/sfx/ride.mp3`,
		desc: 'Ride'
	},
	{
		key: 'Z',
		sound: `${process.env.PUBLIC_URL}/sfx/kick.mp3`,
		desc: 'Kick'
	},
	{
		key: 'X',
		sound: `${process.env.PUBLIC_URL}/sfx/hh-pedal.mp3`,
		desc: 'HH Pedal'
	},
	{
		key: 'C',
		sound: `${process.env.PUBLIC_URL}/sfx/crash.mp3`,
		desc: 'Crash'
	}
];

Now I had access to each key, it's audio source location, and the description which would show on the display when a button or key was pressed.

My next challenge is deciding how to share data to the components who need that data. I mapped out my thought process:

logic chart

Seeing it like this makes what I have to do look a lot more simple. The parent component will be the owner of all state variables, passing them down to the children when needed.

Now, I could write out the hooks needed:

Pad.js

  • playSound():
    • sets the volume of the audio file to the current volume, and resets the current time to 0
    • plays the audio file
    • changes the color of the key temporarily
    • sets the key as the current "active" key
  • handleKeyDown():
    • calls playSound() if the key pressed was a match
  • useEffect():
    • adds an event listener to the page for any key presses and calls the handleKeyDown function

These are all wrapped in the useCallBack hook and passed the appropriate dependencies.

Display.js

  • handleVolumeChange():
    • waits for a change to the input slider
    • updates the text to display the value selected
    • updates the volume using setVolume

Once all the logic was implemented, all that was left to do was test it out and make sure all the tests pass. 🎊

If you made it this far, thanks for reading! ❤️ If you've started working on this project yourself, good luck! And if this helped you at all, please consider ⭐ starring the github repository!

🔝 back to top

drumpad's People

Contributors

souperstition avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.