C#封装C++编写的Speex实现wav音频降噪(字节数组)

在上一篇博文https://blog.csdn.net/zxy13826134783/article/details/105882490的基础上进一步研究,上一篇博客后面使用C#调用Speex是以文件名的方式进行数据传输,明显是不符合远程传输的要求,要实现远程传输,Speex必须能处理音频的字节数组,本文正是基于这种方式进行实现

 

必须在阅读C#封装C++基础上进行本文后面的操作:https://blog.csdn.net/zxy13826134783/article/details/105958311

 

 

注意:本文处理的wav音频文件必须是标准的wav文件,不然会出错

 

本文的Demo可以直接去我的仓库下载:https://gitee.com/zxy15914507674/shared_resource_name,找打对应的

 

speexdsp_Audio.rar下载即可

 

本文Demo的文件结构图:

C#封装C++编写的Speex实现wav音频降噪(字节数组)_第1张图片

进入SpeexWinproj文件夹后

C#封装C++编写的Speex实现wav音频降噪(字节数组)_第2张图片

 

 

为了减少代码的复杂度和业务逻辑,什么安全验证的都没有写进去,只突出核心的部分。

 

找到C++的项目,并找到SpeexWinProj.cpp文件,这正是C++实现降噪的源码,如下:

// SpeexWinProj.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "speex/speex_jitter.h"
#include "speex/speex_echo.h"
#include "speex/speex_preprocess.h"
#include "speex/speex_resampler.h"
#include 
#include 
#include 

#include 
#include  
#include 



#define SAMPLE_RATE   (48000)  
#define SAMPLES_PER_FRAME  (1024)





SpeexPreprocessState *state ;
//初始化操作
void TestBuffer_init(){
	state = speex_preprocess_state_init(1024, SAMPLE_RATE);
	int denoise = 1;
    int noiseSuppress = -25;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_DENOISE, &denoise);
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &noiseSuppress);
    
    int i;
    i = 0;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_AGC, &i);
    i = 80000;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i);
    i = 0;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_DEREVERB, &i);
    float f = 0;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
    f = 0;
    speex_preprocess_ctl(state, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
}
//传入字节数组的,每次处理1024个字节,返回是处理完毕的1024个字节,这样就可以远程传输了
void TestNoise_Buffer(byte *input_out)
{
	speex_preprocess_run(state,(spx_int16_t*)input_out);
		
}
//释放
void TestBuffer_Destory(){
	speex_preprocess_state_destroy(state);
}


找到C++项目中的SpeexWinProj.def文件,该文件定义导出的函数,如下:

LIBRARY BTREE
EXPORTS
    TestNoise_Buffer
    TestBuffer_init
    TestBuffer_Destory

 

然后把C++项目生成,并把生成的dll文件拷贝到C#项目的Debug目录下测试,C#测试代码如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace CSharpCall
{
    class Program
    {
        
        
        unsafe static void Main(string[] args)
        {
           

            FileStream fs = new FileStream("test1.wav", FileMode.Open);
            byte[] fileBuffer = new byte[fs.Length];

            fs.Read(fileBuffer, 0, fileBuffer.Length);

            fs.Close();



            AudioManager manager = new AudioManager();
            manager.Init();
            byte []outbuffer=manager.TestNoiseBuffer(fileBuffer);
           

            FileStream fw = new FileStream("out1.wav", FileMode.Create);
            fw.Write(outbuffer, 0, outbuffer.Length);
            fw.Close();
            Console.WriteLine("转换完成");
           
            Console.ReadKey();
        }
    }



    public class AudioManager {
        //加载dll库,参数为dll库的名称,返回句柄
        [DllImport("kernel32")]
        public static extern IntPtr LoadLibrary(string lpFileName);
        //通过句柄释放dll库
        [DllImport("Kernel32")]
        public static extern bool FreeLibrary(IntPtr handle);
        //根据函数名输出库函数,返回函数的指针
        [DllImport("Kernel32")]
        public static extern IntPtr GetProcAddress(IntPtr handle, String funcname);


        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        unsafe public delegate void TestBuffer_init_delegate();

        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        unsafe public delegate void TestNoise_Buffer_delegate(byte[] in_out_put);


        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        unsafe public delegate void TestBuffer_Destory_delegate();


        TestNoise_Buffer_delegate TestNoise_Buffer;
        TestBuffer_Destory_delegate TestBuffer_Destory;

        
        /// 
        /// 初始化操作
        /// 
        public void Init() {
            //加载c++对应的dll库
            IntPtr dll = LoadLibrary("SpeexWinProj.dll");


            IntPtr TestBuffer_init_func = GetProcAddress(dll, "TestBuffer_init");
            TestBuffer_init_delegate TestBuffer_init = (TestBuffer_init_delegate)Marshal.GetDelegateForFunctionPointer(TestBuffer_init_func, typeof(TestBuffer_init_delegate));

            IntPtr TestNoise_Buffer_func = GetProcAddress(dll, "TestNoise_Buffer");
            TestNoise_Buffer = (TestNoise_Buffer_delegate)Marshal.GetDelegateForFunctionPointer(TestNoise_Buffer_func, typeof(TestNoise_Buffer_delegate));


            IntPtr TestBuffer_Destory_func = GetProcAddress(dll, "TestBuffer_Destory");
           
            TestBuffer_Destory = (TestBuffer_Destory_delegate)Marshal.GetDelegateForFunctionPointer(TestBuffer_Destory_func, typeof(TestBuffer_Destory_delegate));

            TestBuffer_init();
        }
        
        /// 
        /// 音频降噪,处理字节数组
        /// 
        /// 输入的音频字节数组
        /// 处理完毕后的字节数组
        public byte[] TestNoiseBuffer(byte []inputBuffer){
            byte[] outbuffer = new byte[inputBuffer.Length];

            //前44个字节是头文件,不能做降噪处理,不然出现无法打开的情况
            for (int i = 0; i < 44; i++)
            {
                outbuffer[i] = inputBuffer[i];
            }
            //采用速率
            int sampleRate = 1024;
            //每次处理的字节数组,每次处理1024个字节
            byte[] input_out = new byte[sampleRate];


            for (int i = 44; i < inputBuffer.Length - sampleRate; i = i + sampleRate)
            {
                //每次获取1024个字节
                for (int j = 0; j < sampleRate; j++)
                {

                    input_out[j] = inputBuffer[i + j];
                }
                //对1024个字节进行降噪操作
                TestNoise_Buffer(input_out);
                //把降噪后的1024个字节写入输出数组中
                for (int j = 0; j < sampleRate; j++)
                {
                    outbuffer[i + j] = input_out[j];
                }

            }
            //释放资源
            TestBuffer_Destory();
            return outbuffer;
        }
    }
}

然后运行效果图如下图:

最后会在C#项目的Debug目录下生成降噪后的音频文件out1.wav,当然输入的test1.wav也没有噪声,因为有噪声的wav文件太难找了,就找了一个没有噪声的意思意思一下

你可能感兴趣的:(音频处理,C#编程)