Skip to main content

Text-to-Music Prompt Structurer

PyPI version License: MPL 2.0 CI

Convert a musical idea into separate, paste-ready Suno Custom/Advanced fields, not just a generic analysis of genres and instruments.

The engine is deterministic, offline, dependency-free and compatible with Python 3.10+. It is built using NLP-inspired parsing techniques and does not require a hosted LLM. It detects known musical characteristics from free-form text and preserves the original creative direction by default so unfamiliar arrangement details are not silently lost.

Project vision. This library is an effort to design a sophisticated, extensible music-prompting system that works effectively with Suno. Its author, Eduardo J. Barrios, brings advanced knowledge of artificial intelligence (AI), natural language processing (NLP), and large language models (LLMs) to the design of interpretable musical instructions, structured song sections, constraint extraction, and iterative prompt improvement. The goal is to make complex music prompting more systematic, expressive, and reusable.

Install

python -m pip install --upgrade "text-to-music-prompt-structurer>=0.3.0"

Version 0.3.0 improves prompt quality with automatic Exclude extraction, contextual language recognition and optional preflight validation. The Suno Custom/Advanced output introduced in 0.2.0 remains available.

If PyPI has not yet indexed v0.3.0, the GitHub release/tag also supports installation:

python -m pip install "git+https://github.com/edujbarrios/text-to-music-prompt-structurer.git@v0.3.0"

This Git install requires Git and uses the exact v0.3.0 tag.

Get Suno-ready fields (default CLI output)

text-to-music-prompt --title "Luz de madrugada" \
  --exclude "autotune" \
  --section "Intro" --cue "Intro=soft piano, no drums" \
  --section "Verse 1" --cue "Verse 1=intimate, breathy lead" \
  --section "Chorus" --cue "Chorus=full band, layered backing harmonies" \
  --section "Bridge" --section "Final Chorus" --section "Outro" \
  "neo soul with piano, nostalgic female vocals in spanish, d minor, 92 bpm"

The command prints a readable report of separate values for Suno's creation fields. The headings are not Suno metatags:

TITLE
Luz de madrugada

STYLE OF MUSIC
Neo Soul; Nostalgic mood; 92 BPM; D Minor key; Instrumentation: Piano; Vocals: Spanish-language, Female Lead; Creative direction: neo soul with piano, nostalgic female vocals in spanish, d minor, 92 bpm

LYRICS
[Intro]
[soft piano, no drums]

[Verse 1]
[intimate, breathy lead]

[Chorus]
[full band, layered backing harmonies]

[Bridge]

[Final Chorus]

[Outro]

EXCLUDE
autotune

VOCAL GENDER
Female

Copy the value under each heading into its matching Suno field. Do not paste the combined report into the Lyrics box. Bracketed section labels such as [Verse 1] and [Chorus] are common guidance markers; performance cues such as [full band] are best-effort directions, not guaranteed engine instructions.

The skeleton above intentionally contains no invented lyrics. An empty section is an editable template, not a finished song lyric. Write your own lines under the tags, supply a lyric file, or use Suno's own lyric-writing tools.

Complete custom lyrics

text-to-music-prompt \
  --lyrics-file lyrics.txt \
  --title "Luz de madrugada" \
  --exclude "electric guitar" \
  "warm neo soul, 92 bpm, female vocals in Spanish"

A UTF-8 lyrics.txt can contain existing section labels and lyrics:

[Verse 1]
La calle aún respira.
Tu nombre en el cristal.

[Chorus]
Volverá la luz.
Volverá la luz.

Its lyrics and section labels retain their exact wording (leading and trailing blank newlines are stripped); they are not translated, summarized or rewritten. Use either --lyrics-file or --section, not both.

Python API — complex sectional control

from text_to_music_prompt_structurer import (
    MusicPromptEngine,
    SunoSection,
    format_for_suno,
)

