Files
Substation/Protocol.cs
T
mute 1ab397767a 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
2026-08-09 14:01:19 +00:00

179 lines
5.0 KiB
C#

using System.Text.Json.Serialization;
namespace Substation;
public static class Freq
{
public static byte Compress(int ms)
{
if (ms is >= 10 and <= 100) return (byte)ms;
if (ms is > 100 and <= 600) return (byte)((ms - 100) / 5 + 100);
if (ms is > 600 and <= 1000) return (byte)((ms - 600) / 10 + 200);
return 10;
}
public static byte[] Compress4(int[] ms)
{
if (ms.Length != 4) throw new ArgumentException("freq must have exactly 4 values", nameof(ms));
return new byte[]
{
Compress(ms[0]), Compress(ms[1]), Compress(ms[2]), Compress(ms[3])
};
}
}
public static class Intensity
{
public static byte Clamp(int v) => (byte)Math.Clamp(v, 0, 100);
public static byte[] Clamp4(int[] v)
{
if (v.Length != 4) throw new ArgumentException("intensity must have exactly 4 values", nameof(v));
return new byte[] { Clamp(v[0]), Clamp(v[1]), Clamp(v[2]), Clamp(v[3]) };
}
}
public enum StrengthMode : byte
{
None = 0b00,
Add = 0b01,
Sub = 0b10,
Abs = 0b11
}
public enum LimitMode
{
Clamp = 0,
Scale = 1
}
public static class B0
{
public static byte PackModes(StrengthMode a, StrengthMode b) =>
(byte)(((int)a << 2) | (int)b);
public static byte[] Build(
byte seq,
StrengthMode modeA, StrengthMode modeB,
byte strengthA, byte strengthB,
byte[] freqA, byte[] intA,
byte[] freqB, byte[] intB)
{
if (freqA.Length != 4 || intA.Length != 4 || freqB.Length != 4 || intB.Length != 4)
throw new ArgumentException("wave arrays must be 4 bytes each");
var f = new byte[20];
f[0] = 0xB0;
f[1] = (byte)((seq << 4) | (PackModes(modeA, modeB) & 0x0F));
f[2] = strengthA;
f[3] = strengthB;
Buffer.BlockCopy(freqA, 0, f, 4, 4);
Buffer.BlockCopy(intA, 0, f, 8, 4);
Buffer.BlockCopy(freqB, 0, f, 12, 4);
Buffer.BlockCopy(intB, 0, f, 16, 4);
return f;
}
public static readonly byte[] ChannelOff =
{ 0, 0, 0, 0 };
public static readonly byte[] IntensityOff =
{ 0, 0, 0, 101 };
}
public static class BF
{
public static byte[] Build(
byte capA, byte capB,
byte freqBalA, byte freqBalB,
byte intBalA, byte intBalB)
{
return new byte[]
{
0xBF, capA, capB, freqBalA, freqBalB, intBalA, intBalB
};
}
}
public record WaveFrame(byte[] Freq, byte[] Intensity);
public class Command
{
[JsonPropertyName("op")] public string Op { get; set; } = "";
[JsonPropertyName("channel")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Channel { get; set; }
[JsonPropertyName("value")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? Value { get; set; }
[JsonPropertyName("freq")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int[]? Freq { get; set; }
[JsonPropertyName("intensity")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int[]? Intensity { get; set; }
[JsonPropertyName("frames")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public FrameDto[]? Frames { get; set; }
[JsonPropertyName("softcapA")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? SoftCapA { get; set; }
[JsonPropertyName("softcapB")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? SoftCapB { get; set; }
[JsonPropertyName("freqBalA")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? FreqBalA { get; set; }
[JsonPropertyName("freqBalB")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? FreqBalB { get; set; }
[JsonPropertyName("intBalA")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? IntBalA { get; set; }
[JsonPropertyName("intBalB")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? IntBalB { get; set; }
}
public class FrameDto
{
[JsonPropertyName("freq")] public int[]? Freq { get; set; }
[JsonPropertyName("intensity")] public int[]? Intensity { get; set; }
}
public class OkResponse
{
[JsonPropertyName("ok")] public bool Ok => true;
[JsonPropertyName("msg")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Msg { get; set; }
}
public class ErrResponse
{
[JsonPropertyName("ok")] public bool Ok => false;
[JsonPropertyName("error")] public string Error { get; set; } = "";
}
public class StatusResponse
{
[JsonPropertyName("ok")] public bool Ok => true;
[JsonPropertyName("event")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Event { get; set; }
[JsonPropertyName("connected")] public bool Connected { get; set; }
[JsonPropertyName("strengthA")] public int StrengthA { get; set; }
[JsonPropertyName("strengthB")] public int StrengthB { get; set; }
}