Контекст:
Простое. 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, который я нашел в другом вопросе , ни один метод не работал, независимо от того, сколько я отрезал.
Любые идеи относительно природы этого?