CreativePython 0.0.3__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CreativePython/_soundfont.py +66 -0
- CreativePython/examples/ArvoPart.CantusInMemoriam.py +76 -0
- CreativePython/examples/ConcretPH_Xenakis.py +41 -0
- CreativePython/examples/DeepPurple.SmokeOnTheWater.py +67 -0
- CreativePython/examples/JS_Bach.Canon.TriasHarmonica.BWV1072.py +77 -0
- CreativePython/examples/JS_Bach.Canon_1.GoldbergGround.BWV1087.py +39 -0
- CreativePython/examples/Mozart.MusikalischesWurfelspiel.py +101 -0
- CreativePython/examples/PierreCage.StructuresPourDeuxChances.py +47 -0
- CreativePython/examples/RGB_Display.py +73 -0
- CreativePython/examples/TerryRiley.InC.py +34 -0
- CreativePython/examples/arpeggiator1.py +30 -0
- CreativePython/examples/arpeggiator2.py +32 -0
- CreativePython/examples/autumnLeaves.py +77 -0
- CreativePython/examples/axelF.py +26 -0
- CreativePython/examples/biosignals.txt +3555 -0
- CreativePython/examples/boids.py +267 -0
- CreativePython/examples/brownianMelody.py +47 -0
- CreativePython/examples/changesByTupac.py +23 -0
- CreativePython/examples/clementine.py +140 -0
- CreativePython/examples/continuousPitchInstrumentAudio.py +54 -0
- CreativePython/examples/drumExample.py +22 -0
- CreativePython/examples/drumMachinePattern1.py +50 -0
- CreativePython/examples/drumsComeAlive.py +87 -0
- CreativePython/examples/fibonacci.py +19 -0
- CreativePython/examples/findPitchOctave.py +14 -0
- CreativePython/examples/furElise.py +27 -0
- CreativePython/examples/generativeMusic.py +47 -0
- CreativePython/examples/goldenTree.py +55 -0
- CreativePython/examples/guidoWordMusic.py +70 -0
- CreativePython/examples/harmonicesMundi.py +67 -0
- CreativePython/examples/harmonicesMundiRevisisted.py +65 -0
- CreativePython/examples/harmonographLateral.py +47 -0
- CreativePython/examples/harmonographRotary.py +70 -0
- CreativePython/examples/iPianoBlackDown.png +0 -0
- CreativePython/examples/iPianoOctave.png +0 -0
- CreativePython/examples/iPianoParallel.py +73 -0
- CreativePython/examples/iPianoSimple.py +86 -0
- CreativePython/examples/iPianoWhiteCenterDown.png +0 -0
- CreativePython/examples/iPianoWhiteLeftDown.png +0 -0
- CreativePython/examples/iPianoWhiteRightDown.png +0 -0
- CreativePython/examples/midiIn1.py +14 -0
- CreativePython/examples/midiIn2.py +13 -0
- CreativePython/examples/midiIn3.py +25 -0
- CreativePython/examples/midiOut.a.py +12 -0
- CreativePython/examples/midiOut.b.py +14 -0
- CreativePython/examples/midiSynthesizer.py +34 -0
- CreativePython/examples/midiSynthesizer2.py +55 -0
- CreativePython/examples/moondog-bird_slament.wav +0 -0
- CreativePython/examples/musicalSphere.py +178 -0
- CreativePython/examples/note.py +55 -0
- CreativePython/examples/octoplus.py +56 -0
- CreativePython/examples/oscIn1.py +13 -0
- CreativePython/examples/oscIn2.py +19 -0
- CreativePython/examples/pentatonicMelody.py +33 -0
- CreativePython/examples/pianoPhase.py +28 -0
- CreativePython/examples/pianoRollGenerator.py +43 -0
- CreativePython/examples/playNote.py +7 -0
- CreativePython/examples/proteinMusic.py +59 -0
- CreativePython/examples/randomCircles.py +36 -0
- CreativePython/examples/randomCirclesThroughMidiInput.py +52 -0
- CreativePython/examples/randomCirclesTimed.py +67 -0
- CreativePython/examples/retrograde.a.py +22 -0
- CreativePython/examples/retrograde.b.py +36 -0
- CreativePython/examples/retrograde.c.py +41 -0
- CreativePython/examples/rowYourBoat.py +61 -0
- CreativePython/examples/scaleTutor.py +27 -0
- CreativePython/examples/sierpinskiTriangle.py +52 -0
- CreativePython/examples/simpleButtonInstrument.py +34 -0
- CreativePython/examples/simpleCircleInstrument.py +70 -0
- CreativePython/examples/sineMelody.py +23 -0
- CreativePython/examples/sineMelodyPlus.py +28 -0
- CreativePython/examples/sliderControl.py +66 -0
- CreativePython/examples/sonifyBiosignals.py +79 -0
- CreativePython/examples/sonifyImage.py +109 -0
- CreativePython/examples/soundscapeLoutrakiSunset.jpg +0 -0
- CreativePython/examples/stringQuartet.py +36 -0
- CreativePython/examples/textMusic.py +62 -0
- CreativePython/examples/theWayItIs.py +33 -0
- CreativePython/examples/themeAndVariations.py +64 -0
- CreativePython/examples/throwingDice.py +37 -0
- CreativePython/examples/windChimes.py +56 -0
- CreativePython/examples/zipfMetrics.py +81 -0
- CreativePython/resources/.DS_Store +0 -0
- CreativePython/resources/550973__luizguilherme_a__clean-guitarr-riff.mp3 +0 -0
- CreativePython/resources/chopper.jpg +0 -0
- CreativePython/resources/de-brazzas-monkey.jpg +0 -0
- CreativePython/scripts/creativePythonSetup.py +115 -0
- creativepython-0.1.1.dist-info/METADATA +146 -0
- creativepython-0.1.1.dist-info/RECORD +100 -0
- {creativepython-0.0.3.dist-info → creativepython-0.1.1.dist-info}/top_level.txt +1 -5
- gui.py +114 -66
- image.py +18 -2
- midi.py +180 -131
- music.py +120 -83
- osc.py +18 -6
- timer.py +5 -5
- creativepython-0.0.3.dist-info/METADATA +0 -154
- creativepython-0.0.3.dist-info/RECORD +0 -18
- creativepython-0.0.3.dist-info/entry_points.txt +0 -3
- creativepython_setup.py +0 -101
- iannix.py +0 -383
- markov.py +0 -263
- zipf.py +0 -232
- /__init__.py → /CreativePython/__init__.py +0 -0
- {creativepython-0.0.3.dist-info → creativepython-0.1.1.dist-info}/WHEEL +0 -0
- {creativepython-0.0.3.dist-info → creativepython-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from platformdirs import user_data_dir
|
|
3
|
+
from pooch import retrieve
|
|
4
|
+
import shutil, sys, 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 _soundfontPath():
|
|
19
|
+
"""Expose the intended soundfont path as a method."""
|
|
20
|
+
return SOUNDFONT_PATH
|
|
21
|
+
|
|
22
|
+
def _findSoundfont(candidate=None):
|
|
23
|
+
"""
|
|
24
|
+
Finds a soundfont 'default.sf2' and returns its location.
|
|
25
|
+
'candidate' can be another path containing the soundfont.
|
|
26
|
+
"""
|
|
27
|
+
candidates = []
|
|
28
|
+
soundfontPath = None
|
|
29
|
+
|
|
30
|
+
# path as argument?
|
|
31
|
+
if candidate:
|
|
32
|
+
candidates.append(Path(candidate))
|
|
33
|
+
|
|
34
|
+
# path as environment variable?
|
|
35
|
+
env = os.getenv("CREATIVEPYTHON_SOUNDFONT")
|
|
36
|
+
if env:
|
|
37
|
+
candidates.append(Path(env))
|
|
38
|
+
|
|
39
|
+
# default soundfont location
|
|
40
|
+
candidates+= [SOUNDFONT_PATH, Path.home() / "SoundFonts" / SOUNDFONT_NAME]
|
|
41
|
+
|
|
42
|
+
# find first valid candidate
|
|
43
|
+
i = 0
|
|
44
|
+
while soundfontPath is None and i < len(candidates):
|
|
45
|
+
c = candidates[i]
|
|
46
|
+
if c and c.exists():
|
|
47
|
+
soundfontPath = str(c)
|
|
48
|
+
|
|
49
|
+
return soundfontPath
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _downloadSoundfont(destination=SOUNDFONT_PATH):
|
|
53
|
+
"""
|
|
54
|
+
Downloads FluidR3 GM2-2 to given destination as 'default.sf2'
|
|
55
|
+
"""
|
|
56
|
+
# create parent directory
|
|
57
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
# download soundfont
|
|
59
|
+
path = retrieve(
|
|
60
|
+
url=SF2_URL,
|
|
61
|
+
known_hash=f"sha256:{SF2_SHA256}",
|
|
62
|
+
progressbar=True,
|
|
63
|
+
fname=destination.name,
|
|
64
|
+
path=str(destination.parent)
|
|
65
|
+
)
|
|
66
|
+
return path
|
|
@@ -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")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# DeepPurple.SmokeOnTheWater.py
|
|
2
|
+
#
|
|
3
|
+
# Demonstrates how to combine melodic lines, chords, and
|
|
4
|
+
# percussion. This is based on the intro of "Smoke On the Water"
|
|
5
|
+
# by Deep Purple.
|
|
6
|
+
|
|
7
|
+
from music import *
|
|
8
|
+
|
|
9
|
+
##### define the data structure
|
|
10
|
+
score = Score("Deep Purple, Smoke On The Water", 110) # 110 bpm
|
|
11
|
+
|
|
12
|
+
guitarPart = Part(OVERDRIVE_GUITAR, 0)
|
|
13
|
+
bassPart = Part(ELECTRIC_BASS, 1)
|
|
14
|
+
drumPart = Part(0, 9) # using MIDI channel 9 (percussion)
|
|
15
|
+
|
|
16
|
+
guitarPhrase1 = Phrase(0.0) # guitar opening melody
|
|
17
|
+
guitarPhrase2 = Phrase(32.0) # guitar opening melody an octave lower
|
|
18
|
+
bassPhrase = Phrase(64.0) # bass melody
|
|
19
|
+
drumPhrase = Phrase(96.0) # drum pattern
|
|
20
|
+
|
|
21
|
+
##### create musical data
|
|
22
|
+
# guitar opening melody (16QN = 4 measures)
|
|
23
|
+
guitarPitches = [G2, AS2, C3, G2, AS2, CS3, C3, G2, AS2, C3, AS2,
|
|
24
|
+
G2]
|
|
25
|
+
guitarDurations = [QN, QN, DQN, QN, QN, EN, HN, QN, QN, DQN, QN,
|
|
26
|
+
DHN+EN]
|
|
27
|
+
guitarPhrase1.addNoteList(guitarPitches, guitarDurations)
|
|
28
|
+
|
|
29
|
+
# create a power-chord sound by repeating the melody an octave lower
|
|
30
|
+
guitarPhrase2.addNoteList(guitarPitches, guitarDurations)
|
|
31
|
+
Mod.transpose(guitarPhrase2, -12)
|
|
32
|
+
|
|
33
|
+
# bass melody (32EN = 4 measures)
|
|
34
|
+
bassPitches1 = [G2, G2, G2, G2, G2, G2, G2, G2, G2, G2,
|
|
35
|
+
G2, G2, G2, G2, G2, G2, G2, G2]
|
|
36
|
+
bassDurations1 = [EN, EN, EN, EN, EN, EN, EN, EN, EN, EN,
|
|
37
|
+
EN, EN, EN, EN, EN, EN, EN, EN]
|
|
38
|
+
bassPitches2 = [AS2, AS2, C3, C3, C3, AS2, AS2, G2, G2,
|
|
39
|
+
G2, G2, G2, G2, G2]
|
|
40
|
+
bassDurations2 = [EN, EN, EN, EN, EN, EN, EN, EN, EN,
|
|
41
|
+
EN, EN, EN, EN, EN]
|
|
42
|
+
bassPhrase.addNoteList(bassPitches1, bassDurations1)
|
|
43
|
+
bassPhrase.addNoteList(bassPitches2, bassDurations2)
|
|
44
|
+
|
|
45
|
+
# snare drum pattern (2QN x 8 = 4 measures)
|
|
46
|
+
drumPitches = [REST, SNR] * 8
|
|
47
|
+
drumDurations = [QN, QN] * 8
|
|
48
|
+
drumPhrase.addNoteList(drumPitches, drumDurations)
|
|
49
|
+
|
|
50
|
+
##### repeat material as needed (based on how it's arranged in time)
|
|
51
|
+
Mod.repeat(guitarPhrase1, 8)
|
|
52
|
+
Mod.repeat(guitarPhrase2, 6)
|
|
53
|
+
Mod.repeat(bassPhrase, 4)
|
|
54
|
+
Mod.repeat(drumPhrase, 2)
|
|
55
|
+
|
|
56
|
+
##### combine musical material
|
|
57
|
+
guitarPart.addPhrase(guitarPhrase1)
|
|
58
|
+
guitarPart.addPhrase(guitarPhrase2)
|
|
59
|
+
bassPart.addPhrase(bassPhrase)
|
|
60
|
+
drumPart.addPhrase(drumPhrase)
|
|
61
|
+
score.addPart(guitarPart)
|
|
62
|
+
score.addPart(bassPart)
|
|
63
|
+
score.addPart(drumPart)
|
|
64
|
+
|
|
65
|
+
##### play and write score to a MIDI file
|
|
66
|
+
Play.midi(score)
|
|
67
|
+
Write.midi(score, "DeepPurple.SmokeOnTheWater.mid")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# JS_Bach.Canon.TriasHarmonica.BWV1072.py
|
|
2
|
+
#
|
|
3
|
+
# This program creates J.S. Bach's 'Trias Harmonica' BWV 1072 canon.
|
|
4
|
+
#
|
|
5
|
+
# This canon is constructed using two parts (choirs), each consisting
|
|
6
|
+
# of four voices. The first part's voices use the original theme,
|
|
7
|
+
# each separated by a half-note delay. The second part's voices use
|
|
8
|
+
# the inverted theme delayed by a quarter note, each separated by
|
|
9
|
+
# a half-note delay.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
from music import *
|
|
13
|
+
|
|
14
|
+
# define the theme (for choir 1)
|
|
15
|
+
pitches1 = [C4, D4, E4, F4, G4, F4, E4, D4]
|
|
16
|
+
durations1 = [DQN, EN, DQN, EN, DQN, EN, DQN, EN]
|
|
17
|
+
|
|
18
|
+
# define the inverted theme (for choir 2)
|
|
19
|
+
pitches2 = [G4, F4, E4, D4, C4, D4, E4, F4]
|
|
20
|
+
durations2 = [DQN, EN, DQN, EN, DQN, EN, DQN, EN]
|
|
21
|
+
|
|
22
|
+
# how many times to repeat the theme
|
|
23
|
+
times = 8
|
|
24
|
+
|
|
25
|
+
# choir 1 - 4 voices separated by half note
|
|
26
|
+
choir1 = Part()
|
|
27
|
+
|
|
28
|
+
voice1 = Phrase(0.0)
|
|
29
|
+
voice1.addNoteList(pitches1, durations1)
|
|
30
|
+
Mod.repeat(voice1, times) # repeat a number of times
|
|
31
|
+
voice1.addNote(C4, DQN) # add final note
|
|
32
|
+
|
|
33
|
+
voice2 = voice1.copy() # voice 2 is a copy of voice 1
|
|
34
|
+
voice2.setStartTime(HN) # separated by half note
|
|
35
|
+
|
|
36
|
+
voice3 = voice1.copy() # voice 3 is a copy of voice 1
|
|
37
|
+
voice3.setStartTime(HN*2) # separated by two half notes
|
|
38
|
+
|
|
39
|
+
voice4 = voice1.copy() # voice 4 is a copy of voice 1
|
|
40
|
+
voice4.setStartTime(HN*3) # separated by three half notes
|
|
41
|
+
|
|
42
|
+
choir1.addPhrase(voice1)
|
|
43
|
+
choir1.addPhrase(voice2)
|
|
44
|
+
choir1.addPhrase(voice3)
|
|
45
|
+
choir1.addPhrase(voice4)
|
|
46
|
+
|
|
47
|
+
# choir 2 - 4 voices inverted, delayed by quarter note,
|
|
48
|
+
# separated by a half note.
|
|
49
|
+
choir2 = Part()
|
|
50
|
+
|
|
51
|
+
voice5 = Phrase(QN) # delayed by quarter note
|
|
52
|
+
voice5.addNoteList(pitches2, durations2)
|
|
53
|
+
Mod.repeat(voice5, times) # repeat a number of times
|
|
54
|
+
voice5.addNote(G4, DQN) # add final note
|
|
55
|
+
|
|
56
|
+
voice6 = voice5.copy() # voice 6 is a copy of voice 5
|
|
57
|
+
voice6.setStartTime(QN + HN) # separated by half note
|
|
58
|
+
|
|
59
|
+
voice7 = voice5.copy() # voice 7 is a copy of voice 5
|
|
60
|
+
voice7.setStartTime(QN + HN*2) # separated by two half notes
|
|
61
|
+
|
|
62
|
+
voice8 = voice5.copy() # voice 8 is a copy of voice 5
|
|
63
|
+
voice8.setStartTime(QN + HN*3) # separated by three half note
|
|
64
|
+
|
|
65
|
+
choir2.addPhrase(voice5)
|
|
66
|
+
choir2.addPhrase(voice6)
|
|
67
|
+
choir2.addPhrase(voice7)
|
|
68
|
+
choir2.addPhrase(voice8)
|
|
69
|
+
|
|
70
|
+
# score
|
|
71
|
+
canon = Score("J.S. Bach, Trias Harmonica (BWV 1072)", 100)
|
|
72
|
+
canon.addPart(choir1)
|
|
73
|
+
canon.addPart(choir2)
|
|
74
|
+
|
|
75
|
+
# play score, and write it to a MIDI file
|
|
76
|
+
Play.midi(canon)
|
|
77
|
+
Write.midi(canon, "JS_Bach.Canon.TriasHarmonica.BWV1072.mid")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# JS_Bach.Canon_1.GoldbergGround.BWV1087.py
|
|
2
|
+
#
|
|
3
|
+
# This program (re)creates J.S. Bach's Canon No. 1 of the Fourteen on
|
|
4
|
+
# the Goldberg Ground.
|
|
5
|
+
#
|
|
6
|
+
# This canon is constructed using the Goldberg ground as the subject
|
|
7
|
+
# (soggetto) combined with the retrograde of itself.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
from music import *
|
|
11
|
+
|
|
12
|
+
# how many times to repeat the theme
|
|
13
|
+
times = 6
|
|
14
|
+
|
|
15
|
+
# define the data structure
|
|
16
|
+
score = Score("J.S. Bach, Canon 1, Goldberg Ground (BWV1087)", 100)
|
|
17
|
+
part = Part()
|
|
18
|
+
voice1 = Phrase(0.0)
|
|
19
|
+
|
|
20
|
+
# create musical material (soggetto)
|
|
21
|
+
pitches = [G3, F3, E3, D3, B2, C3, D3, G2]
|
|
22
|
+
rhythms = [QN, QN, QN, QN, QN, QN, QN, QN]
|
|
23
|
+
voice1.addNoteList(pitches, rhythms)
|
|
24
|
+
|
|
25
|
+
# create 2nd voice
|
|
26
|
+
voice2 = voice1.copy()
|
|
27
|
+
Mod.retrograde(voice2) # follower is retrograde of leader
|
|
28
|
+
|
|
29
|
+
# combine musical material
|
|
30
|
+
part.addPhrase(voice1)
|
|
31
|
+
part.addPhrase(voice2)
|
|
32
|
+
score.addPart(part)
|
|
33
|
+
|
|
34
|
+
# repeat canon as desired
|
|
35
|
+
Mod.repeat(score, times)
|
|
36
|
+
|
|
37
|
+
# play score and write it to a MIDI file
|
|
38
|
+
Play.midi(score)
|
|
39
|
+
Write.midi(score, "JS_Bach.Canon_1.GoldbergGround.BWV1087.mid")
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Mozart.MusikalischesWurfelspiel.py
|
|
2
|
+
#
|
|
3
|
+
# This program generates an excerpt of Mozart's "Musikalisches
|
|
4
|
+
# Wurfelspiel" (aka Mozart's Dice Game). It demonstrates how
|
|
5
|
+
# randomness may be sieved (harnessed) to produce aesthetic results.
|
|
6
|
+
#
|
|
7
|
+
# See Schwanauer, S, and D Levitt. 1993. Appendix, in Machine Models
|
|
8
|
+
# of Music. Cambridge, MA: MIT Press, pp. 533-538.
|
|
9
|
+
#
|
|
10
|
+
# The original has 16 measures with 11 choices per measure.
|
|
11
|
+
# This excerpt is a simplified form. In this excerpt,
|
|
12
|
+
# musical material is selected from this matrix:
|
|
13
|
+
#
|
|
14
|
+
# I II III IV
|
|
15
|
+
# 96 6 141 30
|
|
16
|
+
# 32 17 158 5
|
|
17
|
+
# 40
|
|
18
|
+
#
|
|
19
|
+
# Columns represent alternatives for a measure. The composer throws
|
|
20
|
+
# dice to select an alternative (choice) from first column.
|
|
21
|
+
# Then, connects it with the choice from second column, and so on.
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
from music import *
|
|
25
|
+
from random import *
|
|
26
|
+
|
|
27
|
+
# musical data structure
|
|
28
|
+
walzerteil = Part() # contains a four-measure motif generated
|
|
29
|
+
# randomly from the matrix above
|
|
30
|
+
|
|
31
|
+
# measure 1 - create alternatives
|
|
32
|
+
# choice 96
|
|
33
|
+
pitches96 = [[C3, E5], C5, G4]
|
|
34
|
+
durations96 = [EN, EN, EN]
|
|
35
|
+
choice96 = Phrase()
|
|
36
|
+
choice96.addNoteList(pitches96, durations96)
|
|
37
|
+
|
|
38
|
+
# choice 32
|
|
39
|
+
pitches32 = [[C3, E3, G4], C5, E5]
|
|
40
|
+
durations32 = [EN, EN, EN]
|
|
41
|
+
choice32 = Phrase()
|
|
42
|
+
choice32.addNoteList(pitches32, durations32)
|
|
43
|
+
|
|
44
|
+
# choice 40
|
|
45
|
+
pitches40 = [[C3, E3, C5], B4, C5, E5, G4, C5]
|
|
46
|
+
durations40 = [SN, SN, SN, SN, SN, SN]
|
|
47
|
+
choice40 = Phrase()
|
|
48
|
+
choice40.addNoteList(pitches40, durations40)
|
|
49
|
+
|
|
50
|
+
# measure 2 - create alternatives
|
|
51
|
+
# choice 6 (same as choice 32)
|
|
52
|
+
choice6 = Phrase()
|
|
53
|
+
choice6.addNoteList(pitches32, durations32)
|
|
54
|
+
|
|
55
|
+
# choice 17
|
|
56
|
+
pitches17 = [[E3, G3, C5], G4, C5, E5, G4, C5]
|
|
57
|
+
durations17 = [SN, SN, SN, SN, SN, SN]
|
|
58
|
+
choice17 = Phrase()
|
|
59
|
+
choice17.addNoteList(pitches17, durations17)
|
|
60
|
+
|
|
61
|
+
# measure 3 - create alternatives
|
|
62
|
+
# choice 141
|
|
63
|
+
pitches141 = [[B2, G3, D5], E5, F5, D5, [G2, C5], B4]
|
|
64
|
+
durations141 = [SN, SN, SN, SN, SN, SN]
|
|
65
|
+
choice141 = Phrase()
|
|
66
|
+
choice141.addNoteList(pitches141, durations141)
|
|
67
|
+
|
|
68
|
+
# choice 158
|
|
69
|
+
pitches158 = [[G2, B4], D5, B4, A4, G4]
|
|
70
|
+
durations158 = [EN, SN, SN, SN, SN]
|
|
71
|
+
choice158 = Phrase()
|
|
72
|
+
choice158.addNoteList(pitches158, durations158)
|
|
73
|
+
|
|
74
|
+
# measure 4 - create alternatives
|
|
75
|
+
# choice 30
|
|
76
|
+
pitches30 = [[C5, G4, E4, C4, C2]]
|
|
77
|
+
durations30 = [DQN]
|
|
78
|
+
choice30 = Phrase()
|
|
79
|
+
choice30.addNoteList(pitches30, durations30)
|
|
80
|
+
|
|
81
|
+
# choice 5
|
|
82
|
+
pitches5 = [[C2, C5, G4, E4, C4], [G2, B4], [C2, E4, C5]]
|
|
83
|
+
durations5 = [SN, SN, QN]
|
|
84
|
+
choice5 = Phrase()
|
|
85
|
+
choice5.addNoteList(pitches5, durations5)
|
|
86
|
+
|
|
87
|
+
# roll the dice!!!
|
|
88
|
+
measure1 = choice([choice96, choice32, choice40])
|
|
89
|
+
measure2 = choice([choice6, choice17])
|
|
90
|
+
measure3 = choice([choice141, choice158])
|
|
91
|
+
measure4 = choice([choice30, choice5])
|
|
92
|
+
|
|
93
|
+
# connect the random measures into a waltz excerpt
|
|
94
|
+
walzerteil.addPhrase(measure1)
|
|
95
|
+
walzerteil.addPhrase(measure2)
|
|
96
|
+
walzerteil.addPhrase(measure3)
|
|
97
|
+
walzerteil.addPhrase(measure4)
|
|
98
|
+
|
|
99
|
+
# view and play randomly generated waltz excerpt
|
|
100
|
+
View.sketch(walzerteil)
|
|
101
|
+
Play.midi(walzerteil)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# PierreCage.StructuresPourDeuxChances.py
|
|
2
|
+
#
|
|
3
|
+
# This program (re)creates pieces similar to:
|
|
4
|
+
#
|
|
5
|
+
# Pierre Boulez, "Structures I for two pianos", and
|
|
6
|
+
# John Cage, "Music of Changes, Book I".
|
|
7
|
+
#
|
|
8
|
+
# The piece generated consists of two parallel phrases containing
|
|
9
|
+
# notes with random pitch and duration.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
from music import *
|
|
13
|
+
from random import * # import random number generator
|
|
14
|
+
|
|
15
|
+
numberOfNotes = 100 # how many notes in each parallel phrase
|
|
16
|
+
|
|
17
|
+
##### define the data structure
|
|
18
|
+
part = Part() # create an empty part
|
|
19
|
+
melody1 = Phrase(0.0) # create phrase (at beginning of piece)
|
|
20
|
+
melody2 = Phrase(0.0) # create phrase (at beginning of piece)
|
|
21
|
+
|
|
22
|
+
##### create musical data
|
|
23
|
+
# create random notes for first melody
|
|
24
|
+
for i in range(numberOfNotes):
|
|
25
|
+
pitch = randint(C1, C7) # get random pitch between C1 and C6
|
|
26
|
+
duration = random() * 1.0 # get random duration (0.0 to 2.0)
|
|
27
|
+
dynamic = randint(PP, FFF) # get random dynamic between P and FF
|
|
28
|
+
note = Note(pitch, duration, dynamic) # create note
|
|
29
|
+
melody1.addNote(note) # and add it to the phrase
|
|
30
|
+
# now, melody1 has been created
|
|
31
|
+
|
|
32
|
+
# create random notes for second melody
|
|
33
|
+
for i in range(numberOfNotes):
|
|
34
|
+
pitch = randint(C1, C7) # get random pitch between C1 and C6
|
|
35
|
+
duration = random() * 1.0 # get random duration (0.0 to 2.0)
|
|
36
|
+
dynamic = randint(PP, FFF) # get random dynamic between P and FF
|
|
37
|
+
note = Note(pitch, duration, dynamic) # create note
|
|
38
|
+
melody2.addNote(note) # and add it to the phrase
|
|
39
|
+
# now, melody2 has been created
|
|
40
|
+
|
|
41
|
+
##### combine musical material
|
|
42
|
+
part.addPhrase(melody1)
|
|
43
|
+
part.addPhrase(melody2)
|
|
44
|
+
|
|
45
|
+
##### play and write part to a MIDI file
|
|
46
|
+
Play.midi(part)
|
|
47
|
+
Write.midi(part, "Pierre Cage.Structures pour deux chances.mid")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# RGB_Display.py
|
|
2
|
+
#
|
|
3
|
+
# Demonstrates how to use sliders to update values in real time (here, the
|
|
4
|
+
# background color of the display). It also uses labels to provide additional
|
|
5
|
+
# feedback and visibility (by showing updated RGB values).
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
from gui import *
|
|
9
|
+
|
|
10
|
+
# create display
|
|
11
|
+
d = Display("RGB Display", 600, 400)
|
|
12
|
+
|
|
13
|
+
# initialize RGB values (0-255)
|
|
14
|
+
red = 255
|
|
15
|
+
green = 255
|
|
16
|
+
blue = 255
|
|
17
|
+
|
|
18
|
+
# initialize display background to these RGB values
|
|
19
|
+
d.setColor( Color(red, green, blue) )
|
|
20
|
+
|
|
21
|
+
# create labels for the sliders with black text and white background
|
|
22
|
+
labelRed = Label(" R ", CENTER, Color.BLACK, Color.WHITE)
|
|
23
|
+
labelGreen = Label(" G ", CENTER, Color.BLACK, Color.WHITE)
|
|
24
|
+
labelBlue = Label(" B ", CENTER, Color.BLACK, Color.WHITE)
|
|
25
|
+
|
|
26
|
+
# add labels to display
|
|
27
|
+
d.add(labelRed, 180, 132)
|
|
28
|
+
d.add(labelGreen, 180, 182)
|
|
29
|
+
d.add(labelBlue, 180, 232)
|
|
30
|
+
|
|
31
|
+
# create labels for the sliders' values with black text and white background
|
|
32
|
+
labelRedValue = Label(" " + str(red) + " ", CENTER, Color.BLACK, Color.WHITE)
|
|
33
|
+
labelGreenValue = Label(" " + str(green) + " ", CENTER, Color.BLACK, Color.WHITE)
|
|
34
|
+
labelBlueValue = Label(" " + str(blue) + " ", CENTER, Color.BLACK, Color.WHITE)
|
|
35
|
+
|
|
36
|
+
# add labels for values to display
|
|
37
|
+
d.add(labelRedValue, 400, 132)
|
|
38
|
+
d.add(labelGreenValue, 400, 182)
|
|
39
|
+
d.add(labelBlueValue, 400, 232)
|
|
40
|
+
|
|
41
|
+
# define function to update red value
|
|
42
|
+
def setRed(value):
|
|
43
|
+
global d, red, green, blue, labelRedValue
|
|
44
|
+
|
|
45
|
+
red = value # update red value
|
|
46
|
+
labelRedValue.setText(" " + str(red) + " ") # update red value label
|
|
47
|
+
d.setColor(Color(red, green, blue)) # update background color
|
|
48
|
+
|
|
49
|
+
# define function to update green value
|
|
50
|
+
def setGreen(value):
|
|
51
|
+
global d, red, green, blue, labelGreenValue
|
|
52
|
+
|
|
53
|
+
green = value # update green value
|
|
54
|
+
labelGreenValue.setText(" " + str(green) + " ") # update green value label
|
|
55
|
+
d.setColor(Color(red, green, blue)) # set background color
|
|
56
|
+
|
|
57
|
+
# define function to update blue value
|
|
58
|
+
def setBlue(value):
|
|
59
|
+
global d, red, green, blue, labelBlueValue
|
|
60
|
+
|
|
61
|
+
blue = value # update blue value
|
|
62
|
+
labelBlueValue.setText(" " + str(blue) + " ") # update blue value label
|
|
63
|
+
d.setColor(Color(red, green, blue)) # set background color
|
|
64
|
+
|
|
65
|
+
# create sliders to set red, green, and blue values, respectively
|
|
66
|
+
sliderRed = Slider(HORIZONTAL, 0, 255, red, setRed)
|
|
67
|
+
sliderGreen = Slider(HORIZONTAL, 0, 255, green, setGreen)
|
|
68
|
+
sliderBlue = Slider(HORIZONTAL, 0, 255, blue, setBlue)
|
|
69
|
+
|
|
70
|
+
# add sliders to display
|
|
71
|
+
d.add(sliderRed, 200, 125)
|
|
72
|
+
d.add(sliderGreen, 200, 175)
|
|
73
|
+
d.add(sliderBlue, 200, 225)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# TerryRiley.InC.py
|
|
2
|
+
#
|
|
3
|
+
# Live coding performance of Terry Riley's "In C".
|
|
4
|
+
# See http://www.flagmusic.com/content/clips/inc.pdf
|
|
5
|
+
|
|
6
|
+
from music import *
|
|
7
|
+
from timer import *
|
|
8
|
+
|
|
9
|
+
# redefine these notes at will
|
|
10
|
+
pitches = [E4, F4, E4]
|
|
11
|
+
durations = [SN, SN, EN]
|
|
12
|
+
|
|
13
|
+
# play above pitches and durations in a continuous loop
|
|
14
|
+
def loopMusic():
|
|
15
|
+
|
|
16
|
+
global pitches, durations
|
|
17
|
+
|
|
18
|
+
# create phrase from current pitches and durations
|
|
19
|
+
theme = Phrase()
|
|
20
|
+
theme.addNoteList( pitches, durations )
|
|
21
|
+
|
|
22
|
+
# play it
|
|
23
|
+
Play.midi( theme )
|
|
24
|
+
|
|
25
|
+
# get duration of phrase in millisecs (assume 60BPM)
|
|
26
|
+
duration = int( theme.getBeatLength() * 1000 )
|
|
27
|
+
|
|
28
|
+
# create and start timer to call this function
|
|
29
|
+
# once recursively, after the elapsed duration
|
|
30
|
+
t = Timer( duration, loopMusic, [], False )
|
|
31
|
+
t.start()
|
|
32
|
+
|
|
33
|
+
# start playing
|
|
34
|
+
loopMusic()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# arpeggiator1.py
|
|
2
|
+
#
|
|
3
|
+
# A basic arpeggiator using absolute pitches.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
from music import *
|
|
7
|
+
|
|
8
|
+
arpeggioPattern = [C4, E4, G4, C5, G4, E4] # arpeggiate the C chord
|
|
9
|
+
duration = TN # duration for each note
|
|
10
|
+
|
|
11
|
+
repetitions = input("How many times to repeat arpeggio: ")
|
|
12
|
+
|
|
13
|
+
arpeggioPhrase = Phrase(0.0) # phrase to store the arpeggio
|
|
14
|
+
|
|
15
|
+
# create arpeggiated sequence of notes
|
|
16
|
+
for pitch in arpeggioPattern:
|
|
17
|
+
n = Note(pitch, duration) # create note with next pitch
|
|
18
|
+
arpeggioPhrase.addNote(n) # and add it to phrase
|
|
19
|
+
|
|
20
|
+
# now, the arpeggiation pattern has been created.
|
|
21
|
+
|
|
22
|
+
# repeat it as many times requested
|
|
23
|
+
Mod.repeat(arpeggioPhrase, repetitions)
|
|
24
|
+
|
|
25
|
+
# add final note to complete arpeggio
|
|
26
|
+
lastPitch = arpeggioPattern[0] # use first pitch as last pitch
|
|
27
|
+
n = Note(lastPitch, duration * 2) # using longer duration
|
|
28
|
+
arpeggioPhrase.addNote(n) # add it
|
|
29
|
+
|
|
30
|
+
Play.midi(arpeggioPhrase)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# arpeggiator2.py
|
|
2
|
+
#
|
|
3
|
+
# A basic arpeggiator using relative pitches.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
from music import *
|
|
7
|
+
|
|
8
|
+
arpeggioPattern = [0, 4, 7, 12, 7, 4] # arpeggiate a major chord
|
|
9
|
+
duration = TN # duration for each note
|
|
10
|
+
|
|
11
|
+
rootPitch = input("Enter root note (e.g., C4): ")
|
|
12
|
+
repetitions = input("How many times to repeat arpeggio: ")
|
|
13
|
+
|
|
14
|
+
arpeggioPhrase = Phrase(0.0) # phrase to store the arpeggio
|
|
15
|
+
|
|
16
|
+
# create arpeggiated sequence of notes
|
|
17
|
+
for interval in arpeggioPattern:
|
|
18
|
+
pitch = rootPitch + interval # calculate absolute pitch
|
|
19
|
+
n = Note(pitch, duration) # create note with next pitch
|
|
20
|
+
arpeggioPhrase.addNote(n) # and add it to phrase
|
|
21
|
+
|
|
22
|
+
# now, the arpeggiation pattern has been created.
|
|
23
|
+
|
|
24
|
+
# repeat it as many times requested
|
|
25
|
+
Mod.repeat(arpeggioPhrase, repetitions)
|
|
26
|
+
|
|
27
|
+
# add final note to complete arpeggio
|
|
28
|
+
lastPitch = rootPitch + arpeggioPattern[0] # close with first pitch
|
|
29
|
+
n = Note(lastPitch, duration * 4) # but with longer duration
|
|
30
|
+
arpeggioPhrase.addNote(n) # add it
|
|
31
|
+
|
|
32
|
+
Play.midi(arpeggioPhrase)
|