Skip to main content

🎵 SongChain 🔗

Coverage Tests

LangChain made it easy to string together language models and their data processing. SongChain does the same for music models — voice, audio, and MIDI-based generation — so musicians and developers can compose AI music pipelines as easily as language pipelines.

Key differences from language chaining:

  • Focus on audio rather than language: musicians work with audio and MIDI clips, and craft songs from variations of them
  • Audio and MIDI need their own encodings: clips expose waveforms, spectrograms, piano rolls, note sequences, and EnCodec tokens — the representations music models actually consume
  • Chaining is temporal too: outputs are concatenated, layered, and looped in time to craft larger pieces

Installation

Into your own project (not yet on PyPI — install from GitHub or a local clone):

pip install git+https://github.com/asampat3090/songchain.git   # from GitHub
pip install /path/to/songchain                                  # from a local clone

# optional model backends (work with either form)
pip install "songchain[generation] @ git+https://github.com/asampat3090/songchain.git"   # MusicGen / AudioGen
pip install "/path/to/songchain[transcription]"                  # Basic Pitch, Pop2Piano

For working on songchain itself:

git clone https://github.com/asampat3090/songchain.git && cd songchain
pip install -e ".[dev]"

Then in your downstream code:

# my_project/make_jingle.py
from songchain import Chain, PromptTemplate, concat
from songchain.models import NoteSequence, Transpose, MIDISynth, Fade

jingle_chain = Chain([
    PromptTemplate("{n1}5:0.2 {n2}5:0.2 {n3}5:0.2 {n3}5:0.6"),
    NoteSequence(),
    Transpose(semitones=-5),
    MIDISynth(sample_rate=22050),
    Fade(fade_out=0.3),
])

a = jingle_chain.run(n1="C", n2="E", n3="G")
b = jingle_chain.run(n1="D", n2="F", n3="A")
concat([a, b], crossfade=0.05).save("jingle.wav")

Quickstart

Chain a prompt through MIDI generation, transformation, and synthesis to audio — no pretrained models needed:

from songchain import Chain, PromptTemplate
from songchain.models import NoteSequence, Transpose, MIDISynth, Fade

chain = Chain([
    PromptTemplate("{root}4 {third}4 {fifth}4 {root}5:1.0"),
    NoteSequence(duration=0.25),     # text  -> MIDI
    Transpose(semitones=-12),        # MIDI  -> MIDI
    MIDISynth(sample_rate=44100),    # MIDI  -> audio
    Fade(fade_out=0.5),              # audio -> audio
])

clip = chain.run(root="C", third="E", fifth="G")
clip.save("arpeggio.wav")

Generate music with a pretrained model (requires [generation]):

from songchain import Chain, PromptTemplate, concat
from songchain.models import MusicGen

chain = Chain([
    PromptTemplate("{genre} beat with {mood} vibes, {bpm} BPM"),
    MusicGen(size="small", duration=8.0),
])

verse = chain.run(genre="lofi", mood="chill", bpm=80)
chorus = chain.run(genre="lofi", mood="uplifting", bpm=80)
song = concat([verse, chorus, verse], crossfade=0.5)
song.save("song.wav")

Chains validate modalities up front — a MIDI model feeding an audio effect fails at construction time, before any weights load. Compose chains with |: Chain([...]) | MIDISynth().

Data: AudioClip and MIDIClip

Clips wrap a file (or in-memory data) and expose every ML representation, so models can be swapped without rewriting preprocessing:

from songchain import AudioClip, MIDIClip

audio = AudioClip("song.wav")
audio.waveform          # (channels x frames) float32 tensor
audio.spectrogram       # STFT power spectrogram
audio.mel_spectrogram   # mel-scaled spectrogram
audio.encodec           # EnCodec discrete codes (requires [generation])
audio.to_mono().resample(32000).slice(0, 10).save("intro.wav")

