mirror of https://github.com/AxioDL/amuse.git
VST UI logic complete, needs some audio output debugging
This commit is contained in:
parent
fa3007b65c
commit
e7c7e5ffd3
|
@ -1,9 +1,48 @@
|
|||
#include "AudioGroupFilePresenter.hpp"
|
||||
#include "VSTBackend.hpp"
|
||||
#include <Shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
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()
|
||||
{
|
||||
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)
|
||||
return true;
|
||||
|
@ -88,13 +127,11 @@ bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter& presenter)
|
|||
if (!loadMeta())
|
||||
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)
|
||||
{
|
||||
case amuse::DataFormat::GCN:
|
||||
|
@ -121,6 +158,11 @@ bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
|
|||
break;
|
||||
}
|
||||
|
||||
return m_loadedData.operator bool();
|
||||
}
|
||||
|
||||
void AudioGroupDataCollection::addToEngine(amuse::Engine& engine)
|
||||
{
|
||||
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
|
||||
m_groupTokens.clear();
|
||||
if (m_loadedGroup)
|
||||
|
@ -145,8 +187,11 @@ bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
|
|||
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)
|
||||
|
@ -155,8 +200,7 @@ AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::
|
|||
|
||||
}
|
||||
|
||||
void AudioGroupCollection::addCollection(AudioGroupFilePresenter& presenter,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||
void AudioGroupCollection::addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& 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());
|
||||
|
||||
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,
|
||||
std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr,
|
||||
nameStr)).first;
|
||||
search->second->_attemptLoad(presenter);
|
||||
search->second->_attemptLoad();
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(dir, &d));
|
||||
|
@ -256,7 +300,7 @@ void AudioGroupFilePresenter::addCollection(const std::wstring& name,
|
|||
std::wstring path = m_backend.getUserDir() + L'\\' + name;
|
||||
AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second;
|
||||
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)
|
||||
{
|
||||
|
@ -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 = {};
|
||||
ins.item.mask = TVIF_TEXT;
|
||||
ins.item.mask = TVIF_TEXT | TVIF_PARAM;
|
||||
ins.hParent = colHandle;
|
||||
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());
|
||||
TreeView_InsertItem(editor.m_collectionTree, &ins);
|
||||
ins.item.pszText = LPWSTR(it->first.c_str());
|
||||
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);
|
||||
TVINSERTSTRUCT ins = {};
|
||||
ins.hParent = TVI_ROOT;
|
||||
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.pszText = LPWSTR(collection.first.c_str());
|
||||
ins.item.cChildren = it->second->m_groups.size() ? 1 : 0;
|
||||
ins.item.pszText = LPWSTR(it->first.c_str());
|
||||
ins.item.lParam = LPARAM(m_iteratorVec.size() << 16);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,34 +59,46 @@ struct AudioGroupDataCollection
|
|||
|
||||
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 _attemptLoad(AudioGroupFilePresenter& presenter);
|
||||
bool _indexData(AudioGroupFilePresenter& presenter);
|
||||
bool _attemptLoad();
|
||||
bool _indexData();
|
||||
|
||||
void addToEngine(amuse::Engine& engine);
|
||||
void removeFromEngine(amuse::Engine& engine) const;
|
||||
};
|
||||
|
||||
struct AudioGroupCollection
|
||||
{
|
||||
using GroupIterator = std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>>::iterator;
|
||||
std::wstring m_path;
|
||||
std::wstring m_name;
|
||||
|
||||
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
||||
std::vector<GroupIterator> m_iteratorVec;
|
||||
|
||||
AudioGroupCollection(const std::wstring& path, const std::wstring& name);
|
||||
void addCollection(AudioGroupFilePresenter& presenter,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
void addCollection(std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
void update(AudioGroupFilePresenter& presenter);
|
||||
void populateFiles(VSTEditor& editor, HTREEITEM colHandle);
|
||||
void populateFiles(VSTEditor& editor, HTREEITEM colHandle, size_t parentIdx);
|
||||
};
|
||||
|
||||
class AudioGroupFilePresenter
|
||||
{
|
||||
friend class VSTBackend;
|
||||
public:
|
||||
using CollectionIterator = std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>::iterator;
|
||||
private:
|
||||
VSTBackend& m_backend;
|
||||
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
|
||||
std::vector<CollectionIterator> m_iteratorVec;
|
||||
public:
|
||||
AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {}
|
||||
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,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
void removeCollection(unsigned idx);
|
||||
VSTBackend& getBackend() {return m_backend;}
|
||||
};
|
||||
|
||||
|
|
|
@ -280,6 +280,49 @@ void VSTBackend::setBlockSize(VstInt32 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)
|
||||
|
|
|
@ -31,6 +31,8 @@ class VSTBackend : public AudioEffectX
|
|||
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
|
||||
std::experimental::optional<amuse::VSTBackendVoiceAllocator> m_voxAlloc;
|
||||
std::experimental::optional<amuse::Engine> m_engine;
|
||||
std::shared_ptr<amuse::Sequencer> m_curSeq;
|
||||
const AudioGroupDataCollection* m_curData = nullptr;
|
||||
size_t m_curFrame = 0;
|
||||
std::wstring m_userDir;
|
||||
AudioGroupFilePresenter m_filePresenter;
|
||||
|
@ -55,6 +57,10 @@ public:
|
|||
amuse::Engine& getAmuseEngine() {return *m_engine;}
|
||||
const std::wstring& getUserDir() const {return m_userDir;}
|
||||
AudioGroupFilePresenter& getFilePresenter() {return m_filePresenter;}
|
||||
|
||||
void loadGroupSequencer(int collectionIdx, int fileIdx, int groupIdx);
|
||||
void setNormalProgram(int programNo);
|
||||
void setDrumProgram(int programNo);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -44,12 +44,22 @@ LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
|
|||
case NM_CLICK:
|
||||
{
|
||||
NMITEMACTIVATE& itemAct = *reinterpret_cast<LPNMITEMACTIVATE>(lParam);
|
||||
if (itemAct.hdr.hwndFrom == editor.m_collectionTree)
|
||||
editor.selectCollection(itemAct.iItem);
|
||||
else if (itemAct.hdr.hwndFrom == editor.m_groupListView)
|
||||
if (itemAct.hdr.hwndFrom == editor.m_groupListView)
|
||||
editor.selectGroup(itemAct.iItem);
|
||||
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;
|
||||
}
|
||||
case TVN_GETDISPINFO:
|
||||
|
@ -135,6 +145,19 @@ LRESULT CALLBACK VSTEditor::ColHeaderWindowProc(HWND hwnd,
|
|||
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)
|
||||
{
|
||||
AEffEditor::open(ptr);
|
||||
|
@ -182,13 +205,9 @@ bool VSTEditor::open(void* ptr)
|
|||
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
|
||||
column.cx = 199;
|
||||
|
||||
LVITEM item = {};
|
||||
item.mask = LVIF_TEXT;
|
||||
item.pszText = L"Test";
|
||||
|
||||
m_collectionTree = CreateWindowW(WC_TREEVIEW,
|
||||
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,
|
||||
199,
|
||||
m_windowRect.bottom - m_windowRect.top - 26,
|
||||
|
@ -251,13 +270,13 @@ bool VSTEditor::open(void* ptr)
|
|||
nullptr,
|
||||
nullptr);
|
||||
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);
|
||||
|
||||
|
||||
m_groupListView = CreateWindowW(WC_LISTVIEW,
|
||||
L"",
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER,
|
||||
201, 1,
|
||||
199,
|
||||
m_windowRect.bottom - m_windowRect.top - 2,
|
||||
|
@ -273,12 +292,11 @@ bool VSTEditor::open(void* ptr)
|
|||
ListView_SetTextBkColor(m_groupListView, CLR_NONE);
|
||||
ListView_SetTextColor(m_groupListView, RGB(255,255,255));
|
||||
ListView_InsertColumn(m_groupListView, 0, &column);
|
||||
ListView_InsertItem(m_groupListView, &item);
|
||||
ShowWindow(m_groupListView, SW_SHOW);
|
||||
|
||||
m_pageListView = CreateWindowW(WC_LISTVIEW,
|
||||
L"",
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER,
|
||||
401, 1,
|
||||
198,
|
||||
m_windowRect.bottom - m_windowRect.top - 2,
|
||||
|
@ -295,10 +313,12 @@ bool VSTEditor::open(void* ptr)
|
|||
ListView_SetTextBkColor(m_pageListView, CLR_NONE);
|
||||
ListView_SetTextColor(m_pageListView, RGB(255,255,255));
|
||||
ListView_InsertColumn(m_pageListView, 0, &column);
|
||||
ListView_InsertItem(m_pageListView, &item);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -346,28 +366,62 @@ void VSTEditor::addAction()
|
|||
}
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,13 @@ class VSTEditor : public AEffEditor
|
|||
HWND m_groupListView;
|
||||
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(
|
||||
_In_ HWND hwnd,
|
||||
_In_ UINT uMsg,
|
||||
|
@ -40,6 +47,8 @@ class VSTEditor : public AEffEditor
|
|||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
);
|
||||
|
||||
void _reselectColumns();
|
||||
public:
|
||||
VSTEditor(VSTBackend& backend);
|
||||
|
||||
|
@ -51,9 +60,10 @@ public:
|
|||
void addAction();
|
||||
void removeAction();
|
||||
|
||||
void selectCollection(int idx);
|
||||
void selectCollection(LPARAM idx);
|
||||
void selectGroup(int idx);
|
||||
void selectPage(int idx);
|
||||
void selectNormalPage(int idx);
|
||||
void selectDrumPage(int idx);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue