@@ -693,32 +693,48 @@ export abstract class LineBarRenderer extends BarRendererBase {
693693 continue ;
694694 }
695695
696- const beatLineX : number = this . getBeatX ( beat , BeatXPosition . Stem ) ;
696+ const stemX : number = this . getBeatX ( beat , BeatXPosition . Stem ) ;
697697 let y1 : number = cy + this . y ;
698698 if ( direction === BeamDirection . Up ) {
699699 y1 += this . getFlagBottomY ( beat , direction ) ;
700700 } else {
701701 y1 += this . getFlagTopY ( beat , direction ) ;
702702 }
703703
704- // ensure we are pixel aligned on the end of the stem to avoid anti-aliasing artifacts
705- // when combining stems and beams on sub-pixel level
706- const y2 : number = ( cy + this . y + this . calculateBeamY ( h , beatLineX ) ) | 0 ;
704+ const y2 : number = cy + this . y + this . calculateBeamY ( h , stemX ) ;
705+
706+ // improve subpixel related artifacts on stem/beam overlaps
707+ let stemY1 : number ;
708+ let stemY2 : number ;
709+ if ( y1 < y2 ) {
710+ stemY1 = y1 ;
711+ stemY2 = y2 ;
712+ } else {
713+ stemY1 = y2 ;
714+ stemY2 = y1 ;
715+ }
716+
717+ if ( direction === BeamDirection . Up ) {
718+ stemY1 = Math . ceil ( stemY1 ) ;
719+ } else {
720+ stemY2 = Math . floor ( stemY2 ) ;
721+ }
707722
708723 if ( y1 < y2 ) {
709- this . paintBeamingStem ( beat , cy + this . y , cx + this . x + beatLineX , y1 , y2 , canvas ) ;
724+ this . paintBeamingStem ( beat , cy + this . y , cx + this . x + stemX , stemY1 , stemY2 , canvas ) ;
710725 } else {
711- this . paintBeamingStem ( beat , cy + this . y , cx + this . x + beatLineX , y2 , y1 , canvas ) ;
726+ this . paintBeamingStem ( beat , cy + this . y , cx + this . x + stemX , stemY2 , stemY1 , canvas ) ;
712727 }
713728
714729 using _ = ElementStyleHelper . beat ( canvas , beamsElement , beat ) ;
715730
716731 const brokenBarOffset : number = this . smuflMetrics . brokenBeamWidth * scaleMod ;
717732 const barCount : number = ModelUtils . getIndex ( beat . duration ) - 2 ;
718733 const barStart : number = cy + this . y ;
734+ const stemThickness = this . smuflMetrics . stemThickness ;
719735
720736 for ( let barIndex : number = 0 ; barIndex < barCount ; barIndex ++ ) {
721- let barStartX : number = 0 ;
737+ let barStartX : number = Math . floor ( stemX + stemThickness ) ;
722738 let barEndX : number = 0 ;
723739 let barStartY : number = 0 ;
724740 let barEndY : number = 0 ;
@@ -737,8 +753,7 @@ export abstract class LineBarRenderer extends BarRendererBase {
737753 beat . beamingMode === BeatBeamingMode . ForceSplitOnSecondaryToNext
738754 ) {
739755 // start part
740- barStartX = beatLineX ;
741- barEndX = barStartX + brokenBarOffset ;
756+ barEndX = Math . ceil ( barStartX + brokenBarOffset ) ;
742757 barStartY = barY + this . calculateBeamY ( h , barStartX ) ;
743758 barEndY = barY + this . calculateBeamY ( h , barEndX ) ;
744759 LineBarRenderer . paintSingleBar (
@@ -751,8 +766,8 @@ export abstract class LineBarRenderer extends BarRendererBase {
751766 ) ;
752767
753768 // end part
754- barEndX = this . getBeatX ( h . beats [ i + 1 ] , BeatXPosition . Stem ) ;
755- barStartX = barEndX - brokenBarOffset ;
769+ barEndX = Math . floor ( this . getBeatX ( h . beats [ i + 1 ] , BeatXPosition . Stem ) ) ;
770+ barStartX = Math . floor ( barEndX - brokenBarOffset ) ;
756771 barStartY = barY + this . calculateBeamY ( h , barStartX ) ;
757772 barEndY = barY + this . calculateBeamY ( h , barEndX ) ;
758773 LineBarRenderer . paintSingleBar (
@@ -766,24 +781,15 @@ export abstract class LineBarRenderer extends BarRendererBase {
766781 } else {
767782 if ( isFullBarJoin ) {
768783 // full bar?
769- barStartX = beatLineX ;
770- barEndX = this . getBeatX ( h . beats [ i + 1 ] , BeatXPosition . Stem ) ;
784+ barEndX = Math . ceil ( this . getBeatX ( h . beats [ i + 1 ] , BeatXPosition . Stem ) ) ;
771785 } else if ( i === 0 || ! BeamingHelper . isFullBarJoin ( h . beats [ i - 1 ] , beat , barIndex ) ) {
772- barStartX = beatLineX ;
773- barEndX = barStartX + brokenBarOffset ;
786+ barEndX = Math . ceil ( barStartX + brokenBarOffset ) ;
774787 } else {
775788 continue ;
776789 }
777790 barStartY = barY + this . calculateBeamY ( h , barStartX ) ;
778791 barEndY = barY + this . calculateBeamY ( h , barEndX ) ;
779792
780- // ensure we are pixel aligned on the end of the stem to avoid anti-aliasing artifacts
781- // when combining stems and beams on sub-pixel level
782- if ( barIndex === 0 ) {
783- barStartY = barStartY | 0 ;
784- barEndY = barEndY | 0 ;
785- }
786-
787793 LineBarRenderer . paintSingleBar (
788794 canvas ,
789795 cx + this . x + barStartX ,
@@ -794,9 +800,8 @@ export abstract class LineBarRenderer extends BarRendererBase {
794800 ) ;
795801 }
796802 } else if ( i > 0 && ! BeamingHelper . isFullBarJoin ( beat , h . beats [ i - 1 ] , barIndex ) ) {
797- barStartX = beatLineX - brokenBarOffset ;
798- barEndX = beatLineX ;
799- barEndX = beatLineX ;
803+ barEndX = Math . ceil ( stemX ) ;
804+ barStartX = Math . floor ( stemX - brokenBarOffset ) ;
800805 barStartY = barY + this . calculateBeamY ( h , barStartX ) ;
801806 barEndY = barY + this . calculateBeamY ( h , barEndX ) ;
802807 LineBarRenderer . paintSingleBar (
@@ -811,6 +816,19 @@ export abstract class LineBarRenderer extends BarRendererBase {
811816 }
812817 }
813818
819+ // const firstStartX = this.getBeatX(h.beats[0], BeatXPosition.Stem);
820+ // const firstStartY = this.calculateBeamY(h, firstStartX);
821+ // const lastEndX = this.getBeatX(h.beats[h.beats.length - 1], BeatXPosition.Stem);
822+ // const lastEndY = this.calculateBeamY(h, lastEndX);
823+ // canvas.lineWidth = 0.5;
824+ // const c = canvas.color;
825+ // canvas.color = new Color(255, 0, 0);
826+ // canvas.moveTo(cx + this.x + firstStartX, cy + this.y + firstStartY);
827+ // canvas.lineTo(cx + this.x + lastEndX, cy + this.y + lastEndY);
828+ // canvas.stroke();
829+ // canvas.lineWidth = 1;
830+ // canvas.color = c;
831+
814832 if ( h . graceType === GraceType . BeforeBeat ) {
815833 const beatLineX : number = this . getBeatX ( h . beats [ 0 ] , BeatXPosition . Stem ) ;
816834 const flagWidth =
0 commit comments