VST UI logic complete, needs some audio output debugging

This commit is contained in:
Jack Andersen 2016-06-13 15:54:24 -10:00
parent fa3007b65c
commit e7c7e5ffd3
6 changed files with 320 additions and 55 deletions

View File

@ -1,9 +1,48 @@
#include "AudioGroupFilePresenter.hpp" #include "AudioGroupFilePresenter.hpp"
#include "VSTBackend.hpp" #include "VSTBackend.hpp"
#include <Shellapi.h>
#include <Shlwapi.h>
namespace amuse namespace amuse
{ {
static const wchar_t *const GMNames[128] =
{
L"Acoustic Grand Piano", L"Bright Acoustic Piano", L"Electric Grand Piano", L"Honky-tonk Piano", L"Rhodes Piano", L"Chorused Piano",
L"Harpsichord", L"Clavinet", L"Celesta", L"Glockenspiel", L"Music Box", L"Vibraphone", L"Marimba", L"Xylophone", L"Tubular Bells", L"Dulcimer",
L"Drawbar Organ", L"Percussive Organ", L"Rock Organ", L"Church Organ", L"Reed Organ", L"Accordion", L"Harmonica", L"Tango Accordion",
L"Acoustic Guitar (nylon)", L"Acoustic Guitar (steel)", L"Electric Guitar (jazz)", L"Electric Guitar (clean)", L"Electric Guitar (muted)",
L"Overdriven Guitar", L"Distortion Guitar", L"Guitar Harmonics", L"Acoustic Bass", L"Electric Bass (finger)", L"Electric Bass (pick)",
L"Fretless Bass", L"Slap Bass 1", L"Slap Bass 2", L"Synth Bass 1", L"Synth Bass 2", L"Violin", L"Viola", L"Cello", L"Contrabass",
L"Tremelo Strings", L"Pizzicato Strings", L"Orchestral Harp", L"Timpani", L"String Ensemble 1", L"String Ensemble 2", L"SynthStrings 1",
L"SynthStrings 2", L"Choir Aahs", L"Voice Oohs", L"Synth Voice", L"Orchestra Hit", L"Trumpet", L"Trombone", L"Tuba", L"Muted Trumpet",
L"French Horn", L"Brass Section", L"Synth Brass 1", L"Synth Brass 2", L"Soprano Sax", L"Alto Sax", L"Tenor Sax", L"Baritone Sax",
L"Oboe", L"English Horn", L"Bassoon", L"Clarinet", L"Piccolo", L"Flute", L"Recorder", L"Pan Flute", L"Bottle Blow", L"Shakuhachi", L"Whistle",
L"Ocarina", L"Lead 1 (square)", L"Lead 2 (sawtooth)", L"Lead 3 (calliope lead)", L"Lead 4 (chiff lead)", L"Lead 5 (charang)",
L"Lead 6 (voice)", L"Lead 7 (fifths)", L"Lead 8 (bass + lead)", L"Pad 1 (new age)", L"Pad 2 (warm)", L"Pad 3 (polysynth)", L"Pad 4 (choir)",
L"Pad 5 (bowed)", L"Pad 6 (metallic)", L"Pad 7 (halo)", L"Pad 8 (sweep)", L"FX 1 (rain)", L"FX 2 (soundtrack)", L"FX 3 (crystal)",
L"FX 4 (atmosphere)", L"FX 5 (brightness)", L"FX 6 (goblins)", L"FX 7 (echoes)", L"FX 8 (sci-fi)", L"Sitar", L"Banjo", L"Shamisen", L"Koto",
L"Kalimba", L"Bagpipe", L"Fiddle", L"Shanai", L"Tinkle Bell", L"Agogo", L"Steel Drums", L"Woodblock", L"Taiko Drum", L"Melodic Tom",
L"Synth Drum", L"Reverse Cymbal", L"Guitar Fret Noise", L"Breath Noise", L"Seashore", L"Bird Tweet", L"Telephone Ring", L"Helicopter",
L"Applause", L"Gunshot"
};
static const wchar_t *const GMPercNames[128] =
{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, L"Acoustic Bass Drum", L"Bass Drum 1", L"Side Stick",
L"Acoustic Snare", L"Hand Clap", L"Electric Snare", L"Low Floor Tom", L"Closed Hi-Hat",
L"High Floor Tom", L"Pedal Hi-Hat", L"Low Tom", L"Open Hi-Hat", L"Low-Mid Tom", L"Hi-Mid Tom",
L"Crash Cymbal 1", L"High Tom", L"Ride Cymbal 1", L"Chinese Cymbal", L"Ride Bell", L"Tambourine",
L"Splash Cymbal", L"Cowbell", L"Crash Cymbal 2", L"Vibraslap", L"Ride Cymbal 2", L"Hi Bongo",
L"Low Bongo", L"Mute Hi Conga", L"Open Hi Conga", L"Low Conga", L"High Timbale", L"Low Timbale",
L"High Agogo", L"Low Agogo", L"Cabasa", L"Maracas", L"Short Whistle", L"Long Whistle", L"Short Guiro",
L"Long Guiro", L"Claves", L"Hi Wood Block", L"Low Wood Block", L"Mute Cuica", L"Open Cuica",
L"Mute Triangle", L"Open Triangle"
};
bool AudioGroupDataCollection::loadProj() bool AudioGroupDataCollection::loadProj()
{ {
std::wstring path = m_path + L"\\proj"; std::wstring path = m_path + L"\\proj";
@ -73,7 +112,7 @@ AudioGroupDataCollection::AudioGroupDataCollection(const std::wstring& path, con
} }
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter& presenter) bool AudioGroupDataCollection::_attemptLoad()
{ {
if (m_metaData && m_loadedData && m_loadedGroup) if (m_metaData && m_loadedData && m_loadedGroup)
return true; return true;
@ -88,13 +127,11 @@ bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter& presenter)
if (!loadMeta()) if (!loadMeta())
return false; return false;
return _indexData(presenter); return _indexData();
} }
bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter) bool AudioGroupDataCollection::_indexData()
{ {
amuse::Engine& engine = presenter.getBackend().getAmuseEngine();
switch (m_metaData->fmt) switch (m_metaData->fmt)
{ {
case amuse::DataFormat::GCN: case amuse::DataFormat::GCN:
@ -121,6 +158,11 @@ bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
break; break;
} }
return m_loadedData.operator bool();
}
void AudioGroupDataCollection::addToEngine(amuse::Engine& engine)
{
m_loadedGroup = engine.addAudioGroup(*m_loadedData); m_loadedGroup = engine.addAudioGroup(*m_loadedData);
m_groupTokens.clear(); m_groupTokens.clear();
if (m_loadedGroup) if (m_loadedGroup)
@ -145,8 +187,11 @@ bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
m_groupTokens.emplace_back(pair.first, pair.second); m_groupTokens.emplace_back(pair.first, pair.second);
} }
} }
}
return m_loadedData && m_loadedGroup; void AudioGroupDataCollection::removeFromEngine(amuse::Engine& engine) const
{
engine.removeAudioGroup(*m_loadedData);
} }
AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::wstring& name) AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::wstring& name)
@ -155,8 +200,7 @@ AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::
} }
void AudioGroupCollection::addCollection(AudioGroupFilePresenter& presenter, void AudioGroupCollection::addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
{ {
for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection) for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection)
{ {
@ -185,7 +229,7 @@ void AudioGroupCollection::addCollection(AudioGroupFilePresenter& presenter,
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize()); memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true); dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
dataCollection._indexData(presenter); dataCollection._indexData();
} }
} }
@ -212,7 +256,7 @@ void AudioGroupCollection::update(AudioGroupFilePresenter& presenter)
m_groups.emplace(nameStr, m_groups.emplace(nameStr,
std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr, std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr,
nameStr)).first; nameStr)).first;
search->second->_attemptLoad(presenter); search->second->_attemptLoad();
} }
} }
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
@ -256,7 +300,7 @@ void AudioGroupFilePresenter::addCollection(const std::wstring& name,
std::wstring path = m_backend.getUserDir() + L'\\' + name; std::wstring path = m_backend.getUserDir() + L'\\' + name;
AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second; AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second;
CreateDirectory(insert.m_path.c_str(), nullptr); CreateDirectory(insert.m_path.c_str(), nullptr);
insert.addCollection(*this, std::move(collection)); insert.addCollection(std::move(collection));
for (std::pair<const std::wstring, std::unique_ptr<AudioGroupDataCollection>>& pair : insert.m_groups) for (std::pair<const std::wstring, std::unique_ptr<AudioGroupDataCollection>>& pair : insert.m_groups)
{ {
@ -300,34 +344,130 @@ void AudioGroupFilePresenter::addCollection(const std::wstring& name,
} }
} }
void AudioGroupCollection::populateFiles(VSTEditor& editor, HTREEITEM colHandle) void AudioGroupFilePresenter::removeCollection(unsigned idx)
{
if (idx < m_iteratorVec.size())
{
CollectionIterator& it = m_iteratorVec[idx];
std::wstring collectionPath = it->second->m_path + L'\0';
SHFILEOPSTRUCT op = {};
op.wFunc = FO_DELETE;
op.pFrom = collectionPath.c_str();
op.fFlags = FOF_NO_UI;
SHFileOperation(&op);
m_audioGroupCollections.erase(it);
}
}
void AudioGroupCollection::populateFiles(VSTEditor& editor, HTREEITEM colHandle, size_t parentIdx)
{ {
TVINSERTSTRUCT ins = {}; TVINSERTSTRUCT ins = {};
ins.item.mask = TVIF_TEXT; ins.item.mask = TVIF_TEXT | TVIF_PARAM;
ins.hParent = colHandle; ins.hParent = colHandle;
ins.hInsertAfter = TVI_LAST; ins.hInsertAfter = TVI_LAST;
for (const auto& group : m_groups) m_iteratorVec.clear();
m_iteratorVec.reserve(m_groups.size());
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
{ {
ins.item.pszText = LPWSTR(group.first.c_str()); ins.item.pszText = LPWSTR(it->first.c_str());
TreeView_InsertItem(editor.m_collectionTree, &ins); ins.item.lParam = LPARAM(0x80000000 | (parentIdx << 16) | m_iteratorVec.size());
HTREEITEM item = TreeView_InsertItem(editor.m_collectionTree, &ins);
if (editor.m_selCollectionIdx == parentIdx && editor.m_selFileIdx == m_iteratorVec.size())
editor.m_deferredCollectionSel = item;
m_iteratorVec.push_back(it);
} }
} }
void AudioGroupFilePresenter::populateEditor(VSTEditor& editor) void AudioGroupFilePresenter::populateCollectionColumn(VSTEditor& editor)
{ {
TreeView_DeleteAllItems(editor.m_collectionTree); TreeView_DeleteAllItems(editor.m_collectionTree);
TVINSERTSTRUCT ins = {}; TVINSERTSTRUCT ins = {};
ins.hParent = TVI_ROOT; ins.hParent = TVI_ROOT;
ins.hInsertAfter = TVI_LAST; ins.hInsertAfter = TVI_LAST;
ins.item.mask = TVIF_CHILDREN | TVIF_TEXT; ins.item.mask = TVIF_CHILDREN | TVIF_TEXT | TVIF_PARAM;
for (const auto& collection : m_audioGroupCollections) m_iteratorVec.clear();
m_iteratorVec.reserve(m_audioGroupCollections.size());
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
{ {
ins.item.cChildren = collection.second->m_groups.size() ? 1 : 0; ins.item.cChildren = it->second->m_groups.size() ? 1 : 0;
ins.item.pszText = LPWSTR(collection.first.c_str()); ins.item.pszText = LPWSTR(it->first.c_str());
ins.item.lParam = LPARAM(m_iteratorVec.size() << 16);
HTREEITEM item = TreeView_InsertItem(editor.m_collectionTree, &ins); HTREEITEM item = TreeView_InsertItem(editor.m_collectionTree, &ins);
collection.second->populateFiles(editor, item); it->second->populateFiles(editor, item, m_iteratorVec.size());
if (editor.m_selCollectionIdx == m_iteratorVec.size() && editor.m_selFileIdx == -1)
editor.m_deferredCollectionSel = item;
m_iteratorVec.push_back(it);
}
}
void AudioGroupFilePresenter::populateGroupColumn(VSTEditor& editor, int collectionIdx, int fileIdx)
{
LVITEM item = {};
item.mask = LVIF_TEXT;
ListView_DeleteAllItems(editor.m_groupListView);
if (collectionIdx < m_iteratorVec.size())
{
CollectionIterator& it = m_iteratorVec[collectionIdx];
if (fileIdx < it->second->m_iteratorVec.size())
{
AudioGroupCollection::GroupIterator& git = it->second->m_iteratorVec[fileIdx];
item.pszText = LPWSTR(git->first.c_str());
ListView_InsertItem(editor.m_groupListView, &item);
}
}
}
void AudioGroupFilePresenter::populatePageColumn(VSTEditor& editor, int collectionIdx, int fileIdx, int groupIdx)
{
LVITEM item = {};
item.mask = LVIF_TEXT | LVIF_PARAM;
ListView_DeleteAllItems(editor.m_pageListView);
if (collectionIdx < m_iteratorVec.size())
{
CollectionIterator& it = m_iteratorVec[collectionIdx];
if (fileIdx < it->second->m_iteratorVec.size())
{
AudioGroupCollection::GroupIterator& git = it->second->m_iteratorVec[fileIdx];
if (groupIdx < git->second->m_groupTokens.size())
{
AudioGroupDataCollection::GroupToken& groupTok = git->second->m_groupTokens[groupIdx];
if (groupTok.m_song)
{
std::map<uint8_t, const amuse::SongGroupIndex::PageEntry*> sortPages;
for (auto& pair : groupTok.m_song->m_normPages)
sortPages[pair.first] = pair.second;
size_t idx = 0;
for (auto& pair : sortPages)
{
wchar_t name[256];
wnsprintf(name, 256, L"%d (%s)", pair.first, GMNames[pair.first] ? GMNames[pair.first] : L"???");
item.pszText = name;
item.iItem = idx++;
item.lParam = pair.first;
ListView_InsertItem(editor.m_pageListView, &item);
}
sortPages.clear();
for (auto& pair : groupTok.m_song->m_drumPages)
sortPages[pair.first] = pair.second;
for (auto& pair : sortPages)
{
wchar_t name[256];
wnsprintf(name, 256, L"%d (%s)", pair.first, GMPercNames[pair.first] ? GMPercNames[pair.first] : L"???");
item.pszText = name;
item.iItem = idx++;
item.lParam = 0x80000000 | pair.first;
ListView_InsertItem(editor.m_pageListView, &item);
}
}
}
}
} }
} }

