2008-10-15 5 views
20

Comment générer un signal audio sinusoïdal ou carré d'une fréquence donnée?Création d'une onde sinusoïdale ou carrée en C#

J'espère pouvoir faire cela pour calibrer l'équipement, alors à quel point ces ondes seraient-elles précises?

+2

Vous seriez mieux d'utiliser un vrai générateur de signaux (avec étalonnage connu) –

Répondre

29

Vous pouvez utiliser NAudio et créer un WaveStream dérivé qui produit des ondes sinusoïdales ou carrées que vous pouvez émettre sur la carte son ou écrire dans un fichier WAV. Si vous avez utilisé des échantillons à virgule flottante de 32 bits, vous pouvez écrire les valeurs directement hors de la fonction sin sans avoir à redimensionner car elle est déjà comprise entre -1 et 1.

Pour la précision, voulez-vous dire exactement la bonne fréquence, ou exactement la bonne forme d'onde? Il n'y a pas de véritable onde carrée, et même l'onde sinusoïdale aura probablement quelques artefacts très silencieux à d'autres fréquences. Si c'est l'exactitude de la fréquence qui 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 quelques exemples de code qui fait un 1 échantillon   kHz à 8 fréquence d'échantillonnage   kHz et avec 16 échantillons de bits (c'est pas à 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)); 
} 
+0

ici est pas une telle chose comme une véritable onde carrée, et même la vague du péché: Très correct, je voulais dire la fréquence, merci – johnc

19

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

Essayez de Creating sine and save to wave file 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); 
} 
Questions connexes