Myatom
This commit is contained in:
@@ -16,7 +16,7 @@ import { SplendidGrandPiano } from 'smplr';
|
|||||||
|
|
||||||
export type ParitionMagicProps = {
|
export type ParitionMagicProps = {
|
||||||
playType: 'practice' | 'normal' | null;
|
playType: 'practice' | 'normal' | null;
|
||||||
timestamp: number;
|
timestamp: React.MutableRefObject<number>;
|
||||||
songID: number;
|
songID: number;
|
||||||
shouldPlay: boolean;
|
shouldPlay: boolean;
|
||||||
onEndReached: () => void;
|
onEndReached: () => void;
|
||||||
@@ -48,6 +48,8 @@ const getCursorToPlay = (
|
|||||||
|
|
||||||
const transitionDuration = 50;
|
const transitionDuration = 50;
|
||||||
|
|
||||||
|
export let updateCursor: (() => void) | undefined = undefined;
|
||||||
|
|
||||||
const PartitionMagic = ({
|
const PartitionMagic = ({
|
||||||
playType,
|
playType,
|
||||||
timestamp,
|
timestamp,
|
||||||
@@ -78,7 +80,36 @@ const PartitionMagic = ({
|
|||||||
const cursorTop = (data?.cursors[cursorDisplayIdx]?.y ?? 0) - cursorPaddingVertical;
|
const cursorTop = (data?.cursors[cursorDisplayIdx]?.y ?? 0) - cursorPaddingVertical;
|
||||||
const cursorLeft = (data?.cursors[0]?.x ?? 0) - cursorPaddingHorizontal;
|
const cursorLeft = (data?.cursors[0]?.x ?? 0) - cursorPaddingHorizontal;
|
||||||
|
|
||||||
console.log(melodySound.current?._loaded);
|
updateCursor = () => {
|
||||||
|
if (!shouldPlay) return;
|
||||||
|
if (!data || data?.cursors.length === 0) return;
|
||||||
|
getCursorToPlay(
|
||||||
|
data!.cursors,
|
||||||
|
currentCurIdx.current,
|
||||||
|
timestamp.current + transitionDuration,
|
||||||
|
(cursor, idx) => {
|
||||||
|
currentCurIdx.current = idx;
|
||||||
|
partitionOffset.value = withTiming(
|
||||||
|
-(cursor.x - data!.cursors[0]!.x) / partitionDims[0],
|
||||||
|
{
|
||||||
|
duration: transitionDuration,
|
||||||
|
easing: Easing.inOut(Easing.ease),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (idx === data!.cursors.length - 1) {
|
||||||
|
setEndPartitionReached(true);
|
||||||
|
}
|
||||||
|
if (playType === 'practice') return;
|
||||||
|
if (!isPianoLoaded) return;
|
||||||
|
cursor.notes.forEach((note) => {
|
||||||
|
piano.current?.start({
|
||||||
|
note: note.note,
|
||||||
|
duration: note.duration,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (!endPartitionReached && currentCurIdx.current + 1 === data?.cursors.length) {
|
if (!endPartitionReached && currentCurIdx.current + 1 === data?.cursors.length) {
|
||||||
// weird contraption but the mobile don't want classic functions to be called
|
// weird contraption but the mobile don't want classic functions to be called
|
||||||
@@ -166,58 +197,7 @@ const PartitionMagic = ({
|
|||||||
}
|
}
|
||||||
}, [endPartitionReached]);
|
}, [endPartitionReached]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(updateCursor, [data?.cursors, isPianoLoaded, timestamp.current]);
|
||||||
if (!melodySound.current || !melodySound.current._loaded) return;
|
|
||||||
if (!data || data?.cursors.length === 0) return;
|
|
||||||
|
|
||||||
melodySound.current.setOnPlaybackStatusUpdate((status) => {
|
|
||||||
//@ts-expect-error positionMillis is not in the type
|
|
||||||
const timestamp = status?.positionMillis ?? 0;
|
|
||||||
getCursorToPlay(
|
|
||||||
data!.cursors,
|
|
||||||
currentCurIdx.current,
|
|
||||||
timestamp + transitionDuration,
|
|
||||||
(cursor, idx) => {
|
|
||||||
currentCurIdx.current = idx;
|
|
||||||
partitionOffset.value = withTiming(
|
|
||||||
-(cursor.x - data!.cursors[0]!.x) / partitionDims[0],
|
|
||||||
{
|
|
||||||
duration: transitionDuration,
|
|
||||||
easing: Easing.inOut(Easing.ease),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, [data?.cursors, melodySound.current?._loaded]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!shouldPlay) return;
|
|
||||||
if (!isPianoLoaded || melodySound.current) return;
|
|
||||||
if (!data || data?.cursors.length === 0) return;
|
|
||||||
getCursorToPlay(
|
|
||||||
data!.cursors,
|
|
||||||
currentCurIdx.current,
|
|
||||||
timestamp + transitionDuration,
|
|
||||||
(cursor, idx) => {
|
|
||||||
currentCurIdx.current = idx;
|
|
||||||
partitionOffset.value = withTiming(
|
|
||||||
-(cursor.x - data!.cursors[0]!.x) / partitionDims[0],
|
|
||||||
{
|
|
||||||
duration: transitionDuration,
|
|
||||||
easing: Easing.inOut(Easing.ease),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (playType === 'practice') return;
|
|
||||||
cursor.notes.forEach((note) => {
|
|
||||||
piano.current?.start({
|
|
||||||
note: note.note,
|
|
||||||
duration: note.duration,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}, [timestamp, data?.cursors, isPianoLoaded]);
|
|
||||||
|
|
||||||
const animatedStyle = useAnimatedStyle(() => ({
|
const animatedStyle = useAnimatedStyle(() => ({
|
||||||
left: `${partitionOffset.value * 100}%`,
|
left: `${partitionOffset.value * 100}%`,
|
||||||
|
|||||||
35
front/components/Play/PlayTimestampShow.tsx
Normal file
35
front/components/Play/PlayTimestampShow.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Text, useTheme } from 'native-base';
|
||||||
|
import { MutableRefObject, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export let updateTime: (() => void) | undefined = undefined;
|
||||||
|
|
||||||
|
type PlayTimestampShowProps = {
|
||||||
|
paused: boolean;
|
||||||
|
time: MutableRefObject<number>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PlayTimestampShow = ({ paused, time }: PlayTimestampShowProps) => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
const textColor = colors.text;
|
||||||
|
const [timeD, setTimeD] = useState<number>(time.current);
|
||||||
|
|
||||||
|
updateTime = () => {
|
||||||
|
setTimeD(time.current);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(updateTime, [time]);
|
||||||
|
return (
|
||||||
|
<Text color={textColor[900]}>
|
||||||
|
{timeD < 0
|
||||||
|
? paused
|
||||||
|
? '0:00'
|
||||||
|
: Math.floor((timeD % 60000) / 1000)
|
||||||
|
.toFixed(0)
|
||||||
|
.toString()
|
||||||
|
: `${Math.floor(timeD / 60000)}:${Math.floor((timeD % 60000) / 1000)
|
||||||
|
.toFixed(0)
|
||||||
|
.toString()
|
||||||
|
.padStart(2, '0')}`}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,11 +6,12 @@ import { MetronomeControls } from '../Metronome';
|
|||||||
import StarProgress from '../StarProgress';
|
import StarProgress from '../StarProgress';
|
||||||
import Song from '../../models/Song';
|
import Song from '../../models/Song';
|
||||||
import { useTheme } from 'native-base';
|
import { useTheme } from 'native-base';
|
||||||
|
import { PlayTimestampShow } from './PlayTimestampShow';
|
||||||
|
|
||||||
type PlayViewControlBarProps = {
|
type PlayViewControlBarProps = {
|
||||||
playType: 'practice' | 'normal' | null;
|
playType: 'practice' | 'normal' | null;
|
||||||
song: Song;
|
song: Song;
|
||||||
time: number;
|
time: React.MutableRefObject<number>;
|
||||||
paused: boolean;
|
paused: boolean;
|
||||||
score: number;
|
score: number;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@@ -132,18 +133,7 @@ const PlayViewControlBar = ({
|
|||||||
}}
|
}}
|
||||||
onPress={onEnd}
|
onPress={onEnd}
|
||||||
/>
|
/>
|
||||||
<Text color={textColor[900]}>
|
<PlayTimestampShow paused={paused} time={time} />
|
||||||
{time < 0
|
|
||||||
? paused
|
|
||||||
? '0:00'
|
|
||||||
: Math.floor((time % 60000) / 1000)
|
|
||||||
.toFixed(0)
|
|
||||||
.toString()
|
|
||||||
: `${Math.floor(time / 60000)}:${Math.floor((time % 60000) / 1000)
|
|
||||||
.toFixed(0)
|
|
||||||
.toString()
|
|
||||||
.padStart(2, '0')}`}
|
|
||||||
</Text>
|
|
||||||
<StarProgress
|
<StarProgress
|
||||||
value={score}
|
value={score}
|
||||||
max={100}
|
max={100}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { useStopwatch } from 'react-use-precision-timer';
|
|||||||
import { MIDIAccess, MIDIMessageEvent, requestMIDIAccess } from '@motiz88/react-native-midi';
|
import { MIDIAccess, MIDIMessageEvent, requestMIDIAccess } from '@motiz88/react-native-midi';
|
||||||
import * as Linking from 'expo-linking';
|
import * as Linking from 'expo-linking';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import PartitionMagic from '../components/Play/PartitionMagic';
|
import PartitionMagic, { updateCursor } from '../components/Play/PartitionMagic';
|
||||||
import useColorScheme from '../hooks/colorScheme';
|
import useColorScheme from '../hooks/colorScheme';
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import { useTheme, useBreakpointValue } from 'native-base';
|
import { useTheme, useBreakpointValue } from 'native-base';
|
||||||
@@ -25,6 +25,7 @@ import { Clock, Cup } from 'iconsax-react-native';
|
|||||||
import PlayViewControlBar from '../components/Play/PlayViewControlBar';
|
import PlayViewControlBar from '../components/Play/PlayViewControlBar';
|
||||||
import ScoreModal from '../components/ScoreModal';
|
import ScoreModal from '../components/ScoreModal';
|
||||||
import { PlayScore, ScoreMessage } from '../components/Play/PlayScore';
|
import { PlayScore, ScoreMessage } from '../components/Play/PlayScore';
|
||||||
|
import { updateTime as updateTimeControlBar } from '../components/Play/PlayTimestampShow';
|
||||||
|
|
||||||
type PlayViewProps = {
|
type PlayViewProps = {
|
||||||
songId: number;
|
songId: number;
|
||||||
@@ -68,7 +69,8 @@ const PlayView = ({ songId }: PlayViewProps) => {
|
|||||||
const webSocket = useRef<WebSocket>();
|
const webSocket = useRef<WebSocket>();
|
||||||
const [paused, setPause] = useState<boolean>(true);
|
const [paused, setPause] = useState<boolean>(true);
|
||||||
const stopwatch = useStopwatch();
|
const stopwatch = useStopwatch();
|
||||||
const [time, setTime] = useState(0);
|
// const [time, setTime] = useState(0);
|
||||||
|
const time = useRef(0);
|
||||||
const [endResult, setEndResult] = useState<unknown>();
|
const [endResult, setEndResult] = useState<unknown>();
|
||||||
const [shouldPlay, setShouldPlay] = useState(false);
|
const [shouldPlay, setShouldPlay] = useState(false);
|
||||||
const songHistory = useQuery(API.getSongHistory(songId));
|
const songHistory = useQuery(API.getSongHistory(songId));
|
||||||
@@ -195,7 +197,10 @@ const PlayView = ({ songId }: PlayViewProps) => {
|
|||||||
setScore(Math.floor((Math.max(points, 0) * 100) / maxPoints));
|
setScore(Math.floor((Math.max(points, 0) * 100) / maxPoints));
|
||||||
|
|
||||||
if (data.type == 'step') {
|
if (data.type == 'step') {
|
||||||
setTime(data.timestamp);
|
// setTime(data.timestamp);
|
||||||
|
time.current = data.timestamp;
|
||||||
|
updateCursor?.();
|
||||||
|
updateTimeControlBar?.();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let formattedMessage = '';
|
let formattedMessage = '';
|
||||||
@@ -261,7 +266,9 @@ const PlayView = ({ songId }: PlayViewProps) => {
|
|||||||
if (playType == 'practice') return;
|
if (playType == 'practice') return;
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
setTime(() => getElapsedTime());
|
time.current = getElapsedTime();
|
||||||
|
updateCursor?.();
|
||||||
|
updateTimeControlBar?.();
|
||||||
}, 200);
|
}, 200);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [playType]);
|
}, [playType]);
|
||||||
|
|||||||
Reference in New Issue
Block a user