youtube/drehbuecher/lieder/werkzeuge/vorschau.py
Lara 69990b6c0f Stand 03.11.2026: Komponist, sechs Lieder-Entwürfe, Suno-Stimme und Auswahl, Remotion-Arbeiten
- Neuer Mitarbeiter Komponist (.claude/agents/komponist.md)
- Liederbuch: Plan + Lieder 1, 2, 3, 4, 5, 12 (drehbuecher/lieder/)
- Suno: feste Stimme aus dem Favoriten, Stilvorlage, ausgewählte Fassungen (suno-auswahl.md)
- Suno-Lizenzantwort für Noa in der Mitte (wissen/)
- Werkzeuge für Melodie-Skizzen und Leseseite
- Laufende Remotion-, Stimmen- und Figurenarbeiten des Tages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018MyLus898ZL9jjJJDvvxa8
2026-11-03 21:29:39 +01:00

166 lines
7.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Melodie-Vorschau der Lied-Entwürfe (Refrain – Strophe – Refrain), ohne Gesang.
import numpy as np, wave, os, sys, subprocess
SR = 44100
OUT = r"C:\Users\lk-lo\Pino-Kanal\Lieder-Vorschau"
os.makedirs(OUT, exist_ok=True)
rng = np.random.default_rng(1)
NAMES = {'C':0,'C#':1,'Db':1,'D':2,'D#':3,'Eb':3,'E':4,'F':5,'F#':6,'Gb':6,'G':7,'G#':8,'Ab':8,'A':9,'A#':10,'Bb':10,'B':11}
def midi(n): # 'F#4'
return 12*(int(n[-1])+1) + NAMES[n[:-1]]
def hz(m): return 440*2**((m-69)/12)
def lead(f, dur):
n = int(SR*(dur+0.25)); t = np.arange(n)/SR
vib = 1 + 0.004*np.sin(2*np.pi*5.2*t)*np.clip((t-0.18)/0.2,0,1)
ph = 2*np.pi*f*np.cumsum(vib)/SR
s = np.sin(ph) + 0.28*np.sin(2*ph) + 0.08*np.sin(3*ph)
env = np.clip(t/0.03,0,1) * np.where(t < dur, 1.0, np.exp(-(t-dur)/0.06)) * (0.85+0.15*np.exp(-t/0.3))
return 0.22*s*env
def glocken(f, dur):
n = int(SR*1.6); t = np.arange(n)/SR
s = np.sin(2*np.pi*2*f*t)*np.exp(-t/0.55) + 0.25*np.sin(2*np.pi*2*f*2.76*t)*np.exp(-t/0.12)
return 0.07*s*np.clip(t/0.002,0,1)
def pluck(f, dur, amp=0.09):
N = int(SR/f); n = int(SR*min(dur+0.4, 3.0))
buf = rng.uniform(-1,1,N); blocks = []
for _ in range(n//N + 1):
blocks.append(buf.copy()); buf = 0.498*(buf + np.roll(buf,-1))
out = np.concatenate(blocks)[:n]
return amp*out*np.clip(np.arange(n)/(SR*0.002),0,1)
def bass(f, dur):
n = int(SR*(dur+0.1)); t = np.arange(n)/SR
s = np.sin(2*np.pi*f*t) + 0.2*np.sin(4*np.pi*f*t)
return 0.16*s*np.exp(-t/0.6)*np.clip(t/0.01,0,1)
def clap():
n = int(SR*0.12); t = np.arange(n)/SR
s = rng.uniform(-1,1,n); s = np.convolve(s, np.ones(6)/6, 'same')
return 0.12*s*np.exp(-t/0.03)
def chord_notes(c):
root = c[0] + (c[1] if len(c)>1 and c[1] in '#b' else '')
rest = c[len(root):]
r = NAMES[root]
iv = [0,3,7] if rest.startswith('m') else [0,4,7]
if '7' in rest: iv = iv + [10]
base = 48 + r if r <= 7 else 36 + r # Gitarrenlage um C3–G3
notes = [base+i for i in iv]
return 40 + (r-4) % 12, notes # Bass-Grundton
def add(mix, sig, at):
i = int(at*SR); j = min(len(mix), i+len(sig))
if j > i: mix[i:j] += sig[:j-i]
def render(name, bpm, sections, strum_every, claps=None, end_chord=None, intro=None):
beat = 60/bpm
total = sum(sum(d for _,d in mel) for mel,_ in sections)
total += sum(d for _,d in intro[1]) if intro else 0
mix = np.zeros(int(SR*(total*beat + 4)))
t0 = 0.0
parts = ([intro] if intro else []) + sections
for mel, chords in parts:
# Melodie
t = t0
for n, d in mel:
if n:
f = hz(midi(n)); add(mix, lead(f, d*beat*0.92), t*beat); add(mix, glocken(f, d*beat), t*beat)
t += d
# Akkorde
t = t0
for c, d in chords:
b, notes = chord_notes(c)
add(mix, bass(hz(b), d*beat), t*beat)
k = 0.0
while k < d - 1e-9:
for idx, m in enumerate(notes):
add(mix, pluck(hz(m), strum_every*beat, 0.07), (t+k)*beat + idx*0.014)
k += strum_every
if claps:
for cb in claps:
pass
t += d
t0 = t
if claps: # Klatscher auf festen Positionen (in Beats ab Start)
for cb in claps: add(mix, clap(), cb*beat)
if end_chord:
b, notes = chord_notes(end_chord)
add(mix, bass(hz(b), 2.5), t0*beat)
for idx, m in enumerate(notes + [notes[0]+12]):
add(mix, pluck(hz(m), 3.0, 0.08), t0*beat + idx*0.03)
add(mix, glocken(hz(m+12), 2), t0*beat + idx*0.03)
# Hall (einfach) + Normalisieren
d = int(0.11*SR); rev = np.zeros_like(mix); rev[d:] = mix[:-d]*0.22
d2 = int(0.23*SR); rev[d2:] += mix[:-d2]*0.12
mix = mix + rev
mix = mix[:int(SR*(t0*beat+3.2))]
mix *= 0.89/np.max(np.abs(mix))
fade = int(SR*1.0); mix[-fade:] *= np.linspace(1,0,fade)
wavp = os.path.join(OUT, name + '.wav')
with wave.open(wavp, 'w') as w:
w.setnchannels(1); w.setsampwidth(2); w.setframerate(SR)
w.writeframes((mix*32767).astype(np.int16).tobytes())
mp3 = os.path.join(OUT, name + '.mp3')
subprocess.run(['ffmpeg','-y','-loglevel','error','-i',wavp,'-af','loudnorm=I=-14:TP=-1.5:LRA=11','-ar','44100','-b:a','160k',mp3], check=True)
os.remove(wavp)
print(name, round(t0*beat+3.2,1), 's')
def L(s): # "G4:1 E4:1 -:2" -> [(note,beats)]
out = []
for tok in s.split():
n, d = tok.split(':'); out.append((None if n == '-' else n, float(d)))
return out
def C(s): return [(c.split(':')[0], float(c.split(':')[1])) for c in s.split()]
# Lied 1 – Zählen, C-Dur, 100 BPM
r1 = (L("G4:1 E4:1 G4:1 E4:1 -:4 A4:1 A4:1 G4:1 G4:1 E4:1 D4:1 -:2 C4:1 D4:1 E4:1 F4:1 G4:1 G4:1 G4:2 A4:.5 G4:.5 F4:.5 E4:.5 D4:1 E4:1 C4:4"),
C("C:4 F:2 G:2 C:4 G:4 C:4 F:4 G:4 C:4"))
s1 = (L("C4:2 D4:2 E4:1 E4:1 D4:1 C4:1 E4:2 F4:2 G4:1 G4:1 F4:1 E4:1 G4:2 A4:.5 G4:.5 F4:.5 E4:.5 E4:.5 D4:.5 D4:1 E4:2 C4:4 -:4"),
C("C:4 G:4 C:4 G:4 F:4 G:4 C:4 C:4"))
render('lied01-zaehlen', 100, [r1, s1, r1], 1, intro=([], C("C:4")), end_chord='C')
# Lied 2 – Farben, G-Dur, 96 BPM
r2 = (L("G4:1 G4:1 G4:1 A4:1 B4:4 B4:1 A4:1 G4:1 A4:1 B4:1 A4:1 A4:2 D4:1 D4:1 E4:1 E4:1 G4:1 G4:1 A4:2 B4:1 B4:1 A4:1 G4:1 A4:1 G4:1 G4:2"),
C("G:4 G:4 C:4 D:4 G:4 C:4 Em:4 G:4"))
s2 = (L("D4:.5 E4:.5 G4:1 D4:.5 E4:.5 G4:1 -:4 G4:.5 A4:.5 B4:.5 A4:.5 G4:.5 E4:.5 -:1 G4:.5 A4:.5 B4:.5 A4:.5 G4:.5 G4:.5 -:1"),
C("G:4 G:4 C:4 G:4"))
render('lied02-farben', 96, [r2, s2, s2, r2], 1, intro=([], C("G:4")), end_chord='G')
# Lied 3 – Einer klein und einer groß, D-Dur, 104 BPM, Zeile = 6 Schläge, Klatscher auf Schlag 5
r3 = (L("F#4:.5 G4:.5 F#4:.5 F#4:.5 A4:.5 A4:.5 B4:1 -:1.5 G4:.25 G4:.25 "
"A4:.5 G4:.5 B4:.5 A4:.5 A4:2 -:2 "
"G4:.5 G4:.5 A4:.5 G4:.25 F#4:.25 G4:.5 F#4:.5 G4:1 -:1.75 A4:.25 "
"B4:.5 A4:.5 G4:.5 F#4:.5 E4:.25 F#4:.25 E4:.5 D4:1 -:2"),
C("D:6 G:3 A7:3 G:6 D:1.5 G:1.5 A:1.5 D:1.5"))
s3 = (L("D4:.5 D4:.5 E4:.5 F#4:.5 A4:.5 F#4:.5 E4:1 -:2 D4:.5 D4:.5 E4:.5 F#4:.5 G4:.5 F#4:.5 D4:1 -:2 "
"D4:.5 D4:.5 E4:.5 F#4:.5 A4:.5 F#4:.5 E4:1 -:2 D4:.5 D4:.5 E4:.5 F#4:.5 G4:.5 F#4:.5 D4:1 -:2"),
C("D:6 G:3 D:3 D:6 G:2 A:2 D:2"))
intro3 = C("D:4")
claps3 = [4 + 6*i + 4 for i in range(12)]
render('lied03-einer-klein-einer-gross', 104, [r3, s3, r3], 2, intro=([], intro3), end_chord='D', claps=claps3)
# Lied 4 – Körperteile, F-Dur, 96 BPM
r4 = (L("F4:1 F4:1 G4:1 A4:1 G4:1 F4:1 -:2 A4:1 F4:1 A4:1 F4:1 G4:1 G4:1 G4:2 C4:1 C4:1 D4:1 E4:1 F4:1 E4:1 D4:1 C4:1 F4:1 F4:1 F4:1 G4:1 A4:1 G4:1 F4:2"),
C("F:4 F:4 F:4 C7:4 Dm:4 Gm:2 C7:2 F:4 C7:2 F:2"))
s4 = (L("C4:.5 D4:.5 E4:.5 F4:.5 G4:.5 F4:.5 -:1 -:4 F4:.5 F4:.5 G4:.5 A4:.5 G4:.5 G4:.5 -:1 F4:.5 F4:.5 G4:.5 A4:.5 G4:.5 F4:.5 -:1"),
C("F:4 F:4 F:4 C7:2 F:2"))
render('lied04-koerperteile', 96, [r4, s4, r4], 1, intro=([], C("F:4")), end_chord='F')
# Lied 5 – Zähneputzen, G-Dur, 96 BPM (Notenname „B“ im Entwurf = H)
r5 = (L("G4:1 G4:1 A4:1 B4:1 G4:4 B4:1 A4:1 B4:1 A4:1 G4:1 A4:1 G4:2 E4:1 E4:1 G4:1 G4:1 A4:1 G4:1 E4:2 E4:1 G4:1 A4:1 G4:1 E4:1 F#4:1 G4:2"),
C("G:4 G:4 G:4 D:4 Em:4 C:4 G:4 D:2 G:2"))
s5 = (L("G4:1 A4:1 B4:1 A4:1 G4:1 E4:1 D4:2 D4:1 E4:1 G4:1 E4:1 G4:1 A4:1 G4:2 G4:1 A4:1 B4:2 -:4"),
C("G:4 D:4 C:4 G:4 G:4 G:4"))
render('lied05-zaehneputzen', 96, [r5, s5, r5], 1, intro=([], C("G:4")), end_chord='G')
# Lied 12 – Gute Nacht, F-Dur, 6/8, 72 punktierte Viertel = 216 Achtel/Min.
r12 = (L("A4:2 G4:1 F4:3 A4:2 G4:1 A4:3 G4:2 F4:1 E4:3 F4:6 C4:2 E4:1 D4:3 F4:2 E4:1 G4:3 "
"A4:2 G4:1 F4:2 E4:1 D4:2 E4:1 C4:3 A4:3 G4:3 A4:3 F4:3 G4:2 F4:1 E4:2 D4:1 F4:6"),
C("F:6 F:6 C:6 F:6 C:6 F:6 Dm:6 C:6 F:6 F:6 C:6 F:6"))
s12 = (L("F4:2 G4:1 A4:3 A4:2 G4:1 F4:3 A4:2 G4:1 F4:3 G4:3 F4:3 E4:2 F4:1 G4:3 A4:2 G4:1 E4:3 -:12"),
C("F:6 F:6 Dm:6 C:6 C:6 F:6 F:6 F:6"))
render('lied12-gute-nacht', 216, [r12, s12, r12], 3, intro=([], C("F:6 F:6")), end_chord='F')