Exploring the Shruti System: A Visual Journey through Indian Classical Scales using Python and NetworkX
Background
In our last article, Algorithmic Approaches to Music Theory: Conventional and Graph-Based Methods, we used conventional Python and graph-based approaches to explore the foundations of music theory, starting with the Western major and minor scales.
Today, let’s take a look at the Indian Shruti system, which is based on 22 Shruti and not 12 notes from an equal temperament system. We will take the same approach and better understand the music theory behind the Shruti system through the implementation of basic scales using both a conventional Python method and a graph-based approach. Then, we can analyze the learnings from an implementation and from a topic perspective.
Shruti major scale: Shruti Shuddha Saptak
The Indian Shruti major scale, also known as the “Shruti Shuddha Saptak,” is a scale in Indian classical music derived from the 22-Shruti system. The term “shruti” refers to the smallest musical interval in Indian classical music. The Indian Shruti major scale is analogous to the Western major scale.
Here is the algorithm to define the Indian Shruti major scale:
- Start with the fundamental frequency (tonic), called “Sa” or “Shadja” in Indian music. This is the first note of the scale.
- Calculate the following frequency ratios for the subsequent notes:
- Sa (Shadja): 1/1
- Re (Rishabh): 9/8
- Ga (Gandhar): 5/4
- Ma (Madhyam): 4/3
- Pa (Pancham): 3/2
- Dha (Dhaivat): 27/16
- Ni (Nishad): 15/8
3. Multiply the fundamental frequency by each of these ratios to get the frequencies of the corresponding notes in the Indian Shruti major scale.
4. The final note, “Sa” (Shadja) in the upper octave, has a ratio of 2/1, which means it’s exactly double the frequency of the starting note.
For example, if the starting note (Sa) has a frequency of 240 Hz:
- Sa (Shadja): 240 * (1/1) = 240 Hz
- Re (Rishabh): 240 * (9/8) = 270 Hz
- Ga (Gandhar): 240 * (5/4) = 300 Hz
- Ma (Madhyam): 240 * (4/3) = 320 Hz
- Pa (Pancham): 240 * (3/2) = 360 Hz
- Dha (Dhaivat): 240 * (27/16) = 405 Hz
- Ni (Nishad): 240 * (15/8) = 450 Hz
- Sa (Shadja) upper octave: 240 * (2/1) = 480 Hz
Keep in mind that these are only approximate values for the Indian Shruti major scale. In actual performance, musicians may make small adjustments to these frequencies based on the specific raga being performed or the melodic context.
Python implementation
Below is the conventional way to code the algorithm for the Shruti Suddha Saptak using Python.
When you run this code, it will output the frequencies of the Indian Shruti major scale based on the provided tonic frequency:
Graph (networkx) implementation
Now, here’s the Python code to represent the Indian Shruti major scale as a NetworkX graph:
This code creates a directed graph with nodes representing the notes of the Indian Shruti major scale and edges representing the frequency ratios between the notes.
We can also visualize the graph with the code below:
The draw_graph function uses NetworkX and matplotlib to visualize the graph with a circular layout. The graph shows the notes with their names and the edges with the frequency ratios.
Now, what if we try to add the minor scale equivalent to both implementations?
Shruti Minor Scale: Asavari Thaat
In the Indian Shruti system, there isn’t a direct equivalent of the Western minor scale. However, you can create a scale with a similar mood or tonality by selecting different swaras (notes) from the 22-shruti system. One possible example is the Asavari Thaat, which is a scale used in Hindustani music and has a somewhat similar tonality to the natural minor scale.
Here’s the algorithm for the Asavari Thaat scale:
- Start with the fundamental frequency (tonic), called “Sa” or “Shadja” in Indian music. This is the first note of the scale.
- Calculate the following frequency ratios for the subsequent notes:
- Sa (Shadja): 1/1
- Re (Rishabh): 9/8
- Ga (Gandhar): 32/27
- Ma (Madhyam): 4/3
- Pa (Pancham): 3/2
- Dha (Dhaivat): 8/5
- Ni (Nishad): 16/9
3. Multiply the fundamental frequency by each of these ratios to get the frequencies of the corresponding notes in the Asavari Thaat scale.
4. The final note, “Sa” (Shadja) in the upper octave, has a ratio of 2/1, which means it’s exactly double the frequency of the starting note.
For example, if the starting note (Sa) has a frequency of 240 Hz:
- Sa (Shadja): 240 * (1/1) = 240 Hz
- Re (Rishabh): 240 * (9/8) = 270 Hz
- Ga (Gandhar): 240 * (32/27) = 284.44 Hz
- Ma (Madhyam): 240 * (4/3) = 320 Hz
- Pa (Pancham): 240 * (3/2) = 360 Hz
- Dha (Dhaivat): 240 * (8/5) = 384 Hz
- Ni (Nishad): 240 * (16/9) = 426.67 Hz
- Sa (Shadja) upper octave: 240 * (2/1) = 480 Hz
Keep in mind that Indian classical music is based on ragas, which have more intricate melodic structures and phrasings than the scales found in Western music. This is just an example of how to create a scale similar to the Western minor scale within the 22-shruti system.
Python implementation
Here is the conventional Python implementation of the Asavari Thaat scale.
When you run this code, it will output the frequencies of the Asavari Thaat scale based on the provided tonic frequency:
We can change the tonic_frequency
variable to generate the scale based on a different starting frequency.
Graph (networkx) implementation
Here’s how we can add the Asavari Thaat scale to the existing major scale NetworkX graph:
Let’s clean up the graph to make it more readable and at scale:
This outputs a graph like below, although it can also be represented in a single directed graph.
Analysis
Learnings on the two implementation approaches
When comparing the implementation of the Indian Shruti major scale and Asavari Thaat scale using Python code versus a NetworkX graph representation, we can observe several differences:
- Representation:
- In the Python implementation, scales are represented as lists of frequency values. This approach focuses on the numeric values of the frequencies.
- In the NetworkX graph representation, the scales are represented as graphs with nodes and edges. This approach emphasizes the relationships between the notes, making it easier to visualize and understand the structure of the scales.
2. Visualization:
- The Python implementation does not inherently provide a visual representation of the scales. If you want to visualize the relationships between the notes, you would need to use additional libraries or tools.
- With the NetworkX graph approach, you can easily create a visual representation of the scales, clearly showing the relationships between the notes and their frequencies. This can be beneficial for understanding the overall structure of the scales and their connections.
3. Scalability:
- In the Python implementation, adding more scales or modifying the existing scales requires changes to the code itself, potentially making it more complex as new scales are added.
- In the NetworkX graph representation, adding more scales or modifying the existing scales can be done by simply adding nodes and edges to the graph. This allows for easier scaling and modification of the representation as new scales are added or existing ones are updated.
4. Flexibility:
- The Python implementation is more focused on the specific calculations of frequencies and may not easily support additional information or properties related to the scales.
- The NetworkX graph representation can store additional information and properties related to the notes, such as names or other attributes, making it a more flexible representation that can be extended to include more information as needed.
While the Python implementation is more focused on the numeric calculations of frequencies, the NetworkX graph approach provides a more visually appealing and flexible representation that emphasizes the relationships between the notes. Depending on the requirements of your specific use case, you may choose one approach over the other based on the advantages and disadvantages of each method.
Learnings on the Shruti method
From the two implementations (Python code and NetworkX graph), we can also learn various aspects of the two scales (Indian Shruti major scale and Asavari Thaat scale) and the Shruti system:
- Frequency Ratios:
- Both implementations allow us to calculate the frequency ratios between the consecutive notes of the scales. These ratios are essential in understanding the intervals between notes, which define the unique characteristics of each scale.
2. Scale Structure:
- The NetworkX graph implementation helps us visualize the structure of the scales and their connections. This visualization makes it easier to understand the relationships between notes in each scale and compare the two scales.
3. Scale Differences:
- Comparing the Python implementations or the NetworkX graph representation, we can observe differences in the frequency ratios between the two scales. For example, the Indian Shruti major scale has a major third (Ga), while the Asavari Thaat scale has a minor third (Ga). This difference in intervals leads to the distinct sound of each scale.
4. Shruti System:
- The Python implementations illustrate the algorithmic approach to generating the scales in the Shruti system, highlighting the importance of frequency ratios in defining the scales. By comparing the two scales, we can see how the Shruti system can generate different scales by modifying the intervals between notes.
5. Flexibility and Extensibility:
- The NetworkX graph representation shows the potential for easily adding more scales or modifying the existing scales, allowing us to analyze a broader range of scales within the Shruti system. This flexibility can help us better understand the relationships between various scales in the system and their properties.
Conclusion
In conclusion, the Python code and NetworkX graph implementations provide different perspectives on the Indian Shruti major scale, the Asavari Thaat scale, and the Shruti system. By examining these implementations, we can gain insights into the structure, relationships, and unique characteristics of the scales and better understand the principles underlying the Shruti system.