Completed
Push — master ( af3ab7...be78bc )
by Patrick
02:17
created

Harmonic::getHalfStop()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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