+ {/* Signal Type Grid */}
+
+
+
+ {signalTypes.map((type) => {
+ const Icon = type.icon;
+ const isSelected = config.signalType === type.value;
+ return (
+
+ );
+ })}
+
+
+
+ {/* Dynamic Controls Based on Signal Type */}
+
+ {config.signalType === "sine" && (
+
+
+
+
+ 20 Hz
+ 200 Hz
+ 2 kHz
+ 20 kHz
+
+
+ )}
+
+ {config.signalType === "sine_sweep" && (
+
+
+
+
+
+
+ setConfig((prev) => ({ ...prev, startFreq: Number(e.target.value) }))
+ }
+ disabled={isCapturing}
+ className="w-full px-2 py-1.5 bg-gray-600 border border-gray-500 rounded text-white text-sm disabled:opacity-50 focus:border-indigo-500 focus:outline-none"
+ />
+ Hz
+
+
+
+
+
+
+ setConfig((prev) => ({ ...prev, endFreq: Number(e.target.value) }))
+ }
+ disabled={isCapturing}
+ className="w-full px-2 py-1.5 bg-gray-600 border border-gray-500 rounded text-white text-sm disabled:opacity-50 focus:border-indigo-500 focus:outline-none"
+ />
+ Hz
+
+
+
+
+
+
+ setConfig((prev) => ({ ...prev, sweepDuration: Number(e.target.value) }))
+ }
+ disabled={isCapturing}
+ className="w-full px-2 py-1.5 bg-gray-600 border border-gray-500 rounded text-white text-sm disabled:opacity-50 focus:border-indigo-500 focus:outline-none"
+ />
+ sec
+
+
+
+
+ Logarithmic sweep: {config.startFreq} Hz → {config.endFreq} Hz (
+ {config.sweepDuration}s)
+
+
+ )}
+
+ {!["sine", "sine_sweep"].includes(config.signalType) && (
+
+
+ {config.signalType === "white" && "Equal power at all frequencies"}
+ {config.signalType === "pink" && "1/f spectrum, equal power per octave"}
+ {config.signalType === "brown" && "1/f² spectrum, -6 dB per octave"}
+ {config.signalType === "blue" && "f spectrum, +3 dB per octave"}
+ {config.signalType === "violet" && "f² spectrum, +6 dB per octave"}
+
+
+ )}
+
+
+ {/* Amplitude Control */}
+
+
+
+ {Math.round(config.amplitude * 100)}%
+
+
+ setConfig((prev) => ({ ...prev, amplitude: Number(e.target.value) / 100 }))
+ }
+ disabled={isCapturing}
+ className="w-full h-2 bg-gray-600 rounded appearance-none cursor-pointer disabled:opacity-50"
+ />
+
+ Silent
+ Full Scale
+
+
+
+ {/* Output Channel Selection */}
+
+
+
+
+
+
+ {!useAllChannels && deviceChannels > 0 && (
+
+
+ {Array.from({ length: deviceChannels }, (_, i) => i + 1).map((channel) => (
+
+ ))}
+
+ {selectedChannels.size === 0 && (
+
+ Select at least one channel
+
+ )}
+
+ )}
+
+
+ {/* Status Indicator */}
+ {isCapturing && config.enabled && (
+
+ )}
+