Skip to content

Commit

Permalink
An unacceptable workflow which allows missing sample resolution
Browse files Browse the repository at this point in the history
1. If samples are missing at load time the screen has a 'resolve
   first' button which lets you pick the first in the list. If two
   are missing, press the button again after you resolve the first.
   obviously bad ui. But
2. If you do that the sample gets resolved and replaced and remapped
3. To do this added a path hash to the sample id and also did quite
   a bit of work cleaning up aliasing, loading, purging, api etc
   to make sure the right stuff happens at the right time
4. Along the way make the find-missing to be all samples in the
   sample db which are missing and not purged as opposed to
   traversing tree looking for attachment to same
  • Loading branch information
baconpaul committed Sep 26, 2024
1 parent d7ea00f commit 51b2682
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 62 deletions.
15 changes: 9 additions & 6 deletions src-ui/app/editor-impl/SCXTEditorResponseHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,15 +423,18 @@ void SCXTEditor::onMissingResolutionWorkItemList(
for (const auto &wi : items)
{
SCLOG("Missing resolution work item");
SCLOG(" path : " << wi.path.u8string());
SCLOG(" zone : " << wi.address);
SCLOG(" var : " << wi.variant);
SCLOG(" md5 : " << wi.md5sum);
SCLOG(" path : " << wi.path.u8string());
SCLOG(" id : " << wi.missingID.to_string());
}

if (!items.empty())
missingResolutionScreen->setWorkItemList(items);

if (items.empty())
{
missingResolutionScreen->setVisible(false);
}
else
{
missingResolutionScreen->setWorkItemList(items);
missingResolutionScreen->setBounds(getLocalBounds());
missingResolutionScreen->setVisible(true);
missingResolutionScreen->toFront(true);
Expand Down
45 changes: 43 additions & 2 deletions src-ui/app/missing-resolution/MissingResolutionScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace scxt::ui::app::missing_resolution
struct Contents : juce::Component, HasEditor
{
MissingResolutionScreen *parent{nullptr};
std::unique_ptr<sst::jucegui::components::TextPushButton> okButton;
std::unique_ptr<sst::jucegui::components::TextPushButton> okButton, resolveZeroButton;
Contents(MissingResolutionScreen *p, SCXTEditor *e) : parent(p), HasEditor(e)
{
okButton = std::make_unique<sst::jucegui::components::TextPushButton>();
Expand All @@ -48,13 +48,25 @@ struct Contents : juce::Component, HasEditor
w->setVisible(false);
});
addAndMakeVisible(*okButton);

resolveZeroButton = std::make_unique<sst::jucegui::components::TextPushButton>();
resolveZeroButton->setLabel("Resolve First");
resolveZeroButton->setOnCallback([w = juce::Component::SafePointer(parent)]() {
if (!w)
return;

w->resolveItem(0);
});
addAndMakeVisible(*resolveZeroButton);
}

void resized() override
{
auto b = getLocalBounds();
b = b.withTrimmedTop(b.getHeight() - 22).withTrimmedLeft(b.getWidth() - 100);
okButton->setBounds(b);

resolveZeroButton->setBounds(b.translated(-110, 0));
}
void paint(juce::Graphics &g) override
{
Expand All @@ -69,7 +81,7 @@ struct Contents : juce::Component, HasEditor

g.setFont(editor->themeApplier.interMediumFor(12));
g.setColour(editor->themeColor(theme::ColorMap::generic_content_medium));
g.drawText(i.md5sum, bd, juce::Justification::bottomLeft);
g.drawText(i.missingID.md5, bd, juce::Justification::bottomLeft);

g.setColour(editor->themeColor(theme::ColorMap::generic_content_low));
g.drawRect(bx, 1);
Expand All @@ -94,4 +106,33 @@ void MissingResolutionScreen::resized()
contentsArea->setBounds(getLocalBounds().reduced(100, 80));
}

void MissingResolutionScreen::resolveItem(int idx)
{
SCLOG("Resoving item " << idx);
const auto &wi = workItems[idx];

fileChooser =
std::make_unique<juce::FileChooser>("Resolve sample " + wi.path.filename().u8string());
fileChooser->launchAsync(
juce::FileBrowserComponent::canSelectFiles | juce::FileBrowserComponent::openMode,
[idx, w = juce::Component::SafePointer(this)](const juce::FileChooser &c) {
auto result = c.getResults();
if (result.isEmpty() || result.size() > 1)
{
return;
}
if (!w)
return;
auto p = fs::path(fs::u8path(result[0].getFullPathName().toStdString()));
w->applyResolution(idx, p);
});
}

void MissingResolutionScreen::applyResolution(int idx, const fs::path &toThis)
{
SCLOG("Resolving item " << idx << " with " << toThis.u8string());
sendToSerialization(
scxt::messaging::client::ResolveSample({workItems[idx], toThis.u8string()}));
}

} // namespace scxt::ui::app::missing_resolution
5 changes: 5 additions & 0 deletions src-ui/app/missing-resolution/MissingResolutionScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ struct MissingResolutionScreen : juce::Component, HasEditor
repaint();
}