View File

@ -59,34 +59,46 @@ struct AudioGroupDataCollection
AudioGroupDataCollection(const std::wstring& path, const std::wstring& name); AudioGroupDataCollection(const std::wstring& path, const std::wstring& name);
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;} bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
bool _attemptLoad(AudioGroupFilePresenter& presenter); bool _attemptLoad();
bool _indexData(AudioGroupFilePresenter& presenter); bool _indexData();
void addToEngine(amuse::Engine& engine);
void removeFromEngine(amuse::Engine& engine) const;
}; };
struct AudioGroupCollection struct AudioGroupCollection
{ {
using GroupIterator = std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>>::iterator;
std::wstring m_path; std::wstring m_path;
std::wstring m_name; std::wstring m_name;
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups; std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
std::vector<GroupIterator> m_iteratorVec;
AudioGroupCollection(const std::wstring& path, const std::wstring& name); AudioGroupCollection(const std::wstring& path, const std::wstring& name);
void addCollection(AudioGroupFilePresenter& presenter, void addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
void update(AudioGroupFilePresenter& presenter); void update(AudioGroupFilePresenter& presenter);
void populateFiles(VSTEditor& editor, HTREEITEM colHandle); void populateFiles(VSTEditor& editor, HTREEITEM colHandle, size_t parentIdx);
}; };
class AudioGroupFilePresenter class AudioGroupFilePresenter
{ {
friend class VSTBackend;
public:
using CollectionIterator = std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>::iterator;
private:
VSTBackend& m_backend; VSTBackend& m_backend;
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections; std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
std::vector<CollectionIterator> m_iteratorVec;
public: public:
AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {} AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {}
void update(); void update();
void populateEditor(VSTEditor& editor); void populateCollectionColumn(VSTEditor& editor);
void populateGroupColumn(VSTEditor& editor, int collectionIdx, int fileIdx);
void populatePageColumn(VSTEditor& editor, int collectionIdx, int fileIdx, int groupIdx);
void addCollection(const std::wstring& name, void addCollection(const std::wstring& name,
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection); std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
void removeCollection(unsigned idx);
VSTBackend& getBackend() {return m_backend;} VSTBackend& getBackend() {return m_backend;}
}; };

View File

@ -280,6 +280,49 @@ void VSTBackend::setBlockSize(VstInt32 blockSize)
engine._rebuildAudioRenderClient(engine.mixInfo().m_sampleRate, blockSize); engine._rebuildAudioRenderClient(engine.mixInfo().m_sampleRate, blockSize);
} }
void VSTBackend::loadGroupSequencer(int collectionIdx, int fileIdx, int groupIdx)
{
if (m_curSeq)
{
m_curSeq->kill();
m_curSeq.reset();
}
if (collectionIdx < m_filePresenter.m_iteratorVec.size())
{
AudioGroupFilePresenter::CollectionIterator& it = m_filePresenter.m_iteratorVec[collectionIdx];
if (fileIdx < it->second->m_iteratorVec.size())
{
AudioGroupCollection::GroupIterator& git = it->second->m_iteratorVec[fileIdx];
if (m_curData)
m_curData->removeFromEngine(*m_engine);
git->second->addToEngine(*m_engine);
m_curData = git->second.get();
if (groupIdx < git->second->m_groupTokens.size())
{
AudioGroupDataCollection::GroupToken& groupTok = git->second->m_groupTokens[groupIdx];
if (groupTok.m_song)
m_curSeq = m_engine->seqPlay(groupTok.m_groupId, -1, nullptr);
}
}
}
}
void VSTBackend::setNormalProgram(int programNo)
{
if (!m_curSeq)
return;
m_curSeq->setChanProgram(0, programNo);
}
void VSTBackend::setDrumProgram(int programNo)
{
if (!m_curSeq)
return;
m_curSeq->setChanProgram(9, programNo);
}
} }
AudioEffect* createEffectInstance(audioMasterCallback audioMaster) AudioEffect* createEffectInstance(audioMasterCallback audioMaster)

