-
Notifications
You must be signed in to change notification settings - Fork 2
/
types.js
1642 lines (1536 loc) · 45.1 KB
/
types.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (C) 2023 euwbah
//
// This file is part of Xen Tuner.
//
// Xen Tuner is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Xen Tuner is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Xen Tuner. If not, see <http://www.gnu.org/licenses/>.
/*
This file is for cosmetic/autocomplete purposes and is not
used in the plugin.
Provides type/class definitions for objects in the plugin,
so that autocomplete is improved.
*/
/**
* A number or string representing a uniquely identifiable accidental symbol.
*
* If this value is a number, it corresponds to a SMuFL symbol. Similar-looking
* SMuFL symbols have the same symbol code.
*
* If this value is a string, it represents an ASCII accidental to be attached to
* the note verbatim. Internally, ASCII accidental SymbolCodes are prefixed with a
* quote (`'`) to signify that they are not SMuFL symbols.
*
* Remember to prepend the quote `'` to tokenized ASCII accidental fingering texts
* before looking up tables.
*
*
* [See list of symbol codes](https://docs.google.com/spreadsheets/d/1kRBJNl-jdvD9BBgOMJQPcVOHjdXurx5UFWqsPf46Ffw/edit?usp=sharing)
* @typedef {number|string} SymbolCode
*/
/**
* Represents accidental symbols attached to a note. Each entry is the {@link SymbolCode} of the symbol and the number of times this symbol occurs.
The keys are NOT ORDERED.
The keys are in left-to-right display order as per accidental display order determined by {@link TuningConfig}.
This object can be hashed into the {@link AccidentalHash}, which can be appended to a nominal number to produce the {@link XenNote.hash}.
The hashed symbols list is sorted by increasing {@link SymbolCode}.
* @typedef {Object.<number, number>} AccidentalSymbols
*/
/**
* Represents a tokenized {@link PluginAPINote} element.
*/
class MSNote {
/**
* {@link PluginAPINote.pitch}
*
* @type {number} */
midiNote;
/**
* {@link PluginAPINote.tpc}
* @type {number}
*/
tpc;
/**
* Number of 12 edo nominals from A4.
* @type {number}
*/
nominalsFromA4;
/**
* @type {AccidentalSymbols?}
*/
accidentals;
/**
* @type {number}
*/
tick;
/**
* {@link PluginAPINote.line}
* @type {number} */
line;
/**
* @type {PluginAPINote}
*/
internalNote;
/**
* List of non-accidental fingering elements attached to this note.
*
* Fingerings that function as accidentals will show up in
* {@link MSNote.accidentals} instead.
*
* @type {PluginAPIElement[]}
*/
fingerings;
}
/**
* Represents a hashed {@link AccidentalSymbols} object or {@link SymbolCode[]} list.
*
* This is a space-separated value where entries come in pairs.
*
* `<SymbolCode> <number of occurrences>`
*
* E.g. `"6 1 41 2"` represents one flat and two up arrows.
*
* `"6 1 'b 1 '6 1"` represents one flat, one 'b' ascii symbol, and one '6' ascii symbol.
*
* The symbol codes must be sorted in increasing order. Numerical SymbolCodes
* come first, followed by string-based ASCII symbol codes, sorted in increasing
* alphabetical order.
*
* @typedef {string} AccidentalHash
*/
/**
* Represents a single abstract composite accidental being applied to a note,
* represented by the degrees of each accidental chain.
*
* For example, in a tuning system with two accidental chains in this order:
* sharps/flats, up/down — the AccidentalVector of [2, -3] represents the degree
* 2 of the sharps/flat chain (double sharp) and degree -3 of the arrows chain
* (three down arrows).
*
* The n-th number represents the degree of the n-th accidental chain.
* The order of which the accidental chains are declared/stored determines
* which number corresponds to which accidental chain.
* @typedef {number[]} AccidentalVector
*/
/**
Think of this as the xen version of ‘tonal pitch class’.
This is how the plugin represents a ‘microtonal’ note,
containing data pertaining to how the note should be
spelt/represented microtonally.
The accidentals object is not sorted. When creating/displaying an
accidental, use orderedSymbols to iterate each symbol in left-to-right order.
If accidentals is null, represents a nominal of the tuning system
(note without accidental).
`<nominal> SymbolCode <degree> SymbolCode <degree> ...`
The SymbolCodes in the hash string must appear in increasing order.
For example, the note A bb d (1 double flat, 1 mirrored flat)
should have the hash string: "0 6 1 10 1".
*/
class XenNote {
/**
* Number of nominals with respect to the {@link TuningConfig.tuningNote absolute tuning note} of {@link TuningConfig}
* @type {number}
*/
nominal;
/**
* A list of symbols in left-to-right display order.
*
* If no symbols present, this is an empty list.
*
* @type {SymbolCode[]}
*/
orderedSymbols;
/**
* If null, this note represents a nominal of the {@link TuningConfig}
* @type {AccidentalSymbols?} */
accidentals;
/**
* Unique ID of this {@link XenNote}
* @type {string}
*/
hash;
/**
* If `true`, this {@link XenNote} has ligature priority (i.e. 'strong ligature')
*
* I.e. this spelling will be chosen over non-ligature enharmonic
* spellings during up/down operations.
*
* If this {@link XenNote} was created from a weak ligature (denoted by `lig(...)?`),
* this will still be `false`.
*
* @type {boolean}
*/
hasLigaturePriority;
/**
* If `true`, this {@link XenNote} has an important ligature that
* should override other enharmonically equivalent spellings in
* all cases.
*
* This spelling will be chosen over other ligature/non-ligature spellings
* during up/down AND ENHARMONIC cycle operations.
*
* These are created from important ligatures denoted by `!` as in:
* `lig(x,...)`.
*
* @type {boolean}
*/
hasImportantLigature;
}
/**
* Contains degrees of secondary accidentals present in a {@link NoteData}
*
* The keys of this lookup are the indices of the secondary accidental,
* such that {@link TuningConfig.secondaryAccList}[idx] will yield the
* secondary accidental that has been matched.
*
* The values of this lookup are positive, non-zero numbers, indicating
* how many times that particular secondary accidental has been matched.
*
* @typedef {Object.<number, number>} SecondaryAccMatches
*/
/**
* Contains information after a note is parsed in {@link readNoteData}.
*
* This is where the {@link TuningConfig} lookup is applied to a {@link MSNote}
* to calculate its {@link XenNote} pitch class, and other secondary accidentals
* that may apply.
*
* During the parsing, new accidentals may be created on the note as the
* {@link parseNote} function fleshes out the fingering-based accidental entry.
*/
class NoteData {
/**
* Tokenized internal 12 edo representation.
* @type {MSNote} */
ms;
/**
* Xen pitch class.
* @type {XenNote} */
xen;
/**
* Number of xen equaves relative to tuning note.
* @type {number} */
equaves;
/**
* {@link SymbolCode}[] list containing secondary accidental symbols
* in left-to-right display order.
*
* If no symbols are present, this will be an empty array.
*
* @type {SymbolCode[]}
*/
secondaryAccSyms;
/**
* Contains degrees of matched secondary accidentals.
*
* If no secondary accidentals are present, this will be an empty object.
*
* @type {SecondaryAccMatches}
*/
secondaryAccMatches;
/**
* If fingering accidental entry was performed, this will contain all accidentals
* symbols to be displayed & attached to the note in left-to-right display order.
*
* Both primary and secondary accidentals are included.
*
* As of now, this is just a concatenation of {@link secondaryAccSyms}
* and {@link XenNote.orderedSymbols xen.orderedSymbols}.
*
* If no accidental entry was performed during, this will be `null`.
*
* @type {SymbolCode[]?}
*/
updatedSymbols;
}
/**
* Contains a lookup for all unique {@link XenNote}s in a tuning system.
*
* Maps {@link XenNote.hash} to a {@link XenNote} object.
*
* @typedef {Object.<string, XenNote>} NotesTable
*/
/**
* Contains a map of {@link XenNote.hash}es to their respective {@link AccidentalVector}s.
*
* Note that this mapping is not bijective - two {@link XenNote}s can have different
* nominals but the same {@link AccidentalVector}.
*
* @typedef {Object.<string, AccidentalVector>} AccidentalVectorTable
*/
/**
* Contains a lookup of accidental vectors to their respective symbols.
*
* The key is an {@link AccidentalVector} list.
*
* Values are {@link SymbolCode}[] lists, in left-to-right display order.
*
* @typedef {Object.<string, SymbolCode[]>} AccidentalVectorSymbols
*/
/**
* Lookup table for the tuning of {@link XenNote}s.
*
* Maps {@link XenNote.hash} to `[cents, equavesAdjusted]`.
*
* Entries do not need to be sorted in any particular order as the indexing
* for pitch sorting is done in StepwiseList.
* See `2.3.5 JI tuning table.csv` for an example.
*
* `cents`: the number of cents this note is from tuning note modulo the equave.
*
* `equavesAdjusted`: the number of times this note has to be taken up/down an
* equave so that its cents mapping will fit modulo the equave.
*
* The equave adjustment has to be kept track of so that notes are tuned with
* in the correct equave, and stepwise up/down operations use the correct equave
* for certain notenames.
*
* Look at the above 2.3.5 JI subset tuning for an example.
* (A4 is the tuning note & equave: 1200 cents.)
*
* Going up stepwise from the note `Dbbbb\\` to `Gx\`, we actually need to
* lower `Gx\` by one equave to actually get the correct next note up.
*
* Similarly, going up stepwise from `Fxx\\` to `Bbb//`, we’ll need to increase
* the equave by 1 so that it sounds in the correct equave.
*
* @typedef {Object.<string, [number, number]>} TuningTable
*/
/**
* This list of lists indexes the {@link XenNote.hash}es in order of ascending pitch
* (within an equave).
*
* Each list represents ‘enharmonically equivalent’ {@link XenNote}s.
* The stepwise up/down plugins uses this to determine what are the possible
* spellings of the next stepwise note, and it chooses the best option
* of enharmonic spelling based on the context (use of implicit accidentals/key
* signature/minimizing accidentals)
* @typedef {string[][]} StepwiseList
*/
/**
* A lookup table for the index of a {@link XenNote.hash} in the {@link StepwiseList}.
*
* This lookup is used to determine the index of a current note, and the next
* note up/down is simply the enharmonically equivalent {@link XenNote}s at index + 1
* or index - 1 of {@link StepwiseList}.
*
* @typedef {Object.<string, number>} StepwiseLookup
*/
/**
A simple lookup table where {@link EnharmonicGraph}[{@link XenNote}] gives the next
enharmonic equivalent spelling of the note, or null if there are no other
enharmonic equivalents.
This lookup table describes a graph composed of several distinct cyclic
directional paths. Each cyclic loop represents enharmonically equivalent notes.
This structure is computed at the same time as the {@link StepwiseList}.
* @typedef {Object.<string, string>} EnharmonicGraph
*/
/**
Represents a user declared accidental chain.
Each element of {@link degreesSymbols} is a list of {@link SymbolCode}s containing the
symbols composed together to represent one degree in the accidental chain
(in the order of which the user declared)
The actual chain degree being represented by `degreesSymbols[n]` and `tunings[n]`
is equal to `n - centralIdx`.
{@link symbolsUsed} is used to determine what symbols are used in this accidental chain.
*/
class AccidentalChain {
/**
* List of {@link SymbolCode}s that make up each degree in this chain.
*
* Central element is null.
*
* @type {(SymbolCode[]|null)[]}
*/
degreesSymbols;
/**
* Lists all unique symbols used in this chain.
*
* @type {SymbolCode[]}
*/
symbolsUsed;
/**
* Tuning of each accidental in cents. Central element is 0.
*
* @type {number[]}
*/
tunings;
/**
* The index of the central element.
* @type {number}
*/
centralIdx;
}
/**
* `LigAccVector` is a subspace/subset of {@link AccidentalVector}
* which corresponds to the degrees of {@link AccidentalChain}s
* in an order specified by {@link Ligature.regarding}.
*
* @typedef {number[]} LigAccVector
*/
/**
* Represents a ligature declaration.
*
* Note: ligatures can be declared weak and important (or both).
*
* A weak ligature will not take special precedence over non-ligatures
* (i.e. the default accidental symbols can be favored over the ligature).
* This is useful for adding support for sporadic enharmonic spellings or special symbols
* that can mean different things depending on other symbols present on the note.
* (See heji/5 limit.txt for an example)
*
* An important ligature takes precedence over the default accidental chain's symbols and other
* non-important ligatures, and overrides the use of non-important spellings in all operations
* up/down/enharmonic respell.
*/
class Ligature {
/**
* Accidental chain indices (starting from 0)
*
* An unordered set representing which n-th accidental chains to consider
* when searching for exact {@link AccidentalVector} matches.
*
* (The indices are 0-based)
*
* @type {number[]}
*/
regarding;
/**
* Search & replace mapping {@link LigAccVector} strings to {@link SymbolCode}s
*
* {@link LigAccVector} is a subspace/subset of {@link AccidentalVector}(s)
* which corresponds to the order of {@link AccidentalChain}s specified
* by {@link regarding}.
*
* @type {Object.<string, SymbolCode[]>}
*/
ligAvToSymbols;
/**
* `true` if ligature is declared to be weak `lig(...)?`
* (question mark)
*
* If a ligature is weak, ligatured symbols do not get special
* priority over non-ligatured symbols when choosing between
* equivalent spellings during up/down operations.
*
* The opposite of a weak ligature is called a 'strong ligature'.
*
* @type {boolean}
*/
isWeak;
/**
* `true` if ligature is declared to override default acc symbols declared
* in the accidental chains `lig(...)!`
* (exclaimation mark)
*
* If a ligature overrides the default accidental symbols, the original
* accidental symbols will no longer be accessible from the up/down/enharmonic
* operations. These important! ligatures also take precedence over non-overidden
* ligatures.
*
* (The default symbols will still tune and be recognized as valid symbols.)
*
* The opposite of an important ligature is called a 'non-important ligature'.
*
* @type {boolean}
*/
isImportant;
}
/**
* Just a list of numbers which filters which next notes are valid for the
* current up/down aux operation.
*
* - If 0 is in the list, the nominal must stay constant.
* - If 1 is in the list, the degree of the first accidental chain must stay constant.
* - If 2 is in the list, the degree of the second accidental chain must stay constant.
* - etc…
* @typedef {number[]} ConstantConstrictions
*/
/**
* Represents a tuning configuration.
*/
class TuningConfig {
/** @type {NotesTable} */
notesTable;
/** @type {TuningTable} */
tuningTable;
/**
* Contains tuning overrides of specified nominals-accidental vector
* pairs, in absolute cents from the reference frequency.
*
* Maps arrays of the form [nominal, avDeg1, avDeg2, ...] to cent
* tuning values.
*
* @type {Object.<string, number>}
*/
tuningOverrideTable;
/** @type {AccidentalVectorTable}*/
avTable;
/**
* An {@link AccidentalVectorSymbols} lookup mapping {@link AccidentalVector}
* to {@link SymbolCode}s that best represent the accidental vector.
*
* If different sets of symbols can represent the same {@link AccidentalVector},
* e.g. {@link Ligature ligatured} vs non-ligatured spellings, the ligatured spelling will take
* precedence if the ligature is not a {@link Ligature.isWeak weak ligature}.
*
* If multiple ligatures exist for the same accidental vector (which really
* shouldn't happen), the last declared ligature will take precedence in this
* lookup.
*
* @type {AccidentalVectorSymbols}
*/
avToSymbols;
/** @type {StepwiseList} */
stepsList;
/** @type {StepwiseLookup} */
stepsLookup;
/** @type {EnharmonicGraph} */
enharmonics;
/** @type {AccidentalChain[]} */
accChains;
/** @type {Ligature[]} */
ligatures;
/**
* List of nominals within an equave in cents (including the first).
*
* @type {number[]} */
nominals;
/**
* Corresponds to {@link nominals}`.length`
* @type {number} */
numNominals;
/**
* In cents.
* @type {number} */
equaveSize;
/**
* MIDI note number of absolute reference note.
*
* The first note of the nominals will be this reference note.
*
* @type {number}
*/
tuningNote;
/**
* How many 12edo nominals from A4 is the absolute reference note.
*
* The first note of the nominals will be this reference note.
*
* @type {number}
*/
tuningNominal;
/**
* If the user specifies a mode-preserving reference tuning change,
* the reference note the user specified is stored in this variable as an offset
* of the number of nominals away from the original reference note specified in
* the tuning config/most recent mode-changing reference tuning change.
*
* Defaults to 0.
*
* This value ONLY affects JI ratio calculations of fingering-based JI annotations,
* and the Display Cents/Steps calculation.
*
* 1/1 will be the relative tuning nominal.
*
* Changing this does not affect the {@link XenNote.nominal} property's relation to
* the absolute tuning nominal.
*
* @type {number}
*/
relativeTuningNominal;
/**
* Effective hz of the absolute reference note ({@link tuningNote} & {@link tuningNominal}).
*
* This value is initially set to {@link originalTuningFreq}, but after a reference
* pitch change (that doesn't change the mode), this value will be updated to match
* the required reference pitch, without actually changing the {@link tuningNote} or
* {@link tuningNominal}.
*
* @type {number}
*/
tuningFreq;
/**
* Stores the original Hz of the reference. This value is read from the tuning config
* file and does not change unless a reference pitch change with mode change (!) is called
* for.
*
* This value is used to calculate the updated {@link tuningFreq} when relative tuning
* changes occur, so that floating point errors don't accumulate.
*
* @type {number}
*/
originalTuningFreq;
/**
* The 0-based Nth entry of this list corresponds to the Nth auxiliary
* operation's {@link ConstantConstrictions} conditions on how a note
* can be transposed.
*
* The first item in this list must be `null`, to signify a non-auxiliary
* operation.
*
* @type {ConstantConstrictions[]}
*/
auxList;
/**
* Lookup of all the accidental symbols/ASCII that affect {@link XenNote} spelling.
*
* When tokenizing a note, if the plugin finds symbols that do not belong
* to this lookup, it will exclude them from affecting the XenNote spelling.
*
* @type {Object.<SymbolCode, boolean>}
*/
usedSymbols;
/**
* Lookup of all the symbols used in secondary accidentals that do not affect {@link XenNote} spelling.
* But the plugin should still recognize these as accidentals and format them as such.
*
* These symbols are not included in {@link usedSymbols}.
*
* @type {Object.<SymbolCode, boolean>}
*/
usedSecondarySymbols;
/**
* These are all the secondary accidentals in the order which they are declared.
*
* The plugin will search for secondary accidentals in this order.
*
* @type {AccidentalHash[]}
*/
secondaryAccList;
/**
* Lookup mapping entries in {@link secondaryAccList} to their index.
*
* E.g. if `6 2 '> 3` is the 3rd element of `secondaryAccList`, then
* `secondaryAccIndexTable['6 2 '> 3'] === 2`.
*
* @type {Object.<AccidentalHash, number>}
*/
secondaryAccIndexTable;
/**
* Lookup mapping secondary accidentals to properly ordered
* {@link SymbolCode}[] arrays. These symbol code arrays represent
* the left-to-right order that the symbol codes should be displayed.
*
* @type {Object.<AccidentalHash, SymbolCode[]>}
*/
secondaryAccTable;
/**
* Contains lookup for tunings of secondary accidentals.
*
* The value mapped to a secondary accidental can either be:
*
* - A single number which denotes the cent offset of the accidental,
* - Or, an array of as many numbers as there are nominals,
* denoting the cent offset of the accidental for each nominal.
*
* @type {Object.<AccidentalHash, number|number[]>}
*/
secondaryTunings;
/**
* Contains lookup for converting ascii verbatim input to SMuFL symbols.
*
* ASCII verbatim input are NOT SymbolCodes, they are literally ascii strings
* that the user types in.
*
* @type {Object.<string, SymbolCode[]>}
*/
asciiToSmuflConv;
/**
* List of keys in asciiToSmuflConv, in order of declaration.
*
* The keys coming earlier in the list will be searched and matched first.
*
* @type {string[]}
*/
asciiToSmuflConvList;
/*
OTHER SECONDARY SETTINGS
*/
/**
* If `true`, every accidental symbol is made explicit, even though it matches
* a carry-over accidental or key signature.
*
* Defaults to `false`.
*
* Set to `true` using the `explicit()` secondary declaration.
*
* @type {boolean}
*/
alwaysExplicitAccidental;
/**
* If `true`, fingering-based text accidentals will not be bolded.
*
* Defaults to `false` (i.e. bold text).
*
* Set to `true` using the `nobold()` secondary declaration.
*
* @type {boolean}
*/
nonBoldTextAccidental;
/**
* If this value is not `null`, it denotes that this tuning config supports
* displaying the step index of the note. The number of this value is the
* number of edosteps/neji steps to display.
*
* @type {number?}
*/
displaySteps;
/**
* Where to position the fingering containing edosteps info of the note.
*
* Defaults to 'below'.
*
* @type {'above'|'below'}
*/
displayStepsPosition;
/**
* How the displayed cents offset should be calculated.
*
* - 'nominal': (Default) The cents offset from the nominal of the note.
* - 'absolute': The absolute number of cents from the relative reference note.
* - 'semitone': Same as above, modulo the 100 cents semitone ranging from +/-50c
*
* @type {'nominal'|'absolute'|'semitone'}
*/
displayCentsReference;
/**
* Number of decimal places precision of the cent offset display.
*
* Defaults to 0
*
* @type {number}
*/
displayCentsPrecision;
/**
* Where to position the fingering containing cents tuning info of the note.
*
* Defaults to 'above'.
*
* @type {'above'|'below'}
*/
displayCentsPosition;
}
/**
* A lookup for memoized parsed {@link TuningConfig}s. Because of how the {@link Cursor}
* requires each voice to be tuned separately one at a time, it will cause many
* unnecessary re-parsings of the same System/Staff Text element.
*
* To prevent re-parsings, this lookup maps verbatim system/staff texts
* to the {@link TuningConfig} it results in when parsed.
*
* @typedef {Object.<string, TuningConfig>} TuningConfigLookup
*/
/**
* Contains a list of N {@link AccidentalSymbol} hashes, where N is the
* number of nominals in the tuning system.
*
* The Xth hash represents the accidental symbol(s) to be applied on the Xth nominal
* by the key signature. The first hash corresponds to the nominal as stated by the
* reference tuning note.
*
* E.g. if `G4: 440` is used, then `KeySig[0]` will be the accidental that applies
* to G, `KeySig[1]` applies to A, etc…
*
* If no accidental is to be applied on the nominal, the entry should be `null`.
*
* The list is to contain N hash/null entries at all times. However, because it
* is impossible to validate whether a KeySig declaration has the right number
* of nominals, validation checks have to be done before attempts to look up the
* KeySig.
*
* @typedef {(?string)[]} KeySig
*/
/**
* Represents a pseudo-{@link TuningConfig} object which is used to change the
* reference note/tuning of the current tuning system without recalculating
* the entire {@link TuningConfig}.
*/
class ChangeReferenceTuning {
/**
* MIDI note number of reference note.
* @type {number}
*/
tuningNote;
/**
* How many 12edo nominals from A4 is the reference note.
* @type {number}
*/
tuningNominal;
/**
* Hz of the reference note.
* @type {number}
*/
tuningFreq;
/**
* `false` if the change reference tuning declaration is prefixed
* with `!` which signifies that the tuning config's nominals should
* be redeclared starting on the new reference note, effectively
* changing the 'mode' of the nominal scale.
*
* E.g. if a tuning config is originally declared to be A4: 440,
* but a reference tuning change is declared as `!C4: 263`, then
* the new interval between the written D and E will actually be
* the same as the interval between B and C before the reference
* tuning change.
*
* Otherwise, if `!` is not stated, then this value is `true`.
*
* If this is `false`, then {@link changeRelativeNominalOnly}
* must also be `false`, otherwise this wouldn't make sense
*
* @type {boolean}
*/
preserveNominalsMode;
/**
* Signifies that only the relative nominal should be changed
* (the frequency is unspecified, e.g. "E5:").
*
* This changes the relative 1/1 of fingering annotations
* that specify JI ratios.
*
* If this is `true`, then {@link preserveNominalsMode} must
* also be `true`.
*
* @type {boolean}
*/
changeRelativeNominalOnly;
}
/**
* A function that updates config properties in parms as part
* of the {@link ConfigUpdateEvent}
*
* @callback configUpdateCallback
* @param {Parms} parms
*/
/**
* This object represents a single parms configuration update event that
* is to be executed when (or after) the cursor reaches tick position.
*
* The purpose of the {@link ConfigUpdateEvent} is to update {@link TuningConfig},
* {@link KeySig}, and other settings on a staff-by-staff basis.
*
* System Text config annotations affect all staves and Staff Text annotations
* affect only the staff that it is on.
*
* This allows the plugin to support multiple simultaneous & changing tuning
* systems and changing key signatures etc… since every config is applied
* according to when it is placed in the score.
*/
class ConfigUpdateEvent {
/**
* When {@link Cursor} is on/passes this tick, the config should
* be applied.
*
* @type {number}
*/
tick;
/**
* Callback function that modifies parms object.
*
* @type {configUpdateCallback}
*/
config;
}
/**
* `parms` represents the global state object of the plugin.
*
* The {@link ConfigUpdateEvent}s in {@link staffConfigs} will modify properties
* of parms over time to reflect the current configurations applied to the current
* staff ({@link Cursor.staffIdx}) to apply at current cursor position.
*/
class Parms {
/**
* Contains ticks of the first {@link PluginAPISegment} of each bar,
* sorted in increasing order.
*
* @type {number[]}
*/
bars;
/**
* Contains a mapping of each {@link Cursor.staffIdx} to a list of
* {@link ConfigUpdateEvent}s that affect that stave.
*
* @type {Object.<number, ConfigUpdateEvent[]>}
*/
staffConfigs;
/**
* Current key signature being presently applied.
*
* @type {KeySig}
*/
currKeySig;
/**
* Current tuning configuration being presently applied
*
* @type {TuningConfig}
*/
currTuning;
// TODO implement currExplicit
currExplicit;
}
/**
* Represents a saved {@link Cursor} position created by
* {@link saveCursorPosition}(Cursor)
*
* Cursor position can be restored with
* {@link restoreCursorPosition}(SavedCursorPosition)
*/
class SavedCursorPosition {
/**
* Saved {@link Cursor.tick}
* @type {number}
*/
tick;
/**
* Saved {@link Cursor.staffIdx}
* @type {number}
*/
staffIdx;
/**
* Saved {@link Cursor.voice}
* @type {number}
*/
voice;
}
/**
* A list of {@link NextNoteOption} which contains enharmonically equivalent spellings
* of a modified note in {@link chooseNextNote}.
*
* To be sorted such that the first entry is used.
*
* @typedef {NextNoteOption[]} NextNoteOptions
*/
/**
* Represents a single option for a possible note spelling for the modified
* note after an up/down operation.
*
* @typedef {Object} NextNoteOption
* @property {NextNote} nextNote
* @property {number} avDist - Squared {@link AccidentalVector} distance from prior accidental context,
* @property {number} absAvDist - Squared {@link AccidentalVector} distance from origin nominal,
* @property {number} numSymbols - Number of symbols in {@link XenNote.orderedSymbols}
* @property {number} lineOffset - Amount to add to {@link PluginAPINote.line} to update the nominal.
* @property {number} sumOfDegree - Sum of degrees of {@link AccidentalVector}
*/
/**
* Return value of {@link chooseNextNote}() function. Contains info about what
* which note the plugin chooses to provide as the ‘next note’ during the
* up/down/enharmonic cycle operations.
*/
class NextNote {
/** @type {XenNote} */
xen;
/**
* Xen nominal of the new note (modulo equave)
* @type {number} */
nominal;