// This was created from released VST2.x plugins, and is technically under the 2-clause BSD license.
// Depending on which country you are in, Steinberg can do fuck all about this. Notable countries for
// this are most members of the United States of America, the entirety of Europe, Japan, and Russia.
// Consult a lawyer if you don't know if clean room reverse engineering is allowed in your country.

// See README.md for all information.

// Known additional information:
// - Function call standard seems to be stdcall.
// - Everything is aligned to 8 bytes.

// VST Versioning:
// - Base-10, thus can't store many version numbers.
// - Always four components, with the major one being able to store the most numbers.
// - Format is A...ABCD, so 1.2.3.4 would turn into 1234.

// Modified 2024-02-05 by Marc Burns <marc@wavtool.com>
// - Downloaded this file from https://github.com/Xaymar/vst2sdk
// - Downloaded Kushview Element public edition from https://github.com/kushview/element/releases/tag/0.46.6
// - Loaded + analyzed Element in Ghidra 11.0.1
// - Added enums and structs until JUCE could compile, referencing Element's decompilation in Ghidra
//   against the JUCE source code to retrieve unknown names and enum values. Struct definitions were
//   reconstructed from access patterns in Element.

#pragma once
#ifndef VST2SDK_VST_H
#define VST2SDK_VST_H

#define VSTCALLBACK
#define VST_ALIGNMENT 8
#define VST_MAGICNUMBER 'VstP'

// Common VST buffer lengths:
// 8: OpCodes(GetLabel, GetName, GetValue)
#define VST_BUFFER_8 8
// 16:
#define VST_BUFFER_16 16
// 24: OpCodes?
#define VST_BUFFER_24 24
// 32: OpCodes(EffectName)
#define VST_BUFFER_32 32
#define VST_EFFECT_BUFFER_SIZE 32
// 64: OpCodes(ProductName, VendorName)
#define VST_BUFFER_64 64
#define VST_VENDOR_BUFFER_SIZE VST_BUFFER_64
#define VST_PRODUCT_BUFFER_SIZE VST_BUFFER_64
#define VST_NAME_BUFFER_SIZE VST_BUFFER_64
// 100:
#define VST_BUFFER_100 100

#define VST_MAX_CHANNELS 32 // Couldn't find any audio editing software which would attempt to add more channels.

#pragma pack(push, VST_ALIGNMENT)

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
|* Enumeration
|*/
enum VST_VERSION {
    VST_VERSION_1       = 0,    // Anything before 2.0, used by official plug-ins.
    VST_VERSION_1_0_0_0 = 1000, // 1.0, used by some third-party plug-ins.
    VST_VERSION_1_1_0_0 = 1100, // 1.1, used by some third-party plug-ins.
    VST_VERSION_2       = 2,    // 2.0, used by official plug-ins.
    VST_VERSION_2_0_0_0 = 2000, // 2.0, used by some third-party plug-ins.
    VST_VERSION_2_1_0_0 = 2100, // 2.1
    VST_VERSION_2_2_0_0 = 2200, // 2.2
    VST_VERSION_2_3_0_0 = 2300, // 2.3
    VST_VERSION_2_4_0_0 = 2400, // 2.4

    // Pad to force 32-bit number.
    _VST_VERSION_PAD = 0xFFFFFFFFul,
};

enum VstPlugCategory {
    kPlugCategUnknown = 0,
    kPlugCategEffect = 1,
    kPlugCategSynth = 2,
    kPlugCategAnalysis = 3,
    kPlugCategMastering = 4,
    kPlugCategSpacializer = 5,
    kPlugCategRoomFx = 6,
    kPlugSurroundFx = 7, // weird
    kPlugCategRestoration = 8,
    kPlugCategOfflineProcess = 9,
    kPlugCategShell = 10,
    kPlugCategGenerator = 11,
    kPlugCategMaxCount,

    // Pad to force 32-bit number.
    _VST_CATEGORY_PAD = 0xFFFFFFFFul,
};

enum VST_EFFECT_OPCODE {
    /* Create/Initialize the effect (if it has not been created already).
     *
     * @return Always 0.
     */
    VST_EFFECT_OPCODE_00         = 0x00,
    VST_EFFECT_OPCODE_CREATE     = 0x00,
    VST_EFFECT_OPCODE_INITIALIZE = 0x00,
    effOpen = 0x00,

    /* Destroy the effect (if there is any) and free its memory.
     *
     * This should destroy the actual object created by VST_ENTRYPOINT.
     *
     * @return Always 0.
     */
    VST_EFFECT_OPCODE_01      = 0x01,
    VST_EFFECT_OPCODE_DESTROY = 0x01,
    effClose = 0x01,

    /* Set Program
     *
     *
     */
    VST_EFFECT_OPCODE_02 = 0x02,
    effSetProgram = 0x02,

    /* Get Program
     *
     *
     */
    VST_EFFECT_OPCODE_03 = 0x03,
    effGetProgram = 0x03,

