diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 376aee26be4..e29f473748f 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -90,26 +90,26 @@ class AudioDevice virtual void stopProcessing(); -protected: - // subclasses can re-implement this for being used in conjunction with - // processNextBuffer() - virtual void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) {} - - // called by according driver for fetching new sound-data - fpp_t getNextBuffer(SampleFrame* _ab); // convert a given audio-buffer to a buffer in signed 16-bit samples // returns num of bytes in outbuf - int convertToS16(const SampleFrame* _ab, + static int convertToS16(const SampleFrame* _ab, const fpp_t _frames, int_sample_t * _output_buffer, const bool _convert_endian = false ); // clear given signed-int-16-buffer - void clearS16Buffer( int_sample_t * _outbuf, - const fpp_t _frames ); + static void clearS16Buffer(int_sample_t * _outbuf, + const fpp_t _frames); +protected: + // subclasses can re-implement this for being used in conjunction with + // processNextBuffer() + virtual void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) {} + + // called by according driver for fetching new sound-data + fpp_t getNextBuffer(SampleFrame* _ab); - inline void setSampleRate( const sample_rate_t _new_sr ) + inline void setSampleRate(const sample_rate_t _new_sr) { m_sampleRate = _new_sr; } diff --git a/include/AudioEngine.h b/include/AudioEngine.h index f80c860d819..857c5bc2258 100644 --- a/include/AudioEngine.h +++ b/include/AudioEngine.h @@ -339,6 +339,8 @@ class LMMS_EXPORT AudioEngine : public QObject void startProcessing(bool needsFifo = true); void stopProcessing(); + void startExporting(const struct qualitySettings& qs); + AudioDevice * tryAudioDevices(); MidiClient * tryMidiClients(); diff --git a/include/AudioFileDevice.h b/include/AudioFileDevice.h index dc9a786a4a8..17547dff16f 100644 --- a/include/AudioFileDevice.h +++ b/include/AudioFileDevice.h @@ -28,19 +28,23 @@ #include -#include "AudioDevice.h" #include "OutputSettings.h" namespace lmms { -class AudioFileDevice : public AudioDevice +class SampleFrame; + +class AudioFileDevice { public: + // getBufferFunction + using BufferFn = std::function; + AudioFileDevice(OutputSettings const & outputSettings, - const ch_cnt_t _channels, const QString & _file, - AudioEngine* audioEngine ); - ~AudioFileDevice() override; + const QString & _file, + const fpp_t defaultBufferSize); + virtual ~AudioFileDevice(); QString outputFile() const { @@ -49,8 +53,20 @@ class AudioFileDevice : public AudioDevice OutputSettings const & getOutputSettings() const { return m_outputSettings; } + sample_rate_t getSampleRate(); + // how many samples to store in a buffer + const fpp_t getDefaultFrameCount(); + + void setSampleRate(sample_rate_t newSampleRate); + + // save audio + void processThisBuffer(SampleFrame* frameBuffer, const fpp_t frameCount); + protected: + // subclasses can re-implement this for being used in conjunction with + virtual void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) {} + int writeData( const void* data, int len ); inline bool outputFileOpened() const @@ -66,10 +82,12 @@ class AudioFileDevice : public AudioDevice private: QFile m_outputFile; OutputSettings m_outputSettings; + + const fpp_t m_defaultFrameCount; } ; using AudioFileDeviceInstantiaton - = AudioFileDevice* (*)(const QString&, const OutputSettings&, const ch_cnt_t, AudioEngine*, bool&); + = AudioFileDevice* (*)(const OutputSettings&, bool&, const QString&, const fpp_t); } // namespace lmms diff --git a/include/AudioFileFlac.h b/include/AudioFileFlac.h index 003450afa14..a8d7df452d1 100644 --- a/include/AudioFileFlac.h +++ b/include/AudioFileFlac.h @@ -37,26 +37,22 @@ class AudioFileFlac : public AudioFileDevice { public: AudioFileFlac(OutputSettings const& outputSettings, - ch_cnt_t const channels, bool& successful, - QString const& file, - AudioEngine* audioEngine - ); - + const QString& file, + const fpp_t defaultBufferSize); ~AudioFileFlac() override; - static AudioFileDevice* getInst(QString const& outputFilename, - OutputSettings const& outputSettings, - ch_cnt_t const channels, - AudioEngine* audioEngine, - bool& successful) + static AudioFileDevice* getInst( + OutputSettings const &outputSettings, + bool &successful, + const QString & outputFilename, + const fpp_t defaultBufferSize) { return new AudioFileFlac( outputSettings, - channels, successful, outputFilename, - audioEngine + defaultBufferSize ); } diff --git a/include/AudioFileMP3.h b/include/AudioFileMP3.h index e56ac0ba332..6dda2fc54d6 100644 --- a/include/AudioFileMP3.h +++ b/include/AudioFileMP3.h @@ -40,21 +40,24 @@ namespace lmms class AudioFileMP3 : public AudioFileDevice { public: - AudioFileMP3( OutputSettings const & outputSettings, - const ch_cnt_t _channels, - bool & successful, - const QString & _file, - AudioEngine* audioEngine ); + AudioFileMP3(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize); ~AudioFileMP3() override; - static AudioFileDevice * getInst( const QString & outputFilename, - OutputSettings const & outputSettings, - const ch_cnt_t channels, - AudioEngine* audioEngine, - bool & successful ) + static AudioFileDevice* getInst( + OutputSettings const &outputSettings, + bool &successful, + const QString & outputFilename, + const fpp_t defaultBufferSize) { - return new AudioFileMP3( outputSettings, channels, successful, - outputFilename, audioEngine ); + return new AudioFileMP3( + outputSettings, + successful, + outputFilename, + defaultBufferSize + ); } protected: diff --git a/include/AudioFileOgg.h b/include/AudioFileOgg.h index 2608da359c7..52bdd6e159f 100644 --- a/include/AudioFileOgg.h +++ b/include/AudioFileOgg.h @@ -40,20 +40,24 @@ namespace lmms class AudioFileOgg : public AudioFileDevice { public: - AudioFileOgg( OutputSettings const & outputSettings, - const ch_cnt_t _channels, - bool & _success_ful, - const QString & _file, - AudioEngine* audioEngine ); + AudioFileOgg(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize); ~AudioFileOgg() override; - static AudioFileDevice * getInst( const QString & outputFilename, - OutputSettings const & outputSettings, - const ch_cnt_t channels, - AudioEngine* audioEngine, - bool & successful ) + static AudioFileDevice* getInst( + OutputSettings const &outputSettings, + bool &successful, + const QString & outputFilename, + const fpp_t defaultBufferSize) { - return new AudioFileOgg( outputSettings, channels, successful, outputFilename, audioEngine ); + return new AudioFileOgg( + outputSettings, + successful, + outputFilename, + defaultBufferSize + ); } diff --git a/include/AudioFileWave.h b/include/AudioFileWave.h index 040af95eac9..a35d96268fb 100644 --- a/include/AudioFileWave.h +++ b/include/AudioFileWave.h @@ -37,21 +37,24 @@ namespace lmms class AudioFileWave : public AudioFileDevice { public: - AudioFileWave( OutputSettings const & outputSettings, - const ch_cnt_t channels, - bool & successful, - const QString & file, - AudioEngine* audioEngine ); + AudioFileWave(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize); ~AudioFileWave() override; - static AudioFileDevice * getInst( const QString & outputFilename, - OutputSettings const & outputSettings, - const ch_cnt_t channels, - AudioEngine* audioEngine, - bool & successful ) + static AudioFileDevice* getInst( + OutputSettings const &outputSettings, + bool &successful, + const QString & outputFilename, + const fpp_t defaultBufferSize) { - return new AudioFileWave( outputSettings, channels, successful, - outputFilename, audioEngine ); + return new AudioFileWave( + outputSettings, + successful, + outputFilename, + defaultBufferSize + ); } diff --git a/include/ExportProjectDialog.h b/include/ExportProjectDialog.h index 37f6e0399a0..983905b7363 100644 --- a/include/ExportProjectDialog.h +++ b/include/ExportProjectDialog.h @@ -62,7 +62,7 @@ private slots: QString m_fileExtension; bool m_multiExport; - ProjectRenderer::ExportFileFormat m_ft; + LmmsExporter::ExportAudioFileFormat m_ft; std::unique_ptr m_renderManager; } ; diff --git a/include/LmmsExporter.h b/include/LmmsExporter.h new file mode 100644 index 00000000000..e8059226164 --- /dev/null +++ b/include/LmmsExporter.h @@ -0,0 +1,130 @@ +/* + * LmmsExporter.h - exporting files (currently only audio files), TODO rename class when things change + * + * Copyright (c) 2024 szeli1 + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef LMMS_LMMS_EXPORTER_H +#define LMMS_LMMS_EXPORTER_H + +#include +#include +#include + +#include "AudioFileDevice.h" +#include "SampleFrame.h" + +namespace lmms +{ +class LmmsExporter +{ +public: + using BufferFn = std::function*, void*)>; + using EndFn = std::function; + + enum class ExportAudioFileFormat : int + { + Wave, + Flac, + Ogg, + MP3, + Count + }; + // in the future more types can be added + enum class ExportFileType + { + Audio + }; + + constexpr static auto NumFileFormats = static_cast(ExportAudioFileFormat::Count); + + struct FileEncodeDevice + { + bool isAvailable() const { return m_getDevInst != nullptr; } + + ExportAudioFileFormat m_fileFormat; + const char* m_description; + const char* m_extension; + AudioFileDeviceInstantiaton m_getDevInst; + }; + + LmmsExporter(const ExportFileType fileType, + const QString& outputLocationAndName); + ~LmmsExporter(); + + void setupAudioRendering( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount, + SampleFrame* exportBuffer, + const fpp_t exportBufferFrameCount); + void setupAudioRendering( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount, + BufferFn getBufferFunction, + EndFn endFunction, + void* getBufferData); + bool canExportAutioFile() const; + + static ExportAudioFileFormat getAudioFileFormatFromFileName(const QString& fileName); + static ExportAudioFileFormat getAudioFileFormatFromExtension(const QString& extenisonString); + static QString getAudioFileExtensionFromFormat(ExportAudioFileFormat fmt); + + static const std::array s_fileEncodeDevices; + + void startExporting(); + void stopExporting(); + +private: + static void processExportingAudioFile(LmmsExporter* thisExporter); + + // audio exporting + bool processNextBuffer(); + bool processThisBuffer(SampleFrame* frameBuffer, const fpp_t frameCount); + void setupAudioRenderingInternal( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount); + + + + ExportFileType m_exportFileType; + QString m_outputFile; + + volatile bool m_abort; + + // called if not nullptr + // while run() + // if returned buffer.size() <= 0 then break; end + BufferFn m_getBufferFunction; + // called at the end of run(), can be nullptr + EndFn m_endFunction; + void* m_getBufferData; + + AudioFileDevice* m_fileDev; + std::vector m_buffer; + std::unique_ptr m_thread; +}; + +} // namespace lmms + +#endif // LMMS_LMMS_EXPORTER_H diff --git a/include/ProjectRenderer.h b/include/ProjectRenderer.h index 14c584a2eb2..d73e80a5d00 100644 --- a/include/ProjectRenderer.h +++ b/include/ProjectRenderer.h @@ -25,10 +25,11 @@ #ifndef LMMS_PROJECT_RENDERER_H #define LMMS_PROJECT_RENDERER_H -#include "AudioFileDevice.h" #include "lmmsconfig.h" +#include "LmmsExporter.h" #include "AudioEngine.h" #include "OutputSettings.h" +#include "PerfLog.h" #include "lmms_export.h" @@ -36,49 +37,21 @@ namespace lmms { -class LMMS_EXPORT ProjectRenderer : public QThread +class LMMS_EXPORT ProjectRenderer : public QObject { Q_OBJECT public: - enum class ExportFileFormat : int - { - Wave, - Flac, - Ogg, - MP3, - Count - } ; - constexpr static auto NumFileFormats = static_cast(ExportFileFormat::Count); - - struct FileEncodeDevice - { - bool isAvailable() const { return m_getDevInst != nullptr; } - - ExportFileFormat m_fileFormat; - const char * m_description; - const char * m_extension; - AudioFileDeviceInstantiaton m_getDevInst; - } ; - - ProjectRenderer( const AudioEngine::qualitySettings & _qs, const OutputSettings & _os, - ExportFileFormat _file_format, + LmmsExporter::ExportAudioFileFormat exportFileFormat, const QString & _out_file ); ~ProjectRenderer() override = default; - bool isReady() const + inline bool isReady() { - return m_fileDev != nullptr; + return m_exporter.canExportAutioFile(); } - static ExportFileFormat getFileFormatFromExtension( - const QString & _ext ); - - static QString getFileExtensionFromFormat( ExportFileFormat fmt ); - - static const std::array fileEncodeDevices; - public slots: void startProcessing(); void abortProcessing(); @@ -88,17 +61,22 @@ public slots: signals: void progressChanged( int ); - + void finished(); private: - void run() override; + // fill m_activeRenderer's buffer + // provided as function pointer to m_activeRenderer + static void nextOutputBuffer(std::vector* bufferOut, void* dataIn); + static void endRendering(void* dataIn); + + const AudioEngine::qualitySettings m_qualitySettings; - AudioFileDevice * m_fileDev; - AudioEngine::qualitySettings m_qualitySettings; + LmmsExporter m_exporter; volatile int m_progress; - volatile bool m_abort; + std::unique_ptr m_timer; + friend class LmmsExporter; } ; diff --git a/include/RenderManager.h b/include/RenderManager.h index 6865227789e..26d8568f8ab 100644 --- a/include/RenderManager.h +++ b/include/RenderManager.h @@ -43,7 +43,7 @@ class RenderManager : public QObject RenderManager( const AudioEngine::qualitySettings & qualitySettings, const OutputSettings & outputSettings, - ProjectRenderer::ExportFileFormat fmt, + LmmsExporter::ExportAudioFileFormat fmt, QString outputPath); ~RenderManager() override; @@ -73,7 +73,7 @@ private slots: const AudioEngine::qualitySettings m_qualitySettings; const AudioEngine::qualitySettings m_oldQualitySettings; const OutputSettings m_outputSettings; - ProjectRenderer::ExportFileFormat m_format; + LmmsExporter::ExportAudioFileFormat m_format; QString m_outputPath; std::unique_ptr m_activeRenderer; diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp index 42e7079b016..f029a1f5db4 100644 --- a/src/core/AudioEngine.cpp +++ b/src/core/AudioEngine.cpp @@ -240,6 +240,15 @@ void AudioEngine::stopProcessing() } +void AudioEngine::startExporting(const struct qualitySettings& qs) +{ + stopProcessing(); + + m_qualitySettings = qs; + + emit qualitySettingsChanged(); + emit sampleRateChanged(); +} sample_rate_t AudioEngine::baseSampleRate() const @@ -545,8 +554,6 @@ void AudioEngine::clearInternal() } - - void AudioEngine::changeQuality(const struct qualitySettings & qs) { // don't delete the audio-device @@ -566,9 +573,6 @@ void AudioEngine::changeQuality(const struct qualitySettings & qs) void AudioEngine::doSetAudioDevice( AudioDevice * _dev ) { // TODO: Use shared_ptr here in the future. - // Currently, this is safe, because this is only called by - // ProjectRenderer, and after ProjectRenderer calls this function, - // it does not access the old device anymore. if( m_audioDev != m_oldAudioDev ) {delete m_audioDev;} if( _dev ) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3608d28486a..296884389f2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -38,6 +38,7 @@ set(LMMS_SRCS core/LadspaManager.cpp core/LfoController.cpp core/LinkedModelGroups.cpp + core/LmmsExporter.cpp core/LocklessAllocator.cpp core/MeterModel.cpp core/MicroTimer.cpp diff --git a/src/core/LmmsExporter.cpp b/src/core/LmmsExporter.cpp new file mode 100644 index 00000000000..f15a6853aee --- /dev/null +++ b/src/core/LmmsExporter.cpp @@ -0,0 +1,285 @@ +/* + * LmmsExporter.cpp - exporting files (currently only audio files), TODO rename class when things change + * + * Copyright (c) 2024 szeli1 + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include + +#include "LmmsExporter.h" + +#include "AudioFileWave.h" +#include "AudioFileFlac.h" +#include "AudioFileOgg.h" +#include "AudioFileMP3.h" + +namespace lmms +{ + +const std::array LmmsExporter::s_fileEncodeDevices +{ + FileEncodeDevice{LmmsExporter::ExportAudioFileFormat::Wave, + QT_TRANSLATE_NOOP("LmmsExporter", "WAV (*.wav)"), + ".wav", &AudioFileWave::getInst }, + FileEncodeDevice{LmmsExporter::ExportAudioFileFormat::Flac, + QT_TRANSLATE_NOOP("LmmsExporter", "FLAC (*.flac)"), + ".flac", + &AudioFileFlac::getInst + }, + FileEncodeDevice{LmmsExporter::ExportAudioFileFormat::Ogg, + QT_TRANSLATE_NOOP("LmmsExporter", "OGG (*.ogg)"), + ".ogg", +#ifdef LMMS_HAVE_OGGVORBIS + &AudioFileOgg::getInst +#else + nullptr +#endif + }, + FileEncodeDevice{LmmsExporter::ExportAudioFileFormat::MP3, + QT_TRANSLATE_NOOP("LmmsExporter", "MP3 (*.mp3)"), + ".mp3", +#ifdef LMMS_HAVE_MP3LAME + &AudioFileMP3::getInst +#else + nullptr +#endif + }, + // Insert your own file-encoder infos here. + // Maybe one day the user can add own encoders inside the program. + + FileEncodeDevice{LmmsExporter::ExportAudioFileFormat::Count, nullptr, nullptr, nullptr} +}; + +LmmsExporter::LmmsExporter(const ExportFileType fileType, + const QString& outputLocationAndName) : + m_exportFileType(fileType), + m_outputFile(outputLocationAndName), + m_abort(false), + m_getBufferFunction(nullptr), + m_endFunction(nullptr), + m_getBufferData(nullptr), + m_fileDev(nullptr), + m_buffer(0) +{ + m_thread = nullptr; +} + +LmmsExporter::~LmmsExporter() +{ + // close thread + stopExporting(); + + if (m_fileDev != nullptr) + { + delete m_fileDev; + } +} + +void LmmsExporter::setupAudioRendering( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount, + SampleFrame* exportBuffer, + const fpp_t exportBufferFrameCount) +{ + setupAudioRenderingInternal(outputSettings, fileFormat, defaultFrameCount); + + processThisBuffer(exportBuffer, exportBufferFrameCount); +} + +void LmmsExporter::setupAudioRendering( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount, + BufferFn getBufferFunction, + EndFn endFunction, + void* getBufferData) +{ + m_getBufferFunction = getBufferFunction; + m_endFunction = endFunction; + m_getBufferData = getBufferData; + + setupAudioRenderingInternal(outputSettings, fileFormat, defaultFrameCount); +} + +bool LmmsExporter::canExportAutioFile() const +{ + return m_fileDev != nullptr && (m_buffer.size() > 0 || m_getBufferFunction != nullptr); +} + + + +LmmsExporter::ExportAudioFileFormat LmmsExporter::getAudioFileFormatFromFileName(const QString& fileName) +{ + // TODO test + QString extension = ""; + for (size_t i = fileName.size(); i >= 0; i--) + { + extension = extension + fileName.at(i); + if (fileName.at(i) == ".") + { + break; + } + } + return getAudioFileFormatFromExtension(extension); +} + +LmmsExporter::ExportAudioFileFormat LmmsExporter::getAudioFileFormatFromExtension(const QString& extenisonString) +{ + int idx = 0; + while (s_fileEncodeDevices[idx].m_fileFormat != ExportAudioFileFormat::Count) + { + if (QString(s_fileEncodeDevices[idx].m_extension) == extenisonString) + { + return s_fileEncodeDevices[idx].m_fileFormat; + } + idx++; + } + return ExportAudioFileFormat::Count; +} + +QString LmmsExporter::getAudioFileExtensionFromFormat(ExportAudioFileFormat fmt) +{ + return s_fileEncodeDevices[static_cast(fmt)].m_extension; +} + + + +void LmmsExporter::startExporting() +{ + if (m_thread.get() != nullptr) { return; } + m_abort = false; + + switch (m_exportFileType) + { + case ExportFileType::Audio: + if (canExportAutioFile()) + { + m_thread = std::make_unique(processExportingAudioFile, this); + } + else if (m_endFunction != nullptr) + { + m_endFunction(m_getBufferData); + } + break; + } +} + +void LmmsExporter::stopExporting() +{ + // close thread + if (m_thread.get() != nullptr) + { + m_abort = true; + m_thread->join(); + // deleting unique_ptr + m_thread = nullptr; + } +} + + + +void LmmsExporter::processExportingAudioFile(LmmsExporter* thisExporter) +{ + while (!thisExporter->m_abort) + { + // if a function pointer was provided + // use that to fill m_buffer + if (thisExporter->m_getBufferFunction != nullptr) + { + thisExporter->processNextBuffer(); + } + + // if thisExporter->m_buffer wasn't filled by + // processNextBuffer() or processThisBuffer() before + if (thisExporter->m_buffer.size() <= 0) + { + break; + } + + thisExporter->m_fileDev->processThisBuffer(thisExporter->m_buffer.data(), thisExporter->m_buffer.size()); + + // if no function pointer was provided + if (thisExporter->m_getBufferFunction == nullptr) + { + // clear buffer to end while loop + thisExporter->m_buffer.clear(); + break; + } + } + + if (thisExporter->m_endFunction != nullptr) + { + thisExporter->m_endFunction(thisExporter->m_getBufferData); + } + + // If the user aborted export-process, the file has to be deleted. + if(thisExporter->m_abort) + { + const QString file = thisExporter->m_fileDev->outputFile(); + QFile(file).remove(); + } +} + + + +bool LmmsExporter::processNextBuffer() +{ + m_getBufferFunction(&m_buffer, m_getBufferData); + if (m_buffer.size() <= 0) { return true; } + + return false; +} + +bool LmmsExporter::processThisBuffer(SampleFrame* frameBuffer, const fpp_t frameCount) +{ + if (frameCount <= 0) { m_buffer.clear(); return true; } + if (m_buffer.size() != frameCount) + { + m_buffer.resize(frameCount); + } + + memcpy(m_buffer.data(), frameBuffer, m_buffer.size() * sizeof(SampleFrame)); + return false; +} + +void LmmsExporter::setupAudioRenderingInternal( + const OutputSettings& outputSettings, + ExportAudioFileFormat fileFormat, + const fpp_t defaultFrameCount) +{ + AudioFileDeviceInstantiaton audioEncoderFactory = s_fileEncodeDevices[static_cast(fileFormat)].m_getDevInst; + + if (audioEncoderFactory) + { + bool successful = false; + + m_fileDev = audioEncoderFactory(outputSettings, successful, m_outputFile, defaultFrameCount); + if(!successful) + { + delete m_fileDev; + m_fileDev = nullptr; + } + } +} + +} // namespace lmms + diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index 3d83515f22e..074bfba9b57 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -22,202 +22,57 @@ * */ - -#include - #include "ProjectRenderer.h" #include "Song.h" -#include "PerfLog.h" - -#include "AudioFileWave.h" -#include "AudioFileOgg.h" -#include "AudioFileMP3.h" -#include "AudioFileFlac.h" - namespace lmms { - -const std::array ProjectRenderer::fileEncodeDevices -{ - - FileEncodeDevice{ ProjectRenderer::ExportFileFormat::Wave, - QT_TRANSLATE_NOOP( "ProjectRenderer", "WAV (*.wav)" ), - ".wav", &AudioFileWave::getInst }, - FileEncodeDevice{ ProjectRenderer::ExportFileFormat::Flac, - QT_TRANSLATE_NOOP("ProjectRenderer", "FLAC (*.flac)"), - ".flac", - &AudioFileFlac::getInst - }, - FileEncodeDevice{ ProjectRenderer::ExportFileFormat::Ogg, - QT_TRANSLATE_NOOP( "ProjectRenderer", "OGG (*.ogg)" ), - ".ogg", -#ifdef LMMS_HAVE_OGGVORBIS - &AudioFileOgg::getInst -#else - nullptr -#endif - }, - FileEncodeDevice{ ProjectRenderer::ExportFileFormat::MP3, - QT_TRANSLATE_NOOP( "ProjectRenderer", "MP3 (*.mp3)" ), - ".mp3", -#ifdef LMMS_HAVE_MP3LAME - &AudioFileMP3::getInst -#else - nullptr -#endif - }, - // Insert your own file-encoder infos here. - // Maybe one day the user can add own encoders inside the program. - - FileEncodeDevice{ ProjectRenderer::ExportFileFormat::Count, nullptr, nullptr, nullptr } - -} ; - - - - ProjectRenderer::ProjectRenderer( const AudioEngine::qualitySettings & qualitySettings, const OutputSettings & outputSettings, - ExportFileFormat exportFileFormat, + LmmsExporter::ExportAudioFileFormat exportFileFormat, const QString & outputFilename ) : - QThread( Engine::audioEngine() ), - m_fileDev( nullptr ), - m_qualitySettings( qualitySettings ), - m_progress( 0 ), - m_abort( false ) + m_qualitySettings(qualitySettings), + m_exporter(LmmsExporter::ExportFileType::Audio, outputFilename), + m_progress(0) { - AudioFileDeviceInstantiaton audioEncoderFactory = fileEncodeDevices[static_cast(exportFileFormat)].m_getDevInst; - - if (audioEncoderFactory) - { - bool successful = false; - - m_fileDev = audioEncoderFactory( - outputFilename, outputSettings, DEFAULT_CHANNELS, - Engine::audioEngine(), successful ); - if( !successful ) - { - delete m_fileDev; - m_fileDev = nullptr; - } - } + m_timer = nullptr; + m_exporter.setupAudioRendering(outputSettings, exportFileFormat, Engine::audioEngine()->framesPerPeriod(), + &nextOutputBuffer, &endRendering, this); } - - -// Little help function for getting file format from a file extension -// (only for registered file-encoders). -ProjectRenderer::ExportFileFormat ProjectRenderer::getFileFormatFromExtension( - const QString & _ext ) -{ - int idx = 0; - while( fileEncodeDevices[idx].m_fileFormat != ExportFileFormat::Count ) - { - if( QString( fileEncodeDevices[idx].m_extension ) == _ext ) - { - return( fileEncodeDevices[idx].m_fileFormat ); - } - ++idx; - } - - return( ExportFileFormat::Wave ); // Default. -} - - - - -QString ProjectRenderer::getFileExtensionFromFormat( - ExportFileFormat fmt ) -{ - return fileEncodeDevices[static_cast(fmt)].m_extension; -} - - - - void ProjectRenderer::startProcessing() { - - if( isReady() ) - { - // Have to do audio engine stuff with GUI-thread affinity in order to - // make slots connected to sampleRateChanged()-signals being called immediately. - Engine::audioEngine()->setAudioDevice( m_fileDev, m_qualitySettings, false, false ); - - start( -#ifndef LMMS_BUILD_WIN32 - QThread::HighPriority -#endif - ); - - } -} - - -void ProjectRenderer::run() -{ -#if 0 -#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_FREEBSD) -#ifdef LMMS_HAVE_SCHED_H - cpu_set_t mask; - CPU_ZERO( &mask ); - CPU_SET( 0, &mask ); - sched_setaffinity( 0, sizeof( mask ), &mask ); -#endif -#endif -#endif - - PerfLogTimer perfLog("Project Render"); + m_timer = std::make_unique("Project Render"); Engine::getSong()->startExport(); // Skip first empty buffer. Engine::audioEngine()->nextBuffer(); + Engine::audioEngine()->startExporting(m_qualitySettings); m_progress = 0; - // Now start processing - Engine::audioEngine()->startProcessing(false); - - // Continually track and emit progress percentage to listeners. - while (!Engine::getSong()->isExportDone() && !m_abort) - { - m_fileDev->processNextBuffer(); - const int nprog = Engine::getSong()->getExportProgress(); - if (m_progress != nprog) - { - m_progress = nprog; - emit progressChanged( m_progress ); - } - } - - // Notify the audio engine of the end of processing. - Engine::audioEngine()->stopProcessing(); - - Engine::getSong()->stopExport(); - - perfLog.end(); - - // If the user aborted export-process, the file has to be deleted. - const QString f = m_fileDev->outputFile(); - if( m_abort ) - { - QFile( f ).remove(); - } + m_exporter.startExporting(); } - - - void ProjectRenderer::abortProcessing() { - m_abort = true; - wait(); + m_exporter.stopExporting(); } +void ProjectRenderer::endRendering(void* dataIn) +{ + ProjectRenderer* thisRenderer = reinterpret_cast(dataIn); + + Engine::audioEngine()->stopProcessing(); + Engine::getSong()->stopExport(); + thisRenderer->m_timer->end(); + thisRenderer->m_timer = nullptr; + + emit thisRenderer->finished(); +} void ProjectRenderer::updateConsoleProgress() { @@ -242,5 +97,50 @@ void ProjectRenderer::updateConsoleProgress() fflush( stderr ); } +// gets a buffer and some data as input +// the sender who constructed lmms::LmmsExporter decides what is dataIn (in this case it is ProjectRenderer) +// fills the provided buffer with AudioEngine::nextBuffer() data and sets the correct size +// this class doesn't own bufferOut +// bufferOut can not be nullptr +// dataIn can be nullptr +void ProjectRenderer::nextOutputBuffer(std::vector* bufferOut, void* dataIn) +{ + ProjectRenderer* thisRenderer = reinterpret_cast(dataIn); + + fpp_t curFrames = Engine::audioEngine()->framesPerPeriod(); + if (bufferOut->size() != curFrames) + { + bufferOut->resize(curFrames); + } + + // get next buffer + const SampleFrame* newBuffer = Engine::audioEngine()->nextBuffer(); + + if (newBuffer != nullptr && Engine::getSong()->isExportDone() == false) + { + // copy new buffer to bufferOut + for (size_t i = 0; i < bufferOut->size(); i++) + { + (*bufferOut)[i] = newBuffer[i]; + } + + // update progress + const int nprog = Engine::getSong()->getExportProgress(); + if (thisRenderer->m_progress != nprog) + { + thisRenderer->m_progress = nprog; + emit thisRenderer->progressChanged(thisRenderer->m_progress); + } + + // delete source buffer + if (Engine::audioEngine()->hasFifoWriter()) { delete[] newBuffer; } + } + else + { + // this will stop LmmsExporter exporting + bufferOut->clear(); + } +} + } // namespace lmms diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index d375b95ee5a..7a40e1645a8 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -38,7 +38,7 @@ namespace lmms RenderManager::RenderManager( const AudioEngine::qualitySettings & qualitySettings, const OutputSettings & outputSettings, - ProjectRenderer::ExportFileFormat fmt, + LmmsExporter::ExportAudioFileFormat fmt, QString outputPath) : m_qualitySettings(qualitySettings), m_oldQualitySettings( Engine::audioEngine()->currentQualitySettings() ), @@ -181,7 +181,7 @@ void RenderManager::restoreMutedState() // Determine the output path for a track when rendering tracks individually QString RenderManager::pathForTrack(const Track *track, int num) { - QString extension = ProjectRenderer::getFileExtensionFromFormat( m_format ); + QString extension = LmmsExporter::getAudioFileExtensionFromFormat(m_format); QString name = track->name(); name = name.remove(QRegularExpression(FILENAME_FILTER)); name = QString( "%1_%2%3" ).arg( num ).arg( name ).arg( extension ); @@ -205,4 +205,4 @@ void RenderManager::updateConsoleProgress() } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp index 2047fffe98b..ebfe9bbcc8e 100644 --- a/src/core/audio/AudioDevice.cpp +++ b/src/core/audio/AudioDevice.cpp @@ -130,17 +130,19 @@ void AudioDevice::renamePort( AudioPort * ) int AudioDevice::convertToS16(const SampleFrame* _ab, const fpp_t _frames, int_sample_t * _output_buffer, - const bool _convert_endian ) + + const bool _convert_endian) { + const unsigned int channels = 2; if( _convert_endian ) { for( fpp_t frame = 0; frame < _frames; ++frame ) { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) + for (ch_cnt_t chnl = 0; chnl < channels; ++chnl) { auto temp = static_cast(AudioEngine::clip(_ab[frame][chnl]) * OUTPUT_SAMPLE_MULTIPLIER); - ( _output_buffer + frame * channels() )[chnl] = + ( _output_buffer + frame * channels )[chnl] = ( temp & 0x00ff ) << 8 | ( temp & 0xff00 ) >> 8; } @@ -150,26 +152,27 @@ int AudioDevice::convertToS16(const SampleFrame* _ab, { for( fpp_t frame = 0; frame < _frames; ++frame ) { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) + for (ch_cnt_t chnl = 0; chnl < channels; ++chnl) { - (_output_buffer + frame * channels())[chnl] + (_output_buffer + frame * channels)[chnl] = static_cast(AudioEngine::clip(_ab[frame][chnl]) * OUTPUT_SAMPLE_MULTIPLIER); } } } - return _frames * channels() * BYTES_PER_INT_SAMPLE; + return _frames * channels * BYTES_PER_INT_SAMPLE; } -void AudioDevice::clearS16Buffer( int_sample_t * _outbuf, const fpp_t _frames ) +void AudioDevice::clearS16Buffer(int_sample_t * _outbuf, const fpp_t _frames) { assert( _outbuf != nullptr ); - memset( _outbuf, 0, _frames * channels() * BYTES_PER_INT_SAMPLE ); + const unsigned int channels = 2; + memset(_outbuf, 0, _frames * channels * BYTES_PER_INT_SAMPLE); } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/core/audio/AudioFileDevice.cpp b/src/core/audio/AudioFileDevice.cpp index f80d4a00f91..ee9b486691f 100644 --- a/src/core/audio/AudioFileDevice.cpp +++ b/src/core/audio/AudioFileDevice.cpp @@ -32,18 +32,15 @@ namespace lmms { -AudioFileDevice::AudioFileDevice( OutputSettings const & outputSettings, - const ch_cnt_t _channels, - const QString & _file, - AudioEngine* _audioEngine ) : - AudioDevice( _channels, _audioEngine ), +AudioFileDevice::AudioFileDevice(OutputSettings const& outputSettings, + const QString& _file, + const fpp_t defaultBufferSize) : m_outputFile( _file ), - m_outputSettings(outputSettings) + m_outputSettings(outputSettings), + m_defaultFrameCount(defaultBufferSize) { using gui::ExportProjectDialog; - setSampleRate( outputSettings.getSampleRate() ); - if( m_outputFile.open( QFile::WriteOnly | QFile::Truncate ) == false ) { QString title, message; @@ -78,7 +75,25 @@ AudioFileDevice::~AudioFileDevice() m_outputFile.close(); } +sample_rate_t AudioFileDevice::getSampleRate() +{ + return m_outputSettings.getSampleRate(); +} + +const fpp_t AudioFileDevice::getDefaultFrameCount() +{ + return m_defaultFrameCount; +} +void AudioFileDevice::setSampleRate(sample_rate_t newSampleRate) +{ + m_outputSettings.setSampleRate(newSampleRate); +} + +void AudioFileDevice::processThisBuffer(SampleFrame* frameBuffer, const fpp_t frameCount) +{ + writeBuffer(frameBuffer, frameCount); +} int AudioFileDevice::writeData( const void* data, int len ) diff --git a/src/core/audio/AudioFileFlac.cpp b/src/core/audio/AudioFileFlac.cpp index dfb97a6beba..55496c386ce 100644 --- a/src/core/audio/AudioFileFlac.cpp +++ b/src/core/audio/AudioFileFlac.cpp @@ -28,14 +28,19 @@ #include #include "AudioFileFlac.h" -#include "endian_handling.h" + +#include "AudioDevice.h" // convertToS16 #include "AudioEngine.h" +#include "endian_handling.h" namespace lmms { -AudioFileFlac::AudioFileFlac(OutputSettings const& outputSettings, ch_cnt_t const channels, bool& successful, QString const& file, AudioEngine* audioEngine): - AudioFileDevice(outputSettings,channels,file,audioEngine), +AudioFileFlac::AudioFileFlac(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize) : + AudioFileDevice(outputSettings, file, defaultBufferSize), m_sf(nullptr) { successful = outputFileOpened() && startEncoding(); @@ -48,9 +53,9 @@ AudioFileFlac::~AudioFileFlac() bool AudioFileFlac::startEncoding() { - m_sfinfo.samplerate=sampleRate(); - m_sfinfo.channels=channels(); - m_sfinfo.frames = audioEngine()->framesPerPeriod(); + m_sfinfo.samplerate = getSampleRate(); + m_sfinfo.channels = 2; + m_sfinfo.frames = getDefaultFrameCount(); m_sfinfo.sections=1; m_sfinfo.seekable=0; @@ -91,28 +96,29 @@ bool AudioFileFlac::startEncoding() void AudioFileFlac::writeBuffer(const SampleFrame* _ab, fpp_t const frames) { + const unsigned int channels = 2; OutputSettings::BitDepth depth = getOutputSettings().getBitDepth(); float clipvalue = std::nextafterf( -1.0f, 0.0f ); if (depth == OutputSettings::BitDepth::Depth24Bit || depth == OutputSettings::BitDepth::Depth32Bit) // Float encoding { - auto buf = std::vector(frames * channels()); + auto buf = std::vector(frames * channels); for(fpp_t frame = 0; frame < frames; ++frame) { - for(ch_cnt_t channel=0; channel(buf.data()), frames); } else // integer PCM encoding { - auto buf = std::vector(frames * channels()); - convertToS16(_ab, frames, buf.data(), !isLittleEndian()); + auto buf = std::vector(frames * channels); + AudioDevice::convertToS16(_ab, frames, buf.data(), !isLittleEndian()); sf_writef_short(m_sf, static_cast(buf.data()), frames); } @@ -128,4 +134,4 @@ void AudioFileFlac::finishEncoding() } } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/core/audio/AudioFileMP3.cpp b/src/core/audio/AudioFileMP3.cpp index 4d1dbc02007..e80ec35f508 100644 --- a/src/core/audio/AudioFileMP3.cpp +++ b/src/core/audio/AudioFileMP3.cpp @@ -35,16 +35,13 @@ namespace lmms { -AudioFileMP3::AudioFileMP3( OutputSettings const & outputSettings, - const ch_cnt_t channels, - bool & successful, - const QString & file, - AudioEngine* audioEngine ) : - AudioFileDevice( outputSettings, channels, file, audioEngine ) +AudioFileMP3::AudioFileMP3(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize) : + AudioFileDevice(outputSettings, file, defaultBufferSize) { successful = true; - // For now only accept stereo sources - successful &= channels == 2; successful &= initEncoder(); successful &= outputFileOpened(); } diff --git a/src/core/audio/AudioFileOgg.cpp b/src/core/audio/AudioFileOgg.cpp index 59b796730bf..8ab20d7ad14 100644 --- a/src/core/audio/AudioFileOgg.cpp +++ b/src/core/audio/AudioFileOgg.cpp @@ -41,12 +41,11 @@ namespace lmms { -AudioFileOgg::AudioFileOgg( OutputSettings const & outputSettings, - const ch_cnt_t channels, - bool & successful, - const QString & file, - AudioEngine* audioEngine ) : - AudioFileDevice( outputSettings, channels, file, audioEngine ) +AudioFileOgg::AudioFileOgg(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize) : + AudioFileDevice(outputSettings, file, defaultBufferSize) { m_ok = successful = outputFileOpened() && startEncoding(); } @@ -85,7 +84,7 @@ bool AudioFileOgg::startEncoding() vc.comments = 1; vc.vendor = nullptr; - m_channels = channels(); + m_channels = 2; bool useVariableBitRate = getOutputSettings().getBitRateSettings().isVariableBitRate(); bitrate_t minimalBitrate = nominalBitrate(); @@ -98,7 +97,7 @@ bool AudioFileOgg::startEncoding() } - m_rate = sampleRate(); // default-samplerate + m_rate = getSampleRate(); // default-samplerate if( m_rate > 48000 ) { m_rate = 48000; @@ -181,14 +180,13 @@ bool AudioFileOgg::startEncoding() void AudioFileOgg::writeBuffer(const SampleFrame* _ab, const fpp_t _frames) { + const unsigned int channels = 2; int eos = 0; - float * * buffer = vorbis_analysis_buffer( &m_vd, _frames * - BYTES_PER_SAMPLE * - channels() ); + float** buffer = vorbis_analysis_buffer( &m_vd, _frames * BYTES_PER_SAMPLE * channels); for( fpp_t frame = 0; frame < _frames; ++frame ) { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) + for (ch_cnt_t chnl = 0; chnl < channels; chnl++) { buffer[chnl][frame] = _ab[frame][chnl]; } @@ -263,4 +261,3 @@ void AudioFileOgg::finishEncoding() #endif // LMMS_HAVE_OGGVORBIS - diff --git a/src/core/audio/AudioFileWave.cpp b/src/core/audio/AudioFileWave.cpp index 4b4b928c5be..1b49523fedb 100644 --- a/src/core/audio/AudioFileWave.cpp +++ b/src/core/audio/AudioFileWave.cpp @@ -24,18 +24,20 @@ */ #include "AudioFileWave.h" -#include "endian_handling.h" + +#include "AudioDevice.h" // convertToS16 #include "AudioEngine.h" +#include "endian_handling.h" namespace lmms { -AudioFileWave::AudioFileWave( OutputSettings const & outputSettings, - const ch_cnt_t channels, bool & successful, - const QString & file, - AudioEngine* audioEngine ) : - AudioFileDevice( outputSettings, channels, file, audioEngine ), +AudioFileWave::AudioFileWave(OutputSettings const& outputSettings, + bool& successful, + const QString& file, + const fpp_t defaultBufferSize) : + AudioFileDevice(outputSettings, file, defaultBufferSize), m_sf( nullptr ) { successful = outputFileOpened() && startEncoding(); @@ -54,9 +56,9 @@ AudioFileWave::~AudioFileWave() bool AudioFileWave::startEncoding() { - m_si.samplerate = sampleRate(); - m_si.channels = channels(); - m_si.frames = audioEngine()->framesPerPeriod(); + m_si.samplerate = getSampleRate(); + m_si.channels = 2; + m_si.frames = getDefaultFrameCount(); m_si.sections = 1; m_si.seekable = 0; @@ -95,16 +97,17 @@ bool AudioFileWave::startEncoding() void AudioFileWave::writeBuffer(const SampleFrame* _ab, const fpp_t _frames) { + const unsigned int channels = 2; OutputSettings::BitDepth bitDepth = getOutputSettings().getBitDepth(); if( bitDepth == OutputSettings::BitDepth::Depth32Bit || bitDepth == OutputSettings::BitDepth::Depth24Bit ) { - auto buf = new float[_frames * channels()]; + auto buf = new float[_frames * channels]; for( fpp_t frame = 0; frame < _frames; ++frame ) { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) + for (ch_cnt_t chnl = 0; chnl < channels; ++chnl) { - buf[frame * channels() + chnl] = _ab[frame][chnl]; + buf[frame * channels + chnl] = _ab[frame][chnl]; } } sf_writef_float( m_sf, buf, _frames ); @@ -112,8 +115,8 @@ void AudioFileWave::writeBuffer(const SampleFrame* _ab, const fpp_t _frames) } else { - auto buf = new int_sample_t[_frames * channels()]; - convertToS16(_ab, _frames, buf, !isLittleEndian()); + auto buf = new int_sample_t[_frames * channels]; + AudioDevice::convertToS16(_ab, _frames, buf, !isLittleEndian()); sf_writef_short( m_sf, buf, _frames ); delete[] buf; @@ -131,4 +134,4 @@ void AudioFileWave::finishEncoding() } } -} // namespace lmms \ No newline at end of file +} // namespace lmms diff --git a/src/core/main.cpp b/src/core/main.cpp index 3e6c2c85f06..ef555351b8a 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -379,7 +379,7 @@ int main( int argc, char * * argv ) AudioEngine::qualitySettings qs(AudioEngine::qualitySettings::Interpolation::Linear); OutputSettings os( 44100, OutputSettings::BitRateSettings(160, false), OutputSettings::BitDepth::Depth16Bit, OutputSettings::StereoMode::JointStereo ); - ProjectRenderer::ExportFileFormat eff = ProjectRenderer::ExportFileFormat::Wave; + LmmsExporter::ExportAudioFileFormat eff = LmmsExporter::ExportAudioFileFormat::Wave; // second of two command-line parsing stages for( int i = 1; i < argc; ++i ) @@ -521,23 +521,23 @@ int main( int argc, char * * argv ) if( ext == "wav" ) { - eff = ProjectRenderer::ExportFileFormat::Wave; + eff = LmmsExporter::ExportAudioFileFormat::Wave; } #ifdef LMMS_HAVE_OGGVORBIS else if( ext == "ogg" ) { - eff = ProjectRenderer::ExportFileFormat::Ogg; + eff = LmmsExporter::ExportAudioFileFormat::Ogg; } #endif #ifdef LMMS_HAVE_MP3LAME else if( ext == "mp3" ) { - eff = ProjectRenderer::ExportFileFormat::MP3; + eff = LmmsExporter::ExportAudioFileFormat::MP3; } #endif else if (ext == "flac") { - eff = ProjectRenderer::ExportFileFormat::Flac; + eff = LmmsExporter::ExportAudioFileFormat::Flac; } else { @@ -776,7 +776,7 @@ int main( int argc, char * * argv ) if ( !renderTracks ) { renderOut = baseName( renderOut ) + - ProjectRenderer::getFileExtensionFromFormat(eff); + LmmsExporter::getAudioFileExtensionFromFormat(eff); } // create renderer diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index d534be96f3f..a7753d0156c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -57,7 +57,7 @@ #include "PluginView.h" #include "ProjectJournal.h" #include "ProjectNotes.h" -#include "ProjectRenderer.h" +#include "LmmsExporter.h" #include "RecentProjectsMenu.h" #include "RemotePlugin.h" #include "SetupDialog.h" @@ -1464,10 +1464,10 @@ void MainWindow::exportProject(bool multiExport) efd.setFileMode( FileDialog::AnyFile ); int idx = 0; QStringList types; - while( ProjectRenderer::fileEncodeDevices[idx].m_fileFormat != ProjectRenderer::ExportFileFormat::Count) + while (LmmsExporter::s_fileEncodeDevices[idx].m_fileFormat != LmmsExporter::ExportAudioFileFormat::Count) { - if(ProjectRenderer::fileEncodeDevices[idx].isAvailable()) { - types << tr(ProjectRenderer::fileEncodeDevices[idx].m_description); + if (LmmsExporter::s_fileEncodeDevices[idx].isAvailable()) { + types << tr(LmmsExporter::s_fileEncodeDevices[idx].m_description); } ++idx; } @@ -1483,7 +1483,7 @@ void MainWindow::exportProject(bool multiExport) efd.setDirectory( ConfigManager::inst()->userProjectsDir() ); baseFilename = tr( "untitled" ); } - efd.selectFile( baseFilename + ProjectRenderer::fileEncodeDevices[0].m_extension ); + efd.selectFile(baseFilename + LmmsExporter::s_fileEncodeDevices[0].m_extension); efd.setWindowTitle( tr( "Select file for project-export..." ) ); } diff --git a/src/gui/modals/ExportProjectDialog.cpp b/src/gui/modals/ExportProjectDialog.cpp index 1f989841f3b..70133f8d731 100644 --- a/src/gui/modals/ExportProjectDialog.cpp +++ b/src/gui/modals/ExportProjectDialog.cpp @@ -56,17 +56,17 @@ ExportProjectDialog::ExportProjectDialog( const QString & _file_name, } int cbIndex = 0; - for (auto i = std::size_t{0}; i < ProjectRenderer::NumFileFormats; ++i) + for (auto i = std::size_t{0}; i < LmmsExporter::NumFileFormats; ++i) { - if( ProjectRenderer::fileEncodeDevices[i].isAvailable() ) + if (LmmsExporter::s_fileEncodeDevices[i].isAvailable()) { // Get the extension of this format. - QString renderExt = ProjectRenderer::fileEncodeDevices[i].m_extension; + QString renderExt = LmmsExporter::s_fileEncodeDevices[i].m_extension; // Add to combo box. - fileFormatCB->addItem( ProjectRenderer::tr( - ProjectRenderer::fileEncodeDevices[i].m_description ), - QVariant( static_cast(ProjectRenderer::fileEncodeDevices[i].m_fileFormat) ) // Format tag; later used for identification. + fileFormatCB->addItem(ProjectRenderer::tr( + LmmsExporter::s_fileEncodeDevices[i].m_description), + QVariant(static_cast(LmmsExporter::s_fileEncodeDevices[i].m_fileFormat)) // Format tag; later used for identification. ); // If this is our extension, select it. @@ -213,27 +213,27 @@ void ExportProjectDialog::onFileFormatChanged(int index) // and adjust the UI properly. QVariant format_tag = fileFormatCB->itemData(index); bool successful_conversion = false; - auto exportFormat = static_cast( + auto exportFormat = static_cast( format_tag.toInt(&successful_conversion) ); Q_ASSERT(successful_conversion); - bool stereoModeVisible = (exportFormat == ProjectRenderer::ExportFileFormat::MP3); + bool stereoModeVisible = (exportFormat == LmmsExporter::ExportAudioFileFormat::MP3); - bool sampleRateControlsVisible = (exportFormat != ProjectRenderer::ExportFileFormat::MP3); + bool sampleRateControlsVisible = (exportFormat != LmmsExporter::ExportAudioFileFormat::MP3); bool bitRateControlsEnabled = - (exportFormat == ProjectRenderer::ExportFileFormat::Ogg || - exportFormat == ProjectRenderer::ExportFileFormat::MP3); + (exportFormat == LmmsExporter::ExportAudioFileFormat::Ogg || + exportFormat == LmmsExporter::ExportAudioFileFormat::MP3); bool bitDepthControlEnabled = - (exportFormat == ProjectRenderer::ExportFileFormat::Wave || - exportFormat == ProjectRenderer::ExportFileFormat::Flac); + (exportFormat == LmmsExporter::ExportAudioFileFormat::Wave || + exportFormat == LmmsExporter::ExportAudioFileFormat::Flac); - bool variableBitrateVisible = !(exportFormat == ProjectRenderer::ExportFileFormat::MP3 || exportFormat == ProjectRenderer::ExportFileFormat::Flac); + bool variableBitrateVisible = !(exportFormat == LmmsExporter::ExportAudioFileFormat::MP3 || exportFormat == LmmsExporter::ExportAudioFileFormat::Flac); #ifdef LMMS_HAVE_SF_COMPLEVEL - bool compressionLevelVisible = (exportFormat == ProjectRenderer::ExportFileFormat::Flac); + bool compressionLevelVisible = (exportFormat == LmmsExporter::ExportAudioFileFormat::Flac); compressionWidget->setVisible(compressionLevelVisible); #endif @@ -248,12 +248,12 @@ void ExportProjectDialog::onFileFormatChanged(int index) void ExportProjectDialog::startBtnClicked() { - m_ft = ProjectRenderer::ExportFileFormat::Count; + m_ft = LmmsExporter::ExportAudioFileFormat::Count; // Get file format from current menu selection. bool successful_conversion = false; QVariant tag = fileFormatCB->itemData(fileFormatCB->currentIndex()); - m_ft = static_cast( + m_ft = static_cast( tag.toInt(&successful_conversion) ); @@ -268,11 +268,11 @@ void ExportProjectDialog::startBtnClicked() } // Find proper file extension. - for (auto i = std::size_t{0}; i < ProjectRenderer::NumFileFormats; ++i) + for (auto i = std::size_t{0}; i < LmmsExporter::NumFileFormats; ++i) { - if (m_ft == ProjectRenderer::fileEncodeDevices[i].m_fileFormat) + if (m_ft == LmmsExporter::s_fileEncodeDevices[i].m_fileFormat) { - m_fileExtension = QString( QLatin1String( ProjectRenderer::fileEncodeDevices[i].m_extension ) ); + m_fileExtension = QString(QLatin1String(LmmsExporter::s_fileEncodeDevices[i].m_extension)); break; } }