VexFlowConverter.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import Vex = require("vexflow");
  2. import {ClefEnum} from "../../VoiceData/Instructions/ClefInstruction";
  3. import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
  4. import {Pitch} from "../../../Common/DataObjects/pitch";
  5. import {Fraction} from "../../../Common/DataObjects/fraction";
  6. import {RhythmInstruction} from "../../VoiceData/Instructions/RhythmInstruction";
  7. import {RhythmSymbolEnum} from "../../VoiceData/Instructions/RhythmInstruction";
  8. import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
  9. import {KeyEnum} from "../../VoiceData/Instructions/KeyInstruction";
  10. import {AccidentalEnum} from "../../../Common/DataObjects/pitch";
  11. import {NoteEnum} from "../../../Common/DataObjects/pitch";
  12. import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
  13. import {GraphicalNote} from "../GraphicalNote";
  14. export class VexFlowConverter {
  15. private static majorMap: {[_: number]: string; } = {
  16. "0": "C", 1: "G", 2: "D", 3: "A", 4: "E", 5: "B", 6: "F#", 7: "C#",
  17. 8: "G#", "-1": "F", "-8": "Fb", "-7": "Cb", "-6": "Gb", "-5": "Db", "-4": "Ab", "-3": "Eb", "-2": "Bb",
  18. };
  19. private static minorMap: {[_: number]: string; } = {
  20. "1": "E", "7": "A#", "0": "A", "6": "D#", "3": "F#", "-5": "Bb", "-4": "F", "-7": "Ab", "-6": "Eb",
  21. "-1": "D", "4": "C#", "-3": "C", "-2": "G", "2": "B", "5": "G#", "-8": "Db", "8": "E#",
  22. };
  23. public static duration(fraction: Fraction): string {
  24. let dur: number = fraction.RealValue;
  25. switch (dur) {
  26. case 0.25:
  27. return "q";
  28. case 0.5:
  29. return "h";
  30. case 1:
  31. return "w";
  32. case 0.125:
  33. return "8";
  34. case 0.0625:
  35. return "16";
  36. // FIXME TODO
  37. default:
  38. return "16";
  39. }
  40. }
  41. /**
  42. * Takes a Pitch and returns a string representing a VexFlow pitch,
  43. * which has the form "b/4", plus its alteration (accidental)
  44. * @param pitch
  45. * @returns {string[]}
  46. */
  47. public static pitch(pitch: Pitch, octaveOffset: number): [string, string] {
  48. let fund: string = NoteEnum[pitch.FundamentalNote].toLowerCase();
  49. let octave: number = pitch.Octave + octaveOffset + 3;
  50. console.log("pitch", pitch.Octave, octaveOffset);
  51. let acc: string = "";
  52. switch (pitch.Accidental) {
  53. case AccidentalEnum.NONE:
  54. break;
  55. case AccidentalEnum.FLAT:
  56. acc = "b";
  57. break;
  58. case AccidentalEnum.SHARP:
  59. acc = "#";
  60. break;
  61. case AccidentalEnum.DOUBLESHARP:
  62. acc = "##";
  63. break;
  64. case AccidentalEnum.DOUBLEFLAT:
  65. acc = "bb";
  66. break;
  67. default:
  68. }
  69. return [fund + acc + "/" + octave, acc];
  70. }
  71. public static StaveNote(notes: GraphicalNote[]): Vex.Flow.StaveNote {
  72. let keys: string[] = [];
  73. let duration: string = VexFlowConverter.duration(notes[0].sourceNote.Length);
  74. let accidentals: string[] = [];
  75. for (let note of notes) {
  76. let res: [string, string] = (note as VexFlowGraphicalNote).vfpitch;
  77. if (res === undefined) {
  78. keys = ["b/4"];
  79. accidentals = [];
  80. duration += "r";
  81. break;
  82. }
  83. keys.push(res[0]);
  84. accidentals.push(res[1]);
  85. }
  86. let vfnote: Vex.Flow.StaveNote = new Vex.Flow.StaveNote({
  87. duration: duration,
  88. keys: keys,
  89. });
  90. for (let i: number = 0, len: number = keys.length; i < len; i += 1) {
  91. let acc: string = accidentals[i];
  92. if (acc) {
  93. vfnote.addAccidental(i, new Vex.Flow.Accidental(acc));
  94. }
  95. }
  96. return vfnote;
  97. }
  98. public static Clef(clef: ClefInstruction): string {
  99. let type: string;
  100. switch (clef.ClefType) {
  101. case ClefEnum.G:
  102. type = "treble";
  103. break;
  104. case ClefEnum.F:
  105. type = "bass";
  106. break;
  107. case ClefEnum.C:
  108. type = "baritone-c";
  109. break;
  110. case ClefEnum.percussion:
  111. type = "percussion";
  112. break;
  113. case ClefEnum.TAB:
  114. type = "tab";
  115. break;
  116. default:
  117. }
  118. return type;
  119. }
  120. public static TimeSignature(rhythm: RhythmInstruction): Vex.Flow.TimeSignature {
  121. let timeSpec: string;
  122. switch (rhythm.SymbolEnum) {
  123. case RhythmSymbolEnum.NONE:
  124. timeSpec = rhythm.Rhythm.Numerator + "/" + rhythm.Rhythm.Denominator;
  125. break;
  126. case RhythmSymbolEnum.COMMON:
  127. timeSpec = "C";
  128. break;
  129. case RhythmSymbolEnum.CUT:
  130. timeSpec = "C|";
  131. break;
  132. default:
  133. }
  134. return new Vex.Flow.TimeSignature(timeSpec);
  135. }
  136. public static keySignature(key: KeyInstruction): string {
  137. if (key === undefined) {
  138. return undefined;
  139. }
  140. let ret: string;
  141. switch (key.Mode) {
  142. case KeyEnum.none:
  143. ret = undefined;
  144. break;
  145. case KeyEnum.minor:
  146. ret = VexFlowConverter.minorMap[key.Key] + "m";
  147. break;
  148. case KeyEnum.major:
  149. ret = VexFlowConverter.majorMap[key.Key];
  150. break;
  151. default:
  152. }
  153. //console.log("keySignature", key, ret);
  154. return ret;
  155. }
  156. }