VexFlowConverter.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. import {SystemLinesEnum} from "../SystemLinesEnum";
  15. export class VexFlowConverter {
  16. private static majorMap: {[_: number]: string; } = {
  17. "0": "C", 1: "G", 2: "D", 3: "A", 4: "E", 5: "B", 6: "F#", 7: "C#",
  18. 8: "G#", "-1": "F", "-8": "Fb", "-7": "Cb", "-6": "Gb", "-5": "Db", "-4": "Ab", "-3": "Eb", "-2": "Bb",
  19. };
  20. private static minorMap: {[_: number]: string; } = {
  21. "1": "E", "7": "A#", "0": "A", "6": "D#", "3": "F#", "-5": "Bb", "-4": "F", "-7": "Ab", "-6": "Eb",
  22. "-1": "D", "4": "C#", "-3": "C", "-2": "G", "2": "B", "5": "G#", "-8": "Db", "8": "E#",
  23. };
  24. public static duration(fraction: Fraction): string {
  25. let dur: number = fraction.RealValue;
  26. if (dur === 1) {
  27. return "w";
  28. } else if (dur < 1 && dur >= 0.5) {
  29. return "h";
  30. } else if (dur < 0.5 && dur >= 0.25) {
  31. return "q";
  32. } else if (dur < 0.25 && dur >= 0.125) {
  33. return "8";
  34. } else if (dur < 0.125 && dur >= 0.0625) {
  35. return "16";
  36. } else if (dur < 0.0625 && dur >= 0.03125) {
  37. return "32";
  38. }
  39. return "128";
  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, clef: ClefInstruction): [string, string, ClefInstruction] {
  48. let fund: string = NoteEnum[pitch.FundamentalNote].toLowerCase();
  49. let octave: number = pitch.Octave + clef.OctaveOffset + 3; // FIXME + 3
  50. let acc: string = "";
  51. switch (pitch.Accidental) {
  52. case AccidentalEnum.NONE:
  53. break;
  54. case AccidentalEnum.FLAT:
  55. acc = "b";
  56. break;
  57. case AccidentalEnum.SHARP:
  58. acc = "#";
  59. break;
  60. case AccidentalEnum.DOUBLESHARP:
  61. acc = "##";
  62. break;
  63. case AccidentalEnum.DOUBLEFLAT:
  64. acc = "bb";
  65. break;
  66. default:
  67. }
  68. return [fund + acc + "/" + octave, acc, clef];
  69. }
  70. public static StaveNote(notes: GraphicalNote[]): Vex.Flow.StaveNote {
  71. let keys: string[] = [];
  72. let frac: Fraction = notes[0].sourceNote.Length;
  73. let duration: string = VexFlowConverter.duration(frac);
  74. let accidentals: string[] = [];
  75. let vfclef: string;
  76. for (let note of notes) {
  77. let res: [string, string, ClefInstruction] = (note as VexFlowGraphicalNote).vfpitch;
  78. if (res === undefined) {
  79. keys = ["b/4"];
  80. accidentals = [];
  81. duration += "r";
  82. break;
  83. }
  84. keys.push(res[0]);
  85. accidentals.push(res[1]);
  86. if (!vfclef) {
  87. vfclef = VexFlowConverter.Clef(res[2]);
  88. }
  89. }
  90. let vfnote: Vex.Flow.StaveNote = new Vex.Flow.StaveNote({
  91. auto_stem: true,
  92. clef: vfclef,
  93. duration: duration,
  94. duration_override: {
  95. denominator: frac.Denominator,
  96. numerator: frac.Numerator,
  97. },
  98. keys: keys,
  99. });
  100. for (let i: number = 0, len: number = keys.length; i < len; i += 1) {
  101. let acc: string = accidentals[i];
  102. if (acc) {
  103. vfnote.addAccidental(i, new Vex.Flow.Accidental(acc));
  104. }
  105. }
  106. return vfnote;
  107. }
  108. public static Clef(clef: ClefInstruction): string {
  109. let type: string;
  110. switch (clef.ClefType) {
  111. case ClefEnum.G:
  112. type = "treble";
  113. break;
  114. case ClefEnum.F:
  115. type = "bass";
  116. break;
  117. case ClefEnum.C:
  118. type = "baritone-c";
  119. break;
  120. case ClefEnum.percussion:
  121. type = "percussion";
  122. break;
  123. case ClefEnum.TAB:
  124. type = "tab";
  125. break;
  126. default:
  127. }
  128. return type;
  129. }
  130. public static TimeSignature(rhythm: RhythmInstruction): Vex.Flow.TimeSignature {
  131. let timeSpec: string;
  132. switch (rhythm.SymbolEnum) {
  133. case RhythmSymbolEnum.NONE:
  134. timeSpec = rhythm.Rhythm.Numerator + "/" + rhythm.Rhythm.Denominator;
  135. break;
  136. case RhythmSymbolEnum.COMMON:
  137. timeSpec = "C";
  138. break;
  139. case RhythmSymbolEnum.CUT:
  140. timeSpec = "C|";
  141. break;
  142. default:
  143. }
  144. return new Vex.Flow.TimeSignature(timeSpec);
  145. }
  146. public static keySignature(key: KeyInstruction): string {
  147. if (key === undefined) {
  148. return undefined;
  149. }
  150. let ret: string;
  151. switch (key.Mode) {
  152. case KeyEnum.none:
  153. ret = undefined;
  154. break;
  155. case KeyEnum.minor:
  156. ret = VexFlowConverter.minorMap[key.Key] + "m";
  157. break;
  158. case KeyEnum.major:
  159. ret = VexFlowConverter.majorMap[key.Key];
  160. break;
  161. default:
  162. }
  163. return ret;
  164. }
  165. public static line(lineType: SystemLinesEnum): any {
  166. return Vex.Flow.StaveConnector.type.DOUBLE;
  167. }
  168. }