C#中使用DirectSound来获取麦克音量

bosnma 2009-03-15 06:12:41
  大家好,我最近在做一个程序需要使用DirectSound, 当用户说话时我要开始录音,当用户说完了自动停止录音,然后这样循环下去.

  现在的问题是如何知道用户是否在说话.请下看下以下代码:

        private void RecordCapturedData()
{
byte[] CaptureData = null;
int ReadPos;
int CapturePos;
int LockSize;
mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos);
LockSize = ReadPos - mNextCaptureOffset;
if (LockSize < 0)
LockSize += mBufferSize;
LockSize -= (LockSize % mNotifySize);
if (0 == LockSize)
return;
CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize);
mNextCaptureOffset += CaptureData.Length;
mNextCaptureOffset %= mBufferSize;
//check state
if (state == State.Recording || state == State.PreRecording)
{
secondBuffer.Add(CaptureData);
}
}


  上面的代码是C# DirectSound的捕获到数据后的处理方法.也就是说,麦克风得到的信号转换成数字信号,在程序里变为一个byte[]数组放到缓存区,然后我可以一个一个的从缓冲区里得到这个byte[]对象,以前我在这里提问过,一些朋友说计算这个byte[]的平均值或方差可以得到用户说话的音量,可是效果不理想.有时好用有时不好用.

  所以来到这里请大家帮忙!是否有办法通过计算缓冲区得到的byte[]数据来得到麦克音量,或通过其他API(最好是DirectSound的)能知道用户当前的说话的音量大小.无论你能否帮上忙,先谢谢你!


以下的信息或许会有帮助:

1.我找到的声音探测的软件(含源码),不过功能太复杂了,不容易分离出来,并且使用的不是DirectSound如果用他的整个程序得重写.
http://www.dreamincode.net/forums/showtopic38890.htm

2.我已经完成的不带自动探测声音的录音的源代码


public class Recorder
{
//由于长度限制,变量略
public void Initialize()
{
// Create capture buffer.
CreateCaptureBuffer();
// Create notification system.
InitNotifications();
mRecBuffer.Start(true);
}
public void Dispose()
{
// Close notification
if (null != mNotificationEvent)
mNotificationEvent.Set();
// Stop recording
mRecBuffer.Stop();
}


#endregion
#region Initialize Recorder
public Recorder()
{
InitCaptureDevice();
mWavFormat = CreateWaveFormat();
buffDes = new BufferDescription();
buffDes.GlobalFocus = true;
buffDes.ControlVolume = true;
buffDes.ControlPan = true;
secDev = new Device();
bufferStates = new List<int>();
}
private void RecordCapturedData()
{
byte[] CaptureData = null;
int ReadPos;
int CapturePos;
int LockSize;
mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos);
LockSize = ReadPos - mNextCaptureOffset;
if (LockSize < 0)
LockSize += mBufferSize;
LockSize -= (LockSize % mNotifySize);
if (0 == LockSize)
return;
CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize);
mNextCaptureOffset += CaptureData.Length;
mNextCaptureOffset %= mBufferSize;
//check state
if (state == State.Recording || state == State.PreRecording)
{
secondBuffer.Add(CaptureData);
}
}
private void CreateCaptureBuffer()
{
CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
if (null != mNotify)
{
mNotify.Dispose();
mNotify = null;
}
if (null != mRecBuffer)
{
mRecBuffer.Dispose();
mRecBuffer = null;
}
// set notification's size: 1 second
mNotifySize = (1024 > mWavFormat.AverageBytesPerSecond / 8) ? 1024 : (mWavFormat.AverageBytesPerSecond / 8);
mNotifySize -= mNotifySize % mWavFormat.BlockAlign;
// set size of buffer
mBufferSize = mNotifySize * cNotifyNum;

bufferdescription.BufferBytes = mBufferSize;
bufferdescription.Format = mWavFormat;

mRecBuffer = new CaptureBuffer(bufferdescription, mCapDev);
mNextCaptureOffset = 0;
}
private bool InitNotifications()
{
if (null == mRecBuffer)
{
MessageBox.Show("Record buffer is not found!");
return false;
}
mNotificationEvent = new AutoResetEvent(false);
if (null == mNotifyThread)
{
mNotifyThread = new Thread(new ThreadStart(WaitThread));
mNotifyThread.Start();
}
BufferPositionNotify[] PositionNotify = new BufferPositionNotify[cNotifyNum + 1];
for (int i = 0; i < cNotifyNum; i++)
{
PositionNotify[i].Offset = (mNotifySize * i) + mNotifySize - 1;
PositionNotify[i].EventNotifyHandle = mNotificationEvent.Handle;
}
mNotify = new Notify(mRecBuffer);
mNotify.SetNotificationPositions(PositionNotify, cNotifyNum);

return true;
}
private bool InitCaptureDevice()
{
CaptureDevicesCollection devices = new CaptureDevicesCollection();
Guid deviceGuid = Guid.Empty;
if (devices.Count > 0)
deviceGuid = devices[0].DriverGuid;
else
{
MessageBox.Show("No device to capture wave!");
return false;
}
try
{
mCapDev = new Capture(deviceGuid);
}
catch (DirectXException e)
{
MessageBox.Show(e.ToString());
return false;
}
return true;
}
private WaveFormat CreateWaveFormat()
{
WaveFormat format = new WaveFormat();
format.FormatTag = WaveFormatTag.Pcm; // PCM
format.SamplesPerSecond = 16000; // 16KHz
format.BitsPerSample = 16; // 16Bit
format.Channels = 1; // Mono
format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;
return format;

}
private void WaitThread()
{
while (true)
{
// waiting for notification
mNotificationEvent.WaitOne(Timeout.Infinite, true);
// process data captured
RecordCapturedData();
}
}
#endregion
}



