Как я могу синтезировать и выводить простые звуковые волны в C #? - PullRequest
4 голосов
/ 01 июня 2009

Если у вас есть шутка, не пытайтесь назвать мой заголовок.

Но да, какой самый простой способ создать простой или бонус для более сложных пилообразных и других волн.

Ответы [ 4 ]

3 голосов
/ 01 июня 2009

По моему опыту, .wav формат файла (запись Википедии содержит список других документов, в которых указан формат файла; используйте тот, который вам больше нравится) - самый простой и широко используемый. Довольно легко написать несжатый PCM.

Для таких вещей, как синусоиды и пилообразные волны, я бы разделил задачу на выборку и создание файла. Таким образом, у вас может быть такой интерфейс, как:

public interface IWave
{       
    double Sample(double time);
}

где Sample будет задано время больше 0 (но, возможно, больше 1) и должно возвращать значение в диапазоне от -1 до 1. (Вместо этого вы можете использовать делегат.) Затем напишите генератор файлов в создайте файл wav на основе длительности выборки (например, «100000 волн») и частоты дискретизации (например, 50000 Гц).

Тогда это просто случай правильной реализации IWave - например, версия, которая возвращает sin(time / (2 * pi)) для простой синусоиды или (time % 1.0) * 2 - 1 для пилообразной волны. Для развлечения бонусов вы можете написать композиционные функции, чтобы ускорить или замедлить волну, усилить ее, объединить другие волны и т. Д. Генератору файлов, конечно, не нужно знать любой этого. Нужно просто взять одиночный IWave и сэмплировать его соответствующее количество раз, соответственно масштабируя диапазон [-1, 1] до [0, 255].

1 голос
/ 22 ноября 2010

Посмотрите на этот вопрос для примера кода о том, как генерировать синусоидальную волну в C #. Распространение этого на квадратные или пилообразные волны было бы довольно легко. Вы можете генерировать более сложные сигналы, смешивая простые.

Вы также можете использовать класс NAudio WaveFileWriter для записи сгенерированных данных в файл WAV, если вам требуется.

1 голос
/ 01 июня 2009

Просто чтобы прояснить то, что Джон уже сказал - все, что вы делаете, это создаете 8-битный (т.е. байт [1024]) или 16-битный буфер и заполняете его (т.е. для прямоугольной волны это [255 255 255 255 0] 0 0 0 255 255 255 255 0 0 0 0]).

0 голосов
/ 03 января 2013

Есть статья Чарльза Петцольда Простой электронный музыкальный секвенсор для Silverlight на основе записи в блоге Жиля Хузама Воспроизведение файлов Wave в Silverlight и Пита Брауна Создание звука с использованием MediaStreamSource в Silverlight 3 Beta . У Майка Ходника есть полезное сообщение в блоге с примером кода, основанным на статье Petzold под названием Синтез цифрового звука на Windows Phone 7 .

В XAML главного окна Майк вводит медиа-элемент

<MediaElement x:Name="media"/>

, а затем использует метод SetSource, чтобы установить источник медиаэлементов для волны, которую он создает

this.media.SetSource(new TonesSource());
this.media.Play();

Майка ToneSource подклассов его BaseSource, который, в свою очередь, подклассов MediaStreamSource и переопределяет некоторые из его методов: OpenMediaAsync, GetSampleAsync, SeekAsync, CloseMedia, GetDiagnosticAsync и SwitchMediaStreamAsync , Больше о них есть в документации MSDN ; Сам код Майка не длинный, но включает в себя сдвиг битов и запись в потоки памяти, и его стоит посмотреть в источнике, представленном в блоге Майка .

Класс Майка ToneSource затем предоставляет стерео сэмплы

protected override StereoSample GetSample()
{
    short left = 0;
    short right = 0;

    foreach (var oscillator in this.leftOscillators)
        left += oscillator.GetNextSample();

    foreach (var oscillator in this.rightOscillators)
        right += oscillator.GetNextSample();

    return new StereoSample() { Left = left, Right = right };
}

используя свой Oscillator класс

public short GetNextSample()
{
    ushort wholePhaseAngle = (ushort)(phaseAngle >> 16);
    short amplitude = 0;
    amplitude = (short)(short.MaxValue * Math.Sin(2 * Math.PI * wholePhaseAngle / ushort.MaxValue));
    amplitude = (short)((amplitude * multiplier) >> 16);
    phaseAngle += phaseAngleIncrement;

    return amplitude;
}

NoiseSource Майк также обеспечивает даже проще, чем его ToneSource

protected override StereoSample GetSample()
{
    return new StereoSample()
    {
        Left = (short)random.Next(short.MinValue, short.MaxValue),
        Right = (short)random.Next(short.MinValue, short.MaxValue)
    };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...