Notes and Chords#

[1]:
from manimusic import *

config.media_embed = True; config.media_width = "100%"
_RV = "-v WARNING -qm --progress_bar None --disable_caching Example"
_RI = "-v WARNING -s --progress_bar None --disable_caching Example"
_RV_mid = "-v WARNING -qm -r 1600,400 --progress_bar None --disable_caching Example"
_RI_mid = "-v WARNING -s -r 1600,400 --progress_bar None --disable_caching Example"
Manim Community v0.17.3

Notes#

Warning

Optional elements can be in any order, but the first two required elements must be in the specified order.

* Fist element         [required]  : "m" Minim or "c" Crotchet or "s" Semibreve
* Second element       [required]  : C,D,E,F,G,A,B
* Reference            [default=0] : Positive or negative number
* Alteration           [optional]  : #,b,n
* Stem                 [default=d] : x,d,u
* Body shifted         [optional]  : r, l
* Note shifted         [optional]  : R, L <- Shift all note
* Alteration shifted   [optional]  : a, h, H, _
[2]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gfc", width=10)
    pt = staff.partition
    partitions = staff.get_ticks()
    n_g = Note(staff, "mC#x", 6/pt, 0).set_color(RED)
    n_f = Note(staff, "cCbu", 6/pt, 1).set_color(PURPLE)
    n_c = Note(staff, "sCn",  6/pt, 2).set_color(TEAL)

    self.add(staff, n_g, n_f, n_c, partitions)

%manim $_RI
_images/CHP_2_4_0.png

Reference#

[3]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    notes = VGroup(
      Note(staff, "mC",   6 /pt).set_color(RED),
      Note(staff, "cC1",  10/pt).set_color(TEAL),
      Note(staff, "sC2",  14/pt).set_color(TEAL),
      Note(staff, "sB-1", 18/pt).set_color(YELLOW),
    )

    self.add(staff, notes)

%manim $_RI_mid
_images/CHP_2_6_0.png

Stems#

Note

The Semibreve note does not have a stem, even if we explicitly define it.

[4]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    notes = VGroup(
      Note(staff, "mC",    6 /pt).set_color(RED),
      Note(staff, "mC1u",  10/pt).set_color(RED),
      Note(staff, "cC2u",  14/pt).set_color(TEAL),
      Note(staff, "cB-1x", 18/pt).set_color(TEAL),    # "x" to remove stem
      Note(staff, "mA-1x", 22/pt).set_color(YELLOW),
      Note(staff, "sBu",   26/pt).set_color(YELLOW),  # <- "u" does nothing to Semibreve
    )

    self.add(staff, notes)

%manim $_RI_mid
_images/CHP_2_8_0.png

Alterations#

Warning

The double sharp and double flat symbols were not included because I never used them. This library is geared towards Harmony and Counterpoint lectures, not writing sheet music. In case you need it, you can perfectly import the symbol with an SVG, change the scale and position using the methods you saw in Staffs chapter.

[5]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    notes = VGroup(
      Note(staff, "mC", 6/pt).set_color(RED),
      Note(staff, "mC1u#", 10/pt).set_color(RED),
      Note(staff, "cCb2u", 14/pt).set_color(TEAL),
      Note(staff, "cBn-1x", 18/pt).set_color(TEAL),
      # Chords:
      Note(staff, "sB-1br"    , 22/pt).set_color(YELLOW),
      Note(staff, "sA-1nh", 22/pt).set_color(YELLOW),
    )

    self.add(staff, notes)

%manim $_RI_mid
_images/CHP_2_10_0.png

Note parts#

[6]:
class Example(Scene):
  def construct(self):
    staff = Staff(width=2).scale(1.4).shift(UP * 0.2)
    note = Note(staff, "cA-1#u",   0.5)

    note.stem.set_color(PURPLE)
    note.body.set_color(RED)
    note.alteration.set_color(TEAL)
    note.additional_lines.set_color(YELLOW)

    self.add(staff, note)

