diff --git a/src/encoder/encoder.cpp b/src/encoder/encoder.cpp index 069bf7d1add3..e1c741ec32d8 100644 --- a/src/encoder/encoder.cpp +++ b/src/encoder/encoder.cpp @@ -155,3 +155,29 @@ EncoderRecordingSettingsPointer EncoderFactory::getEncoderRecordingSettings(Enco return std::make_shared(pConfig, ENCODING_WAVE); } } + +void Encoder::addToTracklist(const QString& artist, + const QString& title, + std::chrono::seconds timecode) { + auto recordedDuration = timecode.count(); + m_trackList.append( + QStringLiteral("%1: %2 - %3") + .arg(QString("%1:%2:%3") + .arg(recordedDuration / 60 * 60, + 2, + 'f', + 0, + '0') // hours + .arg((recordedDuration / 60) % 60, + 2, + 'f', + 0, + '0') // minutes + .arg(recordedDuration % 60, 2, 'f', 0, '0'), + artist.trimmed().isEmpty() + ? QObject::tr("(Unknown Artist)") + : artist, + title.trimmed().isEmpty() + ? QObject::tr("(Unknown Title)") + : title)); +} diff --git a/src/encoder/encoder.h b/src/encoder/encoder.h index 14c9af91d1f5..5cedaa962692 100644 --- a/src/encoder/encoder.h +++ b/src/encoder/encoder.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "encoder/encoderrecordingsettings.h" @@ -32,11 +33,23 @@ class Encoder { virtual void encodeBuffer(const CSAMPLE *samples, const int size) = 0; // Adds metadata to the encoded audio, i.e., the ID3 tag. Currently only used // by EngineRecord, ShoutConnection does something different. - virtual void updateMetaData(const QString& artist, const QString& title, const QString& album) = 0; + virtual void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) = 0; // called at the end when encoding is finished virtual void flush() = 0; // Setup the encoder with the specific settings virtual void setEncoderSettings(const EncoderSettings& settings) = 0; + + protected: + void addToTracklist(const QString& artist, const QString& title, std::chrono::seconds timecode); + QStringList getTrackList() const { + return m_trackList; + } + + private: + QStringList m_trackList; }; typedef std::shared_ptr EncoderPointer; diff --git a/src/encoder/encoderfdkaac.cpp b/src/encoder/encoderfdkaac.cpp index f6edec63ba40..cb32ff240b5f 100644 --- a/src/encoder/encoderfdkaac.cpp +++ b/src/encoder/encoderfdkaac.cpp @@ -1,5 +1,7 @@ #include "encoder/encoderfdkaac.h" +#include + #ifdef __APPLE__ #include #endif @@ -439,9 +441,14 @@ void EncoderFdkAac::processFIFO() { } } -void EncoderFdkAac::updateMetaData( - const QString& artist, const QString& title, const QString& album) { - (void)artist, (void)title, (void)album; +void EncoderFdkAac::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { + Q_UNUSED(artist); + Q_UNUSED(title); + Q_UNUSED(album); + Q_UNUSED(timecode); } void EncoderFdkAac::flush() { diff --git a/src/encoder/encoderfdkaac.h b/src/encoder/encoderfdkaac.h index 1bb77e60c6df..66e2dbf46273 100644 --- a/src/encoder/encoderfdkaac.h +++ b/src/encoder/encoderfdkaac.h @@ -16,7 +16,10 @@ class EncoderFdkAac : public Encoder { int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE* samples, const int sampleCount) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; diff --git a/src/encoder/encoderffmpegcore.cpp b/src/encoder/encoderffmpegcore.cpp index 95bd6ad107d8..831bc8b04178 100644 --- a/src/encoder/encoderffmpegcore.cpp +++ b/src/encoder/encoderffmpegcore.cpp @@ -189,12 +189,15 @@ void EncoderFfmpegCore::encodeBuffer(const CSAMPLE *samples, const int size) { // // Currently this method is used before init() once to save artist, title and album // -void EncoderFfmpegCore::updateMetaData(const QString& artist, const QString& title, const QString& album) { +void EncoderFfmpegCore::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { qDebug() << "ffmpegencodercore: UpdateMetadata: !" << artist << " - " << title << " - " << album; - m_strMetaDataTitle = title; - m_strMetaDataArtist = artist; - m_strMetaDataAlbum = album; + Q_UNUSED(artist); + Q_UNUSED(title); + Q_UNUSED(album); } int EncoderFfmpegCore::initEncoder( diff --git a/src/encoder/encoderffmpegcore.h b/src/encoder/encoderffmpegcore.h index e22614c3e94a..ebb158efd3cf 100644 --- a/src/encoder/encoderffmpegcore.h +++ b/src/encoder/encoderffmpegcore.h @@ -44,7 +44,10 @@ class EncoderFfmpegCore : public Encoder { ~EncoderFfmpegCore(); int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; protected: @@ -70,9 +73,6 @@ class EncoderFfmpegCore : public Encoder { EncoderCallback* m_pCallback; TrackPointer m_pMetaData; - QString m_strMetaDataTitle; - QString m_strMetaDataArtist; - QString m_strMetaDataAlbum; QFile m_pFile; QByteArray m_strReadByteArray; diff --git a/src/encoder/encodermp3.cpp b/src/encoder/encodermp3.cpp index 9868ce6d84cd..ccd3716aec5b 100644 --- a/src/encoder/encodermp3.cpp +++ b/src/encoder/encodermp3.cpp @@ -1,13 +1,23 @@ #include "encoder/encodermp3.h" +#include #include +#include +#include +#include +#include #include #include #include "audio/types.h" #include "encoder/encodercallback.h" #include "encoder/encodermp3settings.h" +#include "util/assert.h" + +namespace { +constexpr size_t kHeaderPadding = 10000; +} // Automatic thresholds for switching the encoder to mono // They have been chosen by testing and to keep the same number @@ -81,7 +91,7 @@ void EncoderMp3::setEncoderSettings(const EncoderSettings& settings) { } } -int EncoderMp3::bufferOutGrow(int size) { +size_t EncoderMp3::bufferOutGrow(size_t size) { if (m_bufferOutSize >= size) { return 0; } @@ -95,7 +105,7 @@ int EncoderMp3::bufferOutGrow(int size) { return 0; } -int EncoderMp3::bufferInGrow(int size) { +size_t EncoderMp3::bufferInGrow(size_t size) { if (m_bufferInSize >= size) { return 0; } @@ -127,16 +137,45 @@ void EncoderMp3::flush() { // `lame_get_lametag_frame` returns the number of bytes copied into buffer, // or the required buffer size, if the provided buffer is too small. // Function failed, if the return value is larger than `m_bufferOutSize`! - int numBytes = static_cast( - lame_get_lametag_frame(m_lameFlags, m_bufferOut, m_bufferOutSize)); + size_t numBytes = lame_get_lametag_frame(m_lameFlags, m_bufferOut, m_bufferOutSize); if (numBytes > m_bufferOutSize) { bufferOutGrow(numBytes); numBytes = static_cast(lame_get_lametag_frame( m_lameFlags, m_bufferOut, m_bufferOutSize)); } - // Write the lame/xing header. + + // Ideally, we should shift the file content forward to insert the header + // (ID3v2 & Xing frame) dynamically, but `EncoderCallback` doesn't support + // that so we use the static header padding and truncate the tracklist if + // too long + size_t tracklistMaxSize = kHeaderPadding - numBytes - + lame_get_id3v2_tag(m_lameFlags, nullptr, 0); + auto trackList = getTrackList().join("\n"); + if (!trackList.isEmpty()) { + // Because of the static header size offset, we need to ensure that the + // tracklist comment won't make the header overflow on the MP3 frames, + // we we truncate to the max value + auto currentSize = static_cast(trackList.size()); + if (currentSize > tracklistMaxSize - 1) { // -1 since we need a byte for the NULL terminator + trackList = trackList.left(tracklistMaxSize - 4) + "..."; + } + id3tag_set_comment(m_lameFlags, trackList.toLatin1()); + } + + size_t id3HeaderNumBytes = lame_get_id3v2_tag(m_lameFlags, nullptr, 0); + QByteArray id3Buffer(id3HeaderNumBytes, 0); + + DEBUG_ASSERT(lame_get_id3v2_tag(m_lameFlags, + (unsigned char*)id3Buffer.data(), + id3HeaderNumBytes) == id3HeaderNumBytes); + DEBUG_ASSERT(id3Buffer.size() + numBytes <= kHeaderPadding); + m_pCallback->seek(0); - m_pCallback->write(nullptr, m_bufferOut, 0, numBytes); + // Write the lame/xing header. + m_pCallback->write((const unsigned char*)id3Buffer.constData(), + m_bufferOut, + id3Buffer.size(), + numBytes); } void EncoderMp3::encodeBuffer(const CSAMPLE *samples, const int size) { @@ -173,6 +212,10 @@ void EncoderMp3::initStream() { m_bufferIn[0] = (float *)malloc(m_bufferOutSize * sizeof(float)); m_bufferIn[1] = (float *)malloc(m_bufferOutSize * sizeof(float)); + + // Add a static header padding, which will be filled one termination + QByteArray headerPad(kHeaderPadding, 0); + m_pCallback->write(nullptr, (unsigned char*)headerPad.constData(), 0, headerPad.size()); } int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) { @@ -219,6 +262,8 @@ int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserE //ID3 Tag if fields are not NULL id3tag_init(m_lameFlags); + // ID3 tags will be written manually when flushing the encoder. + lame_set_write_id3tag_automatic(m_lameFlags, 0); if (!m_metaDataTitle.isEmpty()) { id3tag_set_title(m_lameFlags, m_metaDataTitle.toLatin1().constData()); } @@ -240,8 +285,15 @@ int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserE return 0; } -void EncoderMp3::updateMetaData(const QString& artist, const QString& title, const QString& album) { - m_metaDataTitle = title; - m_metaDataArtist = artist; - m_metaDataAlbum = album; +void EncoderMp3::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { + if (m_bufferOut == nullptr) { + m_metaDataTitle = title; + m_metaDataArtist = artist; + m_metaDataAlbum = album; + } else { + addToTracklist(artist, title, timecode); + } } diff --git a/src/encoder/encodermp3.h b/src/encoder/encodermp3.h index 153ff3505ab6..343ddc4f9890 100644 --- a/src/encoder/encodermp3.h +++ b/src/encoder/encodermp3.h @@ -16,14 +16,17 @@ class EncoderMp3 final : public Encoder { int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; private: void initStream(); - int bufferOutGrow(int size); - int bufferInGrow(int size); + size_t bufferOutGrow(size_t size); + size_t bufferInGrow(size_t size); lame_t m_lameFlags; QString m_metaDataTitle; @@ -35,9 +38,9 @@ class EncoderMp3 final : public Encoder { vbr_mode m_encoding_mode; MPEG_mode_e m_stereo_mode; unsigned char *m_bufferOut; - int m_bufferOutSize; + size_t m_bufferOutSize; float* m_bufferIn[2]; - int m_bufferInSize; + size_t m_bufferInSize; EncoderCallback* m_pCallback; }; diff --git a/src/encoder/encoderopus.cpp b/src/encoder/encoderopus.cpp index ff7975dd4a92..8667a8eb2bd2 100644 --- a/src/encoder/encoderopus.cpp +++ b/src/encoder/encoderopus.cpp @@ -1,5 +1,7 @@ #include "encoder/encoderopus.h" +#include + #include #include #include @@ -460,10 +462,18 @@ void EncoderOpus::writePage(ogg_packet* pPacket) { } while(!ogg_page_eos(&m_oggPage)); } -void EncoderOpus::updateMetaData(const QString& artist, const QString& title, const QString& album) { - m_opusComments.insert("ARTIST", artist); - m_opusComments.insert("TITLE", title); - m_opusComments.insert("ALBUM", album); +void EncoderOpus::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { + // We assume all the base tags are added at the same time, so only check for ARTIST presence + if (!m_opusComments.contains("ARTIST")) { + m_opusComments.insert("ARTIST", artist); + m_opusComments.insert("TITLE", title); + m_opusComments.insert("ALBUM", album); + } + // Tracklist tag not supported in OPUS + Q_UNUSED(timecode); } void EncoderOpus::flush() { diff --git a/src/encoder/encoderopus.h b/src/encoder/encoderopus.h index f5c1ba9e7516..ecc6083ae5c8 100644 --- a/src/encoder/encoderopus.h +++ b/src/encoder/encoderopus.h @@ -28,7 +28,10 @@ class EncoderOpus: public Encoder { int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; diff --git a/src/encoder/encodervorbis.cpp b/src/encoder/encodervorbis.cpp index 96a2b6bd5e9e..a634a2e792c4 100644 --- a/src/encoder/encodervorbis.cpp +++ b/src/encoder/encodervorbis.cpp @@ -1,5 +1,6 @@ #include "encoder/encodervorbis.h" +#include #include // needed for random num gen #include // needed for random num gen #include @@ -31,6 +32,9 @@ EncoderVorbis::EncoderVorbis(EncoderCallback* pCallback) EncoderVorbis::~EncoderVorbis() { if (m_bStreamInitialized) { + auto trackList = m_trackList.join("\n"); + vorbis_comment_add_tag(&m_vcomment, "COMMENT", trackList.toUtf8().constData()); + ogg_stream_clear(&m_oggs); vorbis_block_clear(&m_vblock); vorbis_dsp_clear(&m_vdsp); @@ -161,10 +165,17 @@ void EncoderVorbis::encodeBuffer(const CSAMPLE *samples, const int size) { * * Currently this method is used before init() once to save artist, title and album */ -void EncoderVorbis::updateMetaData(const QString& artist, const QString& title, const QString& album) { - m_metaDataTitle = title; - m_metaDataArtist = artist; - m_metaDataAlbum = album; +void EncoderVorbis::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { + if (!m_bStreamInitialized) { + m_metaDataTitle = title; + m_metaDataArtist = artist; + m_metaDataAlbum = album; + } + // Tracklist tag not supported in OGG + Q_UNUSED(timecode); } void EncoderVorbis::initStream() { diff --git a/src/encoder/encodervorbis.h b/src/encoder/encodervorbis.h index b28779181a41..a771101a5255 100644 --- a/src/encoder/encodervorbis.h +++ b/src/encoder/encodervorbis.h @@ -20,7 +20,10 @@ class EncoderVorbis : public Encoder { int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; @@ -50,4 +53,6 @@ class EncoderVorbis : public Encoder { int m_bitrate; int m_channels; QFile m_file; + + QStringList m_trackList; }; diff --git a/src/encoder/encoderwave.cpp b/src/encoder/encoderwave.cpp index 91e90874cb36..a090632d57a2 100644 --- a/src/encoder/encoderwave.cpp +++ b/src/encoder/encoderwave.cpp @@ -1,11 +1,14 @@ #include "encoder/encoderwave.h" +#include + #include #include "audio/types.h" #include "encoder/encodercallback.h" #include "encoder/encoderwavesettings.h" #include "recording/defs_recording.h" +#include "util/assert.h" // The virtual file context must return the length of the virtual file in bytes. static sf_count_t sf_f_get_filelen (void *user_data) @@ -133,6 +136,15 @@ void EncoderWave::setEncoderSettings(const EncoderSettings& settings) { // call sendPackages() or write() after 'flush()' as outlined in enginebroadcast.cpp void EncoderWave::flush() { + // AIFF uses COMMENT to store the album info, so we don't store the + // tracklist there for backward compatibility. + auto trackList = getTrackList().join("\n"); + if (!trackList.isEmpty() && m_sfInfo.format != SF_FORMAT_AIFF) { + int ret = sf_set_string(m_pSndfile, SF_STR_COMMENT, trackList.toUtf8().constData()); + VERIFY_OR_DEBUG_ASSERT(ret == 0) { + qWarning() << "libsndfile error when storing tracklist: %s", sf_error_number(ret); + } + } sf_write_sync(m_pSndfile); } @@ -146,10 +158,17 @@ void EncoderWave::encodeBuffer(const CSAMPLE *pBuffer, const int iBufferSize) { * * Currently this method is used before init() once to save artist, title and album */ -void EncoderWave::updateMetaData(const QString& artist, const QString& title, const QString& album) { - m_metaDataTitle = title; - m_metaDataArtist = artist; - m_metaDataAlbum = album; +void EncoderWave::updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode) { + if (m_pSndfile == nullptr) { + m_metaDataTitle = title; + m_metaDataArtist = artist; + m_metaDataAlbum = album; + } else { + addToTracklist(artist, title, timecode); + } } void EncoderWave::initStream() { diff --git a/src/encoder/encoderwave.h b/src/encoder/encoderwave.h index 7be763f47818..dd16e1716a6f 100644 --- a/src/encoder/encoderwave.h +++ b/src/encoder/encoderwave.h @@ -22,7 +22,10 @@ class EncoderWave : public Encoder { int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override; void encodeBuffer(const CSAMPLE *samples, const int size) override; - void updateMetaData(const QString& artist, const QString& title, const QString& album) override; + void updateMetaData(const QString& artist, + const QString& title, + const QString& album, + std::chrono::seconds timecode = {}) override; void flush() override; void setEncoderSettings(const EncoderSettings& settings) override; diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 50e739b06567..f2bc1d551a0c 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -1,5 +1,7 @@ #include "engine/sidechain/enginerecord.h" +#include + #include "control/controlproxy.h" #include "encoder/encoder.h" #include "mixer/playerinfo.h" @@ -36,6 +38,8 @@ int EngineRecord::updateFromPreferences() { m_baAlbum = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Album")); m_cueFileName = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "CuePath")); m_bCueIsEnabled = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "CueEnabled")).toInt(); + m_bTracklistAsCommentEnabled = m_pConfig->getValue( + ConfigKey(RECORDING_PREF_KEY, "tracklist_as_comment"), true); m_sampleRate = mixxx::audio::SampleRate::fromDouble(m_sampleRateControl.get()); // Delete m_pEncoder if it has been initialized (with maybe) different bitrate. @@ -201,12 +205,21 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { // write a file stream and emit bytesRecorded. m_pEncoder->encodeBuffer(pBuffer, iBufferSize); - //Writing cueLine before updating the time counter since we prefer to be ahead - //rather than late. - if (m_bCueIsEnabled && metaDataHasChanged()) { - m_cueTrack++; - writeCueLine(); - m_cueFile.flush(); + if (metaDataHasChanged()) { + // Writing cueLine before updating the time counter since we prefer to be ahead + // rather than late. + if (m_bCueIsEnabled) { + m_cueTrack++; + writeCueLine(); + m_cueFile.flush(); + } + + if (m_pCurrentTrack && m_bTracklistAsCommentEnabled) { + m_pEncoder->updateMetaData(m_pCurrentTrack->getArtist(), + m_pCurrentTrack->getTitle(), + m_pCurrentTrack->getAlbum(), + std::chrono::seconds(m_recordedDuration)); + } } // update frames counting and recorded duration (seconds) diff --git a/src/engine/sidechain/enginerecord.h b/src/engine/sidechain/enginerecord.h index 662a7b25d6e9..18c1c1dd065a 100644 --- a/src/engine/sidechain/enginerecord.h +++ b/src/engine/sidechain/enginerecord.h @@ -85,4 +85,5 @@ class EngineRecord : public QObject, public EncoderCallback, public SideChainWor QString m_cueFileName; quint64 m_cueTrack; bool m_bCueIsEnabled; + bool m_bTracklistAsCommentEnabled; }; diff --git a/src/preferences/dialog/dlgprefrecord.cpp b/src/preferences/dialog/dlgprefrecord.cpp index 0ae6b19be8e7..729a471168c8 100644 --- a/src/preferences/dialog/dlgprefrecord.cpp +++ b/src/preferences/dialog/dlgprefrecord.cpp @@ -12,6 +12,7 @@ namespace { constexpr bool kDefaultCueEnabled = true; +constexpr bool kDefaultTracklistAsComment = true; } // anonymous namespace DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) @@ -75,6 +76,7 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) // Setting miscellaneous CheckBoxRecordCueFile->setChecked(m_pConfig->getValue( ConfigKey(RECORDING_PREF_KEY, "CueEnabled"), kDefaultCueEnabled)); + updateTracklistAsComment(); // Setting split comboBoxSplitting->addItem(SPLIT_650MB); @@ -144,6 +146,7 @@ void DlgPrefRecord::slotApply() { saveMetaData(); saveEncoding(); saveUseCueFile(); + saveTracklistAsComment(); saveSplitSize(); } @@ -178,6 +181,7 @@ void DlgPrefRecord::slotUpdate() { // Setting miscellaneous CheckBoxRecordCueFile->setChecked(m_pConfig->getValue( ConfigKey(RECORDING_PREF_KEY, "CueEnabled"), kDefaultCueEnabled)); + updateTracklistAsComment(); QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); int index = comboBoxSplitting->findText(fileSizeStr); @@ -202,6 +206,7 @@ void DlgPrefRecord::slotResetToDefaults() { // 4GB splitting is the default comboBoxSplitting->setCurrentIndex(4); CheckBoxRecordCueFile->setChecked(kDefaultCueEnabled); + updateTracklistAsComment(); } void DlgPrefRecord::slotBrowseRecordingsDir() { @@ -296,6 +301,8 @@ void DlgPrefRecord::setupEncoderUI() { if (m_selFormat.internalName == ENCODING_MP3) { updateTextQuality(); } + + updateTracklistAsComment(); } void DlgPrefRecord::slotSliderQuality() { @@ -344,6 +351,19 @@ void DlgPrefRecord::updateTextCompression() { TextCompression->setText(QString::number(quality)); } +void DlgPrefRecord::updateTracklistAsComment() { + CheckBoxTracklistAsComment->blockSignals(true); + if (m_selFormat.internalName == ENCODING_MP3 || m_selFormat.internalName == ENCODING_WAVE) { + CheckBoxTracklistAsComment->setEnabled(true); + CheckBoxTracklistAsComment->setChecked(m_pConfig->getValue( + ConfigKey(RECORDING_PREF_KEY, "tracklist_as_comment"), kDefaultTracklistAsComment)); + } else { + CheckBoxTracklistAsComment->setEnabled(false); + CheckBoxTracklistAsComment->setChecked(false); + } + CheckBoxTracklistAsComment->blockSignals(true); +} + void DlgPrefRecord::slotGroupChanged() { // On complex scenarios, one could want to enable or disable some controls when changing @@ -434,6 +454,11 @@ void DlgPrefRecord::saveUseCueFile() { ConfigValue(CheckBoxRecordCueFile->isChecked())); } +void DlgPrefRecord::saveTracklistAsComment() { + m_pConfig->setValue(ConfigKey(RECORDING_PREF_KEY, "tracklist_as_comment"), + CheckBoxTracklistAsComment->isChecked()); +} + void DlgPrefRecord::saveSplitSize() { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "FileSize"), ConfigValue(comboBoxSplitting->currentText())); diff --git a/src/preferences/dialog/dlgprefrecord.h b/src/preferences/dialog/dlgprefrecord.h index 17c47a1ea573..86a761dadb62 100644 --- a/src/preferences/dialog/dlgprefrecord.h +++ b/src/preferences/dialog/dlgprefrecord.h @@ -40,10 +40,12 @@ class DlgPrefRecord : public DlgPreferencePage, public Ui::DlgPrefRecordDlg { void loadMetaData(); void updateTextQuality(); void updateTextCompression(); + void updateTracklistAsComment(); void saveRecordingFolder(); void saveMetaData(); void saveEncoding(); void saveUseCueFile(); + void saveTracklistAsComment(); void saveSplitSize(); // Pointer to config object diff --git a/src/preferences/dialog/dlgprefrecorddlg.ui b/src/preferences/dialog/dlgprefrecorddlg.ui index 01a3808af0d9..3a6b2048e21c 100644 --- a/src/preferences/dialog/dlgprefrecorddlg.ui +++ b/src/preferences/dialog/dlgprefrecorddlg.ui @@ -14,7 +14,6 @@ Recording Preferences - @@ -69,7 +68,6 @@ - @@ -97,7 +95,6 @@ - @@ -110,7 +107,6 @@ - @@ -118,20 +114,29 @@ - - Output File Format - + + + 0 + 0 + + + + + 100 + 0 + + Lossless @@ -144,7 +149,6 @@ - @@ -155,7 +159,6 @@ - @@ -163,7 +166,6 @@ - @@ -180,112 +182,108 @@ - - - - - - Quality - - - - - - - 1 - - - 11 - - - 1 - - - 1 - - - 9 - - - Qt::Horizontal - - - 5 - - - - - - - - 60 - 0 - - - - Quality - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - SliderQuality - - - - + + + + + Quality + + + + + + + 1 + + + 11 + + + 1 + + + 1 + + + 9 + + + Qt::Horizontal + + + 5 + + + + + + + + 60 + 0 + + + + Quality + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + SliderQuality + + + + - - - - - - Compression Level - - - - - - - Qt::Horizontal - - - - - - - - 60 - 0 - - - - Compression - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - SliderCompression - - - - + + + + + Compression Level + + + + + + + Qt::Horizontal + + + + + + + + 60 + 0 + + + + Compression + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + SliderCompression + + + + - - @@ -314,7 +312,6 @@ - @@ -337,7 +334,6 @@ - @@ -360,10 +356,19 @@ + + + + Only supported for MP3 and WAV + + + Store the tracklist as comment + + + - @@ -377,7 +382,6 @@ - @@ -391,6 +395,7 @@ LineEditTitle LineEditAuthor LineEditAlbum + CheckBoxTracklistAsComment