View File

@ -31,6 +31,8 @@ class VSTBackend : public AudioEffectX
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend; std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
std::experimental::optional<amuse::VSTBackendVoiceAllocator> m_voxAlloc; std::experimental::optional<amuse::VSTBackendVoiceAllocator> m_voxAlloc;
std::experimental::optional<amuse::Engine> m_engine; std::experimental::optional<amuse::Engine> m_engine;
std::shared_ptr<amuse::Sequencer> m_curSeq;
const AudioGroupDataCollection* m_curData = nullptr;
size_t m_curFrame = 0; size_t m_curFrame = 0;
std::wstring m_userDir; std::wstring m_userDir;
AudioGroupFilePresenter m_filePresenter; AudioGroupFilePresenter m_filePresenter;
@ -55,6 +57,10 @@ public:
amuse::Engine& getAmuseEngine() {return *m_engine;} amuse::Engine& getAmuseEngine() {return *m_engine;}
const std::wstring& getUserDir() const {return m_userDir;} const std::wstring& getUserDir() const {return m_userDir;}
AudioGroupFilePresenter& getFilePresenter() {return m_filePresenter;} AudioGroupFilePresenter& getFilePresenter() {return m_filePresenter;}
void loadGroupSequencer(int collectionIdx, int fileIdx, int groupIdx);
void setNormalProgram(int programNo);
void setDrumProgram(int programNo);
}; };
} }

