Tutorial 04: Advanced Techniques

Master complex notation patterns and advanced features

This tutorial covers advanced techniques for creating complex Carnatic music notation.

Nested Groups

Groups can contain other groups for complex rhythmic patterns:

\beatDuration(4) S [R [G M] P] D N S.

The inner group [G M] is nested within the outer group [R [G M] P], creating a subdivision.

Custom Note Durations

Combine duration prefixes with beat duration for precise control:

\beatDuration(4) S 2 R [G M] 3 P D N S.

Here, R has duration 2 and P has duration 3 at a beat duration of 4 notes per beat.

Fractional Durations

Use fractions for precise duration control:

\beatDuration(4) S 3/2 R G 1/2 M P D N S.

Multiple Roles

Use multiple lines to represent different aspects of the composition:

\beatDuration(4) \role("Perc", notes=true) Sw: S R G M P D N S. Sh: sa ri ga ma pa dha ni sa Perc: ta ki ta ta ta ki ta ta

The first line shows swaras, the second shows sahitya, and the third shows percussion syllables.

Complex Rhythmic Patterns

Combine groups, spacing, and beat duration to create intricate rhythms:

\beatDuration(2) \line("First Speed") S [R G] , [M P] D \beatDuration(4) \line("Second Speed") [S R] [G M] [P D] [N S.] \beatDuration(2) \line("Back to First") S.

Cycle and Line Management

Use cycle and line commands to organize longer pieces:

\cycle("|4|2|2|") \beatDuration(4) \line("Pallavi") Sw: S R G M P D N S. \line("Anupallavi") Sw: S. N D P M G R S \line("Charanam") Sw: S R [G M] P [D N] S.

Practice Exercise

Create a complete composition using all the techniques you've learned:

\cycle("|4|2|2|") \beatDuration(2) \line("Opening") Sw: S R G M , P D N S. Sh: sa ri ga ma , pa dha ni sa \beatDuration(4) \line("Second Speed") Sw: S R [G M] [P D] N S. Sh: sa ri ga ma pa dha ni sa \beatDuration(2) \line("Closing") Sw: S. , , S Sh: sa , , sa

Model Change Events

The Notations library uses the Observer pattern to notify your code when the model changes. This is useful for building interactive editors, undo/redo systems, or keeping views synchronized with the model.

Enabling Events

First, enable events on entities you want to observe:

const group = new Group();
group.enableEvents();  // Now observers will receive notifications

Observing a Group

Add an observer to receive notifications when atoms are added, inserted, or removed:

import { Group, Note, GroupObserver } from 'notations';

const group = new Group();
group.enableEvents();

// Create an observer
const observer: GroupObserver = {
  onAtomsAdded: (group, atoms, index) => {
    console.log(`Added ${atoms.length} atoms at index ${index}`);
  },
  onAtomsRemoved: (group, atoms) => {
    console.log(`Removed ${atoms.length} atoms`);
  }
};

// Register and get unsubscribe function
const unsubscribe = group.addObserver(observer);

// Make changes - observer is notified
group.addAtoms(false, new Note("S"), new Note("R"));
// Output: Added 2 atoms at index 0

// Unsubscribe when done
unsubscribe();

Available Observers

  • GroupObserver - Observe atoms in a Group (onAtomsAdded, onAtomsInserted, onAtomsRemoved)
  • RoleObserver - Observe atoms in a Role (same callbacks as GroupObserver)
  • LineObserver - Observe roles in a Line (onRoleAdded, onRoleRemoved)
  • BlockObserver - Observe items in a Block (onItemAdded, onItemRemoved)

Use Cases

  • Live Editing - Update the rendered view when the user makes changes
  • Undo/Redo - Record changes to build an undo stack
  • Collaboration - Sync changes with other users
  • Validation - Check constraints when the model changes

Try the interactive Model Events demo to see observers in action.

Next Steps