smoosic
Version:
<sub>[Github site](https://github.com/Smoosic/smoosic) | [source documentation](https://smoosic.github.io/Smoosic/release/docs/modules.html) | [change notes](https://aarondavidnewman.github.io/Smoosic/changes.html) | [application](https://smoosic.github.i
774 lines (755 loc) • 25.4 kB
text/typescript
// [Smoosic](https://github.com/AaronDavidNewman/Smoosic)
// Copyright (c) Aaron David Newman 2021.
/**
* A score modifier is anything that isn't mapped specifically to a musical object.
* This includes score text, layout information
* @module /smo/data/scoreModifier
*/
import { smoSerialize } from '../../common/serializationHelpers';
import { SmoMeasureFormat, SmoMeasureFormatParamsSer } from './measureModifiers';
import { SmoAttrs, getId, SmoModifierBase, SvgBox,
SmoDynamicCtor } from './common';
import { SmoMeasure } from './measure';
import { SmoSelector } from '../xform/selections';
import { dynamicCtorInit } from '../../application/dynamicInit';
/**
* Base class for all {@link SmoScore} modifiers.
* It is used to de/serialize the objects.
* @category SmoObject
*/
export abstract class SmoScoreModifierBase implements SmoModifierBase {
/**
* constructor
*
* @type {string}
* @memberof SmoScoreModifierBase
*/
ctor: string;
/**
* When rendered, keep track of the box
*
* @type {(SvgBox | null)}
* @memberof SmoScoreModifierBase
*/
logicalBox: SvgBox | null = null;
/**
* attributes for identification
*
* @type {SmoAttrs}
* @memberof SmoScoreModifierBase
*/
attrs: SmoAttrs;
constructor(ctor: string) {
this.ctor = ctor;
this.attrs = {
id: getId().toString(),
type: ctor
};
}
abstract serialize(): any;
static deserialize(jsonObj: any) {
const rv = SmoDynamicCtor[jsonObj.ctor](jsonObj);
return rv;
}
}
/**
* For global/default font settings.
* @category SmoObject
* @param name to distinguish: chord, lyric etc.
* @param family font family
* @param size in points
* @param custom used to distinguish a specific text is not the default
*/
export interface FontPurpose {
/**
* name of the purpose
* { ENGRAVING: 1, SCORE: 2, CHORDS: 3, LYRICS: 4 }
*/
name: string,
/**
* purpose enumeration
*/
purpose: number,
/**
* font family
*/
family: string,
/**
* default font size
*/
size: number,
/**
* a flag that can be used to indicate if this is the global default, or a customization.
* For lyrics for instance, most lyrics would use the custom font, this would be true if
* it was overridden
*/
custom: boolean
}
// @internal
export type SmoScoreInfoKey = 'name' | 'title' | 'subTitle' | 'composer' | 'copyright';
export const SmoScoreInfoKeys = ['name', 'title', 'subTitle', 'composer', 'copyright'];
/**
* Information about the score itself, like composer etc.
* @category SmoObject
*/
export interface SmoScoreInfo {
/**
* deprecated, now defaults to title
*/
name: string,
/**
* name of score
*/
title: string,
/**
* subtitle/opus
*/
subTitle: string,
/**
* who wrote it
*/
composer: string,
/**
* copyright information
*/
copyright: string,
/**
* for version tracking
*/
version: number
}
export type SmoScorePreferenceBool = 'autoPlay' | 'autoAdvance' | 'showPiano' | 'hideEmptyLines' | 'transposingScore' | 'autoScrollPlayback';
export type SmoScorePreferenceNumber = 'defaultDupleDuration' | 'defaultTripleDuration';
export const SmoScorePreferenceBools: SmoScorePreferenceBool[] = ['autoPlay', 'autoAdvance', 'showPiano', 'hideEmptyLines',
'transposingScore', 'autoScrollPlayback'];
export const SmoScorePreferenceNumbers: SmoScorePreferenceNumber[] = ['defaultDupleDuration', 'defaultTripleDuration'];
/**
* Global score/program behavior preferences, see below for parameters
* @category SmoObject
*/
export interface SmoScorePreferencesParams {
autoPlay: boolean;
autoAdvance: boolean;
autoScrollPlayback: boolean;
defaultDupleDuration: number;
defaultTripleDuration: number;
showPiano: boolean;
hideEmptyLines: boolean;
transposingScore: boolean;
}
/**
* Some default SMO behavior
* @param autoPlay play a new note or chord
* @param autoAdvance Sibelius-like behavior of advancing cursor when a letter note is placed
* @param defaultDupleDuration in ticks, even metered measures
* @param defaultTripleDuration in ticks, 6/8 etc.
* @param showPiano show the piano widget in the score
* @param hideEmptyLines Hide empty lines in full score
* @param transposingScore Whether to show the score parts in concert key
* @category SmoObject
*/
export class SmoScorePreferences {
autoPlay: boolean = true;
autoAdvance: boolean = true;
defaultDupleDuration: number = 4096;
defaultTripleDuration: number = 6144;
showPiano: boolean = false;
hideEmptyLines: boolean = false;
autoScrollPlayback: boolean = true;
transposingScore: boolean = false;
static get defaults(): SmoScorePreferencesParams {
return {
autoPlay: true,
autoAdvance: true,
defaultDupleDuration: 4096,
defaultTripleDuration: 6144,
autoScrollPlayback: true,
showPiano: false,
hideEmptyLines: false,
transposingScore: false
};
}
constructor(params: SmoScorePreferencesParams) {
if (params) {
SmoScorePreferenceBools.forEach((bb) => {
this[bb] = params[bb];
});
SmoScorePreferenceNumbers.forEach((nn) => {
this[nn] = params[nn];
});
// legacy, added later
if (typeof(params.autoScrollPlayback) === 'undefined') {
this.autoScrollPlayback = true;
}
}
}
serialize(): SmoScorePreferencesParams {
return {
...this
}
}
}
/**
* non-musical information about the score
* @category serialization
*/
export interface ScoreMetadataSer {
fonts: FontPurpose[],
preferences: SmoScorePreferencesParams,
renumberingMap: Record<string, string>,
scoreInfo: SmoScoreInfo
}
/**
* Map of measure formatting to measure IDs. We only save non-default formats
* @category SmoObject
* @param measureFormats
* @param partIndex
*/
export interface SmoFormattingManagerParams {
/**
* map of index to {@link SmoMeasureFormat} objects
*/
measureFormats?: SmoMeasureFormat[],
/**
* the associated part, or -1 for the score
*/
partIndex?: number
}
/**
* A score can have different views - one for the score itself and one for each
* part, and each part can have its own formatting and text.
* *Note*: I may move this to part info module.
* @param measureFormats map of index to {@link SmoMeasureFormat} objects
* @param partIndex the associated part, or -1 for the score
* @category SmoObject
*/
export class SmoFormattingManager extends SmoScoreModifierBase {
measureFormats: Record<number, SmoMeasureFormat>;
partIndex: number = -1;
static get forScore() {
return -1;
}
static get defaults(): SmoFormattingManagerParams {
return {
measureFormats: [new SmoMeasureFormat(SmoMeasureFormat.defaults)],
partIndex: -1
};
}
constructor(params: SmoFormattingManagerParams) {
super('SmoFormattingManager');
if (typeof (params) === 'undefined') {
params = {};
}
this.measureFormats = {};
this.partIndex = SmoFormattingManager.forScore;
if (typeof (params.partIndex) !== 'undefined') {
this.partIndex = params.partIndex;
}
if (typeof (params.measureFormats) !== 'undefined' && params.measureFormats.length) {
params.measureFormats.forEach((format) => {
// 0 is default value, so fix case of first measure
if (typeof(format.measureIndex) !== 'number') {
format.measureIndex = 0;
}
this.measureFormats[format.measureIndex] = new SmoMeasureFormat(format);
});
}
}
/**
* Update the measure format for the measure at the given index
* @param format
*/
updateMeasureFormat(format: SmoMeasureFormat) {
this.measureFormats[format.measureIndex] = format;
}
/**
* Update the measure format based on the format of a given measure
* @param measure
*/
updateFormat(measure: SmoMeasure) {
if (this.measureFormats[measure.measureNumber.measureIndex]) {
measure.format = this.measureFormats[measure.measureNumber.measureIndex];
} else {
measure.format = new SmoMeasureFormat(SmoMeasureFormat.defaults);
}
}
serialize(): SmoMeasureFormatParamsSer[] {
const rv: SmoMeasureFormatParamsSer[] = [];
const keys = Object.keys(this.measureFormats);
keys.forEach((key: any) => {
if (!this.measureFormats[key].isDefault) {
rv.push(this.measureFormats[key].serialize());
}
});
return rv;
}
}
export type SmoAudioPlayerType = 'sampler' | 'synthesizer';
/**
* Constructor parameters for audio player
* @category SmoObject
*/
export interface SmoAudioPlayerParameters {
playerType?: SmoAudioPlayerType,
waveform?: OscillatorType,
reverbEnable?: boolean,
reverbDelay?: number,
reverbDecay?: number
}
/**
* web audio API defines this
* @param otype
* @returns
*/
export function IsOscillatorType(otype: OscillatorType | string): otype is OscillatorType {
return ['sine', 'square', 'sawtooth', 'triangle', 'custom'].findIndex((x) => x === otype) >= 0;
}
/**
* Audio playback parameters. Just fun stuff.
* @category SmoObject
*/
export class SmoAudioPlayerSettings extends SmoScoreModifierBase {
static get defaults(): SmoAudioPlayerParameters {
return ({
playerType: 'sampler',
waveform: 'sine',
reverbEnable: true,
reverbDelay: 0.5,
reverbDecay: 2
});
}
static get attributes() {
return ['playerType', 'waveform', 'reverbEnable', 'reverbDelay', 'reverbDecay'];
}
playerType: SmoAudioPlayerType = 'sampler';
waveform: OscillatorType = 'sine';
reverbEnable: boolean = true;
reverbDelay: number = 0.2;
reverbDecay: number = 0.5;
constructor(params: SmoAudioPlayerParameters) {
super('SmoAudioPlayerSettings');
smoSerialize.serializedMerge(SmoAudioPlayerSettings.attributes, SmoAudioPlayerSettings.defaults, this);
smoSerialize.serializedMerge(SmoAudioPlayerSettings.attributes, params, this);
}
serialize(): any {
const params: any = {};
smoSerialize.serializedMergeNonDefault(SmoAudioPlayerSettings.defaults, SmoAudioPlayerSettings.attributes, this, params);
params.ctor = 'SmoAudioPlayerSettings';
return params;
}
}
export type ScaledPageAttributes = 'leftMargin' | 'rightMargin' | 'topMargin' | 'bottomMargin' | 'interGap' | 'intraGap';
/**
* Constructor parameters for {@link SmoPageLayout}, part of {@link SmoLayoutManager}
* @category SmoObject
*/
export interface SmoPageLayoutParams {
leftMargin: number,
rightMargin: number,
topMargin: number,
bottomMargin: number,
interGap: number,
intraGap: number
}
/**
* Define margins and other layout information associated with a specific page, and may
* be different on different pages.
* @category SmoObject
*/
export class SmoPageLayout extends SmoScoreModifierBase {
static get defaults(): SmoPageLayoutParams {
return JSON.parse(JSON.stringify({
leftMargin: 30,
rightMargin: 30,
topMargin: 144,
bottomMargin: 72,
interGap: 30,
intraGap: 10
}));
}
static get attributes(): ScaledPageAttributes[] {
return ['leftMargin', 'rightMargin', 'topMargin', 'bottomMargin', 'interGap', 'intraGap'];
}
leftMargin: number = 30;
rightMargin: number = 30;
topMargin: number = 40;
bottomMargin: number = 40;
interGap: number = 30;
intraGap: number = 10;
constructor(params: SmoPageLayoutParams) {
super('SmoPageLayout');
this.leftMargin = params.leftMargin;
this.rightMargin = params.rightMargin;
this.topMargin = params.topMargin;
this.bottomMargin = params.bottomMargin;
this.interGap = params.interGap;
this.intraGap = params.intraGap;
}
serialize(): any {
const params: any = {};
smoSerialize.serializedMergeNonDefault(SmoPageLayout.defaults, SmoPageLayout.attributes, this, params);
params.ctor = 'SmoPageLayout';
return params;
}
}
export type ScaledGlobalAttributes = 'pageWidth' | 'pageHeight';
export type GlobalLayoutAttributes = 'pageWidth' | 'pageHeight' | 'noteSpacing' | 'svgScale' | 'zoomScale' | 'proportionality' | 'maxMeasureSystem';
export const GlobalLayoutAttributesArray: GlobalLayoutAttributes[] = ['pageWidth', 'pageHeight', 'noteSpacing', 'svgScale', 'zoomScale', 'proportionality', 'maxMeasureSystem'];
/**
* Global layout are parameters that determine the layout of the whole score, because they affect the containing svg element
* @category SmoObject
*/
export interface SmoGlobalLayout {
svgScale: number;
zoomScale: number;
noteSpacing: number;
pageWidth: number;
pageHeight: number;
proportionality: number,
maxMeasureSystem: number
}
/**
* Used to create {@link SmoLayoutManagerParams}
* @category SmoObject
*/
export interface ScaledPageLayout {
svgScale: number;
zoomScale: number;
noteSpacing: number;
pageWidth: number;
pageHeight: number;
leftMargin: number;
rightMargin: number;
topMargin: number;
bottomMargin: number;
interGap: number;
intraGap: number;
pages: number;
maxMeasureSystem: number;
}
/**
* Constructor parameters for {@link SmoLayoutManager}
* @category SmoObject
*/
export interface SmoLayoutManagerParams {
/**
* global svg settings for zoom, page width/height
*/
globalLayout: SmoGlobalLayout,
/**
* page margins for each page
*/
pageLayouts: SmoPageLayout[]
}
/**
* @category serialization
*/
export interface SmoLayoutManagerParamsSer {
/**
* constructor
*/
ctor: string;
/**
* global svg settings for zoom, page width/height
*/
globalLayout: SmoGlobalLayout,
/**
* page margins for each page
*/
pageLayouts: SmoPageLayoutParams[]
}
function isSmoLayoutManagerParamsSer(params: Partial<SmoLayoutManagerParamsSer>): params is SmoLayoutManagerParamsSer {
if (!params.ctor || params.ctor !== 'SmoLayoutManager') {
return false;
}
return true;
}
/**
* Storage and utilities for layout information in the score. Each
* manager has one set of page height/width, since svg element
* must have single length/width and viewbox.
* Each page can have different margins.
* @category SmoObject
*/
export class SmoLayoutManager extends SmoScoreModifierBase {
static get defaultLayout(): SmoGlobalLayout {
return {
svgScale: 0.55,
zoomScale: 2.0,
noteSpacing: 1.0,
pageWidth: 8 * 96 + 48,
pageHeight: 11 * 96,
proportionality: 5,
maxMeasureSystem: 0
};
}
static get defaults(): SmoLayoutManagerParams {
return {
globalLayout: JSON.parse(JSON.stringify(SmoLayoutManager.defaultLayout)),
pageLayouts: []
};
}
static get attributes(): GlobalLayoutAttributes[] {
return ['pageWidth', 'pageHeight', 'noteSpacing', 'svgScale', 'zoomScale', 'maxMeasureSystem'];
}
// Attributes that are scaled by svgScale
/* static get scalableAttributes(): Global {
return ['pageWidth', 'pageHeight'];
}*/
static get scaledPageAttributes(): ScaledPageAttributes[] {
return ['leftMargin', 'rightMargin', 'topMargin', 'bottomMargin', 'interGap', 'intraGap'];
}
static get scaledGlobalAttributes(): ScaledGlobalAttributes[] {
return ['pageWidth', 'pageHeight'];
}
static areLayoutsEqual(g1: SmoGlobalLayout, g2: SmoGlobalLayout) {
let rv = true;
GlobalLayoutAttributesArray.forEach((attr) => {
if (g1[attr] !== g2[attr]) {
rv = false;
}
});
return rv;
}
static isZoomChange(g1: SmoGlobalLayout, g2: SmoGlobalLayout) {
let rv = true;
GlobalLayoutAttributesArray.forEach((attr) => {
if (g1[attr] !== g2[attr] && attr !== 'zoomScale') {
rv = false;
}
});
return rv;
}
/**
* Adjust zoom width so the score takes up the whole score area
*/
zoomToWidth(screenWidth: number) {
const curWidth = this.globalLayout.pageWidth * this.globalLayout.svgScale;
this.globalLayout.zoomScale = ((screenWidth - 350) / curWidth) * this.globalLayout.svgScale; // magic 350 for left controls....TODO standardize this
}
static getScaledPageLayout(globalLayout: SmoGlobalLayout, pageLayout: SmoPageLayout, pages: number): ScaledPageLayout {
const rv: Partial<ScaledPageLayout> = {};
SmoLayoutManager.scaledPageAttributes.forEach((attr: ScaledPageAttributes) => {
rv[attr] = pageLayout[attr] / globalLayout.svgScale;
});
SmoLayoutManager.scaledGlobalAttributes.forEach((attr: ScaledGlobalAttributes) => {
rv[attr] = globalLayout[attr] / globalLayout.svgScale;
});
// Note spacing is relative, so * it and not divide
rv.noteSpacing = globalLayout.noteSpacing * globalLayout.svgScale;
rv.svgScale = globalLayout.svgScale;
rv.zoomScale = globalLayout.zoomScale;
rv.maxMeasureSystem = globalLayout.maxMeasureSystem;
return rv as ScaledPageLayout;
}
globalLayout: SmoGlobalLayout;
pageLayouts: SmoPageLayout[] = [];
constructor(params: SmoLayoutManagerParams) {
super('SmoLayoutManager');
if (typeof(params.globalLayout.maxMeasureSystem) === 'undefined') {
params.globalLayout.maxMeasureSystem = SmoLayoutManager.defaultLayout.maxMeasureSystem;
}
this.globalLayout = JSON.parse(JSON.stringify(params.globalLayout));
if (params.pageLayouts.length) {
params.pageLayouts.forEach((plp) => {
const pageParams: SmoPageLayoutParams = SmoPageLayout.defaults;
SmoPageLayout.attributes.forEach((attr) => {
if (typeof (plp[attr]) !== 'undefined') {
pageParams[attr] = plp[attr];
}
});
this.pageLayouts.push(new SmoPageLayout(pageParams));
});
} else {
this.pageLayouts.push(new SmoPageLayout(SmoPageLayout.defaults));
}
}
trimPages(pageCount: number) {
if (pageCount < this.pageLayouts.length - 1) {
this.pageLayouts = this.pageLayouts.slice(0, pageCount + 1);
}
}
getZoomScale() {
return this.globalLayout.zoomScale;
}
serialize(): SmoLayoutManagerParamsSer {
const rv: Partial<SmoLayoutManagerParamsSer> = { ctor: 'SmoLayoutManager' };
rv.pageLayouts = [];
this.pageLayouts.forEach((pl) => {
rv.pageLayouts!.push(pl.serialize());
});
rv.globalLayout = JSON.parse(JSON.stringify(this.globalLayout));
if (!isSmoLayoutManagerParamsSer(rv)) {
throw 'bad layout manager ' + JSON.stringify(rv);
}
return rv;
}
updateGlobalLayout(params: SmoGlobalLayout) {
SmoLayoutManager.attributes.forEach((attr: string) => {
if (typeof ((params as any)[attr]) !== 'undefined') {
(this.globalLayout as any)[attr] = (params as any)[attr];
}
});
}
// ### addToPageLayouts
// Make sure the next page has a layout. If not, copy settings from
// previous page.
addToPageLayouts(pageNum: number) {
const lastLayout = this.pageLayouts[this.pageLayouts.length - 1];
if (this.pageLayouts.length <= pageNum) {
this.pageLayouts.push(new SmoPageLayout(lastLayout));
}
}
getGlobalLayout(): SmoGlobalLayout {
return JSON.parse(JSON.stringify(this.globalLayout));
}
// Return a deep copy of the page parameters, adjusted for the global scale.
getScaledPageLayout(pageIndex: number): ScaledPageLayout {
return SmoLayoutManager.getScaledPageLayout(this.globalLayout, this.pageLayouts[pageIndex], this.pageLayouts.length);
}
getPageLayout(pageIndex: number): SmoPageLayout {
return new SmoPageLayout(this.pageLayouts[pageIndex]);
}
getPageLayouts(): SmoPageLayout[] {
const rv: SmoPageLayout[] = [];
this.pageLayouts.forEach((pl) => {
rv.push(new SmoPageLayout(pl));
});
return rv;
}
updatePage(pageLayout: SmoPageLayout, pageIndex: number) {
if (this.pageLayouts.length > pageIndex) {
this.pageLayouts[pageIndex] = new SmoPageLayout(pageLayout);
}
}
}
/**
* constructor parameters for system groups (groupings of staves in the score)
* @param leftConnector
* @param rightConnector
* @param mapType
* @param text
* @param shortText
* @param justify
* @param startSelector not used
* @param endSelector not used
* @category SmoObject
*/
export interface SmoSystemGroupParams {
/**
* bracket etc.
*/
leftConnector: number,
/**
* bracket etc.
*/
rightConnector: number,
/**
* future, score groups can be different for different parts of the score
*/
mapType: number,
/**
* whether to justify the notes in the group
*/
justify: boolean,
/**
* if mapped to a range, start
*/
startSelector: SmoSelector,
/**
* if mapped to a range, end
*/
endSelector: SmoSelector
}
/**
* @category serialization
*/
export interface SmoSystemGroupParamsSer extends SmoSystemGroupParams{
/**
* constructor
*/
ctor: string;
}
function isSmoSystemGroupParamsSer(params: Partial<SmoSystemGroupParamsSer>): params is SmoSystemGroupParamsSer {
if (params.ctor === 'SmoSystemGroup') {
return true;
}
return false;
}
/**
* System group is the grouping of staves into a system.
* @category SmoObject
* */
export class SmoSystemGroup extends SmoScoreModifierBase {
static get connectorTypes(): Record<string, number> {
return { brace: 0, bracket: 1, single: 2, double: 3 };
}
static get mapTypes(): Record<string, number> {
return { allMeasures: 0, range: 1 };
}
static get attributes(): string[] {
return ['leftConnector', 'rightConnector', 'text', 'shortText', 'justify',
'startSelector', 'endSelector', 'mapType'];
}
static get defaults(): SmoSystemGroupParams {
return JSON.parse(JSON.stringify({
leftConnector: SmoSystemGroup.connectorTypes.single,
rightConnector: SmoSystemGroup.connectorTypes.single,
mapType: SmoSystemGroup.mapTypes.allMeasures,
justify: true,
startSelector: SmoSelector.default,
endSelector: SmoSelector.default
}));
}
static isSystemGroup(modifier: SmoSystemGroup | SmoModifierBase): modifier is SmoSystemGroup {
return modifier.ctor === 'SmoSystemGroup';
}
leftConnector: number = SmoSystemGroup.connectorTypes.single;
rightConnector: number = SmoSystemGroup.connectorTypes.single;
mapType: number = SmoSystemGroup.mapTypes.allMeasures;
text: string = '';
shortText: string = '';
justify: boolean = true;
startSelector: SmoSelector = SmoSelector.default;
endSelector: SmoSelector = SmoSelector.default;
attrs: SmoAttrs;
constructor(params: SmoSystemGroupParams) {
super('SmoSystemGroup');
smoSerialize.serializedMerge(SmoSystemGroup.attributes, SmoSystemGroup.defaults, this);
smoSerialize.serializedMerge(SmoSystemGroup.attributes, params, this);
this.attrs = {
id: getId().toString(),
type: 'SmoSystemGroup'
};
}
stavesOverlap(group: SmoSystemGroup) {
return (this.startSelector.staff >= group.startSelector.staff && this.startSelector.staff <= group.endSelector.staff) ||
(this.endSelector.staff >= group.startSelector.staff && this.endSelector.staff <= group.endSelector.staff);
}
measuresOverlap(group: SmoSystemGroup) {
return this.stavesOverlap(group) &&
((this.startSelector.measure >= group.startSelector.measure && this.endSelector.measure <= group.startSelector.measure) ||
(this.endSelector.measure >= group.startSelector.measure && this.endSelector.measure <= group.endSelector.measure));
}
overlaps(group: SmoSystemGroup) {
return (this.stavesOverlap(group) && this.mapType === SmoSystemGroup.mapTypes.allMeasures) ||
(this.measuresOverlap(group) && this.mapType === SmoSystemGroup.mapTypes.range);
}
serialize(): SmoSystemGroupParamsSer {
const params: Partial<SmoSystemGroupParamsSer> = {};
smoSerialize.serializedMergeNonDefault(SmoSystemGroup.defaults, SmoSystemGroup.attributes, this, params);
params.ctor = 'SmoSystemGroup';
if (!isSmoSystemGroupParamsSer(params)) {
throw 'bad system group ' + JSON.stringify(params);
}
return params;
}
}
export const scoreModifierDynamicCtorInit = () => {
SmoDynamicCtor['SmoScorePreferences'] = (params: SmoScorePreferencesParams) => new SmoScorePreferences(params);
SmoDynamicCtor['SmoFormattingManager'] = (params: SmoFormattingManagerParams) => new SmoFormattingManager(params);
SmoDynamicCtor['SmoAudioPlayerSettings'] = (params: SmoAudioPlayerParameters) => new SmoAudioPlayerSettings(params);
SmoDynamicCtor['SmoPageLayout'] = (params: SmoPageLayoutParams) => new SmoPageLayout(params);
SmoDynamicCtor['SmoLayoutManager'] = (params: SmoLayoutManagerParams) => new SmoLayoutManager(params);
SmoDynamicCtor['SmoSystemGroup'] = (params: SmoSystemGroupParams) => new SmoSystemGroup(params);
}