-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtommy-practice.html
More file actions
532 lines (436 loc) · 34.3 KB
/
Copy pathtommy-practice.html
File metadata and controls
532 lines (436 loc) · 34.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="max-image-preview:large">
<title>Tommy the Cat – Bass Cover bei 210 BPM + FFT-Video-Sync</title>
<meta name="description" content="Wie ich Tommy the Cat von Primus bei 210 BPM spiele, eine Practice-App mit WSOLA-Algorithmus gebaut habe und zwei separate Kamera-Aufnahmen mit FFT-Cross-Correlation frame-genau synchronisiert habe.">
<meta name="author" content="Mathias Leonhardt">
<meta name="fediverse:creator" content="@ki_mathias@mathstodon.xyz">
<link rel="canonical" href="https://ki-mathias.de/tommy-practice.html">
<link rel="alternate" hreflang="de" href="https://ki-mathias.de/tommy-practice.html">
<link rel="alternate" hreflang="en" href="https://ki-mathias.de/en/tommy-practice.html">
<link rel="alternate" hreflang="x-default" href="https://ki-mathias.de/tommy-practice.html">
<meta property="og:type" content="article">
<meta property="og:title" content="Tommy the Cat – Bass Cover bei 210 BPM + FFT-Video-Sync">
<meta property="og:description" content="Primus-Riff auf dem Bass, vereinfacht aber bei Original-Tempo. Dazu: wie man zwei Kamera-Aufnahmen mit Python-FFT frame-genau synchronisiert.">
<meta property="og:url" content="https://ki-mathias.de/tommy-practice.html">
<meta property="og:locale" content="de_DE">
<meta property="og:site_name" content="Mathias Leonhardt Blog">
<meta property="article:published_time" content="2026-04-14">
<meta property="article:author" content="Mathias Leonhardt">
<meta property="article:tag" content="Bass">
<meta property="article:tag" content="Primus">
<meta property="article:tag" content="Fourier">
<meta property="article:tag" content="FFT">
<meta property="article:tag" content="Musik">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Tommy the Cat – Bass Cover bei 210 BPM + FFT-Video-Sync">
<meta name="twitter:description" content="Primus-Riff auf dem Bass + Python-FFT-Synchronisation zweier Kamera-Aufnahmen.">
<link rel="stylesheet" href="vendor/tailwind.css">
<link rel="preload" href="fonts/inter-400.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/inter-400.woff2) format('woff2'), url(fonts/inter-400.ttf) format('truetype'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url(fonts/inter-500.woff2) format('woff2'), url(fonts/inter-500.ttf) format('truetype'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url(fonts/inter-600.woff2) format('woff2'), url(fonts/inter-600.ttf) format('truetype'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url(fonts/inter-700.woff2) format('woff2'), url(fonts/inter-700.ttf) format('truetype'); }
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Tommy the Cat \u2013 Bass Cover bei 210 BPM + FFT-Video-Sync",
"description": "Wie ich Tommy the Cat von Primus bei 210 BPM spiele, eine Practice-App mit WSOLA-Algorithmus gebaut habe und zwei separate Kamera-Aufnahmen mit FFT-Cross-Correlation frame-genau synchronisiert habe.",
"author": { "@type": "Person", "@id": "https://ki-mathias.de/#mathias", "name": "Mathias Leonhardt", "url": "https://ki-mathias.de/ueber-mich.html", "sameAs": ["https://mathstodon.xyz/@ki_mathias", "https://orcid.org/0009-0009-7154-5351", "https://philpeople.org/profiles/mathias-leonhardt", "https://github.com/pmmathias", "https://www.linkedin.com/in/mathias-leonhardt-96b885100/", "https://scholar.google.com/citations?user=hd8CgpsAAAAJ", "https://pmagentur.com"] },
"publisher": { "@id": "https://ki-mathias.de/#mathias" },
"datePublished": "2026-04-14",
"dateModified": "2026-04-21",
"mainEntityOfPage": { "@type": "WebPage", "@id": "https://ki-mathias.de/tommy-practice.html" },
"inLanguage": "de",
"isAccessibleForFree": true,
"keywords": ["Tommy the Cat", "Primus", "Les Claypool", "Bass", "FFT", "Cross-Correlation", "WSOLA", "SoundTouch", "FFmpeg", "Fourier"],
"articleSection": "Musik",
"wordCount": 1500,
"timeRequired": "PT8M"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Startseite",
"item": "https://ki-mathias.de/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Tommy the Cat – Bass Cover bei 210 BPM + FFT-Video-Sync",
"item": "https://ki-mathias.de/tommy-practice.html"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Wie viele BPM hat Tommy the Cat von Primus?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Tommy the Cat von Primus l\u00e4uft mit 210 BPM. Das gilt f\u00fcr die Album-Version von \"Sailing the Seas of Cheese\" (1991) genauso wie f\u00fcr die meisten Live-Versionen von Les Claypool."
}
},
{
"@type": "Question",
"name": "Kann man Tommy the Cat als Anf\u00e4nger auf dem Bass spielen?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Die Original-Bassline mit Slapping, gepoppten Hammer-Ons und Flamenco-Strokes ist fortgeschritten. Eine vereinfachte Version l\u00e4sst sich aber durchaus bei 210 BPM lernen \u2013 mit langsamem Aufbau ab 80 BPM und einer Practice-App, die das Tempo schrittweise hochsetzt."
}
},
{
"@type": "Question",
"name": "Was ist WSOLA und wozu braucht man es beim \u00dcben?",
"acceptedAnswer": {
"@type": "Answer",
"text": "WSOLA (Waveform Similarity Overlap-Add) ist ein Algorithmus, der Audio-Tempo ver\u00e4ndert, ohne die Tonh\u00f6he zu verschieben. Beim \u00dcben l\u00e4sst sich so ein Song von z.B. 80 BPM bis 210 BPM hochziehen, ohne dass der Bass pl\u00f6tzlich eine Oktave tiefer klingt."
}
}
]
}
</script>
<style>
html { scroll-behavior: smooth; }
body { font-family: 'Inter', system-ui, sans-serif; }
section[id] { scroll-margin-top: 4.5rem; }
#progress-bar { position: fixed; top: 0; left: 0; height: 3px; z-index: 100; background: linear-gradient(90deg, #22d3ee, #f59e0b, #a855f7); transition: width 50ms linear; }
.prose-dark p { margin-bottom: 1.25rem; line-height: 1.8; color: #d1d5db; }
.prose-dark h2 { font-size: 1.75rem; font-weight: 700; margin-top: 0; margin-bottom: 1rem; background: linear-gradient(90deg, #22d3ee, #f59e0b, #a855f7); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
.prose-dark h3 { font-size: 1.25rem; font-weight: 600; color: #f1f5f9; margin-top: 2.5rem; margin-bottom: 0.75rem; }
.prose-dark strong { color: #f1f5f9; font-weight: 600; }
.prose-dark em { color: #94a3b8; font-style: italic; }
.prose-dark ol { color: #d1d5db; padding-left: 1.5rem; margin-bottom: 1.25rem; line-height: 1.8; }
.prose-dark ol li { margin-bottom: 0.5rem; }
.summary-box { border: 1px solid #374151; padding: 1.25rem 1.5rem; border-radius: 0.75rem; background: rgba(55, 65, 81, 0.2); margin: 2rem 0; }
.section-divider { width: 60px; height: 2px; margin: 3rem auto; background: linear-gradient(90deg, #22d3ee, #f59e0b); border-radius: 1px; }
.nav-link { transition: color 0.2s; }
.nav-link.active { color: #22d3ee; }
.chapter-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(34,211,238,0.6); margin-bottom: 0.5rem; }
.code-block { background: rgba(17, 24, 39, 0.8); border: 1px solid #374151; border-radius: 0.75rem; padding: 1.25rem; margin: 1.5rem 0; overflow-x: auto; font-family: 'Fira Code', 'Courier New', monospace; font-size: 0.8rem; line-height: 1.6; color: #86efac; }
.try-it { border-left: 3px solid #22d3ee; padding: 1rem 1.25rem; background: rgba(34, 211, 238, 0.05); border-radius: 0 0.75rem 0.75rem 0; margin: 2rem 0; }
.try-it p { color: #94a3b8; margin-bottom: 0.5rem; }
.try-it strong { color: #22d3ee; }
.video-placeholder { background: rgba(17, 24, 39, 0.6); border: 1px dashed #374151; border-radius: 0.75rem; padding: 3rem 2rem; text-align: center; margin: 2rem 0; color: #6b7280; }
.app-iframe-wrap { position: relative; width: 100%; border-radius: 0.75rem; overflow: hidden; border: 1px solid #374151; margin: 1.5rem 0; }
.katex { color: #e2e8f0; }
</style>
<link rel="stylesheet" href="vendor/katex/katex.min.css">
<script defer src="vendor/katex/katex.min.js"></script>
<script defer src="vendor/katex/auto-render.min.js"></script>
<link rel="alternate" type="application/atom+xml" title="Mathias Leonhardt Blog — RSS (Atom)" href="/feed.xml">
</head>
<body class="bg-gray-950 text-gray-100 antialiased">
<div id="progress-bar" style="width: 0%"></div>
<!-- Navigation (generated by nav.js) -->
<nav class="fixed top-0 left-0 right-0 z-50 border-b border-gray-800/50 bg-gray-950/90 backdrop-blur-md">
<div id="nav-bar"></div>
</nav>
<div id="nav-dropdown" class="fixed top-14 left-0 right-0 z-40 hidden"></div>
<!-- Hidden TOC slot — nav.js picks this up and injects it into the dropdown -->
<div id="nav-toc-items" style="display:none;">
<a href="#das-riff" class="toc-link block text-sm py-1.5 px-3 text-gray-300 rounded-lg hover:bg-gray-800/60 transition">1 · Das Riff</a>
<a href="#practice-app" class="toc-link block text-sm py-1.5 px-3 text-gray-300 rounded-lg hover:bg-gray-800/60 transition">2 · Die Practice-App</a>
<a href="#fft-sync" class="toc-link block text-sm py-1.5 px-3 text-gray-300 rounded-lg hover:bg-gray-800/60 transition">3 · FFT-Cross-Correlation</a>
<a href="#fuer-producer" class="toc-link block text-sm py-1.5 px-3 text-gray-300 rounded-lg hover:bg-gray-800/60 transition">4 · Für Content-Producer</a>
<a href="#faq" class="toc-link block text-sm py-1.5 px-3 text-gray-500 italic rounded-lg hover:bg-gray-800/60 transition">FAQ</a>
</div>
<script src="/nav.js"></script>
<div class="max-w-4xl mx-auto">
<header id="hero" class="pt-24 pb-12 px-4 sm:px-6">
<p class="text-xs uppercase tracking-widest text-cyan-400/60 mb-3">Blogbeitrag · Musik · Bass · Fourier</p>
<h1 class="text-3xl sm:text-4xl font-bold mb-4 bg-gradient-to-r from-cyan-400 via-amber-400 to-purple-400 bg-clip-text text-transparent leading-tight" style="-webkit-background-clip:text; -webkit-text-fill-color:transparent;">
Tommy the Cat — Bass Cover bei 210 BPM + FFT-Video-Sync
</h1>
<p class="text-gray-400 max-w-2xl text-base sm:text-lg leading-relaxed mb-6">
Primus-Riff vereinfacht, aber dafür annähernd bei Originaltempo spielbar :-D Dazu: eine Browser-Practice-App, und zwei separate Kamera-Aufnahmen per FFT frame-genau synchronisiert — nur mit Python und FFmpeg.
</p>
<div class="flex items-center gap-3 text-xs text-gray-500">
<span>KI-Mathias</span><span>·</span>
<time datetime="2026-04-14">April 2026</time><span>·</span>
<span>~8 Min. Lesezeit</span>
</div>
</header>
<main class="max-w-4xl px-4 sm:px-6">
<!-- VIDEO PLACEHOLDER -->
<div class="max-w-3xl mx-auto mb-8">
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden; border-radius:0.75rem; border:1px solid rgba(55,65,81,0.3);">
<iframe src="https://www.youtube-nocookie.com/embed/0JZ5NdSN0Xc"
style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen loading="lazy"
title="Tommy the Cat — Simplified Bass @ 210 BPM"></iframe>
</div>
</div>
<!-- SNIPPET ANSWER BOX -->
<aside class="max-w-3xl mx-auto mb-12" style="border:1px solid rgba(34,211,238,0.25); background:rgba(34,211,238,0.06); border-radius:0.75rem; padding:1.25rem 1.5rem;">
<p style="margin:0 0 0.5rem 0; font-size:0.75rem; color:#22d3ee; font-weight:600; text-transform:uppercase; letter-spacing:0.1em;">Kurzantwort</p>
<p style="margin:0; color:#e5e7eb; line-height:1.7;"><strong style="color:#f1f5f9;">Tommy the Cat von Primus hat 210 BPM.</strong> Les Claypools Original-Bassline — ein komplexes Geflecht aus Slap, Flamenco-Strokes und Hammer-Ons — läuft im Song exakt mit 210 Schlägen pro Minute. In diesem Beitrag zeige ich eine vereinfachte Bass-Version bei Original-Tempo (210 BPM) und erkläre die Technik dahinter: Practice-App mit WSOLA-Algorithmus plus zwei Kamera-Aufnahmen, per FFT frame-genau synchronisiert.</p>
</aside>
<!-- ================================================================ -->
<!-- 1. DAS RIFF -->
<!-- ================================================================ -->
<section id="das-riff" class="pb-16">
<div class="prose-dark">
<p class="chapter-label">Kapitel 1</p>
<h2>Das Riff</h2>
<p>Tommy the Cat von Primus. 210 BPM. Les Claypools Original ist — sagen wir mal — nicht das, was man abends mal eben vom Blatt spielt. Ich hab’s trotzdem versucht, auf meine Art.</p>
<p>Meine Interpretation: vereinfacht, aber bei Original-Tempo spielbar. Kein Slapping im Claypool-Stil, aber <strong>Flamenco-Strokes, Hammer-Ons und Groove</strong>. Wer das Riff zum ersten Mal hört, denkt an Chaos — in Wirklichkeit ist es ein präzises 16-Note-Muster, das sich wiederholt. Jede Note hat eine definierte Technik, eine definierte Saite, einen definierten Bund.</p>
<p>Das Tab unten zeigt meine Vereinfachung. Der erste Takt startet mit einem Flamenco-Down-Stroke auf Bund 7 (A-Saite) und Bund 9 (D-Saite) gleichzeitig — ein Quint-Akkord. Dann kommt der Up-Stroke, gefolgt von zwei Thumb-Schlägen auf die gemutete E-Saite. Ab Note 5 wird es interessant: ein Hammer-On von G nach G♯ auf der E-Saite, ein gepoppter Hammer-On F nach G auf der D-Saite, dann abwechselnde Slap-Ghost-Notes und offene G-Saite als Pop. Das Muster wiederholt sich — der zweite und alle folgenden Takte starten mit einem Hammer-On statt dem initialen Flamenco-Down-Stroke.</p>
<p>Wer das Riff üben will, sollte es ganz langsam beginnen — 80 BPM, einzelne Noten, bis die Handhaltung stimmt. Das Tempo kommt von selbst.</p>
<pre class="bg-gray-900/50 p-4 rounded-lg overflow-x-auto text-xs text-gray-300 font-mono">G|-------------------------------------0-----------0-------------|-------------------------------------0-----------0-------------|
D|-9---9-------------------3---5h------------------------------0-|-9h--9-------------------3---5h------------------------------0-|
A|-7---7---------------------------------------------------------|-7h--7---------------------------------------------------------|
E|---------X---X---3---4-----------4-------4---3-------X---X-----|---------X---X---3---4-----------4-------4---3-------X---X-----|
↓ ↑ T T T H P H T P T T P T T P H ↑ T T T H P H T P T T P T T P
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Legende:
↓ = Flamenco-Down-Stroke ↑ = Flamenco-Up-Stroke
T = Thumb (Slap) P = Pop
H = Hammer-On h = Hammer-On im Tab (z.B. 5h = Hammer-On auf Bund 5)
X = Muted Note (Ghost Note)
Takt 1, Note 1-16:
1) Flamenco-Down-Stroke: Bund 7 (A) + Bund 9 (D) gleichzeitig — Quint-Akkord
2) Flamenco-Up-Stroke: Quint-Akkord, andere Saiten stumm (linke Hand)
3) Thumb auf muted E-Saite
4) Thumb auf muted E-Saite
5) Geslapter Hammer-On von G nach G# auf E-Saite
6) G# auf E-Saite (Ziel des Hammer-Ons)
7) Gepoppter Hammer-On F nach G auf D-Saite (Zeigefinger)
8) G auf D-Saite (Ziel des Hammer-Ons)
9) Slap G# (E-Saite, Bund 4)
10) Pop leere G-Saite
11) Slap muted E-Saite
12) Slap G (E-Saite, Bund 3)
13) Pop leere G-Saite
14) Slap muted E-Saite
15) Slap muted E-Saite
16) Pop D-Saite (leer)
Ab Takt 2: Note 1 wird zu Hammer-On auf Bund 7 (A) + Bund 9 (D),
anschließend Flamenco-Up-Stroke. Alles andere identisch. So weiter.</pre>
<div class="try-it">
<strong>Practice-App:</strong>
<p>Zum interaktiven Üben gibt es eine Browser-App unter <a href="https://pmmathias.github.io/TommyTheCat/" target="_blank" rel="noopener" class="text-cyan-400 hover:text-cyan-300">pmmathias.github.io/TommyTheCat</a> — Tempo justierbar, Drums und Bass getrennt stummschaltbar.</p>
</div>
<p><strong>Ehrliche Einschätzung:</strong> Meine aktuelle Version liegt bei <strong>210 BPM</strong>. Das Primus-Original dürfte eher bei <strong>~230 BPM</strong> liegen. Ich übe weiter — und sobald ich es sauberer und näher am Originaltempo spielen kann, werde ich es vermutlich nochmal neu einspielen. Die Practice-App deckt daher den Bereich <strong>180–240 BPM</strong> ab: von gemütlich üben bis über das Original hinaus.</p>
</div>
</section>
<div class="section-divider"></div>
<!-- ================================================================ -->
<!-- 2. DIE PRACTICE-APP -->
<!-- ================================================================ -->
<section id="practice-app" class="pb-16">
<div class="prose-dark">
<p class="chapter-label">Kapitel 2</p>
<h2>Die Practice-App</h2>
<p>Wer ein Riff bei 210 BPM lernen will, fängt nicht bei 210 BPM an. Das Problem: Drumcomputer-Loops bei 60 % Tempo klingen falsch, weil die Pitches mitskalieren. Ein Schlagzeug bei 100 BPM klingt nicht wie ein Schlagzeug bei 210 BPM in Zeitlupe — es klingt wie ein anderen Instrument.</p>
<p>Die Practice-App löst das mit dem <strong>WSOLA-Algorithmus</strong> (Waveform Similarity Overlap-Add), implementiert über die <a href="https://www.surina.net/soundtouch/" target="_blank" rel="noopener" class="text-cyan-400 hover:text-cyan-300">SoundTouch-Bibliothek</a>. WSOLA verändert das Tempo, hält aber die Tonhöhe konstant. Ein Snare-Hit bei 60 BPM klingt genau so hoch wie bei 210 BPM — nur langsamer.</p>
<p>Die App läuft vollständig im Browser, braucht keine Installation und funktioniert auf dem Smartphone. Empfohlene Vorgehensweise: <strong>Drums an, Bass stumm, Tempo auf 180 BPM runterdrehen</strong>. Das Riff auf dem eigenen Bass mitspielen, bis die Finger die Bewegungssequenz kennen. Dann schrittweise hoch — 190, 200, 210 und wer mutig ist: 230+.</p>
<div class="app-iframe-wrap" style="height:520px;">
<iframe
src="https://pmmathias.github.io/TommyTheCat/"
title="Tommy the Cat Practice App"
width="100%"
height="520"
frameborder="0"
loading="lazy"
allow="autoplay"
style="display:block;border:0;">
</iframe>
</div>
<div class="summary-box">
<strong style="color:#22d3ee;">Technischer Hintergrund WSOLA:</strong>
<p class="text-sm text-gray-300 mt-1 mb-0">WSOLA teilt das Audio-Signal in kurze Überlappungs-Fenster und fügt sie mit angepassten Kreuzkorrelationen neu zusammen — so entsteht ein längeres oder kürzeres Signal ohne Pitch-Shift. Der Algorithmus gehört zur Familie der Time-Scale-Modification-Methoden und ist Standard in professionellen Playback-Systemen.</p>
</div>
</div>
</section>
<div class="section-divider"></div>
<!-- ================================================================ -->
<!-- 3. FFT-CROSS-CORRELATION -->
<!-- ================================================================ -->
<section id="fft-sync" class="pb-16">
<div class="prose-dark">
<p class="chapter-label">Kapitel 3</p>
<h2>Der Tech-Stack — FFT-Cross-Correlation</h2>
<p>Dieses Video besteht aus <strong>ZWEI separaten Kamera-Aufnahmen</strong>. Ich habe Schlagzeug und Bass getrennt aufgenommen, jedes mit einer eigenen Kamera, und die Aufnahmen waren nicht synchronisiert. Wie bringt man zwei Videos, die zu verschiedenen Zeitpunkten gestartet wurden, auf Sample-genaue Übereinstimmung?</p>
<h3>Die Aufnahme-Situation</h3>
<p>In GarageBand wurden zwei Audiospuren gleichzeitig über eine Interface-Box aufgezeichnet: E-Drums und Bass. Aber zwei separate Kameras liefen unabhängig — eine auf das Schlagzeug gerichtet, eine auf den Bass. Kein Klatschholz, kein gemeinsamer Auslöser. Die Videos haben also einen unbekannten zeitlichen Versatz, der irgendwo zwischen 0 und mehreren Sekunden liegt.</p>
<p>Manuelles Synchronisieren per Waveform in einem Video-Editor? Möglich — aber fehleranfällig, unreproduzierbar und nervig. Die Alternative: <strong>Python + scipy + FFmpeg</strong>.</p>
<h3>Schritt 1: Audiospuren extrahieren</h3>
<p>Jedes Video-File enthält eine Audiospur, die das aufgenommene Instrument (plus Umgebungsgräusche) enthält. FFmpeg extrahiert sie als WAV-Datei. Die Herausforderung: Bass und Schlagzeug haben sehr unterschiedliche Frequenzspektren. Ein Butterworth-Bandpass-Filter trennt die relevanten Signale:</p>
<ul style="color:#d1d5db; padding-left:1.5rem; margin-bottom:1.25rem; line-height:1.8;">
<li><strong>Schlagzeug:</strong> 150–6000 Hz (Snare-Transient, Hi-Hat, Kick-Oberton)</li>
<li><strong>Bass:</strong> 40–300 Hz (Grundton und erste Obertöne)</li>
</ul>
<p>Der Butterworth-Filter ist ein Standardwerkzeug der Signalverarbeitung: er dämpft Frequenzen außerhalb des Bandes mit maximaler Flachheit im Durchlassbereich. <code style="color:#86efac; background:rgba(17,24,39,0.8); padding:0.1rem 0.4rem; border-radius:0.25rem;">scipy.signal.butter</code> + <code style="color:#86efac; background:rgba(17,24,39,0.8); padding:0.1rem 0.4rem; border-radius:0.25rem;">sosfilt</code> erledigt das in zwei Zeilen.</p>
<h3>Schritt 2: Cross-Correlation im Frequenzraum</h3>
<p>Die Cross-Correlation zweier Signale \(f\) und \(g\) misst, wie gut sie bei einem bestimmten Zeitversatz übereinstimmen. Der Peak der Kreuzkorrelation liegt genau beim Zeitversatz, bei dem die Signale am besten passen. Statt sie zeitdomänen-weise zu berechnen (langsam, \(O(n^2)\)), nutzen wir das <strong>Faltungstheorem</strong>:</p>
<p style="text-align:center; font-family:monospace; color:#86efac; padding:1rem; background:rgba(17,24,39,0.6); border-radius:0.5rem; margin:1.5rem 0;">
corr(f, g) = IFFT( FFT(f) · conj(FFT(g)) )
</p>
<p>Genau dieselbe Fourier-Transformation, die in unserem <a href="vogelsimulator.html" class="text-cyan-400 hover:text-cyan-300">Vogelsimulator-Post Ozeanwellen erzeugt</a>, synchronisiert hier Bass und Schlagzeug. Im Frequenzraum wird aus einer zeitaufwendigen Faltung eine einfache Multiplikation — <strong>von \(O(n^2)\) auf \(O(n \log n)\)</strong>.</p>
<p>Das Python-Kern-Snippet (der eigentliche Synchronisations-Code):</p>
<div class="code-block">
<pre>import numpy as np
from scipy.signal import butter, sosfilt
def bandpass(signal, lo, hi, sr):
sos = butter(4, [lo, hi], btype='band', fs=sr, output='sos')
return sosfilt(sos, signal)
def find_offset(ref, query, sr):
# FFT-based cross-correlation
n = len(ref) + len(query) - 1
R = np.fft.rfft(ref, n=n)
Q = np.fft.rfft(query, n=n)
corr = np.fft.irfft(R * np.conj(Q), n=n)
peak = np.argmax(corr)
if peak > n // 2:
peak -= n # negative lag
# Sub-sample precision via parabolic interpolation
if 1 <= abs(peak) < len(corr) - 1:
y0, y1, y2 = corr[peak-1], corr[peak], corr[peak+1]
peak += (y2 - y0) / (2 * (2*y1 - y0 - y2))
return peak / sr # offset in seconds</pre>
</div>
<h3>Schritt 3: Parabolische Sub-Sample-Interpolation</h3>
<p>Der naive Ansatz nimmt einfach den Index des Korrelations-Peaks und rechnet ihn in Sekunden um. Das Problem: Bei 44.100 Hz Samplerate ist die Auflösung etwa 22 Mikrosekunden — bei 25 fps entspricht ein Frame 40.000 Mikrosekunden. Das reicht.</p>
<p>Aber für 60-fps-Videos lohnt sich die <strong>parabolische Interpolation</strong>: Wir fitten eine Parabel durch den Peak und seine zwei Nachbarn und berechnen das exakte Subpixel-Maximum. Die Formel steht im Snippet oben. Das Ergebnis: Sub-Sample-genaue Zeitversatz-Bestimmung, die bei 60 fps weit unter einem Frame bleibt.</p>
<h3>Schritt 4: FFmpeg-Render</h3>
<p>Mit dem berechneten Offset-Wert (in Sekunden) rendert FFmpeg das finale Video. Container-Level Seeks sind dabei effizienter als Re-Encoding:</p>
<div class="code-block">
<pre># offset_s = berechneter Versatz in Sekunden (positiv oder negativ)
# Positiver Offset: Video 2 beginnt später als Video 1
ffmpeg -ss {offset_s} -i drums.mp4 \
-i bass.mp4 \
-filter_complex "[0:v][1:v]hstack=inputs=2[v]" \
-map "[v]" -map 0:a \
output.mp4</pre>
</div>
<p>Kein Premiere Pro nötig. Kein manuelles Ausrichten von Waveforms. Nur Python + FFmpeg + ein KI-Agent, der das Skript geschrieben hat. Das gesamte Rendering dauert — abhängig von der Videoqualität — unter zwei Minuten.</p>
<div class="summary-box">
<strong style="color:#22d3ee;">Zusammenfassung Tech-Stack:</strong>
<p class="text-sm text-gray-300 mt-1 mb-0">GarageBand (Aufnahme) → FFmpeg (Audiospuren extrahieren) → scipy Butterworth-Filter (Frequenztrennung) → numpy FFT Cross-Correlation (Offset berechnen) → Parabolische Interpolation (Sub-Sample-Präzision) → FFmpeg (finales Rendering). Vollständig automatisiert, reproduzierbar, frame-genau.</p>
</div>
</div>
</section>
<div class="section-divider"></div>
<!-- ================================================================ -->
<!-- 4. FÜR CONTENT-PRODUCER -->
<!-- ================================================================ -->
<section id="fuer-producer" class="pb-16">
<div class="prose-dark">
<p class="chapter-label">Kapitel 4</p>
<h2>Für Content-Producer — So macht ihr das auch</h2>
<p>Das Verfahren ist nicht auf Bass-Covers beschränkt. Wer mit mehreren Kameras filmt — Interviews, Konzerte, Tutorials — kann dieselbe Pipeline nutzen, solange die Audiospuren ein gemeinsames Referenzsignal enthalten (was sie fast immer tun: Raumhall, Stimme, Musik).</p>
<h3>Das Rezept in fünf Schritten</h3>
<ol>
<li><strong>Audiospuren getrennt aufnehmen</strong> — pro Instrument oder Quelle eine Spur, über ein Audio-Interface oder direkt in die DAW. Kein Click-Track nötig, aber er schadet nicht.</li>
<li><strong>Videos getrennt aufnehmen</strong> — jede Kamera läuft unabhängig. Kein Sync-Signal, kein gemeinsamer Auslöser. Das Python-Skript findet den Versatz automatisch.</li>
<li><strong>Bandpass-Filter pro Instrument</strong> — Drums: 150–6000 Hz, Bass: 40–300 Hz, Gitarre: 80–2000 Hz, Stimme: 100–8000 Hz. Anpassen je nach Quelle.</li>
<li><strong>Cross-Correlation im Frequenzraum</strong> — numpy + scipy, das Snippet von oben. Gibt den Zeitversatz in Sekunden zurück. Typische Laufzeit unter einer Sekunde für 10-Minuten-Audio.</li>
<li><strong>FFmpeg Render</strong> — mit dem berechneten Offset. Nebeneinander (<code style="color:#86efac; background:rgba(17,24,39,0.8); padding:0.1rem 0.4rem; border-radius:0.25rem;">hstack</code>), übereinander (<code style="color:#86efac; background:rgba(17,24,39,0.8); padding:0.1rem 0.4rem; border-radius:0.25rem;">vstack</code>), Picture-in-Picture (<code style="color:#86efac; background:rgba(17,24,39,0.8); padding:0.1rem 0.4rem; border-radius:0.25rem;">overlay</code>) — alles möglich.</li>
</ol>
<h3>Der Vorteil gegenüber manueller Synchronisation</h3>
<p>Manuelles Ausrichten von Waveforms in einem Video-Editor dauert — je nach Länge des Materials — zwischen einer Minute und einer Stunde. Es ist augengesteuertes Schätzen. Wer einmal eine schlecht synchronisierte Aufnahme hochgeladen hat, weiß: Man sieht es sofort. Ein Gitarren-Anschlag, der 80 Millisekunden vor dem Hören sichtbar ist, stört den Zuschauer mehr als man denkt.</p>
<p>Die FFT-Methode ist <strong>frame-genau, automatisch und reproduzierbar</strong>. Wenn sich am Material etwas ändert — neue Takes, anderer Schnitt — läuft das Skript einfach neu. Kein manuelles Nachjustieren. Kein Premiere Pro. Kein Abonnement.</p>
<p>Das komplette Python-Skript (inklusive FFmpeg-Aufruf, Fortschrittsanzeige und Fehlerbehandlung) lässt sich mit einem KI-Agenten in unter zehn Minuten generieren — Eingabe: die obige Beschreibung. Ausgabe: lauffähiger Code. Genau das ist hier passiert.</p>
<div class="try-it">
<strong>Abhängigkeiten:</strong>
<p><code style="color:#86efac;">pip install numpy scipy soundfile</code> — plus eine FFmpeg-Installation im PATH. Keine weiteren Abhängigkeiten. Das Skript läuft auf macOS, Linux und Windows.</p>
</div>
</div>
</section>
<div class="section-divider"></div>
<!-- ================================================================ -->
<!-- FAQ -->
<!-- ================================================================ -->
<section id="faq" class="pb-16">
<div class="prose-dark">
<h2 style="font-size:1.25rem;">Häufige Fragen</h2>
<h3 style="font-size:1rem; margin-top:1.5rem;">Ist das Les Claypools Originalversion?</h3>
<p>Nein. Claypools Originalversion von Tommy the Cat ist eine der technisch anspruchsvollsten Bass-Parts der Rockgeschichte — Slap, Pop, Ghost-Notes und ein perkussiver Stil, der eigene Jahrzehnte der Entwicklung widerspiegelt. Diese Version ist eine vereinfachte Interpretation: kein Claypool-Slapping, stattdessen Flamenco-Strokes und Hammer-Ons. Das Tempo ist original (210 BPM), die Technik ist zugänglicher.</p>
<h3 style="font-size:1rem; margin-top:1.5rem;">Was ist WSOLA?</h3>
<p>WSOLA steht für Waveform Similarity Overlap-Add. Es ist ein Algorithmus zur zeitlichen Skalierung von Audiosignalen ohne Veränderung der Tonhöhe (Pitch-Preservation). Das Signal wird in kurze, überlappende Fenster aufgeteilt; die Fenster werden mit Hilfe von Kreuzkorrelation optimal ausgerichtet und wieder zusammengefügt — länger oder kürzer, je nach gewünschtem Tempo. Das Ergebnis: Ein Schlagzeug-Loop bei 60 BPM klingt genau so wie bei 210 BPM — nur langsamer.</p>
<h3 style="font-size:1rem; margin-top:1.5rem;">Wie funktioniert die FFT-basierte Video-Synchronisation?</h3>
<p>Die Cross-Correlation zweier Audiosignale misst ihre Übereinstimmung bei verschiedenen Zeitversätzen. Der Peak der Kreuzkorrelation liegt genau beim optimalen Versatz. Statt die Korrelation zeitdomänen-weise zu berechnen (\(O(n^2)\)), nutzt das Faltungstheorem die Fourier-Transformation: Im Frequenzraum wird aus der Faltung eine punktweise Multiplikation (\(O(n \log n)\)). Mit parabolischer Interpolation um den Peak herum erreicht man Sub-Sample-Präzision — besser als ein einzelner Videoframe bei 60 fps.</p>
</div>
</section>
<section class="pb-12" data-related-block="1">
<div class="max-w-4xl mx-auto px-4">
<h2 style="font-size:1.15rem; color:#f1f5f9; margin-top:1.5rem; margin-bottom:0.75rem;">Weiterlesen</h2>
<p class="text-sm text-gray-400" style="margin-bottom:0.5rem;">Verwandte Beiträge auf ki-mathias.de:</p>
<ul style="list-style:disc; padding-left:1.5rem; color:#d1d5db;">
<li><a href="/musik.html" class="text-amber-400 hover:text-amber-300" style="font-weight:500;">Warum Dur fröhlich klingt</a> <span class="text-gray-500" style="font-size:0.9em;">— Harmonik, Stimmung, Psychoakustik</span></li>
<li><a href="/euler.html" class="text-amber-400 hover:text-amber-300" style="font-weight:500;">Warum e besonders ist</a> <span class="text-gray-500" style="font-size:0.9em;">— Wachstum, Primzahlen, Zufall</span></li>
</ul>
</div>
</section>
</main>
<footer class="border-t border-gray-800/50 py-8 text-center text-xs text-gray-600">
<p>© 2026 Mathias Leonhardt · Erstellt mit Claude Code (Anthropic)</p>
<p class="mt-1">
<a href="ueber-mich.html" class="hover:text-gray-400">Über mich</a> ·
<a href="impressum.html" class="hover:text-gray-400">Impressum</a> ·
<a href="datenschutz.html" class="hover:text-gray-400">Datenschutz</a>
</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
'use strict';
// 1. Scroll progress bar
var progressBar = document.getElementById('progress-bar');
function updateProgress() {
var scrollTop = window.scrollY;
var docHeight = document.documentElement.scrollHeight - window.innerHeight;
var pct = docHeight > 0 ? Math.min((scrollTop / docHeight) * 100, 100) : 0;
progressBar.style.width = pct + '%';
}
window.addEventListener('scroll', updateProgress, { passive: true });
updateProgress();
// 2. TOC highlighting
var sections = document.querySelectorAll('section[id]');
var tocLinks = document.querySelectorAll('#nav-dropdown .toc-link');
var navObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var id = entry.target.id;
tocLinks.forEach(function(link) {
if (link.getAttribute('href') === '#' + id) link.classList.add('active');
else link.classList.remove('active');
});
}
});
}, { rootMargin: '-20% 0px -75% 0px' });
sections.forEach(function(s) { navObserver.observe(s); });
});
if (typeof renderMathInElement === 'function') {
renderMathInElement(document.body, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '\\(', right: '\\)', display: false }
],
throwOnError: false
});
}
</script>
<!-- video-schema-injected -->
<script type="application/ld+json">{"@context":"https://schema.org","@type":"VideoObject","name":"Tommy the Cat (Primus) — Simplified Bass @ 210 BPM","description":"My simplified take on Tommy the Cat by Primus — not Claypool, not trying to be. Just a version that's actually playable at original tempo.","thumbnailUrl":"https://i.ytimg.com/vi/0JZ5NdSN0Xc/maxresdefault.jpg","uploadDate":"2026-04-14T12:00:00+02:00","duration":"PT39S","embedUrl":"https://www.youtube-nocookie.com/embed/0JZ5NdSN0Xc","contentUrl":"https://www.youtube.com/watch?v=0JZ5NdSN0Xc","inLanguage":"de","publisher":{"@type":"Person","name":"Mathias Leonhardt","url":"https://ki-mathias.de/"}}</script>
</body>
</html>