    /* Set Program Name
     *
     *
     */
    VST_EFFECT_OPCODE_04 = 0x04,
    effSetProgramName = 0x04,

    /* Get Program Name
     *
     * "Returns 0. If ptr is valid, sets the first byte of ptr to 0 then returns 0."
     */
    VST_EFFECT_OPCODE_05 = 0x05,
    effGetProgramName = 0x05,

    /* Get the value? label for the parameter.
     *
     * @param p_int1 Parameter index.
     * @param p_ptr 'char[8]'
     * @return 0 on success, 1 on failure.
     */
    VST_EFFECT_OPCODE_06             = 0x06,
    VST_EFFECT_OPCODE_PARAM_GETLABEL = 0x06,
    effGetParamLabel = 0x06,

    /* Get the string value for the parameter.
     *
     * @param p_int1 Parameter index.
     * @param p_ptr 'char[8]'
     * @return 0 on success, 1 on failure.
     */
    VST_EFFECT_OPCODE_07             = 0x07,
    VST_EFFECT_OPCODE_PARAM_GETVALUE = 0x07,
    effGetParamDisplay = 0x07,

    /* Get the name for the parameter.
     *
     * @param p_int1 Parameter index.
     * @param p_ptr 'char[8]'
     * @return 0 on success, 1 on failure.
     */
    VST_EFFECT_OPCODE_08            = 0x08,
    VST_EFFECT_OPCODE_PARAM_GETNAME = 0x08,
    effGetParamName = 0x08,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_09 = 0x09,

    /* Set the new sample rate for the plugin to use.
     *
     * @param p_float New sample rate as a float (double on 64-bit because register upgrades).
     */
    VST_EFFECT_OPCODE_0A              = 0x0A,
    VST_EFFECT_OPCODE_SETSAMPLERATE   = 0x0A,
    VST_EFFECT_OPCODE_SET_SAMPLE_RATE = 0x0A,
    effSetSampleRate = 0x0A,

    /* Sets the block size, which is the maximum number of samples passed into the effect via process calls.
     *
     * @param p_int2 The maximum number of samples to be passed in.
     */
    VST_EFFECT_OPCODE_0B             = 0x0B,
    VST_EFFECT_OPCODE_SETBLOCKSIZE   = 0x0B,
    VST_EFFECT_OPCODE_SET_BLOCK_SIZE = 0x0B,
    effSetBlockSize = 0x0B,

    /* Effect processing should be suspended/paused.
     *
     * Unclear if this is should result in a flush of buffers.
     *
     * @param p_int2 0 if the effect should suspend processing, 1 if it should resume.
     */
    VST_EFFECT_OPCODE_0C      = 0x0C,
    VST_EFFECT_OPCODE_SUSPEND = 0x0C,
    effMainsChanged = 0x0C,

    /* Retrieve the client rect size of the plugins window.
     * If no window has been created, returns the default rect.
     *
     * @param p_ptr Pointer of type 'struct vst_rect*'.
     * @return On success, returns 1 and updates p_ptr to the rect. On failure, returns 0.
     */
    VST_EFFECT_OPCODE_0D             = 0x0D,
    VST_EFFECT_OPCODE_WINDOW_GETRECT = 0x0D,
    effEditGetRect = 0x0D,

    /* Create the window for the plugin.
     *
     * @param p_ptr HWND of the parent window.
     * @return 0 on failure, or HWND on success.
     */
    VST_EFFECT_OPCODE_0E            = 0x0E,
    VST_EFFECT_OPCODE_WINDOW_CREATE = 0x0E,
    effEditOpen = 0x0E,

    /* Destroy the plugins window.
     *
     * @return Always 0.
     */
    VST_EFFECT_OPCODE_0F             = 0x0F,
    VST_EFFECT_OPCODE_WINDOW_DESTROY = 0x0F,
    effEditClose = 0x0F,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_10 = 0x10,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_11 = 0x11,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_12 = 0x12,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_13 = 0x13,
    effEditIdle = 0x13,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_14 = 0x14,
    effEditTop = 0x14,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_15 = 0x15,

    /* Always returns the FourCC 'NvEF' (0x4E764566).
     */
    VST_EFFECT_OPCODE_16 = 0x16,
    effIdentify = 0x16,

    /* Get Chunk
     *
     *
     */
    VST_EFFECT_OPCODE_17 = 0x17,
    effGetChunk = 0x17,

    /* Set Chunk
     *
     *
     */
    VST_EFFECT_OPCODE_18 = 0x18,
    effSetChunk = 0x18,

    // VST2.x starts here.

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_19 = 0x19,
    effProcessEvents = 0x19,

    /* Can the parameter be automated?
     *
     * @param p_int1 Index of the parameter.
     * @return 1 if the parameter can be automated, otherwise 0.
     */
    VST_EFFECT_OPCODE_1A                  = 0x1A,
    VST_EFFECT_OPCODE_PARAM_ISAUTOMATABLE = 0x1A,
    effCanBeAutomated = 0x1A, // confirmed w/ ghidra

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_1B = 0x1B,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_1C = 0x1C,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_1D = 0x1D, // See VST_EFFECT_OPCODE_05
    effGetProgramNameIndexed = 0x1D,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_1E = 0x1E,

