Skip to content

Commit

Permalink
feat: Add Beat Barré
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielku15 committed Nov 10, 2024
1 parent 06b4ea0 commit f6088c6
Show file tree
Hide file tree
Showing 16 changed files with 270 additions and 11 deletions.
18 changes: 18 additions & 0 deletions src.csharp/AlphaTab/Core/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using AlphaTab.Core.EcmaScript;

Expand Down Expand Up @@ -487,6 +488,23 @@ public static string[] Split(this string value, RegExp pattern)
return pattern.Split(value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string Repeat(this string value, double count)
{
var icount = (int)count;
if (icount == 0)
{
return "";
}

var builder = new StringBuilder(value.Length * icount);
for (var i = 0; i < icount; i++)
{
builder.Append(value);
}
return builder.ToString();
}

public static Task CreatePromise(Action<Action, Action<object>> run)
{
var taskCompletionSource = new TaskCompletionSource<object?>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,8 @@ internal fun <T> Deferred<T>.catch(callback: (alphaTab.core.ecmaScript.Error) ->
@OptIn(ExperimentalUnsignedTypes::class)
internal val ArrayBuffer.byteLength: Int
get() = this.size

internal fun String.repeat(count:Double): String {
return this.repeat(count.toInt())
}

4 changes: 3 additions & 1 deletion src/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import { SustainPedalEffectInfo } from './rendering/effects/SustainPedalEffectIn
import { GolpeEffectInfo } from './rendering/effects/GolpeEffectInfo';
import { GolpeType } from './model/GolpeType';
import { WahPedalEffectInfo } from './rendering/effects/WahPedalEffectInfo';
import { BeatBarreEffectInfo } from './rendering/effects/BeatBarreEffectInfo';

export class LayoutEngineFactory {
public readonly vertical: boolean;
Expand Down Expand Up @@ -509,7 +510,8 @@ export class Environment {
// Score (standard notation)
new EffectBarRendererFactory(Environment.StaffIdBeforeScoreAlways, [
new FermataEffectInfo(),
new WahPedalEffectInfo()
new BeatBarreEffectInfo(),
new WahPedalEffectInfo(),
]),
new EffectBarRendererFactory(
Environment.StaffIdBeforeScoreHideable,
Expand Down
7 changes: 6 additions & 1 deletion src/NotationSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,12 @@ export enum NotationElement {
/**
* The Wah effect signs above and below the staff.
*/
EffectWahPedal
EffectWahPedal,

/**
* The Beat barre effect signs above and below the staff "1/2B IV ─────┐"
*/
BeatBarre
}

/**
Expand Down
13 changes: 13 additions & 0 deletions src/exporter/GpifWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MidiUtils } from '@src/midi/MidiUtils';
import { AccentuationType } from '@src/model/AccentuationType';
import { AutomationType } from '@src/model/Automation';
import { Bar, SustainPedalMarkerType } from '@src/model/Bar';
import { BarreShape } from '@src/model/BarreShape';
import { Beat } from '@src/model/Beat';
import { BendPoint } from '@src/model/BendPoint';
import { BrushType } from '@src/model/BrushType';
Expand Down Expand Up @@ -819,6 +820,18 @@ export class GpifWriter {
this.writeSimplePropertyNode(beatProperties, 'VibratoWTremBar', 'Strength', 'Slight');
break;
}

if (beat.isBarre) {
this.writeSimplePropertyNode(beatProperties, 'BarreFret', 'Fret', beat.barreFret.toString());
switch (beat.barreShape) {
case BarreShape.Full:
this.writeSimplePropertyNode(beatProperties, 'BarreString', 'String', '0');
break;
case BarreShape.Half:
this.writeSimplePropertyNode(beatProperties, 'BarreString', 'String', '1');
break;
}
}
}

private writeRhythm(parent: XmlNode, beat: Beat, rhythms: XmlNode) {
Expand Down
2 changes: 2 additions & 0 deletions src/generated/model/BeatCloner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export class BeatCloner {
clone.isEffectSlurOrigin = original.isEffectSlurOrigin;
clone.beamingMode = original.beamingMode;
clone.wahPedal = original.wahPedal;
clone.barreFret = original.barreFret;
clone.barreShape = original.barreShape;
return clone;
}
}
9 changes: 9 additions & 0 deletions src/generated/model/BeatSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { DynamicValue } from "@src/model/DynamicValue";
import { BeamDirection } from "@src/rendering/utils/BeamDirection";
import { BeatBeamingMode } from "@src/model/Beat";
import { WahPedal } from "@src/model/WahPedal";
import { BarreShape } from "@src/model/BarreShape";
export class BeatSerializer {
public static fromJson(obj: Beat, m: unknown): void {
if (!m) {
Expand Down Expand Up @@ -81,6 +82,8 @@ export class BeatSerializer {
o.set("preferredbeamdirection", obj.preferredBeamDirection as number | null);
o.set("beamingmode", obj.beamingMode as number);
o.set("wahpedal", obj.wahPedal as number);
o.set("barrefret", obj.barreFret);
o.set("barreshape", obj.barreShape as number);
return o;
}
public static setProperty(obj: Beat, property: string, v: unknown): boolean {
Expand Down Expand Up @@ -225,6 +228,12 @@ export class BeatSerializer {
case "wahpedal":
obj.wahPedal = JsonHelper.parseEnum<WahPedal>(v, WahPedal)!;
return true;
case "barrefret":
obj.barreFret = v! as number;
return true;
case "barreshape":
obj.barreShape = JsonHelper.parseEnum<BarreShape>(v, BarreShape)!;
return true;
}
return false;
}
Expand Down
24 changes: 24 additions & 0 deletions src/importer/AlphaTexImporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { NoteAccidentalMode } from '@src/model';
import { GolpeType } from '@src/model/GolpeType';
import { FadeType } from '@src/model/FadeType';
import { WahPedal } from '@src/model/WahPedal';
import { BarreShape } from '@src/model/BarreShape';

/**
* A list of terminals recognized by the alphaTex-parser
Expand Down Expand Up @@ -1639,6 +1640,29 @@ export class AlphaTexImporter extends ScoreImporter {
} else if (syData === 'wahc') {
this._sy = this.newSy();
beat.wahPedal = WahPedal.Closed;
return true;
} else if (syData === 'barre') {
this._sy = this.newSy();

if (this._sy !== AlphaTexSymbols.Number) {
this.error('beat-barre', AlphaTexSymbols.Number, true);
}
beat.barreFret = this._syData as number;
this._sy = this.newSy();

if (this._sy === AlphaTexSymbols.String) {
switch ((this._syData as string).toLowerCase()) {
case 'full':
beat.barreShape = BarreShape.Full;
this._sy = this.newSy();
break;
case 'half':
beat.barreShape = BarreShape.Half;
this._sy = this.newSy();
break;
}
}

return true;
} else {
// string didn't match any beat effect syntax
Expand Down
14 changes: 14 additions & 0 deletions src/importer/GpifParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { Logger } from '@src/Logger';
import { GolpeType } from '@src/model/GolpeType';
import { FadeType } from '@src/model/FadeType';
import { WahPedal } from '@src/model/WahPedal';
import { BarreShape } from '@src/model/BarreShape';

/**
* This structure represents a duration within a gpif
Expand Down Expand Up @@ -1826,6 +1827,19 @@ export class GpifParser {
parseFloat(c.findChildElement('Float')!.innerText)
);
break;
case 'BarreFret':
beat.barreFret = parseInt(c.findChildElement('Fret')!.innerText);
break;
case 'BarreString':
switch (c.findChildElement('String')!.innerText) {
case '0':
beat.barreShape = BarreShape.Full;
break;
case '1':
beat.barreShape = BarreShape.Half;
break;
}
break;
}
break;
}
Expand Down
19 changes: 19 additions & 0 deletions src/model/BarreShape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Lists all beat barré types.
*/
export enum BarreShape {
/**
* No Barré
*/
None,

/**
* Full Barré (play all strings)
*/
Full,

/**
* 1/2 Barré (play only half the strings)
*/
Half
}
20 changes: 19 additions & 1 deletion src/model/Beat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { GraceGroup } from '@src/model/GraceGroup';
import { GolpeType } from './GolpeType';
import { FadeType } from './FadeType';
import { WahPedal } from './WahPedal';
import { BarreShape } from './BarreShape';

/**
* Lists the different modes on how beaming for a beat should be done.
Expand Down Expand Up @@ -476,7 +477,24 @@ export class Beat {
/**
* Whether the wah pedal should be used when playing the beat.
*/
public wahPedal:WahPedal = WahPedal.None;
public wahPedal: WahPedal = WahPedal.None;

/**
* The fret of a barré being played on this beat.
*/
public barreFret: number = -1;

/**
* The shape how the barre should be played on this beat.
*/
public barreShape: BarreShape = BarreShape.None;

/**
* Gets a value indicating whether the beat should be played as Barré
*/
public get isBarre() {
return this.barreShape !== BarreShape.None && this.barreFret >= 0;
}

public addWhammyBarPoint(point: BendPoint): void {
let points = this.whammyBarPoints;
Expand Down
81 changes: 81 additions & 0 deletions src/rendering/effects/BeatBarreEffectInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Beat } from '@src/model/Beat';
import { BarRendererBase } from '@src/rendering/BarRendererBase';
import { EffectBarGlyphSizing } from '@src/rendering/EffectBarGlyphSizing';
import { EffectGlyph } from '@src/rendering/glyphs/EffectGlyph';
import { LineRangedGlyph } from '@src/rendering/glyphs/LineRangedGlyph';
import { EffectBarRendererInfo } from '@src/rendering/EffectBarRendererInfo';
import { Settings } from '@src/Settings';
import { NotationElement } from '@src/NotationSettings';
import { BarreShape } from '@src/model/BarreShape';

export class BeatBarreEffectInfo extends EffectBarRendererInfo {
public get notationElement(): NotationElement {
return NotationElement.EffectLetRing;
}

public get canShareBand(): boolean {
return false;
}

public get hideOnMultiTrack(): boolean {
return false;
}

public shouldCreateGlyph(settings: Settings, beat: Beat): boolean {
return beat.isBarre;
}

public get sizingMode(): EffectBarGlyphSizing {
return EffectBarGlyphSizing.GroupedOnBeat;
}

public createNewGlyph(renderer: BarRendererBase, beat: Beat): EffectGlyph {
let barre = '';
switch (beat.barreShape) {
case BarreShape.None:
case BarreShape.Full:
break;
case BarreShape.Half:
barre += '1/2';
break;
}

barre += 'B ' + BeatBarreEffectInfo.toRoman(beat.barreFret);

return new LineRangedGlyph(barre, false);
}

private static readonly RomanLetters = new Map<string, number>([
// ['M', 1000],
// ['CM', 900],
// ['D', 500],
// ['CD', 400],
// ['C', 100],
// ['XC', 90],
['L', 50],
['XL', 40],
['X', 10],
['IX', 9],
['V', 5],
['IV', 4],
['I', 1]
]);

public static toRoman(num: number): string {
let str = '';

if (num > 0) {
for (var [romanLetter, romanNumber] of BeatBarreEffectInfo.RomanLetters) {
const q = Math.floor(num / romanNumber);
num -= q * romanNumber;
str += romanLetter.repeat(q);
}
}

return str;
}

public canExpand(from: Beat, to: Beat): boolean {
return from.barreFret === to.barreFret && from.barreShape === to.barreShape;
}
}
26 changes: 18 additions & 8 deletions src/rendering/glyphs/LineRangedGlyph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ export class LineRangedGlyph extends GroupedEffectGlyph {
public static readonly LineTopOffset: number = 5;
public static readonly LineSize: number = 8;
private _label: string;
private _dashed: boolean;

public constructor(label: string) {
public constructor(label: string, dashed: boolean = true) {
super(BeatXPosition.OnNotes);
this._label = label;
this._dashed = dashed;
}

public override doLayout(): void {
Expand Down Expand Up @@ -40,17 +42,25 @@ export class LineRangedGlyph extends GroupedEffectGlyph {
let startX: number = cx + this.x + textWidth / 2 + lineSpacing;
let lineY: number = cy + this.y + 4 * this.scale;
let lineSize: number = 8 * this.scale;
if (endX > startX) {
let lineX: number = startX;
while (lineX < endX) {
if (this._dashed) {
if (endX > startX) {
let lineX: number = startX;
while (lineX < endX) {
canvas.beginPath();
canvas.moveTo(lineX, lineY | 0);
canvas.lineTo(Math.min(lineX + lineSize, endX), lineY | 0);
lineX += lineSize + lineSpacing;
canvas.stroke();
}
canvas.beginPath();
canvas.moveTo(lineX, lineY | 0);
canvas.lineTo(Math.min(lineX + lineSize, endX), lineY | 0);
lineX += lineSize + lineSpacing;
canvas.moveTo(endX, (lineY - 5 * this.scale) | 0);
canvas.lineTo(endX, (lineY + 5 * this.scale) | 0);
canvas.stroke();
}
} else {
canvas.beginPath();
canvas.moveTo(endX, (lineY - 5 * this.scale) | 0);
canvas.moveTo(startX, lineY | 0);
canvas.lineTo(endX, lineY | 0);
canvas.lineTo(endX, (lineY + 5 * this.scale) | 0);
canvas.stroke();
}
Expand Down
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f6088c6

Please sign in to comment.