Sound latency with DirectSound

Started by
0 comments, last by Oduig 12 years, 3 months ago
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

Hi there,

[/font]

[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

I am attempting to make an application that can process sound from the Line in jack. I would like for the game to have a fast response speed, but I ran into a roadblock.

[/font]

[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

The library I use (SoundCapture from

[/font]http://www.codeproje...uitarTuner.aspx[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

) only produces a maximum of two notes a second, which is 500ms for each short[] audio sequence. I traced the delay by doing my own measurements on the code, and from what I can see the bottleneck appears to be the DirectSound.Notify object. If I understand correctly, DirectSound should set an autoresetevent when the audio buffer has a certain amount of data. The SoundCaptureBase class (see below for an exerpt) will wait for this event and process the data.

[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]


public abstract class SoundCaptureBase : IDisposable
{
const int BufferSeconds = 3;
const int NotifyPointsInSecond = 2;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

// change in next two will require also code change
const int BitsPerSample = 16;
const int ChannelCount = 1;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

int sampleRate = 44100;
bool isCapturing = false;
bool disposed = false;
Capture capture;
CaptureBuffer buffer;
Notify notify;
int bufferLength;
AutoResetEvent positionEvent;
SafeWaitHandle positionEventHandle;
ManualResetEvent terminated;
Thread thread;
SoundCaptureDevice device;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

public SoundCaptureBase(SoundCaptureDevice device)
{
this.device = device;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

positionEvent = new AutoResetEvent(false);
positionEventHandle = positionEvent.SafeWaitHandle;
terminated = new ManualResetEvent(true);
}

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

/// <summary>
/// Starts capture process.
/// </summary>
public void Start()
{
EnsureIdle();

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

isCapturing = true;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

WaveFormat format = new WaveFormat();
format.Channels = ChannelCount;
format.BitsPerSample = BitsPerSample;
format.SamplesPerSecond = SampleRate;
format.FormatTag = WaveFormatTag.Pcm;
format.BlockAlign = (short)((format.Channels * format.BitsPerSample + 7) / 8);
format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

bufferLength = format.AverageBytesPerSecond * BufferSeconds;
CaptureBufferDescription desciption = new CaptureBufferDescription();
desciption.Format = format;
desciption.BufferBytes = bufferLength;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

capture = new Capture(device.Id);
buffer = new CaptureBuffer(desciption, capture);

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

int waitHandleCount = BufferSeconds * NotifyPointsInSecond;
BufferPositionNotify[] positions = new BufferPositionNotify[waitHandleCount];
for (int i = 0; i < waitHandleCount; i++)
{
BufferPositionNotify position = new BufferPositionNotify();
position.Offset = (i + 1) * bufferLength / positions.Length - 1;
position.EventNotifyHandle = positionEventHandle.DangerousGetHandle();
positions = position;
}

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

notify = new Notify(buffer);
notify.SetNotificationPositions(positions);

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

terminated.Reset();
thread = new Thread(new ThreadStart(ThreadLoop));
thread.Name = "Sound capture1";
thread.Start();
}

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

private void ThreadLoop()
{
buffer.Start(true);
try
{
WaitHandle[] handles = new WaitHandle[] { terminated, positionEvent };
double elapsed;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

// Testing code to find the notification rate of DirectSound
DateTime dt;
int count = 0;
dt = DateTime.Now;
while (WaitHandle.WaitAny(handles) > 0) {
// This is where one would process the audio data
count++;
if (count % 10 == 0) {
elapsed = (DateTime.Now - dt).TotalMilliseconds;
// Breakpoint
elapsed = 0;
}
}
}
finally
{
buffer.Stop();
}
}
}

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

}

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

[/font]

[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

ThreadLoop simply measures the time for an incoming audio stream from DirectSound.Notify. The Start() function initializes the variables.

[/font][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

I cannot seem to find any settings that might cause this half second delay.

[/font]

[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

Thank you for any suggestions,

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

Guido

[/font]

Advertisement
I'm sorry for the double post. The forum seems very bugged at the moment, I could not get my code to display correctly and when I tried to edit it, I made a new post instead...

This topic is closed to new replies.

Advertisement