一直想研究下录音 正好有个项目有机会使用一下强大的 NAudio (https://github.com/naudio/NAudio)库

录音

NAudio 录音类库

public class NAudioRecorder
{
public WaveIn waveSource = null;
public WaveFileWriter waveFile = null;
private string fileName = string.Empty; /// <summary>
/// 开始录音
/// </summary>
public void StartRec()
{
waveSource = new WaveIn();
waveSource.WaveFormat = new WaveFormat(16000, 16, 1); // 16bit,16KHz,Mono的录音格式 waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
//writer = new WaveFileWriter(outputFilePath, capture.WaveFormat);
var capture = new WasapiLoopbackCapture();
Directory.CreateDirectory(fileName);
var outputFilePath = Path.Combine(fileName, "recorded.wav");
waveFile = new WaveFileWriter(outputFilePath, waveSource.WaveFormat); waveSource.StartRecording();
} /// <summary>
/// 停止录音
/// </summary>
public void StopRec()
{
waveSource.StopRecording(); if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
} if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
} /// <summary>
/// 录音结束后保存的文件路径
/// </summary>
/// <param name="fileName">保存wav文件的路径名</param>
public void SetFileName(string fileName)
{
this.fileName = fileName;
} /// <summary>
/// 开始录音回调函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveFile != null)
{
waveFile.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Flush();
}
} /// <summary>
/// 录音结束回调函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
{
if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
} if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
}
}

变声

变声用到的是SoundTouch.dll

SoundTouch wrapper

