Cursor is controlled by partition timestamps provided by playview and can thus be paused and onEndReached is now called

This commit is contained in:
Clément Le Bihan
2023-07-24 17:30:39 +02:00
parent 3ac017a5f0
commit 7438986bcd
4 changed files with 114 additions and 124 deletions

View File

@@ -31,7 +31,9 @@ const PartitionCoord = ({
setPartitionData([base64data, a]);
onPartitionReady();
}}
onEndReached={onEndReached}
onEndReached={() => {
console.log('osmd end reached');
}}
timestamp={timestamp}
/>
)}
@@ -39,6 +41,9 @@ const PartitionCoord = ({
<PhaserCanvas
partitionB64={partitionData?.[0]}
cursorPositions={partitionData?.[1]}
onEndReached={() => {
onEndReached();
}}
/>
)}
</>

View File

@@ -28,7 +28,7 @@ const PartitionView = (props: PartitionViewProps) => {
const [osmd, setOsmd] = useState<OSMD>();
const [soundPlayer, setSoundPlayer] = useState<SoundFont.Player>();
const audioContext = new SAC.AudioContext();
const [wholeNoteLength, setWholeNoteLength] = useState(0); // Length of Whole note, in ms (?)
// const [wholeNoteLength, setWholeNoteLength] = useState(0); // Length of Whole note, in ms (?)
const colorScheme = useColorScheme();
const dimensions = useWindowDimensions();
const OSMD_DIV_ID = 'osmd-div';
@@ -45,15 +45,15 @@ const PartitionView = (props: PartitionViewProps) => {
autoResize: false,
};
// Turns note.Length or timestamp in ms
const timestampToMs = (timestamp: Fraction) => {
const timestampToMs = (timestamp: Fraction, wholeNoteLength: number) => {
return timestamp.RealValue * wholeNoteLength;
};
const getActualNoteLength = (note: Note) => {
let duration = timestampToMs(note.Length);
const getActualNoteLength = (note: Note, wholeNoteLength: number) => {
let duration = timestampToMs(note.Length, wholeNoteLength);
if (note.NoteTie) {
const firstNote = note.NoteTie.Notes.at(1);
if (Object.is(note.NoteTie.StartNote, note) && firstNote) {
duration += timestampToMs(firstNote.Length);
duration += timestampToMs(firstNote.Length, wholeNoteLength);
} else {
duration = 0;
}
@@ -97,9 +97,38 @@ const PartitionView = (props: PartitionViewProps) => {
_osmd.render();
_osmd.cursor.show();
// get the current cursor position
const bpm = _osmd.Sheet.HasBPMInfo ? _osmd.Sheet.getExpressionsStartTempoInBPM() : 60;
// setWholeNoteLength(Math.round((60 / bpm) * 4000));
const wholeNoteLength = Math.round((60 / bpm) * 4000);
const curPos = [];
while (!_osmd.cursor.iterator.EndReached) {
curPos.push(_osmd.cursor.cursorElement.offsetLeft);
const notesToPlay = _osmd.cursor
.NotesUnderCursor()
.filter((note) => {
return note.isRest() == false && note.Pitch;
})
.map((note) => {
return {
note: note,
duration: getActualNoteLength(note, wholeNoteLength),
};
});
const shortestNotes = _osmd!.cursor
.NotesUnderCursor()
.sort((n1, n2) => n1.Length.CompareTo(n2.Length))
.at(0);
const ts = timestampToMs(shortestNotes?.getAbsoluteTimestamp() ?? new Fraction(-1), wholeNoteLength);
const sNL = timestampToMs(shortestNotes?.Length ?? new Fraction(-1), wholeNoteLength);
curPos.push({
offset: _osmd.cursor.cursorElement.offsetLeft,
notes: notesToPlay,
shortedNotes: shortestNotes,
sNinfos: {
ts,
sNL,
isRest: shortestNotes?.isRest(),
}
});
_osmd.cursor.next();
}
console.log('curPos', curPos);
@@ -110,14 +139,14 @@ const PartitionView = (props: PartitionViewProps) => {
console.log('current measure index', _osmd.cursor.iterator.CurrentMeasureIndex);
const osmdCanvas = document.querySelector('#' + OSMD_DIV_ID + ' canvas');
// Ty https://github.com/jimutt/osmd-audio-player/blob/ec205a6e46ee50002c1fa8f5999389447bba7bbf/src/PlaybackEngine.ts#LL77C12-L77C63
const bpm = _osmd.Sheet.HasBPMInfo ? _osmd.Sheet.getExpressionsStartTempoInBPM() : 60;
setWholeNoteLength(Math.round((60 / bpm) * 4000));
props.onPartitionReady(
osmdCanvas.toDataURL(),
curPos.map((pos) => {
return {
x: pos,
timing: Math.floor(Math.random() * 600) + 100,
x: pos.offset,
timing: pos.sNinfos.sNL,
timestamp: pos.sNinfos.ts,
notes: pos.notes,
};
})
);

File diff suppressed because one or more lines are too long

View File

@@ -21,7 +21,6 @@ import { transformQuery, useQuery } from '../Queries';
import API from '../API';
import LoadingComponent, { LoadingView } from '../components/Loading';
import Constants from 'expo-constants';
import VirtualPiano from '../components/VirtualPiano/VirtualPiano';
import { strToKey, keyToStr, Note } from '../models/Piano';
import { useSelector } from 'react-redux';
import { RootState } from '../state/Store';
@@ -70,6 +69,14 @@ function parseMidiMessage(message: MIDIMessageEvent) {
};
}
export const PartitionContext = React.createContext<{
// Timestamp of the play session, in milisecond
timestamp: number;
}>({
timestamp: 0,
});
const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
const accessToken = useSelector((state: RootState) => state.user.accessToken);
const navigation = useNavigation();
@@ -79,7 +86,6 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
const webSocket = useRef<WebSocket>();
const [paused, setPause] = useState<boolean>(true);
const stopwatch = useStopwatch();
const [isVirtualPianoVisible, setVirtualPianoVisible] = useState<boolean>(false);
const [time, setTime] = useState(0);
const [partitionRendered, setPartitionRendered] = useState(false); // Used to know when partitionview can render
const [score, setScore] = useState(0); // Between 0 and 100
@@ -218,7 +224,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
useEffect(() => {
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE).catch(() => {});
const interval = setInterval(() => {
setTime(() => getElapsedTime()); // Countdown
setTime(() =>getElapsedTime()); // Countdown
}, 1);
return () => {
@@ -253,6 +259,11 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
}
return (
<SafeAreaView style={{ flexGrow: 1, flexDirection: 'column' }}>
<PartitionContext.Provider
value={{
timestamp: time,
}}
>
<HStack
width="100%"
justifyContent="center"
@@ -279,7 +290,8 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
/> */}
<PartitionCoord
file={musixml.data}
timestamp={Math.max(0, time)}
// timestamp={Math.max(0, time)}
timestamp={0}
onEndReached={() => {
onEnd();
}}
@@ -288,39 +300,6 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
{!partitionRendered && <LoadingComponent />}
</View>
{isVirtualPianoVisible && (
<Column
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
height: '20%',
width: '100%',
}}
>
<VirtualPiano
onNoteDown={(note) => {
console.log('On note down', keyToStr(note));
}}
onNoteUp={(note) => {
console.log('On note up', keyToStr(note));
}}
showOctaveNumbers={true}
startNote={Note.C}
endNote={Note.B}
startOctave={2}
endOctave={5}
style={{
width: '80%',
height: '100%',
}}
highlightedNotes={[
{ key: strToKey('D3') },
{ key: strToKey('A#'), bgColor: '#00FF00' },
]}
/>
</Column>
)}
<Box
shadow={4}
style={{
@@ -364,20 +343,6 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
}
}}
/>
<IconButton
size="sm"
colorScheme="coolGray"
variant="solid"
icon={
<Icon
as={MaterialCommunityIcons}
name={isVirtualPianoVisible ? 'piano-off' : 'piano'}
/>
}
onPress={() => {
setVirtualPianoVisible(!isVirtualPianoVisible);
}}
/>
<Text>
{time < 0
? paused
@@ -406,6 +371,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
</Row>
</Row>
</Box>
</PartitionContext.Provider>
</SafeAreaView>
);
};