Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding sample exporter #7627

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open

adding sample exporter #7627

wants to merge 33 commits into from

Conversation

szeli1
Copy link
Contributor

@szeli1 szeli1 commented Dec 19, 2024

closes #7452

This Pull request adds sample exporting to lmms that is independent from AudioEngine.

How to test:
Open lmms, load a sample into a sample clip. Open the context menu and click on the new option called "export sample buffer". A file dialog should open up. Select an audio file to export to, or create a new file by using a custom name in the file dialog. Click "open" inside the file dialog. The sample should be exported to the selected output file.

related pull request: #7557
this allows #5990 to be finished

if (outputFileName.isEmpty()) { return; }
if (outputFileName.endsWith(".flac") == false)
{
outputFileName = PathUtil::stripPrefix(outputFileName) + ".flac";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly you let the users choose different file types but then save it as a Flac anyway. This is very confusing in my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the exporter class only supports .flac and this was agreed to in discord. I can still change that, but it will add unreasonable complexity in my view.

outputBuffer[i + 1] = outputBuffer[i + 1] > 1.0f ? 1.0f : outputBuffer[i + 1] < -1.0f ? -1.0f : outputBuffer[i + 1];
i = i + channelCount;
}
size_t count = sf_writef_float(m_fileDescriptor, outputBuffer.data(), static_cast<sf_count_t>(buffer->size()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO all the sndfile related code should be moved into a helper class that is concerned with writing LMMS buffers into files in various formats using sndfile. It could be an RAII class which

  • takes a filename and the export format in its constructor and opens the file using sndfile
  • provides a method to push LMMS buffers which are then written into the file
  • in the destructor closes the file.

Doing so would likely also remove duplicated code in AudioFileFlac and AudioFileWave.

@firewall1110
Copy link
Contributor

It seems that #7627 only exports the content of sample clips into files, i.e. it will not replace the recorded data with references to the exported files.

Can this be fixed with new option to replace old reference or data with reference to exported file?

@michaelgregorius
Copy link
Contributor

It seems that #7627 only exports the content of sample clips into files, i.e. it will not replace the recorded data with references to the exported files.

Can this be fixed with new option to replace old reference or data with reference to exported file?

We should not implement too many workflow crutches that we might never get rid of again. IMO recording to files should be implemented as fast as possible instead of some workarounds.

@szeli1
Copy link
Contributor Author

szeli1 commented Jan 4, 2025

Can this be fixed with new option to replace old reference or data with reference to exported file?

Originally I couldn't do it because the exporting ran on a different thread and SampleClipView didn't wait for the exporting to be done before trying to import it.

@firewall1110
Copy link
Contributor

firewall1110 commented Jan 4, 2025

SampleClipView didn't wait for the exporting to be done

Can this exporting thread before quit trigger event connected to some SampleClip (OR ...) slot that do the same as happens when user load file to clip?

[Of course - only if user want this to happen]

@szeli1
Copy link
Contributor Author

szeli1 commented Jan 4, 2025

I will need to move the FlacExporter into a new file, but it is ready for review.

michaelgregorius and others added 6 commits January 4, 2025 22:36
Use `FileDialog::getSaveFileName` to retrieve the file name of the file
into which the sample buffer is saved. This gives us lots of
functionality automatically, e.g. the request if an existing file should
be overwritten.

Also let remove the appending of the `.flac` file extension and let the
users decide using the system file dialog.
@szeli1
Copy link
Contributor Author

szeli1 commented Jan 5, 2025

I realized that I would rather not touch AudioFileFlac, because I don't fully understand how it works. For example the writeBuffer() function has "integer PCM encoding" built in, while FlacExporter doesn't and it doesn't need to have it. It can certainly be used to replace most libsndfile functions for AudioFileFlac, but I'm unsure if this should be done.

@szeli1
Copy link
Contributor Author

szeli1 commented Jan 5, 2025

@michaelgregorius It seems like you introduced a crash by removing the code that ensures ".flac" file extensions are there. If the name (outputFilename) doesn't contain an extension in the file dialog, then lmms will crash. I believe this happens because after exporting, the exported sample will be reimported by the clip, but the clip will try to import outputFilename without the ".flac" extension that does not exist.

Save the exported file under the name that the users have selected and
do not append ".flac".

This fixes an exception that was thrown because the file is saved with
the appended extension but then attempted to load without it.
@michaelgregorius
Copy link
Contributor

@michaelgregorius It seems like you introduced a crash by removing the code that ensures ".flac" file extensions are there. If the name (outputFilename) doesn't contain an extension in the file dialog, then lmms will crash. I believe this happens because after exporting, the exported sample will be reimported by the clip, but the clip will try to import outputFilename without the ".flac" extension that does not exist.

@szeli1, I have fixed this with commit 5fa60b3 by saving the file with the name that the users have selected and not appending the ".flac" extension.


typedef void (*callbackFn)(void*);

class LmmsMassExporter
Copy link
Contributor

@michaelgregorius michaelgregorius Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some remarks about the name of the class:

  • It lives in the lmms namespace so there is not need to prefix it with "Lmms".
  • Why is it called mass exporter? To me it seems that one of its main features is that it exports data in a thread so perhaps something like ThreadedExporter might be more fitting.

Edit: I have just noticed the vector. Perhaps something like ExportManager or ThreadedExportManager might be better as a name then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like ThreadedExportManager, I will rename.

@szeli1
Copy link
Contributor Author

szeli1 commented Jan 6, 2025

@szeli1, I have fixed this with commit 5fa60b3 by saving the file with the name that the users have selected and not appending the ".flac" extension.

I don't know why do you prefer removing it, but sure, I approve if it works. I will remove the QFileInfo include.

@szeli1
Copy link
Contributor Author

szeli1 commented Jan 8, 2025

@szeli1, I have fixed this with commit 5fa60b3 by saving the file with the name that the users have selected and not appending the ".flac" extension.

It now works, it can export files without file extension, I don't know why is this useful, because the result will be a file without an extension, so every time the user would like to open it, they will have to select a program that can open .flac files.

@CorruptVoidSoul
Copy link

So I tested this with a wav and an ogg file, both exported without problems and there doesn't seem to be any hearable difference.
In case it's wanted, system info is aarch64 Ubuntu running on top of Termux on a phone (samsung galaxy A25).

@michaelgregorius
Copy link
Contributor

@szeli1, I have fixed this with commit 5fa60b3 by saving the file with the name that the users have selected and not appending the ".flac" extension.

It now works, it can export files without file extension, I don't know why is this useful, because the result will be a file without an extension, so every time the user would like to open it, they will have to select a program that can open .flac files.

The reason is that we should let users do what the want to do. The dialog already proposes the "flac" extension so this adds no extra work for the users. The default is that it is exported with the extension.

However, if the users for some reason decide that they want/need to have a file without extension then the previous implementation would make them jump through the hoops to export the file and then having to rename it manually to remove the extension. With the current implementation they simply save it without the extension and they are good.

The current implementation gives the best of both words. I guess we all have some experience with software that attempts to be clever only to do the wrong thing. So please let's not add such behavior to LMMS if it is not even necessary in some way.

{
if (thisObject == nullptr) { return; }
SampleClip* castedThis = static_cast<SampleClip*>(thisObject);
castedThis->setSampleFile(castedThis->m_exportedSampleName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I have thought a bit more about it I do not think that replacing the sample with the one we have just exported is a good idea.

Let's say you have a project with all the samples contained in the project. You now want to export the sample to a different folder outside of the project just to save it. In this case the project file would now point to a file outside of the project folder which might not be the intended effect.

IMO the export feature should simply export the file to wherever the users want. If users want to replace the sample with the exported one it should either be an option in the export dialog (initially disabled) or they should explicitly replace the samples themselves after the export.

Doing it as it is currently done will likely lead to "chaos".

@firewall1110
Copy link
Contributor

If users want to replace the sample with the exported one it should either be an option in the export dialog (initially disabled)

Something like this I mean when wrote:

Can this be fixed with new option to replace old reference or data with reference to exported file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants