From 67ebbf692532996c22f13de99f6703f32238edc5 Mon Sep 17 00:00:00 2001 From: josepma Date: Sun, 30 Oct 2016 03:03:48 +0100 Subject: [PATCH 01/12] launchpad bug #1605923 correct path in cue file when recording to wav --- src/engine/sidechain/enginerecord.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 359d773244b..762ad6201b4 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -370,7 +370,8 @@ bool EngineRecord::openCueFile() { } m_cueFile.write(QString("FILE \"%1\" %2%3\n").arg( - QString(m_fileName).replace(QString("\""), QString("\\\"")), + QString(m_fileName).mid(m_fileName.lastIndexOf("/")+1) //strip path + .replace(QString("\""), QString("\\\"")), // escape doublequote QString(m_encoding).toUpper(), m_encoding == ENCODING_WAVE ? "E" : " ").toLatin1()); return true; From b0007b172be4280b9b0ea9147cf2becdb1aea91c Mon Sep 17 00:00:00 2001 From: josepma Date: Sun, 30 Oct 2016 03:05:23 +0100 Subject: [PATCH 02/12] launchpad bug #1637786 recording to wav heavily distorts on saturation --- src/engine/sidechain/enginerecord.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 762ad6201b4..7c2475946fe 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -308,6 +308,10 @@ bool EngineRecord::openFile() { #endif if (m_pSndfile) { sf_command(m_pSndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE); + // Warning! Depending on how libsndfile is compiled autoclip may not work. + // Ensure CPU_CLIPS_NEGATIVE and CPU_CLIPS_NEGATIVE is setup properly in the build. + sf_command(m_pSndfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ; + // Set meta data int ret = sf_set_string(m_pSndfile, SF_STR_TITLE, m_baTitle.constData()); if (ret != 0) { From 6447a0b092d46dfe9bb3886b8e4f85ad693a5083 Mon Sep 17 00:00:00 2001 From: josepma Date: Mon, 31 Oct 2016 23:38:59 +0100 Subject: [PATCH 03/12] better fix for relative path in cue file --- src/engine/sidechain/enginerecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 7c2475946fe..802df269495 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -374,7 +374,7 @@ bool EngineRecord::openCueFile() { } m_cueFile.write(QString("FILE \"%1\" %2%3\n").arg( - QString(m_fileName).mid(m_fileName.lastIndexOf("/")+1) //strip path + QFileInfo(m_fileName).fileName() //strip path .replace(QString("\""), QString("\\\"")), // escape doublequote QString(m_encoding).toUpper(), m_encoding == ENCODING_WAVE ? "E" : " ").toLatin1()); From a836414ccbc9b63ba5f8c2529042a78963b68dc5 Mon Sep 17 00:00:00 2001 From: josepma Date: Mon, 31 Oct 2016 23:41:49 +0100 Subject: [PATCH 04/12] fix for bug #1638120 : close cue file --- src/engine/sidechain/enginerecord.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 802df269495..0f9bd7f28f6 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -160,6 +160,9 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { if (fileOpen()) { Event::end("EngineRecord recording"); closeFile(); // Close file and free encoder. + if (m_bCueIsEnabled) { + closeCueFile(); + } emit(isRecording(false, false)); } } else if (recordingStatus == RECORD_READY) { From b33faf24114b13703a67add3eeaa9a9358cc61e0 Mon Sep 17 00:00:00 2001 From: josepma Date: Mon, 31 Oct 2016 23:50:07 +0100 Subject: [PATCH 05/12] fix bug #1605921 : Improve recording split size options --- src/engine/sidechain/enginerecord.cpp | 2 +- src/engine/sidechain/enginerecord.h | 2 +- src/preferences/dialog/dlgprefrecord.cpp | 13 +++- src/recording/defs_recording.h | 17 +++-- src/recording/recordingmanager.cpp | 91 +++++++++++++++++++----- src/recording/recordingmanager.h | 11 ++- 6 files changed, 104 insertions(+), 32 deletions(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 0f9bd7f28f6..738bc49ce36 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -217,7 +217,7 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { // gets recorded duration and emit signal that will be used // by RecordingManager to update the label besides start/stop button if (lastDuration != m_recordedDuration) { - emit(durationRecorded(getRecordedDurationStr())); + emit(durationRecorded(m_recordedDuration)); } if (m_bCueIsEnabled) { diff --git a/src/engine/sidechain/enginerecord.h b/src/engine/sidechain/enginerecord.h index b1a387a1337..1f6f1751a91 100644 --- a/src/engine/sidechain/enginerecord.h +++ b/src/engine/sidechain/enginerecord.h @@ -66,7 +66,7 @@ class EngineRecord : public QObject, public EncoderCallback, public SideChainWor // only one error can occur: the specified file was unable to be opened for // writing. void isRecording(bool recording, bool error); - void durationRecorded(QString duration); + void durationRecorded(quint64 durationInt); private: int getActiveTracks(); diff --git a/src/preferences/dialog/dlgprefrecord.cpp b/src/preferences/dialog/dlgprefrecord.cpp index e45c3c1e85d..4da6d9e4ed3 100644 --- a/src/preferences/dialog/dlgprefrecord.cpp +++ b/src/preferences/dialog/dlgprefrecord.cpp @@ -117,6 +117,8 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) slotApply(); // Make sure a corrupt config file won't cause us to record constantly. + // TODO: What does this do exactly? I thougth it stopped the recording when showing + // the preferences page but it does not (and i would preffer that keeps not stopping it). m_pRecordControl->set(RECORD_OFF); comboBoxSplitting->addItem(SPLIT_650MB); @@ -124,14 +126,21 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) comboBoxSplitting->addItem(SPLIT_1024MB); comboBoxSplitting->addItem(SPLIT_2048MB); comboBoxSplitting->addItem(SPLIT_4096MB); + comboBoxSplitting->addItem(SPLIT_60MIN); + comboBoxSplitting->addItem(SPLIT_74MIN); + comboBoxSplitting->addItem(SPLIT_80MIN); + comboBoxSplitting->addItem(SPLIT_120MIN); QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); int index = comboBoxSplitting->findText(fileSizeStr); - if (index > 0) { + if (index >= 0) { // Set file split size comboBoxSplitting->setCurrentIndex(index); } - // Otherwise 650 MB will be default file split size. + else { + //Use max RIFF size (4GB) as default index, since usually people don't want to split. + comboBoxSplitting->setCurrentIndex(4); + } // Read CUEfile info CheckBoxRecordCueFile->setChecked( diff --git a/src/recording/defs_recording.h b/src/recording/defs_recording.h index 4fbb6f52ac9..7bcc90441ea 100644 --- a/src/recording/defs_recording.h +++ b/src/recording/defs_recording.h @@ -18,14 +18,17 @@ #define SPLIT_1024MB "1 GB" #define SPLIT_2048MB "2 GB" #define SPLIT_4096MB "4 GB" +#define SPLIT_60MIN "60 Minutes" +#define SPLIT_74MIN "74 Minutes (CD)" +#define SPLIT_80MIN "80 Minutes (CD)" +#define SPLIT_120MIN "120 Minutes" -// Byte conversions Instead of multiplying megabytes with 1024 to get kilobytes -// I use 1000 Once the recording size has reached there's enough room to add +// Byte conversions. Slightly rounded to leave enough room to add // closing frames by the encoder. All sizes are in bytes. -#define SIZE_650MB Q_UINT64_C(650000000) -#define SIZE_700MB Q_UINT64_C(750000000) -#define SIZE_1GB Q_UINT64_C(1000000000) -#define SIZE_2GB Q_UINT64_C(2000000000) -#define SIZE_4GB Q_UINT64_C(4000000000) +#define SIZE_650MB Q_UINT64_C(680000000) +#define SIZE_700MB Q_UINT64_C(730000000) +#define SIZE_1GB Q_UINT64_C(1070000000) +#define SIZE_2GB Q_UINT64_C(2140000000) +#define SIZE_4GB Q_UINT64_C(4280000000) #endif diff --git a/src/recording/recordingmanager.cpp b/src/recording/recordingmanager.cpp index 33b758b59ad..75d7317cb41 100644 --- a/src/recording/recordingmanager.cpp +++ b/src/recording/recordingmanager.cpp @@ -21,9 +21,12 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE m_recordingLocation(""), m_bRecording(false), m_iNumberOfBytesRecorded(0), + m_iNumberOfBytesRecordedSplit(0), m_split_size(0), + m_split_time(0), m_iNumberSplits(0), - m_durationRecorded("") { + m_secondsRecorded(0), + m_secondsRecordedSplit(0) { m_pToggleRecording = new ControlPushButton(ConfigKey(RECORDING_PREF_KEY, "toggle_recording")); connect(m_pToggleRecording, SIGNAL(valueChanged(double)), this, SLOT(slotToggleRecording(double))); @@ -31,6 +34,7 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE m_recReady = new ControlProxy(m_recReadyCO->getKey(), this); m_split_size = getFileSplitSize(); + m_split_time = getFileSplitTime(); // Register EngineRecord with the engine sidechain. @@ -41,8 +45,8 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE this, SLOT(slotIsRecording(bool, bool))); connect(pEngineRecord, SIGNAL(bytesRecorded(int)), this, SLOT(slotBytesRecorded(int))); - connect(pEngineRecord, SIGNAL(durationRecorded(QString)), - this, SLOT(slotDurationRecorded(QString))); + connect(pEngineRecord, SIGNAL(durationRecorded(quint64)), + this, SLOT(slotDurationRecorded(quint64))); pSidechain->addSideChainWorker(pEngineRecord); } } @@ -80,14 +84,22 @@ void RecordingManager::slotToggleRecording(double v) { } void RecordingManager::startRecording(bool generateFileName) { - m_iNumberOfBytesRecorded = 0; - m_split_size = getFileSplitSize(); - qDebug() << "Split size is:" << m_split_size; - QString encodingType = m_pConfig->getValueString( - ConfigKey(RECORDING_PREF_KEY, "Encoding")); + QString encodingType = m_pConfig->getValueString( + ConfigKey(RECORDING_PREF_KEY, "Encoding")); + + if(generateFileName) { + m_iNumberOfBytesRecorded = 0; + m_secondsRecorded=0; + m_split_size = getFileSplitSize(); + m_split_time = getFileSplitTime(); + if (m_split_time < 999999999) { + qDebug() << "Split time is:" << m_split_time; + } + else { + qDebug() << "Split size is:" << m_split_size; + } - if(generateFileName) { - m_iNumberSplits = 1; + m_iNumberSplits = 1; // Append file extension. QString date_time_str = formatDateTimeForFilename(QDateTime::currentDateTime()); m_recordingFile = QString("%1.%2") @@ -100,17 +112,21 @@ void RecordingManager::startRecording(bool generateFileName) { m_recordingLocation = m_recording_base_file + "."+ encodingType.toLower(); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), m_recording_base_file +".cue"); - } else { + } else { // This is only executed if filesplit occurs. ++m_iNumberSplits; + m_secondsRecorded+=m_secondsRecordedSplit; QString new_base_filename = m_recording_base_file +"part"+QString::number(m_iNumberSplits); m_recordingLocation = new_base_filename + "." +encodingType.toLower(); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), new_base_filename +".cue"); m_recordingFile = QFileInfo(m_recordingLocation).fileName(); - } + } m_recReady->set(RECORD_READY); + + m_iNumberOfBytesRecordedSplit = 0; + m_secondsRecordedSplit=0; } void RecordingManager::stopRecording() @@ -120,6 +136,7 @@ void RecordingManager::stopRecording() m_recordingFile = ""; m_recordingLocation = ""; m_iNumberOfBytesRecorded = 0; + m_secondsRecorded = 0; } void RecordingManager::setRecordingDir() { @@ -145,22 +162,38 @@ QString& RecordingManager::getRecordingDir() { } // Only called when recording is active. -void RecordingManager::slotDurationRecorded(QString durationStr) +void RecordingManager::slotDurationRecorded(quint64 duration) { - if(m_durationRecorded != durationStr) + if(m_secondsRecordedSplit != duration) { - m_durationRecorded = durationStr; - emit(durationRecorded(m_durationRecorded)); + m_secondsRecordedSplit = duration; + if(duration >= m_split_time) + { + qDebug() << "Splitting after " << duration << " seconds"; + stopRecording(); + // Dont generate a new filename. + // This will reuse the previous filename but append a suffix. + startRecording(false); + } + emit(durationRecorded(getRecordedDurationStr(m_secondsRecorded+m_secondsRecordedSplit))); } } +// Copy from the implementation in enginerecord.cpp +QString RecordingManager::getRecordedDurationStr(quint64 duration) { + return QString("%1:%2") + .arg(duration / 60, 2, 'f', 0, '0') // minutes + .arg(duration % 60, 2, 'f', 0, '0'); // seconds +} // Only called when recording is active. void RecordingManager::slotBytesRecorded(int bytes) { // auto conversion to long m_iNumberOfBytesRecorded += bytes; - if(m_iNumberOfBytesRecorded >= m_split_size) + m_iNumberOfBytesRecordedSplit += bytes; + if(m_iNumberOfBytesRecordedSplit >= m_split_size) { + qDebug() << "Splitting after " << m_iNumberOfBytesRecorded << " bytes written"; stopRecording(); // Dont generate a new filename. // This will reuse the previous filename but append a suffix. @@ -200,7 +233,7 @@ QString& RecordingManager::getRecordingLocation() { return m_recordingLocation; } -long RecordingManager::getFileSplitSize() +quint64 RecordingManager::getFileSplitSize() { QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); if(fileSizeStr == SPLIT_650MB) @@ -213,6 +246,28 @@ long RecordingManager::getFileSplitSize() return SIZE_2GB; else if(fileSizeStr == SPLIT_4096MB) return SIZE_4GB; + else if(fileSizeStr == SPLIT_60MIN) + return SIZE_4GB; //Ignore size limit. use time limit + else if(fileSizeStr == SPLIT_74MIN) + return SIZE_4GB; //Ignore size limit. use time limit + else if(fileSizeStr == SPLIT_80MIN) + return SIZE_4GB; //Ignore size limit. use time limit + else if(fileSizeStr == SPLIT_120MIN) + return SIZE_4GB; //Ignore size limit. use time limit else return SIZE_650MB; } +long RecordingManager::getFileSplitTime() +{ + QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); + if(fileSizeStr == SPLIT_60MIN) + return 60*60; + else if(fileSizeStr == SPLIT_74MIN) + return 74*60; + else if(fileSizeStr == SPLIT_80MIN) + return 8;//0*60; //TODO: TEST!. Restore the correct value after that. + else if(fileSizeStr == SPLIT_120MIN) + return 120*60; + else // Do not limit by time for the rest. + return 999999999; +} diff --git a/src/recording/recordingmanager.h b/src/recording/recordingmanager.h index 6a2f48b224e..5b9d58c4b28 100644 --- a/src/recording/recordingmanager.h +++ b/src/recording/recordingmanager.h @@ -57,7 +57,7 @@ class RecordingManager : public QObject public slots: void slotIsRecording(bool recording, bool error); void slotBytesRecorded(int); - void slotDurationRecorded(QString); + void slotDurationRecorded(quint64); private slots: void slotSetRecording(bool recording); @@ -69,7 +69,8 @@ class RecordingManager : public QObject ControlObject* m_recReadyCO; ControlPushButton* m_pToggleRecording; - long getFileSplitSize(); + quint64 getFileSplitSize(); + long getFileSplitTime(); UserSettingsPointer m_pConfig; QString m_recordingDir; @@ -83,9 +84,13 @@ class RecordingManager : public QObject bool m_bRecording; // will be a very large number quint64 m_iNumberOfBytesRecorded; + quint64 m_iNumberOfBytesRecordedSplit; quint64 m_split_size; + long m_split_time; int m_iNumberSplits; - QString m_durationRecorded; + long m_secondsRecorded; + long m_secondsRecordedSplit; + QString getRecordedDurationStr(quint64 duration); }; #endif // RECORDINGMANAGER_H From 5bbe8fef234900c3f6cfa14f7d38932a09fbba02 Mon Sep 17 00:00:00 2001 From: josepma Date: Mon, 31 Oct 2016 23:54:26 +0100 Subject: [PATCH 06/12] fixes bugs #1638115 and#1605922 related to recording and splitting --- src/engine/sidechain/enginerecord.cpp | 42 ++++++++++++++++++++++++++- src/recording/defs_recording.h | 1 + src/recording/recordingmanager.cpp | 11 ++++--- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 738bc49ce36..e45f3c804e9 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -131,6 +131,11 @@ bool EngineRecord::metaDataHasChanged() } m_iMetaDataLife = 0; + //TODO: Needs improvement. Usually when we start recording, all tracks are stopped + // and we start the track just after that. Given that this is executed with start recording, + // it waits for kMetaDataLifeTimeout until it actually notices that the track + // has started playing. This translates to the cue file start time being too late. + // Maybe we need a signal for this too. TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); if (!pTrack) return false; @@ -194,7 +199,42 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { // An error occurred. emit(isRecording(false, true)); } - } else if (recordingStatus == RECORD_ON) { + } else if (recordingStatus == RECORD_SPLIT_CONTINUE) { + if (fileOpen()) { + closeFile(); // Close file and free encoder. + if (m_bCueIsEnabled) { + closeCueFile(); + } + } + updateFromPreferences(); // Update file location from preferences. + if (openFile()) { + qDebug() << "Splitting to a new file: "<< m_fileName; + m_pRecReady->set(RECORD_ON); + emit(isRecording(true, false)); // will notify the RecordingManager + + // Since we just started recording, timeout and clear the metadata. + m_iMetaDataLife = kMetaDataLifeTimeout; + m_pCurrentTrack = TrackPointer(); + + // clean frames counting and get current sample rate. + m_frames = 0; + m_sampleRate = m_pSamplerate->get(); + + if (m_bCueIsEnabled) { + openCueFile(); + m_cueTrack = 0; + } + } else { // Maybe the encoder could not be initialized + qDebug() << "Could not open" << m_fileName << "for writing."; + Event::end("EngineRecord recording"); + qDebug("Setting record flag to: OFF"); + m_pRecReady->slotSet(RECORD_OFF); + // An error occurred. + emit(isRecording(false, true)); + } + } + + if (recordingStatus == RECORD_ON || recordingStatus == RECORD_SPLIT_CONTINUE) { // If recording is enabled process audio to compressed or uncompressed data. if (m_encoding == ENCODING_WAVE || m_encoding == ENCODING_AIFF) { if (m_pSndfile != NULL) { diff --git a/src/recording/defs_recording.h b/src/recording/defs_recording.h index 7bcc90441ea..50600096cf8 100644 --- a/src/recording/defs_recording.h +++ b/src/recording/defs_recording.h @@ -11,6 +11,7 @@ #define RECORD_OFF 0.0 #define RECORD_READY 1.0 #define RECORD_ON 2.0 +#define RECORD_SPLIT_CONTINUE 3.0 //File options for preferences Splitting #define SPLIT_650MB "650 MB (CD)" diff --git a/src/recording/recordingmanager.cpp b/src/recording/recordingmanager.cpp index 75d7317cb41..af6a39baff0 100644 --- a/src/recording/recordingmanager.cpp +++ b/src/recording/recordingmanager.cpp @@ -112,6 +112,9 @@ void RecordingManager::startRecording(bool generateFileName) { m_recordingLocation = m_recording_base_file + "."+ encodingType.toLower(); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), m_recording_base_file +".cue"); + + m_recReady->set(RECORD_READY); + } else { // This is only executed if filesplit occurs. ++m_iNumberSplits; @@ -122,9 +125,10 @@ void RecordingManager::startRecording(bool generateFileName) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), new_base_filename +".cue"); m_recordingFile = QFileInfo(m_recordingLocation).fileName(); - } - m_recReady->set(RECORD_READY); + m_recReady->set(RECORD_SPLIT_CONTINUE); + + } m_iNumberOfBytesRecordedSplit = 0; m_secondsRecordedSplit=0; } @@ -139,6 +143,7 @@ void RecordingManager::stopRecording() m_secondsRecorded = 0; } + void RecordingManager::setRecordingDir() { QDir recordDir(m_pConfig->getValueString( ConfigKey(RECORDING_PREF_KEY, "Directory"))); @@ -170,7 +175,6 @@ void RecordingManager::slotDurationRecorded(quint64 duration) if(duration >= m_split_time) { qDebug() << "Splitting after " << duration << " seconds"; - stopRecording(); // Dont generate a new filename. // This will reuse the previous filename but append a suffix. startRecording(false); @@ -194,7 +198,6 @@ void RecordingManager::slotBytesRecorded(int bytes) if(m_iNumberOfBytesRecordedSplit >= m_split_size) { qDebug() << "Splitting after " << m_iNumberOfBytesRecorded << " bytes written"; - stopRecording(); // Dont generate a new filename. // This will reuse the previous filename but append a suffix. startRecording(false); From e53ca01d2aff56848fecc937954ac351fa0abd2c Mon Sep 17 00:00:00 2001 From: josepma Date: Tue, 1 Nov 2016 00:54:47 +0100 Subject: [PATCH 07/12] Bug #1415720 save wav/aiff in 16/24 or 32bit float --- src/engine/sidechain/enginerecord.cpp | 39 +++++++----- src/engine/sidechain/enginerecord.h | 2 + src/preferences/dialog/dlgprefrecord.cpp | 48 ++++++++++---- src/recording/recordingmanager.cpp | 80 ++++++++++++------------ src/recording/recordingmanager.h | 10 +-- 5 files changed, 109 insertions(+), 70 deletions(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index e45f3c804e9..13643cd39b3 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -69,6 +69,8 @@ void EngineRecord::updateFromPreferences() { // returns a number from 1 .. 10 m_OGGquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality")).toLatin1(); m_MP3quality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality")).toLatin1(); + m_WAVEquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality")).toLatin1(); + m_AIFFquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality")).toLatin1(); m_fileName = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Path")); m_baTitle = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Title")).toLatin1(); m_baAuthor = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Author")).toLatin1(); @@ -131,11 +133,11 @@ bool EngineRecord::metaDataHasChanged() } m_iMetaDataLife = 0; - //TODO: Needs improvement. Usually when we start recording, all tracks are stopped - // and we start the track just after that. Given that this is executed with start recording, - // it waits for kMetaDataLifeTimeout until it actually notices that the track - // has started playing. This translates to the cue file start time being too late. - // Maybe we need a signal for this too. + //TODO: Needs improvement. Usually when we start recording, all tracks are stopped + // and we start the track just after that. Given that this is executed with start recording, + // it waits for kMetaDataLifeTimeout until it actually notices that the track + // has started playing. This translates to the cue file start time being too late. + // Maybe we need a signal for this too. TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); if (!pTrack) return false; @@ -166,8 +168,8 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { Event::end("EngineRecord recording"); closeFile(); // Close file and free encoder. if (m_bCueIsEnabled) { - closeCueFile(); - } + closeCueFile(); + } emit(isRecording(false, false)); } } else if (recordingStatus == RECORD_READY) { @@ -203,8 +205,8 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { if (fileOpen()) { closeFile(); // Close file and free encoder. if (m_bCueIsEnabled) { - closeCueFile(); - } + closeCueFile(); + } } updateFromPreferences(); // Update file location from preferences. if (openFile()) { @@ -234,7 +236,7 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { } } - if (recordingStatus == RECORD_ON || recordingStatus == RECORD_SPLIT_CONTINUE) { + if (recordingStatus == RECORD_ON || recordingStatus == RECORD_SPLIT_CONTINUE) { // If recording is enabled process audio to compressed or uncompressed data. if (m_encoding == ENCODING_WAVE || m_encoding == ENCODING_AIFF) { if (m_pSndfile != NULL) { @@ -335,12 +337,21 @@ bool EngineRecord::openFile() { m_sfInfo.samplerate = m_sampleRate; m_sfInfo.channels = 2; + int quality_sel; if (m_encoding == ENCODING_WAVE) { - m_sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; + quality_sel = m_WAVEquality.toInt(); + m_sfInfo.format = SF_FORMAT_WAV; } else { - m_sfInfo.format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16; + quality_sel = m_AIFFquality.toInt(); + m_sfInfo.format = SF_FORMAT_AIFF; + } + if (quality_sel < 5) { + m_sfInfo.format |= SF_FORMAT_PCM_16; + } else if (quality_sel < 9) { + m_sfInfo.format |= SF_FORMAT_PCM_24; + } else { + m_sfInfo.format |= SF_FORMAT_FLOAT; } - // Creates a new WAVE or AIFF file and writes header information. #ifdef __WINDOWS__ // Pointer valid until string changed @@ -417,7 +428,7 @@ bool EngineRecord::openCueFile() { } m_cueFile.write(QString("FILE \"%1\" %2%3\n").arg( - QFileInfo(m_fileName).fileName() //strip path + QFileInfo(m_fileName).fileName() //strip path .replace(QString("\""), QString("\\\"")), // escape doublequote QString(m_encoding).toUpper(), m_encoding == ENCODING_WAVE ? "E" : " ").toLatin1()); diff --git a/src/engine/sidechain/enginerecord.h b/src/engine/sidechain/enginerecord.h index 1f6f1751a91..5ef097acb49 100644 --- a/src/engine/sidechain/enginerecord.h +++ b/src/engine/sidechain/enginerecord.h @@ -82,6 +82,8 @@ class EngineRecord : public QObject, public EncoderCallback, public SideChainWor Encoder* m_pEncoder; QByteArray m_OGGquality; QByteArray m_MP3quality; + QByteArray m_WAVEquality; + QByteArray m_AIFFquality; QByteArray m_encoding; QString m_fileName; QByteArray m_baTitle; diff --git a/src/preferences/dialog/dlgprefrecord.cpp b/src/preferences/dialog/dlgprefrecord.cpp index 4da6d9e4ed3..761fdcb0e8e 100644 --- a/src/preferences/dialog/dlgprefrecord.cpp +++ b/src/preferences/dialog/dlgprefrecord.cpp @@ -117,8 +117,8 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) slotApply(); // Make sure a corrupt config file won't cause us to record constantly. - // TODO: What does this do exactly? I thougth it stopped the recording when showing - // the preferences page but it does not (and i would preffer that keeps not stopping it). + // TODO: What does this do exactly? I thougth it stopped the recording when showing + // the preferences page but it does not (and i would preffer that keeps not stopping it). m_pRecordControl->set(RECORD_OFF); comboBoxSplitting->addItem(SPLIT_650MB); @@ -155,7 +155,12 @@ void DlgPrefRecord::slotSliderQuality() { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality"), ConfigValue(SliderQuality->value())); } else if (m_pRadioMp3 && m_pRadioMp3->isChecked()) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality"), ConfigValue(SliderQuality->value())); + } else if (m_pRadioWav && m_pRadioWav->isChecked()) { + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality"), ConfigValue(SliderQuality->value())); + } else if (m_pRadioAiff && m_pRadioAiff->isChecked()) { + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality"), ConfigValue(SliderQuality->value())); } + } int DlgPrefRecord::getSliderQualityVal() { @@ -164,10 +169,21 @@ int DlgPrefRecord::getSliderQualityVal() { } void DlgPrefRecord::updateTextQuality() { - int quality = getSliderQualityVal(); - //QString encodingType = comboBoxEncoding->currentText(); + if ((m_pRadioWav && m_pRadioWav->isChecked()) + || (m_pRadioAiff && m_pRadioAiff->isChecked())) { + if (SliderQuality->value() < 5) { + TextQuality->setText(tr("16 bits")); + } else if (SliderQuality->value() < 9) { + TextQuality->setText(tr("24 bits")); + } else { + TextQuality->setText(tr("32 bits float")); + } + } else { + int quality = getSliderQualityVal(); + //QString encodingType = comboBoxEncoding->currentText(); - TextQuality->setText(QString(QString::number(quality) + tr("kbps"))); + TextQuality->setText(QString(QString::number(quality) + tr("kbps"))); + } } void DlgPrefRecord::slotEncoding() { @@ -176,14 +192,24 @@ void DlgPrefRecord::slotEncoding() { //m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText())); if (m_pRadioWav && m_pRadioWav->isChecked()) { + int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality")).toInt(); + // If value == 0 then a default value of 16 bits is proposed. + if (!value) + value = 1; // 16 bits + + SliderQuality->setValue(value); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE)); - groupBoxQuality->setEnabled(false); } else if (m_pRadioFlac && m_pRadioFlac->isChecked()) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_FLAC)); groupBoxQuality->setEnabled(false); } else if (m_pRadioAiff && m_pRadioAiff->isChecked()) { + int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality")).toInt(); + // If value == 0 then a default value of 16 bits is proposed. + if (!value) + value = 1; // 16 bits + + SliderQuality->setValue(value); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_AIFF)); - groupBoxQuality->setEnabled(false); } else if (m_pRadioOgg && m_pRadioOgg->isChecked()) { int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality")).toInt(); // If value == 0 then a default value of 128kbps is proposed. @@ -229,15 +255,15 @@ void DlgPrefRecord::slotRecordPathChange() { void DlgPrefRecord::slotResetToDefaults() { m_pRadioWav->setChecked(true); CheckBoxRecordCueFile->setChecked(false); - // 650MB splitting is the default - comboBoxSplitting->setCurrentIndex(0); + // 4GB splitting is the default + comboBoxSplitting->setCurrentIndex(4); LineEditTitle->setText(""); LineEditAlbum->setText(""); LineEditAuthor->setText(""); - // 6 corresponds to 128kbps (only used by MP3 and Ogg though) - SliderQuality->setValue(6); + // 1 corresponds to 16 bits (WAVE/AIFF) + SliderQuality->setValue(1); } // This function updates/refreshes the contents of this dialog. diff --git a/src/recording/recordingmanager.cpp b/src/recording/recordingmanager.cpp index af6a39baff0..4d654861777 100644 --- a/src/recording/recordingmanager.cpp +++ b/src/recording/recordingmanager.cpp @@ -23,10 +23,10 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE m_iNumberOfBytesRecorded(0), m_iNumberOfBytesRecordedSplit(0), m_split_size(0), - m_split_time(0), + m_split_time(0), m_iNumberSplits(0), - m_secondsRecorded(0), - m_secondsRecordedSplit(0) { + m_secondsRecorded(0), + m_secondsRecordedSplit(0) { m_pToggleRecording = new ControlPushButton(ConfigKey(RECORDING_PREF_KEY, "toggle_recording")); connect(m_pToggleRecording, SIGNAL(valueChanged(double)), this, SLOT(slotToggleRecording(double))); @@ -34,7 +34,7 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE m_recReady = new ControlProxy(m_recReadyCO->getKey(), this); m_split_size = getFileSplitSize(); - m_split_time = getFileSplitTime(); + m_split_time = getFileSplitTime(); // Register EngineRecord with the engine sidechain. @@ -84,22 +84,22 @@ void RecordingManager::slotToggleRecording(double v) { } void RecordingManager::startRecording(bool generateFileName) { - QString encodingType = m_pConfig->getValueString( - ConfigKey(RECORDING_PREF_KEY, "Encoding")); - - if(generateFileName) { - m_iNumberOfBytesRecorded = 0; - m_secondsRecorded=0; - m_split_size = getFileSplitSize(); - m_split_time = getFileSplitTime(); - if (m_split_time < 999999999) { - qDebug() << "Split time is:" << m_split_time; - } - else { - qDebug() << "Split size is:" << m_split_size; - } - - m_iNumberSplits = 1; + QString encodingType = m_pConfig->getValueString( + ConfigKey(RECORDING_PREF_KEY, "Encoding")); + + if(generateFileName) { + m_iNumberOfBytesRecorded = 0; + m_secondsRecorded=0; + m_split_size = getFileSplitSize(); + m_split_time = getFileSplitTime(); + if (m_split_time < 999999999) { + qDebug() << "Split time is:" << m_split_time; + } + else { + qDebug() << "Split size is:" << m_split_size; + } + + m_iNumberSplits = 1; // Append file extension. QString date_time_str = formatDateTimeForFilename(QDateTime::currentDateTime()); m_recordingFile = QString("%1.%2") @@ -113,12 +113,12 @@ void RecordingManager::startRecording(bool generateFileName) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), m_recording_base_file +".cue"); - m_recReady->set(RECORD_READY); + m_recReady->set(RECORD_READY); - } else { + } else { // This is only executed if filesplit occurs. ++m_iNumberSplits; - m_secondsRecorded+=m_secondsRecordedSplit; + m_secondsRecorded+=m_secondsRecordedSplit; QString new_base_filename = m_recording_base_file +"part"+QString::number(m_iNumberSplits); m_recordingLocation = new_base_filename + "." +encodingType.toLower(); @@ -126,11 +126,11 @@ void RecordingManager::startRecording(bool generateFileName) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), new_base_filename +".cue"); m_recordingFile = QFileInfo(m_recordingLocation).fileName(); - m_recReady->set(RECORD_SPLIT_CONTINUE); + m_recReady->set(RECORD_SPLIT_CONTINUE); - } - m_iNumberOfBytesRecordedSplit = 0; - m_secondsRecordedSplit=0; + } + m_iNumberOfBytesRecordedSplit = 0; + m_secondsRecordedSplit=0; } void RecordingManager::stopRecording() @@ -140,7 +140,7 @@ void RecordingManager::stopRecording() m_recordingFile = ""; m_recordingLocation = ""; m_iNumberOfBytesRecorded = 0; - m_secondsRecorded = 0; + m_secondsRecorded = 0; } @@ -172,14 +172,14 @@ void RecordingManager::slotDurationRecorded(quint64 duration) if(m_secondsRecordedSplit != duration) { m_secondsRecordedSplit = duration; - if(duration >= m_split_time) - { - qDebug() << "Splitting after " << duration << " seconds"; - // Dont generate a new filename. - // This will reuse the previous filename but append a suffix. - startRecording(false); - } - emit(durationRecorded(getRecordedDurationStr(m_secondsRecorded+m_secondsRecordedSplit))); + if(duration >= m_split_time) + { + qDebug() << "Splitting after " << duration << " seconds"; + // Dont generate a new filename. + // This will reuse the previous filename but append a suffix. + startRecording(false); + } + emit(durationRecorded(getRecordedDurationStr(m_secondsRecorded+m_secondsRecordedSplit))); } } // Copy from the implementation in enginerecord.cpp @@ -194,10 +194,10 @@ void RecordingManager::slotBytesRecorded(int bytes) { // auto conversion to long m_iNumberOfBytesRecorded += bytes; - m_iNumberOfBytesRecordedSplit += bytes; + m_iNumberOfBytesRecordedSplit += bytes; if(m_iNumberOfBytesRecordedSplit >= m_split_size) { - qDebug() << "Splitting after " << m_iNumberOfBytesRecorded << " bytes written"; + qDebug() << "Splitting after " << m_iNumberOfBytesRecorded << " bytes written"; // Dont generate a new filename. // This will reuse the previous filename but append a suffix. startRecording(false); @@ -263,12 +263,12 @@ quint64 RecordingManager::getFileSplitSize() long RecordingManager::getFileSplitTime() { QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); - if(fileSizeStr == SPLIT_60MIN) + if(fileSizeStr == SPLIT_60MIN) return 60*60; else if(fileSizeStr == SPLIT_74MIN) return 74*60; else if(fileSizeStr == SPLIT_80MIN) - return 8;//0*60; //TODO: TEST!. Restore the correct value after that. + return 80*60; else if(fileSizeStr == SPLIT_120MIN) return 120*60; else // Do not limit by time for the rest. diff --git a/src/recording/recordingmanager.h b/src/recording/recordingmanager.h index 5b9d58c4b28..2b553889d9b 100644 --- a/src/recording/recordingmanager.h +++ b/src/recording/recordingmanager.h @@ -70,7 +70,7 @@ class RecordingManager : public QObject ControlPushButton* m_pToggleRecording; quint64 getFileSplitSize(); - long getFileSplitTime(); + long getFileSplitTime(); UserSettingsPointer m_pConfig; QString m_recordingDir; @@ -86,11 +86,11 @@ class RecordingManager : public QObject quint64 m_iNumberOfBytesRecorded; quint64 m_iNumberOfBytesRecordedSplit; quint64 m_split_size; - long m_split_time; + long m_split_time; int m_iNumberSplits; - long m_secondsRecorded; - long m_secondsRecordedSplit; - QString getRecordedDurationStr(quint64 duration); + long m_secondsRecorded; + long m_secondsRecordedSplit; + QString getRecordedDurationStr(quint64 duration); }; #endif // RECORDINGMANAGER_H From c082deeabc47e175d243a681391eda55717ee139 Mon Sep 17 00:00:00 2001 From: josepma Date: Tue, 1 Nov 2016 10:46:32 +0100 Subject: [PATCH 08/12] typo --- src/engine/sidechain/enginerecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 13643cd39b3..8928346ed7a 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -363,7 +363,7 @@ bool EngineRecord::openFile() { if (m_pSndfile) { sf_command(m_pSndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE); // Warning! Depending on how libsndfile is compiled autoclip may not work. - // Ensure CPU_CLIPS_NEGATIVE and CPU_CLIPS_NEGATIVE is setup properly in the build. + // Ensure CPU_CLIPS_NEGATIVE and CPU_CLIPS_POSITIVE is setup properly in the build. sf_command(m_pSndfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ; // Set meta data From 53ef61b579bcc1ff53d49e0ce63a84bb20df7503 Mon Sep 17 00:00:00 2001 From: josepma Date: Tue, 1 Nov 2016 12:46:12 +0100 Subject: [PATCH 09/12] splitting wav fileformat changes to another branch --- src/engine/sidechain/enginerecord.cpp | 17 ++--------- src/engine/sidechain/enginerecord.h | 2 -- src/preferences/dialog/dlgprefrecord.cpp | 36 ++++-------------------- 3 files changed, 8 insertions(+), 47 deletions(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index 8928346ed7a..bc299fa5d9d 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -69,8 +69,6 @@ void EngineRecord::updateFromPreferences() { // returns a number from 1 .. 10 m_OGGquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality")).toLatin1(); m_MP3quality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality")).toLatin1(); - m_WAVEquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality")).toLatin1(); - m_AIFFquality = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality")).toLatin1(); m_fileName = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Path")); m_baTitle = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Title")).toLatin1(); m_baAuthor = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Author")).toLatin1(); @@ -337,21 +335,12 @@ bool EngineRecord::openFile() { m_sfInfo.samplerate = m_sampleRate; m_sfInfo.channels = 2; - int quality_sel; if (m_encoding == ENCODING_WAVE) { - quality_sel = m_WAVEquality.toInt(); - m_sfInfo.format = SF_FORMAT_WAV; + m_sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; } else { - quality_sel = m_AIFFquality.toInt(); - m_sfInfo.format = SF_FORMAT_AIFF; - } - if (quality_sel < 5) { - m_sfInfo.format |= SF_FORMAT_PCM_16; - } else if (quality_sel < 9) { - m_sfInfo.format |= SF_FORMAT_PCM_24; - } else { - m_sfInfo.format |= SF_FORMAT_FLOAT; + m_sfInfo.format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16; } + // Creates a new WAVE or AIFF file and writes header information. #ifdef __WINDOWS__ // Pointer valid until string changed diff --git a/src/engine/sidechain/enginerecord.h b/src/engine/sidechain/enginerecord.h index 5ef097acb49..1f6f1751a91 100644 --- a/src/engine/sidechain/enginerecord.h +++ b/src/engine/sidechain/enginerecord.h @@ -82,8 +82,6 @@ class EngineRecord : public QObject, public EncoderCallback, public SideChainWor Encoder* m_pEncoder; QByteArray m_OGGquality; QByteArray m_MP3quality; - QByteArray m_WAVEquality; - QByteArray m_AIFFquality; QByteArray m_encoding; QString m_fileName; QByteArray m_baTitle; diff --git a/src/preferences/dialog/dlgprefrecord.cpp b/src/preferences/dialog/dlgprefrecord.cpp index 761fdcb0e8e..b91600d2478 100644 --- a/src/preferences/dialog/dlgprefrecord.cpp +++ b/src/preferences/dialog/dlgprefrecord.cpp @@ -155,12 +155,7 @@ void DlgPrefRecord::slotSliderQuality() { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality"), ConfigValue(SliderQuality->value())); } else if (m_pRadioMp3 && m_pRadioMp3->isChecked()) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "MP3_Quality"), ConfigValue(SliderQuality->value())); - } else if (m_pRadioWav && m_pRadioWav->isChecked()) { - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality"), ConfigValue(SliderQuality->value())); - } else if (m_pRadioAiff && m_pRadioAiff->isChecked()) { - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality"), ConfigValue(SliderQuality->value())); } - } int DlgPrefRecord::getSliderQualityVal() { @@ -169,21 +164,10 @@ int DlgPrefRecord::getSliderQualityVal() { } void DlgPrefRecord::updateTextQuality() { - if ((m_pRadioWav && m_pRadioWav->isChecked()) - || (m_pRadioAiff && m_pRadioAiff->isChecked())) { - if (SliderQuality->value() < 5) { - TextQuality->setText(tr("16 bits")); - } else if (SliderQuality->value() < 9) { - TextQuality->setText(tr("24 bits")); - } else { - TextQuality->setText(tr("32 bits float")); - } - } else { - int quality = getSliderQualityVal(); - //QString encodingType = comboBoxEncoding->currentText(); + int quality = getSliderQualityVal(); + //QString encodingType = comboBoxEncoding->currentText(); - TextQuality->setText(QString(QString::number(quality) + tr("kbps"))); - } + TextQuality->setText(QString(QString::number(quality) + tr("kbps"))); } void DlgPrefRecord::slotEncoding() { @@ -192,24 +176,14 @@ void DlgPrefRecord::slotEncoding() { //m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(comboBoxEncoding->currentText())); if (m_pRadioWav && m_pRadioWav->isChecked()) { - int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "WAVE_Quality")).toInt(); - // If value == 0 then a default value of 16 bits is proposed. - if (!value) - value = 1; // 16 bits - - SliderQuality->setValue(value); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_WAVE)); + groupBoxQuality->setEnabled(false); } else if (m_pRadioFlac && m_pRadioFlac->isChecked()) { m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_FLAC)); groupBoxQuality->setEnabled(false); } else if (m_pRadioAiff && m_pRadioAiff->isChecked()) { - int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "AIFF_Quality")).toInt(); - // If value == 0 then a default value of 16 bits is proposed. - if (!value) - value = 1; // 16 bits - - SliderQuality->setValue(value); m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Encoding"), ConfigValue(ENCODING_AIFF)); + groupBoxQuality->setEnabled(false); } else if (m_pRadioOgg && m_pRadioOgg->isChecked()) { int value = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "OGG_Quality")).toInt(); // If value == 0 then a default value of 128kbps is proposed. From 773cc21a66ebe1a8abc6e98a92a374e36a9b124e Mon Sep 17 00:00:00 2001 From: josepma Date: Wed, 2 Nov 2016 21:11:42 +0100 Subject: [PATCH 10/12] changes from the PR review --- src/preferences/dialog/dlgprefrecord.cpp | 6 -- src/preferences/dialog/dlgprefrecord.h | 1 - src/recording/recordingmanager.cpp | 97 +++++++++++++----------- src/recording/recordingmanager.h | 14 ++-- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/preferences/dialog/dlgprefrecord.cpp b/src/preferences/dialog/dlgprefrecord.cpp index b91600d2478..c2992bc923a 100644 --- a/src/preferences/dialog/dlgprefrecord.cpp +++ b/src/preferences/dialog/dlgprefrecord.cpp @@ -37,8 +37,6 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) setupUi(this); // See RECORD_* #defines in defs_recording.h - m_pRecordControl = new ControlProxy( - RECORDING_PREF_KEY, "status", this); m_pRadioOgg = new QRadioButton("Ogg Vorbis"); m_pRadioMp3 = new QRadioButton(ENCODING_MP3); @@ -116,10 +114,6 @@ DlgPrefRecord::DlgPrefRecord(QWidget* parent, UserSettingsPointer pConfig) this, SLOT(slotChangeSplitSize())); slotApply(); - // Make sure a corrupt config file won't cause us to record constantly. - // TODO: What does this do exactly? I thougth it stopped the recording when showing - // the preferences page but it does not (and i would preffer that keeps not stopping it). - m_pRecordControl->set(RECORD_OFF); comboBoxSplitting->addItem(SPLIT_650MB); comboBoxSplitting->addItem(SPLIT_700MB); diff --git a/src/preferences/dialog/dlgprefrecord.h b/src/preferences/dialog/dlgprefrecord.h index 5adeb93fdef..f7048343a95 100644 --- a/src/preferences/dialog/dlgprefrecord.h +++ b/src/preferences/dialog/dlgprefrecord.h @@ -61,7 +61,6 @@ class DlgPrefRecord : public DlgPreferencePage, public Ui::DlgPrefRecordDlg { // Pointer to config object UserSettingsPointer m_pConfig; - ControlProxy* m_pRecordControl; bool m_bConfirmOverwrite; QString fileTypeExtension; QRadioButton* m_pRadioOgg; diff --git a/src/recording/recordingmanager.cpp b/src/recording/recordingmanager.cpp index 4d654861777..4bb94d040e5 100644 --- a/src/recording/recordingmanager.cpp +++ b/src/recording/recordingmanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "control/controlproxy.h" #include "control/controlpushbutton.h" @@ -34,7 +35,7 @@ RecordingManager::RecordingManager(UserSettingsPointer pConfig, EngineMaster* pE m_recReady = new ControlProxy(m_recReadyCO->getKey(), this); m_split_size = getFileSplitSize(); - m_split_time = getFileSplitTime(); + m_split_time = getFileSplitSeconds(); // Register EngineRecord with the engine sidechain. @@ -83,54 +84,58 @@ void RecordingManager::slotToggleRecording(double v) { } } -void RecordingManager::startRecording(bool generateFileName) { +void RecordingManager::startRecording() { QString encodingType = m_pConfig->getValueString( ConfigKey(RECORDING_PREF_KEY, "Encoding")); - if(generateFileName) { - m_iNumberOfBytesRecorded = 0; - m_secondsRecorded=0; - m_split_size = getFileSplitSize(); - m_split_time = getFileSplitTime(); - if (m_split_time < 999999999) { - qDebug() << "Split time is:" << m_split_time; - } - else { - qDebug() << "Split size is:" << m_split_size; - } + m_iNumberOfBytesRecordedSplit = 0; + m_secondsRecordedSplit=0; + m_iNumberOfBytesRecorded = 0; + m_secondsRecorded=0; + m_split_size = getFileSplitSize(); + m_split_time = getFileSplitSeconds(); + if (m_split_time < INT_MAX) { + qDebug() << "Split time is:" << m_split_time; + } + else { + qDebug() << "Split size is:" << m_split_size; + } - m_iNumberSplits = 1; - // Append file extension. - QString date_time_str = formatDateTimeForFilename(QDateTime::currentDateTime()); - m_recordingFile = QString("%1.%2") - .arg(date_time_str, encodingType.toLower()); + m_iNumberSplits = 1; + // Append file extension. + QString date_time_str = formatDateTimeForFilename(QDateTime::currentDateTime()); + m_recordingFile = QString("%1.%2") + .arg(date_time_str, encodingType.toLower()); + + // Storing the absolutePath of the recording file without file extension. + m_recording_base_file = getRecordingDir(); + m_recording_base_file.append("/").append(date_time_str); + // Appending file extension to get the filelocation. + m_recordingLocation = m_recording_base_file + "."+ encodingType.toLower(); + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), m_recording_base_file +".cue"); + + m_recReady->set(RECORD_READY); +} - // Storing the absolutePath of the recording file without file extension. - m_recording_base_file = getRecordingDir(); - m_recording_base_file.append("/").append(date_time_str); - // Appending file extension to get the filelocation. - m_recordingLocation = m_recording_base_file + "."+ encodingType.toLower(); - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), m_recording_base_file +".cue"); +void RecordingManager::splitContinueRecording() +{ + ++m_iNumberSplits; + m_secondsRecorded+=m_secondsRecordedSplit; - m_recReady->set(RECORD_READY); + m_iNumberOfBytesRecordedSplit = 0; + m_secondsRecordedSplit=0; - } else { - // This is only executed if filesplit occurs. - ++m_iNumberSplits; - m_secondsRecorded+=m_secondsRecordedSplit; - QString new_base_filename = m_recording_base_file +"part"+QString::number(m_iNumberSplits); - m_recordingLocation = new_base_filename + "." +encodingType.toLower(); + QString encodingType = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Encoding")); - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); - m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), new_base_filename +".cue"); - m_recordingFile = QFileInfo(m_recordingLocation).fileName(); + QString new_base_filename = m_recording_base_file +"part"+QString::number(m_iNumberSplits); + m_recordingLocation = new_base_filename + "." +encodingType.toLower(); - m_recReady->set(RECORD_SPLIT_CONTINUE); + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "Path"), m_recordingLocation); + m_pConfig->set(ConfigKey(RECORDING_PREF_KEY, "CuePath"), new_base_filename +".cue"); + m_recordingFile = QFileInfo(m_recordingLocation).fileName(); - } - m_iNumberOfBytesRecordedSplit = 0; - m_secondsRecordedSplit=0; + m_recReady->set(RECORD_SPLIT_CONTINUE); } void RecordingManager::stopRecording() @@ -175,9 +180,8 @@ void RecordingManager::slotDurationRecorded(quint64 duration) if(duration >= m_split_time) { qDebug() << "Splitting after " << duration << " seconds"; - // Dont generate a new filename. // This will reuse the previous filename but append a suffix. - startRecording(false); + splitContinueRecording(); } emit(durationRecorded(getRecordedDurationStr(m_secondsRecorded+m_secondsRecordedSplit))); } @@ -195,12 +199,15 @@ void RecordingManager::slotBytesRecorded(int bytes) // auto conversion to long m_iNumberOfBytesRecorded += bytes; m_iNumberOfBytesRecordedSplit += bytes; + + //Split before reaching the max size. m_split_size has some headroom, as + //seen in the constant defintions in defs_recording.h. Also, note that + //bytes are increased in the order of 10s of KBs each call. if(m_iNumberOfBytesRecordedSplit >= m_split_size) { qDebug() << "Splitting after " << m_iNumberOfBytesRecorded << " bytes written"; - // Dont generate a new filename. // This will reuse the previous filename but append a suffix. - startRecording(false); + splitContinueRecording(); } emit(bytesRecorded(m_iNumberOfBytesRecorded)); } @@ -260,7 +267,7 @@ quint64 RecordingManager::getFileSplitSize() else return SIZE_650MB; } -long RecordingManager::getFileSplitTime() +int RecordingManager::getFileSplitSeconds() { QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); if(fileSizeStr == SPLIT_60MIN) @@ -272,5 +279,5 @@ long RecordingManager::getFileSplitTime() else if(fileSizeStr == SPLIT_120MIN) return 120*60; else // Do not limit by time for the rest. - return 999999999; + return INT_MAX; } diff --git a/src/recording/recordingmanager.h b/src/recording/recordingmanager.h index 2b553889d9b..959ec37164b 100644 --- a/src/recording/recordingmanager.h +++ b/src/recording/recordingmanager.h @@ -34,12 +34,8 @@ class RecordingManager : public QObject // This will try to start recording. If successful, slotIsRecording will be // called and a signal isRecording will be emitted. - // Parameter semantic: If true, the method computes the filename based on - // date/time information. This is the default behavior. If false, - // slotBytesRecorded just noticed that recording must be interrupted - // to split the file. The nth filename will follow the date/time - // name of the first split but with a suffix. - void startRecording(bool generateFileName=true); + // The method computes the filename based on date/time information. + void startRecording(); void stopRecording(); bool isRecordingActive(); void setRecordingDir(); @@ -65,12 +61,16 @@ class RecordingManager : public QObject private: QString formatDateTimeForFilename(QDateTime dateTime) const; + // slotBytesRecorded just noticed that recording must be interrupted + // to split the file. The nth filename will follow the date/time + // name of the first split but with a suffix. + void splitContinueRecording(); ControlProxy* m_recReady; ControlObject* m_recReadyCO; ControlPushButton* m_pToggleRecording; quint64 getFileSplitSize(); - long getFileSplitTime(); + int getFileSplitSeconds(); UserSettingsPointer m_pConfig; QString m_recordingDir; From 1c020de6e5eda1069c0ea335e56a609c2439157e Mon Sep 17 00:00:00 2001 From: josepma Date: Thu, 3 Nov 2016 22:54:21 +0100 Subject: [PATCH 11/12] more review changes (signed/unsigned) --- src/library/recording/dlgrecording.cpp | 6 +++--- src/library/recording/dlgrecording.h | 2 +- src/recording/recordingmanager.cpp | 6 +++--- src/recording/recordingmanager.h | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/library/recording/dlgrecording.cpp b/src/library/recording/dlgrecording.cpp index 019a4c32b18..043a9fffd15 100644 --- a/src/library/recording/dlgrecording.cpp +++ b/src/library/recording/dlgrecording.cpp @@ -34,8 +34,8 @@ DlgRecording::DlgRecording(QWidget* parent, UserSettingsPointer pConfig, connect(m_pRecordingManager, SIGNAL(isRecording(bool)), this, SLOT(slotRecordingEnabled(bool))); - connect(m_pRecordingManager, SIGNAL(bytesRecorded(long)), - this, SLOT(slotBytesRecorded(long))); + connect(m_pRecordingManager, SIGNAL(bytesRecorded(int)), + this, SLOT(slotBytesRecorded(int))); connect(m_pRecordingManager, SIGNAL(durationRecorded(QString)), this, SLOT(slotDurationRecorded(QString))); @@ -129,7 +129,7 @@ void DlgRecording::slotRecordingEnabled(bool isRecording) { } // gets number of recorded bytes and update label -void DlgRecording::slotBytesRecorded(long bytes) { +void DlgRecording::slotBytesRecorded(int bytes) { double megabytes = bytes / 1048576.0; m_bytesRecordedStr = QString::number(megabytes,'f',2); refreshLabel(); diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h index 0f8db1f42ad..53b515bf322 100644 --- a/src/library/recording/dlgrecording.h +++ b/src/library/recording/dlgrecording.h @@ -36,7 +36,7 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib public slots: void toggleRecording(bool toggle); void slotRecordingEnabled(bool); - void slotBytesRecorded(long); + void slotBytesRecorded(int); void refreshBrowseModel(); void slotRestoreSearch(); void slotDurationRecorded(QString durationRecorded); diff --git a/src/recording/recordingmanager.cpp b/src/recording/recordingmanager.cpp index 4bb94d040e5..417cc2e6eed 100644 --- a/src/recording/recordingmanager.cpp +++ b/src/recording/recordingmanager.cpp @@ -187,7 +187,7 @@ void RecordingManager::slotDurationRecorded(quint64 duration) } } // Copy from the implementation in enginerecord.cpp -QString RecordingManager::getRecordedDurationStr(quint64 duration) { +QString RecordingManager::getRecordedDurationStr(unsigned int duration) { return QString("%1:%2") .arg(duration / 60, 2, 'f', 0, '0') // minutes .arg(duration % 60, 2, 'f', 0, '0'); // seconds @@ -196,7 +196,7 @@ QString RecordingManager::getRecordedDurationStr(quint64 duration) { // Only called when recording is active. void RecordingManager::slotBytesRecorded(int bytes) { - // auto conversion to long + // auto conversion to quint64 m_iNumberOfBytesRecorded += bytes; m_iNumberOfBytesRecordedSplit += bytes; @@ -267,7 +267,7 @@ quint64 RecordingManager::getFileSplitSize() else return SIZE_650MB; } -int RecordingManager::getFileSplitSeconds() +unsigned int RecordingManager::getFileSplitSeconds() { QString fileSizeStr = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "FileSize")); if(fileSizeStr == SPLIT_60MIN) diff --git a/src/recording/recordingmanager.h b/src/recording/recordingmanager.h index 959ec37164b..ac7d3ed1f79 100644 --- a/src/recording/recordingmanager.h +++ b/src/recording/recordingmanager.h @@ -46,7 +46,7 @@ class RecordingManager : public QObject signals: // Emits the cumulative number of bytes currently recorded. - void bytesRecorded(long); + void bytesRecorded(int); void isRecording(bool); void durationRecorded(QString); @@ -70,7 +70,7 @@ class RecordingManager : public QObject ControlPushButton* m_pToggleRecording; quint64 getFileSplitSize(); - int getFileSplitSeconds(); + unsigned int getFileSplitSeconds(); UserSettingsPointer m_pConfig; QString m_recordingDir; @@ -86,11 +86,11 @@ class RecordingManager : public QObject quint64 m_iNumberOfBytesRecorded; quint64 m_iNumberOfBytesRecordedSplit; quint64 m_split_size; - long m_split_time; + unsigned int m_split_time; int m_iNumberSplits; - long m_secondsRecorded; - long m_secondsRecordedSplit; - QString getRecordedDurationStr(quint64 duration); + unsigned int m_secondsRecorded; + unsigned int m_secondsRecordedSplit; + QString getRecordedDurationStr(unsigned int duration); }; #endif // RECORDINGMANAGER_H From 3e4902ca1543c5c907823368b75b68300015b2c8 Mon Sep 17 00:00:00 2001 From: josepma Date: Fri, 4 Nov 2016 23:42:25 +0100 Subject: [PATCH 12/12] some improvements in track time in cue files. Fixes the 00:00:44 time on new splits, and improves the time precision of first track of the initial cue. --- src/engine/sidechain/enginerecord.cpp | 42 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/engine/sidechain/enginerecord.cpp b/src/engine/sidechain/enginerecord.cpp index bc299fa5d9d..d951f7a2d81 100644 --- a/src/engine/sidechain/enginerecord.cpp +++ b/src/engine/sidechain/enginerecord.cpp @@ -125,21 +125,26 @@ void EngineRecord::updateFromPreferences() { bool EngineRecord::metaDataHasChanged() { + //Originally, m_iMetaDataLife was used so that getCurrentPlayingTrack was called + //less often, because it was calculating it. + //Nowadays (since Mixxx 1.11), it just accesses a map on a thread safe method. + TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); + if (!pTrack) { + m_iMetaDataLife = kMetaDataLifeTimeout; + return false; + } + + //The counter is kept so that changes back and forth with the faders/crossfader + //(like in scratching or other effects) are not counted as multiple track changes + //in the cue file. A better solution could consist of a signal from PlayerInfo and + //a slot that decides if the changes received are valid or are to be ignored once + //the next process call comes. This could also help improve the time written in the CUE. if (m_iMetaDataLife < kMetaDataLifeTimeout) { m_iMetaDataLife++; return false; } m_iMetaDataLife = 0; - //TODO: Needs improvement. Usually when we start recording, all tracks are stopped - // and we start the track just after that. Given that this is executed with start recording, - // it waits for kMetaDataLifeTimeout until it actually notices that the track - // has started playing. This translates to the cue file start time being too late. - // Maybe we need a signal for this too. - TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); - if (!pTrack) - return false; - if (m_pCurrentTrack) { if (!pTrack->getId().isValid() || !m_pCurrentTrack->getId().isValid()) { if ((pTrack->getArtist() == m_pCurrentTrack->getArtist()) && @@ -219,6 +224,7 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { // clean frames counting and get current sample rate. m_frames = 0; m_sampleRate = m_pSamplerate->get(); + m_recordedDuration = 0; if (m_bCueIsEnabled) { openCueFile(); @@ -248,6 +254,16 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { m_pEncoder->encodeBuffer(pBuffer, iBufferSize); } } + + //Writing cueLine before updating the time counter since we preffer to be ahead + //rather than late. + if (m_bCueIsEnabled) { + if (metaDataHasChanged()) { + m_cueTrack++; + writeCueLine(); + m_cueFile.flush(); + } + } // update frames counting and recorded duration (seconds) m_frames += iBufferSize / 2; @@ -259,14 +275,6 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) { if (lastDuration != m_recordedDuration) { emit(durationRecorded(m_recordedDuration)); } - - if (m_bCueIsEnabled) { - if (metaDataHasChanged()) { - m_cueTrack++; - writeCueLine(); - m_cueFile.flush(); - } - } } }