Skip to content

Commit

Permalink
refactor(note): 💥 rewrite harmonics methods to return an Iterable (…
Browse files Browse the repository at this point in the history
…#584)

Signed-off-by: Albert Mañosa <26429103+albertms10@users.noreply.github.com>
  • Loading branch information
albertms10 authored Jan 26, 2025
1 parent c6ebd22 commit fea6be5
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 84 deletions.
2 changes: 1 addition & 1 deletion example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ void main() {
const Frequency(314).closestPitch(); // Eâ™­4+16
const Frequency(440).closestPitch(temperature: const Celsius(24)); // A4-12

Note.c.inOctave(1).harmonics(upToIndex: 15);
Note.c.inOctave(1).harmonics().take(16).toSet();
// {C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4,
// E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}

Expand Down
21 changes: 12 additions & 9 deletions lib/src/note/frequency.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,24 +109,27 @@ extension type const Frequency._(num hertz) implements num {
index.isNegative ? hertz / (index.abs() + 1) : hertz * (index + 1),
);

/// The [Set] of [harmonics series](https://en.wikipedia.org/wiki/Harmonic_series_(music))
/// [upToIndex] from this [Frequency].
/// The set of [harmonic](https://en.wikipedia.org/wiki/Harmonic_series_(music))
/// or [undertone](https://en.wikipedia.org/wiki/Undertone_series) series
/// from this [Frequency].
///
/// Example:
/// ```dart
/// Note.a.inOctave(3).frequency().harmonics(upToIndex: 2)
/// const Frequency(220).harmonics().take(3).toSet()
/// == const {Frequency(220), Frequency(440), Frequency(660)}
///
/// Note.a.inOctave(5).frequency().harmonics(upToIndex: -2)
/// == {const Frequency(880), const Frequency(440), const Frequency(293.33)}
/// Note.a.inOctave(5).frequency().harmonics(undertone: true).take(3).toSet()
/// == const {Frequency(880), Frequency(440), Frequency(293.33)}
/// ```
///
/// ---
/// See also:
/// * [Pitch.harmonics] for a [ClosestPitch] set of harmonic series.
Set<Frequency> harmonics({required int upToIndex}) => {
for (var i = 0; i <= upToIndex.abs(); i++) harmonic(i * upToIndex.sign),
};
Iterable<Frequency> harmonics({bool undertone = false}) sync* {
var i = 0;
while (true) {
yield harmonic(i++ * (undertone ? -1 : 1));
}
}

/// This [Frequency] formatted as a string.
///
Expand Down
17 changes: 7 additions & 10 deletions lib/src/note/pitch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -465,17 +465,17 @@ final class Pitch extends Scalable<Pitch>
/// ```
TuningFork at(Frequency frequency) => TuningFork(this, frequency);

/// The [ClosestPitch] set of harmonics series [upToIndex] from this [Pitch]
/// from [tuningSystem] and [temperature].
/// The [ClosestPitch] set of harmonics series from this [Pitch] from
/// [tuningSystem], [temperature], and whether [undertone].
///
/// Example:
/// ```dart
/// Note.c.inOctave(1).harmonics(upToIndex: 15).toString()
/// Note.c.inOctave(1).harmonics().take(16).toSet().toString()
/// == '{C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4, '
/// 'E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}'
/// ```
Set<ClosestPitch> harmonics({
required int upToIndex,
Iterable<ClosestPitch> harmonics({
bool undertone = false,
TuningSystem tuningSystem = const EqualTemperament.edo12(),
Celsius temperature = Celsius.reference,
Celsius referenceTemperature = Celsius.reference,
Expand All @@ -484,18 +484,15 @@ final class Pitch extends Scalable<Pitch>
tuningSystem: tuningSystem,
// we deliberately omit the temperature here, as the subsequent call to
// `Frequency.closestPitch` will already take it into account.
)
.harmonics(upToIndex: upToIndex)
.map(
).harmonics(undertone: undertone).map(
(frequency) => frequency
.closestPitch(
tuningSystem: tuningSystem,
temperature: temperature,
referenceTemperature: referenceTemperature,
)
.respelledSimple,
)
.toSet();
);

/// The string representation of this [Pitch] based on [system].
///
Expand Down
117 changes: 57 additions & 60 deletions test/src/note/frequency_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,72 +99,69 @@ void main() {
});

group('.harmonics()', () {
test(
'returns a Set of the harmonic series up to index from this Frequency',
() {
expect(
const Frequency(512).harmonics(upToIndex: -15),
{
const Frequency(512),
const Frequency(256),
const Frequency(170.66666666666666),
const Frequency(128),
const Frequency(102.4),
const Frequency(85.33333333333333),
const Frequency(73.14285714285714),
const Frequency(64),
const Frequency(56.888888888888886),
const Frequency(51.2),
const Frequency(46.54545454545455),
const Frequency(42.666666666666664),
const Frequency(39.38461538461539),
const Frequency(36.57142857142857),
const Frequency(34.13333333333333),
const Frequency(32),
},
);
expect(
const Frequency(400).harmonics(upToIndex: -1),
const {Frequency(400), Frequency(200)},
);
expect(
const Frequency(220).harmonics(upToIndex: 0),
const {Frequency(220)},
);
expect(
const Frequency(110).harmonics(upToIndex: 1),
const {Frequency(110), Frequency(220)},
);
expect(
const Frequency(32).harmonics(upToIndex: 15),
const {
Frequency(32),
Frequency(64),
Frequency(96),
Frequency(128),
Frequency(160),
Frequency(192),
Frequency(224),
Frequency(256),
Frequency(288),
Frequency(320),
Frequency(352),
Frequency(384),
Frequency(416),
Frequency(448),
Frequency(480),
Frequency(512),
},
);
},
);
test('returns a Set of the harmonic series from this Frequency', () {
expect(
const Frequency(512).harmonics(undertone: true).take(16).toSet(),
{
const Frequency(512),
const Frequency(256),
const Frequency(170.66666666666666),
const Frequency(128),
const Frequency(102.4),
const Frequency(85.33333333333333),
const Frequency(73.14285714285714),
const Frequency(64),
const Frequency(56.888888888888886),
const Frequency(51.2),
const Frequency(46.54545454545455),
const Frequency(42.666666666666664),
const Frequency(39.38461538461539),
const Frequency(36.57142857142857),
const Frequency(34.13333333333333),
const Frequency(32),
},
);
expect(
const Frequency(400).harmonics(undertone: true).take(2),
const {Frequency(400), Frequency(200)},
);
expect(
const Frequency(220).harmonics().take(1),
const {Frequency(220)},
);
expect(
const Frequency(110).harmonics().take(2),
const {Frequency(110), Frequency(220)},
);
expect(
const Frequency(32).harmonics().take(16),
const {
Frequency(32),
Frequency(64),
Frequency(96),
Frequency(128),
Frequency(160),
Frequency(192),
Frequency(224),
Frequency(256),
Frequency(288),
Frequency(320),
Frequency(352),
Frequency(384),
Frequency(416),
Frequency(448),
Frequency(480),
Frequency(512),
},
);
});
});

group('.format()', () {
test('returns this Frequency formatted as a string', () {
expect(const Frequency(440).format(), '440 Hz');
expect(const Frequency(415.62).format(), '415.62 Hz');
expect(const Frequency(2200.2968).format(), '2200.2968 Hz');
expect(const Frequency(2200.296).format(), '2200.296 Hz');
});
});
});
Expand Down
12 changes: 8 additions & 4 deletions test/src/note/pitch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ void main() {
group('.harmonics()', () {
test('returns the ClosestPitch set of harmonic series', () {
expect(
Note.c.inOctave(1).harmonics(upToIndex: 15).toString(),
Note.c.inOctave(1).harmonics().take(16).toSet().toString(),
'{C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4, '
'E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}',
);
Expand All @@ -1152,11 +1152,12 @@ void main() {
Note.c
.inOctave(1)
.harmonics(
upToIndex: 15,
tuningSystem: const EqualTemperament.edo12(
fork: TuningFork(Pitch.reference, Frequency(438)),
),
)
.take(16)
.toSet()
.toString(),
'{C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4, '
'E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}',
Expand All @@ -1166,10 +1167,11 @@ void main() {
Note.c
.inOctave(1)
.harmonics(
upToIndex: 15,
tuningSystem:
const EqualTemperament.edo12(fork: TuningFork.c256),
)
.take(16)
.toSet()
.toString(),
'{C1, C2, G2+2, C3, E3-14, G3+2, A♯3-31, C4, D4+4, '
'E4-14, F♯4-49, G4+2, A♭4+41, A♯4-31, B4-12, C5}',
Expand All @@ -1178,7 +1180,9 @@ void main() {
expect(
Note.c
.inOctave(1)
.harmonics(upToIndex: 15, temperature: const Celsius(18))
.harmonics(temperature: const Celsius(18))
.take(16)
.toSet()
.toString(),
'{C1+6, C2+6, G2+8, C3+6, E3-8, G3+8, A♯3-25, C4+6, D4+10, '
'E4-8, F♯4-43, G4+8, A♭4+47, A♯4-25, B4-6, C5+6}',
Expand Down

0 comments on commit fea6be5

Please sign in to comment.