FMOD变声如何捕获并存储处理音效之后的数据
https://www.fmod.com/download 通过邮箱注册账号之后可以获取下载资源,FMOD Engine,.a 文件中带有L后缀的支持日志输出
类似AVAudioEngine的功能,一个Engine可以将N个connect连接(串联和并联)在一起,这样来实现多个输入源,多层处理效果的混合输出。实现这个所需功能也是通过这样的方案来实现的。也就是说,在使用的音效和目标输出之间增加一个自己的自定义音效处理,在实现这个音效处理时,将最终BUFFER数据设置成为上一音效处理效果输入的BUFFER数据,并且存储这些数据写入文件。
1.绑定两个DSP
system->playSound(sound, 0, false, &channel); FMOD::DSP *mydsp = configuration(system); int result = system->getMasterChannelGroup(&mastergroup); //mastergroup应该类似MixOutNode //dsp需要的音效处理效果 //mydsp自定义的音效处理 ERRCHECK(result); //分别绑定,注意先后顺序 mastergroup->addDSP(0, dsp); result = mastergroup->addDSP(0, mydsp); ERRCHECK(result);
2.在自定义的音效效果处理函数中,截取数据并且将上一步处理结果设定为输出
/* dspdesc.read = myDSPCallback; system->createDSP(&dspdesc, &mydsp); */ FMOD_RESULT F_CALLBACK myDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) { printf("+++++++++"); mydsp_data_t *data = (mydsp_data_t *)dsp_state->plugindata; /* This loop assumes inchannels = outchannels, which it will be if the DSP is created with '0' as the number of channels in FMOD_DSP_DESCRIPTION. Specifying an actual channel count will mean you have to take care of any number of channels coming in, but outputting the number of channels specified. Generally it is best to keep the channel count at 0 for maximum compatibility. */ for (unsigned int samp = 0; samp < length; samp++) { /* Feel free to unroll this. */ for (int chan = 0; chan < *outchannels; chan++) { /* This DSP filter just halves the volume! Input is modified, and sent to output. 将输入赋予输出,并且保存这个输入结果(上一音效处理过后的PCM数据) */ data->buffer[(samp * *outchannels) + chan] = outbuffer[(samp * inchannels) + chan] = inbuffer[(samp * inchannels) + chan] * data->volume_linear; } } printf("--->%u\n",length); data->channels = inchannels; //这里有个插曲,原来长度设定为length,结果PCM数据播出一直是断断续续的 fwrite(data->buffer, sizeof(float), length**outchannels, saveFile); return FMOD_OK; }
3.注意点(采样率和输出通道数)
经设定为
system->setDSPBufferSize(44100, 2);
但是测定为获取下来的两项指标为:44100和1(设定其它数据无法正常获取,出现很大的杂音等,急需熟手指导)
3ps:实际效果是指标可能为22050和2,也可能设定和输出并没有关系只是读取的要求
end:以上就是成功实现该项功能的最主要说明,欢迎大家一起探讨
// // ViewController.m // FMOD // // Created by Blockdance_M11Pro on 2023/6/15. // #import "ViewController.h" #include "fmod.h" #include "fmod_common.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. testFunction(); } void testFunction() { // 创建 FMOD 系统对象 FMOD_SYSTEM* system = nullptr; FMOD_System_Create(&system, FMOD_VERSION); // FMOD_System_SetOutput(system, FMOD_OUTPUTTYPE_WAVWRITER); FMOD_System_Init(system, 32, FMOD_INIT_NORMAL | FMOD_INIT_PROFILE_ENABLE, (void *)"/Users/blockdance/Desktop/temp/result.wav"); // 创建声音对象 FMOD_SOUND* sound = nullptr; FMOD_System_CreateSound(system, "/Users/blockdance/Documents/Projects/FMOD/FMOD/singing.wav", FMOD_DEFAULT, nullptr, &sound); // 创建声道对象 FMOD_CHANNEL* channel = nullptr; FMOD_System_PlaySound(system, sound, nullptr, false, &channel); FMOD_CHANNELGROUP *channelgroup = nullptr; FMOD_System_GetMasterChannelGroup(system, &channelgroup); // 创建 DSP 对象并设置效果 FMOD_DSP* pitchDSP = nullptr; FMOD_System_CreateDSPByType(system, FMOD_DSP_TYPE_PITCHSHIFT, &pitchDSP); FMOD_DSP_SetParameterFloat(pitchDSP, FMOD_DSP_PITCHSHIFT_PITCH, 1.6f); // FMOD_DSP* pitchDSP = nullptr; // FMOD_System_CreateDSPByType(system, FMOD_DSP_TYPE_PITCHSHIFT, &pitchDSP); // FMOD_DSP_SetParameterFloat(pitchDSP, FMOD_DSP_PITCHSHIFT_PITCH, 0.8f); // // FMOD_DSP* pitchDSP = nullptr; // FMOD_System_CreateDSPByType(system, FMOD_DSP_TYPE_PITCHSHIFT, &pitchDSP); // FMOD_DSP_SetParameterFloat(pitchDSP, FMOD_DSP_PITCHSHIFT_PITCH, 0.8f); // // FMOD_DSP* pitchDSP = nullptr; // FMOD_System_CreateDSPByType(system, FMOD_DSP_TYPE_PITCHSHIFT, &pitchDSP); // FMOD_DSP_SetParameterFloat(pitchDSP, FMOD_DSP_PITCHSHIFT_PITCH, 0.8f); FMOD_DSP* customerDSP = nullptr; FMOD_DSP_DESCRIPTION customerDES = FMOD_DSP_DESCRIPTION(); customerDES.read = CUSTOMER_FMOD_DSP_READ_CALLBACK; customerDES.create = myDSPCreateCallback; FMOD_System_CreateDSP(system, &customerDES, &customerDSP); // 将 DSP 添加到声道中R FMOD_ChannelGroup_AddDSP(channelgroup, 0, pitchDSP); FMOD_ChannelGroup_AddDSP(channelgroup, 0, customerDSP); // 循环更新 FMOD 系统 while (true) { FMOD_System_Update(system); // 其他逻辑处理 FMOD_BOOL isPlaying = TRUE; FMOD_Channel_IsPlaying(channel, &isPlaying); if (isPlaying == 0) { break; } } // 释放资源 FMOD_Sound_Release(sound); FMOD_DSP_Release(pitchDSP); FMOD_System_Close(system); FMOD_System_Release(system); } typedef struct { float *buffer; float volume_linear; int length_samples; int channels; } mydsp_data_t; FMOD_RESULT CUSTOMER_FMOD_DSP_READ_CALLBACK(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) { mydsp_data_t *data = (mydsp_data_t *)dsp_state->plugindata; /* This loop assumes inchannels = outchannels, which it will be if the DSP is created with '0' as the number of channels in FMOD_DSP_DESCRIPTION. Specifying an actual channel count will mean you have to take care of any number of channels coming in, but outputting the number of channels specified. Generally it is best to keep the channel count at 0 for maximum compatibility. */ for (unsigned int samp = 0; samp < length; samp++) { /* Feel free to unroll this. */ for (int chan = 0; chan < *outchannels; chan++) { /* This DSP filter just halves the volume! Input is modified, and sent to output. */ data->buffer[(samp * *outchannels) + chan] = outbuffer[(samp * inchannels) + chan] = inbuffer[(samp * inchannels) + chan] * data->volume_linear; } } data->channels = inchannels; // //这里有个插曲,原来长度设定为length,结果PCM数据播出一直是断断续续的 // fwrite(data->buffer, sizeof(float), length**outchannels, saveFile); return FMOD_OK; } FMOD_RESULT F_CALLBACK myDSPCreateCallback(FMOD_DSP_STATE *dsp_state) { unsigned int blocksize; FMOD_RESULT result; result = dsp_state->functions->getblocksize(dsp_state, &blocksize); mydsp_data_t *data = (mydsp_data_t *)calloc(sizeof(mydsp_data_t), 1); if (!data) { return FMOD_ERR_MEMORY; } dsp_state->plugindata = data; data->volume_linear = 1.0f; data->length_samples = blocksize; data->buffer = (float *)malloc(blocksize * 8 * sizeof(float)); // *8 = maximum size allowing room for 7.1. Could ask dsp_state->functions->getspeakermode for the right speakermode to get real speaker count. if (!data->buffer) { return FMOD_ERR_MEMORY; } return FMOD_OK; } @end