c – 以编程方式增加麦克风增益

c – 以编程方式增加麦克风增益,第1张

概述我正在尝试为VOIP场景增加麦克风增益. 我正在使用PortAudio来获取输入流(具有类型为paFloat32的样本),我将这些值乘以浮点数,然后将结果流传递给输出设备. 注意:我将它传递给虚拟输出设备,该设备自动重定向到虚拟输入设备(程序:VB-Cable),VOIP应用程序可以将其用作应用了增益的麦克风输入. 我想知道是否有更好的方法来增加信号的增益,从而更好地保持质量. 我已经读过,最好 我正在尝试为VOIP场景增加麦克风的增益.
我正在使用PortAudio来获取输入流(具有类型为pafloat32的样本),我将这些值乘以浮点数,然后将结果流传递给输出设备.
注意:我将它传递给虚拟输出设备,该设备自动重定向到虚拟输入设备(程序:VB-Cable),VOIP应用程序可以将其用作应用了增益的麦克风输入.

我想知道是否有更好的方法来增加信号的增益,从而更好地保持质量.

我已经读过,最好先执行这样的增益计算,首先将输入转换为更高精度的格式,以这种格式执行增益乘法,应用裁剪,然后再回到原始格式.
我不知道如何使用PortAudio的pafloat32类型,我已将我的尝试包括在源代码中.当我启用它时,即使增益设置为1,也会出现明显的噪声问题.

依赖关系:tinycon,PortAudio

编译:g main.cpp tinycon.cpp -o main -L./ -lcygportaudio-2 -lrt -lm -pthread -std = c 11

码:

