@jjlmoya/utils-hardware 1.27.0 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +7 -1
  4. package/src/index.ts +2 -0
  5. package/src/tests/locale_completeness.test.ts +1 -1
  6. package/src/tests/tool_validation.test.ts +1 -1
  7. package/src/tool/mobileSensorTest/bibliography.astro +14 -0
  8. package/src/tool/mobileSensorTest/bibliography.ts +24 -0
  9. package/src/tool/mobileSensorTest/component.astro +241 -0
  10. package/src/tool/mobileSensorTest/entry.ts +29 -0
  11. package/src/tool/mobileSensorTest/i18n/de.ts +186 -0
  12. package/src/tool/mobileSensorTest/i18n/en.ts +186 -0
  13. package/src/tool/mobileSensorTest/i18n/es.ts +186 -0
  14. package/src/tool/mobileSensorTest/i18n/fr.ts +186 -0
  15. package/src/tool/mobileSensorTest/i18n/id.ts +186 -0
  16. package/src/tool/mobileSensorTest/i18n/it.ts +186 -0
  17. package/src/tool/mobileSensorTest/i18n/ja.ts +186 -0
  18. package/src/tool/mobileSensorTest/i18n/ko.ts +186 -0
  19. package/src/tool/mobileSensorTest/i18n/nl.ts +186 -0
  20. package/src/tool/mobileSensorTest/i18n/pl.ts +186 -0
  21. package/src/tool/mobileSensorTest/i18n/pt.ts +186 -0
  22. package/src/tool/mobileSensorTest/i18n/ru.ts +186 -0
  23. package/src/tool/mobileSensorTest/i18n/sv.ts +186 -0
  24. package/src/tool/mobileSensorTest/i18n/tr.ts +186 -0
  25. package/src/tool/mobileSensorTest/i18n/zh.ts +186 -0
  26. package/src/tool/mobileSensorTest/index.ts +11 -0
  27. package/src/tool/mobileSensorTest/logic.ts +39 -0
  28. package/src/tool/mobileSensorTest/mobile-sensor-test.css +460 -0
  29. package/src/tool/mobileSensorTest/seo.astro +15 -0
  30. package/src/tool/mobileSensorTest/ui.ts +31 -0
  31. package/src/tool/subwooferCrossoverTest/bibliography.astro +14 -0
  32. package/src/tool/subwooferCrossoverTest/bibliography.ts +16 -0
  33. package/src/tool/subwooferCrossoverTest/component.astro +253 -0
  34. package/src/tool/subwooferCrossoverTest/entry.ts +29 -0
  35. package/src/tool/subwooferCrossoverTest/i18n/de.ts +188 -0
  36. package/src/tool/subwooferCrossoverTest/i18n/en.ts +188 -0
  37. package/src/tool/subwooferCrossoverTest/i18n/es.ts +188 -0
  38. package/src/tool/subwooferCrossoverTest/i18n/fr.ts +188 -0
  39. package/src/tool/subwooferCrossoverTest/i18n/id.ts +188 -0
  40. package/src/tool/subwooferCrossoverTest/i18n/it.ts +188 -0
  41. package/src/tool/subwooferCrossoverTest/i18n/ja.ts +188 -0
  42. package/src/tool/subwooferCrossoverTest/i18n/ko.ts +188 -0
  43. package/src/tool/subwooferCrossoverTest/i18n/nl.ts +188 -0
  44. package/src/tool/subwooferCrossoverTest/i18n/pl.ts +188 -0
  45. package/src/tool/subwooferCrossoverTest/i18n/pt.ts +188 -0
  46. package/src/tool/subwooferCrossoverTest/i18n/ru.ts +188 -0
  47. package/src/tool/subwooferCrossoverTest/i18n/sv.ts +188 -0
  48. package/src/tool/subwooferCrossoverTest/i18n/tr.ts +188 -0
  49. package/src/tool/subwooferCrossoverTest/i18n/zh.ts +188 -0
  50. package/src/tool/subwooferCrossoverTest/index.ts +11 -0
  51. package/src/tool/subwooferCrossoverTest/logic.ts +30 -0
  52. package/src/tool/subwooferCrossoverTest/seo.astro +15 -0
  53. package/src/tool/subwooferCrossoverTest/subwoofer-crossover-test.css +282 -0
  54. package/src/tool/subwooferCrossoverTest/ui.ts +20 -0
  55. package/src/tools.ts +3 -1