    /* Input connected.
     *
     *
     */
    VST_EFFECT_OPCODE_1F = 0x1F,
    effConnectInput = 0x1F,

    /* Input disconnected.
     *
     *
     */
    VST_EFFECT_OPCODE_20 = 0x20,
    effConnectOutput = 0x20,

    /* Retrieve the name of the input channel at the given index.
     *
     * @param p_int1 Index of the input to get the name for.
     * @param p_ptr Pointer to a char* buffer able to hold at minimum 20 characters. Might need to be 32 even.
     * @return 0 on failure, 1 on success.
     */
    VST_EFFECT_OPCODE_21                   = 0x21,
    VST_EFFECT_OPCODE_INPUT_GETCHANNELNAME = 0x21,
    VST_EFFECT_OPCODE_INPUT_CHANNEL_NAME   = 0x21,
    effGetInputProperties = 0x21,

    /* Retrieve the name of the output channel at the given index.
     *
     * @param p_int1 Index of the output to get the name for.
     * @param p_ptr Pointer to a char* buffer able to hold at minimum 20 characters. Might need to be 32 even.
     * @return 0 on failure, 1 on success.
     */
    VST_EFFECT_OPCODE_22                    = 0x22,
    VST_EFFECT_OPCODE_OUTPUT_GETCHANNELNAME = 0x22,
    VST_EFFECT_OPCODE_OUTPUT_CHANNEL_NAME   = 0x22,
    effGetOutputProperties = 0x22,

    /* Retrieve category of this effect.
     *
     * @return The category that this effect is in, see VST_CATEGORY.
     */
    VST_EFFECT_OPCODE_23              = 0x23,
    VST_EFFECT_OPCODE_EFFECT_CATEGORY = 0x23,
    effGetPlugCategory = 0x23,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_24 = 0x24,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_25 = 0x25,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_26 = 0x26,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_27 = 0x27,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_28 = 0x28,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_29 = 0x29,

    /* Set the speaker arrangement
     *
     * @param p_int2 (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the input.
     * @param p_ptr (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the output.
     */
    VST_EFFECT_OPCODE_2A                      = 0x2A,
    VST_EFFECT_OPCODE_SET_SPEAKER_ARRANGEMENT = 0x2A,
    effSetSpeakerArrangement = 0x2A,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_2B = 0x2B,

    /* Enable/Disable bypassing the effect.
     *
     * @param p_int2 Zero if bypassing the effect is disabled, otherwise 1.
     */
    VST_EFFECT_OPCODE_2C     = 0x2C,
    VST_EFFECT_OPCODE_BYPASS = 0x2C,
    effSetBypass = 0x2C,

    /* Retrieve the effect name into the ptr buffer.
     *
     * @param p_ptr char[64] Buffer containing a zero-terminated effect information string. May be shorter than 64 bytes on older hosts.
     * @return Always 0, even on failure.
     */
    VST_EFFECT_OPCODE_2D          = 0x2D,
    VST_EFFECT_OPCODE_GETNAME     = 0x2D,
    VST_EFFECT_OPCODE_EFFECT_NAME = 0x2D,
    effGetEffectName = 0x2D,

    /* Translate an error code to a string.
     *
     * @param p_ptr char[256] Buffer that should contain a zero-terminated error string.
     */
    VST_EFFECT_OPCODE_2E              = 0x2E,
    VST_EFFECT_OPCODE_TRANSLATE_ERROR = 0x2E,

    /* Retrieve the vendor name into the ptr buffer.
     *
     * @param p_ptr char[64] Buffer containing a zero-terminated vendor information string. May be shorter than 64 bytes on older hosts.
     * @return Always 0, even on failure.
     */
    VST_EFFECT_OPCODE_2F          = 0x2F,
    VST_EFFECT_OPCODE_GETVENDOR   = 0x2F,
    VST_EFFECT_OPCODE_VENDOR_NAME = 0x2F,
    effGetVendorString = 0x2F,

    /* See VST_EFFECT_OPCODE_GETNAME
     *
     * Rarely used, if at all even supported. Not sure what the purpose of this is even.
     */
    VST_EFFECT_OPCODE_30           = 0x30,
    VST_EFFECT_OPCODE_GETNAME2     = 0x30,
    VST_EFFECT_OPCODE_PRODUCT_NAME = 0x30,
    effGetProductString = 0x30,

    /* Retrieve the vendor version in return value.
     *
     * @return Version.
     */
    VST_EFFECT_OPCODE_31               = 0x31,
    VST_EFFECT_OPCODE_GETVENDORVERSION = 0x31,
    VST_EFFECT_OPCODE_VENDOR_VERSION   = 0x31,
    effGetVendorVersion = 0x31,

