Cleanup pass: remove dead code, fix bugs, simplify

Dead code removed:
- MusicAnalyzer.BuildWaveFrame (replaced by DrumDetector + BuildMelodyFrame)
- MusicAnalyzer.ExtractFeatures simplified to melody-only (removed rhythm band)
- MusicAnalyzer.RhythmLow/RhythmHigh constants, TickFeature.RhythmFlux
- LiveCapture._liveMaxFlux + _prevRhythmMag (computed, never read)
- State.ActualA/ActualB, State.LastSentA/LastSentB (set, never read)
- Program.cs StrengthChanged handler (only wrote to dead fields)
- Command.Mode property (never referenced)
- DrumDetector.FreqKick/Snare/Brass/Silent static arrays (unused)

Bugs fixed:
- DrumDetector.BuildFrame: freqBytes was byte[16], now byte[4]
- CoyoteDevice fallback: use nameFilter param instead of hardcoded string

Refactoring:
- Server.DoStatus calls BuildStatusPush(null) instead of duplicating
- HeatMap: removed redundant colW assignment
- Removed unused System.Numerics imports from LiveCapture, MusicAnalyzer
This commit is contained in:
2026-08-09 14:01:19 +00:00
parent badc599dee
commit 1ab397767a
9 changed files with 8 additions and 103 deletions
+3 -65
View File
@@ -1,4 +1,3 @@
using System.Numerics;
using FftSharp;
namespace Substation;
@@ -9,35 +8,15 @@ public static class MusicAnalyzer
public const int HopSize = 1024;
public const double TickDuration = 0.1;
const double RhythmLow = 20, RhythmHigh = 250;
const double MelodyLow = 300, MelodyHigh = 4000;
public static (double rhythmEnergy, double rhythmFlux, double melodyEnergy, double melodyFreq)
ExtractFeatures(double[] magnitude, double[]? prevRhythmMag, int sampleRate)
public static (double melodyEnergy, double melodyFreq)
ExtractFeatures(double[] magnitude, int sampleRate)
{
double binWidth = (double)sampleRate / WindowSize;
int rhythmLoBin = (int)(RhythmLow / binWidth);
int rhythmHiBin = (int)(RhythmHigh / binWidth);
int melodyLoBin = (int)(MelodyLow / binWidth);
int melodyHiBin = (int)(MelodyHigh / binWidth);
// Rhythm band energy
double rhythmEnergy = 0;
for (int i = rhythmLoBin; i <= rhythmHiBin && i < magnitude.Length; i++)
rhythmEnergy += magnitude[i] * magnitude[i];
rhythmEnergy = Math.Sqrt(rhythmEnergy / (rhythmHiBin - rhythmLoBin + 1));
// Spectral flux (positive change in rhythm band)
double rhythmFlux = 0;
if (prevRhythmMag != null)
{
for (int i = rhythmLoBin; i <= rhythmHiBin && i < magnitude.Length; i++)
{
double diff = magnitude[i] - prevRhythmMag[i];
if (diff > 0) rhythmFlux += diff;
}
}
// Melody band: energy + dominant frequency (spectral peak)
double melodyEnergy = 0;
double peakMag = 0;
@@ -55,7 +34,7 @@ public static class MusicAnalyzer
melodyEnergy = Math.Sqrt(melodyEnergy / (melodyHiBin - melodyLoBin + 1));
double melodyFreq = peakBin * binWidth;
return (rhythmEnergy, rhythmFlux, melodyEnergy, melodyFreq);
return (melodyEnergy, melodyFreq);
}
public static int MapPitchToPeriod(double hz)
@@ -73,7 +52,6 @@ public static class MusicAnalyzer
public class TickFeature
{
public double RhythmFlux;
public double MelodyEnergy;
public double MelodyCount;
public readonly List<double> MelodyFreqSamples = new();
@@ -105,44 +83,4 @@ public static class MusicAnalyzer
return new WaveFrame(freqB, intB);
}
public static (WaveFrame chA, WaveFrame chB) BuildWaveFrame(TickFeature tf, double maxFlux, double maxMelodyEnergy)
{
const int rhythmFreqMs = 150;
double normalizedFlux = maxFlux > 0 ? tf.RhythmFlux / maxFlux : 0;
int onsetIntensity = (int)Math.Round(normalizedFlux * 100);
var intA = new[]
{
(byte)Math.Clamp(onsetIntensity, 0, 100),
(byte)Math.Clamp(onsetIntensity * 6 / 10, 0, 100),
(byte)Math.Clamp(onsetIntensity * 3 / 10, 0, 100),
(byte)0
};
var freqA = Freq.Compress4(new[] { rhythmFreqMs, rhythmFreqMs, rhythmFreqMs, rhythmFreqMs });
double avgEnergy = tf.MelodyCount > 0 ? tf.MelodyEnergy / tf.MelodyCount : 0;
double normalizedEnergy = maxMelodyEnergy > 0 ? avgEnergy / maxMelodyEnergy : 0;
int melodyIntensity = (int)Math.Round(normalizedEnergy * 80);
melodyIntensity = Math.Clamp(melodyIntensity, 0, 100);
double weightedFreq = 0;
double totalWeight = 0;
foreach (var f in tf.MelodyFreqSamples)
{
weightedFreq += f * f;
totalWeight += f;
}
double avgMelodyHz = totalWeight > 0 ? weightedFreq / totalWeight : 500;
int estimsMs = MapPitchToPeriod(avgMelodyHz);
var intB = new[]
{
(byte)melodyIntensity, (byte)melodyIntensity,
(byte)melodyIntensity, (byte)melodyIntensity
};
var freqB = Freq.Compress4(new[] { estimsMs, estimsMs, estimsMs, estimsMs });
return (new WaveFrame(freqA, intA), new WaveFrame(freqB, intB));
}
}