使用 VST 插件失真的音频

Posted

技术标签:

【中文标题】使用 VST 插件失真的音频【英文标题】:Audio distorted with VST plugin 【发布时间】:2015-11-08 14:59:52 【问题描述】:

我必须插入一个预先存在的软件,管理 ASIO 音频流,一个简单的 VST 主机。尽管缺少一些文档,我还是设法做到了,但是一旦我加载了插件,我就会得到一个严重失真的音频信号。

我使用的 VST 可以正常工作(与其他 VST 主机一起使用),所以它可能是我制作的代码中的某种错误,但是当我从插件中禁用“PROCESS”时(我的流通过插件,它根本没有得到处理)它会在我发送时返回,没有任何噪音或失真。

我稍微担心的一件事是,当插件需要一些浮点缓冲区时,ASIO 驱动程序填充 __int32 缓冲区时使用的数据类型。

这真的很令人沮丧,因为我检查了无数次我的代码,而且看起来还不错。

这是我正在使用的类的代码;请注意,有些数字是临时硬编码的,以帮助调试。

VSTPlugIn::VSTPlugIn(const char* fullDirectoryName, const char* ID)
    : plugin(NULL)
    , blocksize(128)        // TODO
    , sampleRate(44100.0F)  // TODO
    , hostID(ID)

    this->LoadPlugin(fullDirectoryName);
    this->ConfigurePluginCallbacks();
    this->StartPlugin();

    out = new float*[2];

    for (int i = 0; i < 2; ++i)
    
        out[i] = new float[128];
        memset(out[i], 0, 128);
    


void VSTPlugIn::LoadPlugin(const char* path)

    HMODULE modulePtr = LoadLibrary(path);

    if(modulePtr == NULL)
    
        printf("Failed trying to load VST from '%s', error %d\n", path, GetLastError());
        plugin = NULL;
    

    // vst 2.4 export name
    vstPluginFuncPtr mainEntryPoint = (vstPluginFuncPtr)GetProcAddress(modulePtr, "VSTPluginMain");

    // if "VSTPluginMain" was not found, search for "main" (backwards compatibility mode)
    if(!mainEntryPoint)
    
        mainEntryPoint = (vstPluginFuncPtr)GetProcAddress(modulePtr, "main");
    

    // Instantiate the plugin
    plugin = mainEntryPoint(hostCallback);


void VSTPlugIn::ConfigurePluginCallbacks()

    // Check plugin's magic number
    // If incorrect, then the file either was not loaded properly, is not a
    // real VST plugin, or is otherwise corrupt.
    if(plugin->magic != kEffectMagic) 
    
        printf("Plugin's magic number is bad. Plugin will be discarded\n");
        plugin = NULL;
    

    // Create dispatcher handle
    this->dispatcher = (dispatcherFuncPtr)(plugin->dispatcher);

    // Set up plugin callback functions
    plugin->getParameter     = (getParameterFuncPtr)plugin->getParameter;
    plugin->processReplacing = (processFuncPtr)plugin->processReplacing;
    plugin->setParameter     = (setParameterFuncPtr)plugin->setParameter;


void VSTPlugIn::StartPlugin()

    // Set some default properties
    dispatcher(plugin, effOpen, 0, 0, NULL, 0);
    dispatcher(plugin, effSetSampleRate, 0, 0, NULL, sampleRate);
    dispatcher(plugin, effSetBlockSize, 0, blocksize, NULL, 0.0f);
    this->ResumePlugin();


void VSTPlugIn::ResumePlugin()

    dispatcher(plugin, effMainsChanged, 0, 1, NULL, 0.0f);


void VSTPlugIn::SuspendPlugin()

    dispatcher(plugin, effMainsChanged, 0, 0, NULL, 0.0f);


void VSTPlugIn::ProcessAudio(float** inputs, float** outputs, long numFrames)

    plugin->processReplacing(plugin, inputs, out, 128);
    memcpy(outputs, out, sizeof(float) * 128);

编辑:这是我用来连接我的软件与 VST 主机的代码

// Copying the outer buffer in the inner container
for(unsigned i = 0; i < bufferLenght; i++)

    float f;
    f = ((float) buff[i]) / (float) std::numeric_limits<int>::max()

    if( f > 1 ) f = 1;
    if( f < -1 ) f = -1; 

    samples[0][i] = f;


// DO JOB
for(auto it = inserts.begin(); it != inserts.end(); ++it)

    (*it)->ProcessAudio(samples, samples, bufferLenght);


// Copying the result back into the buffer
for(unsigned i = 0; i < bufferLenght; i++)

    float f = samples[0][i];
    int intval;
    f = f * std::numeric_limits<int>::max();
    if( f > std::numeric_limits<int>::max() ) f = std::numeric_limits<int>::max();
    if( f < std::numeric_limits<int>::min() ) f = std::numeric_limits<int>::min();
    intval = (int) f;

    buff[i] = intval;

其中“buff”定义为“__int32* buff”

【问题讨论】:

听起来像是 VST 浮动音频样本(-1.0,+1.0)和 Asio Int16 值之间的转换问题。 我添加了用于将数据传递到 VST 主机的代码。请注意,我使用的是 Int32 而不是 Int16 我看不到 int32 格式是否正确 - 音频驱动程序使用的格式(Asio 还是其他?)。这一切都取决于此。如果是这样,则您的转换已关闭。我确实看到了其他一些事情:例如,当您分配输出缓冲区时,您的 memset 需要大小为 sizeof(float) * 128 - 再往下看,您做得正确。为什么需要额外的输出缓冲区?为什么不让插件直接输出到'输出'。保存一个 memcpy (ProcessAudio)。 格式是 int32,因为 ASIO 向我返回了那种类型的数据。对于“临时缓冲区”,这是我进行的一项测试,以排除它与导致此问题的输入/输出缓冲区相同。我会删除它,但感谢您指出。不过我还是不知道出了什么问题…… 为什么 ProcessSamples 不考虑 numFrames 和硬编码 128? 【参考方案1】:

我猜当您调用f = std::numeric_limits&lt;int&gt;::max()(以及下面一行中相关的min() 案例)时,这可能会导致溢出。你试过f = std::numeric_limits&lt;int&gt;::max() - 1吗?

上面的代码片段与f = ((float) buff[i]) / (float) std::numeric_limits&lt;int&gt;::max() 相同...我还要在那里减去一个以避免以后可能发生的溢出。

【讨论】:

以上是关于使用 VST 插件失真的音频的主要内容,如果未能解决你的问题,请参考以下文章

从 JUCE 音频 VST 插件控制主机播放

带有 VST 效果插件的网络音频播放器?

将 VST 音频效果/插件应用于音频文件

如何使用命令行编译 VST 3 或音频单元?

iOS VST 音频插件支持

Compressor.VST.v1.1 1CD(音频压缩的 VST 插件)