%manim $_RI_mid
_images/CHP_2_12_0.png

Note

You can use the Note.get_parts(attr1, attr2, ...) method to get multiple parts of the note, if an attribute doesn’t exist it will be ignored.

[7]:
class Example(Scene):
  def construct(self):
    staff = Staff(width=2).scale(1.4).shift(UP * 0.2)
    note = Note(staff, "cA-1#u",   0.5)

    note.get_parts("body", "alteration").set_color(RED)
    note.get_parts("stem", "additional_lines", "random_attr").set_color(TEAL)

    self.add(staff, note)

%manim $_RI_mid
_images/CHP_2_14_0.png

Additional lines#

Note

The additional lines are inside Staff, not Note, but they can also be accessed through Note as an attribute.

[8]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gf", width=2)
    note1 = Note(staff, "cA-1#u", 0.5, 0)
    note2 = Note(staff, "cE1#u",  0.8, 1)
    note1.additional_lines.set_color(RED)
    staff.additional_lines[1][0].set_color(YELLOW)
    staff.additional_lines[1][1].set_color(TEAL)

    self.add(staff) # Note that we are not adding the notes

%manim $_RI_mid
_images/CHP_2_16_0.png

Melodies and Chords#

Note

Points . must be at the end.

[9]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gfc", width=10, bars=[*range(6,13)])
    staff.bars_group.fade(0.6)
    partitions = staff.get_ticks().set_color(YELLOW)
    #                       staff, note1|note2|...  ,prop,line
    chord_line  = ChordLine(staff, "C|Eb|G|Bbla|C1#h", 0.2, 0, merge_stems=True).set_color(RED)
    chord_stems = ChordLine(staff, "Ed|Gu",            0.4, 0, glob="c").set_color(PURPLE)
    melody      =    Melody(staff, "C|Eb|G|Bb |C1 ",   0.2, 1, increment=0.15, glob="cu").set_color(TEAL)
    melody2     =    Melody(staff, "C|Eb.|G...|Bb ",   0.2, 2, increment=1/30, glob="s").set_color(PINK)

    # chord_line.stem.set_color(ORANGE).scale([1,0.8,1], about_edge=UP)

    self.add(staff, partitions, chord_line, chord_stems, melody, melody2)

%manim $_RI
_images/CHP_2_19_0.png

Note

If you have a Staff with only one line you can omit it just like with notes.

[10]:
class Example(Scene):
  def construct(self):
    staff = Staff(width=3).scale(1.4)
    chord_line  = ChordLine(staff, "Cb|Eba|GbH_|Bblh|C1#h", 0.6, glob="m")
    chord_line[0].set_color(RED)
    chord_line[1].set_color(TEAL)
    chord_line[2].set_color(YELLOW)
    chord_line[3].set_color(ORANGE)
    chord_line[4].set_color(PINK)
    self.add(staff, chord_line)

%manim $_RI_mid
_images/CHP_2_21_0.png

Additional lines#

Note

In the ChordLines there can be several additional_lines at the same time, so the lines that are unnecessary will be filtered. In the same way as the Note, these lines do not belong to ChordLine, but to Staff.

[11]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=12, height=0.8)
    #                         0|1  |2  |3  |4 |5 <-- Array order
    chord = ChordLine(staff, "E|D-1|F-1|B-1|C2|A1", 0.3).set_color(RED)
    chord.additional_lines.set_color(TEAL) # access with Chord
    chord[1].set_color(BLUE)
    chord[1].additional_lines.shift(LEFT)  # access with Note (Down)
    chord[4].set_color(BLUE)
    chord[4].additional_lines.shift(RIGHT) # access with Note (Up)

    chord_lines_up   = ChordLine(staff, "C2|E2", 0.5).set_color(ORANGE)
    chord_lines_up.additional_lines.set_color(PINK)
    chord_lines_down = ChordLine(staff, "A-1|F-1", 0.8).set_color(YELLOW)
    chord_lines_down.additional_lines.set_color(BLUE)

    self.add(staff, chord, chord_lines_up, chord_lines_down)


