FMOD_RESULT F_CALLBACK SystemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
{
    if (type == FMOD_SYSTEM_CALLBACK_ERROR)
    {
        FMOD_ERRORCALLBACK_INFO* errorInfo = (FMOD_ERRORCALLBACK_INFO*)commanddata1;
        RunData* data = (RunData*)userdata;
        Common_Mutex_Enter(&data->criticalSection);
        char buffer[512];
        Common_snprintf(buffer, 512, "%s(%s)[%d]", errorInfo->functionname, errorInfo->functionparams, errorInfo->result);
        buffer[511] = '\0';
        data->errorStrings.push_back(buffer);
        Common_Mutex_Leave(&data->criticalSection);
    }
    return FMOD_OK;
}
void drawDSPParameters(ParameterViewerState *state)
{
    FMOD_RESULT              result;
    FMOD_DSP_PARAMETER_DESC *paramdesc;
    char                     pluginname[256];

    Common_Draw("Press %s to scroll down", Common_BtnStr(BTN_DOWN));
    Common_Draw("Press %s to scroll up", Common_BtnStr(BTN_UP));
    Common_Draw("Press %s to return to the plug-in list", Common_BtnStr(BTN_LEFT));
    Common_Draw("");
    
    result = state->dsp->getInfo(pluginname, 0, 0, 0, 0);
    ERRCHECK(result);

    Common_Draw("%s Parameters:", pluginname);
    Common_Draw("--------------------------------------------------");

    for (int i = state->scroll; i < state->numparams; i++)
    {
        result = state->dsp->getParameterInfo(i, &paramdesc);
        ERRCHECK(result);
        switch (paramdesc->type)
        {
            case FMOD_DSP_PARAMETER_TYPE_FLOAT:
            {
                char *units = paramdesc->label;
                Common_Draw("%2d: %-15s [%g, %g] (%.2f%s)", i, paramdesc->name, paramdesc->floatdesc.min, paramdesc->floatdesc.max, paramdesc->floatdesc.defaultval, units);
                break;
            }

            case FMOD_DSP_PARAMETER_TYPE_INT:
            {
                if (paramdesc->intdesc.valuenames)
                {
                    int lengthremaining = 1024;
                    char enums[1024];
                    char *s = enums;
                    for (int j = 0; j < paramdesc->intdesc.max - paramdesc->intdesc.min; ++j)
                    {
                        int len =  Common_snprintf(s, lengthremaining, "%s, ", paramdesc->intdesc.valuenames[j]);
                        if (!len)
                        {
                            break;
                        }
                        s += len;
                        lengthremaining -= len;
                    }
                    if (lengthremaining)
                    {
                        Common_snprintf(s, lengthremaining, "%s", paramdesc->intdesc.valuenames[paramdesc->intdesc.max - paramdesc->intdesc.min]);
                    }
                    Common_Draw("%2d: %-15s [%s] (%s)", i, paramdesc->name, enums, paramdesc->intdesc.valuenames[paramdesc->intdesc.defaultval - paramdesc->intdesc.min]);
                }
                else
                {
                    char *units = paramdesc->label;
                    Common_Draw("%2d: %-15s [%d, %d] (%d%s)", i, paramdesc->name, paramdesc->intdesc.min, paramdesc->intdesc.max, paramdesc->intdesc.defaultval, units);
                }
                break;
            }

            case FMOD_DSP_PARAMETER_TYPE_BOOL:
            {
                if (paramdesc->booldesc.valuenames)
                {
                    Common_Draw("%2d: %-15s [%s, %s] (%s)", i, paramdesc->name, paramdesc->booldesc.valuenames[0], paramdesc->booldesc.valuenames[1], paramdesc->booldesc.valuenames[paramdesc->booldesc.defaultval ? 1 : 0]);
                }
                else
                {
                    Common_Draw("%2d: %-15s [On, Off] (%s)", i, paramdesc->name, paramdesc->booldesc.defaultval ? "On" : "Off");
                }
                break;
            }

            case FMOD_DSP_PARAMETER_TYPE_DATA:
            {
                Common_Draw("%2d: %-15s (Data type: %d)", i, paramdesc->name, paramdesc->datadesc.datatype);
                break;
            }
        }
    }
}