Pergunta

Como faço para gerar um seno ou onda quadrada de áudio de uma determinada frequência?

Espero fazer isso para calibrar o equipamento, então quão precisos essas ondas seriam?

Foi útil?

Solução

Você pode usar Naudio e crie uma transmissão de onda derivada que produz ondas senoida WAV Arquivo. Se você usou amostras de ponto flutuante de 32 bits, poderá escrever os valores diretamente da função SIN sem precisar escalar, pois ele já passa entre -1 e 1.

Quanto à precisão, você quer dizer exatamente a frequência certa ou exatamente a forma de onda certa? Não existe uma onda quadrada verdadeira, e mesmo a onda senoidal provavelmente terá alguns artefatos muito silenciosos em outras frequências. Se for a precisão da frequência que importa, você depende da estabilidade e da precisão do relógio na sua placa de som. Dito isto, imagino que a precisão seria boa o suficiente para a maioria dos usos.

Aqui está algum código de exemplo que faz uma amostra de 1 kHz a uma taxa de amostragem de 8 kHz e com amostras de 16 bits (ou seja, não ponto flutuante):

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));
}

Outras dicas

Isso permite que você forneça frequência, duração e amplitude, e é 100% .NET CLR Código. Sem DLLs externos. Funciona criando um WAV formatado MemoryStream O que é como criar um arquivo apenas na memória, sem armazená -lo no disco. Então toca isso MemoryStream com 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)

Tente de Criando seno e salve para o arquivo de onda em 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);
}

(para qualquer outra pessoa) usando Mathnet

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

Sinusoidal

Gera uma matriz de ondas senoidais do comprimento dado. Isso é equivalente a aplicar uma função senogométrica em escala a um dente de serra periódico da amplitude 2π.

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

Generate.sinusOidal (comprimento, amostragem, frequência, amplitude, média, fase, atraso)

por exemplo

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

Retorna a matriz {0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ...}

E também há

Generate.Square(...

o que vai

Crie uma onda quadrada periódica ...

Não posso falar sobre precisão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top