我嘗試流的聲音樣本從我麥克風我揚聲器使用的DirectSound和C#。它應該類似於'聽麥克風',但後來我想用它來做其他事情。通過測試我的方法,我注意到無聲的發癢,在背景中破解噪音。我想這與寫入和播放緩衝區之間的延遲有關,它必須大於寫入區塊的延遲。如何在使用DirectSound和C#將聲音從麥克風傳輸到揚聲器時避免無聲的發癢噪音?
如果我將錄製和播放之間的延遲設置爲小於50ms。大多數情況下,它的工作,但有時我真的響亮的開裂噪音。所以我決定延遲至少50ms。這對我來說可行,但系統「聽設備」的延遲似乎要短得多。我猜測它大約是15-30ms,幾乎不明顯。對於50ms,我至少會得到一點混響效果。
下面我會告訴你我的麥克風碼(部分): 初始化像這樣做:
capture = new Capture(device);
// Creating the buffer
// Determining the buffer size
bufferSize = format.AverageBytesPerSecond * bufferLength/1000;
while (bufferSize % format.BlockAlign != 0) bufferSize += 1;
chunkSize = Math.Max(bufferSize, 256);
bufferSize = chunkSize * BUFFER_CHUNKS;
this.bufferLength = chunkSize * 1000/format.AverageBytesPerSecond; // Redetermining the buffer Length that will be used.
captureBufferDescription = new CaptureBufferDescription();
captureBufferDescription.BufferBytes = bufferSize;
captureBufferDescription.Format = format;
captureBuffer = new CaptureBuffer(captureBufferDescription, capture);
// Creating Buffer control
bufferARE = new AutoResetEvent(false);
// Adding notifier to buffer.
bufferNotify = new Notify(captureBuffer);
BufferPositionNotify[] bpns = new BufferPositionNotify[BUFFER_CHUNKS];
for(int i = 0 ; i < BUFFER_CHUNKS ; i ++) bpns[i] = new BufferPositionNotify() { Offset = chunkSize * (i+1) - 1, EventNotifyHandle = bufferARE.SafeWaitHandle.DangerousGetHandle() };
bufferNotify.SetNotificationPositions(bpns);
的拍攝將在一個額外的線程中運行這樣的:
// Initializing
MemoryStream tempBuffer = new MemoryStream();
// Capturing
while (isCapturing && captureBuffer.Capturing)
{
bufferARE.WaitOne();
if (isCapturing && captureBuffer.Capturing)
{
captureBuffer.Read(currentBufferPart * chunkSize, tempBuffer, chunkSize, LockFlag.None);
ReportChunk(applyVolume(tempBuffer.GetBuffer()));
currentBufferPart = (currentBufferPart + 1) % BUFFER_CHUNKS;
tempBuffer.Dispose();
tempBuffer = new MemoryStream(); // Reset Buffer;
}
}
// Finalizing
isCapturing = false;
tempBuffer.Dispose();
captureBuffer.Stop();
if (bufferARE.WaitOne(bufferLength + 1)) currentBufferPart = (currentBufferPart + 1) % BUFFER_CHUNKS; // That on next start the correct bufferpart will be read.
stateControlARE.Set();
捕獲時ReportChunk
將數據作爲可以訂閱的事件發送給發言者。所述揚聲器部分被初始化這樣的:
// Creating the dxdevice.
dxdevice = new Device(device);
dxdevice.SetCooperativeLevel(hWnd, CooperativeLevel.Normal);
// Creating the buffer
bufferDescription = new BufferDescription();
bufferDescription.BufferBytes = bufferSize;
bufferDescription.Format = input.Format;
bufferDescription.ControlVolume = true;
bufferDescription.GlobalFocus = true; // That sound doesn't stop if the hWnd looses focus.
bufferDescription.StickyFocus = true; // - " -
buffer = new SecondaryBuffer(bufferDescription, dxdevice);
chunkQueue = new Queue<byte[]>();
// Creating buffer control
bufferARE = new AutoResetEvent(false);
// Register at input device
input.ChunkCaptured += new AInput.ReportBuffer(input_ChunkCaptured);
的數據由所述事件方法放入隊列,簡單地通過:
chunkQueue.Enqueue(buffer);
bufferARE.Set();
灌裝playbackbuffer和開始/停止播放緩衝區被另一個線程來完成:
// Initializing
int wp = 0;
bufferARE.WaitOne(); // wait for first chunk
// Playing/writing data to play buffer.
while (isPlaying)
{
Thread.Sleep(1);
bufferARE.WaitOne(BufferLength * 3); // If a chunk is played and there is no new chunk we try to continue and may stop playing, else may the buffer runs out.
// Note that this may fails if the sender was interrupted within one chunk
if (isPlaying)
{
if (chunkQueue.Count > 0)
{
while (chunkQueue.Count > 0) wp = writeToBuffer(chunkQueue.Dequeue(), wp);
if (buffer.PlayPosition > wp - chunkSize * 3/2) buffer.SetCurrentPosition(((wp - chunkSize * 2 + bufferSize) % bufferSize));
if (!buffer.Status.Playing)
{
buffer.SetCurrentPosition(((wp - chunkSize * 2 + bufferSize) % bufferSize)); // We have 2 chunks buffered so we step back 2 chunks and play them while getting new chunks.
buffer.Play(0, BufferPlayFlags.Looping);
}
}
else
{
buffer.Stop();
bufferARE.WaitOne(); // wait for a filling chunk
}
}
}
// Finalizing
isPlaying = false;
buffer.Stop();
stateControlARE.Set();
writeToBuffer
簡單令狀通過this.buffer.Write(wp, data, LockFlag.None);
並且關注大約bufferSize
和chunkSize
和wp
,其代表最後的寫作位置。我認爲這是對我的代碼很重要的一切。也許定義缺失,至少有另一種方法開始/停止=控制線程。
我已經發布了這段代碼,以防我在填充緩衝區時發生錯誤或者我的初始化錯誤。但是我猜測會出現這個問題,因爲C#字節碼的執行速度太慢或者類似的問題。但最終我的問題仍然是開放的:我的問題是如何減少延遲以及如何避免不應該出現的噪音?
PC輸入往往很嘈雜,尤其是對於板載音頻硬件。音頻芯片通常與實際插孔相距一定距離,主板上的走線可以拾取各種噪音。這種噪音是不可避免的,因爲它是一個物理問題,而不是由軟件引起的。 –
你所說的簡單白化不是我的問題。我的問題是有時會發生無聲的破解。當我在我的系統設置中使用「收聽設備」時,不會發生這種情況。 –
你是怎麼定義「沉默」的? – sq33G