Как исправить треск / треск звука при последовательном воспроизведении сэмплов C# - PullRequest
0 голосов
/ 04 мая 2020

Контекст:
Простое. Net Консольное приложение Core 3.1.
Я пытаюсь воспроизвести звук, созданный программно, из строки, определяющей последовательность нот (длительность и частота), используя синусоидальные волны чтобы имитировать "ретро" звук, а также для простоты.
Я использовал для этого два метода, и оба вызывают одну и ту же проблему.

Метод 1:
Используйте System.Console.Beep(int frequency, int duration) несколько раз. Это приводит к появлению «хлопка» или «треска» между каждой сыгранной нотой. Также была небольшая задержка в воспроизведении, что было нежелательно, и я пошел искать другой метод.

Метод 2:
На этот раз с использованием правильной звуковой библиотеки; NAudio, я использовал SampleGenerator для создания ISampleProvider в List <>, а затем отправил их в ConcatenatingSampleProvider, а затем создал WaveOutEvent, инициализировал его с помощью CSP и воспроизвел его так:

  /// <summary>
  /// Tunes are formatted as such in 120BPM: "#8ths Note Octave Dash" e.g. "4A3-2C4-4re-"
  /// </summary>
  public static async Task PlayTune(string tune) =>
     await Task.Factory.StartNew((tune) =>
     {
        var t = (string)tune;
        List<ISampleProvider> sampleProviders = new List<ISampleProvider>();

        for (int i = 0; i < t.Length; i += 4)
        {
           int.TryParse(t[i].ToString(), out int d);
           var note = t[i + 1].ToString() + t[i + 2].ToString();

           if (note == "re")
              sampleProviders.Add(new SignalGenerator() { Gain = 0.0 }.Take(TimeSpan.FromMilliseconds(1000.0 / 8.0 * d)));
           else
           {
              sampleProviders.Add(new SignalGenerator() { Gain = 0.2, Frequency = GetFrequency(note), Type = SignalGeneratorType.Sin, }
                 .Take(TimeSpan.FromMilliseconds(1000.0 / 8.0 * d)));
           }
        }


        var ewh = new EventWaitHandle(false, EventResetMode.ManualReset);

        using var wo = new WaveOutEvent();
        wo.Init(new ConcatenatingSampleProvider(sampleProviders));
        wo.PlaybackStopped += new EventHandler<StoppedEventArgs>((obj, args) => { ewh.Set(); });

        wo.Play();

        ewh.WaitOne();

     }, tune);

Это, создавая лучший звук и избавляясь от небольшой задержки между нотами консоли, по-прежнему имело ту же проблему с треском / треском между каждым сэмплом в CSP.
Я ничего не нашел в сети похожие проблемы, и безрезультатно изучил некоторые общие c «исправить треск Windows 10».

При моих текущих настройках некоторые звуки будут вызывать небольшое потрескивание, но это очень редко и в сложных случаях, например, в определенной игре. Обычно проблем нет. Использование Windows 10 Home, без выделенной звуковой карты (независимо от того, что встроено в Gigabyte Aourus Elite AM4 mobo), Realtek Audio, наушников.

Как исправить / удалить выскакивание?

ОБНОВЛЕНИЕ:
Как было рекомендовано ниже, я добавил к семплам эффекты постепенного появления / исчезновения, чтобы попытаться смягчить проблему с «нечистыми семплами». Вот текущий код:

 public static async Task PlayTune(string tune) =>
     await Task.Factory.StartNew((tune) =>
     {
        var t = (string)tune;
        var sampleProviders = new List<DelayFadeOutSampleProvider>();
        var durations = new List<double>();

        for (int i = 0; i < t.Length; i += 4)
        {
           int.TryParse(t[i].ToString(), out int d);
           var note = t[i + 1].ToString() + t[i + 2].ToString();

           if (note == "re")
           {
              var fifosp = new DelayFadeOutSampleProvider(new SignalGenerator() { Gain = 0.0 }.Take(TimeSpan.FromMilliseconds(1000.0 / 8.0 * d)), true);
              sampleProviders.Add(fifosp);
              durations.Add(1000.0 / 8.0 * d);
           }
           else
           {
              var fifosp = new DelayFadeOutSampleProvider(new SignalGenerator() { Gain = 0.2, Frequency = GetFrequency(note), Type = SignalGeneratorType.Sin, }
                 .Take(TimeSpan.FromMilliseconds(1000.0 / 8.0 * d)), true);
              fifosp.BeginFadeIn(2);
              sampleProviders.Add(fifosp);
              durations.Add(1000.0 / 8.0 * d);
           }
        }

        for (int i = 0; i < sampleProviders.Count; i++)
        {
           using var wo = new WaveOutEvent();
           var ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
           wo.PlaybackStopped += (sen, args) => ewh.Set();
           wo.Init(sampleProviders[i]);
           wo.Play();

           Thread.Sleep(10);
           sampleProviders[i].BeginFadeOut(durations[i] - 15, 1);

           ewh.WaitOne();
        }
     }, tune);

Это в конечном итоге очень помогло, в начале сэмплов было большое искажение, которое было легко устранено, но в конце есть небольшой всплеск (в зависимости от на заметке) - более громкий хлопок. Я пробовал как засыпать поток вручную, так и использовать предоставленное постепенное исчезновение, и используя собственный SampleProvider, который я нашел в другом вопросе , ни один метод не работал, независимо от того, сколько я отрезал.

Любые идеи относительно природы этого?

...