From 41c91761d2b95803448d45636e08b0e98957c1e6 Mon Sep 17 00:00:00 2001
From: Philipp <49042626+PhilippDehner@users.noreply.github.com>
Date: Sat, 28 Jan 2023 21:32:14 +0100
Subject: [PATCH] web app: Created training component * Piano loading
improvement * Deactivated volume settings * #8
---
web-app/src/App.tsx | 43 ++++---
web-app/src/components/GeneralSettings.tsx | 11 +-
web-app/src/components/Layout.tsx | 8 +-
web-app/src/components/ToneSelector.tsx | 2 -
web-app/src/pages/Home.tsx | 2 +-
web-app/src/pages/Pitch.tsx | 143 ++++++++-------------
web-app/src/types/Tone.ts | 13 +-
web-app/src/types/Trainer.tsx | 133 +++++++++++++++++++
8 files changed, 225 insertions(+), 130 deletions(-)
create mode 100644 web-app/src/types/Trainer.tsx
diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx
index 8e281fa..48ac7d3 100644
--- a/web-app/src/App.tsx
+++ b/web-app/src/App.tsx
@@ -5,24 +5,37 @@ import "./App.css";
import Layout from "./components/Layout";
import Home from "./pages/Home";
import Pitch from "./pages/Pitch";
+import { useState } from "react";
+
+let init = true;
+let piano = new Piano({
+ velocities: 1,
+ release: true,
+ pedal: true
+});
function App() {
- let piano = new Piano();
- piano.toDestination(); //connect it to the speaker output
- piano.load().then(() => {
- console.log("loaded!");
- });
+ const [pianoReadyState, setPianoReadyState] = useState(false);
+
+ if (init) {
+ piano.toDestination(); //connect it to the speaker output
+ piano.load().then(_ => {
+ init = false;
+ setPianoReadyState(true);
+ console.info("Piano loaded");
+ });
+ }
- return (
-
-
- }>
- } />
- } />
-
-
-
- );
+ return (
+
+
+ }>
+ } />
+ } />
+
+
+
+ );
}
export default App;
diff --git a/web-app/src/components/GeneralSettings.tsx b/web-app/src/components/GeneralSettings.tsx
index 1c36562..cd81cfe 100644
--- a/web-app/src/components/GeneralSettings.tsx
+++ b/web-app/src/components/GeneralSettings.tsx
@@ -1,4 +1,3 @@
-import Form from "react-bootstrap/Form";
import { useState } from "react";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
@@ -13,8 +12,6 @@ class Settings {
ToneRange: ToneRange = new ToneRange();
}
-const DefaultToneRange = new ToneRange()
-
interface Props {
settings: Settings;
OnChanged(settings: Settings): void;
@@ -58,8 +55,8 @@ function GeneralSettings(props: Props) {
return (
-
-
+
+ {/*
Volume {volume}%
@@ -71,8 +68,8 @@ function GeneralSettings(props: Props) {
max={100}
/>
-
-
+
*/}
+
(url: string): Promise {
return fetch(url)
.then(response => {
if (!response.ok) {
- throw new Error(response.statusText)
+ console.warn(response.statusText)
}
return response.json()
})
@@ -35,12 +35,12 @@ const Layout = () => {
{currentVersion}
- GitHub
+ GitHub
- {latestVersion!=null &&latestVersion!== currentVersion
+ {latestVersion != null && latestVersion !== currentVersion
?
Newer version available! Download
-
+
here
.
diff --git a/web-app/src/components/ToneSelector.tsx b/web-app/src/components/ToneSelector.tsx
index 2924bd4..db80523 100644
--- a/web-app/src/components/ToneSelector.tsx
+++ b/web-app/src/components/ToneSelector.tsx
@@ -1,7 +1,5 @@
-import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import InputGroup from "react-bootstrap/InputGroup";
-import React from "react";
import { Tone } from "../types/Tone";
import { ToneRange } from "../types/ToneRange";
diff --git a/web-app/src/pages/Home.tsx b/web-app/src/pages/Home.tsx
index a8628fd..0ae3d08 100644
--- a/web-app/src/pages/Home.tsx
+++ b/web-app/src/pages/Home.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Button, Container } from 'react-bootstrap';
+import { Container } from 'react-bootstrap';
import en from "../languages/en.json";
diff --git a/web-app/src/pages/Pitch.tsx b/web-app/src/pages/Pitch.tsx
index 5c798c1..4876f02 100644
--- a/web-app/src/pages/Pitch.tsx
+++ b/web-app/src/pages/Pitch.tsx
@@ -1,19 +1,15 @@
-import React, { useState } from "react";
-import Button from "react-bootstrap/Button";
+import { useState } from "react";
import Alert from "react-bootstrap/Alert";
-import Stack from "react-bootstrap/Stack";
-import Container from "react-bootstrap/Container";
-import Row from "react-bootstrap/Row";
-import Col from "react-bootstrap/Col";
-
import GeneralSettings, { Settings } from "../components/GeneralSettings";
import { Tone } from "../types/Tone";
import ToneSelector from "../components/ToneSelector";
import { Piano } from "@tonejs/piano";
+import Trainer from "../types/Trainer";
let generalSettings: Settings = new Settings();
interface Props {
piano: Piano;
+ pianoLoaded: boolean;
}
enum Result {
@@ -24,57 +20,68 @@ enum Result {
}
function Pitch(props: Props) {
- const [showResult, setShowResult] = useState(false);
const [tonePlaying, setTonePlaying] = useState(
generalSettings.ToneRange.GetRandomTone()
);
- const [activePlayButton, setActivePlayButton] = useState(true);
- const [playedOnce, setPlayedOnce] = useState(false);
+ const [selectorState, setSelectorState] = useState(false);
const [selectedTone, setSelectedTone] = useState(undefined);
- const [result, setResult] = useState(Result.undefined);
-
- const sleep = (seconds: number) => {
- return new Promise(resolve => setTimeout(resolve, seconds * 1000))
- }
+ const [solutionSelected, setSolutionSelected] = useState(false);
- function play() {
- tonePlaying.play(props.piano, generalSettings.Volume);
- setPlayedOnce(true);
- setActivePlayButton(false);
- sleep(5).then(r => {
- stopPlaying();
- })
- }
function stopPlaying() {
- setActivePlayButton(true)
+ console.debug("Pitch: stopPlaying function")
tonePlaying.keyUp(props.piano);
}
function SuggestedToneSelected(tone: Tone): void {
+ console.debug("Pitch: SuggestedToneSelected function")
+ setSolutionSelected(true);
setSelectedTone(tone);
}
- function ClickShowSolution() {
- setShowResult(true);
- if (tonePlaying.Equals(selectedTone!)) setResult(Result.success);
- else if (tonePlaying.Tone === selectedTone?.Tone) setResult(Result.toneRight);
- else setResult(Result.false);
- console.info("Show solution");
- }
-
function GeneralSettingsChanged() {
- console.debug("General settings changed");
+ console.debug("Pitch: General settings changed");
if (!generalSettings.ToneRange.IsInRange(tonePlaying)) {
setTonePlaying(generalSettings.ToneRange.GetRandomTone());
}
}
function NewToneSet() {
+ console.debug("Pitch: NewToneSet function")
setTonePlaying(generalSettings.ToneRange.GetRandomTone());
- setShowResult(false);
stopPlaying();
-}
+ }
+
+ function getResult() {
+ console.debug("Pitch: getResult function")
+ let result = Result.undefined
+
+ if (tonePlaying.Equals(selectedTone!)) result = Result.success;
+ else if (tonePlaying.Tone === selectedTone?.Tone) result = Result.toneRight;
+ else result = Result.false;
+
+ let alert;
+ switch (result) {
+ case Result.success:
+ alert = Richtige Tonhöhe!; break;
+ case Result.toneRight:
+ alert = alert = Richtiger Ton, falsche Oktave. Es war {tonePlaying.Name}.;
+ break;
+ case Result.false:
+ alert = Falsche Tonhöhe! Es war {tonePlaying.Name}.;
+ break;
+ default: ;
+ }
+ return alert;
+ }
+
+ let selector =
return (
<>
@@ -82,63 +89,15 @@ function Pitch(props: Props) {
settings={generalSettings}
OnChanged={GeneralSettingsChanged}
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {(() => {
- let alert;
- switch (result) {
- case Result.success:
- alert = Richtige Tonhöhe!; break;
- case Result.toneRight:
- alert = alert = Richtiger Ton, falsche Oktave. Es war {tonePlaying.Name}.;
- break;
- case Result.false:
- alert = Falsche Tonhöhe! Es war {tonePlaying.Name}.;
- break;
- default: ;
- }
- return showResult ? alert
- : <>>;
- })()}
-
-
-
-
- {/*
- */}
-
- {/*
-
*/}
-
-
+
>
);
}
diff --git a/web-app/src/types/Tone.ts b/web-app/src/types/Tone.ts
index c9b809f..9c9020a 100644
--- a/web-app/src/types/Tone.ts
+++ b/web-app/src/types/Tone.ts
@@ -42,19 +42,14 @@ class Tone {
}
}
- public play(piano: Piano, volume: number = 100) {
- // let audio = new Audio(
- // require("./../resources/sounds/" + this.Name + ".mp3")
- // );
- // audio.volume = volume / 100;
- // console.info("Play sound:", this.Name);
- // audio.play();
-
+ public play(piano: Piano, volume: number = 100, secondsplaying: number | undefined = undefined) {
// piano.pedalDown();
piano.keyDown({
note: this.Name,
- // time: "+1"
+ // velocity: 2//Math.round(volume / 20)
});
+ if (secondsplaying != null && secondsplaying > 0)
+ piano.keyUp({ note: this.Name, time: "+" + secondsplaying });
console.info("Played tone", this.Name);
}
diff --git a/web-app/src/types/Trainer.tsx b/web-app/src/types/Trainer.tsx
new file mode 100644
index 0000000..0954450
--- /dev/null
+++ b/web-app/src/types/Trainer.tsx
@@ -0,0 +1,133 @@
+import React, { ReactNode, useState } from "react";
+import Button from "react-bootstrap/Button";
+import Stack from "react-bootstrap/Stack";
+import Container from "react-bootstrap/Container";
+import Row from "react-bootstrap/Row";
+import Col from "react-bootstrap/Col";
+
+import { Settings } from "../components/GeneralSettings";
+import { Tone } from "../types/Tone";
+import { Piano } from "@tonejs/piano";
+import { Spinner } from "react-bootstrap";
+
+let generalSettings: Settings = new Settings();
+
+interface Props {
+ piano: Piano;
+ tonesPlaying: Tone[];
+ playTonesSimultaneously: boolean;
+ selector: ReactNode;
+ solutionSelected: boolean;
+ pianoLoaded: boolean;
+ ShowSolution(): ReactNode;
+ CreateNewTask(): void;
+ SetSelectorStatus(state: boolean): void;
+}
+
+const WaitBetweenTones = 0.5;
+const MinPlayTime = 3;
+
+function Trainer(props: Props) {
+ const [showResult, setShowResult] = useState(false);
+ const [activePlayButton, setActivePlayButton] = useState(true);
+ const [playedOnce, setPlayedOnce] = useState(false);
+ const [solution, setSolution] = useState(undefined);
+
+ const sleep = (seconds: number) => {
+ return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
+ };
+
+ function play() {
+ console.debug("Trainer: play", props.tonesPlaying);
+ playTones(props.tonesPlaying, 0)
+ setPlayedOnce(true);
+ setActivePlayButton(false);
+ sleep(MinPlayTime).then(r => {
+ stopPlaying();
+ })
+ }
+
+ function playTones(tones: Tone[], wait: number): void {
+ props.SetSelectorStatus(true)
+ tones[0].play(props.piano, generalSettings.Volume);
+ if (tones.length > 1) {
+ sleep(wait).then(r => {
+ playTones(tones.slice((tones.length - 1) * -1), props.playTonesSimultaneously ? 0 : WaitBetweenTones);
+ })
+ }
+ }
+
+ function stopPlaying() {
+ console.debug("Trainer: stopPlaying function");
+ props.tonesPlaying.forEach((tone) => {
+ tone.keyUp(props.piano);
+ });
+ setActivePlayButton(true);
+ }
+
+ function ClickShowSolution() {
+ console.debug("Trainer: ClickShowSolution");
+ setShowResult(true);
+ setSolution(props.ShowSolution());
+ console.info("Show solution");
+ }
+
+ function newTask(): void {
+ props.CreateNewTask();
+ props.SetSelectorStatus(false)
+ setActivePlayButton(true);
+ setShowResult(false)
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+ {props.selector}
+
+
+
+
+
+
+
+ {showResult ? solution : <>>}
+
+
+
+ {/*
+ */}
+
+ {/*
+
*/}
+
+
+ >
+ );
+}
+
+export default Trainer;