View File

@ -44,12 +44,22 @@ LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
case NM_CLICK: case NM_CLICK:
{ {
NMITEMACTIVATE& itemAct = *reinterpret_cast<LPNMITEMACTIVATE>(lParam); NMITEMACTIVATE& itemAct = *reinterpret_cast<LPNMITEMACTIVATE>(lParam);
if (itemAct.hdr.hwndFrom == editor.m_collectionTree) if (itemAct.hdr.hwndFrom == editor.m_groupListView)
editor.selectCollection(itemAct.iItem);
else if (itemAct.hdr.hwndFrom == editor.m_groupListView)
editor.selectGroup(itemAct.iItem); editor.selectGroup(itemAct.iItem);
else if (itemAct.hdr.hwndFrom == editor.m_pageListView) else if (itemAct.hdr.hwndFrom == editor.m_pageListView)
editor.selectPage(itemAct.iItem); {
if (itemAct.lParam & 0x80000000)
editor.selectDrumPage(itemAct.lParam & 0x7fffffff);
else
editor.selectNormalPage(itemAct.lParam & 0x7fffffff);
}
return 0;
}
case TVN_SELCHANGED:
{
NMTREEVIEW& itemAct = *reinterpret_cast<LPNMTREEVIEW>(lParam);
if (itemAct.hdr.hwndFrom == editor.m_collectionTree)
editor.selectCollection(itemAct.itemNew.lParam);
return 0; return 0;
} }
case TVN_GETDISPINFO: case TVN_GETDISPINFO:
@ -135,6 +145,19 @@ LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd,
return CallWindowProc(OriginalListViewProc, hwnd, uMsg, wParam, lParam); return CallWindowProc(OriginalListViewProc, hwnd, uMsg, wParam, lParam);
} }
void VSTEditor::_reselectColumns()
{
if (m_deferredCollectionSel)
{
TreeView_SelectItem(m_collectionTree, m_deferredCollectionSel);
m_deferredCollectionSel = 0;
}
if (m_selGroupIdx != -1)
ListView_SetItemState(m_groupListView, m_selGroupIdx, LVIS_FOCUSED | LVIS_SELECTED, 0xf);
if (m_selPageIdx != -1)
ListView_SetItemState(m_pageListView, m_selPageIdx, LVIS_FOCUSED | LVIS_SELECTED, 0xf);
}
bool VSTEditor::open(void* ptr) bool VSTEditor::open(void* ptr)
{ {
AEffEditor::open(ptr); AEffEditor::open(ptr);
@ -182,13 +205,9 @@ bool VSTEditor::open(void* ptr)
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH; column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
column.cx = 199; column.cx = 199;
LVITEM item = {};
item.mask = LVIF_TEXT;
item.pszText = L"Test";
m_collectionTree = CreateWindowW(WC_TREEVIEW, m_collectionTree = CreateWindowW(WC_TREEVIEW,
L"", L"",
WS_CHILD | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, WS_CHILD | WS_CLIPSIBLINGS | TVS_SHOWSELALWAYS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS,
1, 25, 1, 25,
199, 199,
m_windowRect.bottom - m_windowRect.top - 26, m_windowRect.bottom - m_windowRect.top - 26,
@ -251,13 +270,13 @@ bool VSTEditor::open(void* ptr)
nullptr, nullptr,
nullptr); nullptr);
SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE); SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE);
Button_Enable(m_collectionRemove, TRUE); Button_Enable(m_collectionRemove, FALSE);
SetWindowPos(m_collectionRemove, HWND_TOP, 26, m_windowRect.bottom - m_windowRect.top - 26, 25, 24, SWP_SHOWWINDOW); SetWindowPos(m_collectionRemove, HWND_TOP, 26, m_windowRect.bottom - m_windowRect.top - 26, 25, 24, SWP_SHOWWINDOW);
m_groupListView = CreateWindowW(WC_LISTVIEW, m_groupListView = CreateWindowW(WC_LISTVIEW,
L"", L"",
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER, WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER,
201, 1, 201, 1,
199, 199,
m_windowRect.bottom - m_windowRect.top - 2, m_windowRect.bottom - m_windowRect.top - 2,
@ -273,12 +292,11 @@ bool VSTEditor::open(void* ptr)
ListView_SetTextBkColor(m_groupListView, CLR_NONE); ListView_SetTextBkColor(m_groupListView, CLR_NONE);
ListView_SetTextColor(m_groupListView, RGB(255,255,255)); ListView_SetTextColor(m_groupListView, RGB(255,255,255));
ListView_InsertColumn(m_groupListView, 0, &column); ListView_InsertColumn(m_groupListView, 0, &column);
ListView_InsertItem(m_groupListView, &item);
ShowWindow(m_groupListView, SW_SHOW); ShowWindow(m_groupListView, SW_SHOW);
m_pageListView = CreateWindowW(WC_LISTVIEW, m_pageListView = CreateWindowW(WC_LISTVIEW,
L"", L"",
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER, WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER,
401, 1, 401, 1,
198, 198,
m_windowRect.bottom - m_windowRect.top - 2, m_windowRect.bottom - m_windowRect.top - 2,
@ -295,10 +313,12 @@ bool VSTEditor::open(void* ptr)
ListView_SetTextBkColor(m_pageListView, CLR_NONE); ListView_SetTextBkColor(m_pageListView, CLR_NONE);
ListView_SetTextColor(m_pageListView, RGB(255,255,255)); ListView_SetTextColor(m_pageListView, RGB(255,255,255));
ListView_InsertColumn(m_pageListView, 0, &column); ListView_InsertColumn(m_pageListView, 0, &column);
ListView_InsertItem(m_pageListView, &item);
ShowWindow(m_pageListView, SW_SHOW); ShowWindow(m_pageListView, SW_SHOW);
m_backend.getFilePresenter().populateEditor(*this); m_backend.getFilePresenter().populateCollectionColumn(*this);
m_backend.getFilePresenter().populateGroupColumn(*this, m_selCollectionIdx, m_selFileIdx);
m_backend.getFilePresenter().populatePageColumn(*this, m_selCollectionIdx, m_selFileIdx, m_selGroupIdx);
_reselectColumns();
return true; return true;
} }
@ -346,28 +366,62 @@ void VSTEditor::addAction()
} }
m_backend.getFilePresenter().addCollection(name, std::move(data)); m_backend.getFilePresenter().addCollection(name, std::move(data));
m_backend.getFilePresenter().populateEditor(*this); m_backend.getFilePresenter().populateCollectionColumn(*this);
m_backend.getFilePresenter().populateGroupColumn(*this, m_selCollectionIdx, m_selFileIdx);
m_backend.getFilePresenter().populatePageColumn(*this, m_selCollectionIdx, m_selFileIdx, m_selGroupIdx);
} }
} }
void VSTEditor::removeAction() void VSTEditor::removeAction()
{ {
if (m_selCollectionIdx == -1)
return;
m_backend.getFilePresenter().removeCollection(m_selCollectionIdx);
m_backend.getFilePresenter().populateCollectionColumn(*this);
m_selCollectionIdx = -1;
m_selFileIdx = -1;
m_selGroupIdx = -1;
m_backend.getFilePresenter().populateGroupColumn(*this, m_selCollectionIdx, m_selFileIdx);
m_backend.getFilePresenter().populatePageColumn(*this, m_selCollectionIdx, m_selFileIdx, m_selGroupIdx);
Button_Enable(m_collectionRemove, FALSE);
} }
void VSTEditor::selectCollection(int idx) void VSTEditor::selectCollection(LPARAM idx)
{ {
if (0x80000000 & idx)
{
/* Sub-item */
int rootIdx = (idx >> 16) & 0x7fff;
int subIdx = idx & 0xffff;
Button_Enable(m_collectionRemove, FALSE);
m_selCollectionIdx = rootIdx;
m_selFileIdx = subIdx;
m_backend.getFilePresenter().populateGroupColumn(*this, rootIdx, subIdx);
}
else
{
/* Root-item */
int rootIdx = (idx >> 16) & 0x7fff;
m_selCollectionIdx = rootIdx;
Button_Enable(m_collectionRemove, TRUE);
}
} }
void VSTEditor::selectGroup(int idx) void VSTEditor::selectGroup(int idx)
{ {
m_selGroupIdx = idx;
m_backend.loadGroupSequencer(m_selCollectionIdx, m_selFileIdx, m_selGroupIdx);
m_backend.getFilePresenter().populatePageColumn(*this, m_selCollectionIdx, m_selFileIdx, m_selGroupIdx);
} }
void VSTEditor::selectPage(int idx) void VSTEditor::selectNormalPage(int idx)
{ {
m_backend.setNormalProgram(idx);
}
void VSTEditor::selectDrumPage(int idx)
{
m_backend.setDrumProgram(idx);
} }
} }

