diff --git a/HearingProtector.csproj b/HearingProtector.csproj
index 5de8ecb..33b21d0 100644
--- a/HearingProtector.csproj
+++ b/HearingProtector.csproj
@@ -2,11 +2,17 @@
Exe
- net10.0
+ net10.0-windows
enable
enable
true
true
+ HearingProtector.Program
+
+
+
+
+
diff --git a/Program.cs b/Program.cs
index 45b56bd..0298498 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,10 +1,79 @@
-namespace HearingProtector
+using NAudio.CoreAudioApi;
+
+namespace HearingProtector;
+
+internal static class Program
{
- internal class Program
+ // ─── Настройки — только то, что интересно пользователю ───────────────
+ private const double MinVolumePercent = 1.0; // до какого % убавляем
+ private const double FullDecayMinutes = 30.0; // за сколько минут 100% → MinVolume
+ private const int PollMs = 1000; // шаг цикла
+ private const float UserChangeEps = 0.005f;// порог «ручное изменение»
+ private const int LogEveryTicks = 30; // лог раз в 30 сек
+
+ // ─── Производные величины — считаются автоматически ──────────────────
+ private static readonly double MinVolume = MinVolumePercent / 100.0;
+ private static readonly double TotalTicks = FullDecayMinutes * 60_000.0 / PollMs;
+ private static readonly double DecayPerTick = Math.Pow(MinVolume, 1.0 / TotalTicks);
+ private static readonly double DbPerTick = 20.0 * Math.Log10(DecayPerTick);
+
+ private static async Task Main()
{
- static void Main(string[] args)
+ using var enumerator = new MMDeviceEnumerator();
+ var device = enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
+ var volume = device.AudioEndpointVolume;
+
+ // ── Показываем пользователю, что мы из его настроек вывели ──
+ Console.WriteLine($"Диапазон: 100% → {MinVolumePercent:F1}%");
+ Console.WriteLine($"Заданное время: {FullDecayMinutes:F1} мин " +
+ $"({TotalTicks:F0} тиков по {PollMs} мс)");
+ Console.WriteLine($"Множитель/тик: ×{DecayPerTick:F6} " +
+ $"= {DbPerTick:F4} дБ");
+ Console.WriteLine();
+
+ float current = volume.MasterVolumeLevelScalar;
+ float lastSet = current;
+
+ Console.WriteLine($"Стартуем с {current * 100:F1}%. Ctrl+C — выход.");
+ Console.WriteLine();
+
+ int tick = 0;
+ while (true)
{
- Console.WriteLine("Hello, World!");
+ float actual = volume.MasterVolumeLevelScalar;
+
+ // 1) Реакция на ручное изменение громкости.
+ if (Math.Abs(actual - lastSet) > UserChangeEps)
+ {
+ var dir = actual > lastSet ? "повышение" : "понижение";
+ Console.WriteLine(
+ $"[{DateTime.Now:HH:mm:ss}] Ручное изменение ({dir}): " +
+ $"{lastSet * 100:F1}% → {actual * 100:F1}%");
+ current = actual;
+ }
+
+ // 2) Один экспоненциальный шаг вниз.
+ current = (float)Math.Max(MinVolume, current * DecayPerTick);
+
+ // 3) Применяем, если значение реально отличается.
+ if (Math.Abs(volume.MasterVolumeLevelScalar - current) > 0.0005f)
+ volume.MasterVolumeLevelScalar = current;
+
+ lastSet = current;
+
+ // 4) Редкий лог с ETA.
+ if (++tick % LogEveryTicks == 0)
+ {
+ double etaSec = Math.Log(MinVolume / current) / Math.Log(DecayPerTick)
+ * PollMs / 1000.0;
+ var eta = TimeSpan.FromSeconds(Math.Max(0, etaSec));
+ Console.WriteLine(
+ $"[{DateTime.Now:HH:mm:ss}] " +
+ $"Громкость: {current * 100:F1}% " +
+ $"(до минимума ~{eta:hh\\:mm\\:ss})");
+ }
+
+ await Task.Delay(PollMs);
}
}
-}
+}
\ No newline at end of file