Skip to content

Commit

Permalink
- multipage: Add DecodeFlac to UnzipTask
Browse files Browse the repository at this point in the history
- multipage: Add compress Audio folder function to compress folder with WAV files to FLAC
  • Loading branch information
Christoph Hart committed Jul 29, 2024
1 parent e9a7ea9 commit b7eb82e
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 8 deletions.
36 changes: 33 additions & 3 deletions hi_tools/hi_multipage/ActionComponents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,7 @@ Result UnzipTask::performTaskStatic(WaitJob& t)
}

auto skipFirstFolder = (bool)obj[mpid::SkipFirstFolder];
auto decodeFlac = (bool)obj[mpid::DecodeFlac];

for(int i = 0; i < zipFile->getNumEntries(); i++)
{
Expand All @@ -1470,9 +1471,35 @@ Result UnzipTask::performTaskStatic(WaitJob& t)
zn->filename = zn->filename.fromFirstOccurrenceOf("/", false, false);
}

zipFile->uncompressEntry(i, targetDirectory, overwrite, nullptr);
auto thisFile = targetDirectory.getChildFile(zipFile->getEntry(i)->filename);

zipFile->uncompressEntry(i, targetDirectory, overwrite, nullptr);

if(thisFile.getFileExtension() == ".flac" && decodeFlac)
{
auto tf = thisFile.withFileExtension(".wav");

FlacAudioFormat ff;
WavAudioFormat wf;

auto thisFile = targetDirectory.getChildFile(zipFile->getEntry(i)->filename);
auto fis = new FileInputStream(thisFile);
auto fos = new FileOutputStream(tf);

ScopedPointer<AudioFormatReader> reader = ff.createReaderFor (fis, true);

if(reader != nullptr)
{
ScopedPointer<AudioFormatWriter> writer = wf.createWriterFor (fos, reader->sampleRate, reader->getChannelLayout(), reader->bitsPerSample, reader->metadataValues, 0);

if(writer->writeFromAudioReader (*reader, 0, reader->lengthInSamples))
{
writer->flush();
writer = nullptr;
reader = nullptr;
thisFile.deleteFile();
}
}
}

#if JUCE_MAC

Expand Down Expand Up @@ -1545,7 +1572,10 @@ void UnzipTask::createEditor(Dialog::PageInfo& rootList)
rootList.addChild<Button>(DefaultProperties::getForSetting(infoObject, mpid::SkipFirstFolder,
"Whether to skip the first folder hierarchy in the source archive. \n> This is useful if your archive has all files in a subdirectory and you want to extract the archive directly to the specified target."));

rootList.addChild<Button>(DefaultProperties::getForSetting(infoObject, mpid::SkipIfNoSource,
rootList.addChild<Button>(DefaultProperties::getForSetting(infoObject, mpid::DecodeFlac,
"Whether to decode FLAC files from the archive to WAV files. \n> This should be used if the archive was created using the **File -> Compress Audio Folder** function."));

rootList.addChild<Button>(DefaultProperties::getForSetting(infoObject, mpid::SkipIfNoSource,
"Whether to silently skip the extraction process or throw an error message if the source doesn't exist. Use this option if you conditionally download the archive before extracting."));
}
#endif
Expand Down
7 changes: 7 additions & 0 deletions hi_tools/hi_multipage/LookAndFeelMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,13 @@ select::after:hover
background: #ccc;
}
.no-label
{
color: white;
width: 100%;
}
)";

} // default_css
Expand Down
1 change: 1 addition & 0 deletions hi_tools/hi_multipage/MultiPageIds.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ namespace mpid
DECLARE_ID(Custom);
DECLARE_ID(Data);
DECLARE_ID(Directory);
DECLARE_ID(DecodeFlac);
DECLARE_ID(EmptyText);
DECLARE_ID(Enabled);
DECLARE_ID(EventTrigger);
Expand Down
1 change: 1 addition & 0 deletions hi_tools/hi_multipage/multipage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ var Helpers::getIdList()
DECLARE_ID(Company);
DECLARE_ID(Custom);
DECLARE_ID(Data);
DECLARE_ID(DecodeFlac);
DECLARE_ID(Directory);
DECLARE_ID(EmptyText);
DECLARE_ID(Enabled);
Expand Down
16 changes: 15 additions & 1 deletion hi_tools/simple_css/FlexboxComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,21 @@ struct FlexboxComponent: public Component,
{
jassert(isInvisibleWrapper());
auto fc = getChildComponent(0);
return childSheets[fc]->getFlexItem(fc, fullArea);

auto ss = childSheets[fc];

if(ss == nullptr)
{
childSheets[fc] = parentToUse->css.getForComponent(fc);
ss = childSheets[fc];
}

if(ss != nullptr)
{
return childSheets[fc]->getFlexItem(fc, fullArea);
}

return {};
}

