diff --git a/app/config/config.cpp b/app/config/config.cpp index ba2d62348..2f5f96a88 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -42,6 +42,11 @@ Config::Config() SetDefaults(); } +void Config::SetEntryInternal(const QString &key, NodeParam::DataType type, const QVariant &data) +{ + config_map_[key] = {type, data}; +} + QString Config::GetConfigFilePath() { return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("config.xml")); @@ -55,63 +60,63 @@ Config &Config::Current() void Config::SetDefaults() { config_map_.clear(); - config_map_["TimecodeDisplay"] = Timecode::kTimecodeDropFrame; - config_map_["DefaultStillLength"] = QVariant::fromValue(rational(2)); - config_map_["HoverFocus"] = false; - config_map_["AudioScrubbing"] = true; - config_map_["AutorecoveryInterval"] = 1; - config_map_["Language"] = "en_US"; - config_map_["ScrollZooms"] = false; - config_map_["EnableSeekToImport"] = false; - config_map_["EditToolAlsoSeeks"] = false; - config_map_["EditToolSelectsLinks"] = false; - config_map_["EnableDragFilesToTimeline"] = true; - config_map_["InvertTimelineScrollAxes"] = true; - config_map_["SelectAlsoSeeks"] = false; - config_map_["PasteSeeks"] = true; - config_map_["SelectAlsoSeeks"] = false; - config_map_["SetNameWithMarker"] = false; - config_map_["AutoSeekToBeginning"] = true; - config_map_["DropFileOnMediaToReplace"] = false; - config_map_["AddDefaultEffectsToClips"] = true; - config_map_["AutoscaleByDefault"] = false; - config_map_["Autoscroll"] = AutoScroll::kPage; - config_map_["AutoSelectDivider"] = true; - config_map_["SetNameWithMarker"] = false; - config_map_["RectifiedWaveforms"] = false; - config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; - config_map_["Loop"] = false; + SetEntryInternal(QStringLiteral("TimecodeDisplay"), NodeParam::kInt, Timecode::kTimecodeDropFrame); + SetEntryInternal(QStringLiteral("DefaultStillLength"), NodeParam::kRational, QVariant::fromValue(rational(2))); + SetEntryInternal(QStringLiteral("HoverFocus"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("AudioScrubbing"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("AutorecoveryInterval"), NodeParam::kInt, 1); + SetEntryInternal(QStringLiteral("Language"), NodeParam::kString, "en_US"); + SetEntryInternal(QStringLiteral("ScrollZooms"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("EnableSeekToImport"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("EditToolAlsoSeeks"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("EditToolSelectsLinks"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("EnableDragFilesToTimeline"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("InvertTimelineScrollAxes"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("SelectAlsoSeeks"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("PasteSeeks"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("SelectAlsoSeeks"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("AutoSeekToBeginning"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("DropFileOnMediaToReplace"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("AddDefaultEffectsToClips"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("AutoscaleByDefault"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("Autoscroll"), NodeParam::kInt, AutoScroll::kPage); + SetEntryInternal(QStringLiteral("AutoSelectDivider"), NodeParam::kBoolean, true); + SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("RectifiedWaveforms"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("DropWithoutSequenceBehavior"), NodeParam::kInt, TimelineWidget::kDWSAsk); + SetEntryInternal(QStringLiteral("Loop"), NodeParam::kBoolean, false); - config_map_["AutoCacheInterval"] = 250; + SetEntryInternal(QStringLiteral("AutoCacheInterval"), NodeParam::kInt, 250); - config_map_["NodeCatColor0"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.75f)); - config_map_["NodeCatColor1"] = QVariant::fromValue(Color(0.25f, 0.25f, 0.25f)); - config_map_["NodeCatColor2"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.25f)); - config_map_["NodeCatColor3"] = QVariant::fromValue(Color(0.75f, 0.25f, 0.75f)); - config_map_["NodeCatColor4"] = QVariant::fromValue(Color(0.25f, 0.75f, 0.75f)); - config_map_["NodeCatColor5"] = QVariant::fromValue(Color(0.50f, 0.50f, 0.50f)); - config_map_["NodeCatColor6"] = QVariant::fromValue(Color(0.25f, 0.75f, 0.25f)); - config_map_["NodeCatColor7"] = QVariant::fromValue(Color(0.25f, 0.25f, 0.75f)); - config_map_["NodeCatColor8"] = QVariant::fromValue(Color(0.75f, 0.25f, 0.25f)); + SetEntryInternal(QStringLiteral("NodeCatColor0"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.75f, 0.75f))); + SetEntryInternal(QStringLiteral("NodeCatColor1"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.25f, 0.25f))); + SetEntryInternal(QStringLiteral("NodeCatColor2"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.75f, 0.25f))); + SetEntryInternal(QStringLiteral("NodeCatColor3"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.25f, 0.75f))); + SetEntryInternal(QStringLiteral("NodeCatColor4"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.75f, 0.75f))); + SetEntryInternal(QStringLiteral("NodeCatColor5"), NodeParam::kColor, QVariant::fromValue(Color(0.50f, 0.50f, 0.50f))); + SetEntryInternal(QStringLiteral("NodeCatColor6"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.75f, 0.25f))); + SetEntryInternal(QStringLiteral("NodeCatColor7"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.25f, 0.75f))); + SetEntryInternal(QStringLiteral("NodeCatColor8"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.25f, 0.25f))); - config_map_["AudioOutput"] = QString(); - config_map_["AudioInput"] = QString(); + SetEntryInternal(QStringLiteral("AudioOutput"), NodeParam::kString, QString()); + SetEntryInternal(QStringLiteral("AudioInput"), NodeParam::kString, QString()); - config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1)); - config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5)); + SetEntryInternal(QStringLiteral("DiskCacheBehind"), NodeParam::kRational, QVariant::fromValue(rational(1))); + SetEntryInternal(QStringLiteral("DiskCacheAhead"), NodeParam::kRational, QVariant::fromValue(rational(5))); - config_map_["DefaultSequenceWidth"] = 1920; - config_map_["DefaultSequenceHeight"] = 1080; - config_map_["DefaultSequenceFrameRate"] = QVariant::fromValue(rational(1001, 30000)); - config_map_["DefaultSequenceAudioFrequency"] = 48000; - config_map_["DefaultSequenceAudioLayout"] = QVariant::fromValue(static_cast(AV_CH_LAYOUT_STEREO)); - config_map_["DefaultSequencePreviewFormat"] = PixelFormat::PIX_FMT_RGBA16F; + SetEntryInternal(QStringLiteral("DefaultSequenceWidth"), NodeParam::kInt, 1920); + SetEntryInternal(QStringLiteral("DefaultSequenceHeight"), NodeParam::kInt, 1080); + SetEntryInternal(QStringLiteral("DefaultSequenceFrameRate"), NodeParam::kRational, QVariant::fromValue(rational(1001, 30000))); + SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"), NodeParam::kInt, 48000); + SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeParam::kInt, QVariant::fromValue(static_cast(AV_CH_LAYOUT_STEREO))); + SetEntryInternal(QStringLiteral("DefaultSequencePreviewFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); // Online/offline settings - config_map_["OnlinePixelFormat"] = PixelFormat::PIX_FMT_RGBA32F; - config_map_["OfflinePixelFormat"] = PixelFormat::PIX_FMT_RGBA16F; - config_map_["OnlineOCIOMethod"] = ColorManager::kOCIOAccurate; - config_map_["OfflineOCIOMethod"] = ColorManager::kOCIOFast; + SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA32F); + SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); + SetEntryInternal(QStringLiteral("OnlineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOAccurate); + SetEntryInternal(QStringLiteral("OfflineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOFast); } void Config::Load() @@ -171,7 +176,7 @@ void Config::Load() current_config_[key] = QVariant::fromValue(match.flipped()); } else { - current_config_[key] = value; + current_config_[key] = NodeInput::StringToValue(current_config_.GetConfigEntryType(key), value, false); } } @@ -216,10 +221,10 @@ void Config::Save() // Anything after the hyphen is considered "unimportant" information writer.writeTextElement("Version", QCoreApplication::applicationVersion().split('-').first()); - QMapIterator iterator(current_config_.config_map_); + QMapIterator iterator(current_config_.config_map_); while (iterator.hasNext()) { iterator.next(); - writer.writeTextElement(iterator.key(), iterator.value().toString()); + writer.writeTextElement(iterator.key(), NodeInput::ValueToString(iterator.value().type, iterator.value().data, false)); } writer.writeEndElement(); // Configuration @@ -231,12 +236,17 @@ void Config::Save() QVariant Config::operator[](const QString &key) const { - return config_map_[key]; + return config_map_[key].data; } QVariant &Config::operator[](const QString &key) { - return config_map_[key]; + return config_map_[key].data; +} + +NodeParam::DataType Config::GetConfigEntryType(const QString &key) const +{ + return config_map_[key].type; } OLIVE_NAMESPACE_EXIT diff --git a/app/config/config.h b/app/config/config.h index 342d50484..dfed5a23d 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -26,6 +26,7 @@ #include #include "common/timecodefunctions.h" +#include "node/param.h" OLIVE_NAMESPACE_ENTER @@ -43,10 +44,19 @@ public: QVariant& operator[](const QString&); + NodeParam::DataType GetConfigEntryType(const QString& key) const; + private: Config(); - QMap config_map_; + struct ConfigEntry { + NodeParam::DataType type; + QVariant data; + }; + + void SetEntryInternal(const QString& key, NodeParam::DataType type, const QVariant& data); + + QMap config_map_; static Config current_config_; diff --git a/app/core.cpp b/app/core.cpp index 419e612c0..5f483f3ba 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -205,7 +205,7 @@ void Core::Start() void Core::Stop() { // Save Config - //Config::Save(); + Config::Save(); // Save recently opened projects { diff --git a/app/node/input.cpp b/app/node/input.cpp index 4e75caa5b..890cb57e5 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -327,17 +327,46 @@ void NodeInput::SetDefaultValue(const QVector &default_value) QString NodeInput::ValueToString(const QVariant &value) const { - return ValueToString(data_type_, value); + return ValueToString(data_type_, value, true); } -QString NodeInput::ValueToString(const DataType& data_type, const QVariant &value) +QString NodeInput::ValueToString(const DataType& data_type, const QVariant &value, bool value_is_a_key_track) { - switch (data_type) { - case kRational: + if (!value_is_a_key_track && data_type == kVec2) { + QVector2D vec = value.value(); + + return QStringLiteral("%1:%2").arg(QString::number(vec.x()), + QString::number(vec.y())); + } else if (!value_is_a_key_track && data_type == kVec3) { + QVector3D vec = value.value(); + + return QStringLiteral("%1:%2:%3").arg(QString::number(vec.x()), + QString::number(vec.y()), + QString::number(vec.z())); + } else if (!value_is_a_key_track && data_type == kVec4) { + QVector4D vec = value.value(); + + return QStringLiteral("%1:%2:%3:%4").arg(QString::number(vec.x()), + QString::number(vec.y()), + QString::number(vec.z()), + QString::number(vec.w())); + } else if (!value_is_a_key_track && data_type == kColor) { + Color c = value.value(); + + return QStringLiteral("%1:%2:%3:%4").arg(QString::number(c.red()), + QString::number(c.green()), + QString::number(c.blue()), + QString::number(c.alpha())); + } else if (data_type == kRational) { return value.value().toString(); - case kFootage: + } else if (data_type == kFootage) { return QString::number(reinterpret_cast(value.value().get())); - default: + } else if (data_type == kTexture + || data_type == kSamples + || data_type == kBuffer) { + // These data types need no XML representation + return QString(); + } else { if (value.canConvert()) { return value.toString(); } @@ -346,22 +375,31 @@ QString NodeInput::ValueToString(const DataType& data_type, const QVariant &valu qWarning() << "Failed to convert type" << ToHex(data_type) << "to string"; } - /* fall through */ - - // These data types need no XML representation - case kTexture: - case kSamples: - case kBuffer: return QString(); } } -QVariant NodeInput::StringToValue(const DataType& data_type, const QString &string) +QVariant NodeInput::StringToValue(const DataType& data_type, const QString &string, bool value_is_a_key_track) { - switch (data_type) { - case kRational: + if (!value_is_a_key_track && data_type == kVec2) { + QStringList vals = string.split(':'); + + return QVector2D(vals.at(0).toFloat(), vals.at(1).toFloat()); + } else if (!value_is_a_key_track && data_type == kVec3) { + QStringList vals = string.split(':'); + + return QVector3D(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat()); + } else if (!value_is_a_key_track && data_type == kVec4) { + QStringList vals = string.split(':'); + + return QVector4D(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat(), vals.at(3).toFloat()); + } else if (!value_is_a_key_track && data_type == kColor) { + QStringList vals = string.split(':'); + + return QVariant::fromValue(Color(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat(), vals.at(3).toFloat())); + } else if (data_type == kRational) { return QVariant::fromValue(rational::fromString(string)); - default: + } else { return string; } } @@ -429,7 +467,7 @@ QVariant NodeInput::StringToValue(const QString &string, QList& list, bool traverse, bool exclusive_only) const; diff --git a/app/node/param.cpp b/app/node/param.cpp index b5604c413..601b393da 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -240,8 +240,8 @@ QString NodeParam::GetPrettyDataTypeName(const NodeParam::DataType &type) QByteArray NodeParam::ValueToBytes(const NodeParam::DataType &type, const QVariant &value) { switch (type) { - case kInt: return ValueToBytesInternal(value); - case kFloat: return ValueToBytesInternal(value); + case kInt: return ValueToBytesInternal(value); + case kFloat: return ValueToBytesInternal(value); case kColor: return ValueToBytesInternal(value); case kText: return value.toString().toUtf8(); case kBoolean: return ValueToBytesInternal(value); diff --git a/app/node/param.h b/app/node/param.h index 03e667936..0157d7bdd 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -67,7 +67,7 @@ public: /** * Integer type * - * Resolves to `int` (may resolve to `long` in the future). + * Resolves to int64_t. */ kInt = 0x1, diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index e8ba9dabc..9b9e8897b 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -238,11 +238,11 @@ QList AudioPlaybackCache::GetValidRanges(const TimeRange& range, cons void AudioPlaybackCache::UpdateFilename(const QString &s) { - filename_ = QDir(GetCacheFilename()).filePath(s); + filename_ = QDir(GetCacheDirectory()).filePath(s); filename_.append(QStringLiteral(".pcm")); } -const QString &AudioPlaybackCache::GetCacheFilename() const +const QString &AudioPlaybackCache::GetPCMFilename() const { return filename_; } diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index fe9c7cd6f..facba48d3 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -46,7 +46,7 @@ public: //void SetUuid(const QUuid& id); - const QString& GetCacheFilename() const; + const QString& GetPCMFilename() const; QList GetValidRanges(const TimeRange &range, const qint64 &job_time); diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index 1bc204713..4b580711a 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -297,9 +297,12 @@ QVariant OpenGLProxy::RunNodeAccelerated(const Node *node, switch (data_type) { case NodeInput::kInt: + // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to + // over/underflows if the number is large enough, but the likelihood of that is quite low. shader->setUniformValue(variable_location, value.toInt()); break; case NodeInput::kFloat: + // kFloat technically specifies a double but as above, OpenGL doesn't support those. shader->setUniformValue(variable_location, value.toFloat()); break; case NodeInput::kVec2: diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index bcbdc083b..69cdfe502 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -105,7 +105,7 @@ bool ExportTask::Run() if (params_.audio_enabled()) { // Write audio data now - encoder_->WriteAudio(audio_params(), audio_data_.GetCacheFilename()); + encoder_->WriteAudio(audio_params(), audio_data_.GetPCMFilename()); } encoder_->Close(); diff --git a/app/widget/nodetableview/nodetableview.cpp b/app/widget/nodetableview/nodetableview.cpp index 01fc8c315..7696ace3b 100644 --- a/app/widget/nodetableview/nodetableview.cpp +++ b/app/widget/nodetableview/nodetableview.cpp @@ -157,7 +157,7 @@ void NodeTableView::SetTime(const rational &time) { QVector split_values = input->split_normal_value_into_track_values(value.data()); for (int k=0;ksetText(2 + k, NodeInput::ValueToString(value.type(), split_values.at(k))); + sub_item->setText(2 + k, NodeInput::ValueToString(value.type(), split_values.at(k), true)); } } } diff --git a/app/widget/viewer/audiowaveformview.cpp b/app/widget/viewer/audiowaveformview.cpp index 18193fc1f..490d49b47 100644 --- a/app/widget/viewer/audiowaveformview.cpp +++ b/app/widget/viewer/audiowaveformview.cpp @@ -66,7 +66,7 @@ void AudioWaveformView::paintEvent(QPaintEvent *event) const AudioParams& params = playback_->GetParameters(); if (!playback_ - || playback_->GetCacheFilename().isEmpty() + || playback_->GetPCMFilename().isEmpty() || !params.is_valid()) { return; } @@ -78,7 +78,7 @@ void AudioWaveformView::paintEvent(QPaintEvent *event) cached_waveform_ = QPixmap(size()); cached_waveform_.fill(Qt::transparent); - QFile fs(playback_->GetCacheFilename()); + QFile fs(playback_->GetPCMFilename()); if (fs.open(QFile::ReadOnly)) { diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index d8f561bd0..3c1cc304c 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -502,7 +502,7 @@ void ViewerWidget::PushScrubbedAudio() { if (!IsPlaying() && Config::Current()["AudioScrubbing"].toBool()) { // Get audio src device from renderer - QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetCacheFilename(); + QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetPCMFilename(); QFile audio_src(audio_fn); if (audio_src.open(QFile::ReadOnly)) { @@ -616,7 +616,7 @@ void ViewerWidget::FinishPlayPreprocess() { int64_t playback_start_time = ruler()->GetTime(); - QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetCacheFilename(); + QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetPCMFilename(); if (!audio_fn.isEmpty()) { AudioManager::instance()->SetOutputParams(GetConnectedNode()->audio_playback_cache()->GetParameters()); AudioManager::instance()->StartOutput(audio_fn,