# 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')