CreativePython 0.3.3__tar.gz → 0.3.5__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-0.3.3/src/CreativePython.egg-info → creativepython-0.3.5}/PKG-INFO +1 -1
- {creativepython-0.3.3 → creativepython-0.3.5}/pyproject.toml +1 -1
- {creativepython-0.3.3 → creativepython-0.3.5/src/CreativePython.egg-info}/PKG-INFO +1 -1
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython.egg-info/SOURCES.txt +2 -2
- {creativepython-0.3.3 → creativepython-0.3.5}/src/gui.py +82 -2
- {creativepython-0.3.3 → creativepython-0.3.5}/src/midi.py +10 -4
- {creativepython-0.3.3 → creativepython-0.3.5}/src/music.py +94 -31
- creativepython-0.3.5/tests/testAnimate.py +11 -0
- creativepython-0.3.5/tests/testPeer.py +9 -0
- creativepython-0.3.3/src/CreativePython/examples/.DS_Store +0 -0
- creativepython-0.3.3/src/CreativePython/resources/.DS_Store +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/LICENSE +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/LICENSE-PSF +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/MANIFEST.in +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/README.md +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/setup.cfg +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/__init__.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/ArvoPart.CantusInMemoriam.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/ConcretPH_Xenakis.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/DeepPurple.SmokeOnTheWater.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/JS_Bach.Canon.TriasHarmonica.BWV1072.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/JS_Bach.Canon_1.GoldbergGround.BWV1087.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/Mozart.MusikalischesWurfelspiel.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/PierreCage.StructuresPourDeuxChances.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/RGB_Display.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/TerryRiley.InC.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/arpeggiator1.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/arpeggiator2.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/autumnLeaves.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/axelF.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/biosignals.txt +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/boids.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/brownianMelody.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/changesByTupac.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/clementine.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/continuousPitchInstrumentAudio.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/drumExample.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/drumMachinePattern1.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/drumsComeAlive.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/fibonacci.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/findPitchOctave.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/furElise.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/generativeMusic.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/goldenTree.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/guidoWordMusic.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundi.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundiRevisisted.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonographLateral.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonographRotary.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoBlackDown.png +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoOctave.png +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoParallel.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoSimple.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteCenterDown.png +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteLeftDown.png +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteRightDown.png +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiIn1.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiIn2.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiIn3.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiOut.a.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiOut.b.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer2.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/moondog-bird_slament.wav +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/musicalSphere.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/note.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/octoplus.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/oscIn1.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/oscIn2.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/pentatonicMelody.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/pianoPhase.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/pianoRollGenerator.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/playNote.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/proteinMusic.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/randomCircles.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/randomCirclesThroughMidiInput.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/randomCirclesTimed.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.a.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.b.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.c.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/rowYourBoat.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/scaleTutor.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sierpinskiTriangle.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/simpleButtonInstrument.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/simpleCircleInstrument.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sineMelody.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sineMelodyPlus.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sliderControl.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sonifyBiosignals.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sonifyImage.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/soundscapeLoutrakiSunset.jpg +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/stringQuartet.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/textMusic.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/theWayItIs.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/themeAndVariations.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/throwingDice.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/windChimes.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/zipfMetrics.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/resources/550973__luizguilherme_a__clean-guitarr-riff.mp3 +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/resources/chopper.jpg +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/resources/de-brazzas-monkey.jpg +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython.egg-info/dependency_links.txt +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython.egg-info/requires.txt +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython.egg-info/top_level.txt +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/_RealtimeAudioPlayer.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/_notationRenderer.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/bin/libportaudio.2.dylib +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/iannix.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/image.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/markov.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/osc.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/timer.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/src/zipf.py +0 -0
- {creativepython-0.3.3 → creativepython-0.3.5}/tests/test_keyEvent.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CreativePython
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
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 = "0.3.
|
|
7
|
+
version = "0.3.5"
|
|
8
8
|
description = "A Python-based software environment for developing algorithmic art projects."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CreativePython
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
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
|
|
@@ -20,7 +20,6 @@ src/CreativePython.egg-info/SOURCES.txt
|
|
|
20
20
|
src/CreativePython.egg-info/dependency_links.txt
|
|
21
21
|
src/CreativePython.egg-info/requires.txt
|
|
22
22
|
src/CreativePython.egg-info/top_level.txt
|
|
23
|
-
src/CreativePython/examples/.DS_Store
|
|
24
23
|
src/CreativePython/examples/ArvoPart.CantusInMemoriam.py
|
|
25
24
|
src/CreativePython/examples/ConcretPH_Xenakis.py
|
|
26
25
|
src/CreativePython/examples/DeepPurple.SmokeOnTheWater.py
|
|
@@ -102,9 +101,10 @@ src/CreativePython/examples/themeAndVariations.py
|
|
|
102
101
|
src/CreativePython/examples/throwingDice.py
|
|
103
102
|
src/CreativePython/examples/windChimes.py
|
|
104
103
|
src/CreativePython/examples/zipfMetrics.py
|
|
105
|
-
src/CreativePython/resources/.DS_Store
|
|
106
104
|
src/CreativePython/resources/550973__luizguilherme_a__clean-guitarr-riff.mp3
|
|
107
105
|
src/CreativePython/resources/chopper.jpg
|
|
108
106
|
src/CreativePython/resources/de-brazzas-monkey.jpg
|
|
109
107
|
src/bin/libportaudio.2.dylib
|
|
108
|
+
tests/testAnimate.py
|
|
109
|
+
tests/testPeer.py
|
|
110
110
|
tests/test_keyEvent.py
|
|
@@ -1242,13 +1242,13 @@ class Display(Interactable):
|
|
|
1242
1242
|
"""
|
|
1243
1243
|
Returns the display's canvas width (in pixels).
|
|
1244
1244
|
"""
|
|
1245
|
-
return self._scene.width()
|
|
1245
|
+
return int(self._scene.width())
|
|
1246
1246
|
|
|
1247
1247
|
def getHeight(self):
|
|
1248
1248
|
"""
|
|
1249
1249
|
Returns the display's canvas height (in pixels).
|
|
1250
1250
|
"""
|
|
1251
|
-
return self._scene.height()
|
|
1251
|
+
return int(self._scene.height())
|
|
1252
1252
|
|
|
1253
1253
|
def setSize(self, width, height):
|
|
1254
1254
|
"""
|
|
@@ -4212,6 +4212,86 @@ class Menu():
|
|
|
4212
4212
|
self._qObject.setEnabled(False)
|
|
4213
4213
|
|
|
4214
4214
|
|
|
4215
|
+
#######################################################################################
|
|
4216
|
+
# Animation Engine
|
|
4217
|
+
#######################################################################################
|
|
4218
|
+
# animate() - this is a function to register functions that should be called repeatedly.
|
|
4219
|
+
# Registered functions should expect zero parameters. Also provided is setAnimationRate().
|
|
4220
|
+
# The idea is to provide a simple way to animate things (be it visual, or other).
|
|
4221
|
+
# This is basic functionality, inspired by MIT Processing's draw() function.
|
|
4222
|
+
# Anything more involved can be easily created using a Timer.
|
|
4223
|
+
|
|
4224
|
+
from timer import Timer2
|
|
4225
|
+
|
|
4226
|
+
animationRate = 60 # 60 times per second
|
|
4227
|
+
animationInterval = 1000 / animationRate # convert to milliseconds
|
|
4228
|
+
|
|
4229
|
+
if "_ANIMATIONFUNCTIONS_" not in globals():
|
|
4230
|
+
_ANIMATIONFUNCTIONS_ = [] # claim global variable for animation functions
|
|
4231
|
+
|
|
4232
|
+
def callAnimationFunctions():
|
|
4233
|
+
"""When timer goes off, we call this function, which calls all functions added to the animation list."""
|
|
4234
|
+
global _ANIMATIONFUNCTIONS_
|
|
4235
|
+
|
|
4236
|
+
# call every function in animationFunctions list
|
|
4237
|
+
for function in _ANIMATIONFUNCTIONS_:
|
|
4238
|
+
function()
|
|
4239
|
+
|
|
4240
|
+
# animation engine is just a timer
|
|
4241
|
+
animationEngine = Timer2(
|
|
4242
|
+
timeInterval=animationInterval,
|
|
4243
|
+
function=callAnimationFunctions,
|
|
4244
|
+
parameters=[],
|
|
4245
|
+
repeat=True
|
|
4246
|
+
)
|
|
4247
|
+
|
|
4248
|
+
animationEngine.start() # start it
|
|
4249
|
+
|
|
4250
|
+
|
|
4251
|
+
def animate(function):
|
|
4252
|
+
"""Adds a function to be called repeatedly by the animation engine."""
|
|
4253
|
+
global animationEngine
|
|
4254
|
+
|
|
4255
|
+
if callable(function):
|
|
4256
|
+
_ANIMATIONFUNCTIONS_.append(function) # add function to list of functions to call
|
|
4257
|
+
else:
|
|
4258
|
+
print(f"animate(): function '{function}' is not callable.")
|
|
4259
|
+
|
|
4260
|
+
|
|
4261
|
+
def setAnimationRate(frameRate=60):
|
|
4262
|
+
"""Set animation frame rate (frames per second)."""
|
|
4263
|
+
global animationEngine
|
|
4264
|
+
|
|
4265
|
+
animationInterval = 1000 / frameRate # convert to milliseconds
|
|
4266
|
+
animationEngine.setDelay(animationInterval) # and set it
|
|
4267
|
+
|
|
4268
|
+
|
|
4269
|
+
def getAnimationRate():
|
|
4270
|
+
"""Returns animation frame rate (frames per second)."""
|
|
4271
|
+
global animationEngine
|
|
4272
|
+
|
|
4273
|
+
animationInterval = animationEngine.getDelay() # get delay in milliseconds
|
|
4274
|
+
animationRate = 1000 / animationInterval # convert to times per second (rate)
|
|
4275
|
+
return animationRate
|
|
4276
|
+
|
|
4277
|
+
|
|
4278
|
+
def __stopAnimationEngine__():
|
|
4279
|
+
"""Function to stop and clean-up animation engine."""
|
|
4280
|
+
global animationEngine
|
|
4281
|
+
|
|
4282
|
+
animationEngine.stop() # first, stop it
|
|
4283
|
+
del animationEngine # then, delete it
|
|
4284
|
+
|
|
4285
|
+
# # now, register function with JEM (if possible)
|
|
4286
|
+
# try:
|
|
4287
|
+
# # if we are inside JEM, registerStopFunction() will be available
|
|
4288
|
+
# registerStopFunction(__stopAnimationEngine__) # tell JEM which function to call when the Stop button is pressed
|
|
4289
|
+
|
|
4290
|
+
# except: # otherwise (if we get an error), we are NOT inside JEM
|
|
4291
|
+
# pass # so, do nothing.
|
|
4292
|
+
|
|
4293
|
+
|
|
4294
|
+
|
|
4215
4295
|
#######################################################################################
|
|
4216
4296
|
# Test
|
|
4217
4297
|
#######################################################################################
|
|
@@ -639,11 +639,17 @@ class MidiOut:
|
|
|
639
639
|
noteID = (pitch, channel) # create an ID using pitch-channel pair
|
|
640
640
|
|
|
641
641
|
# next, remove this noteID from the list, so that we may check for remaining instances
|
|
642
|
-
|
|
643
|
-
if noteID
|
|
642
|
+
# check if this note is playing
|
|
643
|
+
if noteID in notesCurrentlyPlaying:
|
|
644
|
+
notesCurrentlyPlaying.remove(noteID) # remove noteID
|
|
644
645
|
|
|
645
|
-
#
|
|
646
|
-
|
|
646
|
+
# only send note off if this was the last instance
|
|
647
|
+
if noteID not in notesCurrentlyPlaying: # is this last instance of note?
|
|
648
|
+
# yes, so turn it off!
|
|
649
|
+
self.sendMidiMessage(NOTE_OFF, channel, pitch, 0)
|
|
650
|
+
else:
|
|
651
|
+
# attempting to turn off a note that is not currently playing
|
|
652
|
+
print(f"MidiOut.frequencyOff(): Attempting to turn off frequency {frequency} Hz (pitch {pitch}) on channel {channel}, which is not currently playing.")
|
|
647
653
|
else:
|
|
648
654
|
# frequency was outside expected range
|
|
649
655
|
print(f"MidiOut.frequencyOff(): Invalid frequency {frequency}, expected frequency in Hz from 8.17 to 12600.0 (float).")
|
|
@@ -125,7 +125,7 @@ MIDI_PITCHES = ["C_1", "CS_1", "D_1", "DS_1", "E_1", "F_1", "FS_1", "G_1", "GS_1
|
|
|
125
125
|
#######################################################################################
|
|
126
126
|
# MIDI rhythm/duration constants
|
|
127
127
|
|
|
128
|
-
DWN = DOTTED_WHOLE_NOTE =
|
|
128
|
+
DWN = DOTTED_WHOLE_NOTE = 6.0
|
|
129
129
|
WN = WHOLE_NOTE = 4.0
|
|
130
130
|
DHN = DOTTED_HALF_NOTE = 3.0
|
|
131
131
|
DDHN = DOUBLE_DOTTED_HALF_NOTE = 3.5
|
|
@@ -536,9 +536,12 @@ def mapScale(value, minValue, maxValue, minResultValue, maxResultValue, scale=CH
|
|
|
536
536
|
so pitchRow must contain offsets (from the root) between 0 and 11.
|
|
537
537
|
"""
|
|
538
538
|
# check if value is within the specified range
|
|
539
|
-
if value < minValue or value > maxValue:
|
|
540
|
-
|
|
541
|
-
|
|
539
|
+
# if value < minValue or value > maxValue:
|
|
540
|
+
# raise ValueError("value, " + str(value) + ", is outside the specified range, " \
|
|
541
|
+
# + str(minValue) + " to " + str(maxValue) + ".")
|
|
542
|
+
|
|
543
|
+
# clamp value to specified range
|
|
544
|
+
value = min(maxValue, max(value, minValue))
|
|
542
545
|
|
|
543
546
|
# check pitch row - it should contain offsets only from 0 to 11
|
|
544
547
|
badOffsets = [offset for offset in scale if offset < 0 or offset > 11]
|
|
@@ -1917,7 +1920,7 @@ class Play:
|
|
|
1917
1920
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
1918
1921
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
1919
1922
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
1920
|
-
duration = int(note.getLength() * FACTOR)
|
|
1923
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
1921
1924
|
startTime = startTime + note.getDuration() * FACTOR # update start time (in milliseconds)
|
|
1922
1925
|
velocity = note.getDynamic()
|
|
1923
1926
|
|
|
@@ -2341,7 +2344,7 @@ class Play:
|
|
|
2341
2344
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
2342
2345
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
2343
2346
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
2344
|
-
duration = int(note.getLength() * FACTOR)
|
|
2347
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
2345
2348
|
velocity = note.getDynamic()
|
|
2346
2349
|
|
|
2347
2350
|
# accumulate non-REST notes
|
|
@@ -2572,7 +2575,7 @@ class Play:
|
|
|
2572
2575
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
2573
2576
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
2574
2577
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
2575
|
-
duration = int(note.getLength() * FACTOR)
|
|
2578
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
2576
2579
|
velocity = note.getDynamic()
|
|
2577
2580
|
|
|
2578
2581
|
# accumulate non-REST notes
|
|
@@ -5399,11 +5402,12 @@ class Read:
|
|
|
5399
5402
|
# part.setTitle(f"Track {trackIndex}") # Optional: name part by track index or name
|
|
5400
5403
|
|
|
5401
5404
|
phrasesForPart = []
|
|
5402
|
-
# stores the logical end time
|
|
5403
|
-
|
|
5405
|
+
# stores the logical end time for each phrase in phrasesForPart
|
|
5406
|
+
phraseCurrentLogicalEndTime = []
|
|
5404
5407
|
|
|
5405
5408
|
activeNotesOnTrack = {} # key=(channel, pitch), value=list of (startTime_ticks, velocity)
|
|
5406
5409
|
absoluteTimeTicksTrack = 0 # cumulative time in ticks for the current track
|
|
5410
|
+
currentPanValue = 0.5 # track current pan (default = center, 0.0-1.0)
|
|
5407
5411
|
|
|
5408
5412
|
for msg in track:
|
|
5409
5413
|
absoluteTimeTicksTrack += msg.time
|
|
@@ -5420,14 +5424,40 @@ class Read:
|
|
|
5420
5424
|
score.setTimeSignature(msg.numerator, msg.denominator)
|
|
5421
5425
|
|
|
5422
5426
|
elif msg.type == 'key_signature':
|
|
5423
|
-
#
|
|
5424
|
-
#
|
|
5425
|
-
#
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5427
|
+
# Map mido key strings to (keySignature, keyQuality)
|
|
5428
|
+
# keySignature: num sharps (positive) or flats (negative)
|
|
5429
|
+
# keyQuality: 0 = Major, 1 = Minor
|
|
5430
|
+
midoKeySignatureMap = {
|
|
5431
|
+
'C': (0, 0), 'Am': (0, 1),
|
|
5432
|
+
'G': (1, 0), 'Em': (1, 1),
|
|
5433
|
+
'D': (2, 0), 'Bm': (2, 1),
|
|
5434
|
+
'A': (3, 0), 'F#m': (3, 1),
|
|
5435
|
+
'E': (4, 0), 'C#m': (4, 1),
|
|
5436
|
+
'B': (5, 0), 'G#m': (5, 1),
|
|
5437
|
+
'F#': (6, 0), 'D#m': (6, 1),
|
|
5438
|
+
'C#': (7, 0), 'A#m': (7, 1),
|
|
5439
|
+
'F': (-1, 0), 'Dm': (-1, 1),
|
|
5440
|
+
'Bb': (-2, 0), 'Gm': (-2, 1),
|
|
5441
|
+
'Eb': (-3, 0), 'Cm': (-3, 1),
|
|
5442
|
+
'Ab': (-4, 0), 'Fm': (-4, 1),
|
|
5443
|
+
'Db': (-5, 0), 'Bbm': (-5, 1),
|
|
5444
|
+
'Gb': (-6, 0), 'Ebm': (-6, 1),
|
|
5445
|
+
'Cb': (-7, 0), 'Abm': (-7, 1)
|
|
5446
|
+
}
|
|
5447
|
+
|
|
5448
|
+
if msg.key in midoKeySignatureMap:
|
|
5449
|
+
signature, quality = midoKeySignatureMap[msg.key]
|
|
5450
|
+
score.setKeySignature(signature)
|
|
5451
|
+
score.setKeyQuality(quality)
|
|
5452
|
+
|
|
5453
|
+
elif msg.type == 'control_change':
|
|
5454
|
+
if msg.is_cc(7): # volume controller
|
|
5455
|
+
part.setVolume(msg.value) # 0-127, no conversion needed
|
|
5456
|
+
elif msg.is_cc(10): # pan controller
|
|
5457
|
+
currentPanValue = msg.value / 127.0 # MIDI 0-127 -> float 0.0-1.0
|
|
5429
5458
|
|
|
5430
5459
|
elif msg.type == 'note_on' and msg.velocity > 0: # note on
|
|
5460
|
+
part.setChannel(msg.channel)
|
|
5431
5461
|
key = (msg.channel, msg.note)
|
|
5432
5462
|
if key not in activeNotesOnTrack:
|
|
5433
5463
|
activeNotesOnTrack[key] = []
|
|
@@ -5440,47 +5470,51 @@ class Read:
|
|
|
5440
5470
|
if not activeNotesOnTrack[key]: # clean up if list is empty
|
|
5441
5471
|
del activeNotesOnTrack[key]
|
|
5442
5472
|
|
|
5443
|
-
|
|
5444
|
-
|
|
5473
|
+
noteStartTime = startTimeTicks / midiFile.ticks_per_beat
|
|
5474
|
+
noteEndTime = absoluteTimeTicksTrack / midiFile.ticks_per_beat
|
|
5445
5475
|
|
|
5446
|
-
if
|
|
5476
|
+
if noteEndTime <= noteStartTime:
|
|
5447
5477
|
continue
|
|
5448
5478
|
|
|
5449
|
-
|
|
5479
|
+
duration = noteEndTime - noteStartTime
|
|
5450
5480
|
|
|
5451
5481
|
targetPhraseIndex = -1
|
|
5452
5482
|
for phraseIdx in range(len(phrasesForPart)):
|
|
5453
5483
|
# A phrase is suitable if this note starts at or after the phrase's current logical end time
|
|
5454
5484
|
# (with a small tolerance for notes that might slightly precede the 'official' end due to rounding)
|
|
5455
5485
|
# jMusic uses a 0.08 beat tolerance.
|
|
5456
|
-
if
|
|
5486
|
+
if phraseCurrentLogicalEndTime[phraseIdx] <= noteStartTime + 0.08:
|
|
5457
5487
|
targetPhraseIndex = phraseIdx
|
|
5458
5488
|
break
|
|
5459
5489
|
|
|
5460
5490
|
# create new phrase if no suitable existing phrase found
|
|
5461
5491
|
if targetPhraseIndex == -1:
|
|
5462
5492
|
newPhrase = Phrase()
|
|
5463
|
-
newPhrase.setStartTime(
|
|
5493
|
+
newPhrase.setStartTime(noteStartTime)
|
|
5464
5494
|
phrasesForPart.append(newPhrase)
|
|
5465
|
-
|
|
5495
|
+
phraseCurrentLogicalEndTime.append(noteStartTime)
|
|
5466
5496
|
targetPhraseIndex = len(phrasesForPart) - 1
|
|
5467
5497
|
|
|
5468
5498
|
# get reference to current phrase and its logical end time
|
|
5469
5499
|
currentSelectedPhrase = phrasesForPart[targetPhraseIndex]
|
|
5470
|
-
currentPhraseLogicalEnd =
|
|
5500
|
+
currentPhraseLogicalEnd = phraseCurrentLogicalEndTime[targetPhraseIndex]
|
|
5471
5501
|
|
|
5472
5502
|
# add rest if there's a gap between current phrase end and note start
|
|
5473
|
-
if
|
|
5474
|
-
restDuration =
|
|
5475
|
-
|
|
5503
|
+
if noteStartTime > currentPhraseLogicalEnd:
|
|
5504
|
+
restDuration = noteStartTime - currentPhraseLogicalEnd
|
|
5505
|
+
|
|
5506
|
+
# add explicit rest for gaps > 0.01 beats (ignore tiny gaps from MIDI timing jitter)
|
|
5507
|
+
if restDuration > 0.01:
|
|
5476
5508
|
restNote = Note(REST, restDuration)
|
|
5477
5509
|
currentSelectedPhrase.addNote(restNote)
|
|
5478
|
-
|
|
5510
|
+
phraseCurrentLogicalEndTime[targetPhraseIndex] += restDuration
|
|
5479
5511
|
|
|
5480
5512
|
# add the actual note and update phrase end time
|
|
5481
|
-
|
|
5513
|
+
# NOTE: preserve exact MIDI timing: set length = duration
|
|
5514
|
+
jmusicNote = Note(msg.note, duration, velocity, length=duration)
|
|
5515
|
+
jmusicNote.setPan(currentPanValue) # apply current pan from CC 10
|
|
5482
5516
|
currentSelectedPhrase.addNote(jmusicNote)
|
|
5483
|
-
|
|
5517
|
+
phraseCurrentLogicalEndTime[targetPhraseIndex] = noteEndTime
|
|
5484
5518
|
|
|
5485
5519
|
# End of message loop for track
|
|
5486
5520
|
# Handle any notes still active at the end of the track (e.g., if no note_off)
|
|
@@ -5572,6 +5606,34 @@ class Write:
|
|
|
5572
5606
|
denominator=denominator,
|
|
5573
5607
|
time=0))
|
|
5574
5608
|
|
|
5609
|
+
# add key signature to metadata track
|
|
5610
|
+
# reverse mapping from (keySignature, keyQuality) to mido key strings
|
|
5611
|
+
reverseKeySignatureMap = {
|
|
5612
|
+
(0, 0): 'C', (0, 1): 'Am',
|
|
5613
|
+
(1, 0): 'G', (1, 1): 'Em',
|
|
5614
|
+
(2, 0): 'D', (2, 1): 'Bm',
|
|
5615
|
+
(3, 0): 'A', (3, 1): 'F#m',
|
|
5616
|
+
(4, 0): 'E', (4, 1): 'C#m',
|
|
5617
|
+
(5, 0): 'B', (5, 1): 'G#m',
|
|
5618
|
+
(6, 0): 'F#', (6, 1): 'D#m',
|
|
5619
|
+
(7, 0): 'C#', (7, 1): 'A#m',
|
|
5620
|
+
(-1, 0): 'F', (-1, 1): 'Dm',
|
|
5621
|
+
(-2, 0): 'Bb', (-2, 1): 'Gm',
|
|
5622
|
+
(-3, 0): 'Eb', (-3, 1): 'Cm',
|
|
5623
|
+
(-4, 0): 'Ab', (-4, 1): 'Fm',
|
|
5624
|
+
(-5, 0): 'Db', (-5, 1): 'Bbm',
|
|
5625
|
+
(-6, 0): 'Gb', (-6, 1): 'Ebm',
|
|
5626
|
+
(-7, 0): 'Cb', (-7, 1): 'Abm'
|
|
5627
|
+
}
|
|
5628
|
+
|
|
5629
|
+
keySignature = score.getKeySignature() # -7 to 7
|
|
5630
|
+
keyQuality = score.getKeyQuality() # 0=Major, 1=Minor
|
|
5631
|
+
keyTuple = (keySignature, keyQuality)
|
|
5632
|
+
|
|
5633
|
+
if keyTuple in reverseKeySignatureMap:
|
|
5634
|
+
midoKeyString = reverseKeySignatureMap[keyTuple]
|
|
5635
|
+
metaTrack.append(mido.MetaMessage('key_signature', key=midoKeyString, time=0))
|
|
5636
|
+
|
|
5575
5637
|
# end of metadata track
|
|
5576
5638
|
metaTrack.append(mido.MetaMessage('end_of_track', time=0))
|
|
5577
5639
|
|
|
@@ -5660,7 +5722,8 @@ class Write:
|
|
|
5660
5722
|
noteTicks = phraseStartTicks + int(noteStartTime * 480)
|
|
5661
5723
|
|
|
5662
5724
|
# calculate note duration in ticks
|
|
5663
|
-
|
|
5725
|
+
# NOTE: we use getDuration() to preserve the exact notated timing
|
|
5726
|
+
soundingTicks = int(note.getDuration() * 480)
|
|
5664
5727
|
|
|
5665
5728
|
# get note velocity (dynamic)
|
|
5666
5729
|
velocity = note.getDynamic()
|
|
@@ -5689,7 +5752,7 @@ class Write:
|
|
|
5689
5752
|
|
|
5690
5753
|
# create note_off event
|
|
5691
5754
|
events.append({
|
|
5692
|
-
'tick': noteTicks +
|
|
5755
|
+
'tick': noteTicks + soundingTicks,
|
|
5693
5756
|
'msg': mido.Message('note_off',
|
|
5694
5757
|
note=pitch,
|
|
5695
5758
|
velocity=0,
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/ConcretPH_Xenakis.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/drumMachinePattern1.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/findPitchOctave.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/generativeMusic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundi.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonographLateral.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/harmonographRotary.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoBlackDown.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteCenterDown.png
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteLeftDown.png
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteRightDown.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer2.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/moondog-bird_slament.wav
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/pentatonicMelody.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/pianoRollGenerator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/randomCirclesTimed.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sierpinskiTriangle.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/simpleButtonInstrument.py
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/simpleCircleInstrument.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/sonifyBiosignals.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/examples/themeAndVariations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython/resources/de-brazzas-monkey.jpg
RENAMED
|
File without changes
|
{creativepython-0.3.3 → creativepython-0.3.5}/src/CreativePython.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|