#include "portaudio.h"#include <iostream>#include <chrono>#include <thread>#include <mutex>#include "tinycon.h"#define SAMPLE_RATE       (44100)#define FRAMES_PER_BUFFER   (441)#define DITHER_FLAG           (1)#define PA_SAMPLE_TYPE  pafloat32#define SAMPLE_SIZE (4)#define SAMPLE_SILENCE  (0)#define PRINTF_S_FORMAT "%f"/*******************************************************************/double multiplIEr = 1.0;double multiplIErStep = 0.1;int main(int argc,char **argv);int xrun(PaStream *stream,int err,char* sampleBlock);voID error1(PaStream *stream,char* sampleBlock);voID error2(PaStream *stream,int err);voID ListDevices();// Use tinycon and a second thread for non blocking inputclass tcon : public tinyConsole{public:        tcon (std::string s): tinyConsole(s) {;}        int hotkeys(char c)        {                if (c == 's') {                        if (multiplIEr >= (0+multiplIErStep)) {                                multiplIEr -= multiplIErStep;                        }                        printf( "MultiplIEr: %f\n",multiplIEr );                        return 1;                }                if (c == 'w') {                        multiplIEr += multiplIErStep;                        printf( "MultiplIEr: %f\n",multiplIEr );                        return 1;                }                return 0;        }};int inputThread() {        tcon tc (std::string(""));        tc.run();}voID ListDevices() {        int i,numDevices,defaultdisplayed;        const PaDeviceInfo *deviceInfo;        Pa_Initialize();        numDevices = Pa_GetDeviceCount();        printf( "Number of devices = %d\n",numDevices );        int isinputDevice = 0;        for( i=0; i<numDevices; i++ )        {                deviceInfo = Pa_GetDeviceInfo( i );                int isinputDevice = (deviceInfo->maxinputChannels > 0);                printf( "%sdeviceid: %d,name: %s\n",(isinputDevice ? "input" : "Output"),i,deviceInfo->name);        }        fprintf (stderr,"Press any key to close\n");        getch();}int main (int argc,char **argv){        int c;        int inputdeviceid = -1;        int outputdeviceid = -1;        opterr = 0;        const char* helpMessage =                "-h : show this help message\n"                "-i <int> : select the input DEVICE by ID\n"                "-o <int> : select the OUPUT DEVICE by ID\n"                "-m <double> : SIGNAL MulTIPLIER\n"                "-s <double> : SIGNAL MulTIPLIER STEP (press w or s while console focused to go up and down by this ammount.\n"                "-d : List devices\n";        while ((c = getopt (argc,argv,"i:o:l:m:s:hd")) != -1) {                switch (c) {                        case 'i':                                inputdeviceid = atoi(optarg);                                break;                        case 'o':                                outputdeviceid = atoi(optarg);                                break;                        case 'm':                                multiplIEr = atof(optarg);                                break;                        case 's':                                multiplIErStep = atof(optarg);                                break;                        case 'd':                                ListDevices();                                return 0;                        case '?':                                if (isprint (optopt))                                        fprintf (stderr,"UnkNown option `-%c'.\n",optopt);                                else                                        fprintf (stderr,"UnkNown option character `\x%x'.\n",optopt);                        case 'h':                                fprintf (stderr,helpMessage);                                fprintf (stderr,"Press any key to close\n");                                getch();                                return 1;                        default:                        abort ();                }        }        // Start non blocking input thread        std::thread nonBlockinginputThread(inputThread);    PaStreamParameters inputParameters,outputParameters;    PaStream *stream = NulL;    PaError err;    const PaDeviceInfo* inputInfo;    const PaDeviceInfo* outputInfo;    char *sampleBlock = NulL;    int i;    int numBytes;    int numChannels;    err = Pa_Initialize();    if( err != paNoError ) error2(stream,err);    inputParameters.device = (inputdeviceid == -1) ? Pa_GetDefaultinputDevice() : inputdeviceid; /* default input device */    inputInfo = Pa_GetDeviceInfo( inputParameters.device );    outputParameters.device = (outputdeviceid == -1) ? Pa_GetDefaultOutputDevice() : outputdeviceid; /* default output device */    outputInfo = Pa_GetDeviceInfo( outputParameters.device );        numChannels = inputInfo->maxinputChannels < outputInfo->maxOutputChannels                ? inputInfo->maxinputChannels : outputInfo->maxOutputChannels;    inputParameters.channelCount = numChannels;    inputParameters.sampleFormat = PA_SAMPLE_TYPE;    inputParameters.suggestedLatency = inputInfo->defaultHighinputLatency ;    inputParameters.hostAPISpecificStreamInfo = NulL;    printf( "input device # %d.\n",inputParameters.device );    printf( "    name: %s\n",inputInfo->name );        outputParameters.channelCount = numChannels;        outputParameters.sampleFormat = PA_SAMPLE_TYPE;        outputParameters.suggestedLatency = outputInfo->defaultHighOutputLatency;        outputParameters.hostAPISpecificStreamInfo = NulL;    printf( "Output device # %d.\n",outputParameters.device );    printf( "    name: %s\n",outputInfo->name );    /* -- setup -- */    err = Pa_OpenStream(              &stream,&inputParameters,&outputParameters,SAMPLE_RATE,FRAMES_PER_BUFFER,paClipOff,/* we won't output out of range samples so don't bother clipPing them */              NulL,/* no callback,use blocking API */              NulL ); /* no callback,so no callback userData */    if( err != paNoError ) error2(stream,err);    numBytes = FRAMES_PER_BUFFER * numChannels * SAMPLE_SIZE ;    sampleBlock = (char *) malloc( numBytes );    if( sampleBlock == NulL )    {        printf("Could not allocate record array.\n");        error1(stream,sampleBlock);    }    err = Pa_StartStream( stream );    if( err != paNoError ) error1(stream,sampleBlock);        while (1) {        // You may get underruns or overruns if the output is not primed by PortAudio.        err = Pa_ReadStream( stream,sampleBlock,FRAMES_PER_BUFFER );        if( err ) xrun(stream,err,sampleBlock);                int blockIndex;                float* sampleBlockShort = (float*)sampleBlock;                for (blockIndex = 0; blockIndex < FRAMES_PER_BUFFER; blockIndex++) {                        /*                        double dSample = (double)sampleBlockShort[blockIndex];                        dSample *= multiplIEr;                        if (dSample > 32767.0) dSample = 32767.0;                        if (dSample < -32768.0) dSample = -32768.0;                        sampleBlockShort[blockIndex] = (short)dSample;                        */                        sampleBlockShort[blockIndex] *= multiplIEr;                }                err = Pa_WriteStream( stream,FRAMES_PER_BUFFER );                if( err ) xrun(stream,sampleBlock);    }    printf("Wire off.\n"); fflush(stdout);    err = Pa_StopStream( stream );    if( err != paNoError ) error1(stream,sampleBlock);    free( sampleBlock );    Pa_Terminate();    return 0;}int xrun(PaStream *stream,char* sampleBlock) {    printf("err = %d\n",err); fflush(stdout);    if( stream ) {       Pa_AbortStream( stream );       Pa_CloseStream( stream );    }    free( sampleBlock );    Pa_Terminate();    if( err & painputOverflow )       fprintf( stderr,"input Overflow.\n" );    if( err & paOutputUnderflow )       fprintf( stderr,"Output Underflow.\n" );    return -2;}voID error1(PaStream *stream,char* sampleBlock) {    free( sampleBlock );    exit(-1);}voID error2(PaStream *stream,int err) {    if( stream ) {       Pa_AbortStream( stream );       Pa_CloseStream( stream );    }    Pa_Terminate();    fprintf( stderr,"An error occured while using the portaudio stream\n" );    fprintf( stderr,"Error number: %d\n",err );    fprintf( stderr,"Error message: %s\n",Pa_GetErrorText( err ) );    exit(-1);}
解决方法 我发现你也可以使用webrtc库.它具有噪音抑制功能,非常方便.我不明白compress_gain_db和target_level_dbfs实际上做了什么,但将它们设置为最高值似乎应用了最大的收益.按照@alexander的建议在int16中工作解决了我的自定义解决方案的许多问题,并修复了循环以覆盖整个缓冲区. webrtc的解决方案和我自己的解决方案都可以通过以下示例代码实时播放.

