主要是想请兄弟把此程序的基本原理讲一下(特别是缓存那块 我不明白)由于篇幅问题 窗体声明部分代码我省掉了  回调函数和指针名称等请引用代码源名称 越详细越好 还有接下来想做数据传输 实现语音通讯 请各位高手给点建议 谢谢大家! 
源代码如下:
 
Option ExplicitPublic Const BUF_SIZE = 327680
Public Const SAMPLES = 22050&
Public Const BITS = 16
Public Const CHANNEL = 1Public Const WIM_OPEN = &H1
Public Const WIM_CLOSE = &H2
Public Const WIM_DATA = &H3
Public Const WOM_OPEN = &H4
Public Const WOM_CLOSE = &H5
Public Const WOM_DONE = &H6
Private hWaveIn As Long
Private hWaveOut As Long
Private inHdr As WAVEHDRw
Private outHdr As WAVEHDR
Private WavInFmt As WAVEFORMAT
Private WavOutFmt As WAVEFORMAT
Private hMemIn As Long
Private hMemOut As Long
Private prevWndProc As Long
Private DesthWnd As LongPublic Sub RegisterWinProc(ByVal hWnd As Long)
prevWndProc = GetWindowLong(hWnd, GWL_WNDPROC) '取得一个指定窗口的窗口地址 并赋值给prevWndProc
SetWindowLong hWnd, GWL_WNDPROC, AddressOf WndProc
DesthWnd = hWndEnd SubPublic Sub UnRegisterWinProc(ByVal hWnd As Long)
SetWindowLong hWnd, GWL_WNDPROC, prevWndProcEnd SubFunction WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'If (Msg = WM_USER) Then
'    Select Case wParam
'        Case WIM_OPEN
'            MsgBox "WaveInOpen ok."
'        Case WIM_CLOSE
'            MsgBox "WaveInClose ok."
'        Case WIM_DATA
'            MsgBox "Buffer full."
'        Case WOM_OPEN
'            MsgBox "WaveOutOpen ok."
'        Case WOM_CLOSE
'            MsgBox "WaveOutClose ok."
'        Case WOM_DONE
'            MsgBox "Data sent."
'    End Select
'End IfSelect Case Msg
    Case MM_WIM_DATA
        MsgBox "Buffer full."
        outHdr.lpData = inHdr.lpData
    Case MM_WIM_OPEN
'        MsgBox "WaveInOpen ok."
    Case MM_WIM_CLOSE
'        MsgBox "WaveInClose ok."
    Case MM_WOM_DONE
        MsgBox "Playback finished."
    Case MM_WOM_OPEN
'        MsgBox "WaveOutOpen ok."
    Case MM_WOM_CLOSE
'        MsgBox "WaveOutClose ok."
End SelectWndProc = CallWindowProc(prevWndProc, hWnd, Msg, wParam, lParam)
End FunctionPublic Function MywaveInProc(ByVal hwi As Long, ByVal uMsg As Long, ByVal dwInstance As Long, ByRef hdr As WAVEHDR, ByVal dwParam2 As Long) As Long
Select Case (uMsg)
    Case MM_WIM_DATA
'        PostMessage DesthWnd, WM_USER, WIM_DATA, 0
    Case MM_WIM_OPEN
'        PostMessage DesthWnd, WM_USER, WIM_OPEN, 0
    Case MM_WIM_CLOSE
'        PostMessage DesthWnd, WM_USER, WIM_CLOSE, 0
End SelectEnd FunctionPublic Function MywaveOutProc(ByVal hwo As Long, ByVal uMsg As Long, ByVal dwInstance As Long, ByRef hdr As WAVEHDR, ByVal dwParam2 As Long) As Long
Select Case (uMsg)
    Case MM_WOM_DONE
'        PostMessage DesthWnd, WM_USER, WOM_DONE, 0
    Case MM_WOM_OPEN
'        PostMessage DesthWnd, WM_USER, WOM_OPEN, 0
    Case MM_WOM_CLOSE
