CreativePython 0.1.0__tar.gz → 0.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-0.1.2/MANIFEST.in +5 -0
- creativepython-0.1.2/PKG-INFO +151 -0
- creativepython-0.1.2/README.md +102 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/pyproject.toml +11 -7
- creativepython-0.1.2/src/CreativePython/_creativepythonSetup.py +134 -0
- creativepython-0.1.2/src/CreativePython/_soundfont.py +72 -0
- creativepython-0.1.2/src/CreativePython/examples/.DS_Store +0 -0
- creativepython-0.1.2/src/CreativePython/examples/ArvoPart.CantusInMemoriam.py +76 -0
- creativepython-0.1.2/src/CreativePython/examples/ConcretPH_Xenakis.py +41 -0
- creativepython-0.1.2/src/CreativePython/examples/DeepPurple.SmokeOnTheWater.py +67 -0
- creativepython-0.1.2/src/CreativePython/examples/JS_Bach.Canon.TriasHarmonica.BWV1072.py +77 -0
- creativepython-0.1.2/src/CreativePython/examples/JS_Bach.Canon_1.GoldbergGround.BWV1087.py +39 -0
- creativepython-0.1.2/src/CreativePython/examples/Mozart.MusikalischesWurfelspiel.py +101 -0
- creativepython-0.1.2/src/CreativePython/examples/PierreCage.StructuresPourDeuxChances.py +47 -0
- creativepython-0.1.2/src/CreativePython/examples/RGB_Display.py +73 -0
- creativepython-0.1.2/src/CreativePython/examples/TerryRiley.InC.py +34 -0
- creativepython-0.1.2/src/CreativePython/examples/arpeggiator1.py +30 -0
- creativepython-0.1.2/src/CreativePython/examples/arpeggiator2.py +32 -0
- creativepython-0.1.2/src/CreativePython/examples/autumnLeaves.py +77 -0
- creativepython-0.1.2/src/CreativePython/examples/axelF.py +26 -0
- creativepython-0.1.2/src/CreativePython/examples/biosignals.txt +3555 -0
- creativepython-0.1.2/src/CreativePython/examples/boids.py +267 -0
- creativepython-0.1.2/src/CreativePython/examples/brownianMelody.py +47 -0
- creativepython-0.1.2/src/CreativePython/examples/changesByTupac.py +23 -0
- creativepython-0.1.2/src/CreativePython/examples/clementine.py +140 -0
- creativepython-0.1.2/src/CreativePython/examples/continuousPitchInstrumentAudio.py +54 -0
- creativepython-0.1.2/src/CreativePython/examples/drumExample.py +22 -0
- creativepython-0.1.2/src/CreativePython/examples/drumMachinePattern1.py +50 -0
- creativepython-0.1.2/src/CreativePython/examples/drumsComeAlive.py +87 -0
- creativepython-0.1.2/src/CreativePython/examples/fibonacci.py +19 -0
- creativepython-0.1.2/src/CreativePython/examples/findPitchOctave.py +14 -0
- creativepython-0.1.2/src/CreativePython/examples/furElise.py +27 -0
- creativepython-0.1.2/src/CreativePython/examples/generativeMusic.py +47 -0
- creativepython-0.1.2/src/CreativePython/examples/goldenTree.py +55 -0
- creativepython-0.1.2/src/CreativePython/examples/guidoWordMusic.py +70 -0
- creativepython-0.1.2/src/CreativePython/examples/harmonicesMundi.py +67 -0
- creativepython-0.1.2/src/CreativePython/examples/harmonicesMundiRevisisted.py +65 -0
- creativepython-0.1.2/src/CreativePython/examples/harmonographLateral.py +47 -0
- creativepython-0.1.2/src/CreativePython/examples/harmonographRotary.py +70 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoBlackDown.png +0 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoOctave.png +0 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoParallel.py +73 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoSimple.py +86 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoWhiteCenterDown.png +0 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoWhiteLeftDown.png +0 -0
- creativepython-0.1.2/src/CreativePython/examples/iPianoWhiteRightDown.png +0 -0
- creativepython-0.1.2/src/CreativePython/examples/midiIn1.py +14 -0
- creativepython-0.1.2/src/CreativePython/examples/midiIn2.py +13 -0
- creativepython-0.1.2/src/CreativePython/examples/midiIn3.py +25 -0
- creativepython-0.1.2/src/CreativePython/examples/midiOut.a.py +12 -0
- creativepython-0.1.2/src/CreativePython/examples/midiOut.b.py +14 -0
- creativepython-0.1.2/src/CreativePython/examples/midiSynthesizer.py +34 -0
- creativepython-0.1.2/src/CreativePython/examples/midiSynthesizer2.py +55 -0
- creativepython-0.1.2/src/CreativePython/examples/moondog-bird_slament.wav +0 -0
- creativepython-0.1.2/src/CreativePython/examples/musicalSphere.py +178 -0
- creativepython-0.1.2/src/CreativePython/examples/note.py +55 -0
- creativepython-0.1.2/src/CreativePython/examples/octoplus.py +56 -0
- creativepython-0.1.2/src/CreativePython/examples/oscIn1.py +13 -0
- creativepython-0.1.2/src/CreativePython/examples/oscIn2.py +19 -0
- creativepython-0.1.2/src/CreativePython/examples/pentatonicMelody.py +33 -0
- creativepython-0.1.2/src/CreativePython/examples/pianoPhase.py +28 -0
- creativepython-0.1.2/src/CreativePython/examples/pianoRollGenerator.py +43 -0
- creativepython-0.1.2/src/CreativePython/examples/playNote.py +7 -0
- creativepython-0.1.2/src/CreativePython/examples/proteinMusic.py +59 -0
- creativepython-0.1.2/src/CreativePython/examples/randomCircles.py +36 -0
- creativepython-0.1.2/src/CreativePython/examples/randomCirclesThroughMidiInput.py +52 -0
- creativepython-0.1.2/src/CreativePython/examples/randomCirclesTimed.py +67 -0
- creativepython-0.1.2/src/CreativePython/examples/retrograde.a.py +22 -0
- creativepython-0.1.2/src/CreativePython/examples/retrograde.b.py +36 -0
- creativepython-0.1.2/src/CreativePython/examples/retrograde.c.py +41 -0
- creativepython-0.1.2/src/CreativePython/examples/rowYourBoat.py +61 -0
- creativepython-0.1.2/src/CreativePython/examples/scaleTutor.py +27 -0
- creativepython-0.1.2/src/CreativePython/examples/sierpinskiTriangle.py +52 -0
- creativepython-0.1.2/src/CreativePython/examples/simpleButtonInstrument.py +34 -0
- creativepython-0.1.2/src/CreativePython/examples/simpleCircleInstrument.py +70 -0
- creativepython-0.1.2/src/CreativePython/examples/sineMelody.py +23 -0
- creativepython-0.1.2/src/CreativePython/examples/sineMelodyPlus.py +28 -0
- creativepython-0.1.2/src/CreativePython/examples/sliderControl.py +66 -0
- creativepython-0.1.2/src/CreativePython/examples/sonifyBiosignals.py +79 -0
- creativepython-0.1.2/src/CreativePython/examples/sonifyImage.py +109 -0
- creativepython-0.1.2/src/CreativePython/examples/soundscapeLoutrakiSunset.jpg +0 -0
- creativepython-0.1.2/src/CreativePython/examples/stringQuartet.py +36 -0
- creativepython-0.1.2/src/CreativePython/examples/textMusic.py +62 -0
- creativepython-0.1.2/src/CreativePython/examples/theWayItIs.py +33 -0
- creativepython-0.1.2/src/CreativePython/examples/themeAndVariations.py +64 -0
- creativepython-0.1.2/src/CreativePython/examples/throwingDice.py +37 -0
- creativepython-0.1.2/src/CreativePython/examples/windChimes.py +56 -0
- creativepython-0.1.2/src/CreativePython/examples/zipfMetrics.py +81 -0
- creativepython-0.1.2/src/CreativePython/resources/.DS_Store +0 -0
- creativepython-0.1.2/src/CreativePython/resources/550973__luizguilherme_a__clean-guitarr-riff.mp3 +0 -0
- creativepython-0.1.2/src/CreativePython/resources/chopper.jpg +0 -0
- creativepython-0.1.2/src/CreativePython/resources/de-brazzas-monkey.jpg +0 -0
- creativepython-0.1.2/src/CreativePython.egg-info/PKG-INFO +151 -0
- creativepython-0.1.2/src/CreativePython.egg-info/SOURCES.txt +108 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/src/CreativePython.egg-info/requires.txt +0 -3
- {creativepython-0.1.0 → creativepython-0.1.2}/src/CreativePython.egg-info/top_level.txt +1 -3
- {creativepython-0.1.0 → creativepython-0.1.2}/src/gui.py +116 -98
- creativepython-0.1.2/src/iannix.py +455 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/src/image.py +18 -2
- creativepython-0.1.2/src/markov.py +543 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/src/midi.py +179 -130
- {creativepython-0.1.0 → creativepython-0.1.2}/src/music.py +172 -137
- {creativepython-0.1.0 → creativepython-0.1.2}/src/osc.py +18 -6
- {creativepython-0.1.0 → creativepython-0.1.2}/src/timer.py +12 -11
- {creativepython-0.1.0 → creativepython-0.1.2}/src/zipf.py +170 -178
- creativepython-0.1.0/MANIFEST.in +0 -1
- creativepython-0.1.0/PKG-INFO +0 -189
- creativepython-0.1.0/README.md +0 -137
- creativepython-0.1.0/src/CreativePython.egg-info/PKG-INFO +0 -189
- creativepython-0.1.0/src/CreativePython.egg-info/SOURCES.txt +0 -22
- creativepython-0.1.0/src/CreativePython.egg-info/entry_points.txt +0 -3
- creativepython-0.1.0/src/creativepython_setup.py +0 -85
- creativepython-0.1.0/src/iannix.py +0 -383
- creativepython-0.1.0/src/markov.py +0 -263
- {creativepython-0.1.0 → creativepython-0.1.2}/LICENSE +0 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/setup.cfg +0 -0
- {creativepython-0.1.0/src → creativepython-0.1.2/src/CreativePython}/__init__.py +0 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/src/CreativePython.egg-info/dependency_links.txt +0 -0
- {creativepython-0.1.0 → creativepython-0.1.2}/src/_RealtimeAudioPlayer.py +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: CreativePython
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: A Python-based software environment for developing algorithmic art projects.
|
|
5
|
+
Author-email: "Dr. Bill Manaris" <manaris@cofc.edu>, Taj Ballinger <ballingertj@g.cofc.edu>, Trevor Ritchie <ritchiets@g.cofc.edu>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Dr. Bill Manaris
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://jythonmusic.me
|
|
29
|
+
Keywords: music,audio,midi,learning,algorithmic art,algoart
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Requires-Python: >=3.9
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Requires-Dist: tinysoundfont>=0.3.6
|
|
37
|
+
Requires-Dist: osc4py3>=1.0.8
|
|
38
|
+
Requires-Dist: mido>=1.3.3
|
|
39
|
+
Requires-Dist: PySide6>=6.9.1
|
|
40
|
+
Requires-Dist: sounddevice>=0.5.2
|
|
41
|
+
Requires-Dist: soundfile>=0.13.1
|
|
42
|
+
Requires-Dist: tqdm>=4.67.1
|
|
43
|
+
Requires-Dist: pooch>=1.8
|
|
44
|
+
Requires-Dist: pypianoroll>=1.0
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: build; extra == "dev"
|
|
47
|
+
Requires-Dist: twine; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# CreativePython
|
|
51
|
+
|
|
52
|
+
CreativePython is a Python-based software environment for learning and developing algorithmic art projects. It mirrors the [JythonMusic API](https://jythonmusic.me/api-reference/), and is powered by [PySide6](https://wiki.qt.io/Qt_for_Python) and [portaudio](http://portaudio.com/).
|
|
53
|
+
|
|
54
|
+
CreativePython is distributed under the MIT License.
|
|
55
|
+
|
|
56
|
+
- [Homepage](https://jythonmusic.me/)
|
|
57
|
+
- [Download All Examples [ZIP]](https://www.dropbox.com/scl/fo/rvc8m8pt4m0281qn0t4oi/AO2Y0W2qOrOcurlQmLa7M54?rlkey=0sf80bmov135tc85dk9k7ats6&dl=1)
|
|
58
|
+
|
|
59
|
+
This package is still under development.
|
|
60
|
+
|
|
61
|
+
# Beginner Installation (IDLE)
|
|
62
|
+
|
|
63
|
+
1. Download and install the latest version of [Python](https://www.python.org/downloads/).
|
|
64
|
+
|
|
65
|
+
2. Download the [CreativePython Setup Script](https://www.dropbox.com/scl/fi/253bvfqsf0ij3rmza88q5/_creativepythonSetup.py?rlkey=iu4y4u8pujltgfx6kbjmodu9m&dl=1).
|
|
66
|
+
|
|
67
|
+
3. Open `creativePythonSetup.py` with IDLE, Python's Integrated Development Learning Environment.
|
|
68
|
+
|
|
69
|
+
4. From the IDLE toolbar, select `Run`, then `Run Module`.
|
|
70
|
+
|
|
71
|
+
5. CreativePython will check for its requirements on your system, download any missing requirements, and install its libraries.
|
|
72
|
+
|
|
73
|
+
6. When you see `[CreativePython Setup]: CreativePython installed successfully.`, you're all done! You're ready to start using CreativePython.
|
|
74
|
+
|
|
75
|
+
**NOTE**: You can use the setup script in any Python3 environment - not just IDLE!
|
|
76
|
+
|
|
77
|
+
# Custom Installation
|
|
78
|
+
|
|
79
|
+
## Windows
|
|
80
|
+
|
|
81
|
+
Install CreativePython using `pip`:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
python -m pip install CreativePython
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## MacOS
|
|
88
|
+
|
|
89
|
+
Use [Homebrew](https://brew.sh/) to install the prerequisite [portaudio](http://portaudio.com/) library, then install CreativePython using `pip`:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
brew install portaudio
|
|
93
|
+
pip install CreativePython
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Linux
|
|
97
|
+
|
|
98
|
+
Use apt, or your preferred package manager, to install the prerequisite [portaudio](http://portaudio.com/) library, then install CreativePython using `pip`:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
sudo apt-get portaudio
|
|
102
|
+
pip install CreativePython
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
# Using CreativePython
|
|
106
|
+
|
|
107
|
+
## Importing Libraries
|
|
108
|
+
|
|
109
|
+
CreativePython's core modules are the `music`, `gui`, `image`, `timer`, `osc`, and `midi` libraries. You can import these libraries into your python code using:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
import music
|
|
113
|
+
from music import *
|
|
114
|
+
from music import Note, Play, C4, HN
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Or a similar statement. CreativePython includes a number of useful constants, so we recommend using wildcard imports like `from music import *`.
|
|
118
|
+
|
|
119
|
+
**NOTE**: The first time you import `music`, CreativePython will ask permission to download a high-quality soundfont (FluidR3 G2-2.sf2) for you. You should only have to do this once.
|
|
120
|
+
|
|
121
|
+
## Running CreativePython programs
|
|
122
|
+
|
|
123
|
+
CreativePython is designed for use in Python's Interactive Mode. To use Interactive Mode, enter a command like:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
python -i <filename>.py
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Example
|
|
130
|
+
|
|
131
|
+
Download [playNote.py](https://www.dropbox.com/scl/fi/z6rkjy4xnofmg0t899se3/playNote.py?rlkey=o3t8c91ne6agj2lqf2aupl8m5&dl=1):
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
# playNote.py
|
|
135
|
+
# Demonstrates how to play a single note.
|
|
136
|
+
|
|
137
|
+
from music import * # import music library
|
|
138
|
+
|
|
139
|
+
note = Note(C4, HN) # create a middle C half note
|
|
140
|
+
Play.midi(note) # and play it!
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
In a terminal, run the code in interactive mode:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
python -i playNote.py
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If this is the first time you've used CreativePython, it will ask to download a soundfont.
|
|
150
|
+
|
|
151
|
+
After you do, you should hear a single C4 half-note.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# CreativePython
|
|
2
|
+
|
|
3
|
+
CreativePython is a Python-based software environment for learning and developing algorithmic art projects. It mirrors the [JythonMusic API](https://jythonmusic.me/api-reference/), and is powered by [PySide6](https://wiki.qt.io/Qt_for_Python) and [portaudio](http://portaudio.com/).
|
|
4
|
+
|
|
5
|
+
CreativePython is distributed under the MIT License.
|
|
6
|
+
|
|
7
|
+
- [Homepage](https://jythonmusic.me/)
|
|
8
|
+
- [Download All Examples [ZIP]](https://www.dropbox.com/scl/fo/rvc8m8pt4m0281qn0t4oi/AO2Y0W2qOrOcurlQmLa7M54?rlkey=0sf80bmov135tc85dk9k7ats6&dl=1)
|
|
9
|
+
|
|
10
|
+
This package is still under development.
|
|
11
|
+
|
|
12
|
+
# Beginner Installation (IDLE)
|
|
13
|
+
|
|
14
|
+
1. Download and install the latest version of [Python](https://www.python.org/downloads/).
|
|
15
|
+
|
|
16
|
+
2. Download the [CreativePython Setup Script](https://www.dropbox.com/scl/fi/253bvfqsf0ij3rmza88q5/_creativepythonSetup.py?rlkey=iu4y4u8pujltgfx6kbjmodu9m&dl=1).
|
|
17
|
+
|
|
18
|
+
3. Open `creativePythonSetup.py` with IDLE, Python's Integrated Development Learning Environment.
|
|
19
|
+
|
|
20
|
+
4. From the IDLE toolbar, select `Run`, then `Run Module`.
|
|
21
|
+
|
|
22
|
+
5. CreativePython will check for its requirements on your system, download any missing requirements, and install its libraries.
|
|
23
|
+
|
|
24
|
+
6. When you see `[CreativePython Setup]: CreativePython installed successfully.`, you're all done! You're ready to start using CreativePython.
|
|
25
|
+
|
|
26
|
+
**NOTE**: You can use the setup script in any Python3 environment - not just IDLE!
|
|
27
|
+
|
|
28
|
+
# Custom Installation
|
|
29
|
+
|
|
30
|
+
## Windows
|
|
31
|
+
|
|
32
|
+
Install CreativePython using `pip`:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
python -m pip install CreativePython
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## MacOS
|
|
39
|
+
|
|
40
|
+
Use [Homebrew](https://brew.sh/) to install the prerequisite [portaudio](http://portaudio.com/) library, then install CreativePython using `pip`:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
brew install portaudio
|
|
44
|
+
pip install CreativePython
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Linux
|
|
48
|
+
|
|
49
|
+
Use apt, or your preferred package manager, to install the prerequisite [portaudio](http://portaudio.com/) library, then install CreativePython using `pip`:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
sudo apt-get portaudio
|
|
53
|
+
pip install CreativePython
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
# Using CreativePython
|
|
57
|
+
|
|
58
|
+
## Importing Libraries
|
|
59
|
+
|
|
60
|
+
CreativePython's core modules are the `music`, `gui`, `image`, `timer`, `osc`, and `midi` libraries. You can import these libraries into your python code using:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
import music
|
|
64
|
+
from music import *
|
|
65
|
+
from music import Note, Play, C4, HN
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or a similar statement. CreativePython includes a number of useful constants, so we recommend using wildcard imports like `from music import *`.
|
|
69
|
+
|
|
70
|
+
**NOTE**: The first time you import `music`, CreativePython will ask permission to download a high-quality soundfont (FluidR3 G2-2.sf2) for you. You should only have to do this once.
|
|
71
|
+
|
|
72
|
+
## Running CreativePython programs
|
|
73
|
+
|
|
74
|
+
CreativePython is designed for use in Python's Interactive Mode. To use Interactive Mode, enter a command like:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
python -i <filename>.py
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Example
|
|
81
|
+
|
|
82
|
+
Download [playNote.py](https://www.dropbox.com/scl/fi/z6rkjy4xnofmg0t899se3/playNote.py?rlkey=o3t8c91ne6agj2lqf2aupl8m5&dl=1):
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
# playNote.py
|
|
86
|
+
# Demonstrates how to play a single note.
|
|
87
|
+
|
|
88
|
+
from music import * # import music library
|
|
89
|
+
|
|
90
|
+
note = Note(C4, HN) # create a middle C half note
|
|
91
|
+
Play.midi(note) # and play it!
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
In a terminal, run the code in interactive mode:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
python -i playNote.py
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If this is the first time you've used CreativePython, it will ask to download a soundfont.
|
|
101
|
+
|
|
102
|
+
After you do, you should hear a single C4 half-note.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "CreativePython"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.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" }
|
|
@@ -24,23 +24,27 @@ dependencies = [
|
|
|
24
24
|
"tinysoundfont>=0.3.6",
|
|
25
25
|
"osc4py3>=1.0.8",
|
|
26
26
|
"mido>=1.3.3",
|
|
27
|
-
"numpy>=2.3.2",
|
|
28
|
-
"pyaudio>=0.2.14",
|
|
29
27
|
"PySide6>=6.9.1",
|
|
30
28
|
"sounddevice>=0.5.2",
|
|
31
29
|
"soundfile>=0.13.1",
|
|
32
30
|
"tqdm>=4.67.1",
|
|
33
31
|
"pooch>=1.8",
|
|
34
|
-
"platformdirs>=4.2",
|
|
35
32
|
"pypianoroll>=1.0"
|
|
36
33
|
]
|
|
37
34
|
|
|
38
35
|
[project.urls]
|
|
39
36
|
Homepage = "https://jythonmusic.me"
|
|
40
37
|
|
|
41
|
-
[
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
CreativePython = [
|
|
40
|
+
"examples/*",
|
|
41
|
+
"scripts/*",
|
|
42
|
+
"resources/*",
|
|
43
|
+
# "bin/windows/*",
|
|
44
|
+
# "bin/macos/*",
|
|
45
|
+
# "licenses/*",
|
|
46
|
+
# "wheels/*.whl"
|
|
47
|
+
]
|
|
44
48
|
|
|
45
49
|
[project.optional-dependencies]
|
|
46
50
|
dev = ["build", "twine"]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# creativePythonSetup.py
|
|
2
|
+
# This script installs CreativePython, and any missing system requirements
|
|
3
|
+
# MacOS: Portaudio (installed via Homebrew)
|
|
4
|
+
# Win64: None
|
|
5
|
+
# Linux: None
|
|
6
|
+
|
|
7
|
+
import os, platform, shutil, subprocess
|
|
8
|
+
import sys, pathlib
|
|
9
|
+
|
|
10
|
+
debug = True
|
|
11
|
+
LOG_PATH = str(pathlib.Path.home() / "Desktop" / "creativepython-install.log")
|
|
12
|
+
|
|
13
|
+
class SetupError(Exception):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def _print(text):
|
|
17
|
+
print(f"[CreativePython Setup]: {text}")
|
|
18
|
+
|
|
19
|
+
def _run(cmd, env=os.environ, log=None, check=True):
|
|
20
|
+
if debug: _print(f"Running: {' '.join(cmd)}")
|
|
21
|
+
result = subprocess.run(
|
|
22
|
+
cmd,
|
|
23
|
+
check=False,
|
|
24
|
+
text=True,
|
|
25
|
+
stdout=subprocess.PIPE,
|
|
26
|
+
stderr=subprocess.PIPE,
|
|
27
|
+
env=env
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if log:
|
|
31
|
+
log.write(f"\n$ {' '.join(cmd)}\n")
|
|
32
|
+
if result.stdout: log.write(result.stdout)
|
|
33
|
+
if result.stderr: log.write(f"\n[stderr]\n{result.stderr}")
|
|
34
|
+
if check and result.returncode != 0:
|
|
35
|
+
raise SetupError(f"Command failed: {' '.join(cmd)} (exit {result.returncode})")
|
|
36
|
+
|
|
37
|
+
return result
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _findHomebrew():
|
|
41
|
+
if debug: _print("Looking for Homebrew...")
|
|
42
|
+
brew = shutil.which("brew") # check if brew is on PATH
|
|
43
|
+
|
|
44
|
+
if not brew:
|
|
45
|
+
if debug: _print("Didn't find Homebrew, checking other locations...")
|
|
46
|
+
# brew not on PATH, so check common install locations
|
|
47
|
+
commonBins = ["/opt/homebrew/bin/brew", "/usr/local/bin/brew"]
|
|
48
|
+
i = 0
|
|
49
|
+
while not brew and i < len(commonBins):
|
|
50
|
+
if os.path.exists(commonBins[i]): # bin is installed, so add it to PATH
|
|
51
|
+
os.environ["PATH"] = commonBins[i] + os.pathsep + os.environ.get("PATH", "")
|
|
52
|
+
brew = commonBins[i]
|
|
53
|
+
i = i + 1
|
|
54
|
+
|
|
55
|
+
if debug:
|
|
56
|
+
if brew: _print(f"Homebrew found at {brew}")
|
|
57
|
+
else: _print("Failed to find Homebrew...")
|
|
58
|
+
|
|
59
|
+
return brew
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _installHomebrew():
|
|
63
|
+
if debug: _print("Installing Homebrew...")
|
|
64
|
+
env = dict(os.environ)
|
|
65
|
+
env["NONINTERACTIVE"] = "1"
|
|
66
|
+
|
|
67
|
+
_run('/bin/bash', '-c', '"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', env=env) # install homebrew
|
|
68
|
+
|
|
69
|
+
brew = _findHomebrew() # and verify installation
|
|
70
|
+
if not brew:
|
|
71
|
+
raise SetupError("Homebrew installation failed. Ensure you have internet access and try again.")
|
|
72
|
+
|
|
73
|
+
if debug: _print("Homebrew installed successfully.")
|
|
74
|
+
return brew
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _isBrewPackageInstalled(package, brew=None):
|
|
78
|
+
if debug: _print(f"Looking for {package}...")
|
|
79
|
+
if not brew: brew = _findHomebrew()
|
|
80
|
+
|
|
81
|
+
isInstalled = subprocess.run(
|
|
82
|
+
[brew, "list", "--versions", package],
|
|
83
|
+
stdout=subprocess.DEVNULL,
|
|
84
|
+
stderr=subprocess.DEVNULL
|
|
85
|
+
).returncode == 0
|
|
86
|
+
|
|
87
|
+
if debug:
|
|
88
|
+
if isInstalled: _print(f"{package} found.")
|
|
89
|
+
else: _print(f"Failed to find {package}...")
|
|
90
|
+
|
|
91
|
+
return isInstalled
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _installBrewPackage(package, brew=None):
|
|
95
|
+
if debug: _print(f"Installing {package}...")
|
|
96
|
+
if not brew: brew = _findHomebrew()
|
|
97
|
+
|
|
98
|
+
_run([brew, 'update']) # update Homebrew...
|
|
99
|
+
_run([brew, 'install', package]) # ... and install package
|
|
100
|
+
|
|
101
|
+
if not _isBrewPackageInstalled(package): # verify installation
|
|
102
|
+
raise SetupError(f"{package} installation failed. Ensure you have internet access and try again.")
|
|
103
|
+
|
|
104
|
+
if debug: _print(f"{package} installed successfully.")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _installCreativePython():
|
|
108
|
+
if debug: _print(f"Installing CreativePython... (log: {LOG_PATH})")
|
|
109
|
+
|
|
110
|
+
with open(LOG_PATH, "w", encoding="utf-8", errors="replace") as log:
|
|
111
|
+
# find the python interpreter location
|
|
112
|
+
py = sys.executable.replace("pythonw.exe", "python.exe")
|
|
113
|
+
|
|
114
|
+
_run([py, '-m', 'pip', 'install', '--upgrade', 'pip', 'setuptools', 'wheel'], log=log, check=False)
|
|
115
|
+
_run([py, '-m', 'pip', 'install', '--user', 'CreativePython'], log=log)
|
|
116
|
+
|
|
117
|
+
if debug: _print("CreativePython installed successfully.")
|
|
118
|
+
|
|
119
|
+
import music # import music to trigger soundfont download
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
|
|
125
|
+
if platform.system() == "Darwin": # check for MacOS...
|
|
126
|
+
brew = _findHomebrew()
|
|
127
|
+
if not brew: # ... check for Homebrew...
|
|
128
|
+
brew = _installHomebrew() # ... no, so install it
|
|
129
|
+
|
|
130
|
+
if not _isBrewPackageInstalled("portaudio", brew): # next, check for portaudio ...
|
|
131
|
+
_installBrewPackage("portaudio", brew) # ... no, so install it
|
|
132
|
+
|
|
133
|
+
# now, requirements have been met
|
|
134
|
+
_installCreativePython()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from platformdirs import user_data_dir
|
|
3
|
+
from pooch import retrieve
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
APP = "CreativePython"
|
|
7
|
+
ORG = "CofC"
|
|
8
|
+
|
|
9
|
+
SOUNDFONT_NAME = "default.sf2"
|
|
10
|
+
CACHE_DIR = Path(user_data_dir(APP, ORG)) / "SoundFonts"
|
|
11
|
+
SOUNDFONT_PATH = CACHE_DIR / SOUNDFONT_NAME
|
|
12
|
+
|
|
13
|
+
SF2_URL = "https://www.dropbox.com/s/xixtvox70lna6m2/FluidR3%20GM2-2.SF2?dl=1"
|
|
14
|
+
SF2_SHA256 = "2ae766ab5c5deb6f7fffacd6316ec9f3699998cce821df3163e7b10a78a64066"
|
|
15
|
+
|
|
16
|
+
##### SOUNDFONTS #####
|
|
17
|
+
|
|
18
|
+
def _findSoundfont(candidate=None):
|
|
19
|
+
"""
|
|
20
|
+
Finds a soundfont 'default.sf2' and returns its location.
|
|
21
|
+
'candidate' can be another path containing the soundfont.
|
|
22
|
+
"""
|
|
23
|
+
candidates = []
|
|
24
|
+
soundfontPath = None
|
|
25
|
+
|
|
26
|
+
# path as argument?
|
|
27
|
+
if candidate:
|
|
28
|
+
candidates.append(Path(candidate))
|
|
29
|
+
|
|
30
|
+
# path as environment variable?
|
|
31
|
+
env = os.getenv("CREATIVEPYTHON_SOUNDFONT")
|
|
32
|
+
if env:
|
|
33
|
+
candidates.append(Path(env))
|
|
34
|
+
|
|
35
|
+
# default soundfont location
|
|
36
|
+
candidates+= [SOUNDFONT_PATH, Path.home() / "SoundFonts" / SOUNDFONT_NAME]
|
|
37
|
+
|
|
38
|
+
# find first valid candidate
|
|
39
|
+
i = 0
|
|
40
|
+
while soundfontPath is None and i < len(candidates):
|
|
41
|
+
c = candidates[i]
|
|
42
|
+
if c and c.exists():
|
|
43
|
+
soundfontPath = str(c)
|
|
44
|
+
|
|
45
|
+
return soundfontPath
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _downloadSoundfont(destination=SOUNDFONT_PATH):
|
|
49
|
+
"""
|
|
50
|
+
Downloads FluidR3 GM2-2 to given destination as 'default.sf2'
|
|
51
|
+
"""
|
|
52
|
+
# create parent directory
|
|
53
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
54
|
+
# download soundfont
|
|
55
|
+
path = retrieve(
|
|
56
|
+
url=SF2_URL,
|
|
57
|
+
known_hash=f"sha256:{SF2_SHA256}",
|
|
58
|
+
progressbar=True,
|
|
59
|
+
fname=destination.name,
|
|
60
|
+
path=str(destination.parent)
|
|
61
|
+
)
|
|
62
|
+
return path
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _installSoundfont():
|
|
66
|
+
soundfontPath = _findSoundfont()
|
|
67
|
+
if not soundfontPath:
|
|
68
|
+
print(f"[CreativePython Setup]: Downloading MIDI Soundfont...")
|
|
69
|
+
_soundfontPath = _downloadSoundfont()
|
|
70
|
+
print(f"[CreativePython Setup]: Soundfont downloaded to {_soundfontPath}")
|
|
71
|
+
|
|
72
|
+
return _soundfontPath
|
|
Binary file
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# ArvoPart.CantusInMemoriam.py
|
|
2
|
+
#
|
|
3
|
+
# Recreates a variation of Arvo Part's "Cantus in Memoriam Benjamin
|
|
4
|
+
# Britten" (1977) for string orchestra and bell, using Mod functions.
|
|
5
|
+
|
|
6
|
+
from music import *
|
|
7
|
+
|
|
8
|
+
# musical parameters
|
|
9
|
+
repetitions = 2 # length of piece
|
|
10
|
+
tempo = 112 # tempo of piece
|
|
11
|
+
bar = WN+HN # length of a measure
|
|
12
|
+
|
|
13
|
+
# create musical data structure
|
|
14
|
+
cantusScore = Score("Cantus in Memoriam Benjamin Britten", tempo)
|
|
15
|
+
|
|
16
|
+
bellPart = Part(TUBULAR_BELLS, 0)
|
|
17
|
+
violinPart = Part(VIOLIN, 1)
|
|
18
|
+
|
|
19
|
+
# bell
|
|
20
|
+
bellPitches = [REST, A4, REST, REST, A4, REST, REST, A4]
|
|
21
|
+
bellDurations = [bar/2, bar/2, bar, bar/2, bar/2, bar, bar/2, bar/2]
|
|
22
|
+
|
|
23
|
+
bellPhrase = Phrase(0.0)
|
|
24
|
+
bellPhrase.addNoteList(bellPitches, bellDurations)
|
|
25
|
+
bellPart.addPhrase(bellPhrase)
|
|
26
|
+
|
|
27
|
+
# violin - define descending aeolian scale and rhythms
|
|
28
|
+
pitches = [A5, G5, F5, E5, D5, C5, B4, A4]
|
|
29
|
+
durations = [HN, QN, HN, QN, HN, QN, HN, QN]
|
|
30
|
+
|
|
31
|
+
# violin 1
|
|
32
|
+
violin1Phrase = Phrase(bar * 6.5) # start after 6 and 1/2 measures
|
|
33
|
+
violin1Phrase.addNoteList(pitches, durations)
|
|
34
|
+
|
|
35
|
+
# violin 2
|
|
36
|
+
violin2Phrase = violin1Phrase.copy()
|
|
37
|
+
violin2Phrase.setStartTime(bar * 7.0) # start after 7 measures
|
|
38
|
+
Mod.elongate(violin2Phrase, 2.0) # double durations
|
|
39
|
+
Mod.transpose(violin2Phrase, -12) # an octave lower
|
|
40
|
+
|
|
41
|
+
# violin 3
|
|
42
|
+
violin3Phrase = violin2Phrase.copy()
|
|
43
|
+
violin3Phrase.setStartTime(bar * 8.0) # start after 8 measures
|
|
44
|
+
Mod.elongate(violin3Phrase, 2.0) # double durations
|
|
45
|
+
Mod.transpose(violin3Phrase, -12) # an octave lower
|
|
46
|
+
|
|
47
|
+
# violin 4
|
|
48
|
+
violin4Phrase = violin3Phrase.copy()
|
|
49
|
+
violin4Phrase.setStartTime(bar * 10.0) # start after 10 measures
|
|
50
|
+
Mod.elongate(violin4Phrase, 2.0) # double durations
|
|
51
|
+
Mod.transpose(violin4Phrase, -12) # an octave lower
|
|
52
|
+
|
|
53
|
+
# repeat phrases enough times
|
|
54
|
+
Mod.repeat(violin1Phrase, 8 * repetitions)
|
|
55
|
+
Mod.repeat(violin2Phrase, 4 * repetitions)
|
|
56
|
+
Mod.repeat(violin3Phrase, 2 * repetitions)
|
|
57
|
+
Mod.repeat(violin4Phrase, repetitions)
|
|
58
|
+
|
|
59
|
+
# violin part
|
|
60
|
+
violinPart.addPhrase(violin1Phrase)
|
|
61
|
+
violinPart.addPhrase(violin2Phrase)
|
|
62
|
+
violinPart.addPhrase(violin3Phrase)
|
|
63
|
+
violinPart.addPhrase(violin4Phrase)
|
|
64
|
+
|
|
65
|
+
# score
|
|
66
|
+
cantusScore.addPart(bellPart)
|
|
67
|
+
cantusScore.addPart(violinPart)
|
|
68
|
+
|
|
69
|
+
# fade in, and fade out
|
|
70
|
+
Mod.fadeIn(cantusScore, WN)
|
|
71
|
+
Mod.fadeOut(cantusScore, WN * 12)
|
|
72
|
+
|
|
73
|
+
# view, play, and write
|
|
74
|
+
View.sketch(cantusScore)
|
|
75
|
+
Play.midi(cantusScore)
|
|
76
|
+
Write.midi (cantusScore, "ArvoPart.CantusInMemoriam.mid")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# ConcretPH_Xenakis.py
|
|
2
|
+
#
|
|
3
|
+
# A short example which generates a random cloud texture
|
|
4
|
+
# inspired by Iannis Xenakis's 'Concret PH' composition
|
|
5
|
+
#
|
|
6
|
+
# see http://en.wikipedia.org/wiki/Concret_PH
|
|
7
|
+
|
|
8
|
+
from music import *
|
|
9
|
+
from random import *
|
|
10
|
+
|
|
11
|
+
# constants for controlling musical parameters
|
|
12
|
+
cloudWidth = 64 # length of piece (in quarter notes)
|
|
13
|
+
cloudDensity = 23.44 # how dense the cloud may be
|
|
14
|
+
particleDuration = 0.2 # how long each sound particle may be
|
|
15
|
+
numParticles = int(cloudDensity * cloudWidth) # how many particles
|
|
16
|
+
|
|
17
|
+
part = Part(BREATHNOISE)
|
|
18
|
+
|
|
19
|
+
# make particles (notes) and add them to cloud (part)
|
|
20
|
+
for i in range(numParticles):
|
|
21
|
+
|
|
22
|
+
# create note with random attributes
|
|
23
|
+
pitch = randint(0, 127) # pick from 0 to 127
|
|
24
|
+
duration = random() * particleDuration # 0 to particleDuration
|
|
25
|
+
dynamic = randint(0, 127) # pick from silent to loud
|
|
26
|
+
panning = random() # pick from left to right
|
|
27
|
+
note = Note(pitch, duration, dynamic, panning) # create note
|
|
28
|
+
|
|
29
|
+
# now, place it somewhere in the cloud (time continuum)
|
|
30
|
+
startTime = random() * cloudWidth # pick from 0 to end of piece
|
|
31
|
+
phrase = Phrase(startTime) # create phrase with this start time
|
|
32
|
+
phrase.addNote(note) # add the above note
|
|
33
|
+
part.addPhrase(phrase) # and add both to the part
|
|
34
|
+
# now, all notes have been created
|
|
35
|
+
|
|
36
|
+
# add some elegance to the end
|
|
37
|
+
Mod.fadeOut(part, 20)
|
|
38
|
+
|
|
39
|
+
View.show(part)
|
|
40
|
+
Play.midi(part)
|
|
41
|
+
Write.midi(part, "ConcretPh.mid")
|