OmniSinger

OmniSinger is a fine-tuned OmniVoice checkpoint that generates singing from text with explicit note and duration control. It is used exactly like a regular OmniVoice checkpoint. The only difference is the input text format, described below.

Give it a short reference clip for the voice, a lyric line annotated with pitch and duration per word, and it sings the line in that voice.

Installation

pip install omnivoice soundfile torch

Quick start

import re

import soundfile as sf
import torch
from omnivoice import OmniVoice


def compute_duration_from_text(text: str) -> float:
    """Sum every `pitch:duration` pair in the text (centiseconds) -> seconds."""
    matches = re.findall(r"-?\d+:(\d+)", text)
    if not matches:
        raise ValueError("No {pitch:duration} tags found in text.")
    return sum(int(d) for d in matches) / 100.0


model = OmniVoice.from_pretrained(
    "mindvu/OmniSinger",  # this repo
    device_map="cuda:0",
    dtype=torch.float16,
)
# Apple Silicon: device_map="mps"
# Intel Arc GPU: device_map="xpu"

text = (
    "[singing] <silence>{0:28} hold{68:144} me{67:33} close{65:73} and{63:50} "
    "hold{59:30} me{69:36} fast{68:114} <silence>{0:45} the{65:24} magic{63:92} "
    "spell{56:45} you{66:40} cast{63:110} <silence>{0:45}"
)

duration = compute_duration_from_text(text)
print(f"Target duration: {duration:.2f}s")

audio = model.generate(
    text=text,
    ref_audio="reference.mp3",   # short clip of the voice you want
    # ref_text="Transcript of the reference clip.",  # optional, see below
    duration=duration,           # must match the total of the tags
    postprocess_output=False,
)  # list of np.ndarray, shape (T,), 24 kHz

sf.write("out.wav", audio[0], 24000)

If you omit ref_text, the transcript of the reference audio is obtained automatically with Whisper ASR.

Input text format

The text is a lyric line where every word carries a note tag and rests are written as <silence> tags.

[singing] word{pitch:duration} word{pitch:duration} <silence>{0:duration} ...
Element Meaning
[singing] Required prefix that switches the model to singing mode.
word{P:D} A sung word. P is the pitch as a MIDI note number (e.g. 60 = C4, 69 = A4). D is the note length in centiseconds (1/100 s).
<silence>{0:D} A rest of D centiseconds. Pitch is always 0.
word{P1:D1,P2:D2} Melisma: one word sung over several notes, as comma-separated pitch:duration pairs.

Examples:

hold{68:144}              -> "hold" on note 68 for 1.44 s
<silence>{0:28}           -> 0.28 s rest
baby{60:104,65:104}       -> "baby" sung as two notes, 1.04 s each

Setting duration

duration (seconds) should equal the sum of all durations in the text, including silences and every note of a melisma. The helper compute_duration_from_text in the quick start does this for you:

total_seconds = sum(all D values) / 100

More examples

English with melisma

text = "[singing] <silence>{0:76} baby{60:69,65:139} i'm{59:20,55:21} <silence>{0:132} dancing{70:97,64:37} in{65:26} the{67:26} dark{60:48} <silence>{0:114} with{54:28} you{69:70} between{63:94} my{62:58} arms{56:42} <silence>{0:33}"

Vietnamese

text = "[singing] <silence>{0:28} bèo{68:144} dạt{67:33} mây{65:73} trôi{63:50} chốn{59:30} xa{69:36} xôi{68:114} <silence>{0:45} anh{65:24} ơi{63:92} em{56:45} vẫn{66:40} đợi{66:110} <silence>{0:45}"

Mixed Vietnamese / English

text = "[singing] <silence>{0:28} ôm{68:144} em{67:33} gần{65:73} và{63:50} cầm{59:30} tay{69:36} em{68:114} <silence>{0:45} the{65:24} magic{63:92} spell{56:45} you{66:40} cast{63:110} <silence>{0:45}"

Tips

  • Reference audio: use a clean clip of a single speaker or singer, a few seconds to ~15 s. The output timbre follows it.
  • Sync of notes and lyrics: every word needs a tag. Words without {pitch:duration} will not be timed correctly.
  • Short phrases work best: split long songs into lines or phrases and generate them one at a time, then concatenate the audio.
  • Rests matter: explicit <silence> tags at phrase boundaries give the most natural breathing and phrasing.
  • Plain speech: OmniSinger can still be prompted like a normal OmniVoice model by leaving out [singing] and the note tags (and not passing a tag-derived duration), though it is optimized for singing.

Output

model.generate returns a list of NumPy arrays (one per input), mono, 24 kHz:

sf.write("out.wav", audio[0], 24000)

License

Please see the license section of the base OmniVoice model and of the data this checkpoint was fine-tuned on.

Disclaimer

Users are strictly prohibited from using this model for unauthorized voice cloning, voice impersonation, fraud, scams, or any other illegal or unethical activities. All users shall ensure full compliance with applicable local laws, regulations, and ethical standards. The developers assume no liability for any misuse of this model and advocate for responsible AI development and use, encouraging the community to uphold safety and ethical principles in AI research and applications.

Downloads last month
3
Safetensors
Model size
0.6B params
Tensor type
I64
·
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support