Created
October 29, 2022 07:30
-
-
Save loganknecht/c374f5990e35b6ca636b696676325683 to your computer and use it in GitHub Desktop.
Piano Gym Cursor Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ----------------------------------------------------------------------------- | |
// Third-Party Libraries | |
// ----------------------------------------------------------------------------- | |
import * as React from "react"; | |
import { useInterval } from "react-use"; | |
import scrollIntoView from "scroll-into-view"; | |
// ----------------------------------------------------------------------------- | |
// Custom Components | |
// ----------------------------------------------------------------------------- | |
// ./ | |
import { sheet_music_cursor_html_element_id } from "./dom_identifiers"; | |
import { ISheetMusicCursorProps } from "./sheet_music_cursor_container"; | |
import { | |
ISheetMusicCursorState, | |
SheetMusicCursorDispatchContext, | |
SheetMusicCursorReducerActionType, | |
SheetMusicCursorStateContext, | |
SheetMusicCursorStatus, | |
} from "./sheet_music_cursor_reducer"; | |
// ../ | |
import { CurrentUserDataStateContext } from "../current_user_data"; | |
import { FlashCardPlayerStateContext, FlashCardPlayerStatus, IFlashCardPlayerState } from "../flash_card_player"; | |
import { SheetMusicDisplayStateContext } from "../sheet_music_display"; | |
import { TimerStateContext } from "../timer"; | |
// ../../ | |
import { easeInOutQuad } from "../../utility/helpers"; | |
import { calculateCurrentPositionUsingTimestamp, IPosition } from "../../utility/open_sheet_music_display_helpers"; | |
// ----------------------------------------------------------------------------- | |
// Resources | |
// ----------------------------------------------------------------------------- | |
// N/A | |
export function SheetMusicCursorController(props: ISheetMusicCursorProps) { | |
// ------------------------------------------------------------------------- | |
// State | |
// ------------------------------------------------------------------------- | |
// ----------- | |
// Props | |
// ----------- | |
// N/A | |
// ----------- | |
// Local State | |
// ----------- | |
const [is_scrolling, setIsScrolling] = React.useState(false); | |
// ----------- | |
// Ref | |
// ----------- | |
const sheet_music_cursor_element_ref = React.useRef<HTMLDivElement | null>(null); | |
// ----------- | |
// Context | |
// ----------- | |
const current_user_data_state = React.useContext(CurrentUserDataStateContext); | |
// --- | |
const flash_card_player_state = React.useContext(FlashCardPlayerStateContext); | |
// --- | |
const sheet_music_cursor_state = React.useContext(SheetMusicCursorStateContext); | |
const sheetMusicCursorDispatch: any = React.useContext(SheetMusicCursorDispatchContext); | |
// --- | |
const sheet_music_display_state = React.useContext(SheetMusicDisplayStateContext); | |
// --- | |
const timer_state = React.useContext(TimerStateContext); | |
// ----------- | |
// Helpers | |
// ----------- | |
const current_user_data = | |
current_user_data_state.user_data !== null ? current_user_data_state.user_data : current_user_data_state.guest_data; | |
const default_x = "-5000px"; | |
const default_y = "-5000px"; | |
const default_height = "20px"; | |
const default_width = "20px"; | |
const render_interval_in_ms = 30; | |
// ----------- | |
// Interval Loop | |
// ----------- | |
useInterval( | |
() => { | |
runScheduler(); | |
}, | |
sheet_music_cursor_state.is_playing === true ? render_interval_in_ms : null, | |
); | |
// ------------------------------------------------------------------------- | |
// Logic | |
// ------------------------------------------------------------------------- | |
const runScheduler = () => { | |
if ( | |
(sheet_music_cursor_state.status === SheetMusicCursorStatus.READY || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.START || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STARTING || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.RUN || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.RUNNING || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STOP || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STOPPED) && | |
sheet_music_display_state.sheet_music_element !== null && | |
sheet_music_display_state.sheet_music_element !== undefined && | |
sheet_music_cursor_state.sheet_music_cursor_element !== null && | |
sheet_music_cursor_state.sheet_music_cursor_element !== undefined | |
) { | |
// console.log("rendering") | |
const tempo_override = | |
current_user_data.local_settings.flash_card_settings.play_sheet_music_flash_card.metronome !== null && | |
current_user_data.local_settings.flash_card_settings.play_sheet_music_flash_card.metronome !== undefined | |
? current_user_data.local_settings.flash_card_settings.play_sheet_music_flash_card.metronome.tempo | |
: null; | |
// console.log("tempo_override: " + tempo_override); | |
renderSheetMusicCursor(tempo_override); | |
if ( | |
flash_card_player_state.options.play_sheet_music_flash_card_options !== null && | |
flash_card_player_state.options.play_sheet_music_flash_card_options !== undefined && | |
flash_card_player_state.options.play_sheet_music_flash_card_options.follow_sheet_music_cursor === true | |
) { | |
scrollToSheetMusicCursor(flash_card_player_state, sheet_music_cursor_state); | |
} | |
} | |
}; | |
// This is dark magic taken from here: | |
// https://vanillajstoolkit.com/helpers/isinviewport/ | |
const isInViewport = (element: HTMLElement) => { | |
const bounding_rectangle = element.getBoundingClientRect(); | |
return ( | |
bounding_rectangle.top >= 0 && | |
bounding_rectangle.left >= 0 && | |
bounding_rectangle.bottom <= (window.innerHeight || document.documentElement.clientHeight) && | |
bounding_rectangle.right <= (window.innerWidth || document.documentElement.clientWidth) | |
); | |
}; | |
const renderSheetMusicCursor = (tempo_override: null | number) => { | |
const is_sheet_music_object_available = | |
sheet_music_display_state.sheet_music_element !== null && | |
sheet_music_display_state.sheet_music_element !== undefined && | |
sheet_music_display_state.open_sheet_music_display_object !== null && | |
sheet_music_display_state.open_sheet_music_display_object.IsReadyToRender() === true && | |
sheet_music_cursor_state.sheet_music_cursor_element !== null && | |
sheet_music_cursor_state.sheet_music_cursor_element !== undefined | |
? true | |
: false; | |
// console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); | |
// console.log(`tempo_override: ${tempo_override}`); | |
// console.log(sheet_music_display_state.open_sheet_music_display_object); | |
// console.log(sheet_music_display_state.sheet_music_container_dom_element); | |
// console.log(sheet_music_cursor_state.sheet_music_cursor_element); | |
// console.log(sheet_music_display_state.sheet_music_element); | |
// console.log("canOSMDRender(): " + canOSMDRender(sheet_music_display_state.open_sheet_music_display_object)); | |
// console.log("is_sheet_music_object_available: " + is_sheet_music_object_available); | |
let current_position: null | IPosition = null; | |
if (is_sheet_music_object_available && sheet_music_display_state.open_sheet_music_display_object !== null) { | |
// window.debug = sheet_music_display_state.open_sheet_music_display_object; | |
const current_timestamp = new Date(); | |
let song_start_timestamp = | |
timer_state.current_split_start_time !== null ? timer_state.current_split_start_time : current_timestamp; | |
if ( | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.NEW || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.LOADING_COMPONENTS | |
) { | |
current_position = { x: -5000, y: -5000, width: 20, height: 20 }; | |
} else if (sheet_music_cursor_state.status === SheetMusicCursorStatus.READY) { | |
// console.log(`current_timestamp: ${current_timestamp}`); | |
current_position = calculateCurrentPositionUsingTimestamp( | |
sheet_music_display_state.open_sheet_music_display_object, | |
current_timestamp, | |
current_timestamp, | |
tempo_override, | |
); | |
// console.log(current_position); | |
} else if ( | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.START || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STARTING || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.RUN || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.RUNNING | |
) { | |
current_position = calculateCurrentPositionUsingTimestamp( | |
sheet_music_display_state.open_sheet_music_display_object, | |
song_start_timestamp, | |
current_timestamp, | |
tempo_override, | |
); | |
} else if ( | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STOP || | |
sheet_music_cursor_state.status === SheetMusicCursorStatus.STOPPED | |
) { | |
let pause_timestamp = current_timestamp; | |
if (timer_state.splits.length > 0) { | |
const first_split = timer_state.splits[0]; | |
song_start_timestamp = first_split[0]; | |
const most_recent_split_stop_time = timer_state.splits[timer_state.splits.length - 1][1]; | |
pause_timestamp = most_recent_split_stop_time; | |
} | |
current_position = calculateCurrentPositionUsingTimestamp( | |
sheet_music_display_state.open_sheet_music_display_object, | |
song_start_timestamp, | |
pause_timestamp, | |
tempo_override, | |
); | |
} | |
} | |
// console.log("-----------------------------------"); | |
// console.log("Current Sheet Music Cursor Position"); | |
// console.log(current_position); | |
if (current_position !== null && sheet_music_cursor_state.sheet_music_cursor_element !== null) { | |
sheet_music_cursor_state.sheet_music_cursor_element.style.left = current_position.x + "px"; | |
sheet_music_cursor_state.sheet_music_cursor_element.style.top = current_position.y + "px"; | |
sheet_music_cursor_state.sheet_music_cursor_element.style.height = current_position.height + "px"; | |
sheet_music_cursor_state.sheet_music_cursor_element.style.width = current_position.width + "px"; | |
} | |
}; | |
const scrollToSheetMusicCursor = (flash_card_player_state: IFlashCardPlayerState, sheet_music_cursor_state: ISheetMusicCursorState) => { | |
if ( | |
flash_card_player_state !== null && | |
flash_card_player_state !== undefined && | |
(flash_card_player_state.status === FlashCardPlayerStatus.START || | |
flash_card_player_state.status === FlashCardPlayerStatus.STARTING || | |
flash_card_player_state.status === FlashCardPlayerStatus.RUN || | |
flash_card_player_state.status === FlashCardPlayerStatus.RUNNING) && | |
sheet_music_display_state !== null && | |
sheet_music_display_state !== undefined && | |
sheet_music_display_state.sheet_music_element !== null && | |
sheet_music_display_state.sheet_music_element !== undefined && | |
sheet_music_cursor_state !== null && | |
sheet_music_cursor_state !== undefined && | |
sheet_music_cursor_state.sheet_music_cursor_element !== null && | |
sheet_music_cursor_state.sheet_music_cursor_element !== undefined | |
) { | |
const is_sheet_music_cursor_in_viewport = isInViewport(sheet_music_cursor_state.sheet_music_cursor_element); | |
// console.log(`sheet_music_cursor_top: ${sheet_music_cursor_top}`); | |
if (is_sheet_music_cursor_in_viewport === false && is_scrolling === false) { | |
const sheet_music_display_element = sheet_music_display_state.sheet_music_element; | |
const sheet_music_cursor_element = sheet_music_cursor_state.sheet_music_cursor_element; | |
// console.log("------------------------------------"); | |
// console.log(sheet_music_display_element); | |
// console.log(sheet_music_cursor_element); | |
// console.log(`is_sheet_music_cursor_in_viewport: ${is_sheet_music_cursor_in_viewport}`); | |
// console.log(sheet_music_display_state.sheet_music_element); | |
// console.log(sheet_music_cursor_state.sheet_music_cursor_element); | |
if ( | |
sheet_music_display_element !== null && | |
sheet_music_display_element !== undefined && | |
sheet_music_cursor_element !== null && | |
sheet_music_cursor_element !== undefined | |
) { | |
const onComplete = () => { | |
setIsScrolling(false); | |
}; | |
setIsScrolling(true); | |
const sheetMusicCursorScrollBarCheck = (target: undefined | HTMLElement, defaultIsScrollable: any) => { | |
if (target !== null && target !== undefined) { | |
// const is_flash_card_player_view = | |
// "classList" in target && target.classList.contains("FlashCardPlayerView") ? true : false; | |
const is_sheet_music_display_view = target.id === sheet_music_display_element.id; | |
// const is_sheet_music_scroll_element = is_flash_card_player_view || is_sheet_music_display_view; | |
const is_sheet_music_scroll_element = is_sheet_music_display_view; | |
return is_sheet_music_scroll_element; | |
} else { | |
return false; | |
} | |
}; | |
const scroll_options = { | |
ease: easeInOutQuad, | |
isScrollable: sheetMusicCursorScrollBarCheck, | |
}; | |
scrollIntoView(sheet_music_cursor_element, scroll_options as any, onComplete); | |
} | |
} | |
} | |
}; | |
// ------------------------------------------------------------------------- | |
// Life Cycle Methods | |
// ------------------------------------------------------------------------- | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.sheet_music_cursor_element !== sheet_music_cursor_element_ref.current) { | |
// console.log("--------------------------------------------------------------"); | |
// console.log("Updating sheet `sheet_music_display_state.sheet_music_element`"); | |
// console.log(sheet_music_display_state.sheet_music_element); | |
// console.log(sheet_music_cursor_element_ref); | |
// console.log(sheet_music_cursor_element_ref.current); | |
sheetMusicCursorDispatch({ | |
payload: { sheet_music_cursor_element: sheet_music_cursor_element_ref.current }, | |
type: SheetMusicCursorReducerActionType.SET_SHEET_MUSIC_CURSOR_ELEMENT, | |
}); | |
} | |
}, [sheet_music_display_state, sheet_music_cursor_element_ref, sheet_music_cursor_element_ref.current]); | |
// INJECT | |
// Continually listen and check if sheet music cursor should be injected | |
// Required in order to support window resizing | |
React.useEffect(() => { | |
if ( | |
sheet_music_display_state.sheet_music_element !== null && | |
sheet_music_display_state.sheet_music_element !== undefined && | |
sheet_music_cursor_state.sheet_music_cursor_element !== null && | |
sheet_music_cursor_state.sheet_music_cursor_element !== undefined | |
) { | |
const is_cursor_a_child_of_sheet_music = sheet_music_display_state.sheet_music_element.contains( | |
sheet_music_cursor_state.sheet_music_cursor_element, | |
); | |
// console.log("is_cursor_a_child_of_sheet_music: " + is_cursor_a_child_of_sheet_music); | |
if (is_cursor_a_child_of_sheet_music === false) { | |
sheet_music_display_state.sheet_music_element.appendChild(sheet_music_cursor_state.sheet_music_cursor_element); | |
} | |
} | |
// This MUST listen to all the state change of these - doesn't seem to work otherwise | |
}, [sheet_music_display_state, sheet_music_cursor_state]); | |
// --------------------- | |
// NEW | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.NEW) { | |
// Do nothing - wait for parent component to initiate | |
} | |
}, [sheet_music_cursor_state.status]); | |
// ------------------------------ | |
// LOADING_COMPONENTS -> READY | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.LOADING_COMPONENTS) { | |
if ( | |
sheet_music_display_state.sheet_music_element !== null && | |
sheet_music_display_state.sheet_music_element !== undefined && | |
sheet_music_cursor_state.sheet_music_cursor_element !== null && | |
sheet_music_cursor_state.sheet_music_cursor_element !== undefined | |
) { | |
sheetMusicCursorDispatch({ | |
payload: { status: SheetMusicCursorStatus.READY }, | |
type: SheetMusicCursorReducerActionType.SET_STATUS, | |
}); | |
} | |
} | |
}, [ | |
sheet_music_display_state.sheet_music_element, | |
sheet_music_cursor_state.sheet_music_cursor_element, | |
sheet_music_cursor_state.status, | |
]); | |
// ------------------------------ | |
// READY -> Waiting for RUNNING | |
React.useEffect(() => { | |
// Do nothing | |
}, []); | |
// START -> STARTING | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.START) { | |
sheetMusicCursorDispatch({ | |
payload: { status: SheetMusicCursorStatus.STARTING }, | |
type: SheetMusicCursorReducerActionType.SET_STATUS, | |
}); | |
} | |
}, [sheet_music_cursor_state.status]); | |
// STARTING -> RUN | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.STARTING) { | |
sheetMusicCursorDispatch({ | |
payload: { status: SheetMusicCursorStatus.RUN }, | |
type: SheetMusicCursorReducerActionType.SET_STATUS, | |
}); | |
} | |
}, [sheet_music_cursor_state.status]); | |
// RUN -> RUNNING | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.RUN) { | |
sheetMusicCursorDispatch({ | |
payload: { status: SheetMusicCursorStatus.RUNNING }, | |
type: SheetMusicCursorReducerActionType.SET_STATUS, | |
}); | |
} | |
}, [sheet_music_cursor_state.status]); | |
// RUNNING | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.RUNNING) { | |
// do nothing | |
} | |
}, [sheet_music_cursor_state.status]); | |
// STOP -> STOPPED | |
React.useEffect(() => { | |
if (sheet_music_cursor_state.status === SheetMusicCursorStatus.STOP) { | |
sheetMusicCursorDispatch({ | |
payload: { status: SheetMusicCursorStatus.STOPPED }, | |
type: SheetMusicCursorReducerActionType.SET_STATUS, | |
}); | |
} | |
}, [sheet_music_cursor_state.status]); | |
// ------------------------------------------------------------------------- | |
// Rendering | |
// ------------------------------------------------------------------------- | |
const debug_element = <div>{`sheet_music_cursor_state.status: ${sheet_music_cursor_state.status}`}</div>; | |
const final_element_to_render = ( | |
<div | |
className="SheetMusicCursor SheetMusicCursorController" | |
id={sheet_music_cursor_html_element_id} | |
ref={sheet_music_cursor_element_ref} | |
style={{ top: default_y, left: default_x, height: default_height, width: default_width }} | |
> | |
{props.debug === true ? debug_element : null} | |
</div> | |
); | |
return final_element_to_render; | |
} | |
// ============================================================================================ | |
// ----------------------------------------------------------------------------- | |
// Third-Party Libraries | |
// ----------------------------------------------------------------------------- | |
import { GraphicalNote, OpenSheetMusicDisplay, VoiceEntry } from "opensheetmusicdisplay"; | |
// ----------------------------------------------------------------------------- | |
// Custom Components | |
// ----------------------------------------------------------------------------- | |
// N/A | |
// ----------------------------------------------------------------------------- | |
// Resources | |
// ----------------------------------------------------------------------------- | |
// N/A | |
export function canSheetMusicBeInterrogated(open_sheet_music_display_object: OpenSheetMusicDisplay): boolean { | |
if ( | |
open_sheet_music_display_object !== null && | |
open_sheet_music_display_object !== undefined && | |
open_sheet_music_display_object.Sheet !== null && | |
open_sheet_music_display_object.Sheet !== undefined && | |
open_sheet_music_display_object.Sheet.MusicPartManager !== undefined && | |
open_sheet_music_display_object.Sheet.MusicPartManager !== null | |
) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
// Used because `iterator.clone` is broken in 0.7.6 | |
export function cloneIterator(open_sheet_music_display_object: OpenSheetMusicDisplay, iterator_to_clone: any): any { | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const iterator = manager.getIterator(); | |
while ((iterator as any).currentTimeStamp.realValue !== (iterator_to_clone as any).currentTimeStamp.realValue && !iterator.EndReached) { | |
iterator.moveToNext(); | |
} | |
return iterator; | |
} | |
export function getStaffEntryFromVoiceEntry(open_sheet_music_display_object: OpenSheetMusicDisplay, voiceEntry: VoiceEntry) { | |
const measure_index = voiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.measureListIndex; | |
const staff_index = voiceEntry.ParentSourceStaffEntry.ParentStaff.idInMusicSheet; | |
const graphical_staff_entry = open_sheet_music_display_object.GraphicSheet.findGraphicalStaffEntryFromMeasureList( | |
staff_index, | |
measure_index, | |
voiceEntry.ParentSourceStaffEntry, | |
); | |
return graphical_staff_entry; | |
} | |
export function findGraphicalNoteFromNote( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
note_to_find: any, | |
): undefined | GraphicalNote { | |
for (let measure_index = 0; measure_index < open_sheet_music_display_object.GraphicSheet.MeasureList.length; measure_index++) { | |
const current_measure = open_sheet_music_display_object.GraphicSheet.MeasureList[measure_index]; | |
for (let voice_index = 0; voice_index < current_measure.length; voice_index++) { | |
const current_voice = current_measure[voice_index]; | |
for (let staff_entry_index = 0; staff_entry_index < current_voice.staffEntries.length; staff_entry_index++) { | |
const staff_entry = current_voice.staffEntries[staff_entry_index]; | |
// See repo: | |
// https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/blob/8b2f7a19f2ed797940420c9580af8437778686b1/src/MusicalScore/Graphical/GraphicalStaffEntry.ts#L147 | |
const discovered_note = staff_entry.findGraphicalNoteFromNote(note_to_find); | |
if (discovered_note !== null && discovered_note !== undefined) { | |
return discovered_note; | |
} | |
} | |
} | |
} | |
return undefined; | |
} | |
export function getMeasureCount(open_sheet_music_display_object: OpenSheetMusicDisplay): number { | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const iterator = manager.getIterator(); | |
let total_measures = 0; | |
while (iterator.EndReached !== true) { | |
total_measures = iterator.CurrentMeasure.MeasureNumber; | |
iterator.moveToNext(); | |
} | |
return total_measures; | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function calcuateTotalSongDurationInMilliseconds( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
tempo_override: null | number, | |
): number { | |
// console.log("------------------------------------------------------------"); | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const iterator = manager.getIterator(); | |
const look_ahead_iterator = manager.getIterator(); | |
look_ahead_iterator.moveToNext(); | |
let total_duration_in_ms = 0; | |
let current_bpm = open_sheet_music_display_object.Sheet.DefaultStartTempoInBpm; | |
while (!look_ahead_iterator.EndReached) { | |
// console.log("~~~"); | |
// console.log("iterator.CurrentMeasureIndex: " + iterator.CurrentMeasureIndex); | |
// console.log("look_ahead_iterator.CurrentMeasureIndex: " + look_ahead_iterator.CurrentMeasureIndex); | |
if (tempo_override !== null) { | |
current_bpm = tempo_override; | |
} else if (iterator.CurrentMeasure !== undefined) { | |
current_bpm = iterator.CurrentMeasure.TempoInBPM; | |
} | |
const current_iterator_relative_timestamp_in_seconds = ((iterator as any).currentTimeStamp.realValue * 4 * 60) / current_bpm; | |
const current_iterator_relative_timestamp_in_milliseconds = current_iterator_relative_timestamp_in_seconds * 1000; | |
const look_ahead_iterator_relative_timestamp_in_seconds = | |
((look_ahead_iterator as any).currentTimeStamp.realValue * 4 * 60) / current_bpm; | |
const look_ahead_iterator_relative_timestamp_in_milliseconds = look_ahead_iterator_relative_timestamp_in_seconds * 1000; | |
const current_duration_in_ms = | |
look_ahead_iterator_relative_timestamp_in_milliseconds - current_iterator_relative_timestamp_in_milliseconds; | |
total_duration_in_ms += current_duration_in_ms; | |
// console.log("current_iterator_relative_timestamp_in_seconds: " + current_iterator_relative_timestamp_in_seconds); | |
// console.log("current_iterator_relative_timestamp_in_milliseconds: " + current_iterator_relative_timestamp_in_milliseconds); | |
// console.log("look_ahead_iterator_relative_timestamp_in_seconds: " + look_ahead_iterator_relative_timestamp_in_seconds); | |
// console.log("look_ahead_iterator_relative_timestamp_in_milliseconds: " + look_ahead_iterator_relative_timestamp_in_milliseconds); | |
// console.log("current_duration_in_ms: " + current_duration_in_ms); | |
// console.log("total_duration_in_ms: " + total_duration_in_ms); | |
// --- | |
iterator.moveToNext(); | |
look_ahead_iterator.moveToNext(); | |
} | |
const final_note_duration_in_seconds = ((look_ahead_iterator as any).currentTimeStamp.Denominator * 4) / current_bpm; | |
const final_note_duration_in_milliseconds = final_note_duration_in_seconds * 1000; | |
total_duration_in_ms += final_note_duration_in_milliseconds; | |
// console.log("final_note_duration_in_seconds: " + final_note_duration_in_seconds); | |
// console.log("final_note_duration_in_milliseconds: " + final_note_duration_in_milliseconds); | |
// console.log("total_duration_in_ms: " + total_duration_in_ms); | |
return total_duration_in_ms; | |
} | |
// A mutation helper | |
// TODO: Correct type - MusicPartManagerIterator | |
// Moves the iterator the timestamp that is | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
song_start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): any { | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const iterator = manager.getIterator(); | |
// For some reason the default iterator is offset by 1 meaning that the | |
// first iterator element contains no information about the first note | |
// This means that all calculations needs to be performed with a look ahead | |
// iterator to calculate the difference in the steps | |
const look_ahead_iterator = manager.getIterator(); | |
look_ahead_iterator.moveToNext(); | |
// console.log("-----------------------"); | |
// console.log("iterator.CurrentMeasureIndex: " + iterator.CurrentMeasureIndex); | |
// console.log("look_ahead_iterator.CurrentMeasureIndex: " + look_ahead_iterator.CurrentMeasureIndex); | |
const song_start_timestamp_in_milliseconds = song_start_timestamp.getTime(); | |
const current_timestamp_in_milliseconds = current_timestamp.getTime(); | |
const current_duration_through_song_in_milliseconds = current_timestamp_in_milliseconds - song_start_timestamp_in_milliseconds; | |
if (current_duration_through_song_in_milliseconds < 0) { | |
return iterator; | |
} | |
// console.log("song_start_timestamp_in_milliseconds: " + song_start_timestamp_in_milliseconds); | |
// console.log("current_timestamp_in_milliseconds: " + current_timestamp_in_milliseconds); | |
// console.log("current_duration_through_song_in_milliseconds: " + current_duration_through_song_in_milliseconds); | |
let current_bpm = open_sheet_music_display_object.Sheet.DefaultStartTempoInBpm; | |
if (tempo_override !== null) { | |
current_bpm = tempo_override; | |
} else if (iterator.CurrentMeasure !== undefined) { | |
current_bpm = iterator.CurrentMeasure.TempoInBPM; | |
} | |
let has_found_iterator_location = false; | |
// Ok this is the weird part | |
// When you use the `drawFromMeasure` and `drawUpToMeasure` feature of the | |
// IOSMDOptions the `realValue` of the `currentTimeStamp` is still the same | |
// expected time as if you were starting from the beginning in the song. | |
// This means that `measure two` will always return `2`, `measure five` -> `5`, | |
// and so on. Because of this you need to calculate the offset to the start | |
// measure that is actually `drawFromMeasure`. The easiest way to do that is | |
// just get the iterator's first real value and use that as the offset for all | |
// relative timestamp calculations | |
// WARNING! WARNING! | |
// `realValue * 4 * 60` may need to be refactored! I believe that the `4` | |
// is the total counts of beats in a measure, which means that this | |
// calculates based off of the top number in the time signature of a piece | |
// I haven't tested this yet, but if there is an issue with non 4/4 | |
// time signatures, I wiould almost GUARANTEE this is the area where a | |
// bug is occurring | |
const start_timestamp_real_value = (iterator as any).currentTimeStamp.realValue; | |
const start_timestamp_offset_in_seconds = (start_timestamp_real_value * 4 * 60) / current_bpm; | |
const start_timestamp_offset_in_milliseconds = start_timestamp_offset_in_seconds * 1000; | |
// console.log("start_timestamp_real_value: " + start_timestamp_real_value); | |
// console.log("start_timestamp_offset_in_seconds: " + start_timestamp_offset_in_seconds); | |
// console.log("start_timestamp_offset_in_milliseconds: " + start_timestamp_offset_in_milliseconds); | |
const relative_duration_through_song_in_milliseconds = | |
start_timestamp_offset_in_milliseconds + current_duration_through_song_in_milliseconds; | |
while (!look_ahead_iterator.EndReached && has_found_iterator_location === false) { | |
// console.log("~~~~~"); | |
if (tempo_override !== null) { | |
current_bpm = tempo_override; | |
} else if (iterator.CurrentMeasure !== undefined) { | |
current_bpm = iterator.CurrentMeasure.TempoInBPM; | |
} | |
const current_iterator_timestamp_real_value = (iterator as any).currentTimeStamp.realValue; | |
const current_iterator_timestamp_in_seconds = (current_iterator_timestamp_real_value * 4 * 60) / current_bpm; | |
const current_iterator_timestamp_in_milliseconds = current_iterator_timestamp_in_seconds * 1000; | |
const look_ahead_iterator_timestamp_real_value = (look_ahead_iterator as any).currentTimeStamp.realValue; | |
const look_ahead_iterator_timestamp_in_seconds = (look_ahead_iterator_timestamp_real_value * 4 * 60) / current_bpm; | |
const look_ahead_iterator_timestamp_in_milliseconds = look_ahead_iterator_timestamp_in_seconds * 1000; | |
// console.log("current_iterator_timestamp_real_value: " + current_iterator_timestamp_real_value); | |
// console.log("current_iterator_timestamp_in_seconds: " + current_iterator_timestamp_in_seconds); | |
// console.log( | |
// "current_iterator_timestamp_in_milliseconds: " + current_iterator_timestamp_in_milliseconds | |
// ); | |
// console.log("---"); | |
// console.log("look_ahead_iterator_timestamp_real_value: " + look_ahead_iterator_timestamp_real_value); | |
// console.log("look_ahead_iterator_timestamp_in_seconds: " + look_ahead_iterator_timestamp_in_seconds); | |
// console.log( | |
// "look_ahead_iterator_timestamp_in_milliseconds: " + look_ahead_iterator_timestamp_in_milliseconds | |
// ); | |
// console.log("---"); | |
// console.log("relative_duration_through_song_in_milliseconds: " + relative_duration_through_song_in_milliseconds); | |
if ( | |
relative_duration_through_song_in_milliseconds >= current_iterator_timestamp_in_milliseconds && | |
relative_duration_through_song_in_milliseconds < look_ahead_iterator_timestamp_in_milliseconds | |
) { | |
has_found_iterator_location = true; | |
} else { | |
iterator.moveToNext(); | |
look_ahead_iterator.moveToNext(); | |
} | |
} | |
return iterator; | |
} | |
// TODO: This should really be decoupled, it should not be returning | |
// width/height and that should be its own thing | |
export interface IPosition { | |
x: number; | |
y: number; | |
height: number; | |
width: number; | |
} | |
export function calculateIteratorNotePosition(open_sheet_music_display_object: any, iterator: any): null | IPosition { | |
// console.log("iterator"); | |
// console.log(iterator); | |
const voiceEntries = iterator.CurrentVisibleVoiceEntries(); | |
// if (iterator.EndReached || iterator.CurrentVoiceEntries === undefined || voiceEntries.length === 0) { | |
// // return; | |
// } | |
let initial_x = 0; | |
let initial_y = 0; | |
let initial_height = 10; | |
const initial_width = 1.5; | |
const graphical_staff_entries: any[] = voiceEntries.map((voice_entry: any) => { | |
return getStaffEntryFromVoiceEntry(open_sheet_music_display_object, voice_entry); | |
}); | |
const sorted_graphical_staff_entries: any = graphical_staff_entries.sort((a, b) => { | |
if ( | |
a !== null && | |
a !== undefined && | |
a.PositionAndShape !== null && | |
a.PositionAndShape !== undefined && | |
a.PositionAndShape.AbsolutePosition !== null && | |
a.PositionAndShape.AbsolutePosition !== undefined && | |
a.PositionAndShape.AbsolutePosition.x !== null && | |
a.PositionAndShape.AbsolutePosition.x !== undefined && | |
b !== null && | |
b !== undefined && | |
b.PositionAndShape !== null && | |
b.PositionAndShape !== undefined && | |
b.PositionAndShape.AbsolutePosition !== null && | |
b.PositionAndShape.AbsolutePosition !== undefined && | |
b.PositionAndShape.AbsolutePosition.x !== null && | |
b.PositionAndShape.AbsolutePosition.x !== undefined | |
) { | |
if (a.PositionAndShape.AbsolutePosition.x <= b.PositionAndShape.AbsolutePosition.x) { | |
return -1; | |
} else { | |
return 1; | |
} | |
} else { | |
return 1; | |
} | |
}); | |
const graphical_staff_entry = sorted_graphical_staff_entries[0]; | |
initial_x = graphical_staff_entry.PositionAndShape.AbsolutePosition.x; | |
// window.debug = graphical_staff_entry | |
const musicSystem = graphical_staff_entry.parentMeasure.parentMusicSystem; | |
// DO NOT REMOVE - Sometimes the data just isn't there? This was in the | |
// original osmd cursor logic as well | |
if (musicSystem === undefined) { | |
return null; | |
} | |
initial_y = musicSystem.PositionAndShape.AbsolutePosition.y + musicSystem.StaffLines[0].PositionAndShape.RelativePosition.y; | |
const bottom_staff_line: any = musicSystem.StaffLines[musicSystem.StaffLines.length - 1]; | |
// const end_y: number = musicSystem.PositionAndShape.AbsolutePosition.y + bottom_staff_line.PositionAndShape.RelativePosition.y + bottom_staff_line.StaffHeight; | |
const end_y: number = | |
musicSystem.PositionAndShape.AbsolutePosition.y + | |
bottom_staff_line.PositionAndShape.RelativePosition.y + | |
open_sheet_music_display_object.EngravingRules.StaffHeight; | |
initial_height = end_y - initial_y; | |
// console.log(musicSystem.PositionAndShape.AbsolutePosition.y); | |
// console.log(bottom_staff_line.PositionAndShape.RelativePosition.y); | |
// console.log(bottom_staff_line.StaffHeight); | |
// console.log(bottom_staff_line); | |
// console.log(bottom_staff_line.boundingBox.size.height); | |
// window.debug = bottom_staff_line | |
// window.debug = open_sheet_music_display_object; | |
// console.log(initial_y) | |
// console.log(bottom_staff_line) | |
// console.log(end_y) | |
const final_x = (initial_x - initial_width / 2) * 10.0 * open_sheet_music_display_object.zoom; | |
const final_y = initial_y * 10.0 * open_sheet_music_display_object.zoom; | |
const final_height = initial_height * 10.0 * open_sheet_music_display_object.zoom; | |
const final_width: number = initial_width * 10.0 * open_sheet_music_display_object.zoom; | |
// const position_and_size_to_return = { x: 0, y: 0 }; | |
const position_and_size_to_return = { x: final_x, y: final_y, height: final_height, width: final_width }; | |
return position_and_size_to_return; | |
} | |
export function calculateFinalNotePosition(open_sheet_music_display_object: any): null | IPosition { | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const iterator = manager.getIterator(); | |
const look_ahead_iterator = manager.getIterator(); | |
look_ahead_iterator.moveToNext(); | |
// return position_and_size_to_return; | |
while (!look_ahead_iterator.endReached) { | |
iterator.moveToNext(); | |
look_ahead_iterator.moveToNext(); | |
} | |
const final_note_position = calculateIteratorNotePosition(open_sheet_music_display_object, iterator); | |
return final_note_position; | |
} | |
export function calculateIteratorMeasureStartPosition(open_sheet_music_display_object: any, iterator: any): IPosition { | |
const current_measure_index = iterator.CurrentMeasureIndex; | |
const voice_index = 0; | |
const graphical_voice_measures = open_sheet_music_display_object.GraphicSheet.MeasureList[current_measure_index]; | |
const graphical_voice_measure = graphical_voice_measures[voice_index]; | |
const start_x = graphical_voice_measure.PositionAndShape.AbsolutePosition.x; | |
const width = graphical_voice_measure.PositionAndShape.boundingRectangle.width; | |
// const end_x = start_x + width; | |
const start_y = graphical_voice_measure.PositionAndShape.AbsolutePosition.y; | |
const height = graphical_voice_measure.PositionAndShape.boundingRectangle.height; | |
// const end_y = start_y + height; | |
const scaled_start_x = start_x * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_width = width * 10.0 * open_sheet_music_display_object.zoom; | |
// const scaled_end_x = end_x * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_start_y = start_y * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_height = height * 10.0 * open_sheet_music_display_object.zoom; | |
// const scaled_end_y = end_y * 10.0 * open_sheet_music_display_object.zoom; | |
const position_to_return = { | |
x: scaled_start_x, | |
y: scaled_start_y, | |
width: scaled_width, | |
height: scaled_height, | |
}; | |
return position_to_return; | |
} | |
export function calculateIteratorMeasureEndPosition(open_sheet_music_display_object: any, iterator: any): IPosition { | |
const current_measure_index = iterator.CurrentMeasureIndex; | |
const voice_index = 0; | |
const graphical_voice_measures = open_sheet_music_display_object.GraphicSheet.MeasureList[current_measure_index]; | |
const graphical_voice_measure = graphical_voice_measures[voice_index]; | |
const start_x = graphical_voice_measure.PositionAndShape.AbsolutePosition.x; | |
const width = graphical_voice_measure.PositionAndShape.boundingRectangle.width; | |
const end_x = start_x + width; | |
const start_y = graphical_voice_measure.PositionAndShape.AbsolutePosition.y; | |
const height = graphical_voice_measure.PositionAndShape.boundingRectangle.height; | |
const end_y = start_y + height; | |
// const scaled_start_x = start_x * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_width = width * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_end_x = end_x * 10.0 * open_sheet_music_display_object.zoom; | |
// const scaled_start_y = start_y * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_height = height * 10.0 * open_sheet_music_display_object.zoom; | |
const scaled_end_y = end_y * 10.0 * open_sheet_music_display_object.zoom; | |
const position_to_return = { | |
x: scaled_end_x, | |
y: scaled_end_y, | |
width: scaled_width, | |
height: scaled_height, | |
}; | |
return position_to_return; | |
} | |
export function calculateIteratorPosition(open_sheet_music_display_object: any, iterator: any): null | IPosition { | |
if (!iterator.EndReached) { | |
return calculateIteratorNotePosition(open_sheet_music_display_object, iterator); | |
} else { | |
return calculateFinalNotePosition(open_sheet_music_display_object); | |
} | |
} | |
export function clamp(number_to_clamp: number, min: number, max: number) { | |
return Math.min(Math.max(number_to_clamp, min), max); | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function calculateCurrentPercentageThroughCurrentIterator( | |
open_sheet_music_display_object: any, | |
iterator: any, | |
song_start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): number { | |
// console.log("tempo_override: " + tempo_override); | |
// Bug! You can't use the `clone` operation on the iterator because it's | |
// broken. For now, just create a new iterator and move it to the | |
// same real value and that is sufficient | |
const manager = open_sheet_music_display_object.Sheet.MusicPartManager; | |
const start_measure_iterator = manager.getIterator(); | |
const look_ahead_iterator = manager.getIterator(); | |
while (look_ahead_iterator.currentTimeStamp.realValue !== iterator.currentTimeStamp.realValue) { | |
look_ahead_iterator.moveToNext(); | |
} | |
look_ahead_iterator.moveToNext(); | |
// Ok this is the weird part | |
// When you use the `drawFromMeasure` and `drawUpToMeasure` feature of the | |
// IOSMDOptions the real value of the measures is still the same expected time | |
// in the song. Because of this you need to calculate the offset to the start | |
// measure that is actually `drawFromMeasure`. The easiest way to do that is | |
// just get the iterator's first real value and use that as the offset for all | |
// relative timestamp calculations | |
let start_measure_bpm = open_sheet_music_display_object.Sheet.DefaultStartTempoInBpm; | |
if (tempo_override !== null) { | |
start_measure_bpm = tempo_override; | |
} else if (start_measure_iterator.CurrentMeasure !== undefined) { | |
start_measure_bpm = start_measure_iterator.CurrentMeasure.TempoInBPM; | |
} | |
const relative_time_calculation_offset_in_seconds = | |
((start_measure_iterator as any).currentTimeStamp.realValue * 4 * 60) / start_measure_bpm; | |
const relative_time_calculation_offset_in_milliseconds = relative_time_calculation_offset_in_seconds * 1000; | |
// ------- | |
const song_start_timestamp_in_milliseconds = song_start_timestamp.getTime(); | |
const current_timestamp_in_milliseconds = current_timestamp.getTime(); | |
const current_duration_through_song_in_milliseconds = current_timestamp_in_milliseconds - song_start_timestamp_in_milliseconds; | |
if (current_duration_through_song_in_milliseconds < 0) { | |
return 0; | |
} | |
// ------- | |
let current_bpm = open_sheet_music_display_object.Sheet.DefaultStartTempoInBpm; | |
if (tempo_override !== null) { | |
current_bpm = tempo_override; | |
} else if (iterator.CurrentMeasure !== undefined) { | |
current_bpm = iterator.CurrentMeasure.TempoInBPM; | |
} | |
// ------- | |
const current_iterator_song_relative_timestamp_in_seconds = (iterator.currentTimeStamp.realValue * 4 * 60) / current_bpm; | |
const current_iterator_song_relative_timestamp_in_milliseconds = current_iterator_song_relative_timestamp_in_seconds * 1000; | |
const current_iterator_song_relative_timestamp_in_milliseconds_with_offset = | |
current_iterator_song_relative_timestamp_in_milliseconds - relative_time_calculation_offset_in_milliseconds; | |
// ------- | |
const look_ahead_iterator_song_relative_timestamp_in_seconds = (look_ahead_iterator.currentTimeStamp.realValue * 4 * 60) / current_bpm; | |
const look_ahead_iterator_song_relative_timestamp_in_milliseconds = look_ahead_iterator_song_relative_timestamp_in_seconds * 1000; | |
const look_ahead_iterator_song_relative_timestamp_in_milliseconds_with_offset = | |
look_ahead_iterator_song_relative_timestamp_in_milliseconds - relative_time_calculation_offset_in_milliseconds; | |
// ------- | |
// console.log("--------------------------------------"); | |
// console.log("start_measure_bpm: " + start_measure_bpm); | |
// console.log("current_bpm: " + current_bpm); | |
// console.log("song_start_timestamp_in_milliseconds: " + song_start_timestamp_in_milliseconds); | |
// console.log("current_timestamp_in_milliseconds: " + current_timestamp_in_milliseconds); | |
// console.log("current_duration_through_song_in_milliseconds: " + current_duration_through_song_in_milliseconds); | |
// console.log("current_bpm: " + current_bpm); | |
// // -- | |
// console.log("iterator.currentTimeStamp.realValue: " + iterator.currentTimeStamp.realValue); | |
// console.log("current_iterator_song_relative_timestamp_in_seconds: " + current_iterator_song_relative_timestamp_in_seconds); | |
// console.log("current_iterator_song_relative_timestamp_in_milliseconds: " + current_iterator_song_relative_timestamp_in_milliseconds); | |
// // -- | |
// console.log("look_ahead_iterator.currentTimeStamp.realValue: " + look_ahead_iterator.currentTimeStamp.realValue); | |
// console.log("look_ahead_iterator_song_relative_timestamp_in_seconds: " + look_ahead_iterator_song_relative_timestamp_in_seconds); | |
// console.log( | |
// "look_ahead_iterator_song_relative_timestamp_in_milliseconds: " + look_ahead_iterator_song_relative_timestamp_in_milliseconds | |
// ); | |
let percentage_through_current_timestep = 0; | |
if (current_duration_through_song_in_milliseconds < current_iterator_song_relative_timestamp_in_milliseconds_with_offset) { | |
// console.log("UNDER!"); | |
percentage_through_current_timestep = 0; | |
} else if ( | |
current_duration_through_song_in_milliseconds >= current_iterator_song_relative_timestamp_in_milliseconds_with_offset && | |
current_duration_through_song_in_milliseconds < look_ahead_iterator_song_relative_timestamp_in_milliseconds_with_offset | |
) { | |
const current_iterator_duration = | |
look_ahead_iterator_song_relative_timestamp_in_milliseconds_with_offset - | |
current_iterator_song_relative_timestamp_in_milliseconds_with_offset; | |
const duration_through_current_iterator = | |
current_duration_through_song_in_milliseconds - current_iterator_song_relative_timestamp_in_milliseconds_with_offset; | |
percentage_through_current_timestep = duration_through_current_iterator / current_iterator_duration; | |
// console.log("current_iterator_duration: " + current_iterator_duration); | |
// console.log("duration_through_current_iterator: " + duration_through_current_iterator); | |
// console.log("percentage_through_current_timestep: " + percentage_through_current_timestep); | |
} else if (current_duration_through_song_in_milliseconds > look_ahead_iterator_song_relative_timestamp_in_milliseconds_with_offset) { | |
// console.log("OVER!"); | |
percentage_through_current_timestep = 1; | |
} | |
const clamped_percentage = clamp(percentage_through_current_timestep, 0, 1); | |
return clamped_percentage; | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function calculateCurrentPositionUsingTimestamp( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): null | IPosition { | |
// console.log("-----------------------------------"); | |
// console.log("Calculationg Current TimeStamp Position"); | |
// console.log("tempo_override: " + tempo_override); | |
// console.log(start_timestamp); | |
// console.log(current_timestamp); | |
let current_timestamp_to_use = current_timestamp; | |
const total_song_duration_in_milliseconds = calcuateTotalSongDurationInMilliseconds(open_sheet_music_display_object, tempo_override); | |
const time_difference = current_timestamp.getTime() - start_timestamp.getTime(); | |
// console.log("total_song_duration_in_milliseconds: " + total_song_duration_in_milliseconds); | |
// console.log("time_difference: " + time_difference); | |
if (time_difference < 0) { | |
// Time provided is < start time | |
// Set time to beginning of song | |
current_timestamp_to_use = start_timestamp; | |
// throw "Time is less and should be more"; | |
} | |
if (time_difference > total_song_duration_in_milliseconds) { | |
// Time provided is > start time | |
// Set time to end of song | |
const new_current_timestamp = new Date(); | |
new_current_timestamp.setTime(start_timestamp.getTime() + total_song_duration_in_milliseconds); | |
current_timestamp_to_use = new_current_timestamp; | |
// throw "Time is more and should be less"; | |
} | |
// console.log("current_timestamp"); | |
// console.log(current_timestamp); | |
// console.log("start_timestamp"); | |
// console.log(start_timestamp); | |
// console.log("current_timestamp_to_use"); | |
// console.log(current_timestamp_to_use); | |
// TODO: error catch for bounds of start_timestamp and current_timestamp in order | |
// to make sure the helper isn't called with weird data | |
// ------------------------ | |
// For Debugging | |
// const new_current_timestamp = new Date(); | |
// new_current_timestamp.setTime(start_timestamp.getTime() + 3000); | |
// current_timestamp_to_use = new_current_timestamp; | |
// ------------------------ | |
const current_timestamp_iterator = getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
const look_ahead_timestamp_iterator = getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
look_ahead_timestamp_iterator.moveToNext(); | |
// console.log("current_timestamp_iterator"); | |
// console.log(current_timestamp_iterator); | |
// console.log("look_ahead_timestamp_iterator"); | |
// console.log(look_ahead_timestamp_iterator); | |
const current_timestamp_iterator_position = calculateIteratorPosition(open_sheet_music_display_object, current_timestamp_iterator); | |
const percentage_through_current_timestep = calculateCurrentPercentageThroughCurrentIterator( | |
open_sheet_music_display_object, | |
current_timestamp_iterator, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
const look_ahead_timestamp_iterator_position = calculateIteratorPosition( | |
open_sheet_music_display_object, | |
look_ahead_timestamp_iterator, | |
); | |
// console.log("current_timestamp_iterator_position"); | |
// console.log(current_timestamp_iterator_position); | |
// console.log("look_ahead_timestamp_iterator_position"); | |
// console.log(look_ahead_timestamp_iterator_position); | |
// console.log(`percentage_through_current_timestep: ${percentage_through_current_timestep}`); | |
// console.log("current_timestamp_iterator.CurrentMeasureIndex: " + current_timestamp_iterator.CurrentMeasureIndex); | |
// console.log("look_ahead_timestamp_iterator.CurrentMeasureIndex: " + look_ahead_timestamp_iterator.CurrentMeasureIndex); | |
if (current_timestamp_iterator_position === null) { | |
return null; | |
} | |
if (look_ahead_timestamp_iterator_position === null) { | |
return null; | |
} | |
// ------------------ | |
// X | |
const x_offset = | |
(look_ahead_timestamp_iterator_position.x - current_timestamp_iterator_position.x) * percentage_through_current_timestep; | |
// ------------------ | |
// DEFAULT Position calculation | |
const interpolated_position: IPosition = { | |
...current_timestamp_iterator_position, | |
x: current_timestamp_iterator_position.x + x_offset, | |
}; | |
// console.log(`x_offset: ${x_offset}`); | |
// console.log(`current_timestamp_iterator_position.x: ${current_timestamp_iterator_position.x}`); | |
// console.log(`interpolated_position: ${x_offset}`); | |
// ------------------ | |
// Line Change Corner Case | |
const is_measure_a_line_change = current_timestamp_iterator_position.y !== look_ahead_timestamp_iterator_position.y; | |
if (is_measure_a_line_change) { | |
// End measure | |
if (percentage_through_current_timestep < 0.5) { | |
const width_offset = current_timestamp_iterator_position.width; | |
const current_timestamp_end_measure_position = calculateIteratorMeasureEndPosition( | |
open_sheet_music_display_object, | |
current_timestamp_iterator, | |
); | |
const current_percentage_through_end_measure = percentage_through_current_timestep / 0.5; | |
const x_distance_from_note_to_end_measure = | |
current_timestamp_end_measure_position.x - width_offset - current_timestamp_iterator_position.x; | |
const new_x_position = | |
current_timestamp_iterator_position.x + x_distance_from_note_to_end_measure * current_percentage_through_end_measure; | |
interpolated_position.x = new_x_position; | |
} | |
// Start measure | |
else { | |
const percentage_offset = percentage_through_current_timestep - 0.5; | |
const current_timestamp_start_measure_position = calculateIteratorMeasureStartPosition( | |
open_sheet_music_display_object, | |
look_ahead_timestamp_iterator, | |
); | |
const current_percentage_through_start_measure = percentage_offset / 0.5; | |
const x_distance_from_start_measure_to_note = | |
look_ahead_timestamp_iterator_position.x - current_timestamp_start_measure_position.x; | |
const new_x_position = | |
current_timestamp_start_measure_position.x + | |
x_distance_from_start_measure_to_note * current_percentage_through_start_measure; | |
interpolated_position.x = new_x_position; | |
interpolated_position.y = look_ahead_timestamp_iterator_position.y; | |
interpolated_position.width = look_ahead_timestamp_iterator_position.width; | |
interpolated_position.height = look_ahead_timestamp_iterator_position.height; | |
} | |
} | |
// ------------------ | |
// console.log(start_timestamp.getTime()); | |
// console.log(current_timestamp_to_use.getTime()); | |
// console.log(look_ahead_timestamp_iterator_position); | |
// console.log(percentage_through_current_timestep); | |
return interpolated_position; | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function getSheetMusicTempoInBPMForTimeStamp( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): null | number { | |
// console.log("-----------------------------------"); | |
// console.log("Getting TempoInBPM"); | |
let current_timestamp_to_use = current_timestamp; | |
const total_song_duration_in_milliseconds = calcuateTotalSongDurationInMilliseconds(open_sheet_music_display_object, tempo_override); | |
const time_difference = current_timestamp.getTime() - start_timestamp.getTime(); | |
// console.log("total_song_duration_in_milliseconds: " + total_song_duration_in_milliseconds); | |
// console.log("time_difference: " + time_difference); | |
if (time_difference < 0) { | |
// Time provided is < start time | |
// Set time to beginning of song | |
current_timestamp_to_use = start_timestamp; | |
} | |
if (time_difference > total_song_duration_in_milliseconds) { | |
// Time provided is > start time | |
// Set time to end of song | |
const new_current_timestamp = new Date(); | |
new_current_timestamp.setTime(start_timestamp.getTime() + total_song_duration_in_milliseconds); | |
current_timestamp_to_use = new_current_timestamp; | |
} | |
// TODO: error catch for bounds of start_timestamp and current_timestamp in order | |
// to make sure the helper isn't called with weird data | |
// ------------------------ | |
// For Debugging | |
// const new_current_timestamp = new Date(); | |
// new_current_timestamp.setTime(start_timestamp.getTime() + 3000); | |
// current_timestamp_to_use = new_current_timestamp; | |
// ------------------------ | |
const current_timestamp_iterator = getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
// ------------------ | |
// console.log(start_timestamp.getTime()); | |
// console.log(current_timestamp_to_use.getTime()); | |
// console.log(current_timestamp_iterator.CurrentMeasure); | |
if (current_timestamp_iterator.CurrentMeasure !== null && current_timestamp_iterator.CurrentMeasure !== undefined) { | |
return current_timestamp_iterator.CurrentMeasure.TempoInBPM; | |
} else { | |
return null; | |
} | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function getSheetMusicBeatsPerMeasureForTimeStamp( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): null | number { | |
// console.log("-----------------------------------"); | |
// console.log("Getting TimeSignature"); | |
let current_timestamp_to_use = current_timestamp; | |
const total_song_duration_in_milliseconds = calcuateTotalSongDurationInMilliseconds(open_sheet_music_display_object, tempo_override); | |
const time_difference = current_timestamp.getTime() - start_timestamp.getTime(); | |
// console.log("total_song_duration_in_milliseconds: " + total_song_duration_in_milliseconds); | |
// console.log("time_difference: " + time_difference); | |
if (time_difference < 0) { | |
// Time provided is < start time | |
// Set time to beginning of song | |
current_timestamp_to_use = start_timestamp; | |
} | |
if (time_difference > total_song_duration_in_milliseconds) { | |
// Time provided is > start time | |
// Set time to end of song | |
const new_current_timestamp = new Date(); | |
new_current_timestamp.setTime(start_timestamp.getTime() + total_song_duration_in_milliseconds); | |
current_timestamp_to_use = new_current_timestamp; | |
} | |
// TODO: error catch for bounds of start_timestamp and current_timestamp in order | |
// to make sure the helper isn't called with weird data | |
// ------------------------ | |
// For Debugging | |
// const new_current_timestamp = new Date(); | |
// new_current_timestamp.setTime(start_timestamp.getTime() + 3000); | |
// current_timestamp_to_use = new_current_timestamp; | |
// ------------------------ | |
const current_timestamp_iterator = getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
// ------------------ | |
// console.log(start_timestamp.getTime()); | |
// console.log(current_timestamp_to_use.getTime()); | |
// console.log(current_timestamp_iterator.CurrentMeasure); | |
if ( | |
current_timestamp_iterator.CurrentMeasure !== null && | |
current_timestamp_iterator.CurrentMeasure !== undefined && | |
current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature !== null && | |
current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature !== undefined | |
) { | |
return current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature.numerator; | |
} else { | |
return null; | |
} | |
} | |
/* | |
* @param tempo_override - override operation to use custom tempo instead of | |
* using sheet music defaults | |
*/ | |
export function getSheetMusicBeatSubdivisionForTimeStamp( | |
open_sheet_music_display_object: OpenSheetMusicDisplay, | |
start_timestamp: Date, | |
current_timestamp: Date, | |
tempo_override: null | number, | |
): null | number { | |
// console.log("-----------------------------------"); | |
// console.log("Getting TimeSignature"); | |
let current_timestamp_to_use = current_timestamp; | |
const total_song_duration_in_milliseconds = calcuateTotalSongDurationInMilliseconds(open_sheet_music_display_object, tempo_override); | |
const time_difference = current_timestamp.getTime() - start_timestamp.getTime(); | |
// console.log("total_song_duration_in_milliseconds: " + total_song_duration_in_milliseconds); | |
// console.log("time_difference: " + time_difference); | |
if (time_difference < 0) { | |
// Time provided is < start time | |
// Set time to beginning of song | |
current_timestamp_to_use = start_timestamp; | |
} | |
if (time_difference > total_song_duration_in_milliseconds) { | |
// Time provided is > start time | |
// Set time to end of song | |
const new_current_timestamp = new Date(); | |
new_current_timestamp.setTime(start_timestamp.getTime() + total_song_duration_in_milliseconds); | |
current_timestamp_to_use = new_current_timestamp; | |
} | |
// TODO: error catch for bounds of start_timestamp and current_timestamp in order | |
// to make sure the helper isn't called with weird data | |
// ------------------------ | |
// For Debugging | |
// const new_current_timestamp = new Date(); | |
// new_current_timestamp.setTime(start_timestamp.getTime() + 3000); | |
// current_timestamp_to_use = new_current_timestamp; | |
// ------------------------ | |
const current_timestamp_iterator = getOSMDIteratorAtCorrectTimeStamp( | |
open_sheet_music_display_object, | |
start_timestamp, | |
current_timestamp_to_use, | |
tempo_override, | |
); | |
// ------------------ | |
// console.log(start_timestamp.getTime()); | |
// console.log(current_timestamp_to_use.getTime()); | |
// console.log(current_timestamp_iterator.CurrentMeasure); | |
if ( | |
current_timestamp_iterator.CurrentMeasure !== null && | |
current_timestamp_iterator.CurrentMeasure !== undefined && | |
current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature !== null && | |
current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature !== undefined | |
) { | |
return current_timestamp_iterator.CurrentMeasure.ActiveTimeSignature.denominator; | |
} else { | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment