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:
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:
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:
Multiple Roles
Use multiple lines to represent different aspects of the composition:
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:
Cycle and Line Management
Use cycle and line commands to organize longer pieces:
Practice Exercise
Create a complete composition using all the techniques you've learned:
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
- Reference Documentation - Complete syntax specification
- Examples - Real-world examples and patterns
- API Documentation - Use the library programmatically
- Observer Pattern API - Full observer API reference