CreativePython 1.1.5__tar.gz → 1.2__tar.gz
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.
- {creativepython-1.1.5/src/CreativePython.egg-info → creativepython-1.2}/PKG-INFO +1 -1
- {creativepython-1.1.5 → creativepython-1.2}/pyproject.toml +2 -2
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/GuiRenderer.py +39 -94
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/RealtimeAudioPlayer.py +9 -8
- {creativepython-1.1.5 → creativepython-1.2/src/CreativePython.egg-info}/PKG-INFO +1 -1
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython.egg-info/SOURCES.txt +3 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython.egg-info/top_level.txt +1 -0
- creativepython-1.2/src/animation.py +554 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/gui.py +472 -139
- {creativepython-1.1.5 → creativepython-1.2}/src/midi.py +52 -52
- {creativepython-1.1.5 → creativepython-1.2}/src/music.py +73 -82
- {creativepython-1.1.5 → creativepython-1.2}/src/osc.py +10 -10
- creativepython-1.2/tests/test_crescendo.py +82 -0
- creativepython-1.2/tests/test_crescendo_import.py +114 -0
- {creativepython-1.1.5 → creativepython-1.2}/LICENSE +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/LICENSE-PSF +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/MANIFEST.in +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/README.md +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/setup.cfg +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/GuiHandler.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/Java-Comparison-Tests/advMetricRunner.pythonSurvey.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/Java-Comparison-Tests/compareMetrics_Java-Vs-Python.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/RunMetrics.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/Surveyor.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/Confidence.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/Contig.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/ExtendedNote.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/Histogram.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/Judgement.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/Measurement.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/PianoRoll.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/PianoRollOld.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_ExtendedNote.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_Histogram.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_Measurement.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_PianoRoll_assertions.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_PianoRoll_integration.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_PianoRoll_quantization.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/data/test_PianoRoll_unit.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/Metric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/ZipfMetrics.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ChordDensityMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ChordDistanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ChordMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ChordNormalizedMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ChromaticToneMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourBasslineDurationMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourBasslineDurationQuantizedMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourBasslinePitchMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourMelodyDurationMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourMelodyDurationQuantizedMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/ContourMelodyPitchMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationBigramMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationDistanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationQuantizedBigramMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationQuantizedDistanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/DurationQuantizedMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/HarmonicBigramMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/HarmonicConsonanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/HarmonicIntervalMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/MelodicBigramMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/MelodicConsonanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/MelodicIntervalMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/PitchDistanceMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/PitchDurationMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/PitchDurationQuantizedMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/PitchMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/RestMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_DurationMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_Metrics_BasicIntervalsAndBigrams.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_Metrics_ChordsAndConsonance.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_Metrics_ContoursAndChromatic.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_Metrics_QuantizedDurationsAndDistances.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_PitchMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/simple/test_RestMetric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/metrics/test_Metric.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/utilities/CSVWriter.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/utilities/PowerLawRandom.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/nevmuse/utilities/__init__.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython/notationRenderer.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython.egg-info/dependency_links.txt +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/CreativePython.egg-info/requires.txt +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/bin/libportaudio.2.dylib +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/iannix.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/image.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/markov.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/timer.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/src/zipf.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testAnimate.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testCompress.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testGameboard.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testHitTesting.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testPeer.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/testToolTips.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/test_keyEvent.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/test_midi.py +0 -0
- {creativepython-1.1.5 → creativepython-1.2}/tests/test_osc.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CreativePython
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2
|
|
4
4
|
Summary: A Python-based software environment for developing algorithmic art projects.
|
|
5
5
|
Author-email: "Dr. Bill Manaris" <manaris@cofc.edu>, Taj Ballinger <ballingertj@g.cofc.edu>, Trevor Ritchie <ritchiets@g.cofc.edu>
|
|
6
6
|
License: MIT License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "CreativePython"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.2"
|
|
8
8
|
description = "A Python-based software environment for developing algorithmic art projects."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -40,7 +40,7 @@ dependencies = [
|
|
|
40
40
|
|
|
41
41
|
[tool.setuptools]
|
|
42
42
|
package-dir = {"" = "src"}
|
|
43
|
-
py-modules = ["gui", "image", "midi", "music", "osc", "timer", "iannix", "markov", "zipf"]
|
|
43
|
+
py-modules = ["gui", "image", "midi", "music", "osc", "timer", "animation", "iannix", "markov", "zipf"]
|
|
44
44
|
|
|
45
45
|
[tool.setuptools.packages.find]
|
|
46
46
|
where = ["src"]
|
|
@@ -624,7 +624,30 @@ class _QPolygonItem(_QtGraphicsItemEventMixin, QtWidgets.QGraphicsPolygonItem):
|
|
|
624
624
|
pass
|
|
625
625
|
|
|
626
626
|
class _QPixmapItem(_QtGraphicsItemEventMixin, QtWidgets.QGraphicsPixmapItem):
|
|
627
|
-
|
|
627
|
+
_colorFilter = None # (r, g, b, a) set by IconMirror._applyColor; None = no filter
|
|
628
|
+
|
|
629
|
+
def paint(self, painter, option, widget=None):
|
|
630
|
+
if self._colorFilter is None:
|
|
631
|
+
super().paint(painter, option, widget)
|
|
632
|
+
return
|
|
633
|
+
|
|
634
|
+
pixmap = self.pixmap()
|
|
635
|
+
if pixmap.isNull():
|
|
636
|
+
return
|
|
637
|
+
|
|
638
|
+
r, g, b, a = self._colorFilter
|
|
639
|
+
image = pixmap.toImage().convertToFormat(QtGui.QImage.Format.Format_ARGB32)
|
|
640
|
+
|
|
641
|
+
filtered = QtGui.QImage(image.size(), QtGui.QImage.Format.Format_ARGB32)
|
|
642
|
+
filtered.fill(QtCore.Qt.GlobalColor.transparent)
|
|
643
|
+
|
|
644
|
+
p = QtGui.QPainter(filtered)
|
|
645
|
+
p.drawImage(0, 0, image)
|
|
646
|
+
p.setCompositionMode(QtGui.QPainter.CompositionMode.CompositionMode_SourceOver)
|
|
647
|
+
p.fillRect(image.rect(), QtGui.QColor(r, g, b, a))
|
|
648
|
+
p.end()
|
|
649
|
+
|
|
650
|
+
painter.drawImage(self.offset(), filtered)
|
|
628
651
|
|
|
629
652
|
class _QGroupItem(_QtGraphicsItemEventMixin, QtWidgets.QGraphicsItemGroup):
|
|
630
653
|
pass
|
|
@@ -974,8 +997,6 @@ class DisplayMirror:
|
|
|
974
997
|
else:
|
|
975
998
|
item.qObject.setZValue(qZValue)
|
|
976
999
|
self._scene.addItem(item.qObject) # attach QGraphicsItem to scene
|
|
977
|
-
cacheMode = QtWidgets.QGraphicsItem.CacheMode.DeviceCoordinateCache
|
|
978
|
-
item.qObject.setCacheMode(cacheMode)
|
|
979
1000
|
|
|
980
1001
|
posArgs = {}
|
|
981
1002
|
if x is not None:
|
|
@@ -1688,15 +1709,12 @@ class _DrawableMirror:
|
|
|
1688
1709
|
self._rotation = 0
|
|
1689
1710
|
self._toolTipText = None
|
|
1690
1711
|
|
|
1691
|
-
# GuiRenderer only handles commands that alter an object visually
|
|
1692
|
-
#
|
|
1712
|
+
# GuiRenderer only handles commands that alter an object visually.
|
|
1713
|
+
# Hit testing (contains/intersects/encloses) is handled entirely in gui.py.
|
|
1693
1714
|
self._commandHandlers = {
|
|
1694
1715
|
'setPosition': self._setPosition,
|
|
1695
1716
|
'setSize': self._setSize,
|
|
1696
1717
|
'setRotation': self._setRotation,
|
|
1697
|
-
'contains': self._contains,
|
|
1698
|
-
'intersects': self._intersects,
|
|
1699
|
-
'encloses': self._encloses,
|
|
1700
1718
|
'setToolTipText': self._setToolTipText,
|
|
1701
1719
|
'show': self._show,
|
|
1702
1720
|
'hide': self._hide,
|
|
@@ -1759,43 +1777,6 @@ class _DrawableMirror:
|
|
|
1759
1777
|
self.qObject.prepareGeometryChange()
|
|
1760
1778
|
self.qObject.setRotation(qtDegree)
|
|
1761
1779
|
|
|
1762
|
-
# ── Hit testing ────────────────────────────────────────────────────────────
|
|
1763
|
-
|
|
1764
|
-
def _contains(self, args, responseId):
|
|
1765
|
-
"""Returns True if the point (x, y) is inside this item."""
|
|
1766
|
-
x = args.get('x', 0)
|
|
1767
|
-
y = args.get('y', 0)
|
|
1768
|
-
globalPoint = QtCore.QPointF(x, y)
|
|
1769
|
-
localPoint = self.qObject.mapFromScene(globalPoint)
|
|
1770
|
-
result = self.qObject.contains(localPoint)
|
|
1771
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
1772
|
-
|
|
1773
|
-
def _intersects(self, args, responseId):
|
|
1774
|
-
"""Returns True if this item intersects another item."""
|
|
1775
|
-
otherObjectId = args.get('otherObjectId')
|
|
1776
|
-
otherMirror = self.guiRenderer._objectRegistry.get(otherObjectId)
|
|
1777
|
-
result = False
|
|
1778
|
-
|
|
1779
|
-
if otherMirror is not None:
|
|
1780
|
-
pathA = self.qObject.mapToScene(self.qObject.shape())
|
|
1781
|
-
pathB = otherMirror.qObject.mapToScene(otherMirror.qObject.shape())
|
|
1782
|
-
result = pathA.intersects(pathB)
|
|
1783
|
-
|
|
1784
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
1785
|
-
|
|
1786
|
-
def _encloses(self, args, responseId):
|
|
1787
|
-
"""Returns True if this item fully encloses another item."""
|
|
1788
|
-
otherObjectId = args.get('otherObjectId')
|
|
1789
|
-
otherMirror = self.guiRenderer._objectRegistry.get(otherObjectId)
|
|
1790
|
-
result = False
|
|
1791
|
-
|
|
1792
|
-
if otherMirror is not None:
|
|
1793
|
-
pathA = self.qObject.mapToScene(self.qObject.shape())
|
|
1794
|
-
pathB = otherMirror.qObject.mapToScene(otherMirror.qObject.shape())
|
|
1795
|
-
result = pathA.contains(pathB)
|
|
1796
|
-
|
|
1797
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
1798
|
-
|
|
1799
1780
|
# ── Visibility ─────────────────────────────────────────────────────────────
|
|
1800
1781
|
|
|
1801
1782
|
def _show(self, args, responseId):
|
|
@@ -2405,6 +2386,7 @@ class PolygonMirror(_GraphicsMirror):
|
|
|
2405
2386
|
# IconMirror — mirror of gui.py's Icon
|
|
2406
2387
|
#######################################################################################
|
|
2407
2388
|
|
|
2389
|
+
|
|
2408
2390
|
class IconMirror(_GraphicsMirror):
|
|
2409
2391
|
"""
|
|
2410
2392
|
Mirror of gui.py's Icon. Backed by a QGraphicsPixmapItem.
|
|
@@ -2474,16 +2456,25 @@ class IconMirror(_GraphicsMirror):
|
|
|
2474
2456
|
'getPixels': self._getPixels,
|
|
2475
2457
|
'setPixels': self._setPixels,
|
|
2476
2458
|
'write': self._write,
|
|
2459
|
+
'setAlpha': self._setAlpha,
|
|
2477
2460
|
})
|
|
2478
2461
|
|
|
2479
2462
|
def _applyColor(self):
|
|
2480
|
-
|
|
2481
|
-
|
|
2463
|
+
r, g, b, a = self._color
|
|
2464
|
+
if [r, g, b, a] == [0, 0, 0, 0]:
|
|
2465
|
+
self.qObject._colorFilter = None
|
|
2466
|
+
else:
|
|
2467
|
+
self.qObject._colorFilter = (r, g, b, a)
|
|
2468
|
+
self.qObject.update()
|
|
2482
2469
|
|
|
2483
2470
|
def _applyThickness(self):
|
|
2484
2471
|
"""No-op — QGraphicsPixmapItem has no pen or brush."""
|
|
2485
2472
|
pass
|
|
2486
2473
|
|
|
2474
|
+
def _setAlpha(self, args, responseId):
|
|
2475
|
+
alpha = args.get('alpha', 255)
|
|
2476
|
+
self.qObject.setOpacity(alpha / 255.0)
|
|
2477
|
+
|
|
2487
2478
|
# ── Size ───────────────────────────────────────────────────────────────────
|
|
2488
2479
|
|
|
2489
2480
|
def _getSize(self, args, responseId):
|
|
@@ -2881,9 +2872,6 @@ class GroupMirror(_DrawableMirror):
|
|
|
2881
2872
|
item.qObject.setZValue(qZValue)
|
|
2882
2873
|
self.qObject.addToGroup(item.qObject)
|
|
2883
2874
|
|
|
2884
|
-
cacheMode = QtWidgets.QGraphicsItem.CacheMode.DeviceCoordinateCache
|
|
2885
|
-
item.qObject.setCacheMode(cacheMode)
|
|
2886
|
-
|
|
2887
2875
|
def _removeChild(self, args, responseId):
|
|
2888
2876
|
"""Removes a child from the group."""
|
|
2889
2877
|
itemId = args.get('itemId')
|
|
@@ -2922,8 +2910,7 @@ class _ControlMirror(_DrawableMirror):
|
|
|
2922
2910
|
- dimensions: setRect(), setPath(), etc. -> setFixedSize()
|
|
2923
2911
|
- color: [r, g, b] -> stylesheets
|
|
2924
2912
|
|
|
2925
|
-
Controls
|
|
2926
|
-
handle their own input directly.
|
|
2913
|
+
Controls handle their own input directly via Qt's widget event system.
|
|
2927
2914
|
|
|
2928
2915
|
Concrete classes must:
|
|
2929
2916
|
1. Call super().__init__(objectId, guiRenderer, args) first.
|
|
@@ -2964,48 +2951,6 @@ class _ControlMirror(_DrawableMirror):
|
|
|
2964
2951
|
def _setRotation(self, args, responseId):
|
|
2965
2952
|
pass # Controls cannot be rotated; gui.py warns at the call site
|
|
2966
2953
|
|
|
2967
|
-
# ── Hit testing ────────────────────────────────────────────────────────────
|
|
2968
|
-
|
|
2969
|
-
def _contains(self, args, responseId):
|
|
2970
|
-
"""Returns True if the point (x, y) is inside this widget's bounding box."""
|
|
2971
|
-
x = args.get('x', 0)
|
|
2972
|
-
y = args.get('y', 0)
|
|
2973
|
-
rect = QtCore.QRectF(self.qObject.geometry())
|
|
2974
|
-
result = rect.contains(QtCore.QPointF(x, y))
|
|
2975
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
2976
|
-
|
|
2977
|
-
def _intersects(self, args, responseId):
|
|
2978
|
-
"""Returns True if this widget's bounding box intersects another item."""
|
|
2979
|
-
otherObjectId = args.get('otherObjectId')
|
|
2980
|
-
otherMirror = self.guiRenderer._objectRegistry.get(otherObjectId)
|
|
2981
|
-
result = False
|
|
2982
|
-
|
|
2983
|
-
if otherMirror is not None:
|
|
2984
|
-
rectA = QtCore.QRectF(self.qObject.geometry())
|
|
2985
|
-
if isinstance(otherMirror, _ControlMirror):
|
|
2986
|
-
rectB = QtCore.QRectF(otherMirror.qObject.geometry())
|
|
2987
|
-
else:
|
|
2988
|
-
rectB = otherMirror.qObject.sceneBoundingRect()
|
|
2989
|
-
result = rectA.intersects(rectB)
|
|
2990
|
-
|
|
2991
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
2992
|
-
|
|
2993
|
-
def _encloses(self, args, responseId):
|
|
2994
|
-
"""Returns True if this widget's bounding box fully encloses another item."""
|
|
2995
|
-
otherObjectId = args.get('otherObjectId')
|
|
2996
|
-
otherMirror = self.guiRenderer._objectRegistry.get(otherObjectId)
|
|
2997
|
-
result = False
|
|
2998
|
-
|
|
2999
|
-
if otherMirror is not None:
|
|
3000
|
-
rectA = QtCore.QRectF(self.qObject.geometry())
|
|
3001
|
-
if isinstance(otherMirror, _ControlMirror):
|
|
3002
|
-
rectB = QtCore.QRectF(otherMirror.qObject.geometry())
|
|
3003
|
-
else:
|
|
3004
|
-
rectB = otherMirror.qObject.sceneBoundingRect()
|
|
3005
|
-
result = rectA.contains(rectB)
|
|
3006
|
-
|
|
3007
|
-
self.guiRenderer.sendResponse(responseId, [result])
|
|
3008
|
-
|
|
3009
2954
|
# ── Size ───────────────────────────────────────────────────────────────────
|
|
3010
2955
|
|
|
3011
2956
|
def _getSize(self, args, responseId):
|
|
@@ -306,9 +306,9 @@ class _RealtimeAudioPlayer:
|
|
|
306
306
|
self.loopRegionStartFrame = max(0.0, float(loopRegionStartFrame))
|
|
307
307
|
self.loopRegionEndFrame = float(loopRegionEndFrame) if loopRegionEndFrame is not None else -1.0
|
|
308
308
|
|
|
309
|
-
# adjust the loop region end frame so it does not exceed the
|
|
309
|
+
# adjust the loop region end frame so it does not exceed the end of the audio file
|
|
310
310
|
if self.loopRegionEndFrame > 0:
|
|
311
|
-
self.loopRegionEndFrame = min(self.loopRegionEndFrame, self.numFrames
|
|
311
|
+
self.loopRegionEndFrame = min(self.loopRegionEndFrame, float(self.numFrames))
|
|
312
312
|
|
|
313
313
|
# ensure the loop region is valid: if the start frame is after or equal to the end frame, reset to default (full file)
|
|
314
314
|
if self.numFrames > 0 and self.loopRegionEndFrame > 0 and self.loopRegionStartFrame >= self.loopRegionEndFrame:
|
|
@@ -689,7 +689,8 @@ class _RealtimeAudioPlayer:
|
|
|
689
689
|
|
|
690
690
|
# determine where playback should end for this segment
|
|
691
691
|
# NOTE: supports three modes: natural EOF, loop region end, or play(size) duration
|
|
692
|
-
effectiveSegmentEndFrame
|
|
692
|
+
# effectiveSegmentEndFrame is the exclusive end (first frame NOT to play)
|
|
693
|
+
effectiveSegmentEndFrame = float(numAudioFrames)
|
|
693
694
|
if looping and self.loopRegionEndFrame > 0:
|
|
694
695
|
effectiveSegmentEndFrame = self.loopRegionEndFrame
|
|
695
696
|
elif not looping and self.targetEndSourceFrame > 0:
|
|
@@ -699,14 +700,13 @@ class _RealtimeAudioPlayer:
|
|
|
699
700
|
# NOTE: batch boundary detection avoids per-sample checks (major optimization)
|
|
700
701
|
framesToProcess = frames
|
|
701
702
|
willHitBoundary = False
|
|
702
|
-
boundaryFrame = -1
|
|
703
703
|
|
|
704
704
|
if effectiveSegmentEndFrame > 0:
|
|
705
705
|
framesToEndpoint = (effectiveSegmentEndFrame - self.playbackPosition) / rateFactor
|
|
706
|
-
if framesToEndpoint < frames
|
|
706
|
+
if 0 <= framesToEndpoint < frames:
|
|
707
707
|
willHitBoundary = True
|
|
708
|
-
|
|
709
|
-
framesToProcess = min(frames,
|
|
708
|
+
# ceil gives the number of frames that stay strictly within the endpoint
|
|
709
|
+
framesToProcess = min(frames, int(np.ceil(framesToEndpoint)))
|
|
710
710
|
|
|
711
711
|
###########################################################################
|
|
712
712
|
# PHASE 2: PITCH SHIFTING VIA TIME-STRETCH INTERPOLATION
|
|
@@ -856,7 +856,8 @@ class _RealtimeAudioPlayer:
|
|
|
856
856
|
outdata[framesToProcess:, :] = 0.0
|
|
857
857
|
|
|
858
858
|
# safety - fill any unfilled portion with silence
|
|
859
|
-
|
|
859
|
+
# skip when willHitBoundary is True: boundary handling already filled remainder (via recursion or explicit zero-fill)
|
|
860
|
+
if framesToProcess < frames and self.isPlaying and not willHitBoundary:
|
|
860
861
|
outdata[framesToProcess:, :] = 0.0
|
|
861
862
|
|
|
862
863
|
# update pan smoothing (prevents clicks from abrupt pan changes)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CreativePython
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2
|
|
4
4
|
Summary: A Python-based software environment for developing algorithmic art projects.
|
|
5
5
|
Author-email: "Dr. Bill Manaris" <manaris@cofc.edu>, Taj Ballinger <ballingertj@g.cofc.edu>, Trevor Ritchie <ritchiets@g.cofc.edu>
|
|
6
6
|
License: MIT License
|
|
@@ -3,6 +3,7 @@ LICENSE-PSF
|
|
|
3
3
|
MANIFEST.in
|
|
4
4
|
README.md
|
|
5
5
|
pyproject.toml
|
|
6
|
+
src/animation.py
|
|
6
7
|
src/gui.py
|
|
7
8
|
src/iannix.py
|
|
8
9
|
src/image.py
|
|
@@ -93,6 +94,8 @@ tests/testGameboard.py
|
|
|
93
94
|
tests/testHitTesting.py
|
|
94
95
|
tests/testPeer.py
|
|
95
96
|
tests/testToolTips.py
|
|
97
|
+
tests/test_crescendo.py
|
|
98
|
+
tests/test_crescendo_import.py
|
|
96
99
|
tests/test_keyEvent.py
|
|
97
100
|
tests/test_midi.py
|
|
98
101
|
tests/test_osc.py
|