import Link from "next/link"; import type { ReactNode } from "react"; import type { Metadata } from "next"; import { SiteShell } from "@/components/site-shell"; import { mono, pre, table, td, th } from "../openontology/ui"; export const metadata: Metadata = { title: "OpenSong · LogicSRC", description: "OpenSong is one plain-text file that is a song: TITLE, STYLE, EXCLUDE STYLES and LYRICS as labelled blocks that paste straight into a music generator, [Section - direction] tags in the lyrics, no Markdown. Kept beside the audio as the same name with .txt; ID3 tags are derived from it, never the reverse.", alternates: { canonical: "/opensong" } }; const EXAMPLE = `TITLE: Who Fired First STYLE: Nordic Viking metal fused with hip-hop, drop-D down-tuned heavy guitars, pounding war drums, tagelharpa and bone flute, male baritone half-rap lead, female contralto lead, massive mixed choir, 96 BPM, call and response EXCLUDE STYLES: autotune, EDM drop, lo-fi, comedy, spoken-word only, children's choir, country, reggae LYRICS: [Cold Open - four syncopated drop-D hits with gang shouts, then silence] WHO! FIRED! FIRST! [Verse 1 - male baritone rap, fast and percussive, confident flow] Smoke on the fjord and a horn in the dark, Two longhouses burning from a single spark. Your side says theirs and their side says yours, Both sides counting bodies on the frozen shores. [Stop - all instruments stop, one whispered word] Hold. [Chorus - full impact, male and female trading lines, choir shouts, gang vocals] Who fired first? Nobody saw! Who fired first? Written in law!`; const RULES: Array<[string, string]> = [ ["Plain text", "UTF-8, no markup of any kind. Generators do not render Markdown, so the format has none."], ["Label lines", "A line on its own ending in a colon opens a block that runs to the next label. Matched without regard to case."], ["Four labels are the song", "TITLE, STYLE, EXCLUDE STYLES, LYRICS: the generator's four fields. Style descriptors are kept in order, because order is emphasis."], ["Other labels describe it", "ARTIST, ALBUM, TRACK, YEAR, LANGUAGE, MODEL, MADE BY, AUTHOR, AUDIO, NOTES. Unknown labels are kept. None of them is pasted."], ["Bracketed tags open sections", "[Name - direction]. The name is normalised for matching (verse, chorus, bridge, outro); unknown names like Cold Open are kept. A tag with nothing under it is instrumental."], ["Sung lines as written", "Capitals, punctuation and repeats reach the generator unchanged. A chorus sung three times is written three times."], ["Tags for the generator, not the listener", "A lyrics view may drop the tags. A generator always gets the whole block."], ["Albums", "NNN. Title.txt beside NNN. Title.mp3, plus an optional lyrics.txt with every song behind a ==== divider. The song file wins."] ]; const MAPPING: Array<[string, string]> = [ ["TITLE", "TIT2 / TITLE"], ["ARTIST", "TPE1 / ARTIST"], ["ALBUM", "TALB / ALBUM"], ["TRACK", "TRCK / TRACKNUMBER"], ["sung lines of LYRICS", "USLT / LYRICS"], ["the whole file", "TXXX:OPENSONG / OPENSONG"] ]; const ABSENT: Array<[string, string]> = [ ["No Markdown", "Generators take plain text. A format they cannot take is a format nobody pastes."], ["No required fields beyond the title", "A title and lyrics is a song. A title and a style is an instrumental."], ["No style vocabulary", "Genres, instruments and moods are kept as written. Models change what they understand too often for a list."], ["No timing, no chords", "Timestamps belong to the rendered audio (LRC does them). A chord chart is a different document."], ["No JSON", "The structured view is derived and regenerated from the text on every read."] ]; export default function OpenSongPage(): ReactNode { return (

LogicSRC standards surface

OpenSong

One plain-text file that is a song, in the blocks a music generator takes. Paste it in, keep it beside the audio, and the song can be made again.

A generated song starts as four fields in a web form and ends as an audio file with none of them attached. The style prompt, the exclusions and the section directions are gone once the page closes. Markdown is no help: the generator reads a # as a word. What it takes is plain text in labelled blocks with [Section] tags in the lyrics, so OpenSong fixes those labels and keeps the file.

Status: 0.1. Same rules as OpenRecipe.md: the file a person writes is canonical, every rule degrades, the structured view is derived.

The shape

Track 002 of Þrøngva, When the Ravens Lied, shortened. The full song is in the spec.

{EXAMPLE}

The eight rules

Every one of them degrades rather than fails.

{RULES.map(([rule, meaning], index) => ( ))}
Rule What it means
{index + 1}. {rule} {meaning}

Discovery

Next to the audio (002-who-fired-first.mp3 has{" "} 002-who-fired-first.txt), a{" "} {''} on the track page, or a site index at{" "} /.well-known/opensong.txt, one URL per line. Served as{" "} text/plain.

ID3 and Vorbis tags, one way

Keep writing tags for players. Generate them from the text on every export. The text file is the canonical copy, because tags have no place for the style or the directions.

{MAPPING.map(([song, tag]) => ( ))}
OpenSong ID3v2 / Vorbis comment
{song} {tag}

What is deliberately absent

{ABSENT.map(([what, why]) => ( ))}
{what} {why}

Where everything lives

); }