Front: Partition: Prevent skip of first note
This commit is contained in:
@@ -25,8 +25,8 @@ import TextButton from './components/TextButton';
|
||||
|
||||
const protectedRoutes = () => ({
|
||||
Home: { component: HomeView, options: { title: translate('welcome'), headerLeft: null } },
|
||||
Settings: { component: SetttingsNavigator, options: { title: 'Settings' } },
|
||||
Play: { component: PlayView, options: { title: translate('play') } },
|
||||
Settings: { component: SetttingsNavigator, options: { title: 'Settings' } },
|
||||
Song: { component: SongLobbyView, options: { title: translate('play') } },
|
||||
Score: { component: ScoreView, options: { title: translate('score'), headerLeft: null } },
|
||||
Search: { component: SearchView, options: { title: translate('search') } },
|
||||
|
||||
@@ -52,6 +52,21 @@ const PartitionView = (props: PartitionViewProps) => {
|
||||
return duration;
|
||||
}
|
||||
|
||||
const playNotesUnderCursor = () => {
|
||||
osmd!.cursor.NotesUnderCursor()
|
||||
.filter((note) => note.isRest() == false)
|
||||
.filter((note) => note.Pitch) // Pitch Can be null, avoiding them
|
||||
.forEach((note) => {
|
||||
// Put your hands together for https://github.com/jimutt/osmd-audio-player/blob/master/src/internals/noteHelpers.ts
|
||||
const fixedKey = note.ParentVoiceEntry.ParentVoice.Parent.SubInstruments.at(0)?.fixedKey ?? 0;
|
||||
const midiNumber = note.halfTone - fixedKey * 12;
|
||||
let duration = getActualNoteLength(note);
|
||||
const gain = note.ParentVoiceEntry.ParentVoice.Volume;
|
||||
console.log('Expecting ' + midiNumber);
|
||||
soundPlayer!.play(midiNumber, audioContext.currentTime, { duration, gain })
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const _osmd = new OSMD(OSMD_DIV_ID, options);
|
||||
Promise.all([
|
||||
@@ -60,11 +75,12 @@ const PartitionView = (props: PartitionViewProps) => {
|
||||
]).then(([player, __]) => {
|
||||
setSoundPlayer(player);
|
||||
_osmd.render();
|
||||
_osmd.cursor.hide();
|
||||
// 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();
|
||||
_osmd.cursor.show();
|
||||
// Do not show cursor before actuall start
|
||||
});
|
||||
setOsmd(_osmd);
|
||||
}, []);
|
||||
@@ -73,7 +89,9 @@ const PartitionView = (props: PartitionViewProps) => {
|
||||
useEffect(() => {
|
||||
if (osmd && osmd.IsReadyToRender()) {
|
||||
osmd.render();
|
||||
osmd.cursor.show();
|
||||
if (!osmd.cursor.hidden) {
|
||||
osmd.cursor.show();
|
||||
}
|
||||
}
|
||||
}, [dimensions])
|
||||
|
||||
@@ -81,6 +99,11 @@ const PartitionView = (props: PartitionViewProps) => {
|
||||
if (!osmd || !soundPlayer) {
|
||||
return;
|
||||
}
|
||||
if (props.timestamp > 0 && osmd.cursor.hidden && !osmd.cursor.iterator.EndReached) {
|
||||
osmd.cursor.show();
|
||||
playNotesUnderCursor();
|
||||
return;
|
||||
}
|
||||
let previousCursorPosition = -1;
|
||||
let currentCursorPosition = osmd.cursor.cursorElement.offsetLeft;
|
||||
while(!osmd.cursor.iterator.EndReached &&
|
||||
@@ -89,25 +112,13 @@ const PartitionView = (props: PartitionViewProps) => {
|
||||
) {
|
||||
previousCursorPosition = currentCursorPosition;
|
||||
osmd.cursor.next();
|
||||
osmd.cursor.show();
|
||||
if (osmd.cursor.iterator.EndReached) {
|
||||
osmd.cursor.hide(); // Lousy fix for https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/issues/1338
|
||||
soundPlayer.stop();
|
||||
props.onEndReached();
|
||||
} else {
|
||||
// Shamelessly stolen from https://github.com/jimutt/osmd-audio-player/blob/ec205a6e46ee50002c1fa8f5999389447bba7bbf/src/PlaybackEngine.ts#LL223C7-L224C1
|
||||
osmd.cursor.NotesUnderCursor()
|
||||
.filter((note) => note.isRest() == false)
|
||||
.filter((note) => note.Pitch) // Pitch Can be null, avoiding them
|
||||
.forEach((note) => {
|
||||
// Put your hands together for https://github.com/jimutt/osmd-audio-player/blob/master/src/internals/noteHelpers.ts
|
||||
const fixedKey = note.ParentVoiceEntry.ParentVoice.Parent.SubInstruments.at(0)?.fixedKey ?? 0;
|
||||
const midiNumber = note.halfTone - fixedKey * 12;
|
||||
let duration = getActualNoteLength(note);
|
||||
const gain = note.ParentVoiceEntry.ParentVoice.Volume;
|
||||
// console.log(midiNumber, duration, gain);
|
||||
soundPlayer.play(midiNumber, audioContext.currentTime, { duration, gain })
|
||||
|
||||
});
|
||||
playNotesUnderCursor();
|
||||
currentCursorPosition = osmd.cursor.cursorElement.offsetLeft;
|
||||
document.getElementById(OSMD_DIV_ID).scrollBy(currentCursorPosition - previousCursorPosition, 0)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
return;
|
||||
}
|
||||
const points = data.info.score;
|
||||
const maxPoints = data.info.maxScore;
|
||||
const maxPoints = data.info.maxScore || 1;
|
||||
|
||||
setScore(Math.floor(Math.max(points, 0) / maxPoints) * 100);
|
||||
|
||||
@@ -154,6 +154,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
input.onmidimessage = (message) => {
|
||||
const keyIsPressed = message.data[2] == 100;
|
||||
const keyCode = message.data[1];
|
||||
console.log(`${keyIsPressed ? 'Pressing' : 'Releasing'} ` + keyCode);
|
||||
webSocket.current?.send(JSON.stringify({
|
||||
type: keyIsPressed ? "note_on" : "note_off",
|
||||
note: keyCode,
|
||||
@@ -171,7 +172,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
useEffect(() => {
|
||||
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE).catch(() => {});
|
||||
let interval = setInterval(() => {
|
||||
setTime(() => stopwatch.getElapsedRunningTime())
|
||||
setTime(() => stopwatch.getElapsedRunningTime() - 3000) // Countdown
|
||||
}, 1);
|
||||
|
||||
return () => {
|
||||
@@ -199,7 +200,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
<View style={{ flexGrow: 1, justifyContent: 'center' }}>
|
||||
<PartitionView file={musixml.data}
|
||||
onPartitionReady={() => setPartitionRendered(true)}
|
||||
timestamp={time}
|
||||
timestamp={Math.max(0, time)}
|
||||
onEndReached={() => {
|
||||
onEnd();
|
||||
navigation.navigate('Score', { songId: song.data.id });
|
||||
@@ -268,8 +269,15 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
} onPress={() => {
|
||||
setVirtualPianoVisible(!isVirtualPianoVisible);
|
||||
}}/>
|
||||
<Text>{Math.floor(time / 60000)}:{Math.floor((time % 60000) / 1000).toFixed(0).toString().padStart(2, '0')}</Text>
|
||||
<IconButton size='sm' colorScheme='coolGray' variant='solid' opacity={time ?? 1} disabled={time == 0} icon={
|
||||
<Text>
|
||||
{ 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>
|
||||
<IconButton size='sm' colorScheme='coolGray' variant='solid' icon={
|
||||
<Icon as={Ionicons} name="stop"/>
|
||||
} onPress={() => {
|
||||
onEnd();
|
||||
|
||||
Reference in New Issue
Block a user