void resolveItem(int idx);
void applyResolution(int idx, const fs::path &toThis);

std::unique_ptr<juce::FileChooser> fileChooser;

std::vector<engine::MissingResolutionWorkItem> workItems;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MissingResolutionScreen);
};
Expand Down
8 changes: 3 additions & 5 deletions src/engine/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1086,11 +1086,9 @@ void Engine::sendFullRefreshToClient() const
getSelectionManager()->sendOtherTabsSelectionToClient();

auto missing = collectMissingResolutionWorkItems(*this);
if (!missing.empty())
{
serializationSendToClient(messaging::client::s2c_send_missing_resolution_workitem_list,
missing, *(getMessageController()));
}
// send missing even if empty. An empty missing flags dont show dialog
serializationSendToClient(messaging::client::s2c_send_missing_resolution_workitem_list, missing,
*(getMessageController()));
}

void Engine::clearAll()
Expand Down
33 changes: 7 additions & 26 deletions src/engine/missing_resolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,16 @@ std::vector<MissingResolutionWorkItem> collectMissingResolutionWorkItems(const E
{
std::vector<MissingResolutionWorkItem> res;

int pidx{0};
for (const auto &p : *(e.getPatch()))
const auto &sm = e.getSampleManager();
auto it = sm->samplesBegin();
while (it != sm->samplesEnd())
{
int gidx{0};
for (const auto &g : *p)
const auto &[id, s] = *it;
if (s->isMissingPlaceholder)
{
int zidx{0};
for (const auto &z : *g)
{
int idx{0};
for (const auto &v : z->variantData.variants)
{
if (v.active && z->samplePointers[idx]->isMissingPlaceholder)
{
auto &sm = z->samplePointers[idx];
MissingResolutionWorkItem wf;
wf.address = {pidx, gidx, zidx};
wf.variant = idx;
wf.path = sm->mFileName;
wf.md5sum = sm->md5Sum;
res.push_back(wf);
}
idx++;
}
zidx++;
}
gidx++;
res.push_back({id, s->mFileName});
}
pidx++;
it++;
}

return res;
Expand Down
4 changes: 1 addition & 3 deletions src/engine/missing_resolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ namespace scxt::engine
{
struct MissingResolutionWorkItem
{
selection::SelectionManager::ZoneAddress address;
int16_t variant;
SampleID missingID;
fs::path path;
std::string md5sum;
};

std::vector<MissingResolutionWorkItem> collectMissingResolutionWorkItems(const Engine &e);
Expand Down
5 changes: 4 additions & 1 deletion src/engine/zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ void Zone::setupOnUnstream(const engine::Engine &e)

if (nid != oid)
{
SCLOG("Relabeling zone on change : " << oid.to_string() << " -> " << nid.to_string());
SCLOG(getName() << " : Relabeling zone on change : " << oid.to_string() << " -> "
<< nid.to_string());
variantData.variants[i].sampleID = nid;
}

Expand Down Expand Up @@ -442,6 +443,8 @@ int16_t Zone::missingSampleCount() const
if (sv.active)
{
auto smp = samplePointers[idx];
// SCLOG("Checking missing sample at " << sv.sampleID.to_string() << " " << smp.get());

if (smp && smp->isMissingPlaceholder)
{
ct++;
Expand Down
12 changes: 5 additions & 7 deletions src/json/missing_resolution_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,13 @@
namespace scxt::json
{
SC_STREAMDEF(scxt::engine::MissingResolutionWorkItem, SC_FROM({
v = {{"a", from.address},
{"v", from.variant},
{"p", from.path.u8string()},
{"md5", from.md5sum}};
v = {
{"i", from.missingID},
{"p", from.path.u8string()},
};
}),
SC_TO({
findIf(v, "a", to.address);
findIf(v, "v", to.variant);
findIf(v, "md5", to.md5sum);
findIf(v, "i", to.missingID);
std::string fp;
findIf(v, "p", fp);
to.path = fs::path(fs::u8path(fp));
Expand Down
4 changes: 3 additions & 1 deletion src/json/utils_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ template <int idType> struct scxt_traits<ID<idType>>
}
};

SC_STREAMDEF(scxt::SampleID, SC_FROM(v = {{"m", from.md5}, {"a", from.multiAddress}});
SC_STREAMDEF(scxt::SampleID,
SC_FROM(v = {{"m", from.md5}, {"a", from.multiAddress}, {"p", from.pathHash}});
, SC_TO(
auto vs = v.find("m"); if (vs) {
std::string m5;
vs->to(m5);
strncpy(to.md5, m5.c_str(), scxt::SampleID::md5len + 1);
findIf(v, "a", to.multiAddress);
findIf(v, "p", to.pathHash);
} else {
std::string legType{"t"}, legID{"i"};
if (SC_UNSTREAMING_FROM_PRIOR_TO(0x2024'08'06))
Expand Down
2 changes: 2 additions & 0 deletions src/messaging/client/client_serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ enum ClientToSerializationMessagesIds

c2s_send_full_part_config,

c2s_resolve_sample,

num_clientToSerializationMessages
};

Expand Down
42 changes: 42 additions & 0 deletions src/messaging/client/missing_resolution_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,47 @@ namespace scxt::messaging::client
{
SERIAL_TO_CLIENT(SendMissingResolutionWorkItemList, s2c_send_missing_resolution_workitem_list,
std::vector<engine::MissingResolutionWorkItem>, onMissingResolutionWorkItemList);

using resolveSamplePayload_t = std::tuple<engine::MissingResolutionWorkItem, std::string>;
inline void doResolveSample(const resolveSamplePayload_t &payload, engine::Engine &e,
messaging::MessageController &cont)
{
auto mwi = std::get<0>(payload);
auto p = fs::path(fs::u8path(std::get<1>(payload)));
auto smp = e.getSampleManager()->loadSampleByPath(p);
SCLOG("Resolving : " << p.u8string());
SCLOG(" Was : " << mwi.missingID.to_string());
SCLOG(" To : " << smp->to_string());
if (smp.has_value())
{
for (auto &p : *(e.getPatch()))
{
for (auto &g : *p)
{
for (auto &z : *g)
{
int vidx{0};
for (auto &v : z->variantData.variants)
{
if (v.active && v.sampleID == mwi.missingID)
{
SCLOG(" Zone : " << z->getName());
v.sampleID = *smp;
z->attachToSampleAtVariation(
*(e.getSampleManager()), *smp, vidx,
engine::Zone::SampleInformationRead::ENDPOINTS);
}
vidx++;
}
}
}
}
}
e.getSampleManager()->purgeUnreferencedSamples();
e.sendFullRefreshToClient();
}
CLIENT_TO_SERIAL(ResolveSample, c2s_resolve_sample, resolveSamplePayload_t,
doResolveSample(payload, engine, cont));

} // namespace scxt::messaging::client
#endif // MISSING_RESOLUTION_MESSAGES_H
1 change: 1 addition & 0 deletions src/sample/sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ bool Sample::load(const fs::path &path)
return false;

md5Sum = infrastructure::createMD5SumFromFile(path);
id.setPathHash(path.u8string().c_str());

// If you add a type here add it in Browser::isLoadableFile also to stay in sync
if (extensionMatches(path, ".wav"))
Expand Down
25 changes: 19 additions & 6 deletions src/sample/sample_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ void SampleManager::restoreFromSampleAddressesAndIDs(const sampleAddressesAndIds
{
if (*nid != id)
{
SCLOG("Adding Alias ID [" << id.to_string() << "] -> [" << nid->to_string()
<< "]");
idAliases[id] = *nid;
addIdAlias(id, *nid);
}
}
}
Expand Down Expand Up @@ -154,6 +152,7 @@ std::optional<SampleID> SampleManager::loadSampleFromSF2(const fs::path &p, sf2:
sp->md5Sum = sf2MD5ByPath[p.u8string()];
assert(!sp->md5Sum.empty());
sp->id.setAsMD5WithAddress(sp->md5Sum, preset, instrument, region);
sp->id.setPathHash(p);

SCLOG("Loading : " << p.u8string());
SCLOG(" : " << sp->id.to_string());
Expand All @@ -169,6 +168,7 @@ std::optional<SampleID> SampleManager::setupSampleFromMultifile(const fs::path &
{
auto sp = std::make_shared<Sample>();
sp->id.setAsMD5WithAddress(md5, idx, -1, -1);
sp->id.setPathHash(p);

sp->parse_riff_wave(data, dataSize);
sp->type = Sample::MULTISAMPLE_FILE;
Expand Down Expand Up @@ -221,6 +221,11 @@ void SampleManager::purgeUnreferencedSamples()
{
SCLOG("Purging : " << b->second->mFileName.u8string());
SCLOG(" : " << b->first.to_string());
if (b->second->isMissingPlaceholder)
{
SCLOG(" : Missing Placeholder");
}

b = samples.erase(b);
}
else
Expand All @@ -231,7 +236,8 @@ void SampleManager::purgeUnreferencedSamples()

if (samples.size() != preSize)
{
SCLOG_WFUNC("PostPurge : Purged " << (preSize - samples.size()));
SCLOG_WFUNC("PostPurge : Purged " << (preSize - samples.size()) << " Remaining "
<< samples.size());
}
updateSampleMemory();
}
Expand Down Expand Up @@ -271,11 +277,18 @@ void SampleManager::addSampleAsMissing(const SampleID &id, const Sample::SampleF
{
auto ms = Sample::createMissingPlaceholder(f);
ms->id = id;
ms->id.setPathHash(f.path);

SCLOG("Missing : " << f.path.u8string());
SCLOG(" : " << id.to_string());
SCLOG(" : " << ms->id.to_string());

samples[id] = ms;
samples[ms->id] = ms;

if (ms->id != id)
{
// Path change so
addIdAlias(id, ms->id);
}
}
}

Expand Down
Loading

0 comments on commit 51b2682

Please sign in to comment.