mirror of https://github.com/AxioDL/amuse.git
Initial VST FilePresenter implementation
This commit is contained in:
parent
6f538dc19c
commit
e4ae1f1f88
|
@ -0,0 +1,310 @@
|
|||
#include "AudioGroupFilePresenter.hpp"
|
||||
#include "VSTBackend.hpp"
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
||||
bool AudioGroupDataCollection::loadProj()
|
||||
{
|
||||
std::wstring path = m_path + L"\\proj";
|
||||
athena::io::FileReader r(path, 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return false;
|
||||
std::vector<uint8_t>& ret = m_projData;
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadPool()
|
||||
{
|
||||
std::wstring path = m_path + L"\\pool";
|
||||
athena::io::FileReader r(path, 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return false;
|
||||
std::vector<uint8_t>& ret = m_poolData;
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadSdir()
|
||||
{
|
||||
std::wstring path = m_path + L"\\sdir";
|
||||
athena::io::FileReader r(path, 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return false;
|
||||
std::vector<uint8_t>& ret = m_sdirData;
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadSamp()
|
||||
{
|
||||
std::wstring path = m_path + L"\\samp";
|
||||
athena::io::FileReader r(path, 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return false;
|
||||
std::vector<uint8_t>& ret = m_sampData;
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadMeta()
|
||||
{
|
||||
std::wstring path = m_path + L"\\meta";
|
||||
athena::io::FileReader r(path, 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return false;
|
||||
std::experimental::optional<MetaData>& ret = m_metaData;
|
||||
ret.emplace(r);
|
||||
return ret.operator bool();
|
||||
}
|
||||
|
||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::wstring& path, const std::wstring& name)
|
||||
: m_path(path), m_name(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter& presenter)
|
||||
{
|
||||
if (m_metaData && m_loadedData && m_loadedGroup)
|
||||
return true;
|
||||
if (!loadProj())
|
||||
return false;
|
||||
if (!loadPool())
|
||||
return false;
|
||||
if (!loadSdir())
|
||||
return false;
|
||||
if (!loadSamp())
|
||||
return false;
|
||||
if (!loadMeta())
|
||||
return false;
|
||||
|
||||
return _indexData(presenter);
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
|
||||
{
|
||||
amuse::Engine& engine = presenter.getBackend().getAmuseEngine();
|
||||
|
||||
switch (m_metaData->fmt)
|
||||
{
|
||||
case amuse::DataFormat::GCN:
|
||||
default:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
amuse::GCNDataTag{});
|
||||
break;
|
||||
case amuse::DataFormat::N64:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
m_metaData->absOffs, amuse::N64DataTag{});
|
||||
break;
|
||||
case amuse::DataFormat::PC:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
m_metaData->absOffs, amuse::PCDataTag{});
|
||||
break;
|
||||
}
|
||||
|
||||
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
|
||||
m_groupTokens.clear();
|
||||
if (m_loadedGroup)
|
||||
{
|
||||
m_groupTokens.reserve(m_loadedGroup->getProj().songGroups().size() +
|
||||
m_loadedGroup->getProj().sfxGroups().size());
|
||||
|
||||
{
|
||||
const auto& songGroups = m_loadedGroup->getProj().songGroups();
|
||||
std::map<int, const amuse::SongGroupIndex*> sortGroups;
|
||||
for (const auto& pair : songGroups)
|
||||
sortGroups[pair.first] = &pair.second;
|
||||
for (const auto& pair : sortGroups)
|
||||
m_groupTokens.emplace_back(pair.first, pair.second);
|
||||
}
|
||||
{
|
||||
const auto& sfxGroups = m_loadedGroup->getProj().sfxGroups();
|
||||
std::map<int, const amuse::SFXGroupIndex*> sortGroups;
|
||||
for (const auto& pair : sfxGroups)
|
||||
sortGroups[pair.first] = &pair.second;
|
||||
for (const auto& pair : sortGroups)
|
||||
m_groupTokens.emplace_back(pair.first, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
return m_loadedData && m_loadedGroup;
|
||||
}
|
||||
|
||||
AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::wstring& name)
|
||||
: m_path(path), m_name(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AudioGroupCollection::addCollection(AudioGroupFilePresenter& presenter,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||
{
|
||||
for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection)
|
||||
{
|
||||
std::wstring collectionPath = m_path + L'\\' + pair.first;
|
||||
|
||||
amuse::IntrusiveAudioGroupData& dataIn = pair.second;
|
||||
auto search = m_groups.find(pair.first);
|
||||
if (search == m_groups.end())
|
||||
{
|
||||
search = m_groups.emplace(pair.first,
|
||||
std::make_unique<AudioGroupDataCollection>(collectionPath,
|
||||
pair.first)).first;
|
||||
}
|
||||
|
||||
AudioGroupDataCollection& dataCollection = *search->second;
|
||||
dataCollection.m_projData.resize(dataIn.getProjSize());
|
||||
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
|
||||
|
||||
dataCollection.m_poolData.resize(dataIn.getPoolSize());
|
||||
memmove(dataCollection.m_poolData.data(), dataIn.getPool(), dataIn.getPoolSize());
|
||||
|
||||
dataCollection.m_sdirData.resize(dataIn.getSdirSize());
|
||||
memmove(dataCollection.m_sdirData.data(), dataIn.getSdir(), dataIn.getSdirSize());
|
||||
|
||||
dataCollection.m_sampData.resize(dataIn.getSampSize());
|
||||
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
|
||||
|
||||
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
|
||||
dataCollection._indexData(presenter);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioGroupCollection::update(AudioGroupFilePresenter& presenter)
|
||||
{
|
||||
std::wstring path = m_path + L"\\*";
|
||||
|
||||
WIN32_FIND_DATAW d;
|
||||
HANDLE dir = FindFirstFileW(path.c_str(), &d);
|
||||
if (dir == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
do
|
||||
{
|
||||
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L".."))
|
||||
continue;
|
||||
|
||||
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
std::wstring nameStr(d.cFileName);
|
||||
auto search = m_groups.find(nameStr);
|
||||
if (search == m_groups.end())
|
||||
{
|
||||
search =
|
||||
m_groups.emplace(nameStr,
|
||||
std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr,
|
||||
nameStr)).first;
|
||||
search->second->_attemptLoad(presenter);
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(dir, &d));
|
||||
|
||||
FindClose(dir);
|
||||
}
|
||||
|
||||
void AudioGroupFilePresenter::update()
|
||||
{
|
||||
std::wstring path = m_backend.getUserDir() + L"\\*";
|
||||
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>& theMap = m_audioGroupCollections;
|
||||
|
||||
WIN32_FIND_DATAW d;
|
||||
HANDLE dir = FindFirstFileW(path.c_str(), &d);
|
||||
if (dir == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
do
|
||||
{
|
||||
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L".."))
|
||||
continue;
|
||||
|
||||
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
std::wstring nameStr(d.cFileName);
|
||||
auto search = theMap.find(nameStr);
|
||||
if (search == theMap.end())
|
||||
{
|
||||
search = theMap.emplace(nameStr,
|
||||
std::make_unique<AudioGroupCollection>(m_backend.getUserDir() + L'\\' + nameStr, nameStr)).first;
|
||||
search->second->update(*this);
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(dir, &d));
|
||||
|
||||
FindClose(dir);
|
||||
}
|
||||
|
||||
void AudioGroupFilePresenter::addCollection(const std::wstring& name,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||
{
|
||||
std::wstring path = m_backend.getUserDir() + L'\\' + name;
|
||||
AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second;
|
||||
insert.addCollection(*this, std::move(collection));
|
||||
|
||||
for (std::pair<const std::wstring, std::unique_ptr<AudioGroupDataCollection>>& pair : insert.m_groups)
|
||||
{
|
||||
std::wstring collectionPath = insert.m_path + L'\\' + pair.first;
|
||||
CreateDirectory(collectionPath.c_str(), nullptr);
|
||||
|
||||
FILE* fp = _wfopen((collectionPath + L"\\proj").c_str(), L"wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second->m_projData.data(), 1, pair.second->m_projData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = _wfopen((collectionPath + L"\\pool").c_str(), L"wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second->m_poolData.data(), 1, pair.second->m_poolData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = _wfopen((collectionPath + L"\\sdir").c_str(), L"wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second->m_sdirData.data(), 1, pair.second->m_sdirData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = _wfopen((collectionPath + L"\\samp").c_str(), L"wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second->m_sampData.data(), 1, pair.second->m_sampData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = _wfopen((collectionPath + L"\\meta").c_str(), L"wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(&*pair.second->m_metaData, 1, sizeof(*pair.second->m_metaData), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioGroupFilePresenter::populateEditor(VSTEditor& editor)
|
||||
{
|
||||
for (const auto& cgollection : m_audioGroupCollections)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__
|
||||
#define __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "optional.hpp"
|
||||
#include <amuse/amuse.hpp>
|
||||
#include <athena/FileReader.hpp>
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
class VSTBackend;
|
||||
class VSTEditor;
|
||||
class AudioGroupFilePresenter;
|
||||
|
||||
struct AudioGroupDataCollection
|
||||
{
|
||||
std::wstring m_path;
|
||||
std::wstring m_name;
|
||||
|
||||
std::vector<uint8_t> m_projData;
|
||||
std::vector<uint8_t> m_poolData;
|
||||
std::vector<uint8_t> m_sdirData;
|
||||
std::vector<uint8_t> m_sampData;
|
||||
|
||||
struct MetaData
|
||||
{
|
||||
amuse::DataFormat fmt;
|
||||
uint32_t absOffs;
|
||||
uint32_t active;
|
||||
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
|
||||
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {}
|
||||
MetaData(athena::io::FileReader& r)
|
||||
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {}
|
||||
};
|
||||
std::experimental::optional<MetaData> m_metaData;
|
||||
|
||||
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
|
||||
const amuse::AudioGroup* m_loadedGroup;
|
||||
struct GroupToken
|
||||
{
|
||||
int m_groupId;
|
||||
const amuse::SongGroupIndex* m_song = nullptr;
|
||||
const amuse::SFXGroupIndex* m_sfx = nullptr;
|
||||
GroupToken(int id, const amuse::SongGroupIndex* song) : m_groupId(id), m_song(song) {}
|
||||
GroupToken(int id, const amuse::SFXGroupIndex* sfx) : m_groupId(id), m_sfx(sfx) {}
|
||||
};
|
||||
std::vector<GroupToken> m_groupTokens;
|
||||
|
||||
bool loadProj();
|
||||
bool loadPool();
|
||||
bool loadSdir();
|
||||
bool loadSamp();
|
||||
bool loadMeta();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
struct AudioGroupCollection
|
||||
{
|
||||
std::wstring m_path;
|
||||
std::wstring m_name;
|
||||
|
||||
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
||||
|
||||
AudioGroupCollection(const std::wstring& path, const std::wstring& name);
|
||||
void addCollection(AudioGroupFilePresenter& presenter,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
void update(AudioGroupFilePresenter& presenter);
|
||||
|
||||
//void populate
|
||||
};
|
||||
|
||||
class AudioGroupFilePresenter
|
||||
{
|
||||
VSTBackend& m_backend;
|
||||
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
|
||||
public:
|
||||
AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {}
|
||||
void update();
|
||||
void populateEditor(VSTEditor& editor);
|
||||
void addCollection(const std::wstring& name,
|
||||
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
VSTBackend& getBackend() {return m_backend;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__
|
|
@ -7,10 +7,12 @@ if (WIN32 AND (EXISTS ${VST3_SDK_ROOT}))
|
|||
add_library(amuse-vst SHARED
|
||||
VSTBackend.hpp VSTBackend.cpp
|
||||
VSTEditor.hpp VSTEditor.cpp
|
||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.cpp
|
||||
${VST2_DIR}/vstplugmain.cpp
|
||||
${VST2_DIR}/audioeffect.cpp
|
||||
${VST2_DIR}/audioeffectx.cpp)
|
||||
${VST2_DIR}/audioeffectx.cpp
|
||||
FileOpenDialog.hpp FileOpenDialog.cpp)
|
||||
target_link_libraries(amuse-vst amuse boo soxr ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS}
|
||||
Msimg32 logvisor athena-core)
|
||||
Msimg32 Shlwapi logvisor athena-core)
|
||||
set_target_properties(amuse-vst PROPERTIES LINK_FLAGS "/EXPORT:VSTPluginMain")
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
#include "FileOpenDialog.hpp"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h> // For common windows data types and function headers
|
||||
#define STRICT_TYPED_ITEMIDS
|
||||
#include <objbase.h> // For COM headers
|
||||
#include <shobjidl.h> // for IFileDialogEvents and IFileDialogControlEvents
|
||||
#include <shlwapi.h>
|
||||
#include <knownfolders.h> // for KnownFolder APIs/datatypes/function headers
|
||||
#include <propvarutil.h> // for PROPVAR-related functions
|
||||
#include <propkey.h> // for the Property key APIs/datatypes
|
||||
#include <propidl.h> // for the Property System APIs
|
||||
#include <strsafe.h> // for StringCchPrintfW
|
||||
#include <shtypes.h> // for COMDLG_FILTERSPEC
|
||||
#include <new>
|
||||
|
||||
// Controls
|
||||
#define CONTROL_GROUP 2000
|
||||
#define CONTROL_RADIOBUTTONLIST 2
|
||||
#define CONTROL_RADIOBUTTON1 1
|
||||
#define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same IDas CONTROL_RADIOBUTTONLIST,
|
||||
// because it is a child control under CONTROL_RADIOBUTTONLIST
|
||||
|
||||
// IDs for the Task Dialog Buttons
|
||||
#define IDC_BASICFILEOPEN 100
|
||||
#define IDC_ADDITEMSTOCUSTOMPLACES 101
|
||||
#define IDC_ADDCUSTOMCONTROLS 102
|
||||
#define IDC_SETDEFAULTVALUESFORPROPERTIES 103
|
||||
#define IDC_WRITEPROPERTIESUSINGHANDLERS 104
|
||||
#define IDC_WRITEPROPERTIESWITHOUTUSINGHANDLERS 105
|
||||
|
||||
HWND ghMainWnd = 0;
|
||||
HINSTANCE ghAppInst = 0;
|
||||
RECT winRect;
|
||||
|
||||
class CDialogEventHandler : public IFileDialogEvents,
|
||||
public IFileDialogControlEvents
|
||||
{
|
||||
public:
|
||||
// IUnknown methods
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(CDialogEventHandler, IFileDialogEvents),
|
||||
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
long cRef = InterlockedDecrement(&_cRef);
|
||||
if (!cRef)
|
||||
delete this;
|
||||
return cRef;
|
||||
}
|
||||
|
||||
// IFileDialogEvents methods
|
||||
IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; };
|
||||
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
|
||||
IFACEMETHODIMP OnTypeChange(IFileDialog *pfd);
|
||||
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
|
||||
|
||||
// IFileDialogControlEvents methods
|
||||
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem);
|
||||
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
|
||||
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; };
|
||||
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
|
||||
|
||||
CDialogEventHandler() : _cRef(1) { };
|
||||
private:
|
||||
~CDialogEventHandler() { };
|
||||
long _cRef;
|
||||
};
|
||||
|
||||
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv);
|
||||
|
||||
std::wstring openDB()
|
||||
{
|
||||
std::wstring ret;
|
||||
|
||||
//Cocreate the file open dialog object
|
||||
IFileDialog *pfd = NULL;
|
||||
|
||||
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Stuff needed for later
|
||||
const COMDLG_FILTERSPEC rgFExt[] = {{L"Audio Group Archive (*.*)", L"*.*"}};
|
||||
|
||||
//Create event handling
|
||||
IFileDialogEvents *pfde = NULL;
|
||||
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
//Hook the event handler
|
||||
DWORD dwCookie;
|
||||
|
||||
hr = pfd->Advise(pfde, &dwCookie);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Set options for the dialog
|
||||
DWORD dwFlags;
|
||||
|
||||
//Get options first so we do not override
|
||||
hr = pfd->GetOptions(&dwFlags);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Get shell items only
|
||||
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Types of files to display (not default)
|
||||
hr = pfd->SetFileTypes(ARRAYSIZE(rgFExt), rgFExt);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Set default file type to display
|
||||
//hr = pfd->SetDefaultExtension(L"sqlite");
|
||||
|
||||
//if (SUCCEEDED(hr))
|
||||
//{
|
||||
//Show dialog
|
||||
hr = pfd->Show(NULL);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Get the result once the user clicks on open
|
||||
IShellItem *result;
|
||||
|
||||
hr = pfd->GetResult(&result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//Print out the file name
|
||||
PWSTR fName = NULL;
|
||||
|
||||
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &fName);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ret.assign(fName);
|
||||
CoTaskMemFree(fName);
|
||||
}
|
||||
|
||||
result->Release();
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pfd->Unadvise(dwCookie);
|
||||
}
|
||||
|
||||
pfde->Release();
|
||||
}
|
||||
|
||||
pfd->Release();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
|
||||
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pDialogEventHandler->QueryInterface(riid, ppv);
|
||||
pDialogEventHandler->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CDialogEventHandler::OnTypeChange(IFileDialog *pfd)
|
||||
{
|
||||
IFileSaveDialog *pfsd;
|
||||
HRESULT hr = pfd->QueryInterface(&pfsd);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
UINT uIndex;
|
||||
hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IPropertyDescriptionList *pdl = NULL;
|
||||
|
||||
|
||||
}
|
||||
pfsd->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
// IFileDialogControlEvents
|
||||
// This method gets called when an dialog control item selection happens (radio-button selection. etc).
|
||||
// For sample sake, let's react to this event by changing the dialog title.
|
||||
HRESULT CDialogEventHandler::OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem)
|
||||
{
|
||||
IFileDialog *pfd = NULL;
|
||||
HRESULT hr = pfdc->QueryInterface(&pfd);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (dwIDCtl == CONTROL_RADIOBUTTONLIST)
|
||||
{
|
||||
switch (dwIDItem)
|
||||
{
|
||||
case CONTROL_RADIOBUTTON1:
|
||||
hr = pfd->SetTitle(L"Longhorn Dialog");
|
||||
break;
|
||||
|
||||
case CONTROL_RADIOBUTTON2:
|
||||
hr = pfd->SetTitle(L"Vista Dialog");
|
||||
break;
|
||||
}
|
||||
}
|
||||
pfd->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __AMUSE_FILEOPENDIALOG_HPP__
|
||||
#define __AMUSE_FILEOPENDIALOG_HPP__
|
||||
|
||||
#include <string>
|
||||
|
||||
std::wstring openDB();
|
||||
|
||||
#endif // __AMUSE_FILEOPENDIALOG_HPP__
|
|
@ -1,5 +1,6 @@
|
|||
#include "VSTBackend.hpp"
|
||||
#include "audiodev/AudioVoiceEngine.hpp"
|
||||
#include <Shlobj.h>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
|
||||
|
@ -141,6 +142,13 @@ VSTBackend::VSTBackend(audioMasterCallback cb)
|
|||
m_booBackend = std::make_unique<VSTVoiceEngine>();
|
||||
m_voxAlloc.emplace(*m_booBackend);
|
||||
m_engine.emplace(*m_voxAlloc);
|
||||
|
||||
WCHAR path[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path)))
|
||||
{
|
||||
m_userDir = std::wstring(path) + L"\\Amuse";
|
||||
CreateDirectory(m_userDir.c_str(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
VSTBackend::~VSTBackend()
|
||||
|
|
|
@ -31,6 +31,7 @@ class VSTBackend : public AudioEffectX
|
|||
std::experimental::optional<amuse::VSTBackendVoiceAllocator> m_voxAlloc;
|
||||
std::experimental::optional<amuse::Engine> m_engine;
|
||||
size_t m_curFrame = 0;
|
||||
std::wstring m_userDir;
|
||||
VSTEditor m_editor;
|
||||
public:
|
||||
VSTBackend(audioMasterCallback cb);
|
||||
|
@ -48,6 +49,9 @@ public:
|
|||
VstInt32 getNumMidiInputChannels();
|
||||
void setSampleRate(float sampleRate);
|
||||
void setBlockSize(VstInt32 blockSize);
|
||||
|
||||
amuse::Engine& getAmuseEngine() {return *m_engine;}
|
||||
const std::wstring& getUserDir() const {return m_userDir;}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "VSTEditor.hpp"
|
||||
#include "VSTBackend.hpp"
|
||||
#include "FileOpenDialog.hpp"
|
||||
#include <Windowsx.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
extern void* hInstance;
|
||||
static WNDPROC OriginalListViewProc = 0;
|
||||
|
@ -45,6 +48,31 @@ LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
|
|||
editor.selectPage(itemAct.iItem);
|
||||
return 0;
|
||||
}
|
||||
case TVN_GETDISPINFO:
|
||||
{
|
||||
NMTVDISPINFO& treeDispInfo = *reinterpret_cast<LPNMTVDISPINFO>(lParam);
|
||||
if (treeDispInfo.item.mask & TVIF_CHILDREN)
|
||||
{
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
switch (HIWORD(wParam))
|
||||
{
|
||||
case BN_CLICKED:
|
||||
{
|
||||
HWND button = HWND(lParam);
|
||||
if (button == editor.m_collectionAdd)
|
||||
editor.addAction();
|
||||
else if (button == editor.m_collectionRemove)
|
||||
editor.removeAction();
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
@ -137,34 +165,56 @@ bool VSTEditor::open(void* ptr)
|
|||
SetWindowLongPtrW(m_rootView, 0, LONG_PTR(this));
|
||||
ShowWindow(m_rootView, SW_SHOW);
|
||||
|
||||
TVINSERTSTRUCT treeItem = {};
|
||||
treeItem.hParent = TVI_ROOT;
|
||||
treeItem.hInsertAfter = TVI_LAST;
|
||||
|
||||
treeItem.item.mask = TVIF_CHILDREN | TVIF_TEXT;
|
||||
treeItem.item.cChildren = 1;
|
||||
treeItem.item.pszText = L"Root A";
|
||||
|
||||
LVCOLUMN column = {};
|
||||
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
|
||||
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
|
||||
column.cx = 200;
|
||||
column.cx = 199;
|
||||
|
||||
LVITEM item = {};
|
||||
item.mask = LVIF_TEXT | LVIF_GROUPID;
|
||||
item.mask = LVIF_TEXT;
|
||||
item.pszText = L"Test";
|
||||
item.iGroupId = 1;
|
||||
|
||||
m_collectionTree = CreateWindowW(WC_TREEVIEW,
|
||||
L"",
|
||||
WS_CHILD | WS_BORDER | TVS_HASLINES,
|
||||
0, 24,
|
||||
201,
|
||||
m_windowRect.bottom - m_windowRect.top - 24,
|
||||
WS_CHILD | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS,
|
||||
1, 25,
|
||||
199,
|
||||
m_windowRect.bottom - m_windowRect.top - 26,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
TreeView_SetBkColor(m_collectionTree, RGB(64,64,64));
|
||||
TreeView_SetTextColor(m_collectionTree, RGB(255,255,255));
|
||||
HTREEITEM rootItemA = TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
treeItem.item.pszText = L"Root B";
|
||||
HTREEITEM rootItemB = TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
treeItem.hParent = rootItemA;
|
||||
treeItem.item.cChildren = 0;
|
||||
treeItem.item.pszText = L"Child A";
|
||||
TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
treeItem.item.pszText = L"Child B";
|
||||
TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
treeItem.hParent = rootItemB;
|
||||
treeItem.item.pszText = L"Child A";
|
||||
TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
treeItem.item.pszText = L"Child B";
|
||||
TreeView_InsertItem(m_collectionTree, &treeItem);
|
||||
ShowWindow(m_collectionTree, SW_SHOW);
|
||||
|
||||
m_collectionHeader = CreateWindowW(WC_HEADER,
|
||||
L"",
|
||||
WS_CHILD,
|
||||
1, 1,
|
||||
200,
|
||||
199,
|
||||
24,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
|
@ -174,12 +224,39 @@ bool VSTEditor::open(void* ptr)
|
|||
OriginalListViewProc = WNDPROC(SetWindowLongPtr(m_collectionHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
|
||||
ShowWindow(m_collectionHeader, SW_SHOW);
|
||||
|
||||
m_collectionAdd = CreateWindowW(WC_BUTTON,
|
||||
L"+",
|
||||
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON,
|
||||
1, m_windowRect.bottom - m_windowRect.top - 26,
|
||||
25, 24,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
SetWindowFont(m_collectionAdd, GetStockObject(ANSI_FIXED_FONT), FALSE);
|
||||
Button_Enable(m_collectionAdd, TRUE);
|
||||
SetWindowPos(m_collectionAdd, HWND_TOP, 1, m_windowRect.bottom - m_windowRect.top - 26, 25, 24, SWP_SHOWWINDOW);
|
||||
|
||||
m_collectionRemove = CreateWindowW(WC_BUTTON,
|
||||
L"-",
|
||||
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON,
|
||||
26, m_windowRect.bottom - m_windowRect.top - 26,
|
||||
25, 24,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE);
|
||||
Button_Enable(m_collectionRemove, TRUE);
|
||||
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 | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
200, 0,
|
||||
201,
|
||||
m_windowRect.bottom - m_windowRect.top,
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
201, 1,
|
||||
199,
|
||||
m_windowRect.bottom - m_windowRect.top - 2,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -189,25 +266,32 @@ bool VSTEditor::open(void* ptr)
|
|||
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
|
||||
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
|
||||
ListView_SetBkColor(m_groupListView, RGB(64,64,64));
|
||||
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 | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
400, 0,
|
||||
200,
|
||||
m_windowRect.bottom - m_windowRect.top,
|
||||
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
|
||||
401, 1,
|
||||
198,
|
||||
m_windowRect.bottom - m_windowRect.top - 2,
|
||||
m_rootView,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
column.pszText = L"Page";
|
||||
column.cx = 198;
|
||||
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_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);
|
||||
|
||||
return true;
|
||||
|
@ -224,6 +308,31 @@ void VSTEditor::update()
|
|||
|
||||
}
|
||||
|
||||
void VSTEditor::addAction()
|
||||
{
|
||||
VstFileSelect fSelect = {};
|
||||
fSelect.command = kVstFileLoad;
|
||||
fSelect.type = kVstFileType;
|
||||
strcpy(fSelect.title, "Select Audio Group Archive");
|
||||
if (m_backend.openFileSelector(&fSelect))
|
||||
{
|
||||
m_backend.closeFileSelector(&fSelect);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring path = openDB();
|
||||
if (path.size())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VSTEditor::removeAction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VSTEditor::selectCollection(int idx)
|
||||
{
|
||||
|
||||
|
|
|
@ -14,12 +14,16 @@ class VSTBackend;
|
|||
/** Editor UI class */
|
||||
class VSTEditor : public AEffEditor
|
||||
{
|
||||
friend class AudioGroupFilePresenter;
|
||||
|
||||
VSTBackend& m_backend;
|
||||
ERect m_windowRect = {0, 0, 420, 600};
|
||||
|
||||
HWND m_rootView;
|
||||
HWND m_collectionHeader;
|
||||
HWND m_collectionTree;
|
||||
HWND m_collectionAdd;
|
||||
HWND m_collectionRemove;
|
||||
HWND m_groupListView;
|
||||
HWND m_pageListView;
|
||||
|
||||
|
@ -43,6 +47,9 @@ public:
|
|||
void close();
|
||||
void update();
|
||||
|
||||
void addAction();
|
||||
void removeAction();
|
||||
|
||||
void selectCollection(int idx);
|
||||
void selectGroup(int idx);
|
||||
void selectPage(int idx);
|
||||
|
|
Loading…
Reference in New Issue