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的文件結構圖:

進入SpeexWinproj文件夾後

 

 

爲了減少代碼的複雜度和業務邏輯,什麼安全驗證的都沒有寫進去,只突出核心的部分。

 

找到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 <stdio.h>
#include <math.h>
#include <stdlib.h>

#include <string.h>
#include <assert.h> 
#include <windows.h>



#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;

        
        /// <summary>
        /// 初始化操作
        /// </summary>
        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();
        }
        
        /// <summary>
        /// 音頻降噪,處理字節數組
        /// </summary>
        /// <param name="inputBuffer">輸入的音頻字節數組</param>
        /// <returns>處理完畢後的字節數組</returns>
        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文件太難找了,就找了一個沒有噪聲的意思意思一下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章