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

Add FLAC export and related options #3731

Merged
merged 20 commits into from
Aug 3, 2017
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,14 @@ ELSE()
ENDIF()

# check for libsndfile
PKG_CHECK_MODULES(SNDFILE REQUIRED sndfile>=1.0.11)
PKG_CHECK_MODULES(SNDFILE REQUIRED sndfile>=1.0.18)
IF(NOT SNDFILE_FOUND)
MESSAGE(FATAL_ERROR "LMMS requires libsndfile1 and libsndfile1-dev >= 1.0.11 - please install, remove CMakeCache.txt and try again!")
ENDIF(NOT SNDFILE_FOUND)
MESSAGE(FATAL_ERROR "LMMS requires libsndfile1 and libsndfile1-dev >= 1.0.18 - please install, remove CMakeCache.txt and try again!")
ENDIF()
# check if we can use SF_SET_COMPRESSION_LEVEL
IF(NOT SNDFILE_VERSION VERSION_LESS 1.0.26)
SET(LMMS_HAVE_SF_COMPLEVEL TRUE)
ENDIF()

IF(WANT_CALF)
SET(LMMS_HAVE_CALF TRUE)
Expand Down
2 changes: 1 addition & 1 deletion doc/lmms.1
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default)
.IP "\fB\-d, --dump\fP \fIin\fP
Dump XML of compressed file \fIin\fP (i.e. MMPZ-file)
.IP "\fB\-f, --format\fP \fIformat\fP
Specify format of render-output where \fIformat\fP is either 'wav', 'ogg' or 'mp3'.
Specify format of render-output where \fIformat\fP is either 'wav', 'flac', 'ogg' or 'mp3'.
.IP "\fB\ --geometry\fP \fIgeometry\fP
Specify the prefered size and position of the main window
.br
Expand Down
68 changes: 68 additions & 0 deletions include/AudioFileFlac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* AudioFileFlac.h - Audio device which encodes a wave stream into a FLAC file.
*
* Copyright (c) 2017 to present Levin Oehlmann <irrenhaus3/at/gmail[dot]com> et al.
*
* 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.
*
*/
Copy link
Member

Choose a reason for hiding this comment

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

You should put the copyright information here.


#ifndef AUDIO_FILE_FLAC_H
#define AUDIO_FILE_FLAC_H

#include "lmmsconfig.h"

#include "AudioFileDevice.h"
#include <sndfile.h>

class AudioFileFlac: public AudioFileDevice
{
public:
AudioFileFlac(OutputSettings const& outputSettings,
ch_cnt_t const channels,
bool& successful,
QString const& file,
Mixer* mixer
);

virtual ~AudioFileFlac();

static AudioFileDevice* getInst(QString const& outputFilename,
OutputSettings const& outputSettings,
ch_cnt_t const channels,
Mixer* mixer,
bool& successful)
{
return new AudioFileFlac(outputSettings,channels,successful,outputFilename,mixer);
}

private:

SF_INFO m_sfinfo;
SNDFILE* m_sf;

virtual void writeBuffer(surroundSampleFrame const* _ab,
fpp_t const frames,
float master_gain) override;

bool startEncoding();
void finishEncoding();

};

#endif //AUDIO_FILE_FLAC_H
6 changes: 2 additions & 4 deletions include/ExportProjectDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#define EXPORT_PROJECT_DIALOG_H

#include <QDialog>
#include <vector>
#include <memory>
#include "ui_export_project.h"

#include "ProjectRenderer.h"
Expand All @@ -39,8 +39,6 @@ class ExportProjectDialog : public QDialog, public Ui::ExportProjectDialog
Q_OBJECT
public:
ExportProjectDialog( const QString & _file_name, QWidget * _parent, bool multi_export );
virtual ~ExportProjectDialog();


protected:
virtual void reject( void );
Expand All @@ -62,7 +60,7 @@ private slots:
bool m_multiExport;

ProjectRenderer::ExportFileFormats m_ft;
RenderManager* m_renderManager;
std::unique_ptr<RenderManager> m_renderManager;
} ;

#endif
11 changes: 10 additions & 1 deletion include/OutputSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class OutputSettings
m_sampleRate(sampleRate),
m_bitRateSettings(bitRateSettings),
m_bitDepth(bitDepth),
m_stereoMode(stereoMode)
m_stereoMode(stereoMode),
m_compressionLevel(0.5)
{
}

Expand All @@ -95,11 +96,19 @@ class OutputSettings
StereoMode getStereoMode() const { return m_stereoMode; }
void setStereoMode(StereoMode stereoMode) { m_stereoMode = stereoMode; }


double getCompressionLevel() const{ return m_compressionLevel; }
void setCompressionLevel(double level){
// legal range is 0.0 to 1.0.
m_compressionLevel = level;
}

private:
sample_rate_t m_sampleRate;
BitRateSettings m_bitRateSettings;
BitDepth m_bitDepth;
StereoMode m_stereoMode;
double m_compressionLevel;
};