...全文
2717 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
liangsongjun 2012-09-04
  • 打赏
  • 举报
回复
需要同样的方案
spider1216 2011-09-05
  • 打赏
  • 举报
回复
你好,我也在做录音的时候能监测到音量大小,好显示出有无声音输入
能发一份给我源码研究吗
~谢谢
pofengwu@gmail.com
ccmada 2011-04-10
  • 打赏
  • 举报
回复
邮箱是1027987743@qq.com
ccmada 2011-04-10
  • 打赏
  • 举报
回复
你好~不麻烦的话也给我发一份吧~我想做一个声音控制的游戏~想研究一下你的源码~谢谢
d8662110 2010-12-23
  • 打赏
  • 举报
回复
你好,我也正在做类似的,就是录音的时候能监测到音量大小,好显示出有无声音输入!能发一份给我研究研究吗?landong250@163.com。谢谢啦1
endy_c 2010-12-22
  • 打赏
  • 举报
回复
你好,我要到做类似的东西,能发一份给我吗?我邮箱gmajkun@163.com,谢谢了
bosnma 2010-03-24
  • 打赏
  • 举报
回复
如果大家着急,可以通过email与我联系:

bosnma@live.com

谢谢各位。
bosnma 2010-03-24
  • 打赏
  • 举报
回复
很老的一个帖子了,汗。

真的非常非常非常非常(一千个非常)抱歉,当时肯定是忙疯了忘了把Solution贴出来。

最后的解决方法就是计算缓冲区波形数据,算法是找了一些开源项目,然后分析这些类似项目的算法得到的。
大体算法如下,具体的项目文档我会在近期整理出来分享给大家哈:

 private void RecordCapturedData()
{
byte[] CaptureData = null;
int ReadPos;
int CapturePos;
int LockSize;
mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos);
LockSize = ReadPos - mNextCaptureOffset;
if (LockSize < 0)
LockSize += mBufferSize;
LockSize -= (LockSize % mNotifySize);
if (0 == LockSize)
return;
CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize);
mNextCaptureOffset += CaptureData.Length;
mNextCaptureOffset %= mBufferSize;

_waveLeft = new double[CaptureData.Length / 4];
_waveRight = new double[CaptureData.Length / 4];

// Split out channels from sample
int h = 0;
for (int i = 0; i < CaptureData.Length; i += 4)
{
_waveLeft[h] = (double)BitConverter.ToInt16(CaptureData, i);
_waveRight[h] = (double)BitConverter.ToInt16(CaptureData, i + 2);
h++;
}


double sum = 0;
foreach (double item in _waveLeft)
{
if (item > 0)
sum += item;
else
sum += -item;
}

int result = (int)(((sum / _waveLeft.Length)) / 32768 * 100);

if (state == State.Starting||state == State.Started)
{
secondBuffer.Add(CaptureData);
}
OnVolumeChanged(new OnVolumeChangedEventArgs(result));

if (state == State.Started)
{
if (result < accuracy)
{
silence++;
if (silence > 10)
{
silence = 0;
SwitchState(State.Paused);
}
}
}
else if (state == State.Paused)
{
if (result > accuracy)
{
silence = 0;
secondBuffer = new List<byte[]>();
int n = _thirdBuffer.Count;
for (int i = 0; i < n; i++)
{
secondBuffer.Add(_thirdBuffer.Dequeue());
}
secondBuffer.Add(CaptureData);
SwitchState(State.Started);

}
}

if (_thirdBuffer.Count <= _THIRD_BUFFER_SIZE)
{
_thirdBuffer.Enqueue(CaptureData);
}
else
{
_thirdBuffer.Enqueue(CaptureData);
_thirdBuffer.Dequeue();
}
}


sxmonsy 2010-02-11
  • 打赏
  • 举报
回复
学习了。学习了。学习了。
sherlock_yang 2010-02-11
  • 打赏
  • 举报
回复
想问问楼主说已经解决是怎么解决的......我也在做点和这有关的东西 谢谢 邮箱:sherlock_yang@hotmail.com
corn8888 2010-02-10
  • 打赏
  • 举报
回复
友情帮顶,顺便学习
友情帮顶,顺便学习
sherlock_yang 2010-02-10
  • 打赏
  • 举报
回复
想问问楼主说已经解决是怎么解决的......我也在做点和这有关的东西 谢谢
热学沸腾56 2009-04-11
  • 打赏
  • 举报
回复
up,mark
Roc_Lee 2009-03-30
  • 打赏
  • 举报
回复
友情帮顶,顺便学习。
Teng_s2000 2009-03-30
  • 打赏
  • 举报
回复
Mark
fcxxfcxx 2009-03-18
  • 打赏
  • 举报
回复
xx
bosnma 2009-03-18
  • 打赏
  • 举报
回复
算了...我自己已经解决掉了.
bosnma 2009-03-16
  • 打赏
  • 举报
回复
加分咯~~~~~~~~~

qq603284891 2009-03-16
  • 打赏
  • 举报
回复
学习赖!顶赖!
fushizhe 2009-03-16
  • 打赏
  • 举报
回复

加载更多回复(9)

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