engine = MusicPromptEngine()
fields = engine.process_suno(
    "cinematic neo soul in d minor, 92 bpm, warm female vocals in spanish",
    title="Luz de madrugada",
    exclude=["autotune", "distorted guitars"],
    sections=[
        SunoSection("Intro", cue="solo electric piano, restrained ambience"),
        SunoSection("Verse 1", "La calle aún respira.", cue="intimate breathy lead"),
        SunoSection("Pre-Chorus", "Todo empieza a brillar.", cue="rising strings"),
        SunoSection("Chorus", "Volverá la luz.", cue="wide harmonies, full drums"),
        SunoSection("Bridge", "Una voz en la ciudad.", cue="half-time feel"),
        SunoSection("Final Chorus", "Volverá la luz.", cue="maximum emotional lift"),
        SunoSection("Outro", cue="piano resolves softly"),
    ],
)

print(fields.style_of_music)      # paste into Style of Music
print(fields.lyrics)              # paste into Lyrics
print(fields.exclude)             # paste into Advanced > Exclude
print(fields.vocal_gender)        # optional Vocal Gender UI control
print(format_for_suno(fields))    # readable combined presentation
payload = fields.to_dict()        # JSON-compatible values for your own app

For instrumental tracks, use --instrumental, or describe the track as instrumental and let process_suno() detect it. Instrumental mode rejects nonempty lyric lines rather than generating a contradictory request.

CLI options

Option Purpose
--format suno Separate Suno fields (default)
--format json Machine-readable object with independent Suno fields
--format legacy Preserve original STYLE/MOOD/BPM/... output
--lyrics-file FILE Supply complete UTF-8 lyrics without rewriting
--section NAME Add an editable structural section (repeatable)
--cue NAME=DIRECTION Add a direction to the named section
--exclude TEXT Fill Suno's separate Exclude control (repeatable)
--instrumental Force Instrumental on
--style-notes TEXT Additional freeform style/arrangement instruction
--no-original Do not append the original creative description
--no-auto-exclude Disable automatic negative-constraint extraction
--check Display prompt-quality issues on stderr
--max-style-chars N Optional caller-defined style budget (with --check)
--max-lyrics-chars N Optional caller-defined lyrics budget (with --check)
--title TITLE Song title

Example JSON command:

text-to-music-prompt --format json --title "Medianoche" \
  --exclude "autotune" "dreamy synthwave 110 bpm female vocals"

Prompt-quality features (v0.3.0)

Automatically extract negative musical constraints

Explicit negatives such as no drums, without autotune, avoid reverb and sin batería populate Suno's Exclude field. The negated instrument is removed from positive keyword detection and from the preserved creative summary so it does not contradict the Exclude field. The extractor uses a conservative, documented vocabulary and deliberately does not guess at open-ended negations.

from text_to_music_prompt_structurer import MusicPromptEngine

fields = MusicPromptEngine().process_suno(
    "neo soul, warm piano, 92 bpm, no drums, without autotune",
    preserve_description=False,
)
print(fields.exclude)         # Drums, Autotune
print(fields.style_of_music)  # Neo Soul; Warm mood; 92 BPM; ...

Use --no-auto-exclude to disable extraction; explicit --exclude arguments are retained. Language detection is also context-aware: Latin trap does not automatically mean Latin-language vocals, and Spanish guitar on its own does not mean Spanish-language singing.

Validate without rewriting

from text_to_music_prompt_structurer import validate_suno_prompt

issues = validate_suno_prompt(
    fields,
    max_style_chars=1000,   # your own budget, not an official Suno limit
    max_lyrics_chars=3000,
)
for issue in issues:
    print(issue.severity, issue.code, issue.message)

This checks missing styles, empty or skeleton-only lyrics, conflicting instrumental/vocal controls and optionally caller-defined length budgets. It never rewrites existing lyrics, and returns machine-readable issue codes.

From the CLI, use --check for diagnostics on stderr while retaining clean prompt output on stdout (including valid JSON):

text-to-music-prompt --format json --check \
  --max-style-chars 1000 "cinematic neo soul without drums"

Automated releases to GitHub and PyPI

