Создание синусоидальной или прямоугольной волны в C#

Как мне сгенерировать звуковой синусоидальный или прямоугольный сигнал заданной частоты?

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

Лучше использовать настоящий генератор сигналов (с известной калибровкой)

Mitch Wheat 15.10.2008 10:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
30
1
66 372
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете использовать NAudio и создать производный WaveStream, который выводит синусоидальные или прямоугольные волны, которые вы можете выводить на звуковую карту или записывать в файл WAV. Если вы использовали 32-битные образцы с плавающей запятой, вы могли бы записать значения непосредственно из функции sin без необходимости масштабирования, поскольку она уже находится между -1 и 1.

Что касается точности, вы имеете в виду именно правильную частоту или именно правильную форму волны? Нет такой вещи, как настоящая прямоугольная волна, и даже синусоида, вероятно, будет иметь несколько очень тихих артефактов на других частотах. Если важна точность частоты, вы полагаетесь на стабильность и точность часов на вашей звуковой карте. Сказав это, я мог бы предположить, что точность будет достаточно хорошей для большинства применений.

Вот пример кода, который делает выборку 1 kHz с частотой дискретизации 8 kHz и с 16-битными выборками (то есть не с плавающей запятой):

int sampleRate = 8000;
short[] buffer = new short[8000];
double amplitude = 0.25 * short.MaxValue;
double frequency = 1000;
for (int n = 0; n < buffer.Length; n++)
{
    buffer[n] = (short)(amplitude * Math.Sin((2 * Math.PI * n * frequency) / sampleRate));
}

здесь нет такой вещи, как настоящая прямоугольная волна, и даже волна греха: Очень правильно, я действительно имел в виду частоту, спасибо

johnc 16.10.2008 09:27

Это позволяет указать частоту, длительность и амплитуду, и это 100% код .NET CLR. Никаких внешних DLL. Он работает, создавая MemoryStream в формате WAV, что похоже на создание файла только в памяти, без сохранения его на диск. Затем он воспроизводит MemoryStream с System.Media.SoundPlayer.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;

public static void PlayBeep(UInt16 frequency, int msDuration, UInt16 volume = 16383)
{
    var mStrm = new MemoryStream();
    BinaryWriter writer = new BinaryWriter(mStrm);

    const double TAU = 2 * Math.PI;
    int formatChunkSize = 16;
    int headerSize = 8;
    short formatType = 1;
    short tracks = 1;
    int samplesPerSecond = 44100;
    short bitsPerSample = 16;
    short frameSize = (short)(tracks * ((bitsPerSample + 7) / 8));
    int bytesPerSecond = samplesPerSecond * frameSize;
    int waveSize = 4;
    int samples = (int)((decimal)samplesPerSecond * msDuration / 1000);
    int dataChunkSize = samples * frameSize;
    int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;
    // var encoding = new System.Text.UTF8Encoding();
    writer.Write(0x46464952); // = encoding.GetBytes("RIFF")
    writer.Write(fileSize);
    writer.Write(0x45564157); // = encoding.GetBytes("WAVE")
    writer.Write(0x20746D66); // = encoding.GetBytes("fmt ")
    writer.Write(formatChunkSize);
    writer.Write(formatType);
    writer.Write(tracks);
    writer.Write(samplesPerSecond);
    writer.Write(bytesPerSecond);
    writer.Write(frameSize);
    writer.Write(bitsPerSample);
    writer.Write(0x61746164); // = encoding.GetBytes("data")
    writer.Write(dataChunkSize);
    {
        double theta = frequency * TAU / (double)samplesPerSecond;
        // 'volume' is UInt16 with range 0 thru Uint16.MaxValue ( = 65 535)
        // we need 'amp' to have the range of 0 thru Int16.MaxValue ( = 32 767)
        double amp = volume >> 2; // so we simply set amp = volume / 2
        for (int step = 0; step < samples; step++)
        {
            short s = (short)(amp * Math.Sin(theta * (double)step));
            writer.Write(s);
        }
    }

    mStrm.Seek(0, SeekOrigin.Begin);
    new System.Media.SoundPlayer(mStrm).Play();
    writer.Close();
    mStrm.Close();
} // public static void PlayBeep(UInt16 frequency, int msDuration, UInt16 volume = 16383)

Попробуйте от Создание синуса и сохранение в файл wav на C#

private void TestSine()
{
    IntPtr format;
    byte[] data;
    GetSineWave(1000, 100, 44100, -1, out format, out data);
    WaveWriter ww = new WaveWriter(File.Create(@"d:\work\sine.wav"),
        AudioCompressionManager.FormatBytes(format));
    ww.WriteData(data);
    ww.Close();
}

private void GetSineWave(double freq, int durationMs, int sampleRate, short decibel, out IntPtr format, out byte[] data)
{
    short max = dB2Short(decibel);//short.MaxValue
    double fs = sampleRate; // sample freq
    int len = sampleRate * durationMs / 1000;
    short[] data16Bit = new short[len];
    for (int i = 0; i < len; i++)
    {
        double t = (double)i / fs; // current time
        data16Bit[i] = (short)(Math.Sin(2 * Math.PI * t * freq) * max);
    }
    IntPtr format1 = AudioCompressionManager.GetPcmFormat(1, 16, (int)fs);
    byte[] data1 = new byte[data16Bit.Length * 2];
    Buffer.BlockCopy(data16Bit, 0, data1, 0, data1.Length);
    format = format1;
    data = data1;
}

private static short dB2Short(double dB)
{
    double times = Math.Pow(10, dB / 10);
    return (short)(short.MaxValue * times);
}

Использование Math.NET Числа

https://numerics.mathdotnet.com/Generate.html

Sinusoidal

Generates a Sine wave array of the given length. This is equivalent to applying a scaled trigonometric Sine function to a periodic sawtooth of amplitude 2π.

s(x)=A⋅sin(2πνx+θ)

Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)

например

 Generate.Sinusoidal(15, 1000.0, 100.0, 10.0);

возвращает массив {0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ...}

и есть также

Generate.Square(...

который будет

create a periodic square wave...

не могу говорить о точности.

Другие вопросы по теме