View File

@ -28,6 +28,13 @@ class VSTEditor : public AEffEditor
HWND m_groupListView; HWND m_groupListView;
HWND m_pageListView; HWND m_pageListView;
int m_selCollectionIdx = -1;
int m_selFileIdx = -1;
int m_selGroupIdx = -1;
int m_selPageIdx = -1;
HTREEITEM m_deferredCollectionSel = 0;
static LRESULT CALLBACK WindowProc( static LRESULT CALLBACK WindowProc(
_In_ HWND hwnd, _In_ HWND hwnd,
_In_ UINT uMsg, _In_ UINT uMsg,
@ -40,6 +47,8 @@ class VSTEditor : public AEffEditor
_In_ WPARAM wParam, _In_ WPARAM wParam,
_In_ LPARAM lParam _In_ LPARAM lParam
); );
void _reselectColumns();
public: public:
VSTEditor(VSTBackend& backend); VSTEditor(VSTBackend& backend);
@ -51,9 +60,10 @@ public:
void addAction(); void addAction();
void removeAction(); void removeAction();
void selectCollection(int idx); void selectCollection(LPARAM idx);
void selectGroup(int idx); void selectGroup(int idx);
void selectPage(int idx); void selectNormalPage(int idx);
void selectDrumPage(int idx);
}; };
} }