midi = MIDIClip("melody.mid")
midi.pianoroll(type="binary")     # (128 x steps) — MidiNet, MuseGAN style
midi.pianoroll(type="velocity")   # velocity-aware — Music Transformer style
midi.notes(type="index")          # monophonic — MelodyRNN, MusicVAE style
midi.notes(type="note")           # note names — DeepBach style
midi.transpose(5).time_stretch(0.5).synthesize().save("variation.wav")

Models

All models share one interface — declare input/output modality, implement generate — and register by name (get_model("musicgen", duration=8.0)).

Model Chain Backend Extra
NoteSequence text → MIDI built-in —
Transpose, MIDITimeStretch MIDI → MIDI built-in —
MIDISynth MIDI → audio built-in —
Gain, Reverse, Fade audio → audio built-in —
MusicGen text → audio Meta audiocraft [generation]
AudioGen text → audio Meta audiocraft [generation]
BasicPitch audio → MIDI Spotify basic-pitch [transcription]
Pop2Piano audio → MIDI HuggingFace [transcription]

Add your own by subclassing a base (e.g. TextToAudioModel) and decorating with @register("name").

Temporal composition

from songchain import concat, overlay, loop, concat_midi

track = concat([intro, verse, chorus], crossfade=0.25)  # join in time
mix = overlay([drums, bass, melody])                    # layer tracks
beat = loop(bar, times=8)                               # repeat
medley = concat_midi([melody_a, melody_b])              # join MIDI

Dataset preparation

Split songs into fixed-size chunks with text descriptions — the layout audiocraft-style fine-tuning expects:

from songchain.util import split_audio_and_save

split_audio_and_save(30, "my_songs/", "chill bollywood beats with vocals")
# -> my_songs/output/000_000.wav, 000_000.txt, ...

End-to-end example

examples/make_song.py composes a complete short song — a four-chord progression (C–Am–F–G) with an arpeggiated melody chain overlaid on a bass chain, arranged bar-by-bar, looped, and faded — and writes both the audio and the MIDI:

python examples/make_song.py
# wrote ./song.wav (15.7s) and ./song.mid

This exact workflow is verified by the integration tests in tests/test_integration.py, which run the example and assert the artifacts are real: audible audio at the right duration, and MIDI that reloads with the full arrangement and can itself be fed back into a chain.

Development

pip install -e ".[dev]"
pytest --cov=songchain          # run tests with coverage
coverage-badge -o coverage.svg -f  # refresh the badge
black songchain tests && flake8    # format + lint

The test suite runs without any heavy model downloads — pretrained backends are exercised through fakes.

Metadata

Release files for songchain 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for songchain 0.2.0
File Size Uploaded Provenance Actions
songchain-0.2.0.tar.gz 27.3 kB With provenance Details for songchain-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for songchain 0.2.0
File Interpreter ABI Platform Actions
songchain-0.2.0-py3-none-any.whl Python 3 none any Details for songchain-0.2.0-py3-none-any.whl

Total release size: 48.9 kB

Release files / songchain-0.2.0.tar.gz

Download URL songchain-0.2.0.tar.gz
Size 27.3 kB
Tags Source
SHA-256 checksum
How to use checksums
677b0574aabf8d8082950c9820d1b5dbf6ac25fe36c02584f39acf6eaa01dacb
BLAKE2b-256 checksum
How to use checksums
10aef84f742de2ff6d65b852d302f07c9fbef90c6911968a966837ff11b17f9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 10, 2026.

Transparency log

Release files / songchain-0.2.0-py3-none-any.whl

Download URL songchain-0.2.0-py3-none-any.whl
Size 21.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
829434370736e3059d6b075c0a92400c1e9ad72527ba87b219e1922b62ad08d6
BLAKE2b-256 checksum
How to use checksums
babd7c4e2f0a187275fa0b483f4274ae37a2f3c12086c2fab30b350eb7bd1afa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 10, 2026.

Transparency log

Security for songchain 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for songchain-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 10, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page