src/Domain/Interval.ts
import { IntervalPrimitives } from '../primitives/Interval';
export class IntervalQuality {
private static readonly all: IntervalQuality[] = [];
private constructor(private readonly name: string) {
IntervalQuality.all.push(this);
}
get Name(): string {
return this.name;
}
public static readonly Minor: IntervalQuality = new IntervalQuality('Minor');
public static readonly Major: IntervalQuality = new IntervalQuality('Major');
public static readonly Augmented: IntervalQuality = new IntervalQuality('Augmented');
public static readonly Diminished: IntervalQuality = new IntervalQuality('Diminished');
public static readonly Perfect: IntervalQuality = new IntervalQuality('Perfect');
public static From(name: string) {
switch (name) {
case 'Minor':
return IntervalQuality.Minor;
case 'Major':
return IntervalQuality.Major;
case 'Augmented':
return IntervalQuality.Augmented;
case 'Diminished':
return IntervalQuality.Diminished;
case 'Perfect':
return IntervalQuality.Perfect;
default:
throw new Error('Invalid interval quality');
}
}
}
export class Interval {
private static readonly all: Interval[] = [];
private constructor(
private readonly name: string,
private readonly abreviature: string,
private readonly distance: number,
private readonly quality: IntervalQuality,
public invert: () => Interval,
public raiseOctave: () => Interval
) {
Interval.all.push(this);
}
get Name(): string {
return this.name;
}
get To(): IntervalPrimitives {
return {
name: this.name,
abreviature: this.abreviature,
distance: this.distance,
quality: this.quality.Name,
};
}
public static From(primitive: IntervalPrimitives) {
const interval = Interval.intervals.find(
(i) =>
i.name == primitive.name &&
i.distance == primitive.distance &&
i.abreviature == primitive.abreviature &&
i.quality == IntervalQuality.From(primitive.quality)
);
if (!interval) {
throw new Error('Invalid interval primitive');
}
return interval;
}
public static readonly Unison: Interval = new Interval(
'Unison',
'U',
0,
IntervalQuality.Perfect,
() => Interval.PerfectOctave,
() => Interval.PerfectOctave
);
public static readonly DiminishedUnison: Interval = new Interval(
'Diminished Unison',
'd1',
-1,
IntervalQuality.Diminished,
() => Interval.AugmentedUnison,
() => Interval.DiminishedUnison
);
public static readonly AugmentedUnison: Interval = new Interval(
'Augmented Unison',
'A1',
1,
IntervalQuality.Augmented,
() => Interval.DiminishedUnison,
() => Interval.AugmentedUnison
);
public static readonly MinorSecond: Interval = new Interval(
'Minor Second',
'm2',
1,
IntervalQuality.Minor,
() => Interval.MajorSeventh,
() => Interval.MinorNinth
);
public static readonly MajorSecond: Interval = new Interval(
'Major Second',
'M2',
2,
IntervalQuality.Major,
() => Interval.MinorSeventh,
() => Interval.MajorNinth
);
public static readonly AugmentedSecond: Interval = new Interval(
'Augmented Second',
'A2',
3,
IntervalQuality.Augmented,
() => Interval.DiminishedSeventh,
() => Interval.AugmentedNinth
);
public static readonly MinorThird: Interval = new Interval(
'Minor Third',
'm3',
3,
IntervalQuality.Minor,
() => Interval.MajorSixth,
() => Interval.MinorThird
);
public static readonly MajorThird: Interval = new Interval(
'Major Third',
'M3',
4,
IntervalQuality.Major,
() => Interval.MinorSixth,
() => Interval.MajorThird
);
public static readonly PerfectFourth: Interval = new Interval(
'Perfect Fourth',
'P4',
5,
IntervalQuality.Perfect,
() => Interval.PerfectFifth,
() => Interval.PerfectEleventh
);
public static readonly AugmentedFourth: Interval = new Interval(
'Augmented Fourth',
'A4',
6,
IntervalQuality.Augmented,
() => Interval.DiminishedFifth,
() => Interval.AugmentedEleventh
);
public static readonly DiminishedFifth: Interval = new Interval(
'Diminished Fifth',
'd5',
6,
IntervalQuality.Diminished,
() => Interval.AugmentedFourth,
() => Interval.DiminishedFifth
);
public static readonly Tritone: Interval = new Interval(
'Diminished Fifth',
'd5',
6,
IntervalQuality.Diminished,
() => Interval.AugmentedFourth,
() => Interval.Tritone
);
public static readonly PerfectFifth: Interval = new Interval(
'Perfect Fifth',
'P5',
7,
IntervalQuality.Perfect,
() => Interval.PerfectFourth,
() => Interval.PerfectFifth
);
public static readonly AugmentedFifth: Interval = new Interval(
'Augmented Fifth',
'A5',
8,
IntervalQuality.Augmented,
() => Interval.AugmentedFourth,
() => Interval.AugmentedFifth
);
public static readonly MinorSixth: Interval = new Interval(
'Minor Sixth',
'm6',
8,
IntervalQuality.Minor,
() => Interval.MajorThird,
() => Interval.MinorThirteenth
);
public static readonly MajorSixth: Interval = new Interval(
'Major Sixth',
'M6',
9,
IntervalQuality.Major,
() => Interval.MinorThird,
() => Interval.MajorThirteenth
);
public static readonly DiminishedSeventh: Interval = new Interval(
'Diminished Seventh',
'd7',
9,
IntervalQuality.Diminished,
() => Interval.AugmentedSecond,
() => Interval.DiminishedSeventh
);
public static readonly MinorSeventh: Interval = new Interval(
'Minor Seventh',
'm7',
10,
IntervalQuality.Minor,
() => Interval.MajorSecond,
() => Interval.MinorSeventh
);
public static readonly MajorSeventh: Interval = new Interval(
'Major Seventh',
'M7',
11,
IntervalQuality.Major,
() => Interval.MinorSecond,
() => Interval.MajorSeventh
);
public static readonly PerfectOctave: Interval = new Interval(
'Perfect Octave',
'PO',
12,
IntervalQuality.Perfect,
() => Interval.Unison,
() => Interval.PerfectOctave
);
public static readonly DiminishedNinth: Interval = new Interval(
'Diminished Ninth',
'd9',
13,
IntervalQuality.Minor,
() => Interval.AugmentedUnison,
() => Interval.DiminishedNinth
);
public static readonly MinorNinth: Interval = new Interval(
'Minor Ninth',
'm9',
13,
IntervalQuality.Minor,
() => Interval.MajorSeventh,
() => Interval.MinorNinth
);
public static readonly MajorNinth: Interval = new Interval(
'Major Ninth',
'M9',
14,
IntervalQuality.Major,
() => Interval.MinorSeventh,
() => Interval.MajorNinth
);
public static readonly AugmentedNinth: Interval = new Interval(
'Augmented Ninth',
'A9',
15,
IntervalQuality.Augmented,
() => Interval.DiminishedUnison,
() => Interval.AugmentedNinth
);
public static readonly PerfectEleventh: Interval = new Interval(
'Perfect Eleventh',
'P11',
17,
IntervalQuality.Perfect,
() => Interval.PerfectFifth,
() => Interval.PerfectEleventh
);
public static readonly AugmentedEleventh: Interval = new Interval(
'Augmented Eleventh',
'A11',
18,
IntervalQuality.Augmented,
() => Interval.DiminishedFifth,
() => Interval.AugmentedEleventh
);
public static readonly MinorThirteenth: Interval = new Interval(
'Minor Thirteenth',
'm13',
20,
IntervalQuality.Minor,
() => Interval.MajorThird,
() => Interval.MinorThirteenth
);
public static readonly MajorThirteenth: Interval = new Interval(
'Major Thirteenth',
'M13',
21,
IntervalQuality.Major,
() => Interval.MinorThird,
() => Interval.MajorThirteenth
);
isLargarThan(other: Interval): boolean {
return this.distance > other.distance;
}
public static get intervals(): Interval[] {
return Interval.all;
}
public static get unique(): Interval[] {
return Interval.all.filter(
(i) =>
i.distance <= 12 &&
(i.quality === IntervalQuality.Perfect ||
i.quality === IntervalQuality.Minor ||
i.quality === IntervalQuality.Major)
);
}
}
export const enum IntervalDirection {
Ascending,
Descending,
Level,
}