This commit is contained in:
Clément Le Bihan
2024-01-18 05:43:03 +01:00
parent 0b78772d0b
commit 74f804bb9a
4 changed files with 83 additions and 71 deletions

View File

@@ -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}%`,

View 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>
);
};

View File

@@ -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}

View File

@@ -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]);