代码示例包括在下面.

$./main.exe -h-h : show this help message-i <int> : select the input DEVICE by ID-o <int> : select the OUPUT DEVICE by ID-c <int [0,90]> : compression_gain_db-t <int [0,31]> : target_level_dbfs-g <0 or 1> : toggle webrtc gain control on and off (1 by default)-k <0 or 1> : toggle custom gain control on and off (1 by default)-f <int [1,maxInt]> : customGainControlFactor-q <int [0,3]> : webrtc noise supression level,high is more suppression-e <0 or 1> : toggle webrtc noise suppression on and off (1 by default)-d : List devicesReal time controls:compression_gain_db            UP_KEY='a' DOWN_KEY='s'target_dbfs_level              UP_KEY='d' DOWN_KEY='f'webrtcGainControlEnabled                           TOGGLE_KEY='g'webrtcNoiseSuppressionLevel    UP_KEY='q' DOWN_KEY='w'webrtcNoiseSuppressionEnabled                      TOGGLE_KEY='e'customGainFactor               UP_KEY='h' DOWN_KEY='j'customGainFactorEnabled                            TOGGLE_KEY='k'Press any key to close

依赖关系:tinycon,PortAudio,libwebrtc-audio-processing-devel

注意:我正在使用cygwin,如果你遇到libwebrtc问题,请参阅here

编译:g main.cpp tinycon.cpp -o main -L./ -lcygportaudio-2 -lrt -lm -pthread -I /usr/include / webrtc_audio_processing / -DWEBRTC_WIN -DWEBRTC

main.cpp中

