Skip to content

Commit

Permalink
initial stab at game - paired w/ @ISPOL
Browse files Browse the repository at this point in the history
  • Loading branch information
lpatmo committed Sep 13, 2023
1 parent 24002e2 commit 502ff43
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 38 deletions.
14 changes: 10 additions & 4 deletions src/helpers/playMusic.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ function stopAll() {

/**
* Plays a sequence of notes in piano
* @params {string} selectedInstrument
* @params {object} answer
* @params {array} guess
* @params {integer} currentRow
* @params {integer} volume
* @return
*/
export function playSequence(selectedInstrument, answer, guess, currentRow, volume) {
Expand Down Expand Up @@ -49,9 +51,9 @@ export function playSequence(selectedInstrument, answer, guess, currentRow, volu

/**
* Play celebration
* @params {string} selectedInstrument
* @params {object} answer
* @params {array} guess
* @params {integer} currentRow
* @params {integer} volume
* @return
*/

Expand All @@ -71,13 +73,16 @@ export function playCelebrationSequence(selectedInstrument, answer, volume) {

/**
* Plays a single note
* @params {string} selectedInstrument
* @params {string} note
* @params {object} answer
* @params {integer} currentRow
* @params {integer} volume
* @params {integer} octave
* @return
*/

export function playNote(selectedInstrument, note, answer, currentNote, volume) {
export function playNote(selectedInstrument, note, answer, currentNote, volume, octave=answer.sequence[currentNote].slice(-1)) {
//Stop any previous melodies from playing
stopAll();
const instrument = instrumentsObj[selectedInstrument];
Expand All @@ -95,7 +100,8 @@ export function playNote(selectedInstrument, note, answer, currentNote, volume)
}

instrument.loaded().then(() => {
const octave = answer.sequence[currentNote].slice(-1);
//If octave is passed in as an optional param, get it from that; otherwise, get it from the octave.
//const oct = octave || answer.sequence[currentNote].slice(-1);
const now = context.currentTime;
instrument.start({ note: `${note}${octave}`, time: now, duration: 0.5 });
})
Expand Down
114 changes: 80 additions & 34 deletions src/routes/Practice.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,70 @@ import VolumeContext from '../contexts/VolumeContext'
import PianoNew from '../PianoNew'
import isNote from '../helpers/isNote'
import getNote from '../helpers/getNote'
import { playNote } from "../helpers/playMusic";
import { playNote, playSequence } from "../helpers/playMusic";
import Instruments from '../Instruments'
import Grid from '@mui/material/Grid';
import styles from './Practice.module.css'


export default function Practice() {
const [volume, setVolume] = useState(3);
const [inProgress, setInProgress] = useState(false);
const [isPaused, setIsPaused] = useState(false);
const [gameOver, setGameOver] = useState(false);
const [instrument, setInstrument] = useState('acoustic_grand_piano')
const [octave, setOctave] = useState(4);
const [error, setError] = useState(null);
const [hasFlats, setHasFlats] = useState(false);
const answer = { sequence: [`D${octave}`] }
const [guess, setGuess] = useState("");
const [answer, setAnswer] = useState({ sequence: [`Ab${octave}`], duration: [1], hasFlats: false })
const [firstTimePlayed, setFirstTimePlayed] = useState(true);
const possibleNotes = ["A", "B", "C", "D", "E", "F", "G", "Db", "C#", "Eb", "D#", "Gb", "F#", "Ab", "G#", "Bb", "A#"]
const possibleOctaves = [3, 4, 5];

function getRandomElement(possibleValues) {
const randomIndex = Math.floor(Math.random() * possibleValues.length)
return possibleValues[randomIndex];
}

function getNewNote() {
const selectedNote = getRandomElement(possibleNotes);
const hasFlats = selectedNote[1] === "b";
setAnswer({ sequence: [`${selectedNote}${getRandomElement(possibleOctaves)}`], duration: [1], hasFlats: hasFlats })
}
function startGame() {
getNewNote();
setInProgress(true);
setIsPaused(false);
}

function playGame() {
if (firstTimePlayed) {
setFirstTimePlayed(false);
}
setIsPaused(false);
playSequence(instrument, answer, undefined, undefined, volume);
}

function handlePianoPress(note) {
console.log('note', note)
handleKeyDown({ key: note });
}
function compareNoteWithAnswer(note, answerNote) {
//note: F. Ab C# G.
//answerNote: Gb3 F4 C#3
console.log('!!!comparing', note, answerNote)
console.log('1) answerNote.slice(0,-1)', answerNote.slice(0,-1))
console.log('2) with', note[1] === '.' ? note[0] : note)
return answerNote.slice(0,-1) === (note[1] === '.' ? note[0] : note)
}

function handleSubmit() {
console.log('submitting...')
}
// function getPercentage() {
// console.log("guess", guess)
// console.log("guess.length", guess.length)
// console.log("typeof guess", typeof guess)
// console.log("guess[0]", guess[0])
// console.log("guess[1]", guess[1])
// return `${guess.split("").filter((el) => el === "\uDFE9").length} / ${guess.length}`;
// }

const handleKeyDown = useCallback(
(event) => {
Expand All @@ -37,25 +78,24 @@ export default function Practice() {
case event.keyCode === 37:
// The left arrow key was pressed.
console.log("left key pressed", event.keyCode)
setOctave(octave > 3 ? octave-1 : octave);
setOctave(octave > 3 ? octave - 1 : octave);
break;
case event.keyCode === 39:
// The right arrow key was pressed.
setOctave(octave < 5 ? octave+1 : octave);
setOctave(octave < 5 ? octave + 1 : octave);
break;
case isNote(event.key):
/*Update guess state after valid note*/
let note = getNote(event, answer?.hasFlats);
console.log("note", note)
if (note[1] === "b") {
note = note[0].toUpperCase() + note[1];
} else {
note = note.toUpperCase();
}


/*Play the note in the same octave as the corresponding answer*/
playNote(instrument, note, answer, 0, volume);
playNote(instrument, note, answer, 0, volume, octave);
//setError("");

//highlight piano keyboard notes
Expand All @@ -82,9 +122,19 @@ export default function Practice() {
}
}
}, 200)
break;
case event.key === "Enter":
handleSubmit(event);

if (inProgress && !isPaused) {
console.log('comparing...')
if (compareNoteWithAnswer(note, answer?.sequence[0] )) {
setGuess(guess + '🟩')
getNewNote();
setFirstTimePlayed(true);
setIsPaused(true);
} else {
setGuess(guess + '🟥')
}
}

break;
case RegExp("^[a-zA-Z0-9]$").test(event.key):
setError(`${event.key.toUpperCase()} is not a valid note.`);
Expand All @@ -93,42 +143,38 @@ export default function Practice() {
break;
}
},
[answer, gameOver, handleSubmit, volume, instrument]
[answer, gameOver, volume, instrument, guess, isPaused]
);

useEffect(() => {
//listen to keyboard events
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [handleSubmit, handleKeyDown]);
}, [handleKeyDown]);

return (
<>
<VolumeContext.Provider value={volume}>
<Navbar showCountdown={false} isPracticing={true} />
<PianoNew handlePianoPress={handlePianoPress} octave={octave} hasFlats={hasFlats} className={styles.keyboard} setOctave={setOctave} />
<Grid container sx={{ mt: 5 }} spacing={1} justifyContent="center">
<div className={styles.guessContainer}>{answer?.sequence[0]}{guess}</div>
{/* {getPercentage()} */}
</Grid>
<PianoNew handlePianoPress={handlePianoPress} octave={octave} hasFlats={answer?.hasFlats} className={styles.keyboard} setOctave={setOctave} />
<Grid container spacing={1} justifyContent="center">
<Grid item xl={4} lg={5} md={7} className={styles.right}>
<Instruments instrument={instrument} setInstrument={setInstrument} />
{/* <InputLabel variant="standard" htmlFor="difficulty">
Key
</InputLabel>
<NativeSelect
defaultValue="C major"
inputProps={{
name: 'key',
id: 'key',
}}
onChange={(e) => setKey(e.target.value)}
sx={{ fontSize: '1.6rem' }}
>
<option value="c_major">C major</option>
<option value="d_major">D major</option>
</NativeSelect> */}
</Grid>
</Grid>
<Grid container sx={{ mt: 5 }} spacing={1} justifyContent="center">
<button type="button" className={styles.action}>Start Game</button>
{inProgress || isPaused ?
<>
<button type="button" className={styles.action} onClick={playGame}>{firstTimePlayed ? "Hear next note" : "Hear again"}</button>
<button type="button" className={styles.action} onClick={(e) => { e.preventDefault(); setIsPaused(!isPaused); if (isPaused) { playGame() } }}>{isPaused ? "Continue" : "Pause"}</button>
<button type="button" className={styles.action} onClick={(e) => { e.preventDefault(); setInProgress(false); setGuess("") }}>Reset game</button>
</>

: <button type="button" className={styles.action} onClick={startGame}>Start Game</button>}
</Grid>
</VolumeContext.Provider>
</>
Expand Down
4 changes: 4 additions & 0 deletions src/routes/Practice.module.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.keyboard {
margin-top: 3em;
}
.guessContainer {
max-width: 70%;
border: 1px solid pink;
}

0 comments on commit 502ff43

Please sign in to comment.