'        PostMessage DesthWnd, WM_USER, WOM_CLOSE, 0
End SelectEnd FunctionPublic Sub WaveInInit(ByVal nCh As Integer, ByVal Sample As Long, ByVal nBits As Integer)
Dim ret As Long
Dim Msg As String * 200
WavInFmt.wFormatTag = WAVE_FORMAT_PCM
WavInFmt.nChannels = nCh
WavInFmt.nSamplesPerSec = Sample
WavInFmt.nBlockAlign = nBits * nCh / 8
WavInFmt.wBitsPerSample = nBits
WavInFmt.cbSize = 0
WavInFmt.nAvgBytesPerSec = nBits * Sample * nCh / 8
ret = waveInOpen(hWaveIn, WAVE_MAPPER, WavInFmt, DesthWnd, 0, CALLBACK_WINDOW) 'AddressOf MywaveInProc, 0, CALLBACK_FUNCTION)
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInOpen:" & Msg
        Exit Sub
End If
hMemIn = GlobalAlloc(GMEM_MOVEABLE + GMEM_SHARE + GMEM_ZEROINIT, BUF_SIZE)
inHdr.lpData = GlobalLock(hMemIn)
inHdr.dwBufferLength = BUF_SIZE
inHdr.dwFlags = 0
inHdr.dwLoops = 0
inHdr.dwUser = 0
ret = waveInPrepareHeader(hWaveIn, inHdr, Len(inHdr))
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInPrepareHeader" & Msg
        Exit Sub
End IfEnd SubPublic Sub WaveInRecord()
Dim ret As Long
Dim Msg As String * 200
ret = waveInAddBuffer(hWaveIn, inHdr, Len(inHdr))
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInAddBuffer" & Msg
        Exit Sub
End If
ret = WaveInStart(hWaveIn)
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInAddBuffer" & Msg
        Exit Sub
End IfEnd Sub
Public Sub WaveInDeinit()
Dim ret As Long
Dim Msg As String * 200
ret = waveInStop(hWaveIn)
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInStop" & Msg
        Exit Sub
End If
ret = waveInReset(hWaveIn)
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInReset" & Msg
        Exit Sub
End If
ret = waveInUnprepareHeader(hWaveIn, inHdr, Len(inHdr))
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInUnprepareHeader" & Msg
        Exit Sub
End If
GlobalUnlock hMemIn
GlobalFree hMemIn
ret = waveInClose(hWaveIn)
If ret <> 0 Then
        waveInGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveInClose" & Msg
        Exit Sub
End IfEnd SubPublic Sub WaveOutInit(ByVal nCh As Integer, ByVal Sample As Long, ByVal nBits As Integer)
Dim ret As Long
Dim Msg As String * 200
WavOutFmt.wFormatTag = WAVE_FORMAT_PCM
WavOutFmt.nChannels = nCh
WavOutFmt.nSamplesPerSec = Sample
WavOutFmt.nBlockAlign = nBits * nCh / 8
WavOutFmt.wBitsPerSample = nBits
WavOutFmt.cbSize = 0
WavOutFmt.nAvgBytesPerSec = nBits * Sample * nCh / 8
ret = waveOutOpen(hWaveOut, WAVE_MAPPER, WavOutFmt, DesthWnd, 0, CALLBACK_WINDOW) ' AddressOf MywaveOutProc, 0, CALLBACK_FUNCTION)
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutOpen:" & Msg
        Exit Sub
End If
hMemOut = GlobalAlloc(GMEM_MOVEABLE + GMEM_SHARE + GMEM_ZEROINIT, BUF_SIZE)
outHdr.lpData = GlobalLock(hMemOut)
outHdr.dwBufferLength = BUF_SIZE
outHdr.dwFlags = 0
outHdr.dwLoops = 0
outHdr.dwUser = 0
ret = waveOutPrepareHeader(hWaveOut, outHdr, Len(outHdr))
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutPrepareHeader" & Msg
        Exit Sub
