Harmonic::getSeries()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace ExtendedStrings\Strings;
6
7
class Harmonic
8
{
9
    private $halfStop;
10
    private $baseStop;
11
    private $number;
12
    private $string;
13
14
    /**
15
     * Harmonic constructor.
16
     *
17
     * @param Stop $halfStop
18
     *     The harmonic-pressure stop.
19
     * @param Stop|null $baseStop
20
     *     The base stop (defaults to an open string).
21
     * @param VibratingStringInterface $string
22
     *     The string.
23
     */
24
    public function __construct(Stop $halfStop, Stop $baseStop = null, VibratingStringInterface $string)
25
    {
26
        $baseStop = $baseStop ?: new Stop(1.0);
27
        if ($halfStop->getStringLength() > $baseStop->getStringLength()) {
28
            throw new \InvalidArgumentException("The half-stop cannot be lower than the base stop.");
29
        }
30
31
        $this->baseStop = $baseStop;
32
        $this->halfStop = $halfStop;
33
        $this->string = $string;
34
    }
35
36
    /**
37
     * Returns the sounding frequency of the harmonic (in Hz).
38
     *
39
     * @return float
40
     */
41
    public function getSoundingFrequency(): float
42
    {
43
        return $this->baseStop->getFrequency($this->string) * $this->getNumber();
44
    }
45
46
    /**
47
     * Returns the string lengths that produce a given harmonic number.
48
     *
49
     * @param int  $number    The harmonic number.
50
     * @param bool $exclusive When enabled, equivalent lengths will only be
51
     *                        returned for the lowest harmonic number, e.g. the
52
     *                        string length 0.5 will only be returned for
53
     *                        harmonic 2 (not for harmonics 4, 6, 8, etc.).
54
     *
55
     * @return float[]
56
     */
57
    public static function getStringLengthsFromNumber(int $number, bool $exclusive = false): array
58
    {
59
        $harmonics = [];
60
        for ($numerator = 1; $numerator <= $number; $numerator++) {
61
            if (!$exclusive || $numerator === 1 || (int) Math::gcd($numerator, $number) === 1) {
62
                $harmonics[] = $numerator / $number;
63
            }
64
        }
65
66
        return $harmonics;
67
    }
68
69
    /**
70
     * Returns the harmonic series.
71
     *
72
     * @param int $limit
73
     *
74
     * @return float[]
75
     */
76
    public static function getSeries(int $limit): array
77
    {
78
        $series = [];
79
        $base = 0;
80
        for ($denominator = 1; $denominator <= $limit; $denominator++) {
81
            $base = $series[$denominator] = $base + 1 / $denominator;
82
        }
83
84
        return $series;
85
    }
86
87
    /**
88
     * Returns the harmonic-pressure stop.
89
     *
90
     * @return Stop
91
     */
92
    public function getHalfStop(): Stop
93
    {
94
        return $this->halfStop;
95
    }
96
97
    /**
98
     * Returns the base stop.
99
     *
100
     * @return Stop
101
     */
102
    public function getBaseStop(): Stop
103
    {
104
        return $this->baseStop;
105
    }
106
107
    /**
108
     * Returns the string.
109
     *
110
     * @return VibratingStringInterface
111
     */
112
    public function getString(): VibratingStringInterface
113
    {
114
        return $this->string;
115
    }
116
117
    /**
118
     * Returns whether this is a natural harmonic.
119
     *
120
     * @return bool
121
     */
122
    public function isNatural(): bool
123
    {
124
        return Math::isZero(1 - $this->baseStop->getStringLength());
125
    }
126
127
    /**
128
     * Returns the harmonic number.
129
     *
130
     * @return int The harmonic number.
131
     */
132
    public function getNumber(): int
133
    {
134
        if (!isset($this->number)) {
135
            $this->number = intval(1 / Math::gcd(
136
                1,
137
                $this->halfStop->getStringLength() / $this->baseStop->getStringLength()
138
            ));
139
        }
140
141
        return $this->number;
142
    }
143
}
144