0

I'm creating a stave note with multiple keys:

const staveNote: vexflow.Flow.StaveNote = new this.VF.StaveNote({
  keys: this.renderNotesSortedByPitch(placedChord.notes),
  duration: chordDuration,
  auto_stem: true,
  clef: Clef.TREBLE
});

private renderNotesSortedByPitch(notes: Array<Note>): Array<string> {
  const vexflowNotes: Array<string> = new Array<string>();
  notes
  // this.sortNotesByPitch(notes)
  .forEach((note: Note) => {
    vexflowNotes.push(this.renderNote(note));
  });
  return vexflowNotes;
}

private sortNotesByPitch(notes: Array<Note>): Array<Note> {
  return notes.sort((noteA: Note, noteB: Note) => {
    return noteA.pitch.chroma.value - noteB.pitch.chroma.value   <--- No arithmetic operation on strings
  });
}

and I get the following warning in the browser console:

Warning:  Unsorted keys in note will be sorted. See https://github.com/0xfe/vexflow/issues/104 for details. Error
    at Function.b.StackTrace (http://localhost:4200/vendor.js:93990:4976)
    at Function.b.W (http://localhost:4200/vendor.js:93990:5134)
    at http://localhost:4200/vendor.js:93990:255605
    at Array.forEach (<anonymous>)
    at e.value (http://localhost:4200/vendor.js:93990:255572)
    at new e (http://localhost:4200/vendor.js:93990:250357)
    at SheetService.vexflowRenderSoundtrack (http://localhost:4200/main.js:2083:51)
    at SheetService.createSoundtrackSheet (http://localhost:4200/main.js:2004:14)
    at SheetComponent.createSheet (http://localhost:4200/main.js:2465:35)
    at SheetComponent.ngAfterViewInit (http://localhost:4200/main.js:2452:14)

I understand I need to provide the keys already sorted the way Vexflow is sorting them.

A similar issue is also described there.

How to sort the keys with the note.pitch.chroma.value being a string ?

It'd be nice to have some method in the same fashion as:

staveNote.setKeyStyle(0, { fillStyle: 'red' });

Say, some such method:

staveNote.setDotted(0);

Or:

staveNote.setKeyStyle(0, { fillStyle: 'red', dotted: true });

UPDATE: Following a suggestion I could create the methods to sort the notes before adding them as keys in the stave:

  private getNoteFrequency(note: Note): number {
    return Tone.Frequency(note.renderAbc()).toFrequency();
  }

  private sortNotesByPitch(notes: Array<Note>): Array<Note> {
    return notes.sort((noteA: Note, noteB: Note) => {
      return this.getNoteFrequency(noteA) - this.getNoteFrequency(noteB);
    });
  }

The Vexflow warning message was no longer displayed in the browser console.

Stephane
  • 11,836
  • 25
  • 112
  • 175

1 Answers1

1

Vexflow expects your notes to be sorted vertically, no way around that. You need to write your own function to compare two notes given as strings.

here's a working note-string-comparison-function which doesn't take accidentals into account: repl.it/repls/WobblyFavorableYottabyte

edited for clarity, thanks @gristow for the correction!

sschmidTU
  • 132
  • 5
  • here's a working note-string-comparison-function which doesn't take into account accidentals: https://repl.it/repls/WobblyFavorableYottabyte – sschmidTU Mar 24 '20 at 21:12
  • 2
    The sorting routine you describe is incorrect for VexFlow -- VexFlow only compares what line/space the notes are on. So: although E# is a higher pitch than Fb, it should be sorted first in the array. (See StaveNote.js for the sorting routine: https://github.com/0xfe/vexflow/blob/b6874d4e38a962bf0d512ae598a67719ebe7c61c/src/stavenote.js#L515) – gristow Mar 24 '20 at 23:21
  • Shall I understand the sorting routine is not exposed in the API for us to use ? – Stephane Mar 25 '20 at 12:15
  • @sschmidTU Following your suggestion of comparing frequencies, I can get the frequency of each note with the `Tone.Frequency(note.renderAbc()).toFrequency()` method call. I could then create the method to sort the notes. The Vexflow warning message was not displayed in the browser console any longer. – Stephane Mar 25 '20 at 12:37
  • 1
    @Stephane -- you should ignore accidentals in your sort. Your routine is close, but will fail if you have the keys [Fb4, E#4]. VexFlow will expect them to be sorted as [E#4, Fb4], but your algorithm will sort them as [Fb4, E#4] and VexFlow will again give a warning. And, yes, the sorting routine is not exposed in the API. – gristow Mar 25 '20 at 13:42
  • @gristow All right, I'll strip the `#` accidental from the note if any then, so as to get `E4` from `E#4` as a note, before getting the frequency. – Stephane Mar 25 '20 at 16:03
  • @gristow you're right, thanks for the correction! updated the answer. My example function does not take accidentals into account, so Stephane i think you're on the right track, just add ignoring of accidentals to the code, and you should be good. – sschmidTU Mar 26 '20 at 16:08
  • 1
    by the way, the way Vexflow sorts unsorted notes is `this.keyProps.sort((a, b) => a.line - b.line);`, from stavenote.js – sschmidTU Mar 26 '20 at 16:09