bool isInvisibleWrapper() const { return invisibleWrapper; }
Expand Down
174 changes: 174 additions & 0 deletions tools/multipagecreator/Source/DialogLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,177 @@ Dialog* ProjectExporter::createDialog(State& state)
} // namespace library
} // namespace multipage
} // namespace hise


namespace hise {
namespace multipage {
namespace library {
using namespace juce;
var AudioFolderCompressor::createFolder(State::Job& t, const var& state)
{
// All variables:
auto sourceFolder = File(state["sourceFolder"].toString());
auto targetFolder = File(state["targetFolder"].toString());
auto createArchive = (bool)state["createArchive"];

t.setMessage ("Collecting files...");

auto fileList = sourceFolder.findChildFiles (File::findFilesAndDirectories, true, "*");

int index = 0;
int numFiles = (double)fileList.size();

for(auto f: fileList)
{
if(f.getFileName() == ".DS_Store")
continue;

t.setMessage ("Compressing " + f.getFileName());

t.getProgress() = (double)(index++) / numFiles;
auto tf = targetFolder.getChildFile(f.getRelativePathFrom(sourceFolder));

if(f.getFileExtension() == ".wav")
{
tf.deleteFile();
tf.getParentDirectory().createDirectory();
WavAudioFormat wf;
ScopedPointer<FileInputStream> fis = new FileInputStream(f);
ScopedPointer<FileOutputStream> fos = new FileOutputStream(tf.withFileExtension(".flac"));

ScopedPointer<AudioFormatReader> reader = wf.createReaderFor(fis.release(), true);

if(reader != nullptr)
{
FlacAudioFormat ff;

ScopedPointer<AudioFormatWriter> writer = ff.createWriterFor (fos, reader->sampleRate, reader->getChannelLayout(), reader->bitsPerSample, reader->metadataValues, 8);

if(writer != nullptr)
{
fos.release();
writer->writeFromAudioReader (*reader, 0, reader->lengthInSamples);
writer->flush();
writer = nullptr;

continue;
}
}

reader = nullptr;
fis = nullptr;
fos = nullptr;

f.copyFileTo (tf);
}
else
{
tf.getParentDirectory().createDirectory();
f.copyFileTo (tf);
}
}

if(createArchive)
{
ZipFile::Builder builder;

auto targetFileList = targetFolder.findChildFiles (File::findFilesAndDirectories, true, "*");

t.setMessage("Building Archive");

t.getProgress() = 0.0;

index = 0;

for(auto tf: targetFileList)
{
builder.addFile(tf, 0);
}

auto archiveFile = targetFolder.getParentDirectory().getChildFile(targetFolder.getFileName()).withFileExtension (".zip");
FileOutputStream fos(archiveFile);
builder.writeToStream (fos, &t.getProgress());
}

// ADD CODE here...

return var(""); // return a error
}

Dialog* AudioFolderCompressor::createDialog(State& state)
{
DynamicObject::Ptr fullData = new DynamicObject();
fullData->setProperty(mpid::LayoutData, JSON::parse(R"({"StyleSheet": "ModalPopup", "Style": "", "UseViewport": true, "ConfirmClose": true, "DialogWidth": 700, "DialogHeight": 550})"));
fullData->setProperty(mpid::Properties, JSON::parse(R"({"Header": "Compress Audio Folder", "Subtitle": "Subtitle", "Image": "", "ProjectName": "AudioFolderCompressor", "Company": "HISE", "Version": "1.0.0", "BinaryName": "AudioFolderCompressor", "UseGlobalAppData": false, "Icon": ""})"));
using namespace factory;
auto mp_ = new Dialog(var(fullData.get()), state, false);
auto& mp = *mp_;
auto& List_0 = mp.addPage<List>({
{ mpid::Style, "gap: 10px;" }
});

List_0.addChild<MarkdownText>({
{ mpid::Text, R"(Please select the folder that you want to compress.
> This will create a duplicate folder that will convert all WAV files into FLAC files to leverage the best compression algorithm for installer archives.)" }
});

List_0.addChild<FileSelector>({
{ mpid::ID, "sourceFolder" },
{ mpid::Required, 1 },
{ mpid::Directory, 1 },
{ mpid::Text, "Source" },
{ mpid::Help, "Select the source directory that you want to compress. This will recursively copy all files (or encode WAV files) to the target location." }
});

List_0.addChild<FileSelector>({
{ mpid::ID, "targetFolder" },
{ mpid::Required, 1 },
{ mpid::Directory, 1 },
{ mpid::Text, "Target" },
{ mpid::Help, "The target folder where the copied / converted files will be located." }
});

List_0.addChild<Button>({
{ mpid::Text, "Create ZIP Archive from folder" },
{ mpid::ID, "createArchive" },
{ mpid::Help, R"(Enable this if you want to create a ZIP archive from the target files. This will create a ZIP file next to the target directory.
> Using this option will set the compression level to the lowest possible setting (since we've already compressed the audio file payload) so that the decoding will be a bit faster.)" }
});

// Custom callback for page List_0
List_0.setCustomCheckFunction([](Dialog::PageBase* b, const var& obj){

return Result::ok();

});

auto& List_5 = mp.addPage<List>({
});

List_5.addChild<MarkdownText>({
{ mpid::Text, "The files are being converted..." }
});

auto& LambdaTaskId_7 = List_5.addChild<LambdaTask>({
{ mpid::Text, "Progress" },
{ mpid::ID, "LambdaTaskId" },
{ mpid::Function, "createFolder" }
});

// TODO: add var createFolder(State::Job& t, const var& stateObject) to class
LambdaTaskId_7.setLambdaAction(state, BIND_MEMBER_FUNCTION_2(AudioFolderCompressor::createFolder));

// Custom callback for page List_5
List_5.setCustomCheckFunction([](Dialog::PageBase* b, const var& obj){

return Result::ok();

});

return mp_;
}
} // namespace library
} // namespace multipage
} // namespace hise
20 changes: 19 additions & 1 deletion tools/multipagecreator/Source/DialogLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,24 @@ struct ProjectExporter: public HardcodedDialogWithState




namespace hise {
namespace multipage {
namespace library {
using namespace juce;
struct AudioFolderCompressor: public HardcodedDialogWithState
{
var createFolder(State::Job& t, const var& state);
AudioFolderCompressor()
{
setOnCloseFunction([](){});
setSize(700, 550);
}

Dialog* createDialog(State& state) override;

};
} // namespace library
} // namespace multipage
} // namespace hise


13 changes: 11 additions & 2 deletions tools/multipagecreator/Source/MainComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ PopupMenu MainComponent::getMenuForIndex(int topLevelMenuIndex, const String&)
m.addItem(CommandId::FileSaveAs, "Save file as");
m.addItem(CommandId::FileExportAsProjucerProject, "Export as Projucer project");
m.addItem(CommandId::FileExportAsMonolith, "Export as monolith payload");
m.addItem(CommandId::FileCompressAudioFolder, "Compress audio folder");
m.addSeparator();
m.addItem(CommandId::FileCreateCSS, "Create CSS stylesheet");
m.addSeparator();
Expand Down Expand Up @@ -291,7 +292,8 @@ void MainComponent::menuItemSelected(int menuItemID, int)

if(fc.browseForFileToSave(true))
{
MonolithData::exportMonolith(rt, fc.getResult());
FileOutputStream fos(fc.getResult());
MonolithData::exportMonolith(rt, &fos);
}

break;
Expand All @@ -303,6 +305,11 @@ void MainComponent::menuItemSelected(int menuItemID, int)
tree->setRoot(*c);
resized();
break;
case FileCompressAudioFolder:
addAndMakeVisible(modalDialog = new ModalDialog(*this, new multipage::library::AudioFolderCompressor()));

break;

case EditUndo: c->getUndoManager().undo(); c->refreshCurrentPage(); break;
case EditRedo: c->getUndoManager().redo(); c->refreshCurrentPage(); break;
case EditToggleMode:
Expand Down Expand Up @@ -643,7 +650,9 @@ void MainComponent::createDialog(const File& f)
{
hardcodedDialog = nullptr;

addAndMakeVisible(c = MonolithData(f).create(rt));
FileInputStream fis(f);

addAndMakeVisible(c = MonolithData(&fis).create(rt));
}
}
else
Expand Down
3 changes: 2 additions & 1 deletion tools/multipagecreator/Source/MainComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct ComponentWithEdge: public Component,
{
struct LAF: public LookAndFeel_V4
{
void drawStretchableLayoutResizerBar (Graphics &g, int w, int h, bool isVerticalBar, bool isMouseOver, bool isMouseDragging) override
void drawStretchableLayoutResizerBar (Graphics &g, Component& c, int w, int h, bool isVerticalBar, bool isMouseOver, bool isMouseDragging) override
{


Expand Down Expand Up @@ -1253,6 +1253,7 @@ class MainComponent : public Component,
FileSaveAs,
FileExportAsProjucerProject,
FileExportAsMonolith,
FileCompressAudioFolder,
FileQuit,
EditUndo,
EditRedo,
Expand Down

0 comments on commit b7eb82e

Please sign in to comment.