Skip to content

Commit 7ac7de9

Browse files
committed
Tighten up positioning, some refactoring.
1 parent 79d4dde commit 7ac7de9

File tree

7 files changed

+63
-66
lines changed

7 files changed

+63
-66
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ const renderOptions = {
1717
xOffset: 3,
1818
widthFactor: 1.7,
1919
lineHeight: 185,
20-
clefWidth: 45,
21-
meterWidth: 30,
20+
clefWidth: 60,
21+
meterWidth: 25,
2222
repeatWidthModifier: 35,
23-
keySigAccidentalWidth: 20,
23+
keySigAccidentalWidth: 10,
2424
tabsVisibility: 1,
2525
voltaHeight: 25,
2626
renderWidth: 500,

lib/main/draw-to-context.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function drawToContext(context, tune) {
2323
part.bars.forEach((bar) => {
2424
let tabsPositionY;
2525
if (tune.renderOptions.staveVisibility) {
26-
tabsPositionY = bar.position.y + 60;
26+
tabsPositionY = bar.position.y + 65;
2727
} else {
2828
tabsPositionY = bar.position.y;
2929
}
@@ -96,13 +96,15 @@ export default function drawToContext(context, tune) {
9696
});
9797

9898
// DRAW CURVES
99-
part.curves.forEach((partCurve) => {
100-
const vexCurve = new Curve(partCurve.startNote, partCurve.endNote, {
101-
thickness: 2,
102-
cps: [{ x: -5, y: 7 }, { x: 0, y: 7 }],
103-
x_shift: -10
99+
if (staveVisibility) {
100+
part.curves.forEach((partCurve) => {
101+
const vexCurve = new Curve(partCurve.startNote, partCurve.endNote, {
102+
thickness: 2,
103+
cps: [{ x: -5, y: 7 }, { x: 0, y: 7 }],
104+
x_shift: -10
105+
});
106+
vexCurve.setContext(context).draw();
104107
});
105-
vexCurve.setContext(context).draw();
106-
});
108+
}
107109
});
108110
}

lib/main/fill-empty-space.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ function expandBars(line, renderOptions) {
4949
const expandedBars = line.map((bar, i) => {
5050
const newBar = Object.assign({}, bar);
5151

52-
// if it's a lead-in bar, don't add space
5352
let spaceToAdd;
5453
if ((bar.isFirst || (bar.repeats.includes(Vex.Flow.Barline.type.REPEAT_BEGIN) && bar !== line[line.length - 1])) && bar.notes.length < 3) {
5554
spaceToAdd = 0;

lib/main/generate-vex-objects.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,24 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
163163
tabNoteToAdd.addModifier(tabGraceNoteGroup);
164164
}
165165

166-
obj.pitches.forEach((pitch) => {
166+
obj.pitches.every((pitch) => {
167167
if (pitch.startTie) {
168168
currentPart.curves.push({
169169
startNote: noteToAdd
170170
});
171+
return false;
171172
}
172173
if (pitch.endTie) {
173174
currentPart.curves[currentPart.curves.length - 1].endNote = noteToAdd;
175+
return false;
174176
}
175177
if (pitch.startSlur) {
176178
pitch.startSlur.forEach(() => {
177179
currentPart.curves.push({
178180
startNote: noteToAdd
179181
});
180182
});
183+
return false;
181184
}
182185
if (pitch.endSlur) {
183186
pitch.endSlur.forEach(() => {
@@ -190,13 +193,15 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
190193
i += -1;
191194
}
192195
});
196+
return false;
193197
}
198+
return true;
194199
});
195200

196201
currentBar.tabNotes.push(tabNoteToAdd);
197202
} else { // IS a rest
198203
noteToAdd = new StaveNote({
199-
clef: tuneAttrs.clef, keys: ['b/4'], duration: `${duration}r`
204+
clef: tuneAttrs.clef, keys: ['b/4'], duration: `${duration}r`,
200205
});
201206

202207
const tabNoteToAdd = new TabNote({
@@ -252,6 +257,9 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
252257
if (meter === '4/4') {
253258
currentBar.beams = Beam.generateBeams(currentBar.notes, { groups: [new Vex.Flow.Fraction(2, 4)] });
254259
} else if (meter === '3/8' || meter === '6/8' || meter === '9/8' || meter === '12/8') {
260+
// 3/8 isn't technically a compound time signature, maybe should call the function something else.
261+
// I believe this is handling beams correctly for all time signatures though, need a visual test suite
262+
// & compare to VexFlow visual tests https://www.vexflow.com/tests/
255263
currentBar.beams = generateBeamsCompound(currentBar.notes);
256264
} else {
257265
currentBar.beams = Beam.generateBeams(currentBar.notes, { groups: Beam.getDefaultBeamGroups(meter) });

lib/main/set-bar-positions.js

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import Vex from 'vexflow';
22
import { Formatter } from 'vexflow/src/formatter';
33

4+
const NEW_PART_MULTIPLIER = 1.25;
5+
46
/**
57
* Takes the Tune and sets the .position properties of each Bar object contained there.
68
* Sets width of each Bar according to the renderOptions and based on the contents of
@@ -22,7 +24,7 @@ export default function setBarPositions(tune) {
2224

2325
newTune.parts = tune.parts.map((part, partIndex) => {
2426
const newPart = Object.assign({}, part);
25-
newPart.bars = newPart.bars.map((bar, i) => {
27+
newPart.bars = newPart.bars.map((bar, barIndex) => {
2628
const newBar = Object.assign({}, bar);
2729

2830
// calculate space needed for clefSigMeterWidth
@@ -35,9 +37,12 @@ export default function setBarPositions(tune) {
3537
// get vexFlow to tell me how much space the notes need
3638
const formatter = new Formatter();
3739
formatter.createTickContexts([newBar.voice]);
38-
3940
let notesWidth = formatter.preCalculateMinTotalWidth([newBar.voice]) * widthFactor;
4041

42+
// it still doesn't give enough space, so add more if there are few notes in the bar
43+
notesWidth *= 1 + 3 / ((newBar.notes.length + 1) * (newBar.notes.length + 1));
44+
45+
// extra space for accidentals (sharp and flat signs)
4146
const notesWithAccidentals = newBar.notes.reduce((acc, note) => {
4247
if (note.modifiers) {
4348
note.modifiers.forEach((modifier) => {
@@ -48,16 +53,7 @@ export default function setBarPositions(tune) {
4853
}
4954
return acc;
5055
}, 0);
51-
5256
notesWidth += notesWithAccidentals * keySigAccidentalWidth;
53-
// still had crowding in bars with few notes, even when using
54-
// preCalculateMinTotalWidth, seems to be the same problem my own code had before
55-
if (newBar.notes.length === 3) { notesWidth *= 1.25; }
56-
if (newBar.notes.length === 2) { notesWidth *= 1.55; }
57-
if (newBar.notes.length === 1) { notesWidth *= 1.75; }
58-
// also note I am adding width here if the length is lower than 4, but at the
59-
// fillEmptySpace stage am preventing it from sharing space with the bar
60-
// if it's lower than 4. that seems wrong ??
6157

6258
// determine total min width of the bar including clefSigMeterWidth
6359
let minWidth = notesWidth + newBar.position.clefSigMeterWidth;
@@ -66,25 +62,23 @@ export default function setBarPositions(tune) {
6662
}
6763
if (minWidth > renderWidth) { minWidth = renderWidth; }
6864

69-
// 14 another magic number to represent the height needed when 6 strings are in the tab
70-
// when there are less strings, it will reduce the vertical space used by an appropriate amount
7165
const spaceForStave = lineHeight * 0.5;
72-
const spaceForTabs = lineHeight * ((14 - (6 - tabNumberOfLines)) / 14) - spaceForStave;
66+
const spaceForTabs = 0.5 * lineHeight - (6 - tabNumberOfLines) / 14;
7367

74-
if (i === 0) { // first bar of part
68+
if (barIndex === 0) { // first bar of part
7569
newBar.position.x = xOffset;
7670

7771
if (partIndex === 0) { // first part
78-
yCursor += (lineHeight * 1.25); // very top of tune
72+
yCursor += (lineHeight * NEW_PART_MULTIPLIER); // very top of tune
7973
} else {
8074
if (tabsVisibility) {
81-
yCursor += spaceForTabs * 1.25;
75+
yCursor += spaceForTabs * NEW_PART_MULTIPLIER;
8276
}
8377
if (staveVisibility) {
84-
yCursor += spaceForStave * 1.25;
78+
yCursor += spaceForStave * NEW_PART_MULTIPLIER;
8579
}
8680
}
87-
} else if (newPart.bars[i - 1].position.x + newPart.bars[i - 1].position.width + minWidth > renderWidth) { // first bar of a new line
81+
} else if (newPart.bars[barIndex - 1].position.x + newPart.bars[barIndex - 1].position.width + minWidth > renderWidth) { // first bar of a new line
8882
newBar.position.x = xOffset;
8983
if (tabsVisibility) {
9084
yCursor += spaceForTabs;
@@ -93,7 +87,7 @@ export default function setBarPositions(tune) {
9387
yCursor += spaceForStave;
9488
}
9589
} else { // bar on an incomplete line
96-
newBar.position.x = newPart.bars[i - 1].position.x + newPart.bars[i - 1].position.width;
90+
newBar.position.x = newPart.bars[barIndex - 1].position.x + newPart.bars[barIndex - 1].position.width;
9791
}
9892
newBar.position.y = yCursor;
9993
newBar.position.width = minWidth;

lib/utils/tests/get-tab-position.test.js

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,14 @@ import { TUNINGS } from '../../constants/tunings';
44
import AbcObjects from '../../test-data/abcjs-objects';
55
import AbcKeySignatures from '../../test-data/abc-key-signatures';
66

7-
const tuning = {
8-
displayName: 'Guitar (EADGBE)',
9-
strings: ['e/3', 'a/3', 'd/4', 'g/4', 'b/4', 'e/5'],
10-
type: 'strings_fretted'
11-
};
12-
137
// TODO: separate unit tests from integration
148

159
test('e3 is lowest note on guitar', () => {
1610
const keys = ['e/3'];
1711
const abcKeySignature = AbcKeySignatures.CMajor;
1812
const barContents = [AbcObjects.Notes.Eighths.F];
1913

20-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 6, fret: 0 }]);
14+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 6, fret: 0 }]);
2115
});
2216

2317
test('sharped note causes itself and later notes to be sharped', () => {
@@ -28,9 +22,9 @@ test('sharped note causes itself and later notes to be sharped', () => {
2822
const barContents = [f, fSharp, f];
2923

3024
// str: 1, fret: 1 is F natural
31-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 1 }]);
32-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
33-
expect(getTabPosition(keys, abcKeySignature, barContents, 2, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
25+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 1 }]);
26+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
27+
expect(getTabPosition(keys, abcKeySignature, barContents, 2, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
3428
});
3529

3630
test('sharp in key signature causes note to be sharped', () => {
@@ -40,7 +34,7 @@ test('sharp in key signature causes note to be sharped', () => {
4034
const barContents = [f];
4135

4236
// str: 1, fret: 2 is F sharp
43-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
37+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
4438
});
4539

4640
// bugfix: in abcjs key sig, accidental.note when the note is 'b',
@@ -52,9 +46,9 @@ test('in B Flat Minor key, B notes get flatted', () => {
5246
const barContents = [b];
5347

5448
// str: 1, fret: 6 is B flat
55-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 6 }]);
49+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 6 }]);
5650
// now with C major key sig, should be a B natural
57-
expect(getTabPosition(keys, AbcKeySignatures.CMajor, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 7 }]);
51+
expect(getTabPosition(keys, AbcKeySignatures.CMajor, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 7 }]);
5852
});
5953

6054
test('sharped note, when sharp already exists in key sig, doesnt sharp the note twice', () => {
@@ -65,7 +59,7 @@ test('sharped note, when sharp already exists in key sig, doesnt sharp the note
6559

6660
// str: 1, fret: 1 is F natural and str: 1, fret: 2 is F sharp. we're checking to make
6761
// sure it doesn't somehow end up str: 1, fret: 3
68-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
62+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
6963
});
7064

7165
test('natural accidental cancels out key sig sharp', () => {
@@ -76,7 +70,7 @@ test('natural accidental cancels out key sig sharp', () => {
7670

7771
// the natural accidental on the specific note should cancel out the sharp accidental in the key sig
7872
// str: 1, fret: 1 is F natural
79-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 1 }]);
73+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 1 }]);
8074
});
8175

8276
test('grace note - sharped grace note causes itself and later grace notes to be sharped', () => {
@@ -88,9 +82,9 @@ test('grace note - sharped grace note causes itself and later grace notes to be
8882

8983
// str: 1, fret: 1 is F natural
9084
// passing is GraceNote true, meaning we're getting tab position for the grace notes here
91-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, true)).toStrictEqual([{ str: 1, fret: 1 }]);
92-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
93-
expect(getTabPosition(keys, abcKeySignature, barContents, 2, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
85+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 1 }]);
86+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 2 }]);
87+
expect(getTabPosition(keys, abcKeySignature, barContents, 2, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 2 }]);
9488
});
9589

9690
test('grace note - sharp in key signature causes grace note to be sharped', () => {
@@ -100,7 +94,7 @@ test('grace note - sharp in key signature causes grace note to be sharped', () =
10094
const barContents = [cWithFGraceNote];
10195

10296
// str: 1, fret: 2 is F sharp
103-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
97+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 2 }]);
10498
});
10599

106100
test('grace note - sharped grace note causes later regular notes to be sharped', () => {
@@ -112,7 +106,7 @@ test('grace note - sharped grace note causes later regular notes to be sharped',
112106

113107
// passing isGraceNote as false because we're testing a regular F note at position 1 and
114108
// confirming the sharp from previously sharped F grace note applies to it
115-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
109+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
116110
});
117111

118112
test('grace note - sharped regular note causes later grace notes to be sharped', () => {
@@ -124,7 +118,7 @@ test('grace note - sharped regular note causes later grace notes to be sharped',
124118

125119
// passingisGraceNote as true because we're testing the F grace note attached to the C note
126120
// in position 1 and confirming it's sharped by the accidental from the F Sharp at position 0
127-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
121+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 2 }]);
128122
});
129123

130124

@@ -136,7 +130,7 @@ test('grace note - natural accidental on grace note cancels out key sig sharp',
136130

137131
// the natural accidental on the specific grace note should cancel out the sharp accidental in the key sig
138132
// should be str: 1, fret: 1 for F natural
139-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, true)).toStrictEqual([{ str: 1, fret: 1 }]);
133+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 1 }]);
140134
});
141135

142136

@@ -148,7 +142,7 @@ test('grace note - accidental on grace note does affect attached regular note',
148142

149143
// The regular F has a F Sharp grace note attached (before) it, so the note should
150144
// become sharped, testing the regular note F so isGraceNote is false
151-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
145+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
152146
});
153147

154148
test('grace note - grace is not affected by accidental on attached regular note', () => {
@@ -159,7 +153,7 @@ test('grace note - grace is not affected by accidental on attached regular note'
159153

160154
// Now it's a F Sharp regular note with a F grace note attached having no accidental. The
161155
// regular note comes "after" the grace not, so the grace note pitch should be F Natural
162-
expect(getTabPosition(keys, abcKeySignature, barContents, 0, tuning, true)).toStrictEqual([{ str: 1, fret: 1 }]);
156+
expect(getTabPosition(keys, abcKeySignature, barContents, 0, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 1 }]);
163157
});
164158

165159
test('grace note - accidental on n-1 regular note will apply to regular note n over accidental on n-1 grace note', () => {
@@ -170,7 +164,7 @@ test('grace note - accidental on n-1 regular note will apply to regular note n o
170164
const barContents = [fSharpWithFFlatGraceNote, f];
171165

172166
// The sharp accidental from the n-1 note should be applied, not the flat from the n-1 grace note
173-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, false)).toStrictEqual([{ str: 1, fret: 2 }]);
167+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, false)).toStrictEqual([{ str: 1, fret: 2 }]);
174168
});
175169

176170
test('grace note - accidental on n-1 regular note will apply to grace note n over accidental on n-1 grace note', () => {
@@ -181,7 +175,7 @@ test('grace note - accidental on n-1 regular note will apply to grace note n ove
181175
const barContents = [fSharpWithFFlatGraceNote, f];
182176

183177
// The sharp accidental from the n-1 note should be applied, not the flat from the n-1 grace note
184-
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
178+
expect(getTabPosition(keys, abcKeySignature, barContents, 1, TUNINGS.GUITAR_STANDARD, true)).toStrictEqual([{ str: 1, fret: 2 }]);
185179
});
186180

187181
// TEST FOR TIN WHISTLE

visual-tool/scripts/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ const allNottinghamTunes = Tunes1 + Tunes2 + Tunes3 + Tunes4 + Tunes5 + Tunes6 +
2424
const defaultRenderOptions = {
2525
xOffset: 3,
2626
widthFactor: 1.5,
27-
lineHeight: 185,
28-
clefWidth: 40,
29-
meterWidth: 30,
27+
lineHeight: 190,
28+
clefWidth: 60,
29+
meterWidth: 25,
3030
repeatWidthModifier: 35,
31-
keySigAccidentalWidth: 20,
31+
keySigAccidentalWidth: 10,
3232
tabsVisibility: 1,
3333
staveVisibility: 1,
3434
tabStemsVisibility: 0,
35-
voltaHeight: 25,
35+
voltaHeight: 27,
3636
renderWidth: 650,
3737
tuning: AbcjsVexFlowRenderer.TUNINGS.GUITAR_STANDARD,
3838
};
@@ -93,7 +93,7 @@ tuning.onchange = (e) => {
9393
};
9494

9595
const vexRendererWidth = 500;
96-
const vexRendererHeight = 1000;
96+
const vexRendererHeight = 2000;
9797

9898
const customOptions = [];
9999
const nottinghamOptions = [];

0 commit comments

Comments
 (0)