Mail to Keith Dan
keith的天空
海阔凭鱼跃,天高任鸟飞

应一个朋友委托,做一个录音程序.
我原本以为要用direct来做,先是在google上搜索了一把,收获不大。后来在codeproject上发现一篇文章A full-duplex audio player in C# using the waveIn/waveOut APIs ,原来可以很简单。在System32下原来有一个多媒体处理的API,winmm.dll,发现之非常兴奋,哈哈。
原来微软已经提供了一系列的wavein 和waveout方法,参考了里面一些东西做法。做了一些修改。由于我以前对音频并不怎么了解,特地查了一下音频的有关知识,不了解的朋友也可以了解一下,呵呵,知识共享拉。
其中音频采样率(位/bit),采样率包括32000Hz,44100Hz,48000Hz3种,采样大小分为16位和8位,声道通常就是2(立体声)和1(单声道)了。其中有一个重要的数据叫采样速率,计算公式为采样速率=采样率×采样大小×声道。我们通常比较熟悉的128K的MP3就是44100×16×2=1411.2Kb/s,这样的音频很大,通常10秒种就有1M多。而如果使用模拟信号的话并非采样率越高越好,只会盲目的增加我们文件的大小,只有数字信号的时候才会提高我们的效果。
对于音频这一块,希望其他朋友能提供给一些更多的知识与技术。特别是音频对比和频谱图等等。
那么我们往下看。

//wav头
                long chunksize = fs.Length + 36;
                WriteChars(bw, 
"RIFF");//格式
                bw.Write((int)chunksize);//文件长度(要加上头的36字节)
                WriteChars(bw, "WAVE");//标示
                WriteChars(bw, "fmt ");//fmt
                bw.Write((int)16);//fmt长度
                bw.Write(m_Format.wFormatTag);//压缩模式
                bw.Write(m_Format.nChannels);//声道
                bw.Write(m_Format.nSamplesPerSec);//采样率包含:32000Hz,44100Hz,48000Hz.
                bw.Write(m_Format.nAvgBytesPerSec);//每秒播放字节
                bw.Write(m_Format.nBlockAlign);//位速
                bw.Write(m_Format.wBitsPerSample);//采样大小
                WriteChars(bw,"data");//data标志
                bw.Write(fs.Length);//音频长度

这就是我们需要给wave文件写上的头。
大家查一下winmm.dll就会发现,里面提供了很多有用的API,非常的棒。
// WaveIn calls
        [DllImport(mmdll)]
        
public static extern int waveInGetNumDevs();
        [DllImport(mmdll)]
        
public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHdr pwh, int cbwh);
        [DllImport(mmdll)]
        
public static extern int waveInClose(IntPtr hwi);
        [DllImport(mmdll)]
        
public static extern int waveInOpen(out IntPtr phwi, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
        [DllImport(mmdll)]
        
public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
        [DllImport(mmdll)]
        
public static extern int waveInUnprepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
        [DllImport(mmdll)]
        
public static extern int waveInReset(IntPtr hwi);
        [DllImport(mmdll)]
        
public static extern int waveInStart(IntPtr hwi);
        [DllImport(mmdll)]
        
public static extern int waveInStop(IntPtr hwi);
其中DataArrived方法是委托的方法,它将我们接收到的数据拷贝到m_RecBuffer中,再写入到文件里。在这里我并没有使用MenmoyStream,看到windows录音限制1分钟,我估计它(我并没有认真看过)是讲数据写入内存,再统一存储的,为了没有限制,所以直接用了FileStream,写到文件里了。
private void DataArrived(IntPtr data, int size)
        
{
            
try
            
{
                
if (m_RecBuffer == null || m_RecBuffer.Length < size)
                
{
                    m_RecBuffer 
= new byte[size];
                }

                System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 
0, size);

                bw_tmp.Write(m_RecBuffer);
                _recordSize
+=m_RecBuffer.Length;
            }

            
catch(Exception e)
            
{
                
return;
            }

        }

里面我加入了一些功能,包括开始,停止,暂停,继续等等。

在此,我想问一下其他朋友,音频的频谱图是基于怎样的算法呢?如何画的?这个我很想了解,有这方面知识的朋友望能告知,给点参考。在此谢过。

Source
--------------------------------------------
参考:
A full-duplex audio player in C# using the waveIn/waveOut APIs
PCM编码及其技术
posted on 2006-12-19 14:42  KeithDan  阅读(10427)  评论(31编辑  收藏  举报