我正在使用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 – 以编程方式增加麦克风增益所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)