0

I had to plug into a pre-existing software, managing ASIO audio streams, a simple VST host. Despite of lack of some documentation, I managed to do so however once I load the plugin I get a badly distorted audio signal back.

The VST I'm using works properly (with other VST Hosts) so it's probably some kind of bug in the code I made, however when I disable the "PROCESS" from the plugin (my stream goes through the plugin, it simply does not get processed) it gets back as I sent without any noise or distortion on it.

One thing I'm slightly concerned about is the type of the data used as the ASIO driver fills an __int32 buffer while the plugins wants some float buffer.

That's really depressing as I reviewed zillions of times my code and it seems to be fine.

Here is the code of the class I'm using; please note that some numbers are temporarily hard-coded to help debugging.

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);
}

EDIT: Here's the code I use to interface my sw with the VST Host

// 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;
}

where "buff" is defined as "__int32* buff"

Socket2104
  • 122
  • 2
  • 9
  • Sounds like a conversion problem between VST float audio samples (-1.0, +1.0) and Asio Int16 values. – obiwanjacobi Nov 08 '15 at 15:42
  • I added the code I use to pass my data to the VST Host. Please note that I'm using Int32 and not Int16 – Socket2104 Nov 08 '15 at 16:12
  • I cannot see if an int32 is the correct format - the format the audio driver uses (Asio or other?). It all depends on that. If that is of, your conversion is off. I do see some other things: like when you allocate the out buffers your memset needs to be of size sizeof(float) * 128 - further down you did it correctly. And why do you need the extra out buffer? Why not let the plugin output directly into 'outputs'. Saves a memcpy (ProcessAudio). – obiwanjacobi Nov 09 '15 at 06:21
  • Format is int32 because the ASIO return me that type of data. For the "temporary buffer", that was a test that I carried out to exclude it was the same in/out buffer to cause this issue. I will remove it, but thank you for pointing out. Still I can't know what's wrong though... – Socket2104 Nov 09 '15 at 10:26
  • 1
    Why is ProcessSamples disregarding numFrames and hard coding 128? – jaket Nov 09 '15 at 11:06
  • That could be a slight mistake, however numFrames == 128 at any time – Socket2104 Nov 09 '15 at 13:53
  • It all depends on how that Int32 buffer is filled - need more input on that. Is it interleaved or sequential? – obiwanjacobi Nov 09 '15 at 14:47
  • I actually don't know which one method it is used, I will check it out, however I'm reading the data from an existing infrastructure which wraps the ASIO drivers and exposes only the "mono" streams; the rest of the software is performing quite good so I think (I hope) I can rely on that underlying implementation – Socket2104 Nov 09 '15 at 16:34

1 Answers1

0

I'm guessing that when you call f = std::numeric_limits<int>::max() (and the related min() case on the line below), this might cause overflow. Have you tried f = std::numeric_limits<int>::max() - 1?

Same goes for the code snippit above with f = ((float) buff[i]) / (float) std::numeric_limits<int>::max()... I'd also subtract one there to avoid a potential overflow later on.

Nik Reiman
  • 39,067
  • 29
  • 104
  • 160