How do I transpose music chords using JavaScript?

前端 未结 7 1360
忘掉有多难
忘掉有多难 2021-02-08 08:56

I was wondering how would one create a javascript function for transposing music chords.

Since I don\'t expect everyone to be a musician here, I\'ll try to explain how i

7条回答
  •  北恋
    北恋 (楼主)
    2021-02-08 09:34

    All of these solutions are lacking the fact that after transposing a note, it needs to be converted to a sharp or flat depending on the key or chord.

    So the API must be:

    transpose(note, semitones, useSharps)
    

    Here is my implementation. It also handles multiple # and b modifiers.

    function transposeNote(note, semitones, useSharps) {
      // parse root followed by modifiers (# and b)
      const rx = /^([a-gA-G])([#b]*)$/;
      const m = rx.exec(note);
      if (!m) {
        return null;
      }
      // convert note from 0 to 11 based off of A
      let root;
      switch (m[1].toUpperCase()) {
        case "A":
          root = 0;
          break;
        case "B":
          root = 2;
          break;
        case "C":
          root = 3;
          break;
        case "D":
          root = 5;
          break;
        case "E":
          root = 7;
          break;
        case "F":
          root = 8;
          break;
        case "G":
          root = 10;
          break;
      }
      // modify root
      let mods = m[2];
      if (mods) {
        for (var i = 0; i < mods.length; i++) {
          if (mods.charAt(i) === "#") {
            root++;
          } else {
            root--;
          }
        }
      }
      // transpose note
      root = (root + semitones) % 12;
    
      if (root < 0) {
        root += 12
      }
    
      // convert back to a note
      const sharps = [
        "A",
        "A#",
        "B",
        "C",
        "C#",
        "D",
        "D#",
        "E",
        "F",
        "F#",
        "G",
        "G#"
      ];
      const flats = [
        "A",
        "Bb",
        "B",
        "C",
        "Db",
        "D",
        "Eb",
        "E",
        "F",
        "Gb",
        "G",
        "Ab"
      ];
      const transposedNote = useSharps ? sharps[root] : flats[root];
      return transposedNote;
    }
    
    function transposeChord(chord, semitones, useSharps) {
      const rx = /^([a-gA-G][#b]*)\s*([^\/]*)(\/[a-gA-G][#b]*)?$/;
      const m = rx.exec(chord);
      if (!m) {
        return null;
      }
      const root = transposeNote(m[1], semitones, useSharps);
      const quality = m[2] || "";
      let bass = m[3] || "";
      if (bass.length > 0) {
        bass = "/" + transposeNote(bass.substring(1), semitones, useSharps);
      }
      return root + quality + bass;
    }
    

    Use it like this

    console.log(transposeChord("Cmin7/Eb", 3, false));
    

提交回复
热议问题