CreativePython 0.3.4__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.4/src/CreativePython.egg-info → creativepython-0.3.5}/PKG-INFO +1 -1
- {creativepython-0.3.4 → creativepython-0.3.5}/pyproject.toml +1 -1
- {creativepython-0.3.4 → creativepython-0.3.5/src/CreativePython.egg-info}/PKG-INFO +1 -1
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython.egg-info/SOURCES.txt +2 -2
- {creativepython-0.3.4 → creativepython-0.3.5}/src/gui.py +80 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/midi.py +10 -4
- {creativepython-0.3.4 → creativepython-0.3.5}/src/music.py +88 -28
- creativepython-0.3.5/tests/testAnimate.py +11 -0
- creativepython-0.3.5/tests/testPeer.py +9 -0
- creativepython-0.3.4/src/CreativePython/examples/.DS_Store +0 -0
- creativepython-0.3.4/src/CreativePython/resources/.DS_Store +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/LICENSE +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/LICENSE-PSF +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/MANIFEST.in +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/README.md +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/setup.cfg +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/__init__.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/ArvoPart.CantusInMemoriam.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/ConcretPH_Xenakis.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/DeepPurple.SmokeOnTheWater.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/JS_Bach.Canon.TriasHarmonica.BWV1072.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/JS_Bach.Canon_1.GoldbergGround.BWV1087.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/Mozart.MusikalischesWurfelspiel.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/PierreCage.StructuresPourDeuxChances.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/RGB_Display.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/TerryRiley.InC.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/arpeggiator1.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/arpeggiator2.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/autumnLeaves.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/axelF.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/biosignals.txt +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/boids.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/brownianMelody.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/changesByTupac.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/clementine.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/continuousPitchInstrumentAudio.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/drumExample.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/drumMachinePattern1.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/drumsComeAlive.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/fibonacci.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/findPitchOctave.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/furElise.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/generativeMusic.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/goldenTree.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/guidoWordMusic.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundi.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundiRevisisted.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonographLateral.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonographRotary.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoBlackDown.png +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoOctave.png +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoParallel.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoSimple.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteCenterDown.png +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteLeftDown.png +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteRightDown.png +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiIn1.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiIn2.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiIn3.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiOut.a.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiOut.b.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer2.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/moondog-bird_slament.wav +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/musicalSphere.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/note.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/octoplus.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/oscIn1.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/oscIn2.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/pentatonicMelody.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/pianoPhase.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/pianoRollGenerator.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/playNote.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/proteinMusic.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/randomCircles.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/randomCirclesThroughMidiInput.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/randomCirclesTimed.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.a.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.b.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/retrograde.c.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/rowYourBoat.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/scaleTutor.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sierpinskiTriangle.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/simpleButtonInstrument.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/simpleCircleInstrument.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sineMelody.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sineMelodyPlus.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sliderControl.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sonifyBiosignals.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/sonifyImage.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/soundscapeLoutrakiSunset.jpg +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/stringQuartet.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/textMusic.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/theWayItIs.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/themeAndVariations.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/throwingDice.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/windChimes.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/zipfMetrics.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/resources/550973__luizguilherme_a__clean-guitarr-riff.mp3 +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/resources/chopper.jpg +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/resources/de-brazzas-monkey.jpg +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython.egg-info/dependency_links.txt +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython.egg-info/requires.txt +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython.egg-info/top_level.txt +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/_RealtimeAudioPlayer.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/_notationRenderer.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/bin/libportaudio.2.dylib +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/iannix.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/image.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/markov.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/osc.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/timer.py +0 -0
- {creativepython-0.3.4 → creativepython-0.3.5}/src/zipf.py +0 -0
- {creativepython-0.3.4 → 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
|
|
@@ -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
|
|
@@ -1920,7 +1920,7 @@ class Play:
|
|
|
1920
1920
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
1921
1921
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
1922
1922
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
1923
|
-
duration = int(note.getLength() * FACTOR)
|
|
1923
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
1924
1924
|
startTime = startTime + note.getDuration() * FACTOR # update start time (in milliseconds)
|
|
1925
1925
|
velocity = note.getDynamic()
|
|
1926
1926
|
|
|
@@ -2344,7 +2344,7 @@ class Play:
|
|
|
2344
2344
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
2345
2345
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
2346
2346
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
2347
|
-
duration = int(note.getLength() * FACTOR)
|
|
2347
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
2348
2348
|
velocity = note.getDynamic()
|
|
2349
2349
|
|
|
2350
2350
|
# accumulate non-REST notes
|
|
@@ -2575,7 +2575,7 @@ class Play:
|
|
|
2575
2575
|
# NOTE: Below we use note length as opposed to duration (getLength() vs. getDuration())
|
|
2576
2576
|
# since note length gives us a more natural sounding note (with proper decay), whereas
|
|
2577
2577
|
# note duration captures the more formal (printed score) duration (which sounds unnatural).
|
|
2578
|
-
duration = int(note.getLength() * FACTOR)
|
|
2578
|
+
duration = int(note.getLength() * FACTOR) # convert to milliseconds
|
|
2579
2579
|
velocity = note.getDynamic()
|
|
2580
2580
|
|
|
2581
2581
|
# accumulate non-REST notes
|
|
@@ -5402,11 +5402,12 @@ class Read:
|
|
|
5402
5402
|
# part.setTitle(f"Track {trackIndex}") # Optional: name part by track index or name
|
|
5403
5403
|
|
|
5404
5404
|
phrasesForPart = []
|
|
5405
|
-
# stores the logical end time
|
|
5406
|
-
|
|
5405
|
+
# stores the logical end time for each phrase in phrasesForPart
|
|
5406
|
+
phraseCurrentLogicalEndTime = []
|
|
5407
5407
|
|
|
5408
5408
|
activeNotesOnTrack = {} # key=(channel, pitch), value=list of (startTime_ticks, velocity)
|
|
5409
5409
|
absoluteTimeTicksTrack = 0 # cumulative time in ticks for the current track
|
|
5410
|
+
currentPanValue = 0.5 # track current pan (default = center, 0.0-1.0)
|
|
5410
5411
|
|
|
5411
5412
|
for msg in track:
|
|
5412
5413
|
absoluteTimeTicksTrack += msg.time
|
|
@@ -5423,14 +5424,40 @@ class Read:
|
|
|
5423
5424
|
score.setTimeSignature(msg.numerator, msg.denominator)
|
|
5424
5425
|
|
|
5425
5426
|
elif msg.type == 'key_signature':
|
|
5426
|
-
#
|
|
5427
|
-
#
|
|
5428
|
-
#
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
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
|
|
5432
5458
|
|
|
5433
5459
|
elif msg.type == 'note_on' and msg.velocity > 0: # note on
|
|
5460
|
+
part.setChannel(msg.channel)
|
|
5434
5461
|
key = (msg.channel, msg.note)
|
|
5435
5462
|
if key not in activeNotesOnTrack:
|
|
5436
5463
|
activeNotesOnTrack[key] = []
|
|
@@ -5443,47 +5470,51 @@ class Read:
|
|
|
5443
5470
|
if not activeNotesOnTrack[key]: # clean up if list is empty
|
|
5444
5471
|
del activeNotesOnTrack[key]
|
|
5445
5472
|
|
|
5446
|
-
|
|
5447
|
-
|
|
5473
|
+
noteStartTime = startTimeTicks / midiFile.ticks_per_beat
|
|
5474
|
+
noteEndTime = absoluteTimeTicksTrack / midiFile.ticks_per_beat
|
|
5448
5475
|
|
|
5449
|
-
if
|
|
5476
|
+
if noteEndTime <= noteStartTime:
|
|
5450
5477
|
continue
|
|
5451
5478
|
|
|
5452
|
-
|
|
5479
|
+
duration = noteEndTime - noteStartTime
|
|
5453
5480
|
|
|
5454
5481
|
targetPhraseIndex = -1
|
|
5455
5482
|
for phraseIdx in range(len(phrasesForPart)):
|
|
5456
5483
|
# A phrase is suitable if this note starts at or after the phrase's current logical end time
|
|
5457
5484
|
# (with a small tolerance for notes that might slightly precede the 'official' end due to rounding)
|
|
5458
5485
|
# jMusic uses a 0.08 beat tolerance.
|
|
5459
|
-
if
|
|
5486
|
+
if phraseCurrentLogicalEndTime[phraseIdx] <= noteStartTime + 0.08:
|
|
5460
5487
|
targetPhraseIndex = phraseIdx
|
|
5461
5488
|
break
|
|
5462
5489
|
|
|
5463
5490
|
# create new phrase if no suitable existing phrase found
|
|
5464
5491
|
if targetPhraseIndex == -1:
|
|
5465
5492
|
newPhrase = Phrase()
|
|
5466
|
-
newPhrase.setStartTime(
|
|
5493
|
+
newPhrase.setStartTime(noteStartTime)
|
|
5467
5494
|
phrasesForPart.append(newPhrase)
|
|
5468
|
-
|
|
5495
|
+
phraseCurrentLogicalEndTime.append(noteStartTime)
|
|
5469
5496
|
targetPhraseIndex = len(phrasesForPart) - 1
|
|
5470
5497
|
|
|
5471
5498
|
# get reference to current phrase and its logical end time
|
|
5472
5499
|
currentSelectedPhrase = phrasesForPart[targetPhraseIndex]
|
|
5473
|
-
currentPhraseLogicalEnd =
|
|
5500
|
+
currentPhraseLogicalEnd = phraseCurrentLogicalEndTime[targetPhraseIndex]
|
|
5474
5501
|
|
|
5475
5502
|
# add rest if there's a gap between current phrase end and note start
|
|
5476
|
-
if
|
|
5477
|
-
restDuration =
|
|
5478
|
-
|
|
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:
|
|
5479
5508
|
restNote = Note(REST, restDuration)
|
|
5480
5509
|
currentSelectedPhrase.addNote(restNote)
|
|
5481
|
-
|
|
5510
|
+
phraseCurrentLogicalEndTime[targetPhraseIndex] += restDuration
|
|
5482
5511
|
|
|
5483
5512
|
# add the actual note and update phrase end time
|
|
5484
|
-
|
|
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
|
|
5485
5516
|
currentSelectedPhrase.addNote(jmusicNote)
|
|
5486
|
-
|
|
5517
|
+
phraseCurrentLogicalEndTime[targetPhraseIndex] = noteEndTime
|
|
5487
5518
|
|
|
5488
5519
|
# End of message loop for track
|
|
5489
5520
|
# Handle any notes still active at the end of the track (e.g., if no note_off)
|
|
@@ -5575,6 +5606,34 @@ class Write:
|
|
|
5575
5606
|
denominator=denominator,
|
|
5576
5607
|
time=0))
|
|
5577
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
|
+
|
|
5578
5637
|
# end of metadata track
|
|
5579
5638
|
metaTrack.append(mido.MetaMessage('end_of_track', time=0))
|
|
5580
5639
|
|
|
@@ -5663,7 +5722,8 @@ class Write:
|
|
|
5663
5722
|
noteTicks = phraseStartTicks + int(noteStartTime * 480)
|
|
5664
5723
|
|
|
5665
5724
|
# calculate note duration in ticks
|
|
5666
|
-
|
|
5725
|
+
# NOTE: we use getDuration() to preserve the exact notated timing
|
|
5726
|
+
soundingTicks = int(note.getDuration() * 480)
|
|
5667
5727
|
|
|
5668
5728
|
# get note velocity (dynamic)
|
|
5669
5729
|
velocity = note.getDynamic()
|
|
@@ -5692,7 +5752,7 @@ class Write:
|
|
|
5692
5752
|
|
|
5693
5753
|
# create note_off event
|
|
5694
5754
|
events.append({
|
|
5695
|
-
'tick': noteTicks +
|
|
5755
|
+
'tick': noteTicks + soundingTicks,
|
|
5696
5756
|
'msg': mido.Message('note_off',
|
|
5697
5757
|
note=pitch,
|
|
5698
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.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/examples/drumMachinePattern1.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/findPitchOctave.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/generativeMusic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonicesMundi.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonographLateral.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/harmonographRotary.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteCenterDown.png
RENAMED
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/iPianoWhiteLeftDown.png
RENAMED
|
File without changes
|
{creativepython-0.3.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/midiSynthesizer2.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/examples/pentatonicMelody.py
RENAMED
|
File without changes
|
|
File without changes
|
{creativepython-0.3.4 → 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.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/examples/sierpinskiTriangle.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → creativepython-0.3.5}/src/CreativePython/examples/simpleButtonInstrument.py
RENAMED
|
File without changes
|
{creativepython-0.3.4 → 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.4 → 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.4 → 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.4 → creativepython-0.3.5}/src/CreativePython/resources/de-brazzas-monkey.jpg
RENAMED
|
File without changes
|
{creativepython-0.3.4 → 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
|