Reproduzir som no .NET usando dados de forma de onda geradas
Pergunta
Como posso reproduzir um som com base em dados de forma de onda que o meu programa .NET está gerando a partir de funções de entrada do usuário e matemáticos?
Por "dados de forma de onda" Quero dizer SPL (nível de pressão sonora) valores em um intervalo de tempo-série fixa (provavelmente 44,1 kHz). Eu presumo que isso requer algum tipo de acordo tampão de streaming.
Note, que este tem que ser ao vivo / em tempo real, de modo que apenas a criação de um arquivo .wav e, em seguida, jogar que não vai ser suficiente. VB.NET é preferida, mas é aceitável C # também.
Só para esclarecer:. O que eu estou procurando é um exemplo de código de trabalho simples
Solução
Você pode fazer isso usando NAudio . Você cria um fluxo que deriva de WaveStream e em seu método de leitura anulado, você retornar suas amostras que você pode gerar em tempo real. Você tem controle sobre o tamanho dos buffers usados ??pelo placa de som que lhe dá o controle sobre a latência.
Outras dicas
Como jogar a partir de uma matriz de duplas
PlayerEx pl = new PlayerEx();
private static void PlayArray(PlayerEx pl)
{
double fs = 8000; // sample freq
double freq = 1000; // desired tone
short[] mySound = new short[4000];
for (int i = 0; i < 4000; i++)
{
double t = (double)i / fs; // current time
mySound[i] = (short)(Math.Cos(t * freq) * (short.MaxValue));
}
IntPtr format = AudioCompressionManager.GetPcmFormat(1, 16, (int)fs);
pl.OpenPlayer(format);
byte[] mySoundByte = new byte[mySound.Length * 2];
Buffer.BlockCopy(mySound, 0, mySoundByte, 0, mySoundByte.Length);
pl.AddData(mySoundByte);
pl.StartPlay();
}
Confira este segmento em carregar-se um DirectSound tampão com dados arbitrários e reproduzi-lo .
Per comentário: Sim, eu sei. Você vai precisar de traduzir o C ++ em C # ou VB.NET. Mas, o conceito é que é importante. Você cria um buffer DirectSound secundário e, em seguida, usá-lo para transmitir ao longo de seu tampão primário e jogo.
Eu acho que você vai precisar usar DirectSound ( DirectX API) para isso. Ele funciona off buffers que você pode preencher com os seus dados gerados.
Talvez algo como este ( aqui na máquina de volta way) vai ajudar
Eu tenho esse código, mas você terá que ter código para gerar o arquivo de wav na memória.
Option Strict Off
Option Explicit On
Imports Microsoft.DirectX.DirectSound
Imports Microsoft.DirectX
Imports System.Threading
Public Class Form1
Const SRATE As Integer = 44100
Const FREQ As Integer = 440
Const DUR As Integer = 1
Private dsDesc As BufferDescription
Private wvFormat As WaveFormat
Private DS As Device
Dim SecondaryBuffer As Microsoft.DirectX.DirectSound.SecondaryBuffer
Dim BufferDescription As Microsoft.DirectX.DirectSound.BufferDescription
Dim DXFormat As Microsoft.DirectX.DirectSound.WaveFormat
Dim sbuf(DUR * SRATE) As Short
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Show()
DS = New Microsoft.DirectX.DirectSound.Device
DS.SetCooperativeLevel(Me, CooperativeLevel.Normal)
wvFormat.FormatTag = WaveFormatTag.Pcm
wvFormat.Channels = 1
wvFormat.SamplesPerSecond = SRATE
wvFormat.BitsPerSample = 16
wvFormat.AverageBytesPerSecond = 2 * SRATE
wvFormat.BlockAlign = 2
dsDesc = New BufferDescription(wvFormat)
dsDesc.BufferBytes = 2 * DUR * SRATE
dsDesc.Flags = 0
Dim buff1 = PlayWave(400)
Dim buff2 = PlayWave(600)
buff1 = PlayWave(400)
buff1.Play(0, Microsoft.DirectX.DirectSound.BufferPlayFlags.Default)
Thread.Sleep(1000)
buff1 = PlayWave(600)
buff1.Play(0, Microsoft.DirectX.DirectSound.BufferPlayFlags.Default)
' End
End Sub
Function PlayWave(FREQ As Integer) As SecondaryBuffer
' create a buffer
Dim dsBuffer As SecondaryBuffer
dsBuffer = New SecondaryBuffer(dsDesc, DS)
Dim sbuf(DUR * SRATE) As Short
' create tone
For i As Integer = 0 To DUR * SRATE
sbuf(i) = CShort(10000 * Math.Sin(2 * Math.PI * FREQ * i / SRATE))
Next
' copy to buffer
dsBuffer.Write(0, sbuf, LockFlag.EntireBuffer)
Return dsBuffer
End Function