| name | generative-music-composer |
| description | Creates algorithmic music composition systems using procedural generation, Markov chains, L-systems, and neural approaches for ambient, adaptive, and experimental music. |
| license | MIT |
Generative Music Composer
This skill provides guidance for creating algorithmic and procedural music systems that generate compositions autonomously or semi-autonomously.
Core Competencies
- Algorithmic Composition: Rule-based music generation
- Stochastic Methods: Markov chains, probability distributions
- Formal Grammars: L-systems, generative grammars for music
- Adaptive Systems: Music that responds to input/context
- Neural Approaches: ML-based generation techniques
Generative Music Fundamentals
Generation Paradigms
| Approach | Description | Best For |
|---|
| Rule-based | Explicit compositional rules | Traditional styles, controlled output |
| Stochastic | Probability-driven selection | Natural variation, surprise |
| Grammar-based | Recursive structure generation | Complex forms, self-similarity |
| Constraint-based | Satisfy musical constraints | Harmony, voice leading |
| Learning-based | Train on corpus | Style imitation, novelty |
Musical Elements to Generate
┌─────────────────────────────────────────────────────────┐
│ Music Generation Layers │
├─────────────────────────────────────────────────────────┤
│ │
│ Macro Structure │ Form, sections, key areas │
│ ──────────────────────────────────────────────────────│
│ Harmony │ Chord progressions, voice leading │
│ ──────────────────────────────────────────────────────│
│ Melody │ Pitch sequences, contour, rhythm │
│ ──────────────────────────────────────────────────────│
│ Rhythm │ Duration patterns, meter, groove │
│ ──────────────────────────────────────────────────────│
│ Timbre/Texture │ Instrumentation, dynamics │
│ ──────────────────────────────────────────────────────│
│ Micro Variation │ Ornaments, expression, humanize │
│ │
└─────────────────────────────────────────────────────────┘
Stochastic Generation
Markov Chain Melody
import random
from collections import defaultdict
class MarkovMelodyGenerator:
"""Generate melodies using Markov chains"""
def __init__(self, order=2):
self.order = order
self.transitions = defaultdict(list)
def train(self, melodies):
"""Learn from existing melodies (lists of MIDI notes)"""
for melody in melodies:
for i in range(len(melody) - self.order):
state = tuple(melody[i:i + self.order])
next_note = melody[i + self.order]
self.transitions[state].append(next_note)
def generate(self, length, seed=None):
"""Generate a new melody"""
if seed is None:
seed = random.choice(list(self.transitions.keys()))
melody = list(seed)
for _ in range(length - self.order):
state = tuple(melody[-self.order:])
state .transitions:
next_note = random.choice(.transitions[state])
:
next_note = random.choice(
[n notes .transitions.values() n notes]
)
melody.append(next_note)
melody
Weighted Random Selection
def weighted_choice(options, weights):
"""Select with custom probability distribution"""
total = sum(weights)
r = random.uniform(0, total)
cumulative = 0
for option, weight in zip(options, weights):
cumulative += weight
if r <= cumulative:
return option
return options[-1]
scale_weights = {
1: 0.20,
2: 0.10,
3: 0.15,
4: 0.10,
5: 0.20,
6: 0.10,
7: 0.05,
8: 0.10
}
def generate_scale_melody(length, key='C', scale='major'):
degrees = list(scale_weights.keys())
weights = list(scale_weights.values())
melody = [weighted_choice(degrees, weights) for _ in (length)]
[degree_to_midi(d, key, scale) d melody]
Grammar-Based Generation
L-System for Musical Structure
class MusicalLSystem:
"""L-system for generating musical phrases"""
def __init__(self):
self.rules = {
'A': 'AB',
'B': 'CA',
'C': 'DC',
'D': 'A'
}
self.interpretations = {
'A': self._phrase_a,
'B': self._phrase_b,
'C': self._phrase_c,
'D': self._phrase_d
}
def generate_structure(self, axiom='A', iterations=4):
"""Generate formal structure"""
result = axiom
for _ in range(iterations):
result = ''.join(self.rules.get(c, c) for c in result)
return result
def realize(self, structure):
"""Convert structure to musical phrases"""
phrases = []
symbol structure:
symbol .interpretations:
phrases.append(.interpretations[symbol]())
phrases
():
generate_phrase(contour=, cadence=)
():
generate_phrase(contour=, cadence=)
():
generate_phrase(contour=, cadence=)
():
generate_phrase(contour=, cadence=)
Generative Grammar for Rhythm
class RhythmGrammar:
"""Context-free grammar for rhythm generation"""
def __init__(self):
self.rules = {
'MEASURE': [
['HALF', 'HALF'],
['QUARTER', 'QUARTER', 'QUARTER', 'QUARTER'],
['DOTTED_HALF', 'QUARTER'],
['BEAT', 'BEAT', 'BEAT', 'BEAT']
],
'HALF': [
['QUARTER', 'QUARTER'],
['half']
],
'QUARTER': [
['EIGHTH', 'EIGHTH'],
['quarter'],
['SIXTEENTH', 'SIXTEENTH', 'EIGHTH']
],
'BEAT': [
['quarter'],
['EIGHTH', 'EIGHTH'],
['TRIPLET']
],
'EIGHTH': [
['eighth'],
['SIXTEENTH', 'SIXTEENTH']
],
'TRIPLET': [
['triplet', 'triplet', 'triplet']
],
: [
[]
]
}
():
symbol .rules:
[symbol]
production = random.choice(.rules[symbol])
result = []
s production:
result.extend(.generate(s))
result
Constraint-Based Harmony
Voice Leading Rules
class HarmonyGenerator:
"""Generate chord progressions with voice leading constraints"""
def __init__(self, key='C', mode='major'):
self.key = key
self.mode = mode
self.chord_vocabulary = self._build_chords()
def generate_progression(self, length=8):
"""Generate progression satisfying constraints"""
progression = [self._tonic_chord()]
for _ in range(length - 2):
current = progression[-1]
candidates = self._valid_next_chords(current)
next_chord = self._select_chord(candidates, current)
progression.append(next_chord)
progression.append(self._dominant_chord())
progression.append(self._tonic_chord())
return progression
def _valid_next_chords(self, current):
"""Filter chords by voice leading constraints"""
candidates = []
for chord in self.chord_vocabulary:
if self._check_voice_leading(current, chord):
candidates.append(chord)
return candidates
():
._has_parallel_fifths(chord1, chord2):
._has_parallel_octaves(chord1, chord2):
._resolves_tendencies(chord1, chord2):
._excessive_movement(chord1, chord2):
Functional Harmony
PROGRESSION_TENDENCIES = {
'I': {'IV': 0.3, 'V': 0.3, 'vi': 0.2, 'ii': 0.1, 'iii': 0.1},
'ii': {'V': 0.7, 'vii': 0.2, 'IV': 0.1},
'iii': {'vi': 0.4, 'IV': 0.3, 'ii': 0.2, 'I': 0.1},
'IV': {'V': 0.4, 'I': 0.2, 'ii': 0.2, 'vii': 0.1, 'vi': 0.1},
'V': {'I': 0.6, 'vi': 0.3, 'IV': 0.1},
'vi': {'IV': 0.3, 'ii': 0.3, 'V': 0.2, 'I': 0.1, 'iii': 0.1},
'vii': {: , : , : }
}
():
progression = []
_ (length - ):
current = progression[-]
tendencies = PROGRESSION_TENDENCIES[current]
next_chord = weighted_choice(
(tendencies.keys()),
(tendencies.values())
)
progression.append(next_chord)
progression
Adaptive and Interactive Music
Parameter-Driven Generation
class AdaptiveComposer:
"""Music that responds to external parameters"""
def __init__(self):
self.parameters = {
'energy': 0.5,
'tension': 0.5,
'density': 0.5,
'tempo_factor': 1.0
}
def update_parameter(self, name, value):
self.parameters[name] = max(0, min(1, value))
def generate_measure(self):
"""Generate music adapted to current parameters"""
energy = self.parameters['energy']
tension = self.parameters['tension']
density = self.parameters['density']
note_density = int(4 + density * 12)
velocity_range = (40 + int(energy * 40), 80 + int(energy * ))
tension < :
chord_pool = [, , , ]
tension < :
chord_pool = [, , , , ]
:
chord_pool = [, , , , ]
._generate_notes(
density=note_density,
velocity_range=velocity_range,
harmonic_pool=chord_pool
)
Game Audio Adaptive System
class GameMusicSystem:
"""Layered adaptive music for games"""
def __init__(self):
self.layers = {
'ambient': {'volume': 1.0, 'active': True},
'percussion': {'volume': 0.0, 'active': False},
'melody': {'volume': 0.0, 'active': False},
'intensity': {'volume': 0.0, 'active': False}
}
self.current_state = 'exploration'
def set_game_state(self, state, transition_time=2.0):
"""Crossfade layers based on game state"""
presets = {
'exploration': {
'ambient': 1.0, 'percussion': 0.0,
'melody': 0.3, 'intensity': 0.0
},
'tension': {
'ambient': 0.7, 'percussion': 0.3,
'melody': 0.5, :
},
: {
: , : ,
: , :
},
: {
: , : ,
: , :
}
}
target = presets.get(state, presets[])
._crossfade_to(target, transition_time)
.current_state = state
Output Formats
MIDI Generation
from midiutil import MIDIFile
def create_midi(melody, filename='output.mid', tempo=120):
"""Export melody to MIDI file"""
midi = MIDIFile(1)
track = 0
channel = 0
time = 0
volume = 100
midi.addTempo(track, 0, tempo)
for note in melody:
pitch = note['pitch']
duration = note['duration']
midi.addNote(track, channel, pitch, time, duration, volume)
time += duration
with open(filename, 'wb') as f:
midi.writeFile(f)
Best Practices
Musical Coherence
- Repetition with variation: Repeat themes but vary them
- Motivic development: Transform small ideas
- Hierarchical structure: Phrases → sections → movements
- Tension and release: Build and resolve over time
Avoiding Common Pitfalls
- Pure randomness sounds chaotic—add constraints
- Too many rules sound mechanical—add stochastic variation
- Test with actual audio, not just data
- Consider performance/playability
References
references/music-theory-primer.md - Essential music theory for generation
references/markov-music.md - Advanced Markov chain techniques
references/midi-reference.md - MIDI specification and libraries