Cursor is controlled by partition timestamps provided by playview and can thus be paused and onEndReached is now called
This commit is contained in:
@@ -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();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user