Воспроизведение звука в .NET с использованием сгенерированных данных формы сигнала
Вопрос
Как я могу воспроизвести звук на основе данных формы волны, которые моя .NET-программа генерирует на основе пользовательского ввода и математических функций?
Под "данными о форме волны" я подразумеваю значения SPL (уровня звукового давления) во временном ряду с фиксированным интервалом (вероятно, 44,1 кГц).Я предполагаю, что для этого требуется какое-то устройство потокового буфера.
Обратите внимание, что это должно происходить в режиме реального времени, поэтому простого создания файла .wav и последующего воспроизведения этого будет недостаточно.VB.NET предпочтителен, но C # также приемлем.
Просто чтобы прояснить:То, что я ищу, - это простой пример рабочего кода.
Решение
Вы можете сделать это с помощью НАудио.Вы создаете поток, производный от WaveStream, и в его переопределенном методе чтения возвращаете свои выборки, которые вы можете сгенерировать на лету.У вас есть контроль над размером буферов, используемых звуковой картой, что дает вам контроль над задержкой.
Другие советы
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();
}
Проверьте этот поток при загрузке Направленный звук буфер с произвольными данными и их воспроизведение.
За комментарий:Да, я знаю.Вам нужно будет перевести C ++ на C # или VB.NET .Но концепция - это то, что важно.Вы создаете вторичный буфер DirectSound, а затем используете его для потоковой передачи в ваш основной буфер и воспроизведения.
Я думаю, вам нужно будет использовать Направленный звук (DirectX API) для этого.Он обрабатывает буферы, которые вы могли бы заполнить своими сгенерированными данными.
Может быть, что-то вроде это (здесь в обратном пути машина) поможет
У меня есть этот код, но у вас должен быть код для генерации вашего wav-файла в памяти.
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