End IfEnd SubPublic Sub WaveOutPlayback()
Dim ret As Long
Dim Msg As String * 200ret = waveOutWrite(hWaveOut, outHdr, Len(outHdr))
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutWrite" & Msg
        Exit Sub
End IfEnd Sub
Public Sub WaveOutDeinit()
Dim ret As Long
Dim Msg As String * 200
ret = waveOutReset(hWaveOut)
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutReset" & Msg
        Exit Sub
End If
ret = waveOutUnprepareHeader(hWaveOut, outHdr, Len(outHdr))
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutUnprepareHeader" & Msg
        Exit Sub
End If
GlobalUnlock hMemOut
GlobalFree hMemOut
ret = waveOutClose(hWaveOut)
If ret <> 0 Then
        waveOutGetErrorText ret, Msg, Len(Msg)
        MsgBox "waveOutClose" & Msg
        Exit Sub
End IfEnd Sub

解决方案 »

  1.   

    我做的时候 Buf_Size设了512,你的    327680太大。录音缓冲有人用了8个,这个应该要大于二。我做的时候缓冲区不使用GlobalAlloc,而是直接定义byte()数组,比如定8个512的 dim Buffer(511,7) as Byte,将8个缓冲看作是队列,然后inHdr.lpData = GlobalLock(hMemIn)好使用inHdr.lpData =Varptr(Buffer(0,0))等,由于数组是在内存中连续存放的,所以很容易用Varptr函数取得地址。在WaveInInit时要注意把8个缓冲赋给WAVEHDR数组,都要prepareheader,都用waveinAddbuffer初始化。在MM_WIM_DATA消息里处理取得的数据,用网络发送。512字节的缓冲感觉很好,延时的感觉很小。并采用多缓冲,连续性也很好,放歌都没问题。这些都是我从网上找到的经验
      

  2.   

    但是有一个问题很奇怪,我在网上也搜到一则帖子,说waveOut放音时,它的回调消息MM_WOM_DONE好像会有点延时才收到,我做的时候好像也有这个问题,很奇怪,不知道那位高手能够解决一下。我的做法是在网络收到数据时候触发用播放WaveOut,如果在MM_WOM_DONE里放似乎会有数据包堆积的现象,就是来不及放,而这个在理论上是不会发生的,也或许是我的队列设计有问题。还有那位高手有语音数据压缩的技术,求教
      

  3.   

    给一些关键性代码,其他基本和搂主的一样
    Public hWaveIn As Long
    Public WavInFmt As WAVEFORMAT'录音缓冲
    Public Const WaveInMaxQueen = 8
    Public hMemInBuffer(BUF_SIZE, WaveInMaxQueen - 1) As Byte
    Public inHdrArray(WaveInMaxQueen - 1) As WAVEHDR
    Public currWavInHdr As Integer, lastWavInHdr As Integer, nextWavInHdr As IntegerPublic Recording As Boolean
    Public Function WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
     Select Case Msg
        Case MM_WIM_DATA
            
            waveInUnprepareHeader hWaveIn, inHdrArray(currWavInHdr), Len(inHdrArray(0))
            
            
             CopyMemory WavRecordData(0), hMemInBuffer(0, currWavInHdr), BUF_SIZE + 1
    '可以先定义一个WavRecordData(), 这样拷贝过去的就是录音获取到的数据
            nextWavInHdr = (currWavInHdr - 1 + WaveInMaxQueen) Mod WaveInMaxQueen
            currWavInHdr = (currWavInHdr + 1) Mod WaveInMaxQueen
    '注:这里的计算方式我大致觉得就是队列,但这是网上别人的计算放大,就沿用了
            If Recording Then
                inHdrArray(nextWavInHdr).dwFlags = 0
                inHdrArray(nextWavInHdr).dwLoops = 0
                waveInPrepareHeader hWaveIn, inHdrArray(nextWavInHdr), Len(inHdrArray(0))
                waveInAddBuffer hWaveIn, inHdrArray(nextWavInHdr), Len(inHdrArray(0))
                 
            End If
    。Public Sub WaveInInit(ByVal nCh As Integer, ByVal Sample As Long, ByVal nBits As Integer)
    Dim ret As Long
    Dim Msg As String * 200
    Dim wIndex As Integer
    WavInFmt.wFormatTag = WAVE_FORMAT_PCM
    WavInFmt.nChannels = nCh
    WavInFmt.nSamplesPerSec = Sample
    WavInFmt.nBlockAlign = nBits * nCh / 8
    WavInFmt.wBitsPerSample = nBits
    WavInFmt.cbSize = 0
    WavInFmt.nAvgBytesPerSec = nBits * Sample * nCh / 8
    ret = waveInOpen(hWaveIn, WAVE_MAPPER, WavInFmt, DesthWnd, 0, CALLBACK_WINDOW)   
    If ret <> 0 Then
            waveInGetErrorText ret, Msg, Len(Msg)
            MsgBox "waveInOpen:" & Msg
            Exit Sub
    End If'初始化多缓冲区
    For wIndex = 0 To WaveInMaxQueen - 1
            inHdrArray(wIndex).dwFlags = 0
            inHdrArray(wIndex).dwLoops = 0
            inHdrArray(wIndex).dwBytesRecorded = 0
            inHdrArray(wIndex).dwUser = 0
            inHdrArray(wIndex).dwBufferLength = BUF_SIZE + 1
            inHdrArray(wIndex).lpData = VarPtr(hMemInBuffer(0, wIndex))
    Next wIndex
    For wIndex = 0 To WaveInMaxQueen - 2
            waveInPrepareHeader hWaveIn, inHdrArray(wIndex), Len(inHdrArray(0))
            waveInAddBuffer hWaveIn, inHdrArray(wIndex), Len(inHdrArray(0))
    Next wIndex 
            
            
        currWavInHdr = 0
        nextWavInHdr = 0End Sub
      

  4.   

    转一则文章,网上搜到的,蛮有启发性,仅供参考,小弟懂的也只有那么多了:
    **********************************************************
    实时录音并显示波形、频谱    本文讲述如何实时录音,以及将录音波形频谱实时显示的方法。Windows提供了一个多媒体控制接口(MCI),用它可以录音,很方便。但是这种方法不能实时给出录音的原始数据,因此要显示波形和频谱都是不可能实现的。要达到实时的效果,就要使用Windows提供的另一套函数,即低级音频函数。其中和录音有关的是以waveIn开头的一组函数。    低级音频函数的使用比较繁琐,大致要有以下几个步骤。 用waveInOpen打开设备,并设置回调。因为要保证实时性,所以不能用查询的方式,而必须设置回调。 
    为设备分配足够的内存做缓冲区,动态分配或静态数组都可以。为了保证实时性,程序用了双缓冲技术,在处理一个缓冲区数据的同时另一个缓冲区用于录音。为了便于说明写成Buffer1、Buffer2。 
    将Buffer1关联到设备上去,waveInPrepareBuffer、waveInAddBuffer。 
    开始录音,waveInStart 
    当驱动程序填满这个缓冲区(Buffer1)时就会产生回调(消息为WIM_DATA),这时立刻将Buffer2关联到设备上继续录音,然后处理Buffer1,当驱动程序填满Buffer2时又会产生回调,这是再将Buffer1关联到设备上,而去处理Buffer2,如此反复就使得录音能够实时的进行下去。 
    停止录音,waveInStop 
    关闭设备,waveInClose 
        上面就是实时录音的一个基本流程,产生回调时,其lParam就是一个指向WAVEHDR结构的指针,通过这个指针就可以得到原始数据(注意了:我这个程序只是单声道8位的PCM格式,因此正好一个字节就是一个采样点的值,对于其他格式的我就不知道了)。有了原始数据就可以很容易的画出波形了,而频谱也就是多一次FFT变换而已,没什么太难的。    这里是我用LCC写的例子,非常简单,而且相信大家都可以很容易的移植到BCB上来。另外,我偷了一下懒,FFT用了我以前封装到DLL中的函数(现在已经忘了怎么写了^_^),可以在此下载 (不要觉得奇怪,就是这个时钟,将其中的DEMO.DLL拿来用就是了)。当然你也可以自己写一个FFT放到程序里去。-*-*-PATCH-*-*-2002-06-11    上次那个程序还不好,原因是双缓冲还不能满足实时的要求,因此这次用了8缓冲循环技术。新的程序也是用LCC写的。
        开始时依次将0-6号缓冲区关联到设备上,而7号缓冲区不关联,然后开始录音,这是驱动程序开始向0号缓冲区输出数据,当0号缓冲区数据满时产生回调,这时驱动程序会自动向1号缓冲区输出数据,但这时应将7号缓冲区关联到设备上去,然后处理0号缓冲区的数据。然后当1号缓冲区数据满时又会产生回调,这时驱动程序会自动向2号缓冲区输出数据,而将0号缓冲区关联到设备上去。这样如此反复,始终保持1个缓冲区用于驱动输出数据,1个缓冲区用于处理数据,6个缓冲区处于等待状态。
        而如果只有两个缓冲区,就只能一个用于驱动输出,一个用于处理数据。这样在产生回调的时候就会出现没有处于等待状态的缓冲区的情况,这样驱动程序就不能自动向缓冲区输出数据。而要等waveInPrepareBuffer、waveInAddBuffer调用之后,这样就会出现一个小小的间隙,而导致录音不连续。-*-*-PATCH-*-*-2002-06-11    只是我的个人观点,有什么不对的地方,还望指教。-*-*-PATCH-*-*-2003-04-07    程序中有一个错误,在WIM_DATA的处理过程里。 case WIM_DATA:
      waveInUnprepareHeader(hwi,pwhi,sizeof(WAVEHDR));//释放错误。
      nextWavHdr=(currWavHdr-1+MAX_INQUEU)%MAX_INQUEU;
      currWavHdr=(currWavHdr+1)%MAX_INQUEU;
      if(b_playing)
      {
       pwhi=&whis[nextWavHdr];
       pwhi->dwFlags=0;
       pwhi->dwLoops=0;
       waveInPrepareHeader(hwi,pwhi,sizeof(WAVEHDR));
       waveInAddBuffer(hwi,pwhi,sizeof(WAVEHDR));
      }当0号缓冲区数据满时,应该释放0号句柄。这第一次是对的,但是第二次当1号缓冲满的时候,程序却释放了7号句柄。这里是错的,解决方法就是计算正确的句柄号。或者, 
    waveInUnprepareHeader(hwi,LPWAVEHDR(lParam),sizeof(WAVEHDR));     这样就可以了,感谢flinming发现这个问题。    另外,《网络语音传输》中的程序也有这个问题,请大家自己改吧。-*-*-PATCH-*-*-2003-04-07
      

  5.   

    QQ 79807084
    我是五一前盯上这个技术,本来只是想做一个语音的音量电平指示,就像很多录音软件那样,后来发现并不是很好做,搜索引擎都馊翻了,资料少得可怜,大多说用peakmeter,说微软有例子,事实上找不到,而且peakmeter根本不行,发了封mail给waveCN的作者(著名国产录音软件),很快得到回复说是边录边分析其中的数据,这里很感谢waveCN。后来慢慢找到一些关于WaveIn API的资料,google里发现一些论坛形式的帖子,原来就是CSDN的社区,再一搜,得到一些很好的经验,特别是512字节的缓冲,上边说收的时候缓冲两个数据就能放了。但是我觉得我如果要作网络传输,压缩和考虑网络带宽是一个重要的问题。据说ITU的G792压缩很好,但是原码是c,不精通的,没办法。。
      

  6.   

    可以。winsock还不错,用UDP还可以广播,可以找一些winsock的文章,不是很麻烦。UDP协议非连接的,用bind端口以后,点对点发送接收
      

  7.   

    这个模块怎样使用?在form_load事件中使用RegisterWinProc me.hwnd,整个IDE就会立即关闭.