🎵 SongChain 🔗
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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.