#endif
1 change: 1 addition & 0 deletions include/ProjectRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ProjectRenderer : public QThread
enum ExportFileFormats: int
{
WaveFile,
FlacFile,
OggFile,
MP3File,
NumFileFormats
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ set(LMMS_SRCS
core/audio/AudioFileDevice.cpp
core/audio/AudioFileMP3.cpp
core/audio/AudioFileOgg.cpp
core/audio/AudioFileFlac.cpp
core/audio/AudioFileWave.cpp
core/audio/AudioJack.cpp
core/audio/AudioOss.cpp
Expand Down
10 changes: 8 additions & 2 deletions src/core/ProjectRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "AudioFileWave.h"
#include "AudioFileOgg.h"
#include "AudioFileMP3.h"
#include "AudioFileFlac.h"

#ifdef LMMS_HAVE_SCHED_H
#include "sched.h"
Expand All @@ -42,6 +43,11 @@ const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] =
{ ProjectRenderer::WaveFile,
QT_TRANSLATE_NOOP( "ProjectRenderer", "WAV-File (*.wav)" ),
".wav", &AudioFileWave::getInst },
{ ProjectRenderer::FlacFile,
QT_TRANSLATE_NOOP("ProjectRenderer", "FLAC-File (*.flac)"),
".flac",
&AudioFileFlac::getInst
},
{ ProjectRenderer::OggFile,
QT_TRANSLATE_NOOP( "ProjectRenderer", "Compressed OGG-File (*.ogg)" ),
".ogg",
Expand Down Expand Up @@ -176,8 +182,8 @@ void ProjectRenderer::run()

Engine::getSong()->startExport();
Engine::getSong()->updateLength();
//skip first empty buffer
Engine::mixer()->nextBuffer();
//skip first empty buffer
Engine::mixer()->nextBuffer();

const Song::PlayPos & exportPos = Engine::getSong()->getPlayPos(
Song::Mode_PlaySong );
Expand Down
119 changes: 119 additions & 0 deletions src/core/audio/AudioFileFlac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* AudioFileFlac.cpp - Audio device which encodes a wave stream into a FLAC file (Implementation).
*
* Copyright (c) 2017 to present Levin Oehlmann <irrenhaus3/at/gmail[dot]com> et al.
*
* 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 <memory>
Copy link
Member

Choose a reason for hiding this comment

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

Here, too.


#include "AudioFileFlac.h"
#include "endian_handling.h"
#include "Mixer.h"

AudioFileFlac::AudioFileFlac(OutputSettings const& outputSettings, ch_cnt_t const channels, bool& successful, QString const& file, Mixer* mixer):
AudioFileDevice(outputSettings,channels,file,mixer),
m_sf(nullptr)
{
successful = outputFileOpened() && startEncoding();
}

AudioFileFlac::~AudioFileFlac()
{
finishEncoding();
}

bool AudioFileFlac::startEncoding()
{
m_sfinfo.samplerate=sampleRate();
m_sfinfo.channels=channels();
m_sfinfo.frames = mixer()->framesPerPeriod();
m_sfinfo.sections=1;
m_sfinfo.seekable=0;

m_sfinfo.format = SF_FORMAT_FLAC;

switch (getOutputSettings().getBitDepth())
{
case OutputSettings::Depth_24Bit:
case OutputSettings::Depth_32Bit:
// FLAC does not support 32bit sampling, so take it as 24.
m_sfinfo.format |= SF_FORMAT_PCM_24;
break;
default:
m_sfinfo.format |= SF_FORMAT_PCM_16;
}

#ifdef LMMS_HAVE_SF_COMPLEVEL
double compression = getOutputSettings().getCompressionLevel();
sf_command(m_sf,SFC_SET_COMPRESSION_LEVEL,&compression,sizeof(double));
#endif

m_sf = sf_open(
#ifdef LMMS_BUILD_WIN32
outputFile().toLocal8Bit().constData(),
#else
outputFile().toUtf8().constData(),
#endif
SFM_WRITE,
&m_sfinfo
);

sf_command(m_sf,SFC_SET_CLIPPING,nullptr,SF_TRUE);
Copy link
Member

Choose a reason for hiding this comment

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

It is conventional to put spaces between parameters.

Copy link
Member

Choose a reason for hiding this comment

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

Like foo(b, a, r);.


sf_set_string(m_sf,SF_STR_SOFTWARE,"LMMS");

return true;
}

void AudioFileFlac::writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames, float master_gain)
{
OutputSettings::BitDepth depth = getOutputSettings().getBitDepth();

if (depth == OutputSettings::Depth_24Bit || depth == OutputSettings::Depth_32Bit) // Float encoding
{
std::unique_ptr<sample_t[]> buf{ new sample_t[frames*channels()] };
for(fpp_t frame = 0; frame < frames; ++frame)
{
for(ch_cnt_t channel=0; channel<channels(); ++channel)
{
buf[frame*channels()+channel] = _ab[frame][channel] * master_gain;
}
}
sf_writef_float(m_sf,static_cast<float*>(buf.get()),frames);
}
else // integer PCM encoding
{
std::unique_ptr<int_sample_t[]> buf{ new int_sample_t[frames*channels()] };
convertToS16(_ab,frames,master_gain,buf.get(),!isLittleEndian());
sf_writef_short(m_sf,static_cast<short*>(buf.get()),frames);
}

}


void AudioFileFlac::finishEncoding()
{
if (m_sf)
{
sf_write_sync(m_sf);
sf_close(m_sf);
}
}
6 changes: 5 additions & 1 deletion src/core/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void printHelp()
"-c, --config <configfile> Get the configuration from <configfile>\n"
"-d, --dump <in> Dump XML of compressed file <in>\n"
"-f, --format <format> Specify format of render-output where\n"
" Format is either 'wav', 'ogg' or 'mp3'.\n"
" Format is either 'wav', 'flac', 'ogg' or 'mp3'.\n"
" --geometry <geometry> Specify the size and position of the main window\n"
" geometry is <xsizexysize+xoffset+yoffsety>.\n"
"-h, --help Show this usage information and exit.\n"
Expand Down Expand Up @@ -444,6 +444,10 @@ int main( int argc, char * * argv )
eff = ProjectRenderer::MP3File;
}
#endif
else if (ext == "flac")
{
eff = ProjectRenderer::FlacFile;
}
else
{
printf( "\nInvalid output format %s.\n\n"
Expand Down
Loading