public class SoundTouch
{
private IntPtr handle; public SoundTouch()
{
handle = soundtouch_createInstance();
} ~SoundTouch()
{
soundtouch_destroyInstance(handle);
} /// <summary>
/// Get SoundTouch version string
/// </summary>
public static String GetVersionString()
{
// convert "char *" data to c# string
return Marshal.PtrToStringAnsi(soundtouch_getVersionString());
} /// <summary>
/// Returns number of processed samples currently available in SoundTouch for immediate output.
/// </summary>
public uint NumSamples()
{
return soundtouch_numSamples(handle);
} /// <summary>
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception.
/// </summary>
/// <param name="samples">Sample buffer to input</param>
/// <param name="numSamples">Number of sample frames in buffer. Notice
/// that in case of multi-channel sound a single sample frame contains
/// data for all channels</param>
public void PutSamples(float[] samples, uint numSamples)
{
soundtouch_putSamples(handle, samples, numSamples);
} /// <summary>
/// Sets the number of channels
/// </summary>
/// <param name="numChannels">1 = mono, 2 = stereo, n = multichannel</param>
public void SetChannels(uint numChannels)
{
soundtouch_setChannels(handle, numChannels);
} /// <summary>
/// Sets sample rate.
/// </summary>
/// <param name="srate">Samplerate, e.g. 44100</param>
public void SetSampleRate(uint srate)
{
soundtouch_setSampleRate(handle, srate);
} /// <summary>
/// Receive processed samples from the processor.
/// </summary>
/// <param name="outBuffer">Buffer where to copy output samples</param>
/// <param name="maxSamples">Max number of sample frames to receive</param>
/// <returns></returns>
public uint ReceiveSamples(float[] outBuffer, uint maxSamples)
{
return soundtouch_receiveSamples(handle, outBuffer, maxSamples);
} /// <summary>
/// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers.
//
/// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream.
/// </summary>
public void Flush()
{
soundtouch_flush(handle);
} /// <summary>
/// Clears all the samples in the object's output and internal processing
/// buffers.
/// </summary>
public void Clear()
{
soundtouch_clear(handle);
} /// <summary>
/// Sets new tempo control value.
/// </summary>
/// <param name="newTempo">Tempo setting. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo.</param>
public void SetTempo(float newTempo)
{
soundtouch_setTempo(handle, newTempo);
} /// <summary>
/// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %);
/// </summary>
/// <param name="newTempo">Tempo setting in %</param>
public void SetTempoChange(float newTempo)
{
soundtouch_setTempoChange(handle, newTempo);
} /// <summary>
/// Sets new rate control value.
/// </summary>
/// <param name="newRate">Rate setting. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rate.</param>
public void SetRate(float newRate)
{
soundtouch_setTempo(handle, newRate);
} /// <summary>
/// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %);
/// </summary>
/// <param name="newRate">Rate setting in %</param>
public void SetRateChange(float newRate)
{
soundtouch_setRateChange(handle, newRate);
} /// <summary>
/// Sets new pitch control value.
/// </summary>
/// <param name="newPitch">Pitch setting. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch.</param>
public void SetPitch(float newPitch)
{
soundtouch_setPitch(handle, newPitch);
} /// <summary>
/// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00 for +- one octave);
/// </summary>
/// <param name="newPitch">Pitch setting in octaves</param>
public void SetPitchOctaves(float newPitch)
{
soundtouch_setPitchOctaves(handle, newPitch);
} /// <summary>
/// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12 for +- one octave);
/// </summary>
/// <param name="newPitch">Pitch setting in semitones</param>
public void SetPitchSemiTones(float newPitch)
{
soundtouch_setPitchSemiTones(handle, newPitch);
} /// <summary>
/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data
/// and internally converts it to float format before processing
/// </summary>
/// <param name="samples">Sample input buffer.</param>
/// <param name="numSamples">Number of sample frames in buffer. Notice
/// that in case of multi-channel sound a single
/// sample frame contains data for all channels.</param>
public void PutSamples_i16(short[] samples, uint numSamples)
{
soundtouch_putSamples_i16(handle, samples, numSamples);
} /// <summary>
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
/// </summary>
/// <param name="settingId">Setting ID number. see SETTING_... defines.</param>
/// <param name="value"New setting value></param>
/// <returns>nonzero if successful, otherwise zero</returns>
public int SetSetting(int settingId, int value)
{
return soundtouch_setSetting(handle, settingId, value);
} /// <summary>
/// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
/// </summary>
/// <param name="settingId">Setting ID number</param>
/// <returns>The setting value</returns>
public int soundtouch_getSetting(int settingId)
{
return soundtouch_getSetting(handle, settingId);
} /// <summary>
/// Returns number of samples currently unprocessed in SoundTouch internal buffer
/// </summary>
/// <returns>Number of sample frames</returns>
public uint NumUnprocessedSamples()
{
return soundtouch_numUnprocessedSamples(handle);
} /// <summary>
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples
/// into int16 (short) return data type
/// </summary>
/// <param name="outBuffer">Buffer where to copy output samples.</param>
/// <param name="maxSamples">How many samples to receive at max.</param>
/// <returns>Number of received sample frames</returns>
public uint soundtouch_receiveSamples_i16(short[] outBuffer, uint maxSamples)
{
return soundtouch_receiveSamples_i16(handle, outBuffer, maxSamples);
} /// <summary>
/// Check if there aren't any samples available for outputting.
/// </summary>
/// <returns>nonzero if there aren't any samples available for outputting</returns>
public int IsEmpty()
{
return soundtouch_isEmpty(handle);
} [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_getVersionId")]
/// <summary>
/// Get SoundTouch library version Id
/// </summary>
public static extern int GetVersionId(); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr soundtouch_createInstance(); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_destroyInstance(IntPtr h); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr soundtouch_getVersionString(); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setRate(IntPtr h, float newRate); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setTempo(IntPtr h, float newTempo); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setRateChange(IntPtr h, float newRate); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setTempoChange(IntPtr h, float newTempo); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setPitch(IntPtr h, float newPitch); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setPitchOctaves(IntPtr h, float newPitch); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setPitchSemiTones(IntPtr h, float newPitch); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setChannels(IntPtr h, uint numChannels); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_setSampleRate(IntPtr h, uint srate); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_flush(IntPtr h); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_putSamples(IntPtr h, float[] samples, uint numSamples); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_putSamples_i16(IntPtr h, short[] samples, uint numSamples); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void soundtouch_clear(IntPtr h); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int soundtouch_setSetting(IntPtr h, int settingId, int value); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int soundtouch_getSetting(IntPtr h, int settingId); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern uint soundtouch_numUnprocessedSamples(IntPtr h); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern uint soundtouch_receiveSamples(IntPtr h, float[] outBuffer, uint maxSamples); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern uint soundtouch_receiveSamples_i16(IntPtr h, short[] outBuffer, uint maxSamples); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern uint soundtouch_numSamples(IntPtr h); [DllImport("SoundTouch.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int soundtouch_isEmpty(IntPtr h);
}

  源码下载(https://files.cnblogs.com/files/leoxjy/demo.zip)

C# 录音和变调的更多相关文章

  1. 几行代码把Chrome搞崩溃之:HTML5 MP3录音由ScriptProcessorNode升级成AudioWorkletNode采坑记

    关键词: STATUS_ACCESS_VIOLATION AudioContext AudioWorkletNode audioWorklet addModule resume suspended c ...

  2. FFmpeg + SoundTouch实现音频的变调变速

    本文使用FFmpeg + SoundTouch实现将音频解码后,进行变调变速处理,并将处理后的结果保存为WAV文件. 主要有以下内容: 实现一个FFmpeg的工具类,保存多媒体文件所需的解码信息 将解 ...

  3. iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

    --iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制, ...

  4. HTML5网页录音和压缩,边猜边做..(附源码)

    宣传一下自己的qq群: (暗号:C#交流) 欢迎喜欢C#,热爱C#,正在学习C#,准备学习C#的朋友来这里互相学习交流,共同进步 群刚建,人不多,但是都是真正热爱C#的 我也是热爱C#的 希望大家可以 ...

  5. Android音频开发之AudioRecord录音实现

    前言: 其实在Android中录音可以用MediaRecord录音,操作比较简单.但是不能对音频进行处理.考虑到项目中做的是实时语音只能选择AudioRecord进行录音. 本文算是对AudioRec ...

  6. iOS 直播-实现后台录音并推流

    iOS 直播-实现后台录音并推流 从一个月前开始开始接收公司的直播类app.到今天为止测试都已接近尾声,但是产品哥哥加了一个要求,就是在app进入后台后也实时保证录音并且推流. 刚听到这个的时候我也是 ...

  7. ubuntu 下简单录音

    找了半天录音工具,甚至都在尝试用 pyAudio 自己写了,结果发现,原来有现成命令行工具用! 就是 sox 工具包.这个工具包有 4 个工具:sox, play, rec, soxi.rec 和 p ...

  8. 微信录音接口的调用以及amr文件转码MP3文件的实现

    最近实现录音功能,主要涉及到录音的上传和下载,以及转码问题.微信,QQ默认的的音频文件是amr格式的,而播放器却不识别amr格式的音频,必须尽行转码.amr文件分为两种,一种是通用的amr格式,这种文 ...

  9. Android 录音器

    Android自带的mediarecoder录音器不含pause暂停功能,解决方法:录制多个音频片段,最后合成一个文件. 参照 : http://blog.csdn.net/a601445984/ar ...

随机推荐

  1. shell 判断操作系统

    #!/bin/sh a=`uname -a` b="Darwin" c="centos" d="ubuntu" if [[ $a =~ $b ...

  2. Cisco路由器用SSH替代Telnet连接

    本文告诉你若何用SSH替代Telnet. 使用Telnet这个用来访谒远程计较机的TCP/IP和你的用户名和口令.很快地,会有人进行监听,而且他们会操作你平安是因为你意识的缺乏. SSH是替代Teln ...

  3. [技术博客]采用Qthread实现多线程连接等待

    采用Qthread实现多线程连接等待 ​ 本组的安卓自动化测试软件中,在测试开始前需要进行连接设备的操作,如下图左侧的按钮 ​ ​ 后端MonkeyRunner相关操作的程序中提供了connect() ...

  4. Leetcode:2. 两数相加

    题目描述: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来 ...

  5. 把ngnix注册为linux服务 将Nginx设置为linux下的服务 并设置nginx开机启动

    一.创建服务脚本 vim /etc/init.d/nginx 脚本内容如下 #! /bin/sh# chkconfig: - 85 15 PATH=/usr/local/nginx/sbin/ DES ...

  6. arcpy地理处理工具案例教程-景观形状指数计算

    arcpy地理处理工具案例教程-景观形状指数计算 商务合作,科技咨询,版权转让:向日葵,135-4855_4328,xiexiaokui#qq.com 使用方法:输入要素类即可,其余参数均默认. 商务 ...

  7. Alpine容器中运行go的二进制文件

    Alpine容器中运行go的二进制文件 kuSorZ · 3月之前 · 214 次点击 · 预计阅读时间 1 分钟 · 2分钟之前 开始浏览 原文出处:https://cloud.tencent.co ...

  8. Java一行代码

    1.整数格式化成0X 的形式字符串 String hour=String.format("%02d", txtWaringTime.getCurrentHour()); Strin ...

  9. [转]js对象中取属性值(.)和[ ]的区别

    原文地址:https://www.jianshu.com/p/6a76530e4f8f 今天在写js的过程中遇到这么一个问题,取一个对象的属性值,通过obj.keys怎么都取不出来,但是用obj[ke ...

  10. snf快速开发平台试用演示地址

      BS演示地址: http://49.4.68.200:65432 administrator / Administrator     snf-cs试用版本下载地址:https://pan.baid ...