Skip to content

Commit c744783

Browse files
committed
Implement curves
1 parent 70694a2 commit c744783

File tree

12 files changed

+136
-22539
lines changed

12 files changed

+136
-22539
lines changed

lib/main/draw-to-context.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Vex from 'vexflow';
22
import { Stave } from 'vexflow/src/stave';
33
import { TabStave } from 'vexflow/src/tabstave';
44
import { Formatter } from 'vexflow/src/formatter';
5+
import { Curve } from 'vexflow/src/curve';
56
import { convertKeySignature } from '../utils';
67

78
/**
@@ -20,7 +21,6 @@ export default function drawToContext(context, tune) {
2021

2122
tune.parts.forEach((part) => {
2223
part.bars.forEach((bar) => {
23-
2424
let tabsPositionY;
2525
if (tune.renderOptions.staveVisibility) {
2626
tabsPositionY = bar.position.y + 60;
@@ -94,5 +94,15 @@ export default function drawToContext(context, tune) {
9494
});
9595
}
9696
});
97+
98+
// 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
104+
});
105+
vexCurve.setContext(context).draw();
106+
});
97107
});
98108
}

lib/main/generate-vex-objects.js

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Bar from '../models/bar';
1313
import Part from '../models/part';
1414
import Tune from '../models/tune';
1515

16-
import { getKeys, getVexDuration, addDecorations, getTabPosition } from '../utils';
16+
import { getKeys, getVexDuration, addDecorations, getTabPosition, generateBeamsCompound } from '../utils';
1717
import { VEX_ACCIDENTAL_FROM_ABCJS } from '../constants';
1818

1919
/**
@@ -163,6 +163,36 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
163163
tabNoteToAdd.addModifier(tabGraceNoteGroup);
164164
}
165165

166+
obj.pitches.forEach((pitch) => {
167+
if (pitch.startTie) {
168+
currentPart.curves.push({
169+
startNote: noteToAdd
170+
});
171+
}
172+
if (pitch.endTie) {
173+
currentPart.curves[currentPart.curves.length - 1].endNote = noteToAdd;
174+
}
175+
if (pitch.startSlur) {
176+
pitch.startSlur.forEach(() => {
177+
currentPart.curves.push({
178+
startNote: noteToAdd
179+
});
180+
});
181+
}
182+
if (pitch.endSlur) {
183+
pitch.endSlur.forEach(() => {
184+
let i = currentPart.curves.length - 1;
185+
while (i >= 0) {
186+
if (!currentPart.curves[i].endNote) {
187+
currentPart.curves[i].endNote = noteToAdd;
188+
return;
189+
}
190+
i += -1;
191+
}
192+
});
193+
}
194+
});
195+
166196
currentBar.tabNotes.push(tabNoteToAdd);
167197
} else { // IS a rest
168198
noteToAdd = new StaveNote({
@@ -198,7 +228,7 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
198228
if (obj.endTriplet && inTriplet) {
199229
currentBar.tuplets.push(new Tuplet(inTriplet.notes, {
200230
num_notes: inTriplet.num_notes,
201-
notes_occupied: inTriplet.notes_occupied,
231+
notes_occupied: inTriplet.notes_occupied
202232
}));
203233
// I think still need to create tuplets for the tabNotes so they align correctly,
204234
// but don't want to draw them because it's already drawn in the regular stave
@@ -210,17 +240,21 @@ export default function generateVexObjects(partRegions, tuneAttrs, renderOptions
210240
}
211241
}); // end of barRegion.contents.forEach
212242

243+
const { meter } = tune.tuneAttrs;
244+
213245
// set the voice so setBarPositions can use it to have VexFlow Formatter figure out the space needed
214-
const meterArray = tune.tuneAttrs.meter.split('/');
246+
const meterArray = meter.split('/');
215247
const voice = new Voice({ num_beats: meterArray[0], beat_value: meterArray[1] });
216248
voice.setStrict(false);
217249
voice.addTickables(currentBar.notes);
218250
currentBar.voice = voice;
219251

220-
if (tuneAttrs.meter === '4/4') {
252+
if (meter === '4/4') {
221253
currentBar.beams = Beam.generateBeams(currentBar.notes, { groups: [new Vex.Flow.Fraction(2, 4)] });
254+
} else if (meter === '3/8' || meter === '6/8' || meter === '9/8' || meter === '12/8') {
255+
currentBar.beams = generateBeamsCompound(currentBar.notes);
222256
} else {
223-
currentBar.beams = Beam.generateBeams(currentBar.notes, { groups: Beam.getDefaultBeamGroups(tuneAttrs.meter) });
257+
currentBar.beams = Beam.generateBeams(currentBar.notes, { groups: Beam.getDefaultBeamGroups(meter) });
224258
}
225259
});
226260
});

lib/main/set-bar-positions.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,24 @@ export default function setBarPositions(tune) {
100100

101101
return newBar;
102102
});
103+
104+
let firstBarY;
105+
newPart.curves.forEach((curve) => {
106+
newPart.bars.forEach((bar) => {
107+
bar.notes.forEach((note) => {
108+
if (note === curve.startNote) {
109+
firstBarY = bar.position.y;
110+
}
111+
if (note === curve.endNote) {
112+
if (firstBarY !== bar.position.y) {
113+
newPart.curves.push({ endNote: curve.endNote });
114+
curve.endNote = null;
115+
}
116+
}
117+
});
118+
});
119+
});
120+
103121
return newPart;
104122
});
105123
return newTune;

lib/models/part.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export default class Part {
22
constructor(title) {
33
this.title = title; // i don't really use this...
44
this.bars = []; // the Bar class from bar.js
5+
this.curves = [];
56
Object.seal(this);
67
}
78
}

lib/test-data/abc-key-signatures.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,21 @@ const BFlatMajor = {
2323
}
2424
]
2525
};
26-
const AbcKeySignatures = { CMajor, GMajor, BFlatMajor };
26+
27+
const DMajor = {
28+
accidentals: [
29+
{
30+
acc: 'sharp',
31+
note: 'c'
32+
},
33+
{
34+
acc: 'sharp',
35+
note: 'f'
36+
}
37+
38+
]
39+
40+
};
41+
42+
const AbcKeySignatures = { CMajor, DMajor, GMajor, BFlatMajor };
2743
export default AbcKeySignatures;

lib/utils/get-tab-position.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ function convertToFingering(fret) {
195195
* fret, but we can enter any string for fret, so we just write the positions in string form on the first line of tablature
196196
*/
197197
function getHarmonicaPosition(adjustedAbsoluteChromatic, pitchOffset) {
198-
199198
// 'd' = draw bend, 'b' = blow bend, 'ob' = overblow, 'od' = overdraw
200199
const harmonicaPositions = [
201200
'^1', // c
@@ -257,35 +256,35 @@ function getHarmonicaPosition(adjustedAbsoluteChromatic, pitchOffset) {
257256
*/
258257
function getTinWhistlePosition(adjustedAbsoluteChromatic, pitchOffset) {
259258
const whistlePositions = [
260-
'6', // D
259+
'6', // D, 1
261260
'5½',
262-
'5', // E
261+
'5', // E, M2
263262
'4½', // F
264-
'4',
265-
'3', // G
263+
'4', // M3
264+
'3', // G, P4
266265
'2½',
267-
'2', // A
266+
'2', // A, P5
268267
'1½',
269-
'1', // B
268+
'1', // B, M6
270269
'½', // C
271-
'0',
272-
'6+', // D
270+
'0', // M7
271+
'6+', // D, P8
273272
'5½+',
274-
'5+', // E
273+
'5+', // E, M2
275274
'4½+', // F
276-
'4+',
277-
'3+', // G
275+
'4+', // M3
276+
'3+', // G, P4
278277
'2½+',
279-
'2+', // A
278+
'2+', // A, P5
280279
'1½+',
281-
'1+', // B
280+
'1+', // B, M6
282281
'½+', // C
283-
'0+'
282+
'0+' // M7
284283
];
285284

285+
// pitch offset for C is -2...
286286
const startPitch = 50 + pitchOffset;
287287

288-
289288
if (adjustedAbsoluteChromatic - startPitch >= 0 && adjustedAbsoluteChromatic - startPitch < whistlePositions.length) {
290289
return [{ str: 1, fret: whistlePositions[adjustedAbsoluteChromatic - startPitch] }];
291290
}

lib/utils/tests/generate-beams-compound.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { generateBeamsCompound } from '../index';
1616
// each test case should present an entire bar's worth of notes, for simplicity
1717
// also test tuplets
1818

19-
jest.mock('vexflow/src/beam');
19+
jest.mock('../../vexflow/build/cjs/vexflow');
2020
Beam.mockReturnValue(null);
2121

2222
test('6 8th notes should result in 2 beams of 3 notes each', () => {
@@ -29,7 +29,7 @@ test('6 8th notes should result in 2 beams of 3 notes each', () => {
2929
expect(Beam.mock.calls[1][0].length).toBe(3); // 3 notes in the second beam
3030
});
3131

32-
jest.mock('vexflow/src/beam');
32+
jest.mock('../../vexflow/build/cjs/vexflow');
3333
Beam.mockReturnValue(null);
3434

3535
// change this to a dotted quarter

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getTabPosition } from '../index';
2+
import { TUNINGS } from '../../constants/tunings';
23

34
import AbcObjects from '../../test-data/abcjs-objects';
45
import AbcKeySignatures from '../../test-data/abc-key-signatures';
@@ -182,3 +183,33 @@ test('grace note - accidental on n-1 regular note will apply to grace note n ove
182183
// The sharp accidental from the n-1 note should be applied, not the flat from the n-1 grace note
183184
expect(getTabPosition(keys, abcKeySignature, barContents, 1, tuning, true)).toStrictEqual([{ str: 1, fret: 2 }]);
184185
});
186+
187+
// TEST FOR TIN WHISTLE
188+
test('tin whistle - C Major scale for C whistle', () => {
189+
// each will be put into its own single-element keys[] array
190+
const noteKeys = ['c/4', 'd/4', 'e/4', 'f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'd/5', 'e/5', 'f/5', 'g/5', 'a/5', 'b/5'];
191+
const abcKeySignature = AbcKeySignatures.CMajor;
192+
193+
const barContents = []; // this wouldn't be empty but if it's OK I'll leave it?
194+
195+
const expectedPositions = [
196+
'6',
197+
'5',
198+
'4',
199+
'3',
200+
'2',
201+
'1',
202+
'0',
203+
'6+',
204+
'5+',
205+
'4+',
206+
'3+',
207+
'2+',
208+
'1+',
209+
'0+'
210+
];
211+
212+
expectedPositions.forEach((position, i) => {
213+
expect(getTabPosition([noteKeys[i]], abcKeySignature, barContents, 1, TUNINGS.TIN_WHISTLE_C, false)).toStrictEqual([{ str: 1, fret: position }]);
214+
});
215+
});

lib/vexflow

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit dadc65fb797e1405ac960a860d4b8dcea421d435

0 commit comments

Comments
 (0)