@@ -0,0 +1,253 @@
1
+ ---
2
+ import type { KnownLocale } from '../../types';
3
+ import type { SubwooferCrossoverTestUI } from './ui';
4
+ import { Icon } from 'astro-icon/components';
5
+ import './subwoofer-crossover-test.css';
6
+
7
+ interface Props {
8
+ locale?: KnownLocale;
9
+ ui?: Record<string, unknown>;
10
+ }
11
+
12
+ const { ui } = Astro.props;
13
+ const t = (ui ?? {}) as SubwooferCrossoverTestUI;
14
+
15
+ const S = JSON.stringify({
16
+ ready: t.statusReady,
17
+ running: t.statusRunning,
18
+ stopped: t.statusStopped,
19
+ start: t.start,
20
+ stop: t.stop,
21
+ safeStart: t.safeStart,
22
+ dropoutEmpty: t.dropoutEmpty,
23
+ crossoverEstimate: t.crossoverEstimate,
24
+ });
25
+ ---
26
+
27
+ <div id="sct-root" class="sct-shell" data-s={S}>
28
+ <section class="sct-console" aria-label={t.sweepLabel}>
29
+ <div class="sct-stage">
30
+ <div class="sct-orbit" aria-hidden="true">
31
+ <div class="sct-ring sct-ring-a"></div>
32
+ <div class="sct-ring sct-ring-b"></div>
33
+ <div class="sct-driver">
34
+ <Icon name="mdi:speaker" class="sct-speaker-icon" />
35
+ </div>
36
+ </div>
37
+
38
+ <div class="sct-frequency-panel">
39
+ <span id="sct-status" class="sct-status">{t.statusReady}</span>
40
+ <output id="sct-frequency" class="sct-frequency" aria-live="polite">200 Hz</output>
41
+ <div class="sct-meter" aria-hidden="true">
42
+ <span id="sct-meter-fill" class="sct-meter-fill"></span>
43
+ </div>
44
+ <div class="sct-readouts">
45
+ <span>{t.targetFrequency}: <strong>10 Hz</strong></span>
46
+ <span>{t.elapsed}: <strong id="sct-elapsed">0.0s</strong></span>
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="sct-controls">
52
+ <button id="sct-toggle" class="sct-primary" type="button">
53
+ <Icon name="mdi:play" class="sct-button-icon" />
54
+ <span>{t.start}</span>
55
+ </button>
56
+ <button id="sct-mark" class="sct-secondary" type="button" disabled>
57
+ <Icon name="mdi:map-marker-radius" class="sct-button-icon" />
58
+ <span>{t.markDropout}</span>
59
+ </button>
60
+ <button id="sct-reset" class="sct-ghost" type="button">
61
+ <Icon name="mdi:restart" class="sct-button-icon" />
62
+ <span>{t.reset}</span>
63
+ </button>
64
+ </div>
65
+
66
+ <div class="sct-tuning">
67
+ <label class="sct-slider-wrap" for="sct-volume">
68
+ <span>{t.volume}</span>
69
+ <input id="sct-volume" class="sct-slider" type="range" min="0" max="0.6" value="0.22" step="0.01" />
70
+ </label>
71
+ <label class="sct-slider-wrap" for="sct-duration">
72
+ <span>{t.duration}</span>
73
+ <input id="sct-duration" class="sct-slider" type="range" min="20" max="90" value="45" step="5" />
74
+ </label>
75
+ </div>
76
+
77
+ <div class="sct-result">
78
+ <div>
79
+ <span class="sct-result-label">{t.dropoutLabel}</span>
80
+ <strong id="sct-dropout">{t.dropoutEmpty}</strong>
81
+ </div>
82
+ <p id="sct-note">{t.safeStart}</p>
83
+ </div>
84
+
85
+ </section>
86
+
87
+ <script>
88
+ const root = document.getElementById('sct-root');
89
+ const strings = JSON.parse(root?.dataset?.s ?? '{}') as Record<string, string>;
90
+ const frequencyDisplay = document.getElementById('sct-frequency');
91
+ const elapsedDisplay = document.getElementById('sct-elapsed');
92
+ const meterFill = document.getElementById('sct-meter-fill') as HTMLSpanElement | null;
93
+ const statusDisplay = document.getElementById('sct-status');
94
+ const toggleButton = document.getElementById('sct-toggle') as HTMLButtonElement | null;
95
+ const markButton = document.getElementById('sct-mark') as HTMLButtonElement | null;
96
+ const resetButton = document.getElementById('sct-reset') as HTMLButtonElement | null;
97
+ const volumeInput = document.getElementById('sct-volume') as HTMLInputElement | null;
98
+ const durationInput = document.getElementById('sct-duration') as HTMLInputElement | null;
99
+ const dropoutDisplay = document.getElementById('sct-dropout');
100
+ const noteDisplay = document.getElementById('sct-note');
101
+
102
+ const startHz = 200;
103
+ const endHz = 10;
104
+ let audioContext: AudioContext | null = null;
105
+ let oscillator: OscillatorNode | null = null;
106
+ let gainNode: GainNode | null = null;
107
+ let startTime = 0;
108
+ let animationId = 0;
109
+ let running = false;
110
+ let currentHz = startHz;
111
+
112
+ function formatHz(value: number): string {
113
+ return value >= 100 ? `${Math.round(value)} Hz` : `${value.toFixed(1)} Hz`;
114
+ }
115
+
116
+ function sweepFrequency(elapsed: number, duration: number): number {
117
+ const progress = Math.min(1, Math.max(0, elapsed / duration));
118
+ return startHz * Math.pow(endHz / startHz, progress);
119
+ }
120
+
121
+ function setButtonPlaying(isPlaying: boolean): void {
122
+ if (!toggleButton) return;
123
+ const label = toggleButton.querySelector('span');
124
+ toggleButton.dataset.playing = isPlaying ? 'true' : 'false';
125
+ if (label) label.textContent = isPlaying ? strings.stop! : strings.start!;
126
+ }
127
+
128
+ function getAudioContext(): AudioContext | null {
129
+ if (audioContext) return audioContext;
130
+ const win = window as typeof window & { webkitAudioContext?: typeof AudioContext };
131
+ const Context = win.AudioContext ?? win.webkitAudioContext;
132
+ if (!Context) return null;
133
+ audioContext = new Context();
134
+ return audioContext;
135
+ }
136
+
137
+ function getElapsed(): { elapsed: number; progress: number } {
138
+ const duration = Number(durationInput?.value ?? 45);
139
+ const elapsed = running && audioContext ? audioContext.currentTime - startTime : 0;
140
+ currentHz = running ? sweepFrequency(elapsed, duration) : currentHz;
141
+ const progress = Math.min(1, Math.max(0, elapsed / duration));
142
+ return { elapsed, progress };
143
+ }
144
+
145
+ function refreshFrequencyDisplay(elapsed: number, progress: number): void {
146
+ if (frequencyDisplay) frequencyDisplay.textContent = formatHz(currentHz);
147
+ if (elapsedDisplay) elapsedDisplay.textContent = `${elapsed.toFixed(1)}s`;
148
+ if (meterFill) meterFill.style.transform = `scaleX(${1 - progress})`;
149
+ }
150
+
151
+ function updateVisuals(): void {
152
+ const { elapsed, progress } = getElapsed();
153
+ refreshFrequencyDisplay(elapsed, progress);
154
+ if (running && progress < 1) {
155
+ animationId = requestAnimationFrame(updateVisuals);
156
+ } else if (running) {
157
+ stopSweep();
158
+ }
159
+ }
160
+
161
+ function setupOscillator(context: AudioContext, duration: number, volume: number): void {
162
+ oscillator = context.createOscillator();
163
+ gainNode = context.createGain();
164
+ oscillator.type = 'sine';
165
+ oscillator.frequency.setValueAtTime(startHz, context.currentTime);
166
+ oscillator.frequency.exponentialRampToValueAtTime(endHz, context.currentTime + duration);
167
+ gainNode.gain.setValueAtTime(0.0001, context.currentTime);
168
+ gainNode.gain.exponentialRampToValueAtTime(Math.max(0.0001, volume), context.currentTime + 0.08);
169
+ gainNode.gain.setValueAtTime(Math.max(0.0001, volume), context.currentTime + duration - 0.08);
170
+ gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + duration);
171
+ oscillator.connect(gainNode);
172
+ gainNode.connect(context.destination);
173
+ oscillator.start();
174
+ oscillator.stop(context.currentTime + duration);
175
+ }
176
+
177
+ function applyRunningState(): void {
178
+ root?.classList.add('is-running');
179
+ if (markButton) markButton.disabled = false;
180
+ if (statusDisplay) statusDisplay.textContent = strings.running!;
181
+ }
182
+
183
+ function startSweep(): void {
184
+ const context = getAudioContext();
185
+ if (!context) return;
186
+ if (context.state === 'suspended') void context.resume();
187
+ stopSweep(false);
188
+ setupOscillator(context, Number(durationInput?.value ?? 45), Number(volumeInput?.value ?? 0.22));
189
+ startTime = context.currentTime;
190
+ currentHz = startHz;
191
+ running = true;
192
+ applyRunningState();
193
+ setButtonPlaying(true);
194
+ updateVisuals();
195
+ }
196
+
197
+ function cleanupAudio(): void {
198
+ if (gainNode && audioContext) {
199
+ gainNode.gain.cancelScheduledValues(audioContext.currentTime);
200
+ gainNode.gain.setTargetAtTime(0.0001, audioContext.currentTime, 0.025);
201
+ }
202
+ if (oscillator) {
203
+ try { oscillator.stop(); } catch { }
204
+ oscillator.disconnect();
205
+ }
206
+ oscillator = null;
207
+ gainNode = null;
208
+ }
209
+
210
+ function applyStoppedState(): void {
211
+ root?.classList.remove('is-running');
212
+ if (markButton) markButton.disabled = true;
213
+ }
214
+
215
+ function stopSweep(resetStatus = true): void {
216
+ cancelAnimationFrame(animationId);
217
+ cleanupAudio();
218
+ running = false;
219
+ applyStoppedState();
220
+ if (resetStatus && statusDisplay) statusDisplay.textContent = strings.stopped!;
221
+ setButtonPlaying(false);
222
+ }
223
+
224
+ toggleButton?.addEventListener('click', () => {
225
+ if (running) stopSweep();
226
+ else startSweep();
227
+ });
228
+
229
+ markButton?.addEventListener('click', () => {
230
+ if (!dropoutDisplay) return;
231
+ dropoutDisplay.textContent = formatHz(currentHz);
232
+ if (noteDisplay) {
233
+ noteDisplay.textContent = `${strings.crossoverEstimate!}: ${formatHz(currentHz)}.`;
234
+ }
235
+ stopSweep();
236
+ });
237
+
238
+ resetButton?.addEventListener('click', () => {
239
+ stopSweep(false);
240
+ currentHz = startHz;
241
+ if (dropoutDisplay) dropoutDisplay.textContent = strings.dropoutEmpty!;
242
+ if (noteDisplay) noteDisplay.textContent = strings.safeStart!;
243
+ if (statusDisplay) statusDisplay.textContent = strings.ready!;
244
+ updateVisuals();
245
+ });
246
+
247
+ volumeInput?.addEventListener('input', () => {
248
+ if (gainNode && audioContext) {
249
+ gainNode.gain.setTargetAtTime(Number(volumeInput.value), audioContext.currentTime, 0.03);
250
+ }
251
+ });
252
+ </script>
253
+ </div>
@@ -0,0 +1,29 @@
1
+ import type { HardwareToolEntry, ToolLocaleContent } from '../../types';
2
+ import type { SubwooferCrossoverTestUI } from './ui';
3
+
4
+ export type SubwooferCrossoverTestLocaleContent = ToolLocaleContent<SubwooferCrossoverTestUI>;
5
+
6
+ export const subwooferCrossoverTest: HardwareToolEntry<SubwooferCrossoverTestUI> = {
7
+ id: 'subwoofer-crossover-test',
8
+ icons: {
9
+ bg: 'mdi:speaker-wireless',
10
+ fg: 'mdi:waves-arrow-left',
11
+ },
12
+ i18n: {
13
+ de: () => import('./i18n/de').then((m) => m.content),
14
+ en: () => import('./i18n/en').then((m) => m.content),
15
+ es: () => import('./i18n/es').then((m) => m.content),
16
+ fr: () => import('./i18n/fr').then((m) => m.content),
17
+ id: () => import('./i18n/id').then((m) => m.content),
18
+ it: () => import('./i18n/it').then((m) => m.content),
19
+ ja: () => import('./i18n/ja').then((m) => m.content),
20
+ ko: () => import('./i18n/ko').then((m) => m.content),
21
+ nl: () => import('./i18n/nl').then((m) => m.content),
22
+ pl: () => import('./i18n/pl').then((m) => m.content),
23
+ pt: () => import('./i18n/pt').then((m) => m.content),
24
+ ru: () => import('./i18n/ru').then((m) => m.content),
25
+ sv: () => import('./i18n/sv').then((m) => m.content),
26
+ tr: () => import('./i18n/tr').then((m) => m.content),
27
+ zh: () => import('./i18n/zh').then((m) => m.content),
28
+ },
29
+ };
@@ -0,0 +1,188 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SubwooferCrossoverTestUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'subwoofer-frequenzweichen-test-online';
7
+ const title = 'Subwoofer Frequenzweichentest';
8
+ const description =
9
+ 'Führe einen Sinus-Sweep von 200 Hz bis 10 Hz in deinem Browser durch, um zu finden, wo dein Subwoofer abfällt, aussetzt oder an die Hauptlautsprecher übergibt.';
10
+
11
+ const faqData = [
12
+ {
13
+ question: 'Was misst ein Subwoofer-Frequenzweichen-Test?',
14
+ answer:
15
+ 'Er hilft dir, den Punkt zu hören, an dem der Bass zwischen deinen Hauptlautsprechern und dem Subwoofer nicht mehr durchgängig klingt. Eine Lücke, ein plötzlicher Pegelwechsel oder ein fehlender Bereich kann auf eine falsche Übergangsfrequenz, ein Phasenproblem, Raumauslöschung oder die Grenze des Subwoofers hinweisen.',
16
+ },
17
+ {
18
+ question: 'Warum sweeped dieser Test von 200 Hz auf 10 Hz herunter?',
19
+ answer:
20
+ 'Die meisten Heimkino-Übergangsfrequenzen liegen zwischen 60 Hz und 120 Hz, während viele Kompaktlautsprecher oberhalb oder unterhalb dieses Bereichs an Ausgabe verlieren. Das Heruntersweepen von 200 Hz macht die Lautsprecher-Subwoofer-Übergabe leicht hörbar, bevor der Ton den tiefen Subbass erreicht.',
21
+ },
22
+ {
23
+ question: 'Kann dieser Online-Subwoofer-Basstest Lautsprecher beschädigen?',
24
+ answer:
25
+ 'Ja, sehr tiefe Frequenzen bei hoher Lautstärke können kleine Lautsprecher überlasten oder einen Subwoofer überfordern. Starte leise, vermeide verstärkte Bassmoden und stoppe sofort, wenn du Klappern, Klopfen oder mechanische Überlastung hörst.',
26
+ },
27
+ {
28
+ question: 'Ist die markierte Ausfallfrequenz die exakte Übergangsfrequenz, die ich einstellen sollte?',
29
+ answer:
30
+ 'Nein. Betrachte sie als Hörtipp, nicht als Labormessung. Die beste Übergangsfrequenz hängt auch von den Lautsprecherspezifikationen, der Raumaufstellung, der Phase, der Entfernungskorrektur und dem Kalibrierungsziel ab.',
31
+ },
32
+ ];
33
+
34
+ const howToData = [
35
+ {
36
+ name: 'Stelle eine sichere Hörlautstärke ein',
37
+ text: 'Reduziere zuerst die Systemlautstärke. Der Sweep verwendet eine erzeugte Sinuswelle, sodass der Bass auch dann intensiv werden kann, wenn die Browser-Lautstärke moderat erscheint.',
38
+ },
39
+ {
40
+ name: 'Starte den 200 Hz bis 10 Hz Sweep',
41
+ text: 'Drücke Sweep starten und höre von deinem normalen Sitzplatz aus. Der Ton bewegt sich gleichmäßig durch den Bassbereich, in dem sich Subwoofer, Hauptlautsprecher und Raumakustik überlappen.',
42
+ },
43
+ {
44
+ name: 'Höre auf den Ausfall oder die Übergabe',
45
+ text: 'Achte auf den Moment, in dem der Bass schwächer wird, verschwindet, den Ort wechselt oder zwischen Subwoofer und Hauptlautsprechern ungleichmäßig klingt.',
46
+ },
47
+ {
48
+ name: 'Markiere die Frequenz',
49
+ text: 'Drücke Ausfall markieren am ersten deutlichen Problempegel. Verwende diese Frequenz als Hinweis zur Anpassung von Übergangsfrequenz, Phase, Aufstellung oder Raumkorrektur.',
50
+ },
51
+ ];
52
+
53
+ const faqSchema: WithContext<FAQPage> = {
54
+ '@context': 'https://schema.org',
55
+ '@type': 'FAQPage',
56
+ mainEntity: faqData.map((item) => ({
57
+ '@type': 'Question',
58
+ name: item.question,
59
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
60
+ })),
61
+ };
62
+
63
+ const howToSchema: WithContext<HowTo> = {
64
+ '@context': 'https://schema.org',
65
+ '@type': 'HowTo',
66
+ name: title,
67
+ description,
68
+ step: howToData.map((step, index) => ({
69
+ '@type': 'HowToStep',
70
+ position: index + 1,
71
+ name: step.name,
72
+ text: step.text,
73
+ })),
74
+ };
75
+
76
+ const appSchema: WithContext<SoftwareApplication> = {
77
+ '@context': 'https://schema.org',
78
+ '@type': 'SoftwareApplication',
79
+ name: title,
80
+ description,
81
+ applicationCategory: 'UtilityApplication',
82
+ operatingSystem: 'All',
83
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
84
+ inLanguage: 'de',
85
+ };
86
+
87
+ export const content: ToolLocaleContent<SubwooferCrossoverTestUI> = {
88
+ slug,
89
+ title,
90
+ description,
91
+ faq: faqData,
92
+ howTo: howToData,
93
+ schemas: [faqSchema, howToSchema, appSchema],
94
+ bibliography,
95
+ seo: [
96
+ { type: 'title', text: 'Finde Die Basslücke Zwischen Deinen Lautsprechern Und Dem Subwoofer', level: 2 },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'Ein Subwoofer sollte nicht wie eine separate Box in der Ecke klingen. Der Bass sollte gleichmäßig bleiben, wenn die Töne von deinen Hauptlautsprechern in den Sub übergehen. Dieser Test sweeped von <strong>200 Hz bis 10 Hz</strong>, damit du genau die Zone hören kannst, in der die Übergabe schwach, dröhnend, ortbar oder stumm wird.',
100
+ },
101
+ {
102
+ type: 'table',
103
+ headers: ['Was du hörst', 'Was es normalerweise bedeutet', 'Was du zuerst versuchen solltest'],
104
+ rows: [
105
+ ['Bass verschwindet um 70-100 Hz', 'Subwoofer und Lautsprecher löschen sich gegenseitig nahe der Übergangsfrequenz aus.', 'Phase umkehren, Entfernung/Verzögerung anpassen, dann den Sweep wiederholen.'],
106
+ ['Bass dröhnt in einem schmalen Band', 'Raummode oder zu viel Überlappung zwischen Lautsprechern und Subwoofer.', 'Übergangsfrequenz leicht senken oder Subwoofer/Hörposition verschieben.'],
107
+ ['Bass scheint vom Subwoofer-Standort zu kommen', 'Übergangsfrequenz zu hoch oder Subwoofer-Pegel zu heiß.', '80 Hz oder niedriger versuchen und Subwoofer-Verstärkung reduzieren.'],
108
+ ['Tiefbass verblasst unter 30-40 Hz', 'Normale Ausdehnungsgrenze vieler Subs, besonders kompakter Modelle.', 'Subwoofer-Spezifikation prüfen, bevor du ein Problem verfolgst, das physikalisch sein könnte.'],
109
+ ],
110
+ },
111
+ { type: 'title', text: 'Was Dir Die Ausfallfrequenz Sagt', level: 3 },
112
+ {
113
+ type: 'diagnostic',
114
+ variant: 'info',
115
+ title: 'Verwende die markierte Frequenz als Abstimmungshinweis',
116
+ badge: 'Hörtipps',
117
+ html: '<p>Wenn der markierte Punkt nahe deiner AVR-Übergangsfrequenz liegt, ist das Problem wahrscheinlich Integration: Phase, Entfernung, Polarität, Pegel oder die Steilheit der Filter. Liegt der markierte Punkt viel tiefer, hörst du vielleicht, wie der Subwoofer an seine Leistungsgrenze stößt. Ändert sich das Problem stark, wenn du deinen Kopf bewegst, dominiert der Raum das Ergebnis.</p>',
118
+ },
119
+ {
120
+ type: 'title',
121
+ text: 'Übliche Übergangsfrequenzbereiche',
122
+ level: 3,
123
+ },
124
+ {
125
+ type: 'table',
126
+ headers: ['Lautsprechertyp', 'Typischer Übergangsfrequenz-Startpunkt', 'Warum'],
127
+ rows: [
128
+ ['Kleine Satelliten', '100-150 Hz', 'Winzige Gehäuse können normalerweise keinen sauberen oberen Bass bei Kino-Lautstärken wiedergeben.'],
129
+ ['Regallautsprecher', '70-100 Hz', 'Oft genug Bass für eine saubere Übergabe, ohne den Sub ortbar zu machen.'],
130
+ ['Standlautsprecher', '50-80 Hz', 'Größere Tieftöner können mehr Mittelbass bewältigen, aber der Raum kann trotzdem Subwoofer-Bassmanagement bevorzugen.'],
131
+ ['THX-Setup', '80 Hz', 'Ein praktischer Standardwert, der für viele Systeme gut funktioniert und Tiefbass zum Sub leitet.'],
132
+ ],
133
+ },
134
+ { type: 'title', text: 'Übergangsfrequenzproblem Oder Raumproblem?', level: 3 },
135
+ {
136
+ type: 'comparative',
137
+ columns: 2,
138
+ items: [
139
+ {
140
+ title: 'Übergangsfrequenz oder Phasenproblem',
141
+ description: 'Die Schwachstelle erscheint nahe der Übergangsfrequenz und verbessert sich nach Änderung von Phase, Polarität, Entfernung oder Übergangsfrequenz-Einstellung.',
142
+ points: ['Normalerweise vom gleichen Sitzplatz aus wiederholbar.', 'Oft um 60-120 Hz zentriert.'],
143
+ },
144
+ {
145
+ title: 'Raumauslöschung',
146
+ description: 'Die Schwachstelle ändert sich drastisch, wenn du deinen Kopf bewegst, den Sitzplatz wechselst oder den Subwoofer ein kurzes Stück verschiebst.',
147
+ points: ['Sehr positionsabhängig.', 'Oft mehr durch Aufstellung als durch Einstellungen zu lösen.'],
148
+ },
149
+ ],
150
+ },
151
+ {
152
+ type: 'tip',
153
+ title: 'Beste Art, den Test durchzuführen',
154
+ html: 'Setze dich dorthin, wo du tatsächlich Filme schaust oder Musik hörst. Stehe nicht neben dem Subwoofer. Eine Übergangsfrequenz, die neben dem Gehäuse gut klingt, kann auf dem Sofa immer noch eine Lücke hinterlassen.',
155
+ },
156
+ {
157
+ type: 'summary',
158
+ title: 'Was nach dem Sweep zu ändern ist',
159
+ items: [
160
+ 'Liegt die Lücke nahe der aktuellen Übergangsfrequenz, probiere 10-Hz-Änderungen und wiederhole den Sweep.',
161
+ 'Teste den Phasenschalter oder die Verzögerungseinstellung des Subwoofers, wenn das schwache Band nahe der Übergangsfrequenz liegt.',
162
+ 'Wird der Bass an einem Sitzplatz stärker und verschwindet an einem anderen, verschiebe den Subwoofer, bevor du alle AVR-Einstellungen änderst.',
163
+ 'Nach Aufstellungs- oder Übergangsfrequenzänderungen führe die Raumkorrektur erneut aus, damit der Receiver das neue Setup misst.',
164
+ 'Verwende die markierte Frequenz als Leitfaden für die Abstimmung und bestätige dann mit Musik, Filmen und vertrauten Basslinien.',
165
+ ],
166
+ },
167
+ ],
168
+ ui: {
169
+ sweepLabel: 'Subwoofer-Tieffrequenz-Sweep',
170
+ currentFrequency: 'Aktuelle Frequenz',
171
+ targetFrequency: 'Ziel',
172
+ elapsed: 'Verstrichen',
173
+ statusReady: 'Bereit für Tief-Sweep',
174
+ statusRunning: 'Sweepe nach unten',
175
+ statusStopped: 'Sweep gestoppt',
176
+ start: 'Sweep starten',
177
+ stop: 'Sweep stoppen',
178
+ markDropout: 'Ausfall markieren',
179
+ reset: 'Zurücksetzen',
180
+ volume: 'Ausgabepegel',
181
+ duration: 'Sweep-Dauer',
182
+ safeStart: 'Starte mit niedriger Lautstärke und markiere dann die erste Frequenz, bei der der Bass schwer hörbar wird.',
183
+ roomNote: 'Raumposition und Phase können das Ergebnis drastisch verändern.',
184
+ dropoutLabel: 'Markierter Punkt',
185
+ dropoutEmpty: 'Noch nicht markiert',
186
+ crossoverEstimate: 'Geschätzter Ausfallpunkt',
187
+ },
188
+ };
@@ -0,0 +1,188 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SubwooferCrossoverTestUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'subwoofer-crossover-test';
7
+ const title = 'Subwoofer Crossover Test';
8
+ const description =
9
+ 'Run a 200 Hz to 10 Hz sine sweep in your browser to find where your subwoofer fades, drops out, or hands off to your main speakers.';
10
+
11
+ const faqData = [
12
+ {
13
+ question: 'What does a subwoofer crossover test measure?',
14
+ answer:
15
+ 'It helps you hear the point where bass stops sounding continuous between your main speakers and subwoofer. A gap, sudden level change, or missing range can point to an incorrect crossover frequency, phase issue, room cancellation, or subwoofer limit.',
16
+ },
17
+ {
18
+ question: 'Why does this test sweep from 200 Hz down to 10 Hz?',
19
+ answer:
20
+ 'Most home theater crossovers sit between 60 Hz and 120 Hz, while many compact speakers start losing output above or below that range. Sweeping down from 200 Hz makes the speaker-to-subwoofer handoff easy to hear before the tone reaches deep sub-bass.',
21
+ },
22
+ {
23
+ question: 'Can this online subwoofer bass test damage speakers?',
24
+ answer:
25
+ 'Yes, very low frequencies at high volume can overdrive small speakers or stress a subwoofer. Start quietly, avoid boosted bass modes, and stop immediately if you hear rattling, knocking, or mechanical distress.',
26
+ },
27
+ {
28
+ question: 'Is the marked dropout frequency the exact crossover setting I should use?',
29
+ answer:
30
+ 'No. Treat it as a listening clue, not a lab measurement. The best crossover setting also depends on speaker specifications, room placement, phase, distance correction, and calibration target.',
31
+ },
32
+ ];
33
+
34
+ const howToData = [
35
+ {
36
+ name: 'Set a safe listening level',
37
+ text: 'Lower your system volume first. The sweep uses a generated sine wave, so the bass can become intense even when the browser volume looks modest.',
38
+ },
39
+ {
40
+ name: 'Start the 200 Hz to 10 Hz sweep',
41
+ text: 'Press Start sweep and listen from your normal seat. The tone moves steadily through the bass range where subwoofers, main speakers, and room acoustics overlap.',
42
+ },
43
+ {
44
+ name: 'Listen for the dropout or handoff',
45
+ text: 'Pay attention to the moment where bass becomes weaker, disappears, changes location, or sounds uneven between the subwoofer and main speakers.',
46
+ },
47
+ {
48
+ name: 'Mark the frequency',
49
+ text: 'Press Mark dropout at the first clear problem point. Use that frequency as a clue for adjusting crossover, phase, placement, or room correction.',
50
+ },
51
+ ];
52
+
53
+ const faqSchema: WithContext<FAQPage> = {
54
+ '@context': 'https://schema.org',
55
+ '@type': 'FAQPage',
56
+ mainEntity: faqData.map((item) => ({
57
+ '@type': 'Question',
58
+ name: item.question,
59
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
60
+ })),
61
+ };
62
+
63
+ const howToSchema: WithContext<HowTo> = {
64
+ '@context': 'https://schema.org',
65
+ '@type': 'HowTo',
66
+ name: title,
67
+ description,
68
+ step: howToData.map((step, index) => ({
69
+ '@type': 'HowToStep',
70
+ position: index + 1,
71
+ name: step.name,
72
+ text: step.text,
73
+ })),
74
+ };
75
+
76
+ const appSchema: WithContext<SoftwareApplication> = {
77
+ '@context': 'https://schema.org',
78
+ '@type': 'SoftwareApplication',
79
+ name: title,
80
+ description,
81
+ applicationCategory: 'UtilityApplication',
82
+ operatingSystem: 'All',
83
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
84
+ inLanguage: 'en',
85
+ };
86
+
87
+ export const content: ToolLocaleContent<SubwooferCrossoverTestUI> = {
88
+ slug,
89
+ title,
90
+ description,
91
+ faq: faqData,
92
+ howTo: howToData,
93
+ schemas: [faqSchema, howToSchema, appSchema],
94
+ bibliography,
95
+ seo: [
96
+ { type: 'title', text: 'Find The Bass Gap Between Your Speakers And Subwoofer', level: 2 },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'A subwoofer should not sound like a separate box in the corner. Bass should stay even as notes move from your main speakers into the sub. This test sweeps from <strong>200 Hz down to 10 Hz</strong> so you can hear the exact zone where the handoff becomes weak, boomy, localizable, or silent.',
100
+ },
101
+ {
102
+ type: 'table',
103
+ headers: ['What you hear', 'What it usually means', 'What to try first'],
104
+ rows: [
105
+ ['Bass vanishes around 70-100 Hz', 'Subwoofer and speakers may be cancelling each other near the crossover.', 'Flip phase, adjust distance/delay, then repeat the sweep.'],
106
+ ['Bass gets boomy around one narrow band', 'Room mode or too much overlap between speakers and subwoofer.', 'Lower crossover slightly or move the subwoofer/listening position.'],
107
+ ['Bass seems to come from the subwoofer location', 'Crossover may be too high or subwoofer level may be too hot.', 'Try 80 Hz or lower and reduce subwoofer gain.'],
108
+ ['Deep bass fades below 30-40 Hz', 'Normal extension limit for many subs, especially compact models.', 'Check the subwoofer specification before chasing a problem that may be physical.'],
109
+ ],
110
+ },
111
+ { type: 'title', text: 'What The Dropout Frequency Tells You', level: 3 },
112
+ {
113
+ type: 'diagnostic',
114
+ variant: 'info',
115
+ title: 'Use the marked frequency as a tuning clue',
116
+ badge: 'Listening clues',
117
+ html: '<p>If the marked point is close to your AVR crossover, the problem is probably integration: phase, distance, polarity, level, or the slope of the filters. If the marked point is much lower, you may be hearing the subwoofer running out of output. If the problem changes a lot when you move your head, the room is dominating the result.</p>',
118
+ },
119
+ {
120
+ type: 'title',
121
+ text: 'Common Crossover Ranges',
122
+ level: 3,
123
+ },
124
+ {
125
+ type: 'table',
126
+ headers: ['Speaker type', 'Typical crossover starting point', 'Why'],
127
+ rows: [
128
+ ['Small satellites', '100-150 Hz', 'Tiny cabinets usually cannot play clean upper bass at theater levels.'],
129
+ ['Bookshelf speakers', '70-100 Hz', 'Often enough bass for a clean handoff without making the sub easy to locate.'],
130
+ ['Floorstanding speakers', '50-80 Hz', 'Larger woofers can handle more mid-bass, but the room may still prefer subwoofer bass management.'],
131
+ ['THX-style setup', '80 Hz', 'A practical default that works well for many systems and keeps deep bass routed to the sub.'],
132
+ ],
133
+ },
134
+ { type: 'title', text: 'Crossover Problem Or Room Problem?', level: 3 },
135
+ {
136
+ type: 'comparative',
137
+ columns: 2,
138
+ items: [
139
+ {
140
+ title: 'Crossover or phase issue',
141
+ description: 'The weak spot appears near the crossover frequency and improves after changing phase, polarity, distance, or crossover setting.',
142
+ points: ['Usually repeatable from the same seat.', 'Often centered around 60-120 Hz.'],
143
+ },
144
+ {
145
+ title: 'Room cancellation',
146
+ description: 'The weak spot changes dramatically when you move your head, change seats, or move the subwoofer a short distance.',
147
+ points: ['Very position dependent.', 'Often solved by placement more than settings.'],
148
+ },
149
+ ],
150
+ },
151
+ {
152
+ type: 'tip',
153
+ title: 'Best way to run the test',
154
+ html: 'Sit where you actually watch movies or listen to music. Do not stand next to the subwoofer. A crossover that sounds good beside the cabinet can still leave a hole at the sofa.',
155
+ },
156
+ {
157
+ type: 'summary',
158
+ title: 'What to change after the sweep',
159
+ items: [
160
+ 'If the hole is near the current crossover, try 10 Hz changes and repeat the sweep.',
161
+ 'Try the subwoofer phase switch or delay setting if the weak band sits near the crossover.',
162
+ 'If the bass gets stronger in one seat and disappears in another, move the subwoofer before changing every AVR setting.',
163
+ 'After placement or crossover changes, rerun room correction so the receiver measures the new setup.',
164
+ 'Use the marked frequency to guide tuning, then confirm with music, movies, and familiar bass lines.',
165
+ ],
166
+ },
167
+ ],
168
+ ui: {
169
+ sweepLabel: 'Subwoofer low-frequency sweep',
170
+ currentFrequency: 'Current frequency',
171
+ targetFrequency: 'Target',
172
+ elapsed: 'Elapsed',
173
+ statusReady: 'Ready for low sweep',
174
+ statusRunning: 'Sweeping down',
175
+ statusStopped: 'Sweep stopped',
176
+ start: 'Start sweep',
177
+ stop: 'Stop sweep',
178
+ markDropout: 'Mark dropout',
179
+ reset: 'Reset',
180
+ volume: 'Output level',
181
+ duration: 'Sweep duration',
182
+ safeStart: 'Start at low volume, then mark the first frequency where bass becomes hard to hear.',
183
+ roomNote: 'Room position and phase can change the result dramatically.',
184
+ dropoutLabel: 'Marked point',
185
+ dropoutEmpty: 'Not marked yet',
186
+ crossoverEstimate: 'Estimated dropout point',
187
+ },
188
+ };