Domanda

Come posso generare un seno audio o un'onda quadra di una data frequenza?

Spero di farlo per calibrare l'apparecchiatura, quindi quanto precise sarebbero queste onde?

È stato utile?

Soluzione

Puoi usare NAudio e creare un WaveStream derivato che emette onde sinusoidali o quadrate che potresti emettere sulla scheda audio oppure scrivi in ??un WAV . Se hai usato campioni a virgola mobile a 32 bit, potresti scrivere i valori direttamente dalla funzione sin senza ridimensionare poiché va già tra -1 e 1.

Per precisione, intendi esattamente la frequenza giusta o esattamente la forma d'onda giusta? Non esiste una vera onda quadra e anche l'onda sinusoidale avrà probabilmente alcuni artefatti molto silenziosi ad altre frequenze. Se è la precisione della frequenza che conta, ti affidi alla stabilità e alla precisione dell'orologio nella tua scheda audio. Detto questo, immaginerei che la precisione sarebbe abbastanza buona per la maggior parte degli usi.

Ecco un esempio di codice che crea un campione di 1 & nbsp; kHz con una frequenza di campionamento di 8 & nbsp; kHz e con campioni di 16 bit (ovvero, non in virgola mobile):

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

Altri suggerimenti

Ciò ti consente di fornire frequenza, durata e ampiezza, ed è un codice CLR .NET al 100%. Nessuna DLL esterna. Funziona creando un MemoryStream formattato WAV che è come creare un file solo in memoria, senza memorizzarlo su disco. Quindi riproduce quel MemoryStream con 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)

Prova da Creazione di seno e salvataggio nel file wave in 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);
}

(per chiunque altro) usando Mathnet

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

  

sinusoidale

     

Genera un array di onde sinusoidali della lunghezza specificata. Questo equivale a   applicare una funzione seno trigonometrica ridimensionata a un dente di sega periodico   di ampiezza 2p.

     

s (x) = A·sin (2p?x + ?)

     

Generate.Sinusoidal (lunghezza, samplingRate, frequenza, ampiezza, medio, fase, ritardo)

es

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

restituisce l'array {0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ...}

e c'è anche

Generate.Square(...

che sarà

  

crea un'onda quadra periodica ...

non posso parlare di precisione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top