Initial work on VST editor UI

This commit is contained in:
Jack Andersen 2016-06-10 14:47:02 -10:00
parent fd0dd8922a
commit 6f7a7405d7
6 changed files with 304 additions and 29 deletions

View File

@ -1,8 +1,15 @@
unset(VST_MAIN_SRC CACHE) set(VST3_SDK_ROOT "" CACHE PATH "Path to VST 3.x SDK directory containing 'public.sdk' and 'plugininterfaces'")
find_file(VST_MAIN_SRC vst36/vstplugmain.cpp) if (WIN32 AND (EXISTS ${VST3_SDK_ROOT}))
if (NOT (${VST_MAIN_SRC} STREQUAL "VST_MAIN_SRC-NOTFOUND")) message(STATUS "Found VST SDK; building plugin")
message(STATUS "${VST_MAIN_SRC} Found VST SDK; building plugin") include_directories(${VST3_SDK_ROOT} ${VST3_SDK_ROOT}/public.sdk/source/vst2.x)
set(VST2_DIR ${VST3_SDK_ROOT}/public.sdk/source/vst2.x)
add_definitions(${BOO_SYS_DEFINES})
add_library(amuse-vst SHARED add_library(amuse-vst SHARED
VSTBackend.hpp VSTBackend.cpp VSTBackend.hpp VSTBackend.cpp
VSTEditor.hpp VSTEditor.cpp ${VST_MAIN_SRC}) VSTEditor.hpp VSTEditor.cpp
${VST2_DIR}/vstplugmain.cpp
${VST2_DIR}/audioeffect.cpp
${VST2_DIR}/audioeffectx.cpp)
target_link_libraries(amuse-vst amuse boo soxr ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS} Msimg32 logvisor athena-core)
set_target_properties(amuse-vst PROPERTIES LINK_FLAGS "/EXPORT:VSTPluginMain")
endif() endif()

View File