#include "portaudio.h"#include <iostream>#include <limits>#include <chrono>#include <thread>#include <mutex>#include "tinycon.h"#include "webrtc/modules/audio_processing/include/audio_processing.h"#include "webrtc/modules/interface/module_common_types.h"#include "webrtc/system_wrappers/include/trace.h"using webrtc::AudioProcessing;using webrtc::AudioFrame;using webrtc::GainControl;using webrtc::NoiseSuppression;#define SAMPLE_RATE       (32000)#define FRAMES_PER_BUFFER   (320)#define DITHER_FLAG           (0)#define PA_SAMPLE_TYPE paInt16#define SAMPLE_SIZE (2)#define SAMPLE_SILENCE  (0)#define PRINTF_S_FORMAT "%d"/*******************************************************************/int customGainFactor = 1;int customGainFactorStep = 1;bool customGainControlEnabled = true;int compression_gain_db = 1;int compression_gain_dbStep = 1;int target_level_dbfs = 1;int target_level_dbfsstep = 1;bool webrtcGainControlEnabled = true;bool webrtcNoiseSuppressionEnabled = true;int webrtcNoiseSuppressionLevel = 1;int main(int argc,int err);voID ListDevices();webrtc::NoiseSuppression::Level webrtcNoiseSuppressionLevelToEnum(int level);// Use tinycon and a second thread for non blocking inputclass tcon : public tinyConsole{public:        tcon (std::string s): tinyConsole(s) {;}        int hotkeys(char c)        {                if (c == 'a') {                        if (compression_gain_db >= (0+compression_gain_dbStep)) {                                compression_gain_db -= compression_gain_dbStep;                        }                        printf( "Compression_gain_db: %d\n",compression_gain_db );                        return 1;                }                if (c == 's') {                        if (compression_gain_db <= (90-compression_gain_dbStep)) {                                compression_gain_db += compression_gain_dbStep;                        }                        printf( "Compression_gain_db: %d\n",compression_gain_db );                        return 1;                }                if (c == 'd') {                        if (target_level_dbfs >= (0+target_level_dbfsstep)) {                                target_level_dbfs -= target_level_dbfsstep;                        }                        printf( "target_level_dbfs: %d\n",target_level_dbfs );                        return 1;                }                if (c == 'f') {                        if (target_level_dbfs <= (31-target_level_dbfsstep)) {                                target_level_dbfs += target_level_dbfsstep;                        }                        printf( "target_level_dbfs: %d\n",target_level_dbfs );                        return 1;                }                if (c == 'g') {                        webrtcGainControlEnabled = !webrtcGainControlEnabled;                        printf("webrtcGainControlEnabled: %s\n",(webrtcGainControlEnabled) ? "true" : "false");                        return 1;                }                if (c == 'h') {                        if (customGainFactor >= (1+customGainFactorStep)) {                                customGainFactor -= customGainFactorStep;                        }                        printf( "customGainFactor: %d\n",customGainFactor );                        return 1;                }                if (c == 'j') {                        customGainFactor += customGainFactorStep;                        printf( "customGainFactor: %d\n",customGainFactor );                        return 1;                }                if (c == 'k') {                        customGainControlEnabled = !customGainControlEnabled;                        printf("customGainControlEnabled: %s\n",(customGainControlEnabled) ? "true" : "false");                        return 1;                }                if (c == 'q') {                        if (webrtcNoiseSuppressionLevel <= (3-1)) {                                webrtcNoiseSuppressionLevel += 1;                        }                        printf( "webrtcNoiseSuppressionLevel: %d\n",webrtcNoiseSuppressionLevel );                        return 1;                }                if (c == 'w') {                        if (webrtcNoiseSuppressionLevel >= (0+1)) {                                webrtcNoiseSuppressionLevel -= 1;                        }                        printf( "webrtcNoiseSuppressionLevel: %d\n",webrtcNoiseSuppressionLevel );                        return 1;                }                if (c == 'e') {                        webrtcNoiseSuppressionEnabled = !webrtcNoiseSuppressionEnabled;                        printf("webrtcNoiseSuppressionEnabled: %s\n",(webrtcNoiseSuppressionEnabled) ? "true" : "false");                        return 1;                }                return 0;        }};int inputThread() {        tcon tc (std::string(""));        tc.run();}voID ListDevices() {        int i,char **argv){        int c;        int inputdeviceid = -1;        int outputdeviceid = -1;        opterr = 0;        const char* helpMessage =                "-h : show this help message\n"                "-i <int> : select the input DEVICE by ID\n"                "-o <int> : select the OUPUT DEVICE by ID\n"                "-c <int [0,90]> : compression_gain_db\n"                "-t <int [0,31]> : target_level_dbfs\n"                "-g <0 or 1> : toggle webrtc gain control on and off (1 by default)\n"                "-k <0 or 1> : toggle custom gain control on and off (1 by default)\n"                "-f <int [1,maxInt]> : customGainControlFactor\n"                "-q <int [0,5]> : webrtc noise supression level,high is more suppression\n"                "-e <0 or 1> : toggle webrtc noise suppression on and off (1 by default)\n"                "-d : List devices\n"                "\n"                "Real time controls:\n"                "compression_gain_db            UP_KEY='a' DOWN_KEY='s'\n"                "target_dbfs_level              UP_KEY='d' DOWN_KEY='f'\n"                "webrtcGainControlEnabled                           TOGGLE_KEY='g'\n"                "webrtcNoiseSuppressionLevel    UP_KEY='q' DOWN_KEY='w'\n"                "webrtcNoiseSuppressionEnabled                      TOGGLE_KEY='e'\n"                "customGainFactor               UP_KEY='h' DOWN_KEY='j'\n"                "customGainFactorEnabled                            TOGGLE_KEY='k'\n";        while ((c = getopt (argc,"i:o:c:t:g:k:f:w:q:hd")) != -1) {                switch (c) {                        case 'i':                                inputdeviceid = atoi(optarg);                                break;                        case 'o':                                outputdeviceid = atoi(optarg);                                break;                        case 'c':                                compression_gain_db = atoi(optarg);                                break;                        case 't':                                target_level_dbfs = atoi(optarg);                                break;                        case 'g':                                webrtcGainControlEnabled = (atoi(optarg) == 1) ? true : false;                                break;                        case 'f':                                customGainFactor = atoi(optarg);                                break;                        case 'k':                                customGainControlEnabled = (atoi(optarg) == 1) ? true : false;                                break;                        case 'w':                                webrtcNoiseSuppressionLevel = atoi(optarg);                                break;                        case 'e':                                webrtcNoiseSuppressionEnabled = (atoi(optarg) == 1) ? true : false;                                break;                        case 'd':                                ListDevices();                                return 0;                        case '?':                                if (isprint (optopt))                                        fprintf (stderr,sampleBlock);    }        // Configure webrtc::audioprocessing        int webrtcErr;        AudioProcessing* apm = AudioProcessing::Create();        apm->high_pass_filter()->Enable(true);        apm->noise_suppression()->set_level(webrtcNoiseSuppressionLevelToEnum(webrtcNoiseSuppressionLevel));        apm->noise_suppression()->Enable(webrtcNoiseSuppressionEnabled);        apm->gain_control()->set_mode(apm->gain_control()->kFixedDigital);        apm->gain_control()->set_compression_gain_db(compression_gain_db);        apm->gain_control()->set_target_level_dbfs(target_level_dbfs);        apm->gain_control()->Enable(webrtcGainControlEnabled);    err = Pa_StartStream( stream );    if( err != paNoError ) error1(stream,sampleBlock);        while (1) {        // You may get underruns or overruns if the output is not primed by PortAudio.        err = Pa_ReadStream( stream,sampleBlock);                // Run custom gain solution                if (customGainControlEnabled) {                        int blockIndex;                        short* sampleBlockShort = (short*)sampleBlock;                        for (blockIndex = 0; blockIndex < FRAMES_PER_BUFFER*numChannels; blockIndex++) {                                        int iSample = (int)sampleBlockShort[blockIndex];                                        iSample *= customGainFactor;                                        if (iSample > std::numeric_limits<short>::max())                                        iSample =                                                  (iSample > std::numeric_limits<short>::max()) ? std::numeric_limits<short>::max()                                                : (iSample < std::numeric_limits<short>::min()) ? std::numeric_limits<short>::min()                                                : iSample;                                        sampleBlockShort[blockIndex] = (short)iSample;                        }                }                // Apply webrtc gain and noise suppression                apm->noise_suppression()->set_level(webrtcNoiseSuppressionLevelToEnum(webrtcNoiseSuppressionLevel));                apm->noise_suppression()->Enable(webrtcNoiseSuppressionEnabled);                apm->gain_control()->set_compression_gain_db(compression_gain_db);                apm->gain_control()->set_target_level_dbfs(target_level_dbfs);                apm->gain_control()->Enable(webrtcGainControlEnabled);                webrtc::AudioFrame frame;                frame.num_channels_ = numChannels;                frame.sample_rate_hz_ = SAMPLE_RATE;                frame.samples_per_channel_ = FRAMES_PER_BUFFER;                memcpy(frame.data_,numBytes);                if ((webrtcErr = apm->Processstream(&frame)) < 0) {                        printf("Error Code: %d\n",webrtcErr); fflush(stdout);                        return -1;                }                memcpy(sampleBlock,frame.data_,numBytes);                err = Pa_WriteStream( stream,Pa_GetErrorText( err ) );    exit(-1);}webrtc::NoiseSuppression::Level webrtcNoiseSuppressionLevelToEnum(int level) {        switch (level) {                case 0 : return webrtc::NoiseSuppression::Level::kLow;                case 1 : return webrtc::NoiseSuppression::Level::kModerate;                case 2 : return webrtc::NoiseSuppression::Level::kHigh;                case 3 : return webrtc::NoiseSuppression::Level::kVeryHigh;        }}
总结

以上是内存溢出为你收集整理的c – 以编程方式增加麦克风增益全部内容,希望文章能够帮你解决c – 以编程方式增加麦克风增益所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/1225022.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存