Skip to content

Instantly share code, notes, and snippets.

@loganknecht
Created October 29, 2022 07:30
Show Gist options
  • Save loganknecht/c374f5990e35b6ca636b696676325683 to your computer and use it in GitHub Desktop.
Save loganknecht/c374f5990e35b6ca636b696676325683 to your computer and use it in GitHub Desktop.
Piano Gym Cursor Example
// -----------------------------------------------------------------------------
// 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