Publishing runs through .github/workflows/release.yml whenever the package version is updated in pyproject.toml on main. It tests, lints, builds and checks artifacts, then publishes to PyPI through GitHub Actions OIDC Trusted Publishing. A GitHub release with wheel and source distribution is also created. PyPI must first have a matching Trusted Publisher under the project's Publishing settings: owner edujbarrios, repository text-to-music-prompt-structurer, workflow release.yml, environment pypi. There is no need for a long-lived PyPI token.

Outputs and migration

  • Suno human-readable report: default CLI mode; paste values individually into Suno.
  • JSON: --format json keeps style_of_music, lyrics, title, exclude, instrumental, vocal_gender and lyric_brief as independent properties.
  • Legacy analysis: --format legacy or Python format_prompt() for existing integrations that need the STYLE/MOOD/BPM report.

A title is optional; exclude and instrumental are Advanced controls in Suno, not strings to paste inside lyrics. vocal_gender is a suggested UI control when unambiguous vocal type is detected. lyric_brief is not a Suno lyrics field.

Legacy API / compatibility

MusicPromptEngine().process(text) still returns the existing MusicPrompt dataclass with detected genre, subgenre, mood, BPM, key, instruments, production, language, voice type, vocal style, rhythm, structure, era and theme. format_prompt(prompt) still generates the previous STYLE: ...\nMOOD: ... analysis view.

Changed in 0.2: format_for_suno(prompt) now renders actual Suno fields instead of aliasing format_prompt(). The CLI defaults to Suno fields, but --format legacy retains its previous display.

SunoPrompt and SunoPromptEngine remain aliases of the original MusicPrompt and MusicPromptEngine. Use SunoFields when you need paste-ready Suno controls.

An optional lyric_brief in SunoFields is explicitly a theme brief for a lyric-generation tool. It is not auto-inserted into Lyrics because prose requests may be sung literally.

Supported and unsupported behavior

This package does not connect to Suno, generate audio, guarantee exact timing, guarantee every section cue will be obeyed, or use an LLM to write new lyrics. Some free-form details are outside its keyword vocabulary; the original source sentence is preserved as additional musical guidance unless --no-original is set. Manually review ambiguous instructions or contradictory constraints before pasting into Suno.

Official source references for the field design and conventions:

Development

git clone https://github.com/edujbarrios/text-to-music-prompt-structurer.git
cd text-to-music-prompt-structurer
python -m pip install -e ".[dev]"
python -m pytest
ruff check .

See CONTRIBUTING.md to extend the vocabularies.

License

Copyright © 2026 Eduardo J. Barrios.

Licensed under the Mozilla Public License 2.0. See NOTICE for attribution details.

Metadata

Release files for text-to-music-prompt-structurer 0.3.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 text-to-music-prompt-structurer 0.3.0
File Size Uploaded
text_to_music_prompt_structurer-0.3.0.tar.gz 48.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for text-to-music-prompt-structurer 0.3.0
File Interpreter ABI Platform
text_to_music_prompt_structurer-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 94.5 kB

Release files / text_to_music_prompt_structurer-0.3.0.tar.gz

Download URL text_to_music_prompt_structurer-0.3.0.tar.gz
Size 48.1 kB
Tags Source
SHA-256 checksum
How to use checksums
614e3d21482064cc6bcbccf67d00c0b4d6a984f751fc81486d38d0cd290cd8b6
BLAKE2b-256 checksum
How to use checksums
4320c563a9a8c3ee36f5104c522fd1c3f4742bd059591d1caa377847c3335326
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 13, 2026.

Transparency log

Release files / text_to_music_prompt_structurer-0.3.0-py3-none-any.whl

Download URL text_to_music_prompt_structurer-0.3.0-py3-none-any.whl
Size 46.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
916f2a60508cd5982a49d903f1298865eaf47abd5878616da546debe15735b22
BLAKE2b-256 checksum
How to use checksums
7767e5024bf1f42f63f33871ec8180e7b2262122525646490863de9aa4914ea0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

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