2009-08-19 2 views
5

У меня есть программа, которая воспроизводит звуковые сигналы, которые должны воспроизводиться одновременно. Для этого я воспроизвожу интервал в 100 мс аудиопотока за каждые 100 мс. Но у меня есть нежелательные сигналы в начале и конце каждого 100-миллисекундного аудиопотока (из-за постоянного тока), так что выходной звук не является гладким, даже значение сигналов одинаково. Мой код приведен ниже. Пожалуйста, помогите мне, что я должен сделать, чтобы иметь правильный звук в реальном времени.Как воспроизводить аудио из потока в реальном времени

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

ответ

1

С этим кодом существует ряд недостатков. Я предполагаю, что когда вы запускаете этот код, вы слышите щелчок или выскакивание звуков каждые 100 мс. Это происходит из-за вызова Thread.Sleep (100) внутри цикла while (true). В основном, ваше приложение ждет 100 мс (дайте или возьмите небольшое количество времени), а затем вызовите Play(), который выполняет небольшую обработку и затем ставит в очередь массив для воспроизведения. В результате существует небольшой промежуток времени между воспроизведением каждого массива 100 мс, который производит клики.

Однако, если вы просто прокомментировали строку Thread.Sleep (100), ваше приложение перейдет в бесконечный цикл, где он будет поддерживать очередность в 100 мс массиве после 100 мс массива, пока не закончится память. Но, по крайней мере, воспроизведение не будет иметь артефактов каждые 100 мс.

Если вы изменили линию на Thread.Sleep (80), она будет работать немного лучше, в том смысле, что вам потребуется больше времени для исчерпания памяти, но это все равно произойдет, потому что вы все равно будете демпинговать буферы в систему воспроизведения звука быстрее, чем система может их воспроизводить.

Кроме того, даже если вы избавитесь от щелчка каждые 100 мс, вы все равно не услышите ничего, что выйдет из ваших колонок, потому что ваш код устанавливает каждое значение выборки до 1000. Вы будете слышать только что-нибудь если вы меняете значения выборки с течением времени. Кстати, единственная причина, по которой вы слышите щелчки, заключается в том, что для этого значения выборки установлено значение 1000, и в течение этих небольших временных интервалов между кусками значение воспроизведения возвращается к 0. Если вы установите для каждого значения выборки значение 0, вы никогда не сможете услышать что-нибудь вообще.

Я мог бы помочь вам в дальнейшем, но мне нужно было бы лучше понять, что вы пытаетесь сделать, точно. Вы пытаетесь играть непрерывный тон с определенной частотой?

4

Если вы ищете способ воспроизвести аудио через определенный поток, рассмотрели ли вы NAudio http://naudio.codeplex.com/?

Вы можете определить поток, как из файла, так и из другого местоположения (т. Е. Памяти), а затем заполнить поток данными, которые вы хотите воспроизвести. Пока вы можете продолжать предоставлять аудиоданные в поток до того, как указатель чтения появится в конце буфера, вы не услышите эти артефакты в сгенерированном звуке.

BTW - Я полагаю, вы знаете, что библиотеки управляемого Direct X для .Net больше не разрабатываются и фактически являются тупиком для такого рода разработки аудио?

0

Если «нежелательные сигналы» означают легкий звук с обоих концов, это может быть проблема с конвертом, которую в Csound можно контролировать с помощью кода операции «linen» или чего-то подобного. Идея состоит в том, что вам нужно увеличить амплитуду на переднем конце и немного вниз на заднем конце, чтобы избежать щелкающего звука громкоговорителей, резко прекративших выход в средней волне, так сказать. Достаточно нескольких мс - экспериментируйте с ним, пока вы не избавитесь от всплытия, не заметив амплитудную модуляцию.

Посмотрите здесь: http://www.csounds.com/journal/issue11/csoundEnvelopes.html

Если вы пытаетесь произвести плавный сигнал, формулируя идентичный сигнал последовательно через равные промежутки время, то вы всегда будете слышать этот хлопающий звук, потому что конец одного сигнала не совпадает с началом следующего сигнала. Очень сложно получить формы сигналов точно, и это не очень хорошая стратегия. Лучшей стратегией было бы использовать огибающую (как описано выше) и перекрывать формы волны (называемые голубей-хвост), так что распад старой артикуляции происходит одновременно с возникновением новой артикуляции.

Однако эта стратегия не даст совершенно чистого звука, потому что наличие двух одинаковых осциллограмм, перекрывающихся асинхронно, будет немного сокращать друг друга и вызывать уменьшение амплитуды на каждом этапе осциллограмм.

Смежные вопросы