-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Changes from 13 commits
5f1c9dc
b41bbab
ed7a4b6
d7bb49a
36354a8
8fe7994
5ba265f
caba25e
f89475d
dfe6a69
9d24ebc
14b6ce3
20cbfbf
65443db
d7ee49c
18cda1d
597d947
597bc8f
2c3cb02
521c08c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* AudioFileFlac.h - Audio device which encodes a wave stream into a FLAC file. | ||
*/ | ||
|
||
#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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
#include "AudioFileWave.h" | ||
#include "AudioFileOgg.h" | ||
#include "AudioFileMP3.h" | ||
#include "AudioFileFlac.h" | ||
|
||
#ifdef LMMS_HAVE_SCHED_H | ||
#include "sched.h" | ||
|
@@ -42,6 +43,11 @@ const ProjectRenderer::FileEncodeDevice ProjectRenderer::fileEncodeDevices[] = | |
{ ProjectRenderer::WaveFile, | ||
QT_TRANSLATE_NOOP( "ProjectRenderer", "WAV-File (*.wav)" ), | ||
".wav", &AudioFileWave::getInst }, | ||
{ ProjectRenderer::FlacFile, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @irrenhaus3 this needs formatting, spaces versus tabs. :) |
||
QT_TRANSLATE_NOOP("ProjectRenderer", "FLAC-File (*.flac)"), | ||
".flac", | ||
&AudioFileFlac::getInst | ||
}, | ||
{ ProjectRenderer::OggFile, | ||
QT_TRANSLATE_NOOP( "ProjectRenderer", "Compressed OGG-File (*.ogg)" ), | ||
".ogg", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#include <memory> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is conventional to put spaces between parameters. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like |
||
|
||
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); | ||
} | ||
} |
There was a problem hiding this comment.
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.