2009-08-19 20 views
5

Ho un programma che produce segnali audio che dovrebbero essere riprodotti simultaneamente. Per questo, suono un intervallo di 100 ms di flusso audio in ogni periodo di 100 ms. Ma ho segnali indesiderati all'inizio e alla fine di ogni flusso audio da 100 ms (a causa della DC) in modo che il suono in uscita non sia uniforme anche se il valore dei segnali è lo stesso. Il mio codice è allegato sotto. Per favore aiutami cosa dovrei fare per avere un audio corretto in tempo reale.Come riprodurre l'audio da un flusso in tempo reale

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

risposta

1

C'è un numero di cose che non vanno con questo codice. Immagino che quando si esegue questo codice, si sentono clic o scoppiettano suoni ogni 100 ms. Questo a causa della chiamata Thread.Sleep (100) all'interno del ciclo while (true). Fondamentalmente, la tua app è in attesa di 100 ms (dà o prende una piccola quantità di tempo), quindi chiama Play(), che esegue un po 'di elaborazione e quindi accoda l'array per la riproduzione. Di conseguenza, c'è un piccolo intervallo di tempo tra la riproduzione di ciascun array da 100 ms, che sta producendo i clic.

Tuttavia, se hai appena commentato la riga Thread.Sleep (100), la tua app entrerebbe in un ciclo infinito dove continua ad accodarsi fino a 100 ms di array dopo un array di 100 ms finché non hai esaurito la memoria. Ma almeno la riproduzione non avrebbe gli artefatti ogni 100 ms.

Se la riga è stata modificata in Thread.Sleep (80), funzionerebbe un po 'meglio, nel senso che richiederebbe più tempo per esaurire la memoria, ma ciò si verificherebbe ancora perché si effettuerebbe ancora il dumping buffer nel sistema di riproduzione audio più veloce di quanto il sistema possa riprodurli.

Inoltre, anche se si elimina il clic ogni 100 ms, non si sentirà ancora alcun suono proveniente dai diffusori, poiché il codice imposta ogni valore di campionamento su 1000. Si sentirà solo qualcosa se si variano i valori del campione nel tempo. Per inciso, l'unica ragione per cui si sentono i clic è perché questo valore di esempio è impostato su 1000, e durante quei pochi intervalli di tempo tra i blocchi il valore di riproduzione torna a 0. Se si imposta ciascun valore di esempio su 0, non si sentire qualcosa.

Potrei aiutarti ulteriormente, ma avrei bisogno di avere un'idea migliore di quello che stai cercando di fare, esattamente. Stai cercando di suonare un tono continuo ad una certa frequenza?

4

Se stai cercando un modo per riprodurre l'audio attraverso uno stream definito, hai considerato NAudio http://naudio.codeplex.com/?

è possibile definire un flusso, sia da un file o qualche altra posizione (vale a dire di memoria) e quindi popolare il flusso con i dati che si desidera riprodurre. Finché si è in grado di continuare a fornire i dati audio al flusso prima che il puntatore di lettura arriva alla fine del buffer, si sente solito questi manufatti nel audio generato.

BTW - Presumo che tu sappia che le librerie Managed Direct X per .Net non sono più in fase di sviluppo ed è effettivamente un punto morto per questo tipo di sviluppo Audio?

0

Se per "segnali indesiderati" si intende un leggero suono scoppiettante alle due estremità, potrebbe trattarsi di un problema di inviluppo, che in Csound potrebbe essere controllato dal codice operativo "biancheria" o qualcosa di simile. L'essere idea che è necessario rampa l'ampiezza sull'estremità anteriore, e giù sul back-end, per evitare la ticchettio degli altoparlanti bruscamente cessando la loro produzione in onda metà, per così dire. Qualche ms dovrebbe essere sufficiente - esperimento con essa fino a sbarazzarsi del popping senza notare la modulazione di ampiezza.

Guardate qui: http://www.csounds.com/journal/issue11/csoundEnvelopes.html

Se si sta cercando di produrre un segnale senza soluzione di continuità articolando un identico forma d'onda in sequenza a intervalli regolari, allora si avrà sempre sentire questo rumore di scoppio perché la fine di una forma d'onda non è allineata con l'inizio della prossima forma d'onda. È molto difficile allineare esattamente le forme d'onda, e questa non è davvero una buona strategia. Una strategia migliore sarebbe quella di utilizzare un inviluppo (come descritto sopra) e sovrapporre le forme d'onda (chiamate tortora-coda) in modo che il decadimento della vecchia articolazione avvenga simultaneamente all'aumento della nuova articolazione.

Tuttavia, questa strategia non produrrà un suono completamente puro poiché la presenza di due forme d'onda un po 'identiche che si sovrappongono in modo asincrono si annulleranno a vicenda e causeranno una diminuzione dell'ampiezza ad ogni giuntura delle forme d'onda.

Problemi correlati