Skip to main content

Retro game music generation library with semantic API for 8-bit/16-bit style MIDI and audio composition

Project description

Banner

flexinfer-chiptune

A Python library for generating 8-bit/16-bit style music and sound effects with a semantic API that agents can use to programmatically compose music. Supports both MIDI export and direct audio synthesis with authentic retro chip waveforms.

Features

  • Music Theory Foundation: Scales, chords, arpeggios with emotion-to-music mapping
  • Game Theme Templates: Pre-built patterns for battle, boss, victory, overworld, etc.
  • Multiple Chip Systems: NES 2A03, Game Boy DMG, C64 SID, and Sega Genesis FM
  • Audio Effects: Vibrato, tremolo, echo, chorus, tape delay, and effect chains
  • Procedural Generation: Markov-based melodies, auto bass lines, countermelodies
  • Adaptive Intensity: Dynamic music that responds to game state (0.0-1.0)
  • Preset Library: One-liner genre presets, effect chains, and quick composers
  • CLI Tool: Generate music from the command line
  • Agent-Friendly API: Natural language context to music generation
  • Dual Export: MIDI files or direct WAV synthesis

Installation

pip install flexinfer-chiptune

Or with uv:

uv add flexinfer-chiptune

For audio playback support:

pip install flexinfer-chiptune[audio]

Quick Start

Command Line Interface

# Generate a battle theme
chiptune generate --preset battle --output battle.wav

# Generate with custom settings
chiptune generate --preset overworld --root G --bpm 130 --bars 16 --effects space

# Generate a sound effect
chiptune sfx coin --output coin.mid

# List all available presets
chiptune list all

Using Genre Presets

from chiptune.presets import GenrePresets, QuickCompose

# One-liner battle track with drums
composer = QuickCompose.battle_track(length_bars=16)
track = composer.build()

# Pre-configured genre composers
battle = GenrePresets.battle_theme()       # A minor, 165 BPM
overworld = GenrePresets.overworld()       # C major, 120 BPM
dungeon = GenrePresets.dungeon()           # E dorian, 85 BPM
title = GenrePresets.title_screen()        # F major, 130 BPM
chase = GenrePresets.chase_scene()         # E phrygian, 185 BPM

Using the Composer API

from chiptune import ChiptuneComposer, AudioExporter
from chiptune.presets import EffectPresets

# Create a heroic battle theme
composer = ChiptuneComposer.create(bpm=150, root="A", mode="minor")
composer.set_progression(["i", "VII", "VI", "V"])
composer.add_melody(length_bars=8, contour="ascending")
composer.add_countermelody(motion="contrary")
composer.add_bass(style="octave")
composer.add_drums(pattern="driving")

# Build and export with effects
track = composer.build()
effects = EffectPresets.retro_gaming()

exporter = AudioExporter()
exporter.export_wav(track, "battle_theme.wav", effects=effects)

Audio Effects

from chiptune.output.audio.effects import (
    Tremolo, Vibrato, Echo, TapeDelay, Chorus, EffectChain
)

# Individual effects
tremolo = Tremolo(rate=5.0, depth=0.3)
echo = Echo(delay_time=0.25, feedback=0.5)
chorus = Chorus.lush()

# Chain effects together
chain = EffectChain(effects=[
    Tremolo.subtle(),
    Chorus.classic(),
    Echo.medium(),
])

# Or use the | operator
chain = Tremolo() | Chorus.subtle() | Echo.short()

# Apply to audio
output = chain.process(samples, sample_rate=44100)

Effect Presets

from chiptune.presets import EffectPresets

# Pre-built effect chains
clean = EffectPresets.clean()           # No effects
retro = EffectPresets.retro_gaming()    # Subtle chorus + echo
space = EffectPresets.space_adventure() # Lush chorus + space delay
lofi = EffectPresets.lo_fi_nostalgia()  # Tape delay + tremolo
arcade = EffectPresets.arcade_cabinet() # Chorus + slapback
dreamy = EffectPresets.dreamy()         # Heavy modulation effects
dungeon = EffectPresets.dungeon_reverb() # Cavernous echo
boss = EffectPresets.boss_battle()       # Punchy minimal effects

Procedural Melody Generation

from chiptune.generation import (
    MarkovMelodyGenerator, MelodyStyle,
    BassGenerator, CountermelodyGenerator,
    IntensityProfile, IntensityController
)

# Generate melody from Markov chain
gen = MarkovMelodyGenerator(order=2)
gen.train_from_midi_pitches([60, 62, 64, 65, 67, 65, 64, 62, 60])
notes = gen.generate(16, start_pitch=60)

# Use style presets
heroic = MelodyStyle.heroic()
mysterious = MelodyStyle.mysterious()
chiptune = MelodyStyle.chiptune()

# Auto-generate bass lines
bass_gen = BassGenerator.jazz()
bass_notes = bass_gen.generate(chords, beats_per_chord=4)

# Generate countermelody
counter_gen = CountermelodyGenerator.contrary()
counter = counter_gen.generate(melody, scale=scale)

