web-dev-qa-db-fra.com

Créer une onde sinusoïdale ou carrée en C #

Comment générer une onde sinusoïdale ou carrée audio à une fréquence donnée?

J'espère pouvoir le faire pour calibrer du matériel. Quelle est donc la précision de ces vagues?

20
johnc

Vous pouvez utiliser NAudio et créer un WaveStream dérivé qui génère des ondes sinusoïdales ou carrées que vous pouvez exporter vers la carte son ou écrire dans un fichier WAV . Si vous utilisez des échantillons à virgule flottante 32 bits, vous pouvez écrire les valeurs directement à partir de la fonction sin sans avoir à mettre à l'échelle car elle se situe déjà entre -1 et 1.

En ce qui concerne la précision, voulez-vous dire exactement la bonne fréquence, ou exactement la bonne forme d'onde? Il n’existe pas de véritable onde carrée, et même l’onde sinusoïdale aura probablement quelques artefacts très calmes à d’autres fréquences. Si la précision de la fréquence compte, vous dépendez de la stabilité et de la précision de l'horloge de votre carte son. Cela dit, j'imagine que la précision serait suffisante pour la plupart des utilisations. 

Voici un exemple de code permettant de créer un échantillon de 1 kHz à une fréquence d'échantillonnage de 8 kHz et avec des échantillons de 16 bits (c'est-à-dire sans virgule flottante):

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));
}
30
Mark Heath

Cela vous permet d'indiquer la fréquence, la durée et l'amplitude. Il s'agit d'un code .NET CLR à 100%. Pas de DLL externe. Cela fonctionne en créant une MemoryStream au format WAV, ce qui revient à créer un fichier en mémoire uniquement, sans le stocker sur le disque. Ensuite, il joue cette MemoryStream avec 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)
23
Edward

Essayez de Création de sinus et sauvegarde dans un fichier wav en 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);
}
5
Aleks

(pour quiconque) utilisant Mathnet 

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

sinusoïdal

Génère un tableau d'onde sinusoïdale de la longueur donnée. Ceci équivaut à Appliquer une fonction sinonométrique trigonométrique mise à l'échelle à une dent de scie périodique D'amplitude 2π.

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

Generate.Sinusoidal (longueur, fréquence d'échantillonnage, fréquence, amplitude, moyenne, phase, retard)

par exemple

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

retourne le tableau {0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ...}

et il y a aussi 

Generate.Square(...

qui va 

créer une onde carrée périodique ...

ne peut pas parler de précision.

0
Declan Taylor