diff --git a/currentGitHash.txt b/currentGitHash.txt index c4ccdabaf5..9d4f0a4bff 100644 --- a/currentGitHash.txt +++ b/currentGitHash.txt @@ -1 +1 @@ -a33df6689dc4519fa7dcb395ed243e9edd73dbff +6a72add15636d86ff04214643711399abbba6e87 diff --git a/hi_backend/backend/currentGit.h b/hi_backend/backend/currentGit.h index de5f37aa4b..4d42a84ba9 100644 --- a/hi_backend/backend/currentGit.h +++ b/hi_backend/backend/currentGit.h @@ -1 +1 @@ -#define PREVIOUS_HISE_COMMIT "a33df6689dc4519fa7dcb395ed243e9edd73dbff" +#define PREVIOUS_HISE_COMMIT "6a72add15636d86ff04214643711399abbba6e87" diff --git a/hi_core/hi_components/markdown_components/MarkdownPreview.cpp b/hi_core/hi_components/markdown_components/MarkdownPreview.cpp index c177480a36..151c834030 100644 --- a/hi_core/hi_components/markdown_components/MarkdownPreview.cpp +++ b/hi_core/hi_components/markdown_components/MarkdownPreview.cpp @@ -60,6 +60,269 @@ static bool areMajorWebsitesAvailable() return false; } +void DocUpdater::SnippetCreator::createSnippetDatabase() +{ + showStatusMessage("Create Snippet database"); + + auto am = dynamic_cast(&holder)->getAssetManager(); + am->initialise(); + + auto appDataFolder = NativeFileHandler::getAppDataDirectory(nullptr); + + if(snippetDirectory.isEmpty()) + { + auto f = appDataFolder.getChildFile("snippetBrowser.xml"); + + if(auto xml = XmlDocument::parse(f)) + { + if(auto c = xml->getChildByName("snippetDirectory")) + snippetDirectory = c->getStringAttribute("value"); + } + } + + if(snippetDirectory.isNotEmpty()) + { + File snippetRoot(snippetDirectory); + + auto snippetList = snippetRoot.findChildFiles(File::findFiles, false, "*.md"); + + struct Item + { + Item(const MarkdownLink& l, const String& name_): + name(name_) + { + auto h = l.getHeaderFromFile({}); + + description = l.toString(MarkdownLink::Format::ContentWithoutHeader); + priority = h.getKeyValue("priority").getIntValue(); + + auto catIndex = getCategories().indexOf(h.getKeyValue("category")); + + if(catIndex != -1) + cat = (Category)catIndex; + + snippet = h.getKeyValue("HiseSnippet"); + } + + static StringArray getCategories() + { + return { "All", "Modules", "MIDI", "Scripting", "Scriptnode", "UI" }; + } + + enum class Category + { + All, + Modules, + Midi, + Scripting, + Scriptnode, + UI, + numCategories + }; + + Image createScreenshot(BackendRootWindow* rw) const + { + + if(cat == Category::Scriptnode) + { + MainController::ScopedBadBabysitter sbb(rw->getBackendProcessor()); + + { + MessageManagerLock mm; + BackendCommandTarget::Actions::loadSnippet(rw, snippet); + } + + Processor::Iterator iter(rw->getMainSynthChain(), false); + + while(auto holder = iter.getNextProcessor()) + { + if(auto nw = holder->getActiveNetwork()) + { + MessageManagerLock mm; + + ScopedPointer c; + + c = new scriptnode::DspNetworkGraphPanel(rw->getRootFloatingTile()); + + c->setContentWithUndo(dynamic_cast(holder), 0); + + + + + if(auto graph = c->getContent()->canvas.getContent()) + { + auto comp = dynamic_cast(graph); + + while(comp != nullptr) + { + comp->setVisible(true); + comp = comp->getParentComponent(); + } + + auto img = graph->createComponentSnapshot(graph->getLocalBounds(), true); + return img; + } + } + } + } + else + { + SuspendHelpers::ScopedTicket ss(rw->getBackendProcessor()); + + MainController::ScopedBadBabysitter sbb(rw->getBackendProcessor()); + + { + MessageManagerLock mm; + BackendCommandTarget::Actions::loadSnippet(rw, snippet); + } + + if(auto jmp = JavascriptMidiProcessor::getFirstInterfaceScriptProcessor(rw->getBackendProcessor())) + { + auto cs = Point(jmp->getScriptingContent()->getContentWidth(), jmp->getScriptingContent()->getContentHeight()); + + if(cs == Point(600, 500) || jmp->getScriptingContent()->getNumComponents() == 0) + { + auto t = Thread::getCurrentThread(); + + if(t != nullptr) + t->wait(200); + + // skip the interface if its the default value + return {}; + } + + MessageManagerLock mm; + + ScriptContentComponent content(jmp); + content.setNewContent(jmp->getScriptingContent()); + content.setSize(content.getContentWidth(), content.getContentHeight()); + return content.createComponentSnapshot(content.getLocalBounds(), true); + } + } + + return {}; + } + + String createMarkdown(bool includeImage) const + { + String s; + String nl = "\n"; + + s << "## " << name << nl << nl; + + if(includeImage) + { + s << "![](/images/snippets/" << MarkdownLink::Helpers::getSanitizedFilename(name) + ".png)" << nl; + } + + s << description << nl << nl; + + s << "```" << nl; + s << snippet << nl; + s << "```" << nl << nl; + + return s; + } + + bool operator<(const Item& other) const { return priority > other.priority; } + bool operator>(const Item& other) const { return priority < other.priority; } + bool operator==(const Item& other) const { return priority == other.priority; } + + Category cat; + String description; + String snippet; + int priority = 3; + String name; + }; + + std::map> list; + + for(int i = 0; i < (int)Item::Category::numCategories; i++) + { + list[(Item::Category)i] = {}; + } + + for(auto sn: snippetList) + { + MarkdownLink l(snippetRoot, sn.getFileName()); + + Item i(l, sn.getFileNameWithoutExtension()); + list[i.cat].push_back(i); + } + + String nl = "\n"; + + auto targetDirectory = holder.getDatabaseRootDirectory().getChildFile("tutorials/"); + auto imgDirectory = holder.getDatabaseRootDirectory().getChildFile("images").getChildFile("snippets"); + + if(imgDirectory.isDirectory()) + imgDirectory.deleteRecursively(); + + imgDirectory.createDirectory(); + + + + targetDirectory.createDirectory(); + + PNGImageFormat format; + + int listIndex = 0; + + StringArray ignoreNames({ "_Template", "SnippetDB", "README"}); + + for(auto& l: list) + { + String s; + + auto catName = Item::getCategories()[(int)l.first]; + + s << "---" << nl; + s << "keywords: " << catName << " Snippets" << nl; + s << "summary: Examples in the category " << catName << nl; + s << "index: " << String(++listIndex) << nl; + s << "author: various" << nl; + s << "modified: 01.01.2024" << nl; + s << "---" << nl << nl; + + std::sort(l.second.begin(), l.second.end()); + + for(const auto& i: l.second) + { + if(ignoreNames.indexOf(i.name) != -1) + continue; + + showStatusMessage("Create docs for " + i.name); + + auto img = i.createScreenshot(root.getComponent()); + + if(threadToUse != nullptr && threadToUse->threadShouldExit()) + return; + + if(img.isValid()) + { + auto imageFile = imgDirectory.getChildFile(MarkdownLink::Helpers::getSanitizedFilename(i.name)).withFileExtension("png"); + + imageFile.deleteFile(); + + FileOutputStream fos(imageFile); + format.writeImageToStream(img, fos); + } + + s << i.createMarkdown(img.isValid()); + } + + auto targetFile = targetDirectory.getChildFile(MarkdownLink::Helpers::getSanitizedFilename(catName)).getChildFile("readme.md"); + + targetFile.getParentDirectory().createDirectory(); + targetFile.replaceWithText(s); + } + } + else + { + showStatusMessage("Can't find snippet directory"); + } +} + DocUpdater::DocUpdater(MarkdownDatabaseHolder& holder_, bool fastMode_, bool allowEdit) : MarkdownContentProcessor(holder_), DialogWindowWithBackgroundThread("Update documentation", false), @@ -168,6 +431,11 @@ DocUpdater::~DocUpdater() } +void DocUpdater::runSilently(MarkdownDatabaseHolder& holder) +{ + new DocUpdater(holder, true, false); +} + void DocUpdater::run() { if (fastMode) @@ -432,269 +700,18 @@ void DocUpdater::createLocalHtmlFiles() DatabaseCrawler::createHtmlFilesInHtmlFolder(htmlDir, getHolder(), this, &getProgressCounter()); } -void DocUpdater::createSnippetDatabase() -{ -#if USE_BACKEND - showStatusMessage("Create Snippet database"); - - auto root = GET_BACKEND_ROOT_WINDOW(this); - - auto am = dynamic_cast(root->getBackendProcessor())->getAssetManager(); - am->initialise(); - - auto appDataFolder = NativeFileHandler::getAppDataDirectory(nullptr); - - auto f = appDataFolder.getChildFile("snippetBrowser.xml"); - String snippetDirectory; - if(auto xml = XmlDocument::parse(f)) - { - if(auto c = xml->getChildByName("snippetDirectory")) - snippetDirectory = c->getStringAttribute("value"); - } +void DocUpdater::createSnippetDatabase() +{ + SnippetCreator sc(getHolder(), GET_BACKEND_ROOT_WINDOW(this), getCurrentThread()); - if(snippetDirectory.isNotEmpty()) + sc.logger = [this](const String& message) { - File snippetRoot(snippetDirectory); - - auto snippetList = snippetRoot.findChildFiles(File::findFiles, false, "*.md"); - - struct Item - { - Item(const MarkdownLink& l, const String& name_): - name(name_) - { - auto h = l.getHeaderFromFile({}); - - description = l.toString(MarkdownLink::Format::ContentWithoutHeader); - priority = h.getKeyValue("priority").getIntValue(); - - auto catIndex = getCategories().indexOf(h.getKeyValue("category")); + this->showStatusMessage(message); + }; - if(catIndex != -1) - cat = (Category)catIndex; - - snippet = h.getKeyValue("HiseSnippet"); - } - - static StringArray getCategories() - { - return { "All", "Modules", "MIDI", "Scripting", "Scriptnode", "UI" }; - } - - enum class Category - { - All, - Modules, - Midi, - Scripting, - Scriptnode, - UI, - numCategories - }; - - Image createScreenshot(BackendRootWindow* rw) const - { - - if(cat == Category::Scriptnode) - { - MainController::ScopedBadBabysitter sbb(rw->getBackendProcessor()); - - { - MessageManagerLock mm; - BackendCommandTarget::Actions::loadSnippet(rw, snippet); - } - - Processor::Iterator iter(rw->getMainSynthChain(), false); - - while(auto holder = iter.getNextProcessor()) - { - if(auto nw = holder->getActiveNetwork()) - { - MessageManagerLock mm; - - ScopedPointer c; - - c = new scriptnode::DspNetworkGraphPanel(rw->getRootFloatingTile()); - - c->setContentWithUndo(dynamic_cast(holder), 0); - - - - - if(auto graph = c->getContent()->canvas.getContent()) - { - auto comp = dynamic_cast(graph); - - while(comp != nullptr) - { - comp->setVisible(true); - comp = comp->getParentComponent(); - } - - auto img = graph->createComponentSnapshot(graph->getLocalBounds(), true); - return img; - } - } - } - } - else - { - SuspendHelpers::ScopedTicket ss(rw->getBackendProcessor()); - - MainController::ScopedBadBabysitter sbb(rw->getBackendProcessor()); - - { - MessageManagerLock mm; - BackendCommandTarget::Actions::loadSnippet(rw, snippet); - } - - if(auto jmp = JavascriptMidiProcessor::getFirstInterfaceScriptProcessor(rw->getBackendProcessor())) - { - auto cs = Point(jmp->getScriptingContent()->getContentWidth(), jmp->getScriptingContent()->getContentHeight()); - - if(cs == Point(600, 500) || jmp->getScriptingContent()->getNumComponents() == 0) - { - Thread::getCurrentThread()->wait(200); - // skip the interface if its the default value - return {}; - } - - MessageManagerLock mm; - - ScriptContentComponent content(jmp); - content.setNewContent(jmp->getScriptingContent()); - - content.setSize(content.getContentWidth(), content.getContentHeight()); - - return content.createComponentSnapshot(content.getLocalBounds(), true); - } - } - - return {}; - } - - String createMarkdown(bool includeImage) const - { - String s; - String nl = "\n"; - - s << "## " << name << nl << nl; - - if(includeImage) - { - s << "![](/images/snippets/" << MarkdownLink::Helpers::getSanitizedFilename(name) + ".png)" << nl; - } - - s << description << nl << nl; - - s << "```" << nl; - s << snippet << nl; - s << "```" << nl << nl; - - return s; - } - - bool operator<(const Item& other) const { return priority > other.priority; } - bool operator>(const Item& other) const { return priority < other.priority; } - bool operator==(const Item& other) const { return priority == other.priority; } - - Category cat; - String description; - String snippet; - int priority = 3; - String name; - }; - - std::map> list; - - for(int i = 0; i < (int)Item::Category::numCategories; i++) - { - list[(Item::Category)i] = {}; - } - - for(auto sn: snippetList) - { - MarkdownLink l(snippetRoot, sn.getFileName()); - - Item i(l, sn.getFileNameWithoutExtension()); - list[i.cat].push_back(i); - } - - String nl = "\n"; - - auto targetDirectory = holder.getDatabaseRootDirectory().getChildFile("tutorials/"); - auto imgDirectory = holder.getDatabaseRootDirectory().getChildFile("images").getChildFile("snippets"); - - if(imgDirectory.isDirectory()) - imgDirectory.deleteRecursively(); - - imgDirectory.createDirectory(); - - auto brw = GET_BACKEND_ROOT_WINDOW(this); - - targetDirectory.createDirectory(); - - PNGImageFormat format; - - int listIndex = 0; - - StringArray ignoreNames({ "_Template", "SnippetDB", "README"}); - - for(auto& l: list) - { - String s; - - auto catName = Item::getCategories()[(int)l.first]; - - s << "---" << nl; - s << "keywords: " << catName << " Snippets" << nl; - s << "summary: Examples in the category " << catName << nl; - s << "index: " << String(++listIndex) << nl; - s << "author: various" << nl; - s << "modified: 01.01.2024" << nl; - s << "---" << nl << nl; - - std::sort(l.second.begin(), l.second.end()); - - for(const auto& i: l.second) - { - if(ignoreNames.indexOf(i.name) != -1) - continue; - - showStatusMessage("Create docs for " + i.name); - - auto img = i.createScreenshot(brw); - - if(threadShouldExit()) - return; - - if(img.isValid()) - { - auto imageFile = imgDirectory.getChildFile(MarkdownLink::Helpers::getSanitizedFilename(i.name)).withFileExtension("png"); - - imageFile.deleteFile(); - - FileOutputStream fos(imageFile); - format.writeImageToStream(img, fos); - } - - s << i.createMarkdown(img.isValid()); - } - - auto targetFile = targetDirectory.getChildFile(MarkdownLink::Helpers::getSanitizedFilename(catName)).getChildFile("readme.md"); - - targetFile.getParentDirectory().createDirectory(); - - targetFile.replaceWithText(s); - } - } - else - { - showStatusMessage("Can't find snippet directory"); - } -#endif + sc.createSnippetDatabase(); } void DocUpdater::downloadAndTestFile(const String& targetFileName) diff --git a/hi_core/hi_components/markdown_components/MarkdownPreview.h b/hi_core/hi_components/markdown_components/MarkdownPreview.h index 0dc83282fe..185b86bd6b 100644 --- a/hi_core/hi_components/markdown_components/MarkdownPreview.h +++ b/hi_core/hi_components/markdown_components/MarkdownPreview.h @@ -60,6 +60,7 @@ class RLottieFloatingTile : public FloatingTileContent, #endif + class DocUpdater : public DialogWindowWithBackgroundThread, public MarkdownContentProcessor, public DatabaseCrawler::Logger, @@ -68,6 +69,31 @@ class DocUpdater : public DialogWindowWithBackgroundThread, { public: + struct SnippetCreator + { + SnippetCreator(MarkdownDatabaseHolder& holder_, BackendRootWindow* rootWindow, Thread* t): + holder(holder_), + root(rootWindow), + threadToUse(t) + {} + + Component::SafePointer root; + std::function logger; + String snippetDirectory; + Thread* threadToUse = nullptr; + + void showStatusMessage(const String& message) + { + if(logger) + logger(message); + } + + void createSnippetDatabase(); + + MarkdownDatabaseHolder& holder; + Component* rootWindow; + }; + enum CacheURLType { Hash, @@ -125,10 +151,7 @@ class DocUpdater : public DialogWindowWithBackgroundThread, showStatusMessage(message); } - static void runSilently(MarkdownDatabaseHolder& holder) - { - new DocUpdater(holder, true, false); - } + static void runSilently(MarkdownDatabaseHolder& holder); void run() override; diff --git a/hi_scripting/scripting/api/ScriptModulationMatrix.cpp b/hi_scripting/scripting/api/ScriptModulationMatrix.cpp index 475a59f1aa..6d3777c1a7 100644 --- a/hi_scripting/scripting/api/ScriptModulationMatrix.cpp +++ b/hi_scripting/scripting/api/ScriptModulationMatrix.cpp @@ -997,7 +997,7 @@ void ScriptModulationMatrix::ModulatorTargetData::updateValue() } else if(targetMode == TargetMode::FrequencyMode) { - processor->setAttribute(PolyFilterEffect::Parameters::Frequency, componentValue, sendNotification); + processor->setAttribute(PolyFilterEffect::Parameters::Frequency, componentValue, sendNotificationAsync); } } @@ -1412,7 +1412,7 @@ void ScriptModulationMatrix::ModulatorTargetData::init(const var& json) auto defaultMode = ValueModeHelpers::getMode(json[MatrixIds::Mode]); // make sure the bipolar mod is cranked up fully. - processor->setAttribute(PolyFilterEffect::Parameters::BipolarIntensity, 1.0, sendNotification); + processor->setAttribute(PolyFilterEffect::Parameters::BipolarIntensity, 1.0, sendNotificationSync); if (defaultMode == ValueMode::Undefined) defaultMode = ValueMode::Scale; @@ -1648,7 +1648,7 @@ void ScriptModulationMatrix::ParameterTargetData::updateValue() if (valueToSend != lastParameterValue) { lastParameterValue = valueToSend; - processor->setAttribute(subIndex, valueToSend, sendNotification); + processor->setAttribute(subIndex, valueToSend, sendNotificationAsync); dynamic_cast(sc.getObject())->sendRepaintMessage(); } } diff --git a/hi_scripting/scripting/scriptnode/api/DspNetwork.cpp b/hi_scripting/scripting/scriptnode/api/DspNetwork.cpp index 1041a7b5ef..c7fdf1e4c8 100644 --- a/hi_scripting/scripting/scriptnode/api/DspNetwork.cpp +++ b/hi_scripting/scripting/scriptnode/api/DspNetwork.cpp @@ -2000,8 +2000,13 @@ bool DspNetwork::CodeManager::SnexSourceCompileHandler::triggerCompilation() auto currentThread = getMainController()->getKillStateHandler().getCurrentThread(); - if (currentThread == MainController::KillStateHandler::TargetThread::SampleLoadingThread || - currentThread == MainController::KillStateHandler::TargetThread::ScriptingThread) + auto shouldBeSync = currentThread == MainController::KillStateHandler::TargetThread::SampleLoadingThread || + currentThread == MainController::KillStateHandler::TargetThread::ScriptingThread; + + if(getMainController()->isFlakyThreadingAllowed()) + shouldBeSync = true; + + if (shouldBeSync) { getParent()->handleCompilation(); return true; diff --git a/hi_scripting/scripting/scriptnode/api/NodeBase.cpp b/hi_scripting/scripting/scriptnode/api/NodeBase.cpp index 1fab0874ad..8c7d988bde 100644 --- a/hi_scripting/scripting/scriptnode/api/NodeBase.cpp +++ b/hi_scripting/scripting/scriptnode/api/NodeBase.cpp @@ -1012,6 +1012,12 @@ void Parameter::setDynamicParameter(parameter::dynamic_base::Ptr ownedNew) { // We don't need to lock if the network isn't active yet... bool useLock = parent->isActive(true) && parent->getRootNetwork()->isInitialised(); + + auto ph = parent->getRootNetwork()->getParentHolder(); + + if(ph == nullptr) + return; + SimpleReadWriteLock::ScopedWriteLock sl(parent->getRootNetwork()->getConnectionLock(), useLock); dynamicParameter = ownedNew; diff --git a/projects/standalone/Source/Main.cpp b/projects/standalone/Source/Main.cpp index 536126f521..b8b8e1bcad 100644 --- a/projects/standalone/Source/Main.cpp +++ b/projects/standalone/Source/Main.cpp @@ -69,9 +69,14 @@ class CommandLineActions - static File getFilePathArgument(const StringArray& args, const File& root = File()) + static File getFilePathArgument(const StringArray& args, const File& root = File(), const String& wildcard="-p:") { - auto s = getArgument(args, "-p:"); + if(wildcard.isNotEmpty()) + { + jassert(wildcard.startsWithChar('-') && wildcard.endsWithChar(':')); + } + + auto s = getArgument(args, wildcard); if (s.isNotEmpty() && File::isAbsolutePath(s)) return File(s); @@ -84,9 +89,14 @@ class CommandLineActions return rel; } - throwErrorAndQuit("`" + s + "` is not a valid path"); + // other wildcards are optional + if(wildcard == "-p:") + { + throwErrorAndQuit("`" + s + "` is not a valid path"); + RETURN_IF_NO_THROW(File()); + } - RETURN_IF_NO_THROW(File()); + return File(); } public: @@ -157,8 +167,9 @@ class CommandLineActions print("If you want to include VST2 and or VST3 plugins, specify the version."); print("If no VST flag is set, then the VST2 plugin is included as default"); print(""); - print("create-docs -p:PATH"); - print("Creates the HISE documentation files from the markdown files in the given directory."); + print("create-docs -p:PATH -h:PATH -s:PATH"); + print("Creates the HISE documentation files from the markdown files in the given directory (-p) to the given di."); + print("to the HTML directory specified by -h (and optionally rebuilding the snippet examples from -s)"); print("load -p:PATH"); print(""); print("Loads the given file (either .xml file or .hip file) and returns the status code"); @@ -428,10 +439,13 @@ class CommandLineActions { auto args = getCommandLineArgs(commandLine); auto docRoot = getFilePathArgument(args); - + + + auto snippetRoot = getFilePathArgument(args, {}, "-s:"); + if(!docRoot.isDirectory()) throwErrorAndQuit("Not a valid directory"); - + print("Create HISE instance"); CompileExporter::setExportingFromCommandLine(); @@ -441,12 +455,53 @@ class CommandLineActions ScopedPointer ed = sp.createEditor(); auto bp = dynamic_cast(sp.getCurrentProcessor()); - + + bp->setDatabaseRootDirectory(docRoot); + + print("Create tutorials from HISE Snippet database"); + + if(snippetRoot != File()) + { + bp->prepareToPlay(44100, 512); + snippetRoot.createDirectory(); + + + + struct CreatorThread: public Thread + { + CreatorThread(MarkdownDatabaseHolder& holder, BackendRootWindow* rootWindow, const File& snippetRoot): + Thread("Creating snippets"), + sc(holder, rootWindow, nullptr) + { + sc.logger = [](const String& message) + { + print(message); + }; + + sc.snippetDirectory = snippetRoot.getFullPathName(); + } + + void run() override + { + sc.createSnippetDatabase(); + } + + bool finished = false; + DocUpdater::SnippetCreator sc; + }; + + CreatorThread sc(*bp, dynamic_cast(ed.get()), snippetRoot); + + sc.run(); + } + hise::DatabaseCrawler crawler(*bp); - + + + print("Rebuild database"); - bp->setDatabaseRootDirectory(docRoot); + bp->setForceCachedDataUse(false); crawler.clearResolvers(); @@ -463,6 +518,28 @@ class CommandLineActions print("Writing data files"); crawler.createDataFiles(docRoot.getChildFile("cached"), true); + + auto htmlDir = getFilePathArgument(args, {}, "-h:"); + + if(htmlDir != File()) + { + htmlDir.createDirectory(); + String htmlBaseLink = "https://docs.hise.dev/"; + + auto templateDir = docRoot.getChildFile("template"); + auto templateTarget = htmlDir.getChildFile("template"); + templateDir.copyDirectoryTo(templateTarget); + + auto headerFile = templateTarget.getChildFile("header.html"); + + auto headerContent = headerFile.loadFileAsString(); + + headerContent = headerContent.replace("{BASE_URL}", htmlBaseLink); + headerFile.replaceWithText(headerContent); + + DatabaseCrawler::createImagesInHtmlFolder(htmlDir, *bp, nullptr, nullptr); + DatabaseCrawler::createHtmlFilesInHtmlFolder(htmlDir, *bp, nullptr, nullptr); + } } static void setHiseFolder(const String& commandLine)