maialib 1.5.0__cp311-cp311-musllinux_1_2_x86_64.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/__init__.py +4 -0
- maialib/maiacore/__init__.py +4 -0
- maialib/maiacore/__init__.pyi +23 -0
- maialib/maiacore/maiacore.cpython-311-x86_64-linux-musl.so +0 -0
- maialib/maiacore/maiacore.pyi +1396 -0
- maialib/maiapy/__init__.py +3 -0
- maialib/maiapy/__init__.pyi +3 -0
- maialib/maiapy/other.py +131 -0
- maialib/maiapy/other.pyi +20 -0
- maialib/maiapy/plots.py +656 -0
- maialib/maiapy/plots.pyi +10 -0
- maialib/maiapy/sethares_dissonance.py +331 -0
- maialib/maiapy/sethares_dissonance.pyi +11 -0
- maialib/setup.py +48 -0
- maialib/xml-scores-examples/Bach_Cello_Suite_1.mxl +0 -0
- maialib/xml-scores-examples/Beethoven_Symphony_5_mov_1.xml +172197 -0
- maialib/xml-scores-examples/Chopin_Fantasie_Impromptu.mxl +0 -0
- maialib/xml-scores-examples/Dvorak_Symphony_9_mov_4.mxl +0 -0
- maialib/xml-scores-examples/Mahler_Symphony_8_Finale.mxl +0 -0
- maialib/xml-scores-examples/Mozart_Requiem_Introitus.mxl +0 -0
- maialib/xml-scores-examples/Strauss_Also_Sprach_Zarathustra.mxl +0 -0
- maialib-1.5.0.dist-info/LICENSE.txt +674 -0
- maialib-1.5.0.dist-info/METADATA +179 -0
- maialib-1.5.0.dist-info/RECORD +28 -0
- maialib-1.5.0.dist-info/WHEEL +5 -0
- maialib-1.5.0.dist-info/top_level.txt +2 -0
- maialib.libs/libgcc_s-a3a07607.so.1 +0 -0
- maialib.libs/libstdc++-496613c0.so.6.0.32 +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import plotly
|
|
4
|
+
import plotly.express as px
|
|
5
|
+
import plotly.graph_objects as go
|
|
6
|
+
from maialib import maiacore as mc
|
|
7
|
+
from typing import List, Tuple, Callable, Optional
|
|
8
|
+
|
|
9
|
+
__all__ = ["plotSetharesDissonanceCurve", "plotScoreSetharesDissonance", "plotChordDyadsSetharesDissonanceHeatmap"]
|
|
10
|
+
|
|
11
|
+
def _dissmeasure(fvec: List[float], amp: List[float], model: str = 'min') -> float:
|
|
12
|
+
"""
|
|
13
|
+
Given a list of partials in fvec, with amplitudes in amp, this routine
|
|
14
|
+
calculates the dissonance by summing the roughness of every sine pair
|
|
15
|
+
based on a model of Plomp-Levelt's roughness curve.
|
|
16
|
+
|
|
17
|
+
The older model (model='product') was based on the product of the two
|
|
18
|
+
amplitudes, but the newer model (model='min') is based on the minimum
|
|
19
|
+
of the two amplitudes, since this matches the beat frequency amplitude.
|
|
20
|
+
"""
|
|
21
|
+
# Sort by frequency
|
|
22
|
+
sort_idx = np.argsort(fvec)
|
|
23
|
+
am_sorted = np.asarray(amp)[sort_idx]
|
|
24
|
+
fr_sorted = np.asarray(fvec)[sort_idx]
|
|
25
|
+
|
|
26
|
+
# Sum amplitudes for unique frequencies
|
|
27
|
+
freq_amp_dict = {}
|
|
28
|
+
for f, a in zip(fr_sorted, am_sorted):
|
|
29
|
+
freq_amp_dict[f] = freq_amp_dict.get(f, 0) + a
|
|
30
|
+
|
|
31
|
+
# Extract updated frequencies and amplitudes from the dictionary
|
|
32
|
+
fr_sorted = np.array(list(freq_amp_dict.keys()))
|
|
33
|
+
am_sorted = np.array(list(freq_amp_dict.values()))
|
|
34
|
+
|
|
35
|
+
# Used to stretch dissonance curve for different freqs:
|
|
36
|
+
Dstar = 0.24 # Point of maximum dissonance
|
|
37
|
+
S1 = 0.0207
|
|
38
|
+
S2 = 18.96
|
|
39
|
+
|
|
40
|
+
C1 = 5
|
|
41
|
+
C2 = -5
|
|
42
|
+
|
|
43
|
+
# Plomp-Levelt roughness curve:
|
|
44
|
+
A1 = -3.51
|
|
45
|
+
A2 = -5.75
|
|
46
|
+
|
|
47
|
+
# Generate all combinations of frequency components
|
|
48
|
+
idx = np.transpose(np.triu_indices_from(np.eye(len(fr_sorted)), k=0))
|
|
49
|
+
fr_pairs = fr_sorted[idx]
|
|
50
|
+
am_pairs = am_sorted[idx]
|
|
51
|
+
|
|
52
|
+
Fmin = fr_pairs[:, 0]
|
|
53
|
+
S = Dstar / (S1 * Fmin + S2)
|
|
54
|
+
Fdif = fr_pairs[:, 1] - fr_pairs[:, 0]
|
|
55
|
+
|
|
56
|
+
if model == 'min':
|
|
57
|
+
a = np.amin(am_pairs, axis=1)
|
|
58
|
+
elif model == 'product':
|
|
59
|
+
a = np.prod(am_pairs, axis=1) # Older model
|
|
60
|
+
else:
|
|
61
|
+
raise ValueError('model should be "min" or "product"')
|
|
62
|
+
SFdif = S * Fdif
|
|
63
|
+
D = np.sum(a * (C1 * np.exp(A1 * SFdif) + C2 * np.exp(A2 * SFdif)))
|
|
64
|
+
|
|
65
|
+
return D, fr_pairs, am_pairs
|
|
66
|
+
|
|
67
|
+
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]:
|
|
68
|
+
"""
|
|
69
|
+
Compute the Sethares Dissonance Curve of a given base frequency
|
|
70
|
+
|
|
71
|
+
Return
|
|
72
|
+
A tuple that contains a Plotly figure, and the pair 'ratios' and 'dissonance' lists
|
|
73
|
+
"""
|
|
74
|
+
freqs = fundamentalFreq * np.array(list(range(1, numPartials+1)))
|
|
75
|
+
amps = 0.88**np.array(list(range(0, numPartials))
|
|
76
|
+
) if amplCallback == None else amplCallback(freqs)
|
|
77
|
+
|
|
78
|
+
if len(freqs) != len(amps):
|
|
79
|
+
raise ValueError(
|
|
80
|
+
"The size of amplVec must be equal to the 'numPartials' (6 is the default)")
|
|
81
|
+
|
|
82
|
+
# Calculate the number of points based on ratioStepIncrement
|
|
83
|
+
numPoints = int((ratioHighLimit - ratioLowLimit) / ratioStepIncrement) + 1
|
|
84
|
+
|
|
85
|
+
ratios = np.linspace(ratioLowLimit, ratioHighLimit, numPoints)
|
|
86
|
+
dissonances = []
|
|
87
|
+
fr_pairsVec = []
|
|
88
|
+
amp_pairsVec = []
|
|
89
|
+
for r in ratios:
|
|
90
|
+
extended_freqs = np.concatenate([freqs, r * freqs])
|
|
91
|
+
extended_amps = np.concatenate([amps, amps])
|
|
92
|
+
d, fr_pairs, amp_pairs = _dissmeasure(extended_freqs, extended_amps)
|
|
93
|
+
dissonances.append(d)
|
|
94
|
+
fr_pairsVec.append(fr_pairs)
|
|
95
|
+
amp_pairsVec.append(amp_pairs)
|
|
96
|
+
|
|
97
|
+
# Plotting using Plotly
|
|
98
|
+
fig = go.Figure()
|
|
99
|
+
fig.add_trace(go.Scatter(x=ratios, y=dissonances,
|
|
100
|
+
mode='lines', name='Dissonance'))
|
|
101
|
+
|
|
102
|
+
# Adding lines for the notable intervals
|
|
103
|
+
intervals = [(1, 1), (6, 5), (5, 4), (4, 3), (3, 2), (5, 3),
|
|
104
|
+
(2, 1), (4, 1), (8, 1), (16, 1), (32, 1)]
|
|
105
|
+
|
|
106
|
+
# Filter intervals based on ratioHighLimit
|
|
107
|
+
filtered_intervals = [(n, d)
|
|
108
|
+
for n, d in intervals if n/d <= ratioHighLimit]
|
|
109
|
+
|
|
110
|
+
for n, d in filtered_intervals:
|
|
111
|
+
fig.add_shape(
|
|
112
|
+
type="line",
|
|
113
|
+
x0=n/d,
|
|
114
|
+
y0=min(dissonances),
|
|
115
|
+
x1=n/d,
|
|
116
|
+
y1=max(dissonances),
|
|
117
|
+
line=dict(color="Silver", width=1)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
partialsTitle = "partial" if numPartials == 1 else "partials"
|
|
121
|
+
fig.update_layout(
|
|
122
|
+
title=f"<b>Sethares' Sensory Dissonance Curve</b><br><i>f<sub>0</sub>={fundamentalFreq}Hz | {numPartials} harmonic {partialsTitle}</i>",
|
|
123
|
+
title_x=0.5,
|
|
124
|
+
xaxis_title="Frequency Ratio",
|
|
125
|
+
yaxis_title="Sensory Dissonance",
|
|
126
|
+
xaxis_type="log",
|
|
127
|
+
xaxis=dict(
|
|
128
|
+
tickvals=[n/d for n, d in filtered_intervals],
|
|
129
|
+
ticktext=['{}/{}'.format(n, d) for n, d in filtered_intervals]
|
|
130
|
+
),
|
|
131
|
+
yaxis=dict(showticklabels=True)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
fig.add_shape(
|
|
135
|
+
# Rectangle with reference to the plot
|
|
136
|
+
type="rect",
|
|
137
|
+
xref="paper",
|
|
138
|
+
yref="paper",
|
|
139
|
+
x0=0,
|
|
140
|
+
y0=0,
|
|
141
|
+
x1=1.0,
|
|
142
|
+
y1=1.0,
|
|
143
|
+
line=dict(
|
|
144
|
+
color="black",
|
|
145
|
+
width=1,
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
df = pd.DataFrame(data=list(zip(ratios, dissonances, fr_pairsVec,
|
|
150
|
+
amp_pairsVec)), columns=['ratio', 'dissonance', 'freqs', 'amps'])
|
|
151
|
+
|
|
152
|
+
return fig, df
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _setharesDissonanceDataFrameInterpolation(df: pd.DataFrame, interpolatePoints: int) -> pd.DataFrame:
|
|
156
|
+
def split(a, n):
|
|
157
|
+
k, m = divmod(len(a), n)
|
|
158
|
+
return (a[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))
|
|
159
|
+
|
|
160
|
+
firstMeasureNumber = df.measure.min(skipna=True)
|
|
161
|
+
lastMeasureNumber = df.measure.max(skipna=True)
|
|
162
|
+
|
|
163
|
+
if interpolatePoints >= lastMeasureNumber:
|
|
164
|
+
raise Exception(
|
|
165
|
+
"ERROR: The score number of measures must be greater then the interpolate points value")
|
|
166
|
+
|
|
167
|
+
ranges = list(
|
|
168
|
+
split(range(firstMeasureNumber, lastMeasureNumber+1), interpolatePoints))
|
|
169
|
+
data = []
|
|
170
|
+
for sub in ranges:
|
|
171
|
+
sub_df = df.query(f'(measure >= {sub.start}) & (measure < {sub.stop})')
|
|
172
|
+
floatMeasure = (sub.start + sub.stop) / 2
|
|
173
|
+
dissonance = round(sub_df["dissonance"].mean(skipna=True))
|
|
174
|
+
chordSizeMean = round(sub_df["chordSize"].mean(skipna=True))
|
|
175
|
+
|
|
176
|
+
obj = {
|
|
177
|
+
"floatMeasure": floatMeasure,
|
|
178
|
+
"dissonance": dissonance,
|
|
179
|
+
"chordSizeMean": chordSizeMean,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
data.append(obj)
|
|
183
|
+
|
|
184
|
+
new_df = pd.DataFrame.from_records(data)
|
|
185
|
+
return new_df
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def plotScoreSetharesDissonance(score: mc.Score, plotType='line', lineShape='linear', numPartialsPerNote: int = 6, useMinModel: bool = True,
|
|
189
|
+
amplCallback: Optional[Callable[[
|
|
190
|
+
List[float]], List[float]]] = None,
|
|
191
|
+
dissCallback: Optional[Callable[[List[float]], float]] = None, **kwargs) -> Tuple[go.Figure, pd.DataFrame]:
|
|
192
|
+
"""Plot 2D line graph of the Sethares Dissonance over time
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
score (maialib.Score): A maialib Score object loaded with a valid MusicXML file
|
|
196
|
+
plotType (str): Can be 'line' or 'scatter'
|
|
197
|
+
lineShape (str): Can be 'linear' or 'spline'
|
|
198
|
+
numPartialsPerNote (int): Amount of spectral partials for each note
|
|
199
|
+
useMinModel (bool): Sethares dissonance values can be computed using the 'minimal amplitude' model
|
|
200
|
+
or the 'product amplitudes' model. The 'min' model is a more recent approach
|
|
201
|
+
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
202
|
+
dissCallback: Custom user function callback to receive all paired partial dissonances and computes
|
|
203
|
+
a single total dissonance value output
|
|
204
|
+
Kwargs:
|
|
205
|
+
measureStart (int): Start measure to plot
|
|
206
|
+
measureEnd (int): End measure to plot
|
|
207
|
+
numPoints (int): Number of interpolated points
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
A list: [Plotly Figure, The plot data as a Pandas Dataframe]
|
|
211
|
+
|
|
212
|
+
Raises:
|
|
213
|
+
RuntimeError, KeyError
|
|
214
|
+
|
|
215
|
+
Examples of use:
|
|
216
|
+
|
|
217
|
+
>>> myScore = ml.Score("/path/to/score.xml")
|
|
218
|
+
>>> ml.plotScoreSetharesDissonance(myScore)
|
|
219
|
+
>>> ml.plotScoreSetharesDissonance(myScore, numPoints=15)
|
|
220
|
+
>>> ml.plotScoreSetharesDissonance(myScore, measureStart=10, measureEnd=20)
|
|
221
|
+
"""
|
|
222
|
+
# ===== GET THE PLOT TITLE ===== #
|
|
223
|
+
workTitle = score.getTitle()
|
|
224
|
+
if workTitle.strip() == "":
|
|
225
|
+
workTitle = "No Title"
|
|
226
|
+
plotTitle = f'<b>Sethares Sensory Dissonance</b><br><i>{workTitle}</i>'
|
|
227
|
+
|
|
228
|
+
# ===== COMPUTE THE SETHARES DISSONANCE ===== #
|
|
229
|
+
df = score.getChordsDataFrame(kwargs)
|
|
230
|
+
|
|
231
|
+
df["dissonance"] = df.apply(lambda row: row.chord.getSetharesDissonance(
|
|
232
|
+
numPartialsPerNote, useMinModel, amplCallback, dissCallback), axis=1)
|
|
233
|
+
df["chordNotes"] = df.apply(lambda row: ', '.join(
|
|
234
|
+
[str(x.getPitch()) for x in row.chord.getNotes()]), axis=1)
|
|
235
|
+
df["chordSize"] = df.apply(lambda row: row.chord.size(), axis=1)
|
|
236
|
+
dissonanceMean = df.dissonance.mean()
|
|
237
|
+
|
|
238
|
+
# ===== CHECK THE INTERPOLATION POINTS ===== #
|
|
239
|
+
plotHoverData = ["chordNotes", "chordSize"]
|
|
240
|
+
if "numPoints" in kwargs:
|
|
241
|
+
df = _setharesDissonanceDataFrameInterpolation(df, kwargs["numPoints"])
|
|
242
|
+
plotHoverData = ["chordSizeMean"]
|
|
243
|
+
|
|
244
|
+
# ===== PLOT ===== #
|
|
245
|
+
fig = None
|
|
246
|
+
if plotType == 'line':
|
|
247
|
+
fig = px.line(df, x="floatMeasure", y="dissonance",
|
|
248
|
+
hover_data=plotHoverData, title=plotTitle, line_shape=lineShape)
|
|
249
|
+
else:
|
|
250
|
+
fig = px.scatter(df, x="floatMeasure", y="dissonance",
|
|
251
|
+
hover_data=plotHoverData, title=plotTitle)
|
|
252
|
+
|
|
253
|
+
fig.add_hline(y=dissonanceMean, line_width=3, line_dash="dash",
|
|
254
|
+
line_color="green", annotation_text="Mean")
|
|
255
|
+
|
|
256
|
+
fig.update_layout(
|
|
257
|
+
title_x=0.5,
|
|
258
|
+
xaxis_title="Measures",
|
|
259
|
+
yaxis_title="Sensory Dissonance",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
fig.add_shape(
|
|
263
|
+
# Rectangle with reference to the plot
|
|
264
|
+
type="rect",
|
|
265
|
+
xref="paper",
|
|
266
|
+
yref="paper",
|
|
267
|
+
x0=0,
|
|
268
|
+
y0=0,
|
|
269
|
+
x1=1.0,
|
|
270
|
+
y1=1.0,
|
|
271
|
+
line=dict(
|
|
272
|
+
color="black",
|
|
273
|
+
width=1,
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return fig, df
|
|
278
|
+
|
|
279
|
+
def plotChordDyadsSetharesDissonanceHeatmap(chord: mc.Chord, numPartialsPerNote: int = 6, useMinModel: bool = True, amplCallback: Optional[Callable[[
|
|
280
|
+
List[float]], List[float]]] = None, dissonanceThreshold: float = 0.1, dissonanceDecimalPoint: int = 2) -> Tuple[plotly.graph_objs._figure.Figure, pd.DataFrame]:
|
|
281
|
+
"""Plot chord dyads Sethares dissonance heatmap
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
chord (maialib.Chord): A maialib Chord
|
|
285
|
+
|
|
286
|
+
Kwargs:
|
|
287
|
+
numPartialsPerNote (int): Amount of spectral partials for each note
|
|
288
|
+
useMinModel (bool): Sethares dissonance values can be computed using the 'minimal amplitude' model
|
|
289
|
+
or the 'product amplitudes' model. The 'min' model is a more recent approach
|
|
290
|
+
amplCallback: Custom user function callback to generate the amplitude of each spectrum partial
|
|
291
|
+
dissonanceThreshold (float): Dissonance threshold to skip small dissonance values
|
|
292
|
+
dissonanceDecimalPoint (int): Round chord dissonance value in the plot title
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
A list: [Plotly Figure, The plot data as a Pandas Dataframe]
|
|
296
|
+
|
|
297
|
+
Raises:
|
|
298
|
+
RuntimeError, KeyError
|
|
299
|
+
|
|
300
|
+
Examples of use:
|
|
301
|
+
|
|
302
|
+
>>> import maialib as ml
|
|
303
|
+
>>> myChord = ml.Chord(["C3", "E3", "G3"])
|
|
304
|
+
>>> fig, df = plotChordDyadsSetharesDissonanceHeatmap(myChord)
|
|
305
|
+
>>> fig.show()
|
|
306
|
+
"""
|
|
307
|
+
df = chord.getSetharesDyadsDataFrame(numPartialsPerNote=numPartialsPerNote, useMinModel=useMinModel, amplCallback=amplCallback)
|
|
308
|
+
dfFiltered = df[df.dissonance > dissonanceThreshold]
|
|
309
|
+
|
|
310
|
+
# Pivot the dataframe to create a matrix
|
|
311
|
+
matrix_df = dfFiltered.pivot(index='baseFreq', columns='targetFreq', values='dissonance')
|
|
312
|
+
|
|
313
|
+
# Create a heatmap using Plotly
|
|
314
|
+
fig = px.imshow(matrix_df,
|
|
315
|
+
labels=dict(x="Target Frequency (Hz)", y="Base Frequency (Hz)", color="Dissonance"), color_continuous_scale='Inferno')
|
|
316
|
+
|
|
317
|
+
# Extract unique frequencies for x and y ticks
|
|
318
|
+
x_ticks = sorted(matrix_df.columns.unique())
|
|
319
|
+
y_ticks = sorted(matrix_df.index.unique())
|
|
320
|
+
|
|
321
|
+
roundedXTicksValues = [round(num, 0) for num in x_ticks]
|
|
322
|
+
roundedYTicksValues = [round(num, 0) for num in y_ticks]
|
|
323
|
+
|
|
324
|
+
# Update x and y ticks to only show unique frequencies and set log scale
|
|
325
|
+
fig.update_xaxes(type='log', tickvals=x_ticks, ticktext=roundedXTicksValues)
|
|
326
|
+
fig.update_yaxes(type='log', tickvals=y_ticks, ticktext=roundedYTicksValues)
|
|
327
|
+
|
|
328
|
+
roundedDissonanceValue = round(df.dissonance.sum(), dissonanceDecimalPoint)
|
|
329
|
+
fig.update_layout(title=f'<b>Chord Dyads Sethares Dissonance Heatmap</b><br><i>Chord Dissonance={str(roundedDissonanceValue)}</i>', title_x=0.5)
|
|
330
|
+
|
|
331
|
+
return fig, dfFiltered
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import plotly
|
|
3
|
+
import plotly.graph_objects as go
|
|
4
|
+
from maialib import maiacore as mc
|
|
5
|
+
from typing import Callable
|
|
6
|
+
|
|
7
|
+
__all__ = ['plotSetharesDissonanceCurve', 'plotScoreSetharesDissonance', 'plotChordDyadsSetharesDissonanceHeatmap']
|
|
8
|
+
|
|
9
|
+
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]: ...
|
|
10
|
+
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]: ...
|
|
11
|
+
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) -> tuple[plotly.graph_objs._figure.Figure, pd.DataFrame]: ...
|
maialib/setup.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
with open("LICENSE.txt", "r", encoding="utf-8") as fh:
|
|
7
|
+
license_txt = fh.read()
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name="maialib",
|
|
11
|
+
version="1.5.0-dev",
|
|
12
|
+
author="Nycholas Maia",
|
|
13
|
+
author_email="nyckmaia@gmail.com",
|
|
14
|
+
description="A C++/Python library to manipulate music data",
|
|
15
|
+
long_description=long_description,
|
|
16
|
+
long_description_content_type="text/markdown",
|
|
17
|
+
license="GNU General Public License v3 or later (GPLv3+)",
|
|
18
|
+
url="https://github.com/nyckmaia/maialib",
|
|
19
|
+
project_urls={
|
|
20
|
+
"Bug Tracker": "https://github.com/nyckmaia/maialib/issues",
|
|
21
|
+
},
|
|
22
|
+
keywords=["music", "score", "sheet music", "analysis"],
|
|
23
|
+
packages=find_packages(),
|
|
24
|
+
package_data={"": ['*.so', '*.pyd', '__init__.pyi', 'maiacore/__init__.pyi',
|
|
25
|
+
"py.typed", "*.pyi", "**/*.pyi",
|
|
26
|
+
"xml-scores-examples/Bach_Cello_Suite_1.mxl",
|
|
27
|
+
"xml-scores-examples/Beethoven_Symphony_5_mov_1.xml",
|
|
28
|
+
"xml-scores-examples/Chopin_Fantasie_Impromptu.mxl",
|
|
29
|
+
"xml-scores-examples/Dvorak_Symphony_9_mov_4.mxl",
|
|
30
|
+
"xml-scores-examples/Mahler_Symphony_8_Finale.mxl",
|
|
31
|
+
"xml-scores-examples/Mozart_Requiem_Introitus.mxl",
|
|
32
|
+
"xml-scores-examples/Strauss_Also_Sprach_Zarathustra.mxl"]},
|
|
33
|
+
|
|
34
|
+
include_package_data=True,
|
|
35
|
+
py_modules=["maiacore", "maiapy"],
|
|
36
|
+
classifiers=[
|
|
37
|
+
"Development Status :: 3 - Alpha",
|
|
38
|
+
"Programming Language :: Python :: 3",
|
|
39
|
+
"Programming Language :: C++",
|
|
40
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
41
|
+
"Operating System :: OS Independent",
|
|
42
|
+
"Intended Audience :: Science/Research",
|
|
43
|
+
"Natural Language :: English",
|
|
44
|
+
"Topic :: Software Development :: Libraries"
|
|
45
|
+
],
|
|
46
|
+
python_requires=">=3.8.0",
|
|
47
|
+
zip_safe=False,
|
|
48
|
+
)
|
|
Binary file
|