@ -71,8 +71,8 @@ struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
VSTVoiceEngine() VSTVoiceEngine()
{ {
m_mixInfo.m_periodFrames = 512; m_mixInfo.m_periodFrames = 1024;
m_mixInfo.m_sampleRate = 96000.0; m_mixInfo.m_sampleRate = 44100.0;
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
m_mixInfo.m_bitsPerSample = 32; m_mixInfo.m_bitsPerSample = 32;
_buildAudioRenderClient(); _buildAudioRenderClient();
@ -131,17 +131,23 @@ static logvisor::Module Log("amuse::AudioUnitBackend");
VSTBackend::VSTBackend(audioMasterCallback cb) VSTBackend::VSTBackend(audioMasterCallback cb)
: AudioEffectX(cb, 0, 0), m_editor(*this) : AudioEffectX(cb, 0, 0), m_editor(*this)
{ {
isSynth();
setUniqueID(kBackendID); setUniqueID(kBackendID);
setNumInputs(0); setNumInputs(0);
setNumOutputs(2); setNumOutputs(2);
canProcessReplacing();
setEditor(&m_editor); setEditor(&m_editor);
sizeWindow(800, 520);
m_booBackend = std::make_unique<VSTVoiceEngine>(); m_booBackend = std::make_unique<VSTVoiceEngine>();
m_voxAlloc.emplace(*m_booBackend); m_voxAlloc.emplace(*m_booBackend);
m_engine.emplace(*m_voxAlloc); m_engine.emplace(*m_voxAlloc);
} }
VSTBackend::~VSTBackend()
{
editor = nullptr;
}
AEffEditor* VSTBackend::getEditor() AEffEditor* VSTBackend::getEditor()
{ {
return &m_editor; return &m_editor;
@ -151,6 +157,16 @@ VstInt32 VSTBackend::processEvents(VstEvents* events)
{ {
VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend); VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend);
/* Handle group load request */
int reqGroup = engine.m_reqGroup;
if (engine.m_curGroup != reqGroup)
{
engine.m_curGroup = reqGroup;
if (engine.m_curSeq)
engine.m_curSeq->kill();
engine.m_curSeq = m_engine->seqPlay(reqGroup, -1, nullptr);
}
if (engine.m_midiReceiver) if (engine.m_midiReceiver)
{ {
for (VstInt32 i=0 ; i<events->numEvents ; ++i) for (VstInt32 i=0 ; i<events->numEvents ; ++i)
@ -172,16 +188,6 @@ void VSTBackend::processReplacing(float**, float** outputs, VstInt32 sampleFrame
{ {
VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend); VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend);
/* Handle group load request */
int reqGroup = engine.m_reqGroup;
if (engine.m_curGroup != reqGroup)
{
engine.m_curGroup = reqGroup;
if (engine.m_curSeq)
engine.m_curSeq->kill();
engine.m_curSeq = m_engine->seqPlay(reqGroup, -1, nullptr);
}
/* Output buffers */ /* Output buffers */
engine.m_renderFrames = sampleFrames; engine.m_renderFrames = sampleFrames;
engine.m_outputData = outputs; engine.m_outputData = outputs;
@ -207,6 +213,12 @@ VstPlugCategory VSTBackend::getPlugCategory()
return kPlugCategSynth; return kPlugCategSynth;
} }
bool VSTBackend::getEffectName(char* text)
{
strcpy(text, "Amuse");
return true;
}
bool VSTBackend::getProductString(char* text) bool VSTBackend::getProductString(char* text)
{ {
strcpy(text, "Amuse"); strcpy(text, "Amuse");
@ -219,6 +231,12 @@ bool VSTBackend::getVendorString(char* text)
return true; return true;
} }
bool VSTBackend::getProgramNameIndexed(VstInt32 category, VstInt32 index, char* text)
{
strcpy(text, "Sampler");
return true;
}
bool VSTBackend::getOutputProperties(VstInt32 index, VstPinProperties* properties) bool VSTBackend::getOutputProperties(VstInt32 index, VstPinProperties* properties)
{ {
bool returnCode = false; bool returnCode = false;
@ -226,6 +244,7 @@ bool VSTBackend::getOutputProperties(VstInt32 index, VstPinProperties* propertie
{ {
strcpy(properties->label, "Amuse Out"); strcpy(properties->label, "Amuse Out");
properties->flags = kVstPinIsStereo | kVstPinIsActive; properties->flags = kVstPinIsStereo | kVstPinIsActive;
properties->arrangementType = kSpeakerArrStereo;
returnCode = true; returnCode = true;
} }
return returnCode; return returnCode;
@ -247,12 +266,13 @@ void VSTBackend::setBlockSize(VstInt32 blockSize)
{ {
AudioEffectX::setBlockSize(blockSize); AudioEffectX::setBlockSize(blockSize);
VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend); VSTVoiceEngine& engine = static_cast<VSTVoiceEngine&>(*m_booBackend);
engine.m_interleavedBuf.resize(blockSize * 2);
engine._rebuildAudioRenderClient(engine.mixInfo().m_sampleRate, blockSize); engine._rebuildAudioRenderClient(engine.mixInfo().m_sampleRate, blockSize);
} }
}
AudioEffect* createEffectInstance(audioMasterCallback audioMaster) AudioEffect* createEffectInstance(audioMasterCallback audioMaster)
{ {
return new VSTBackend(audioMaster); return new amuse::VSTBackend(audioMaster);
}
} }

View File

@ -1,7 +1,7 @@
#ifndef __AMUSE_VSTBACKEND_HPP__ #ifndef __AMUSE_VSTBACKEND_HPP__
#define __AMUSE_VSTBACKEND_HPP__ #define __AMUSE_VSTBACKEND_HPP__
#include <vst36/audioeffectx.h> #include "audioeffectx.h"
#include "VSTEditor.hpp" #include "VSTEditor.hpp"
#include <memory> #include <memory>
#include "optional.hpp" #include "optional.hpp"
@ -34,13 +34,16 @@ class VSTBackend : public AudioEffectX
VSTEditor m_editor; VSTEditor m_editor;
public: public:
VSTBackend(audioMasterCallback cb); VSTBackend(audioMasterCallback cb);
~VSTBackend();
AEffEditor* getEditor(); AEffEditor* getEditor();
VstInt32 processEvents(VstEvents* events); VstInt32 processEvents(VstEvents* events);
void processReplacing(float** inputs, float** outputs, VstInt32 sampleFrames); void processReplacing(float** inputs, float** outputs, VstInt32 sampleFrames);
VstInt32 canDo(char* text); VstInt32 canDo(char* text);
VstPlugCategory getPlugCategory(); VstPlugCategory getPlugCategory();
bool getEffectName(char* text);
bool getProductString(char* text); bool getProductString(char* text);
bool getVendorString(char* text); bool getVendorString(char* text);
bool getProgramNameIndexed(VstInt32 category, VstInt32 index, char* text);
bool getOutputProperties(VstInt32 index, VstPinProperties* properties); bool getOutputProperties(VstInt32 index, VstPinProperties* properties);
VstInt32 getNumMidiInputChannels(); VstInt32 getNumMidiInputChannels();
void setSampleRate(float sampleRate); void setSampleRate(float sampleRate);

View File

@ -1,6 +1,9 @@
#include "VSTEditor.hpp" #include "VSTEditor.hpp"
#include "VSTBackend.hpp" #include "VSTBackend.hpp"
extern void* hInstance;
static WNDPROC OriginalListViewProc = 0;
namespace amuse namespace amuse
{ {
@ -15,14 +18,227 @@ bool VSTEditor::getRect(ERect** rect)
return true; return true;
} }
LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
VSTEditor& editor = *reinterpret_cast<VSTEditor*>(GetWindowLongPtrW(hwnd, 0));
switch (uMsg)
{
case WM_NOTIFY:
{
NMHDR& itemAct = *reinterpret_cast<LPNMHDR>(lParam);
switch (itemAct.code)
{
case HDN_BEGINTRACK:
return TRUE;
case NM_CLICK:
{
NMITEMACTIVATE& itemAct = *reinterpret_cast<LPNMITEMACTIVATE>(lParam);
if (itemAct.hdr.hwndFrom == editor.m_collectionListView)
editor.selectCollection(itemAct.iItem);
else if (itemAct.hdr.hwndFrom == editor.m_groupFileListView)
editor.selectGroupFile(itemAct.iItem);
else if (itemAct.hdr.hwndFrom == editor.m_groupListView)
editor.selectGroup(itemAct.iItem);
else if (itemAct.hdr.hwndFrom == editor.m_pageListView)
editor.selectPage(itemAct.iItem);
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_SETCURSOR:
return TRUE;
case WM_LBUTTONDBLCLK:
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
TRIVERTEX verts[] =
{
{rect.left, rect.top, 0x6000, 0x6000, 0x7000, 0xff00},
{rect.right, rect.bottom, 0x2000, 0x2000, 0x2800, 0xff00}
};
GRADIENT_RECT grect = {0, 1};
GradientFill(dc, verts, 2, &grect, 1, GRADIENT_FILL_RECT_V);
SetTextColor(dc, RGB(255,255,255));
SetBkMode(dc, TRANSPARENT);
SelectObject(dc, GetStockObject(ANSI_VAR_FONT));
rect.left += 6;
LPWSTR str = LPWSTR(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
DrawText(dc, str, -1, &rect, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
EndPaint(hwnd, &ps);
return 0;
}
}
return CallWindowProc(OriginalListViewProc, hwnd, uMsg, wParam, lParam);
}
bool VSTEditor::open(void* ptr) bool VSTEditor::open(void* ptr)
{ {
AEffEditor::open(ptr); AEffEditor::open(ptr);
#if _WIN32 HWND hostView = HWND(ptr);
#elif __APPLE__
#else WNDCLASSW notifyCls =
#endif {
CS_HREDRAW | CS_VREDRAW,
WindowProc,
0,
8,
HINSTANCE(hInstance),
nullptr,
nullptr,
HBRUSH(COLOR_BACKGROUND),
nullptr,
L"VSTNotify"
};
RegisterClassW(&notifyCls);
m_rootView = CreateWindowW(L"VSTNotify",
L"",
WS_CHILD,
0, 0,
m_windowRect.right,
m_windowRect.bottom,
hostView,
nullptr,
HINSTANCE(hInstance),
nullptr);
SetWindowLongPtrW(m_rootView, 0, LONG_PTR(this));
ShowWindow(m_rootView, SW_SHOW);
LV_COLUMN column = {};
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
column.cx = 200;
m_collectionListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
0, 0,
201,
m_windowRect.bottom - m_windowRect.top,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Collection";
HWND header = ListView_GetHeader(m_collectionListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
OriginalListViewProc = WNDPROC(SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
ListView_SetBkColor(m_collectionListView, RGB(64,64,64));
ListView_InsertColumn(m_collectionListView, 0, &column);
ShowWindow(m_collectionListView, SW_SHOW);
m_groupFileListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
200, 0,
201,
m_windowRect.bottom - m_windowRect.top,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"File";
header = ListView_GetHeader(m_groupFileListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_groupFileListView, RGB(64,64,64));
ListView_InsertColumn(m_groupFileListView, 0, &column);
ShowWindow(m_groupFileListView, SW_SHOW);
m_groupListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
400, 0,
201,
m_windowRect.bottom - m_windowRect.top,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Group";
header = ListView_GetHeader(m_groupListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_groupListView, RGB(64,64,64));
ListView_InsertColumn(m_groupListView, 0, &column);
ShowWindow(m_groupListView, SW_SHOW);
m_pageListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
600, 0,
200,
m_windowRect.bottom - m_windowRect.top,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Page";
header = ListView_GetHeader(m_pageListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_pageListView, RGB(64,64,64));
ListView_InsertColumn(m_pageListView, 0, &column);
ShowWindow(m_pageListView, SW_SHOW);
return true; return true;
} }
void VSTEditor::close()
{
AEffEditor::close();
UnregisterClassW(L"VSTNotify", HINSTANCE(hInstance));
}
void VSTEditor::update()
{
}
void VSTEditor::selectCollection(int idx)
{
}
void VSTEditor::selectGroupFile(int idx)
{
}
void VSTEditor::selectGroup(int idx)
{
}
void VSTEditor::selectPage(int idx)
{
}
} }

View File

@ -1,7 +1,11 @@
#ifndef __AMUSE_VSTEDITOR_HPP__ #ifndef __AMUSE_VSTEDITOR_HPP__
#define __AMUSE_VSTEDITOR_HPP__ #define __AMUSE_VSTEDITOR_HPP__
#include <vst36/aeffeditor.h> #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include "aeffeditor.h"
namespace amuse namespace amuse
{ {
@ -11,12 +15,38 @@ class VSTBackend;
class VSTEditor : public AEffEditor class VSTEditor : public AEffEditor
{ {
VSTBackend& m_backend; VSTBackend& m_backend;
ERect m_windowRect = {10, 10, 410, 520}; ERect m_windowRect = {0, 0, 520, 800};
HWND m_rootView;
HWND m_collectionListView;
HWND m_groupFileListView;
HWND m_groupListView;
HWND m_pageListView;
static LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
static LRESULT CALLBACK ColHeaderWindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
public: public:
VSTEditor(VSTBackend& backend); VSTEditor(VSTBackend& backend);
bool getRect(ERect** rect); bool getRect(ERect** rect);
bool open(void* ptr); bool open(void* ptr);
void close();
void update();
void selectCollection(int idx);
void selectGroupFile(int idx);
void selectGroup(int idx);
void selectPage(int idx);
}; };
} }

View File

@ -2,7 +2,6 @@
#include "amuse/Voice.hpp" #include "amuse/Voice.hpp"
#include "amuse/Submix.hpp" #include "amuse/Submix.hpp"
#include "amuse/Engine.hpp" #include "amuse/Engine.hpp"
#include <syslog.h>
namespace amuse namespace amuse
{ {