Adaptive Intensity

from chiptune.generation import IntensityProfile, IntensityController

# Intensity profiles for different game states
calm = IntensityProfile.calm()           # Low, steady
building = IntensityProfile.building()    # Gradually increasing
battle = IntensityProfile.battle()        # High, volatile
boss = IntensityProfile.boss_fight()      # Maximum intensity

# Controller maps intensity to musical parameters
controller = IntensityController.action()
tempo = controller.get_tempo(progress=0.5)      # 80-160 BPM
velocity = controller.get_velocity(progress=0.5) # 60-120
layers = controller.get_active_layers(0.5, total_layers=4)

Chip Systems

from chiptune.chip.systems import NES2A03, GameBoyChip, SIDChip, GenesisChip

# NES 2A03 (2 pulse + triangle + noise)
nes = NES2A03.create()
nes_fami = NES2A03.famitracker_style()

# Game Boy DMG
gameboy = GameBoyChip.create()

# Commodore 64 SID
sid = SIDChip.create()

# Sega Genesis YM2612 (FM synthesis)
genesis = GenesisChip.create()

Sound Effects

from chiptune import SFXGenerator

sfx = SFXGenerator()

# Generate common game sounds (returns MIDI bytes)
coin = sfx.coin_collect()
jump = sfx.jump()
explosion = sfx.explosion()
powerup = sfx.powerup()
laser = sfx.laser()
teleport = sfx.teleport()
door_open = sfx.door_open()
menu_select = sfx.menu_select()

# Save to file
sfx.save(coin, "coin.mid")

Jingles

from chiptune import Jingle

# Quick musical phrases
victory = Jingle.victory_fanfare(root="C", tempo=140)
item = Jingle.item_get(root="G")
level_up = Jingle.level_up()
game_over = Jingle.game_over()

Agent API

from chiptune import MusicAgent

agent = MusicAgent()

# Generate music from natural language context
music = agent.compose_for_context(
    context="player enters the boss arena",
    duration_seconds=30.0,
    intensity=0.9,
)

# Generate a sound effect
sfx = agent.generate_sfx("coin_collect")

CLI Reference

chiptune generate [options]
  --preset, -p    Genre preset: battle, overworld, dungeon, victory,
                  title, shop, sad, chase (default: overworld)
  --output, -o    Output file path (default: output.wav)
  --bars, -b      Length in bars (default: 8)
  --root, -r      Root note (C, D, E, F, G, A, B with optional #/b)
  --bpm           Tempo in BPM (overrides preset default)
  --effects, -e   Effect preset: clean, retro, space, lofi, arcade,
                  dreamy, dungeon, boss (default: retro)
  --format, -f    Output format: wav, midi (default: wav)
  --no-drums      Exclude drums
  --no-bass       Exclude bass
  --no-counter    Exclude countermelody
  --seed, -s      Random seed for reproducibility

chiptune sfx <type> [options]
  type            Effect type: jump, land, coin, powerup, damage,
                  explosion, laser, shield, teleport, menu_select,
                  menu_confirm, menu_back, success, error,
                  door_open, door_close, heartbeat, countdown
  --output, -o    Output file path (default: sfx.mid)

chiptune list [category]
  category        What to list: presets, effects, sfx, all (default: all)

Semantic Mappings

Emotions to Musical Elements

Emotion Scale/Mode Tempo Character
Heroic Major/Lydian Fast Driving, 4ths/5ths
Mysterious Dorian Medium Syncopated
Danger Phrygian/Locrian Fast Urgent, chromatic
Peaceful Pentatonic Slow Flowing, 3rds/6ths
Sad Minor/Aeolian Slow Simple, minor 3rds

Game Contexts to Themes

Context Characteristics
Battle Fast, minor, syncopated, driving drums
Boss Epic, chromatic, heavy bass, intense
Victory Major fanfare, I-IV-V-I, triumphant
Overworld Adventurous, major, walking bass
Dungeon Modal, sparse, atmospheric
Shop Relaxed, major, simple rhythm
Chase Very fast, phrygian, urgent

Development

# Clone the repository
git clone https://gitlab.flexinfer.ai/libs/py-chiptune.git
cd py-chiptune

# Install dependencies
uv sync

# Run tests
uv run pytest

# Type checking
uv run mypy src/chiptune

# Linting
uv run ruff check src/chiptune

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flexinfer_chiptune-0.5.2-py3-none-any.whl (113.2 kB view details)

Uploaded Python 3

File details

Details for the file flexinfer_chiptune-0.5.2-py3-none-any.whl.

File metadata

File hashes

Hashes for flexinfer_chiptune-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a136383e009d5e35d4be9abf00b846d644edd9ffc96e497aaf5b87acc35466e7
MD5 2fb271a16175a8b49da470a9d6a166a2
BLAKE2b-256 5c1ee28438c89a74aba4d136556ea259fd54f4e19feb5a26fc3653478f087b52

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page