    /* User defined OP Code, for custom interaction.
     *
     */
    VST_EFFECT_OPCODE_32     = 0x32,
    VST_EFFECT_OPCODE_CUSTOM = 0x32,
    effVendorSpecific = 0x32,

    /* Test for support of a specific named feature.
     *
     * @param p_ptr Pointer to a zero-terminated buffer containing the feature name.
     * @return Non-zero if the feature is supported, otherwise 0.
     */
    VST_EFFECT_OPCODE_33       = 0x33,
    VST_EFFECT_OPCODE_SUPPORTS = 0x33,
    effCanDo = 0x33,

    /* Number of samples that are at the tail at the end of playback.
     *
     * @return 0 or 1 for no tail, > 1 for number of samples to tail.
     */
    VST_EFFECT_OPCODE_34             = 0x34,
    VST_EFFECT_OPCODE_GETTAILSAMPLES = 0x34,
    VST_EFFECT_OPCODE_TAIL_SAMPLES   = 0x34,
    effGetTailSize = 0x34,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_35 = 0x35,
    effIdle = 0x35,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_36 = 0x36,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_37 = 0x37,

    /* Parameter Properties
     *
     * @param p_ptr vst_parameter_properties*
     * @return 1 if supported, otherwise 0.
     */
    VST_EFFECT_OPCODE_38                       = 0x38,
    VST_EFFECT_OPCODE_GET_PARAMETER_PROPERTIES = VST_EFFECT_OPCODE_38,
    effGetParameterProperties = 0x38,
    
    VST_EFFECT_OPCODE_39                       = 0x39,
    VST_EFFECT_OPCODE_GET_KEYS_REQUIRED = VST_EFFECT_OPCODE_39,
    effKeysRequired = 0x39,

    /* Retrieve the VST Version supported.
     *
     * @return Return 0 for <2.0, 2 for 2.0, 2100 for 2.1, 2200 for 2.2, 2300 for 2.3, etc.
     */
    VST_EFFECT_OPCODE_3A          = 0x3A,
    VST_EFFECT_OPCODE_VST_VERSION = 0x3A,

    // VST 2.1 or later

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_3B = 0x3B,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_3C = 0x3C,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_3D = 0x3D,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_3E = 0x3E,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_3F = 0x3F,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_40 = 0x40,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_41 = 0x41,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_42 = 0x42,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_43 = 0x43,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_44 = 0x44,

    // VST 2.3 or later

    /* Retrieve the speaker arrangement.
     *
     * @param p_int2 (vst_speaker_arrangement**) Pointer to a pointer to the speaker arrangement for the input.
     * @param p_ptr (vst_speaker_arrangement**) Pointer to a pointer to the speaker arrangement for the output.
     */
    VST_EFFECT_OPCODE_45                      = 0x45,
    VST_EFFECT_OPCODE_GET_SPEAKER_ARRANGEMENT = 0x45,
    effGetSpeakerArrangement = 0x45,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_46 = 0x46,
    effShellGetNextPlugin = 0x46,

    /* Begin processing of audio.
     *
     *
     *
     */
    VST_EFFECT_OPCODE_PROCESS_BEGIN = 0x47,
    effStartProcess = 0x47,

    /* End processing of audio.
     *
     *
     *
     */
    VST_EFFECT_OPCODE_PROCESS_END = 0x48,
    effStopProcess = 0x48,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_49 = 0x49,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4A = 0x4A,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4B = 0x4B,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4C = 0x4C,

    // VST 2.4 or later

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4D = 0x4D,
    effSetProcessPrecision = 0x4D,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4E = 0x4E,

    /*
     *
     *
     */
    VST_EFFECT_OPCODE_4F = 0x4F,

    // Highest number of known OPCODE.
    VST_EFFECT_OPCODE_MAX,

    // Pad to force 32-bit number.
    _VST_EFFECT_OPCODE_PAD = 0xFFFFFFFFul,
};

// ghidra
enum VST_HOST_OPCODE {
    /*
     * @param int1 -1 or Parameter Index
     * @return Expected to return... something.
     */
    VST_HOST_OPCODE_00 = 0x00, // cb(vst, 0x00, ?, 0, 0);
    audioMasterAutomate = 0x00,
    
    VST_HOST_OPCODE_01 = 0x01,
    audioMasterVersion = 0x01,
    
    VST_HOST_OPCODE_02 = 0x02, // bool cb(0, 0x02, 0, 0, 0);
    audioMasterCurrentId = 0x02,
    
    VST_HOST_OPCODE_03 = 0x03,
    audioMasterIdle = 0x03,
    
    VST_HOST_OPCODE_04 = 0x04,
    audioMasterPinConnected = 0x04,
    
    VST_HOST_OPCODE_05 = 0x05,
    
    VST_HOST_OPCODE_06 = 0x06,
    audioMasterWantMidi = 0x06,
    
    VST_HOST_OPCODE_07 = 0x07,
    audioMasterGetTime = 0x07,
    