%manim $_RI_mid
_images/CHP_2_23_0.png

Note

So that you don’t get confused when selecting notes of a chord, define the chords in an ascending or descending way, so identifying the index of each note will be easier.

[12]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=3, height=0.8).scale(2).shift(UP)
    chord = ChordLine(staff, "D-1l|E-1|A-1l|B-1|C2l|D2", 0.4, merge_stems=True)
    # chord.stem.scale([1,0.9,1],about_edge=UP)
    self.add(staff, chord)


%manim $_RI
_images/CHP_2_25_0.png

Multi-Chords#

[13]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gf", width=12, height=0.7)

    multi_chords = VGroup(
      MultiChord(staff, "m|Cd,G#u|A-1d#,C1u", 0.2, [1, 0]), # order matters [0, 1] or [1, 0]
      MultiChord(staff, "s|C,G",              0.3, [0])          .set_color(RED),
      MultiChord(staff, "c|C,G",              0.3, [1], glob="x").set_color(TEAL),
      MultiChord(staff, "m|C,G|A-1b,C2",      0.5, [1, 0])       .set_color(YELLOW),
      MultiChord(staff, "m|C,G|A-1b,C1",      0.7, [1, 0], glob="u#").set_color(PURPLE),
      MultiChord(staff, "m|C,G|A-1b,C1d",     0.9, [1, 0], glob="u") .set_color(GOLD),
    )

    multi_chords[3].additional_lines.shift(LEFT*0.2)
    multi_chords[4].additional_lines.shift(RIGHT*0.2)
    multi_chords[-1][0].set_color(PINK) # From GOLD to PINK

    self.add(staff, multi_chords)
%manim $_RI_mid
_images/CHP_2_27_0.png

Intervals#

[14]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gf", width=3, height=0.7)
    multi_chord = MultiChord(staff, "m|Cd,G#u|A-1d#,C1u", 0.6)

    vi1 = VInterval(
        multi_chord[0][0],
        multi_chord[0][1],
        buff=0.1,
        direction=LEFT # Default: RIGHT
    ).set_color(BLUE)

    tex_interval = vi1.get_text("X", background_buff=0.08, font_size=30, color=BLUE, buff=0.2)

    self.add(staff, multi_chord, vi1, tex_interval)


%manim $_RI_mid
_images/CHP_2_29_0.png

Note progression#

[15]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    notes = VGroup(
      Note(staff, "mB-1b",6 /pt).set_color(RED),
      Note(staff, "mC#",  10/pt).set_color(BLUE),
      Note(staff, "cA#",  14/pt).set_color(GREEN),
      Note(staff, "cE1",  18/pt).set_color(TEAL),
      Note(staff, "mA1n", 22/pt).set_color(YELLOW),
    )

    self.play(ShowStaff(staff))
    self.play(
      # Write(notes[0]),
      # Write(notes[0].additional_lines),
      # Or
      notes[0].show_note(Write)
    )

    for i in range(1,len(notes)):
      base_note   = notes[i-1]
      target_note = notes[i]
      self.play(
        TransformFromCopy(
          base_note.get_parts("body", "stem"),
          target_note.get_parts("body", "stem")
        ),
        # ShowAdditionLinesNote creates the alteration and
        # additional lines for the Note in case they exist
        *ShowAdditionLinesNote(target_note, Write)
      )
    self.wait()

%manim $_RV_mid

This can be simplified if we use Melody.

