|
@@ -35,6 +35,8 @@ export class ExpressionReader {
|
|
|
private openContinuousTempoExpression: ContinuousTempoExpression;
|
|
|
private activeInstantaneousDynamic: InstantaneousDynamicExpression;
|
|
|
private openOctaveShift: OctaveShift;
|
|
|
+ private lastWedge: ContinuousDynamicExpression;
|
|
|
+ private WedgeYPosXml: number;
|
|
|
private openPedal: Pedal;
|
|
|
private openWavyLine: WavyLine;
|
|
|
constructor(musicSheet: MusicSheet, instrument: Instrument, staffNumber: number) {
|
|
@@ -76,6 +78,21 @@ export class ExpressionReader {
|
|
|
} else { this.directionTimestamp = Fraction.createFromFraction(offsetFraction); }
|
|
|
}
|
|
|
|
|
|
+ // read default-y for wedge node
|
|
|
+ let newWedgeYPos: number;
|
|
|
+ const directionTypeNode: IXmlElement = xmlNode.element("direction-type");
|
|
|
+ let wedgeNode: IXmlElement;
|
|
|
+ if (directionTypeNode) {
|
|
|
+ wedgeNode = directionTypeNode.element("wedge");
|
|
|
+ if (wedgeNode) {
|
|
|
+ const yPosAttr: IXmlAttribute = wedgeNode.attribute("default-y");
|
|
|
+ if (yPosAttr) {
|
|
|
+ newWedgeYPos = this.readPosition(yPosAttr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.WedgeYPosXml = newWedgeYPos;
|
|
|
+
|
|
|
const placeAttr: IXmlAttribute = xmlNode.attribute("placement");
|
|
|
if (placeAttr) {
|
|
|
try {
|
|
@@ -92,11 +109,9 @@ export class ExpressionReader {
|
|
|
this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
this.placement = PlacementEnum.Below;
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
if (this.placement === PlacementEnum.NotYetDefined) {
|
|
|
try {
|
|
|
- const directionTypeNode: IXmlElement = xmlNode.element("direction-type");
|
|
|
if (directionTypeNode) {
|
|
|
const dynamicsNode: IXmlElement = directionTypeNode.element("dynamics");
|
|
|
if (dynamicsNode) {
|
|
@@ -105,7 +120,6 @@ export class ExpressionReader {
|
|
|
this.readExpressionPlacement(defAttr, "read dynamics y pos");
|
|
|
}
|
|
|
}
|
|
|
- const wedgeNode: IXmlElement = directionTypeNode.element("wedge");
|
|
|
if (wedgeNode) {
|
|
|
const defAttr: IXmlAttribute = wedgeNode.attribute("default-y");
|
|
|
if (defAttr) {
|
|
@@ -461,18 +475,30 @@ export class ExpressionReader {
|
|
|
return PlacementEnum.NotYetDefined;
|
|
|
}
|
|
|
}
|
|
|
- private readExpressionPlacement(defAttr: IXmlAttribute, catchLogMessage: string): void {
|
|
|
+ private readExpressionPlacement(yPosAttr: IXmlAttribute, catchLogMessage: string): void {
|
|
|
try {
|
|
|
- const y: number = parseInt(defAttr.value, 10);
|
|
|
+ const y: number = this.readPosition(yPosAttr);
|
|
|
if (y < 0) {
|
|
|
this.placement = PlacementEnum.Below;
|
|
|
} else if (y > 0) {
|
|
|
this.placement = PlacementEnum.Above;
|
|
|
- }
|
|
|
+ }
|
|
|
} catch (ex) {
|
|
|
log.debug("ExpressionReader.readExpressionParameters", catchLogMessage, ex);
|
|
|
}
|
|
|
-
|
|
|
+ }
|
|
|
+ private readPosition(posAttr: IXmlAttribute): number {
|
|
|
+ try {
|
|
|
+ const xOrY: number = parseInt(posAttr.value, 10);
|
|
|
+ if (xOrY < 0) {
|
|
|
+ this.placement = PlacementEnum.Below;
|
|
|
+ } else if (xOrY > 0) {
|
|
|
+ this.placement = PlacementEnum.Above;
|
|
|
+ }
|
|
|
+ return xOrY;
|
|
|
+ } catch (ex) {
|
|
|
+ log.debug("ExpressionReader.readExpressionParameters", ex);
|
|
|
+ }
|
|
|
}
|
|
|
private interpretInstantaneousDynamics(dynamicsNode: IXmlElement,
|
|
|
currentMeasure: SourceMeasure,
|
|
@@ -532,7 +558,9 @@ export class ExpressionReader {
|
|
|
}
|
|
|
private interpretWords(wordsNode: IXmlElement, currentMeasure: SourceMeasure, inSourceMeasureCurrentFraction: Fraction): void {
|
|
|
const text: string = wordsNode.value;
|
|
|
- if (currentMeasure.Rules.IgnoreBracketsWords && /^\(\s*\)$/.test(text)) { // regex: brackets with arbitrary white space in-between
|
|
|
+ if (currentMeasure.Rules.IgnoreBracketsWords && (
|
|
|
+ /^\(\s*\)$/.test(text) || /^\[\s*\]$/.test(text) // (*) and [*]
|
|
|
+ )) { // regex: brackets with arbitrary white space in-between
|
|
|
return;
|
|
|
}
|
|
|
let fontStyle: FontStyles;
|
|
@@ -567,9 +595,25 @@ export class ExpressionReader {
|
|
|
this.directionTimestamp = Fraction.createFromFraction(inSourceMeasureCurrentFraction);
|
|
|
}
|
|
|
const wedgeNumberXml: number = this.readNumber(wedgeNode);
|
|
|
+
|
|
|
+ const typeAttributeString: string = wedgeNode.attribute("type")?.value?.toLowerCase();
|
|
|
+
|
|
|
+ // check for duplicate
|
|
|
+ if (this.lastWedge && this.lastWedge.parentMeasure.MeasureNumberXML === currentMeasure.MeasureNumberXML &&
|
|
|
+ this.lastWedge.StaffNumber === this.staffNumber &&
|
|
|
+ this.placement === this.lastWedge.Placement &&
|
|
|
+ this.WedgeYPosXml !== undefined &&
|
|
|
+ this.lastWedge.YPosXml === this.WedgeYPosXml &&
|
|
|
+ this.lastWedge.StartMultiExpression.Timestamp.Equals(this.directionTimestamp) &&
|
|
|
+ this.lastWedge.DynamicType === ContDynamicEnum[typeAttributeString]
|
|
|
+
|
|
|
+ ) {
|
|
|
+ // duplicate, ignore
|
|
|
+ return;
|
|
|
+ }
|
|
|
//Ending needs to use previous fraction, not current.
|
|
|
//If current is used, when there is a system break it will mess up
|
|
|
- if (wedgeNode.attribute("type")?.value?.toLowerCase() === "stop") {
|
|
|
+ if (typeAttributeString === "stop") {
|
|
|
this.createNewMultiExpressionIfNeeded(currentMeasure, wedgeNumberXml, inSourceMeasureCurrentFraction);
|
|
|
} else {
|
|
|
this.createNewMultiExpressionIfNeeded(currentMeasure, wedgeNumberXml);
|
|
@@ -622,6 +666,8 @@ export class ExpressionReader {
|
|
|
currentMeasure,
|
|
|
this.activeInstantaneousDynamic,
|
|
|
numberXml);
|
|
|
+ this.lastWedge = continuousDynamicExpression;
|
|
|
+ this.lastWedge.YPosXml = this.WedgeYPosXml;
|
|
|
this.openContinuousDynamicExpressions.push(continuousDynamicExpression);
|
|
|
let multiExpression: MultiExpression = this.getMultiExpression;
|
|
|
if (!multiExpression) {
|