    VST_HOST_OPCODE_08 = 0x08,
    audioMasterProcessEvents = 0x08,
    
    VST_HOST_OPCODE_09 = 0x09, // b
    
    VST_HOST_OPCODE_0A = 0x0A,
    audioMasterTempoAt = 0x0A,
    
    VST_HOST_OPCODE_0B = 0x0B,
    audioMasterGetNumAutomatableParameters = 0x0B,
    
    VST_HOST_OPCODE_0C = 0x0C, // b
    
    VST_HOST_OPCODE_0D = 0x0D,
    audioMasterIOChanged = 0x0D,
    
    VST_HOST_OPCODE_0E = 0x0E,
    audioMasterNeedIdle = 0x0E,
    
    VST_HOST_OPCODE_0F = 0x0F,
    audioMasterSizeWindow = 0x0F,
    
    VST_HOST_OPCODE_10 = 0x10,
    audioMasterGetSampleRate = 0x10,
    
    VST_HOST_OPCODE_11 = 0x11,
    audioMasterGetBlockSize = 0x11,
    
    VST_HOST_OPCODE_12 = 0x12, // b
    VST_HOST_OPCODE_13 = 0x13, // b
    VST_HOST_OPCODE_14 = 0x14, // b
    VST_HOST_OPCODE_15 = 0x15, // b
    VST_HOST_OPCODE_16 = 0x16, // b
    
    VST_HOST_OPCODE_17 = 0x17,
    audioMasterGetCurrentProcessLevel = 0x17,
    
    VST_HOST_OPCODE_18 = 0x18,
    audioMasterGetAutomationState = 0x18,
    
    VST_HOST_OPCODE_19 = 0x19, // b
    VST_HOST_OPCODE_1A = 0x1A, // b
    VST_HOST_OPCODE_1B = 0x1B, // b
    VST_HOST_OPCODE_1C = 0x1C, // b
    VST_HOST_OPCODE_1D = 0x1D, // b
    
    VST_HOST_OPCODE_1E = 0x1E,
    audioMasterSetOutputSampleRate = 0x1E,
    
    VST_HOST_OPCODE_1F = 0x1F, // b
    
    VST_HOST_OPCODE_20 = 0x20,
    audioMasterGetVendorString = 0x20,
    
    VST_HOST_OPCODE_21 = 0x21,
    audioMasterGetProductString = 0x21,
    
    VST_HOST_OPCODE_22 = 0x22,
    audioMasterGetVendorVersion = 0x22,
    
    VST_HOST_OPCODE_23 = 0x23, // b
    VST_HOST_OPCODE_24 = 0x24, // b
    VST_HOST_OPCODE_25 = 0x25,
    audioMasterCanDo = 0x25,
    
    VST_HOST_OPCODE_26 = 0x26, // b
    VST_HOST_OPCODE_27 = 0x27, // b
    VST_HOST_OPCODE_28 = 0x28, // b
    
    VST_HOST_OPCODE_29 = 0x29,
    audioMasterGetDirectory = 0x29,
    
    VST_HOST_OPCODE_2A = 0x2A,
    audioMasterUpdateDisplay = 0x2A,

    /* Parameter gained focus.
     *
     * @param int1 Parameter index.
     */
    VST_HOST_OPCODE_2B = 0x2B,
    audioMasterBeginEdit = 0x2B,
    

    /* Parameter lost focus.
     *
     * @param int1 Parameter index.
     */
    VST_HOST_OPCODE_2C = 0x2C,
    audioMasterEndEdit = 0x2C,

    VST_HOST_OPCODE_2D = 0x2D,
    VST_HOST_OPCODE_2E = 0x2E,
    VST_HOST_OPCODE_2F = 0x2F,

    // Highest number of known OPCODE.
    VST_HOST_OPCODE_MAX,

    // Cannot distinguish all these in ghidra - just assign to made up values
    audioMasterSetTime = 0x40,
    audioMasterGetParameterQuantization = 0x41,
    audioMasterGetInputLatency = 0x42,
    audioMasterGetOutputLatency = 0x43,
    audioMasterGetPreviousPlug = 0x44,
    audioMasterGetNextPlug = 0x45,
    audioMasterWillReplaceOrAccumulate = 0x46,
    audioMasterOfflineStart = 0x47,
    audioMasterOfflineRead = 0x48,
    audioMasterOfflineWrite = 0x49,
    audioMasterOfflineGetCurrentPass = 0x4a,
    audioMasterOfflineGetCurrentMetaPass = 0x4b,
    audioMasterGetOutputSpeakerArrangement = 0x4c,
    audioMasterVendorSpecific = 0x4d,
    audioMasterSetIcon = 0x4e,
    audioMasterGetLanguage = 0x4f,
    audioMasterOpenWindow = 0x50,
    audioMasterCloseWindow = 0x51,
    
    // Pad to force 32-bit number.
    _VST_HOST_OPCODE_PAD = 0xFFFFFFFFul,
};