[16]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    #                      0     |1   |2  |3  |4
    notes = Melody(staff, "mB-1b.|mC#u|sA#|cE1|mA1n", 6/pt, increment=2/pt)
    notes[0].set_color(RED)
    notes[3].set_color(TEAL)

    self.play(ShowStaff(staff))
    self.play(notes[0].show_note(Write))

    for i in range(1,len(notes)):
      base_note   = notes[i-1]
      target_note = notes[i]
      self.play(
        TransformFromCopy(
          base_note.get_parts("body", "stem"),
          target_note.get_parts("body", "stem")
        ),
        # ShowAdditionLinesNote creates the alteration and
        # additional lines for the next Note in case they exist
        *ShowAdditionLinesNote(target_note, Write),
        run_time=1
      )
    self.wait()

%manim $_RV_mid

Chord progression#

[17]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    pt = staff.partition
    chords = VGroup(
      ChordLine(staff, "C|G|Bba|C1r#", 0.2, glob="s"),
      ChordLine(staff, "A-1b|F|C1#|F1", 0.4, glob="s"),
      ChordLine(staff, "B-1ba|D#|Bb|E1", 0.6, glob="s"),
    )

    self.play(ShowStaff(staff))
    self.play(chords[0].show_chord(Write))

    for i in range(1,len(chords)):
      base_chord   = chords[i-1]
      target_chord = chords[i]
      self.play(
        *[
          TransformFromCopy(
            base_note.get_parts("body", "stem"),
            target_note.get_parts("body", "stem"),
            run_time=2
          )
          for base_note, target_note in zip(base_chord, target_chord)
        ],
        LaggedAnim(
          0.8, # <- Start animation after 0.8 secs
          *ShowAdditionLinesChord(target_chord, Write),
        )
      )
    self.wait()

%manim $_RV_mid

Multi-chord progression#

[18]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gf", width=10)
    pt = staff.partition
    chords = VGroup(
      MultiChord(staff, "m|Cd   ,  G#u|A-1d#,C1u", 0.2),
      MultiChord(staff, "m|GdR#H,Abua_|B-1b ,C1u", 0.4),
      MultiChord(staff, "m|G-1d ,  Gbu|B-1b ,Bbu", 0.6),
      MultiChord(staff, "m|C-1d ,  G0u|Ebd  ,C1u", 0.8),
    )

    self.play(ShowStaff(staff))
    self.play(chords[0].show_chord(Write))

    for i in range(1,len(chords)):
      base   = chords[i-1]
      target = chords[i]
      self.play(
        *[
          TransformFromCopy(
            note_base.get_parts("body", "stem"),
            note_target.get_parts("body", "stem"),
            run_time=2
          )
          for chord_base, chord_target in zip(base, target)
          for note_base, note_target in zip(chord_base, chord_target)
        ],
        LaggedAnim(
          1.2, # <- Start animation after 1.2 secs
          *ShowAdditionLinesMultiChord(target, Write),
        )
      )
    self.wait()

%manim $_RV

Same but with HarmonyProgression#

[19]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="gf", width=12, height=1)

    chords = HarmonyProgression(
      staff,
      "m|Cd   ,  G#u|A-1d#,C1u",
      "m|GdR#H,Abua_|B-1b ,C1u",
      "m|G-1d ,  Gbu|B-1b ,Bbu",
      "m|C-1d ,  G0u|Ebd  ,C1u",
    )

    self.play(ShowStaff(staff))
    self.play( chords.show_chord(0, Write) )
    for i in range(1,len(chords)):
      self.play(
        *chords.transform(i-1, i, run_time=2),
      )
    self.wait()

%manim $_RV
[20]:
class Example(Scene):
  def construct(self):
    staff = Staff(clefs="g", width=10)
    chords = HarmonyProgression(
      staff,
      "s|C,G,Bba,C1r#",
      "s|A-1b,F,C1#,F1",
      "s|B-1ba,D#,Bb,E1",
    )

    self.play(ShowStaff(staff))
    self.play(chords[0].show_chord(Write))

    for i in range(1,len(chords)):
      self.play(*chords.transform(i-1, i, run_time=2))
    self.wait()

%manim $_RV_mid