Time Signatures and Rhythm
The TimeSignature
and Duration
classes provide comprehensive support for musical time, rhythm, and meter.
Understanding Time Signatures
- Time Signature
A notation that specifies how many beats are in each measure and what note value gets one beat
- Numerator
The top number - how many beats per measure
- Denominator
The bottom number - which note value gets one beat (4 = quarter note, 8 = eighth note)
- Meter
The rhythmic pattern created by the time signature (simple, compound, complex)
Creating Time Signatures
Basic Time Signatures
// Common time signatures
var fourFour = new TimeSignature(4, 4); // Common time
var threeFour = new TimeSignature(3, 4); // Waltz time
var sixEight = new TimeSignature(6, 8); // Compound duple
var fiveFour = new TimeSignature(5, 4); // Complex meter
var sevenEight = new TimeSignature(7, 8); // Complex meter
// Using predefined signatures
var common = TimeSignature.CommonTime; // 4/4
var cut = TimeSignature.CutTime; // 2/2 (alla breve)
// Access properties
Console.WriteLine($"{fourFour.Numerator}/{fourFour.Denominator}"); // 4/4
Console.WriteLine($"Beats per measure: {fourFour.BeatsPerMeasure}"); // 4
Time Signature Properties
var sixEight = new TimeSignature(6, 8);
// Basic properties
int beats = sixEight.Numerator; // 6
int beatUnit = sixEight.Denominator; // 8
int beatsPerMeasure = sixEight.BeatsPerMeasure; // 6
// Meter classification
bool isCompound = sixEight.IsCompound; // true (divisible by 3)
bool isSimple = fourFour.IsSimple; // true
bool isComplex = fiveFour.IsComplex; // true (5 or 7 beats)
// Beat grouping
var beatGroups = sixEight.GetBeatGroups(); // [3, 3] for 6/8
Working with Durations
Creating Durations
// Basic note durations
var whole = new Duration(DurationType.Whole);
var half = new Duration(DurationType.Half);
var quarter = new Duration(DurationType.Quarter);
var eighth = new Duration(DurationType.Eighth);
var sixteenth = new Duration(DurationType.Sixteenth);
// Dotted notes (add 50% of value)
var dottedHalf = new Duration(DurationType.Half, 1); // 1 dot
var doubleDottedQuarter = new Duration(DurationType.Quarter, 2); // 2 dots
// Tuplets
var tripletEighth = Duration.CreateTuplet(DurationType.Eighth, 3, 2);
// 3 eighth notes in the time of 2
// Get duration values
double quarterValue = quarter.GetValue(); // 0.25 (quarter of a whole note)
double dottedHalfValue = dottedHalf.GetValue(); // 0.75 (0.5 + 0.25)
Duration Symbols
// Get music notation symbols
var whole = new Duration(DurationType.Whole);
var quarter = new Duration(DurationType.Quarter);
var eighth = new Duration(DurationType.Eighth);
Console.WriteLine(whole.GetSymbol()); // 𝅝 (whole note)
Console.WriteLine(quarter.GetSymbol()); // ♩ (quarter note)
Console.WriteLine(eighth.GetSymbol()); // ♪ (eighth note)
// Dotted notes
var dottedQuarter = new Duration(DurationType.Quarter, 1);
Console.WriteLine(dottedQuarter.GetSymbol()); // ♩.
Time Calculations
Duration in Time
// Calculate actual time duration at a given tempo
int bpm = 120; // 120 beats per minute
var quarter = new Duration(DurationType.Quarter);
var half = new Duration(DurationType.Half);
var eighth = new Duration(DurationType.Eighth);
double quarterSeconds = quarter.GetTimeInSeconds(bpm); // 0.5 seconds
double halfSeconds = half.GetTimeInSeconds(bpm); // 1.0 seconds
double eighthSeconds = eighth.GetTimeInSeconds(bpm); // 0.25 seconds
// With different tempos
double slowQuarter = quarter.GetTimeInSeconds(60); // 1.0 second
double fastQuarter = quarter.GetTimeInSeconds(180); // 0.333 seconds
Duration in Measures
var fourFour = new TimeSignature(4, 4);
var threeFour = new TimeSignature(3, 4);
var wholeNote = new Duration(DurationType.Whole);
var halfNote = new Duration(DurationType.Half);
var quarterNote = new Duration(DurationType.Quarter);
// How many measures does each duration span?
double wholeMeasures = wholeNote.GetValueInMeasures(fourFour); // 1.0
double halfMeasures = halfNote.GetValueInMeasures(fourFour); // 0.5
double quarterMeasures = quarterNote.GetValueInMeasures(fourFour); // 0.25
// In 3/4 time
double wholeIn34 = wholeNote.GetValueInMeasures(threeFour); // 1.333
double halfIn34 = halfNote.GetValueInMeasures(threeFour); // 0.667
Rhythm Patterns
Building Rhythmic Patterns
public class RhythmPattern
{
private List<Duration> durations = new List<Duration>();
private TimeSignature timeSignature;
public RhythmPattern(TimeSignature timeSignature)
{
this.timeSignature = timeSignature;
}
public RhythmPattern AddDuration(Duration duration)
{
durations.Add(duration);
return this;
}
public double GetTotalBeats()
{
return durations.Sum(d => d.GetValue() * timeSignature.Denominator);
}
public bool FillsMeasure()
{
return Math.Abs(GetTotalBeats() - timeSignature.Numerator) < 0.0001;
}
}
// Create a basic rock beat pattern
var rockBeat = new RhythmPattern(new TimeSignature(4, 4))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter));
Console.WriteLine(rockBeat.FillsMeasure()); // true
Common Rhythm Patterns
public static class CommonRhythms
{
// Clave pattern (2-3)
public static RhythmPattern Clave23()
{
return new RhythmPattern(new TimeSignature(4, 4))
.AddDuration(new Duration(DurationType.Quarter)) // Beat 1
.AddDuration(new Duration(DurationType.Quarter)) // Beat 2
.AddDuration(new Duration(DurationType.Eighth)) // Beat 3 &
.AddDuration(new Duration(DurationType.Eighth))
.AddDuration(new Duration(DurationType.Quarter)); // Beat 4
}
// Shuffle rhythm
public static RhythmPattern Shuffle()
{
var tripletEighth = Duration.CreateTuplet(DurationType.Eighth, 3, 2);
return new RhythmPattern(new TimeSignature(4, 4))
.AddDuration(new Duration(DurationType.Quarter)) // First note of triplet
.AddDuration(tripletEighth) // Last note of triplet
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(tripletEighth);
}
// Waltz pattern
public static RhythmPattern Waltz()
{
return new RhythmPattern(new TimeSignature(3, 4))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter));
}
}
Complex Meters
Working with Odd Time Signatures
// 5/4 time (3+2 or 2+3)
var fiveFour = new TimeSignature(5, 4);
var beatGroups54 = fiveFour.GetBeatGroups(); // Could be [3, 2] or [2, 3]
// 7/8 time (common groupings)
var sevenEight = new TimeSignature(7, 8);
// Common groupings: 3+2+2, 2+3+2, 2+2+3
// Create a 7/8 pattern
var sevenEightPattern = new RhythmPattern(sevenEight)
.AddDuration(new Duration(DurationType.Eighth)) // 1
.AddDuration(new Duration(DurationType.Eighth)) // 2
.AddDuration(new Duration(DurationType.Eighth)) // 3
.AddDuration(new Duration(DurationType.Eighth)) // 4
.AddDuration(new Duration(DurationType.Eighth)) // 5
.AddDuration(new Duration(DurationType.Eighth)) // 6
.AddDuration(new Duration(DurationType.Eighth)); // 7
Compound Meters
// 6/8 - Compound duple (2 main beats, each divided into 3)
var sixEight = new TimeSignature(6, 8);
bool isCompound = sixEight.IsCompound; // true
// 9/8 - Compound triple (3 main beats)
var nineEight = new TimeSignature(9, 8);
// 12/8 - Compound quadruple (4 main beats)
var twelveEight = new TimeSignature(12, 8);
// Create a 6/8 pattern with proper feel
var sixEightPattern = new RhythmPattern(sixEight)
.AddDuration(new Duration(DurationType.DottedQuarter)) // Main beat 1
.AddDuration(new Duration(DurationType.DottedQuarter)); // Main beat 2
Tempo and BPM
Working with Tempo
public class Tempo
{
public int BPM { get; }
public string Marking { get; }
public Tempo(int bpm, string marking = "")
{
BPM = bpm;
Marking = marking;
}
// Common tempo markings
public static Tempo Grave => new Tempo(40, "Grave");
public static Tempo Largo => new Tempo(50, "Largo");
public static Tempo Adagio => new Tempo(70, "Adagio");
public static Tempo Andante => new Tempo(90, "Andante");
public static Tempo Moderato => new Tempo(110, "Moderato");
public static Tempo Allegro => new Tempo(130, "Allegro");
public static Tempo Vivace => new Tempo(160, "Vivace");
public static Tempo Presto => new Tempo(180, "Presto");
public static Tempo Prestissimo => new Tempo(200, "Prestissimo");
public double GetBeatDuration(TimeSignature timeSignature)
{
// Duration of one beat in seconds
return 60.0 / BPM;
}
public double GetMeasureDuration(TimeSignature timeSignature)
{
// Duration of one measure in seconds
return (60.0 / BPM) * timeSignature.BeatsPerMeasure;
}
}
// Calculate timing
var allegro = Tempo.Allegro; // 130 BPM
var fourFour = new TimeSignature(4, 4);
double beatDuration = allegro.GetBeatDuration(fourFour); // ~0.46 seconds
double measureDuration = allegro.GetMeasureDuration(fourFour); // ~1.85 seconds
Syncopation and Rhythm
Creating Syncopated Rhythms
public class SyncopatedRhythm
{
// Basic syncopation - emphasis on off-beats
public static RhythmPattern BasicSyncopation()
{
return new RhythmPattern(new TimeSignature(4, 4))
.AddDuration(new Duration(DurationType.Eighth))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Eighth))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter));
}
// Anticipated beat
public static RhythmPattern Anticipation()
{
var tiedEighth = new Duration(DurationType.Eighth);
return new RhythmPattern(new TimeSignature(4, 4))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.Quarter))
.AddDuration(new Duration(DurationType.DottedQuarter))
.AddDuration(tiedEighth); // Anticipates next measure
}
}
Polyrhythms
Creating Polyrhythms
public class Polyrhythm
{
public static void Create3Against2()
{
// 3 notes against 2 notes in same time span
var threeNotes = Duration.CreateTuplet(DurationType.Quarter, 3, 2);
var twoNotes = new Duration(DurationType.Quarter);
// Both fill the same time
var pattern1 = new List<Duration> { threeNotes, threeNotes, threeNotes };
var pattern2 = new List<Duration> { twoNotes, twoNotes };
}
public static void Create4Against3()
{
// 4 notes against 3 notes
var fourNotes = Duration.CreateTuplet(DurationType.Quarter, 4, 3);
var threeNotes = Duration.CreateTuplet(DurationType.Quarter, 3, 4);
}
}
Practical Applications
Metronome Implementation
public class Metronome
{
private readonly int bpm;
private readonly TimeSignature timeSignature;
private int currentBeat = 1;
public Metronome(int bpm, TimeSignature timeSignature)
{
this.bpm = bpm;
this.timeSignature = timeSignature;
}
public double GetIntervalMs()
{
return 60000.0 / bpm; // Milliseconds between beats
}
public string GetBeatType()
{
if (currentBeat == 1)
return "Downbeat";
else if (timeSignature.IsCompound &&
currentBeat % (timeSignature.Numerator / timeSignature.GetBeatGroups().Count) == 1)
return "Strong";
else
return "Weak";
}
public void NextBeat()
{
currentBeat++;
if (currentBeat > timeSignature.BeatsPerMeasure)
currentBeat = 1;
}
}
Rhythm Notation Helper
public class RhythmNotation
{
public static string GetBeaming(List<Duration> durations)
{
var result = new StringBuilder();
foreach (var duration in durations)
{
if (duration.Type == DurationType.Eighth)
result.Append("♫ "); // Beamed eighths
else if (duration.Type == DurationType.Sixteenth)
result.Append("♬ "); // Beamed sixteenths
else
result.Append(duration.GetSymbol() + " ");
}
return result.ToString();
}
public static string GetCountingPattern(TimeSignature ts)
{
if (ts.Equals(new TimeSignature(4, 4)))
return "1 e & a 2 e & a 3 e & a 4 e & a";
else if (ts.Equals(new TimeSignature(3, 4)))
return "1 e & a 2 e & a 3 e & a";
else if (ts.Equals(new TimeSignature(6, 8)))
return "1 2 3 4 5 6";
else
return "Custom counting pattern";
}
}
Best Practices
Choose appropriate time signatures: Match the natural feel of the music
Consider beat grouping: 6/8 feels different from 3/4 despite same total
Use tuplets carefully: They add rhythmic interest but can be complex
Respect the downbeat: Strong beats provide rhythmic foundation
Match tempo to style: Different genres have typical tempo ranges
See Also
13 June 2025