// ghidra
enum VstSpeakerArrangementType {
    kSpeakerArrUserDefined = -2,
    kSpeakerArrEmpty = -1,
    kSpeakerArrMono = 0,
    kSpeakerArrStereo = 1,
    kSpeakerArrStereoSurround = 2,
    kSpeakerArrStereoCenter = 3,
    kSpeakerArrStereoSide = 4,
    kSpeakerArrStereoCLfe = 5,
    kSpeakerArr30Cine = 6,
    kSpeakerArr30Music = 7,
    kSpeakerArr31Cine = 8,
    kSpeakerArr31Music = 9,
    kSpeakerArr40Cine = 0xa,
    kSpeakerArr40Music = 0xb,
    kSpeakerArr41Cine = 0xc,
    kSpeakerArr41Music = 0xd,
    kSpeakerArr50 = 0xe,
    kSpeakerArr51 = 0xf,
    kSpeakerArr60Cine = 0x10,
    kSpeakerArr61Cine = 0x12,
    kSpeakerArr60Music = 0x11,
    kSpeakerArr61Music = 0x13,
    kSpeakerArr70Music = 0x15,
    kSpeakerArr70Cine = 0x14,
    kSpeakerArr71Music = 0x17,
    kSpeakerArr71Cine = 0x16,
    kSpeakerArr80Cine = 0x18,
    kSpeakerArr80Music = 0x19,
    kSpeakerArr81Cine = 0x1a,
    kSpeakerArr81Music = 0x1b,
    kSpeakerArr102 = 0x1c,

    // Pad to force 32-bit number.
    _VST_ARRANGEMENT_TYPE_PAD = 0xFFFFFFFFul,
};

// ghidra
enum VstSpeakerType {
    kSpeakerL = 1,
    kSpeakerR = 2,
    kSpeakerC = 3,
    kSpeakerLfe = 4,
    kSpeakerLs = 5,
    kSpeakerRs = 6,
    kSpeakerLc = 7,
    kSpeakerRc = 8,
    kSpeakerS = 9,
    kSpeakerSl = 10,
    kSpeakerSr = 11,
    kSpeakerTm = 12,
    kSpeakerTfl = 13,
    kSpeakerTfc = 14,
    kSpeakerTfr = 15,
    kSpeakerTrl = 16,
    kSpeakerTrc = 17,
    kSpeakerTrr = 18,
    kSpeakerLfe2 = 19,

    // Pad to force 32-bit number.
    _VST_SPEAKER_TYPE_PAD = 0xFFFFFFFFul,
};

enum VST_PARAMETER_FLAGS {
    /**
     * Parameter is an on/off switch.
     */
    VST_PARAMETER_FLAGS_SWITCH = 1,
    /**
     * Limits defined by integers.
     */
    VST_PARAMETER_FLAGS_INTEGER_LIMITS = 1 << 1,
    /**
     * Uses float steps.
     */
    VST_PARAMETER_FLAGS_STEP_FLOAT = 1 << 2,
    /**
     * Uses integer steps.
     */
    VST_PARAMETER_FLAGS_STEP_INT = 1 << 3,
    /**
     * Respect index variable for display ordering.
     */
    VST_PARAMETER_FLAGS_INDEX = 1 << 4,
    /**
     * Respect category value and names.
     */
    VST_PARAMETER_FLAGS_CATEGORY = 1 << 5,
    VST_PARAMETER_FLAGS_UNKNOWN6 = 1 << 6,
    _VST_PARAMETER_FLAGS_PAD     = 0xFFFFFFFFul,
};

// ghidra
enum VST_EVENT_TYPE {
    kVstMidiType = 1,
    kVstSysExType = 6
};

// ghidra
enum VST_EFFECT_FLAGS {
    effFlagsHasEditor = 0x1,
    effFlagsCanReplacing = 0x10,
    effFlagsProgramChunks = 0x20,
    effFlagsIsSynth = 0x100,
    effFlagsNoSoundInStop = 0x200,
    effFlagsCanDoubleReplacing = 0x1000,
};

// ghidra
enum VstProcessPrecision {
    kVstProcessPrecision32 = 0,
    kVstProcessPrecision64 = 1
};

// ghidra
enum VST_TIME_INFO_FLAGS {
    kVstTransportChanged = 0x1,
    kVstTransportPlaying = 0x2,
    kVstTransportCycleActive = 0x4,
    kVstTransportRecording = 0x8,
    kVstAutomationWriting = 0x40,
    kVstAutomationReading = 0x80,
    kVstNanosValid = 0x100,
    kVstPpqPosValid = 0x200,
    kVstTempoValid = 0x400,
    kVstBarsValid = 0x800,
    kVstCyclePosValid = 0x1000,
    kVstTimeSigValid = 0x2000,
    kVstSmpteValid = 0x4000,
    kVstClockValid = 0x8000
};

// ghidra
enum VST_PIN_FLAGS {
    kVstPinIsActive = 0x1,
    kVstPinIsStereo = 0x2,
    kVstPinUseSpeaker = 0x4
};

