maialib 1.9.4__cp38-cp38-macosx_10_15_universal2.whl → 1.9.5__cp38-cp38-macosx_10_15_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of maialib might be problematic. Click here for more details.
- maialib/maiacore/maiacore.cpython-38-darwin.so +0 -0
- maialib/maiacore/maiacore.pyi +5 -5
- maialib/maiapy/sethares_dissonance.py +66 -10
- maialib/maiapy/sethares_dissonance.pyi +61 -6
- maialib/xml-scores-examples/Beethoven_Symphony_5_mov_1.xml +38647 -40319
- {maialib-1.9.4.dist-info → maialib-1.9.5.dist-info}/METADATA +1 -1
- {maialib-1.9.4.dist-info → maialib-1.9.5.dist-info}/RECORD +10 -10
- {maialib-1.9.4.dist-info → maialib-1.9.5.dist-info}/LICENSE.txt +0 -0
- {maialib-1.9.4.dist-info → maialib-1.9.5.dist-info}/WHEEL +0 -0
- {maialib-1.9.4.dist-info → maialib-1.9.5.dist-info}/top_level.txt +0 -0
|
Binary file
|
maialib/maiacore/maiacore.pyi
CHANGED
|
@@ -93,7 +93,7 @@ class Chord:
|
|
|
93
93
|
@typing.overload
|
|
94
94
|
def getHarmonicDensity(self, lowerBoundPitch: str = '', higherBoundPitch: str = '') -> float:
|
|
95
95
|
...
|
|
96
|
-
def getHarmonicSpectrum(self, numPartialsPerNote: int = 6, amplCallback: typing.Callable[[list[float]], list[float]] = None) -> tuple[list[float], list[float]]:
|
|
96
|
+
def getHarmonicSpectrum(self, numPartialsPerNote: int = 6, amplCallback: typing.Callable[[list[float]], list[float]] = None, partialsDecayExpRate: float = 0.8799999952316284) -> tuple[list[float], list[float]]:
|
|
97
97
|
...
|
|
98
98
|
def getIntervals(self, firstNoteAsReference: bool = False) -> list[Interval]:
|
|
99
99
|
...
|
|
@@ -139,9 +139,9 @@ class Chord:
|
|
|
139
139
|
...
|
|
140
140
|
def getRoot(self) -> Note:
|
|
141
141
|
...
|
|
142
|
-
def getSetharesDissonance(self, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: typing.Callable[[list[float]], list[float]] = None, dissCallback: typing.Callable[[list[float]], float] = None) -> float:
|
|
142
|
+
def getSetharesDissonance(self, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: typing.Callable[[list[float]], list[float]] = None, partialsDecayExpRate: float = 0.8799999952316284, dissCallback: typing.Callable[[list[float]], float] = None) -> float:
|
|
143
143
|
...
|
|
144
|
-
def getSetharesDyadsDataFrame(self, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: typing.Callable[[list[float]], list[float]] = None) -> typing.Any:
|
|
144
|
+
def getSetharesDyadsDataFrame(self, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: typing.Callable[[list[float]], list[float]] = None, partialsDecayExpRate: float = 0.8799999952316284) -> typing.Any:
|
|
145
145
|
...
|
|
146
146
|
def getStackDataFrame(self, enharmonyNotes: bool = False) -> typing.Any:
|
|
147
147
|
...
|
|
@@ -946,7 +946,7 @@ class Note:
|
|
|
946
946
|
...
|
|
947
947
|
def getFrequency(self, equalTemperament: bool = True, freqA4: float = 440.0) -> float:
|
|
948
948
|
...
|
|
949
|
-
def getHarmonicSpectrum(self, numPartials: int = 6, amplCallback: typing.Callable[[list[float]], list[float]] = None) -> tuple[list[float], list[float]]:
|
|
949
|
+
def getHarmonicSpectrum(self, numPartials: int = 6, amplCallback: typing.Callable[[list[float]], list[float]] = None, partialsDecayExpRate: float = 0.8799999952316284) -> tuple[list[float], list[float]]:
|
|
950
950
|
...
|
|
951
951
|
def getLongType(self) -> str:
|
|
952
952
|
...
|
|
@@ -1411,4 +1411,4 @@ C: ClefSign # value = <ClefSign.C: 2>
|
|
|
1411
1411
|
F: ClefSign # value = <ClefSign.F: 1>
|
|
1412
1412
|
G: ClefSign # value = <ClefSign.G: 0>
|
|
1413
1413
|
P: ClefSign # value = <ClefSign.P: 3>
|
|
1414
|
-
__version__: str = '"1.9.
|
|
1414
|
+
__version__: str = '"1.9.5"'
|
|
@@ -67,16 +67,69 @@ def _dissmeasure(fvec: List[float], amp: List[float], model: str = 'min') -> flo
|
|
|
67
67
|
return D, fr_pairs, am_pairs
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def plotSetharesDissonanceCurve(fundamentalFreq: float = 440, numPartials: int = 6, ratioLowLimit: float = 1.0, ratioHighLimit: float = 2.3, ratioStepIncrement: float = 0.001, amplCallback: Optional[Callable[[List[float]], List[float]]] = None) -> Tuple[go.Figure, pd.DataFrame]:
|
|
70
|
+
def plotSetharesDissonanceCurve(fundamentalFreq: float = 440, numPartials: int = 6, ratioLowLimit: float = 1.0, ratioHighLimit: float = 2.3, ratioStepIncrement: float = 0.001, amplCallback: Optional[Callable[[List[float]], List[float]]] = None, partialsDecayExpRate: float = 0.88) -> Tuple[go.Figure, pd.DataFrame]:
|
|
71
71
|
"""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
Generate and return the sensory dissonance curve (Sethares) for a harmonic spectrum.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
fundamentalFreq : float, default=440
|
|
77
|
+
Base frequency (f₀) in Hz on which the partials are built.
|
|
78
|
+
|
|
79
|
+
numPartials : int, default=6
|
|
80
|
+
Number of harmonics (partials) to include.
|
|
81
|
+
|
|
82
|
+
ratioLowLimit : float, default=1.0
|
|
83
|
+
Lower bound of the frequency ratio axis (intervals).
|
|
84
|
+
|
|
85
|
+
ratioHighLimit : float, default=2.3
|
|
86
|
+
Upper bound of the frequency ratio axis.
|
|
87
|
+
|
|
88
|
+
ratioStepIncrement : float, default=0.001
|
|
89
|
+
Step size between successive frequency ratios in the dissonance curve.
|
|
90
|
+
|
|
91
|
+
amplCallback : Optional[Callable[[List[float]], List[float]]], default=None
|
|
92
|
+
Optional function that receives a list of partial frequencies and returns
|
|
93
|
+
corresponding amplitudes. If None, amplitudes decay exponentially by
|
|
94
|
+
`partialsDecayExpRate`.
|
|
95
|
+
|
|
96
|
+
partialsDecayExpRate : float, default=0.88
|
|
97
|
+
Exponential decay rate for harmonics when `amplCallback` is None:
|
|
98
|
+
amplitude_i = (partialsDecayExpRate)**i.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
fig : go.Figure
|
|
103
|
+
Plotly figure of the sensory dissonance curve with a log-scaled frequency ratio
|
|
104
|
+
axis. Includes vertical lines for musically notable intervals (e.g., 3/2, 5/4).
|
|
105
|
+
|
|
106
|
+
df : pandas.DataFrame
|
|
107
|
+
DataFrame with columns:
|
|
108
|
+
- 'ratio': frequency ratio values
|
|
109
|
+
- 'dissonance': sensory dissonance computed for each ratio
|
|
110
|
+
- 'freqs': frequency pair vectors used for calculation
|
|
111
|
+
- 'amps': amplitude pair vectors used in calculation
|
|
112
|
+
|
|
113
|
+
Behavior
|
|
114
|
+
--------
|
|
115
|
+
1. Constructs frequency vector `freqs` with integer multiples of `fundamentalFreq`.
|
|
116
|
+
2. Computes amplitude vector `amps` via `amplCallback`, or using exponential decay.
|
|
117
|
+
3. Validates matching lengths for `freqs` and `amps`, raising ValueError if mismatched.
|
|
118
|
+
4. Constructs a `ratios` array from `ratioLowLimit` to `ratioHighLimit`.
|
|
119
|
+
5. For each ratio r:
|
|
120
|
+
- Concatenates `freqs` with r × `freqs`; likewise for amplitudes.
|
|
121
|
+
- Applies `_dissmeasure` to compute sensory dissonance, frequency pairs, and amplitude pairs.
|
|
122
|
+
6. Builds a Plotly figure plotting dissonance vs. ratio and overlays lines at common musical intervals.
|
|
123
|
+
7. Returns the figure and a pandas DataFrame for further analysis.
|
|
124
|
+
|
|
125
|
+
Exceptions
|
|
126
|
+
----------
|
|
127
|
+
ValueError:
|
|
128
|
+
Raised if the output of `amplCallback` (if provided) does not match `numPartials` in length.
|
|
76
129
|
"""
|
|
77
130
|
freqs = fundamentalFreq * np.array(list(range(1, numPartials+1)))
|
|
78
|
-
amps =
|
|
79
|
-
|
|
131
|
+
amps = partialsDecayExpRate**np.array(list(range(0, numPartials))
|
|
132
|
+
) if amplCallback == None else amplCallback(freqs)
|
|
80
133
|
|
|
81
134
|
if len(freqs) != len(amps):
|
|
82
135
|
raise ValueError(
|
|
@@ -190,6 +243,7 @@ def _setharesDissonanceDataFrameInterpolation(df: pd.DataFrame, interpolatePoint
|
|
|
190
243
|
|
|
191
244
|
|
|
192
245
|
def plotScoreSetharesDissonance(score: mc.Score, plotType='line', lineShape='linear', numPartialsPerNote: int = 6, useMinModel: bool = True,
|
|
246
|
+
partialsDecayExpRate: float = 0.88,
|
|
193
247
|
amplCallback: Optional[Callable[[
|
|
194
248
|
List[float]], List[float]]] = None,
|
|
195
249
|
dissCallback: Optional[Callable[[List[float]], float]] = None, **kwargs) -> Tuple[go.Figure, pd.DataFrame]:
|
|
@@ -202,6 +256,7 @@ def plotScoreSetharesDissonance(score: mc.Score, plotType='line', lineShape='lin
|
|
|
202
256
|
numPartialsPerNote (int): Amount of spectral partials for each note
|
|
203
257
|
useMinModel (bool): Sethares dissonance values can be computed using the 'minimal amplitude' model
|
|
204
258
|
or the 'product amplitudes' model. The 'min' model is a more recent approach
|
|
259
|
+
partialsDecayExpRate (float): Partials decay exponential rate (default: 0.88)
|
|
205
260
|
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
206
261
|
dissCallback: Custom user function callback to receive all paired partial dissonances and computes
|
|
207
262
|
a single total dissonance value output
|
|
@@ -233,7 +288,7 @@ def plotScoreSetharesDissonance(score: mc.Score, plotType='line', lineShape='lin
|
|
|
233
288
|
df = score.getChordsDataFrame(kwargs)
|
|
234
289
|
|
|
235
290
|
df["dissonance"] = df.apply(lambda row: row.chord.getSetharesDissonance(
|
|
236
|
-
numPartialsPerNote, useMinModel, amplCallback, dissCallback), axis=1)
|
|
291
|
+
numPartialsPerNote, useMinModel, amplCallback, partialsDecayExpRate, dissCallback), axis=1)
|
|
237
292
|
df["chordNotes"] = df.apply(lambda row: ', '.join(
|
|
238
293
|
[str(x.getPitch()) for x in row.chord.getNotes()]), axis=1)
|
|
239
294
|
df["chordSize"] = df.apply(lambda row: row.chord.size(), axis=1)
|
|
@@ -282,7 +337,7 @@ def plotScoreSetharesDissonance(score: mc.Score, plotType='line', lineShape='lin
|
|
|
282
337
|
|
|
283
338
|
|
|
284
339
|
def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: Optional[Callable[[
|
|
285
|
-
List[float]], List[float]]] = None, dissonanceThreshold: float = 0.1, dissonanceDecimalPoint: int = 2, showValues: bool = False,
|
|
340
|
+
List[float]], List[float]]] = None, partialsDecayExpRate: float = 0.88, dissonanceThreshold: float = 0.1, dissonanceDecimalPoint: int = 2, showValues: bool = False,
|
|
286
341
|
valuesDecimalPlaces: int = 2) -> Tuple[plotly.graph_objs._figure.Figure, pd.DataFrame]:
|
|
287
342
|
"""Plot chord dyads Sethares dissonance heatmap
|
|
288
343
|
|
|
@@ -294,6 +349,7 @@ def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote:
|
|
|
294
349
|
useMinModel (bool): Sethares dissonance values can be computed using the 'minimal amplitude' model
|
|
295
350
|
or the 'product amplitudes' model. The 'min' model is a more recent approach
|
|
296
351
|
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
352
|
+
partialsDecayExpRate (float): Partials decay exponential rate (default: 0.88)
|
|
297
353
|
dissonanceThreshold (float): Dissonance threshold to skip small dissonance values
|
|
298
354
|
dissonanceDecimalPoint (int): Round chord dissonance value in the plot title
|
|
299
355
|
showValues (bool): If True, show numerical values inside heatmap cells
|
|
@@ -313,7 +369,7 @@ def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote:
|
|
|
313
369
|
>>> fig.show()
|
|
314
370
|
"""
|
|
315
371
|
df = chord.getSetharesDyadsDataFrame(
|
|
316
|
-
numPartialsPerNote=numPartialsPerNote, useMinModel=useMinModel, amplCallback=amplCallback)
|
|
372
|
+
numPartialsPerNote=numPartialsPerNote, useMinModel=useMinModel, amplCallback=amplCallback, partialsDecayExpRate=partialsDecayExpRate)
|
|
317
373
|
dfFiltered = df[df.dissonance > dissonanceThreshold]
|
|
318
374
|
|
|
319
375
|
# Pivot para matriz (targetFreq como linhas, baseFreq como colunas)
|
|
@@ -4,14 +4,67 @@ import plotly.graph_objects as go
|
|
|
4
4
|
from maialib import maiacore as mc
|
|
5
5
|
from typing import Callable
|
|
6
6
|
|
|
7
|
-
def plotSetharesDissonanceCurve(fundamentalFreq: float = 440, numPartials: int = 6, ratioLowLimit: float = 1.0, ratioHighLimit: float = 2.3, ratioStepIncrement: float = 0.001, amplCallback: Callable[[list[float]], list[float]] | None = None) -> tuple[go.Figure, pd.DataFrame]:
|
|
7
|
+
def plotSetharesDissonanceCurve(fundamentalFreq: float = 440, numPartials: int = 6, ratioLowLimit: float = 1.0, ratioHighLimit: float = 2.3, ratioStepIncrement: float = 0.001, amplCallback: Callable[[list[float]], list[float]] | None = None, partialsDecayExpRate: float = 0.88) -> tuple[go.Figure, pd.DataFrame]:
|
|
8
8
|
"""
|
|
9
|
-
|
|
9
|
+
Generate and return the sensory dissonance curve (Sethares) for a harmonic spectrum.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
fundamentalFreq : float, default=440
|
|
14
|
+
Base frequency (f₀) in Hz on which the partials are built.
|
|
15
|
+
|
|
16
|
+
numPartials : int, default=6
|
|
17
|
+
Number of harmonics (partials) to include.
|
|
18
|
+
|
|
19
|
+
ratioLowLimit : float, default=1.0
|
|
20
|
+
Lower bound of the frequency ratio axis (intervals).
|
|
21
|
+
|
|
22
|
+
ratioHighLimit : float, default=2.3
|
|
23
|
+
Upper bound of the frequency ratio axis.
|
|
24
|
+
|
|
25
|
+
ratioStepIncrement : float, default=0.001
|
|
26
|
+
Step size between successive frequency ratios in the dissonance curve.
|
|
27
|
+
|
|
28
|
+
amplCallback : Optional[Callable[[List[float]], List[float]]], default=None
|
|
29
|
+
Optional function that receives a list of partial frequencies and returns
|
|
30
|
+
corresponding amplitudes. If None, amplitudes decay exponentially by
|
|
31
|
+
`partialsDecayExpRate`.
|
|
32
|
+
|
|
33
|
+
partialsDecayExpRate : float, default=0.88
|
|
34
|
+
Exponential decay rate for harmonics when `amplCallback` is None:
|
|
35
|
+
amplitude_i = (partialsDecayExpRate)**i.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
fig : go.Figure
|
|
40
|
+
Plotly figure of the sensory dissonance curve with a log-scaled frequency ratio
|
|
41
|
+
axis. Includes vertical lines for musically notable intervals (e.g., 3/2, 5/4).
|
|
42
|
+
|
|
43
|
+
df : pandas.DataFrame
|
|
44
|
+
DataFrame with columns:
|
|
45
|
+
- 'ratio': frequency ratio values
|
|
46
|
+
- 'dissonance': sensory dissonance computed for each ratio
|
|
47
|
+
- 'freqs': frequency pair vectors used for calculation
|
|
48
|
+
- 'amps': amplitude pair vectors used in calculation
|
|
49
|
+
|
|
50
|
+
Behavior
|
|
51
|
+
--------
|
|
52
|
+
1. Constructs frequency vector `freqs` with integer multiples of `fundamentalFreq`.
|
|
53
|
+
2. Computes amplitude vector `amps` via `amplCallback`, or using exponential decay.
|
|
54
|
+
3. Validates matching lengths for `freqs` and `amps`, raising ValueError if mismatched.
|
|
55
|
+
4. Constructs a `ratios` array from `ratioLowLimit` to `ratioHighLimit`.
|
|
56
|
+
5. For each ratio r:
|
|
57
|
+
- Concatenates `freqs` with r × `freqs`; likewise for amplitudes.
|
|
58
|
+
- Applies `_dissmeasure` to compute sensory dissonance, frequency pairs, and amplitude pairs.
|
|
59
|
+
6. Builds a Plotly figure plotting dissonance vs. ratio and overlays lines at common musical intervals.
|
|
60
|
+
7. Returns the figure and a pandas DataFrame for further analysis.
|
|
61
|
+
|
|
62
|
+
Exceptions
|
|
63
|
+
----------
|
|
64
|
+
ValueError:
|
|
65
|
+
Raised if the output of `amplCallback` (if provided) does not match `numPartials` in length.
|
|
13
66
|
"""
|
|
14
|
-
def plotScoreSetharesDissonance(score: mc.Score, plotType: str = 'line', lineShape: str = 'linear', numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: Callable[[list[float]], list[float]] | None = None, dissCallback: Callable[[list[float]], float] | None = None, **kwargs) -> tuple[go.Figure, pd.DataFrame]:
|
|
67
|
+
def plotScoreSetharesDissonance(score: mc.Score, plotType: str = 'line', lineShape: str = 'linear', numPartialsPerNote: int = 6, useMinModel: bool = True, partialsDecayExpRate: float = 0.88, amplCallback: Callable[[list[float]], list[float]] | None = None, dissCallback: Callable[[list[float]], float] | None = None, **kwargs) -> tuple[go.Figure, pd.DataFrame]:
|
|
15
68
|
'''Plot 2D line graph of the Sethares Dissonance over time
|
|
16
69
|
|
|
17
70
|
Args:
|
|
@@ -21,6 +74,7 @@ def plotScoreSetharesDissonance(score: mc.Score, plotType: str = 'line', lineSha
|
|
|
21
74
|
numPartialsPerNote (int): Amount of spectral partials for each note
|
|
22
75
|
useMinModel (bool): Sethares dissonance values can be computed using the \'minimal amplitude\' model
|
|
23
76
|
or the \'product amplitudes\' model. The \'min\' model is a more recent approach
|
|
77
|
+
partialsDecayExpRate (float): Partials decay exponential rate (default: 0.88)
|
|
24
78
|
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
25
79
|
dissCallback: Custom user function callback to receive all paired partial dissonances and computes
|
|
26
80
|
a single total dissonance value output
|
|
@@ -42,7 +96,7 @@ def plotScoreSetharesDissonance(score: mc.Score, plotType: str = 'line', lineSha
|
|
|
42
96
|
>>> ml.plotScoreSetharesDissonance(myScore, numPoints=15)
|
|
43
97
|
>>> ml.plotScoreSetharesDissonance(myScore, measureStart=10, measureEnd=20)
|
|
44
98
|
'''
|
|
45
|
-
def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: Callable[[list[float]], list[float]] | None = None, dissonanceThreshold: float = 0.1, dissonanceDecimalPoint: int = 2, showValues: bool = False, valuesDecimalPlaces: int = 2) -> tuple[plotly.graph_objs._figure.Figure, pd.DataFrame]:
|
|
99
|
+
def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: Callable[[list[float]], list[float]] | None = None, partialsDecayExpRate: float = 0.88, dissonanceThreshold: float = 0.1, dissonanceDecimalPoint: int = 2, showValues: bool = False, valuesDecimalPlaces: int = 2) -> tuple[plotly.graph_objs._figure.Figure, pd.DataFrame]:
|
|
46
100
|
'''Plot chord dyads Sethares dissonance heatmap
|
|
47
101
|
|
|
48
102
|
Args:
|
|
@@ -53,6 +107,7 @@ def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote:
|
|
|
53
107
|
useMinModel (bool): Sethares dissonance values can be computed using the \'minimal amplitude\' model
|
|
54
108
|
or the \'product amplitudes\' model. The \'min\' model is a more recent approach
|
|
55
109
|
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
110
|
+
partialsDecayExpRate (float): Partials decay exponential rate (default: 0.88)
|
|
56
111
|
dissonanceThreshold (float): Dissonance threshold to skip small dissonance values
|
|
57
112
|
dissonanceDecimalPoint (int): Round chord dissonance value in the plot title
|
|
58
113
|
showValues (bool): If True, show numerical values inside heatmap cells
|