2009-08-19 13 views
5

Tengo un programa que produce señales de audio que se supone que se reproducirán simultáneamente. Para esto, reproduzco un intervalo de 100 ms de transmisión de audio en cada período de 100 ms. Pero tengo señales no deseadas al principio y al final de cada flujo de audio de 100 ms (debido a la corriente continua), de modo que el sonido de salida no es uniforme, incluso el valor de las señales es el mismo. Mi código está adjunto abajo. Por favor, ayúdame en lo que debo hacer para tener un audio correcto en tiempo real.Cómo reproducir audio de una transmisión en tiempo real

using System; 
using System.Windows.Forms; 
using Microsoft.DirectX.DirectSound; 
using System.IO; 

namespace TestSound 
{ 
    class CSound : Form 
    { 
     const int HEADER_SIZE = 44; 
     const bool FLAG_STEREO = true; 
     const short BITS_PER_SAMPLE = 16; 
     const int SAMPLE_RATE = 44100; 

     int numberOfSamples; 
     MemoryStream stream; 
     BinaryWriter writer; 
     Device ApplicationDevice = null; 
     SecondaryBuffer buffer = null; 
     BufferDescription description; 

     public CSound() 
     { 
      try 
      { 
       ApplicationDevice = new Device(); 
      } 
      catch 
      { 
       MessageBox.Show("Unable to create sound device."); 
       ApplicationDevice = null; 
       return; 
      } 
      ApplicationDevice.SetCooperativeLevel(this, CooperativeLevel.Priority); 
      description = new BufferDescription(); 
      description.ControlEffects = false; 
      stream = new MemoryStream(); 
      writer = new BinaryWriter(stream); 
     } 

     private void AddHeader() 
     { 
      stream.Position = 0; 

      writer.Write(0x46464952); // "RIFF" in ASCII 
      writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1)/8)) - 8); 
      writer.Write(0x45564157); // "WAVE" in ASCII 
      writer.Write(0x20746d66); // "fmt " in ASCII 
      writer.Write(16); 
      writer.Write((short)1); 
      writer.Write((short)(FLAG_STEREO ? 2 : 1)); 
      writer.Write(SAMPLE_RATE); 
      writer.Write(SAMPLE_RATE * (FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE/8); 
      writer.Write((short)((FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE/8)); 
      writer.Write(BITS_PER_SAMPLE); 
      writer.Write(0x61746164); // "data" in ASCII 
      writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1)/8)); 
     } 

     public void Play(short[] samples) 
     { 
      if (ApplicationDevice == null) 
       return; 

      stream.Position = HEADER_SIZE; 
      numberOfSamples = samples.Length; 
      for (int i = 0; i < numberOfSamples; i++) 
      { 
       writer.Write(samples[i]); 
       if (FLAG_STEREO) 
        writer.Write(samples[i]); 
      } 
      AddHeader(); 
      stream.Position = 0; 

      try 
      { 
       if (buffer != null) 
       { 
        buffer.Dispose(); 
        buffer = null; 
       } 
       buffer = new SecondaryBuffer(stream, description, ApplicationDevice); 
       buffer.Play(0, BufferPlayFlags.Default); 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.Message); 
      } 
     } 

     static short[] samples = new short[4410]; // 100 ms 
     static CSound sound; 

     static void Main() 
     { 
      Form form = new Form(); 
      form.Show(); 

      sound = new CSound(); 
      Random random = new Random(); 
      for (int i = 0; i < samples.Length; i++) 
       samples[i] = 1000; // constant value 

      while (true) 
      { 
       sound.Play(samples); 
       System.Threading.Thread.Sleep(100); // 100 ms 
      } 
     } 
    } 
} 

Respuesta

1

Hay un número de cosas mal con este código. Supongo que cuando ejecutas este código, estás oyendo clic o estallando sonidos cada 100 ms. Esto se debe a la llamada Thread.Sleep (100) dentro del ciclo while (true). Básicamente, su aplicación está esperando 100 ms (dar o tomar una pequeña cantidad de tiempo) y luego llamar a Play(), lo que hace un poco de procesamiento y luego pone en cola la matriz para la reproducción. Como resultado, hay un pequeño intervalo de tiempo entre la reproducción de cada matriz de 100 ms, que produce los clics.

Sin embargo, si acaba de comentar la línea Thread.Sleep (100), su aplicación entraría en un bucle infinito donde sigue haciendo cola en una matriz de 100 ms después de una matriz de 100 ms hasta que se quede sin memoria. Pero al menos la reproducción no tendría los artefactos cada 100 ms.

Si cambió la línea a Thread.Sleep (80), funcionaría un poco mejor, en el sentido de que le llevaría más tiempo quedarse sin memoria, pero esto seguiría sucediendo porque aún estaría descargando almacena en el sistema de reproducción de audio más rápido de lo que el sistema puede reproducirlos.

Además, incluso si se deshace del clic cada 100 ms, aún no oirá nada saliendo de los parlantes, porque su código establece cada valor de muestra en 1000. Solo escuchará cualquier cosa si varía los valores de muestra a lo largo del tiempo. Por cierto, la única razón por la que escuchas clics es porque este valor de muestra está establecido en 1000, y durante esos pequeños intervalos de tiempo entre fragmentos, el valor de reproducción vuelve a 0. Si estableces cada valor de muestra en 0, nunca lo harías escuchar algo en absoluto.

Podría ayudarlo con esto, pero necesitaría tener una mejor idea de lo que está tratando de hacer, exactamente. ¿Estás tratando de tocar un tono continuo a cierta frecuencia?

4

Si está buscando una manera de reproducir audio a través de una secuencia definida, ¿ha considerado NAudio http://naudio.codeplex.com/?

Puede definir una transmisión, ya sea desde un archivo o desde otra ubicación (es decir, memoria) y luego completar la transmisión con los datos que desea reproducir. Siempre que pueda continuar proporcionando datos de audio a la transmisión antes de que el puntero de lectura llegue al final del búfer, no escuchará estos artefactos en el audio generado.

BTW - Supongo que sabe que las bibliotecas Managed Direct X para .Net ya no se están desarrollando y es efectivamente un callejón sin salida para este tipo de desarrollo de audio.

0

Si por "señales indeseables" quiere decir un ligero estallido en cada extremo, podría ser un problema de envolvente, que en Csound podría controlarse con el código de operación 'linen' o algo similar. La idea es que necesitas aumentar la amplitud en la parte delantera, y hacia abajo en la parte posterior ligeramente para evitar el sonido de los altavoces al cesar abruptamente su salida en la mitad de la onda, por así decirlo. Unos pocos ms deberían ser suficientes: experimente con él hasta que se deshaga del estallido sin notar la modulación de la amplitud.

vistazo aquí: http://www.csounds.com/journal/issue11/csoundEnvelopes.html

Si usted está tratando de producir una señal sin problemas mediante la articulación de una forma de onda secuencialmente idéntica a intervalos regulares, entonces siempre escuchar este sonido de explosión debido a que el fin de una forma de onda no se alinea con el comienzo de la siguiente forma de onda Es muy difícil hacer que las formas de onda se alineen con precisión, y esa no es realmente una buena estrategia. Una mejor estrategia sería usar una envolvente (como se describió anteriormente) y superponer las formas de onda (llamadas dove-tailing) para que la descomposición de la antigua articulación ocurra simultáneamente con el aumento de la nueva articulación.

Sin embargo, esta estrategia no producirá un sonido completamente puro porque la presencia de dos formas de onda idénticas que se superponen asincrónicamente se cancelarán un poco y harán que la amplitud disminuya en cada unión de las formas de onda.

Cuestiones relacionadas