// ghidra
enum VstSmpteFrameRate {
    kVstSmpte24fps = 0,
    kVstSmpte25fps = 1,
    kVstSmpte2997fps = 2,
    kVstSmpte30fps = 3,
    kVstSmpte2997dfps = 4,
    kVstSmpte30dfps = 5,
    kVstSmpteFilm16mm = 6,
    kVstSmpteFilm35mm = 7,
    kVstSmpte239fps = 10, // why???
    kVstSmpte249fps = 11,
    kVstSmpte599fps = 12,
    kVstSmpte60fps = 13,
};

/*******************************************************************************
|* Structures
|*/

// ghidra
struct VstEvent {
    int32_t type;
    int32_t byteSize;
    int32_t deltaFrames;
    int32_t flags;
    char data[28];
};

// ghidra
struct VstMidiEvent {
    int32_t type;
    int32_t byteSize;
    int32_t deltaFrames;
    int32_t flags;
    int32_t noteLength;
    int32_t noteOffset;
    char midiData[4];
    char detune;
    char noteOffVelocity;
};

// ghidra
struct VstMidiSysexEvent {
    int32_t type;
    int32_t byteSize;
    int32_t deltaFrames;
    int32_t flags;
    int32_t dumpBytes; //4
    intptr_t resvd1;   //8
    char* sysexDump;   //8
    intptr_t resvd2;   //8
};

// ghidra
struct VstEvents {
    int32_t numEvents;
    intptr_t resvd;
    VstEvent* events[];
};

// ghidra
struct VstTimeInfo {
    double samplePos;
    double sampleRate;
    double nanoSeconds;
    double ppqPos;
    double tempo;
    double barStartPos;
    double cycleStartPos;
    double cycleEndPos;
    int32_t timeSigNumerator;
    int32_t timeSigDenominator;
    int32_t smpteOffset;
    int32_t smpteFrameRate;
    int32_t _unknown;
    int32_t flags;
};

struct ERect {
    int16_t top;
    int16_t left;
    int16_t bottom;
    int16_t right;
};

// ghidra
constexpr const int32_t kVstMaxVendorStrLen = 64;
constexpr const int32_t kVstMaxProductStrLen = 64;

// ghidra
struct VstPinProperties {
    char label[64];
    int32_t flags;
    int32_t arrangementType;
    char shortLabel[8];
    
    char reserved[48];
};

struct AEffect {
    int32_t magic; // Should always be VST_MAGICNUMBER

    // 64-bit adds 4-byte padding here to align pointers.

    /* Control the VST through an opcode and up to four parameters.
     *
     * @param this Pointer to the effect itself.
     * @param opcode The opcode to run, see VST_EFFECT_OPCODES.
     * @param p_int1 Parameter, see VST_EFFECT_OPCODES.
     * @param p_int2 Parameter, see VST_EFFECT_OPCODES.
     * @param p_ptr Parameter, see VST_EFFECT_OPCODES.
     * @param p_float Parameter, see VST_EFFECT_OPCODES.
     */
    intptr_t(VSTCALLBACK* dispatcher)(AEffect* pthis, int32_t opcode, int32_t p_int1,
                                                 intptr_t p_int2, void* p_ptr, float p_float);

    /* Process the given number of samples in inputs and outputs.
     *
     * Different to process_float how? Never seen any difference.
     *
     * @param pthis Pointer to the effect itself.
     * @param inputs Pointer to an array of 'const float[samples]' with size numInputs.
     * @param outputs Pointer to an array of 'float[samples]' with size numOutputs.
     * @param samples Number of samples per channel in inputs.
     */
    void(VSTCALLBACK* process)(AEffect* pthis, const float* const* inputs, float** outputs,
                                          int32_t samples);

    /* Updates the value for the parameter at the given index, or does nothing if out of bounds.
     *
     * @param pthis Pointer to the effect itself.
     * @param index Parameter index.
     * @param value New value for the parameter.
     */
    void(VSTCALLBACK* setParameter)(AEffect* pthis, uint32_t index, float value);

    /* Returns the value stored for the parameter at index, or 0 if out of bounds.
     *
     * @param pthis Pointer to the effect itself.
     * @param index Parameter index.
     * @return float Value of the parameter.
     */
    float(VSTCALLBACK* getParameter)(AEffect* pthis, uint32_t index);

    int32_t numPrograms; // Number of possible programs.
    int32_t numParams;   // Number of possible parameters.
    int32_t numInputs;   // Number of inputs.
    int32_t numOutputs;  // Number of outputs.

    /* Bitflags
     *
     * Bit        Description
     * 1        Effect has "Editor"
     * 2        Unknown (Found in: ReaDelay)
     * 3        Unknown (Found in: ReaDelay)
     * 4        Unknown (Found in: ReaDelay)
     * 5        Has process_float (Found in: ReaDelay, ReaComp, ReaControlMIDI, ReaStream, ReaFir)
     * 6        Unknown (Found in: ReaControlMIDI, ReaStream, ReaFir)
     * 10        Unknown (Found in: ReaFir)
     * 13        Has process_double (Found in: ReaControlMIDI)
     */
    int32_t flags;

