2008-10-15 154 views
20

¿Cómo puedo generar una onda sinusoidal o cuadrada de audio de una frecuencia determinada?Crear onda sinusoidal o cuadrada en C#

Tengo la esperanza de hacer esto para calibrar el equipo, entonces, ¿qué tan precisas serían estas ondas?

+2

Usted sería mejor usar un generador de señal real (con la calibración conocida) –

Respuesta

29

Puede usar NAudio y crear un WaveStream derivado que genera ondas sinusoidales o cuadradas que puede enviar a la tarjeta de sonido o escribir en un archivo WAV. Si utilizó muestras de coma flotante de 32 bits, puede escribir los valores directamente de la función sin sin tener que escalar, ya que va entre -1 y 1.

En cuanto a precisión, ¿se refiere exactamente a la frecuencia correcta, o exactamente la forma de onda correcta? No existe una onda cuadrada verdadera, e incluso la onda sinusoidal probablemente tendrá algunos artefactos muy silenciosos en otras frecuencias. Si lo que importa es la precisión de la frecuencia, depende de la estabilidad y la precisión del reloj en su tarjeta de sonido. Habiendo dicho eso, me imagino que la precisión sería lo suficientemente buena para la mayoría de los usos.

Aquí hay un código de ejemplo que hace una muestra de 1   kHz con una frecuencia de muestreo de 8   kHz y con muestras de 16 bits (es decir, no coma flotante):

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

aquí hay tal cosa como una verdadera onda cuadrada, e incluso la ola pecado: Muy correcto, en realidad quería decir frecuencia, gracias – johnc

19

Esto le permite dar la frecuencia, duración y amplitud, y es 100% .NET código CLR. Sin DLL externos. Funciona al crear un formato WAV-MemoryStream que es como crear un archivo en memoria solamente, sin almacenarlo en el disco. Entonces juega ese 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) 
4

Trate 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); 
} 
Cuestiones relacionadas