    // 64-bit adds 4-byte padding here to align pointers.

    intptr_t resvd1;
    intptr_t resvd2;

    /* Initial delay before processing of samples can actually begin in Samples.
     *
     * Should be updated before or during handling the 0x47 control call.
     */
    int32_t initialDelay;

    int32_t _unknown_int32_00[2]; // Unknown int32_t values.
    float   _unknown_float_00;    // Seems to always be 1.0

    void* object; // Pointer to Plugin internal data
    void* user;   // Pointer to Host internal data.

    /* Id of the plugin.
     *
     * Due to this not being enough for uniqueness, it should not be used alone
     * for indexing. Ideally you want to index like this:
     *     [unique_id][module_name][version][flags]
     * If any of the checks after unique_id fail, you default to the first
     * possible choice.
     */
    int32_t uniqueID;

    /* Plugin version
     *
     * Unrelated to the minimum VST Version, but often the same.
     */
    int32_t version;

    // There is no padding here if everything went right.

    /* Process the given number of single samples in inputs and outputs.
     *
     * @param pthis Pointer to the effect itself.
     * @param inputs Pointer to an array of 'const float[samples]' with size numInputs.
     * @param outputs Pointer to an array of 'float[samples]' with size numOutputs.
     * @param samples Number of samples per channel in inputs.
     */
    void(VSTCALLBACK* processReplacing)(AEffect* pthis, const float* const* inputs, float** outputs,
                                                   int32_t samples);

    /* Process the given number of double samples in inputs and outputs.
     *
     * Used only by 2.4 hosts and plugins, possibly restricted to said version.
     *
     * @param pthis Pointer to the effect itself.
     * @param inputs Pointer to an array of 'const double[samples]' with size numInputs.
     * @param outputs Pointer to an array of 'double[samples]' with size numOutputs.
     * @param samples Number of samples per channel in inputs.
     */
    void(VSTCALLBACK* processDoubleReplacing)(AEffect* pthis, const double* const* inputs, double** outputs,
                                                         int32_t samples);

    // Everything after this is unknown and was present in reacomp-standalone.dll.
    uint8_t _unknown[56]; // 56-bytes of something. Could also just be 52-bytes.
};

struct VstParameterProperties {
    float step_f32;
    float step_small_f32;
    float step_large_f32;

    char name[VST_BUFFER_64];

    uint32_t flags;
    int32_t  min_value_i32;
    int32_t  max_value_i32;
    int32_t  step_i32;

    char label[VST_BUFFER_8];

    uint16_t index;

    uint16_t category;
    uint16_t num_parameters_in_category;
    uint16_t _unknown_00;

    char category_label[VST_BUFFER_24];

    char _unknown_01[VST_BUFFER_16];
};

struct VstSpeakerProperties {
    float            _unknown_00; // 10.0 if LFE, otherwise random? Never exceeds -PI to PI range.
    float            _unknown_04; // 10.0 if LFE, otherwise random? Never exceeds -PI to PI range.
    float            _unknown_08; // 0.0 if LFE, otherwise 1.0.
    float            _unknown_0C;
    char             name[VST_BUFFER_64];
    int32_t          type;

    uint8_t _unknown[28]; // Padding detected from testing.
};

struct VstSpeakerArrangement {
    int32_t                type;
    int32_t                numChannels;                   // Number of channels in speakers.
    VstSpeakerProperties   speakers[VST_MAX_CHANNELS]; // Array of speaker properties, actual size defined by channels.
};

/* Callback used by the plugin to interface with the host.
 *
 * @param opcode See VST_HOST_OPCODE
 * @param p_str Zero terminated string or null on call.
 * @return ?
 */
typedef intptr_t (*audioMasterCallback)(AEffect* plugin, int32_t opcode, int32_t p_int1, int64_t p_int2,
                                        const char* p_str, int32_t p_int3);

static const char* vst_host_string[] = {
    "GetResourcePath", // ReaControlMIDI
    "get_ini_file",    // ReaControlMIDI
    "resolve_fn",      // ReaControlMIDI
};

using VstInt32 = int32_t;

/* Entry point for VST2.x plugins.
 *
 * @return A new instance of the VST2.x effect.
 */
#define VST_ENTRYPOINT AEffect* VSTPluginMain(vst_host_callback callback)
#define VST_ENTRYPOINT_WINDOWS                   \
    AEffect* MAIN(vst_host_callback callback) \
    {                                            \
        return VSTPluginMain(callback);          \
    }
#define VST_ENTRYPOINT_MACOS                           \
    AEffect* main_macho(vst_host_callback callback) \
    {                                                  \
        return VSTPluginMain(callback);                \
    }

#ifdef __cplusplus
}
#endif

#pragma pack(pop)

#endif
