diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index 9794b77c5..174f37fb4 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -184,25 +184,21 @@ void AudioManager::HardReset() Pa_Initialize(); } -bool AudioManager::StartRecording(const QString &filename, const AudioParams ¶ms) +bool AudioManager::StartRecording(const EncodingParams ¶ms) { if (input_device_ == paNoDevice) { return false; } - EncodingParams encode_param; - encode_param.EnableAudio(params, ExportCodec::kCodecMP3); - encode_param.SetFilename(filename); - - input_encoder_ = new FFmpegEncoder(encode_param); + input_encoder_ = new FFmpegEncoder(params); if (!input_encoder_->Open()) { qCritical() << "Failed to open encoder for recording"; return false; } - PaStreamParameters p = GetPortAudioParams(params, input_device_); + PaStreamParameters p = GetPortAudioParams(params.audio_params(), input_device_); - if (Pa_OpenStream(&input_stream_, &p, nullptr, params.sample_rate(), paFramesPerBufferUnspecified, paNoFlag, InputCallback, input_encoder_) == paNoError) { + if (Pa_OpenStream(&input_stream_, &p, nullptr, params.audio_params().sample_rate(), paFramesPerBufferUnspecified, paNoFlag, InputCallback, input_encoder_) == paNoError) { if (Pa_StartStream(input_stream_) == paNoError) { return true; } diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index 62fd0e920..bf71e2223 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -74,7 +74,7 @@ public: void HardReset(); - bool StartRecording(const QString &filename, const AudioParams ¶ms); + bool StartRecording(const EncodingParams ¶ms); void StopRecording(); diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 9b38505b6..01985e0d0 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -50,7 +50,7 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const { QStringList pix_fmts; - const AVCodec* codec_info = GetEncoder(c); + const AVCodec* codec_info = GetEncoder(c, AudioParams::kFormatInvalid); if (codec_info) { for (int i=0; codec_info->pix_fmts[i]!=-1; i++) { @@ -579,7 +579,7 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV } // Find encoder - const AVCodec* encoder = GetEncoder(codec); + const AVCodec* encoder = GetEncoder(codec, params().audio_params().format()); if (!encoder) { SetError(tr("Failed to find codec for 0x%1").arg(codec, 16)); return false; @@ -653,7 +653,7 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV codec_ctx->sample_rate = params().audio_params().sample_rate(); codec_ctx->channel_layout = params().audio_params().channel_layout(); codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout); - codec_ctx->sample_fmt = encoder->sample_fmts[0]; + codec_ctx->sample_fmt = FFmpegUtils::GetFFmpegSampleFormat(params().audio_params().format()); codec_ctx->time_base = {1, codec_ctx->sample_rate}; if (params().audio_bit_rate() > 0) { @@ -842,7 +842,7 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio, bool pla return true; } -const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c) +const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, AudioParams::Format aformat) { switch (c) { case ExportCodec::kCodecH264: @@ -872,7 +872,24 @@ const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c) case ExportCodec::kCodecAAC: return avcodec_find_encoder(AV_CODEC_ID_AAC); case ExportCodec::kCodecPCM: - return avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE); + switch (aformat) { + case AudioParams::kFormatInvalid: + case AudioParams::kFormatCount: + break; + case AudioParams::kFormatUnsigned8: + return avcodec_find_encoder(AV_CODEC_ID_PCM_U8); + case AudioParams::kFormatSigned16: + return avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE); + case AudioParams::kFormatSigned32: + return avcodec_find_encoder(AV_CODEC_ID_PCM_S32LE); + case AudioParams::kFormatSigned64: + return avcodec_find_encoder(AV_CODEC_ID_PCM_S64LE); + case AudioParams::kFormatFloat32: + return avcodec_find_encoder(AV_CODEC_ID_PCM_F32LE); + case AudioParams::kFormatFloat64: + return avcodec_find_encoder(AV_CODEC_ID_PCM_F64LE); + } + break; case ExportCodec::kCodecFLAC: return avcodec_find_encoder(AV_CODEC_ID_FLAC); case ExportCodec::kCodecOpus: diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index 82e7040da..1bbc1ac54 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -80,7 +80,7 @@ private: bool InitializeResampleContext(const AudioParams &audio, bool planar); - static const AVCodec *GetEncoder(ExportCodec::Codec c); + static const AVCodec *GetEncoder(ExportCodec::Codec c, AudioParams::Format aformat); AVFormatContext* fmt_ctx_; diff --git a/app/config/config.cpp b/app/config/config.cpp index e5de5fcc8..f52b0c175 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -122,6 +122,11 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("AudioInput"), NodeValue::kText, QString()); SetEntryInternal(QStringLiteral("AudioRecordingFormat"), NodeValue::kInt, ExportFormat::kFormatWAV); + SetEntryInternal(QStringLiteral("AudioRecordingCodec"), NodeValue::kInt, ExportCodec::kCodecPCM); + SetEntryInternal(QStringLiteral("AudioRecordingSampleRate"), NodeValue::kInt, 48000); + SetEntryInternal(QStringLiteral("AudioRecordingChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO); + SetEntryInternal(QStringLiteral("AudioRecordingSampleFormat"), NodeValue::kInt, AudioParams::kFormatSigned16); + SetEntryInternal(QStringLiteral("AudioRecordingBitRate"), NodeValue::kInt, 320); SetEntryInternal(QStringLiteral("DiskCacheBehind"), NodeValue::kRational, QVariant::fromValue(rational(0))); SetEntryInternal(QStringLiteral("DiskCacheAhead"), NodeValue::kRational, QVariant::fromValue(rational(60))); diff --git a/app/config/config.h b/app/config/config.h index 11f466cc3..b5c18e063 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -30,6 +30,8 @@ namespace olive { +#define OLIVE_CONFIG(x) Config::Current()[QStringLiteral(x)] + class Config { public: static Config& Current(); diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index ba5280897..c7a467d5c 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -211,6 +211,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()[QStringLiteral("OnlinePixelFormat")].toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing()); audio_tab_->sample_rate_combobox()->SetSampleRate(ap.sample_rate()); + audio_tab_->sample_format_combobox()->SetSampleFormat(ap.format()); audio_tab_->channel_layout_combobox()->SetChannelLayout(ap.channel_layout()); video_aspect_ratio_ = static_cast(vp.width()) / static_cast(vp.height()); @@ -515,7 +516,7 @@ ExportParams ExportDialog::GenerateParams() const AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(), audio_tab_->channel_layout_combobox()->GetChannelLayout(), - AudioParams::kInternalFormat); + audio_tab_->sample_format_combobox()->GetSampleFormat()); ExportParams params; params.set_encoder(Encoder::GetTypeFromFormat(format_combobox_->GetFormat())); @@ -553,7 +554,7 @@ ExportParams ExportDialog::GenerateParams() const } if (audio_enabled_->isChecked()) { - ExportCodec::Codec audio_codec = static_cast(audio_tab_->codec_combobox()->currentData().toInt()); + ExportCodec::Codec audio_codec = audio_tab_->GetCodec(); params.EnableAudio(audio_render_params, audio_codec); params.set_audio_bit_rate(audio_tab_->bit_rate_slider()->GetValue() * 1000); diff --git a/app/dialog/export/exportaudiotab.cpp b/app/dialog/export/exportaudiotab.cpp index 0db6dd0cd..70ef8d19a 100644 --- a/app/dialog/export/exportaudiotab.cpp +++ b/app/dialog/export/exportaudiotab.cpp @@ -59,7 +59,9 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) : row++; layout->addWidget(new QLabel(tr("Format:")), row, 0); - layout->addWidget(new QComboBox(), row, 1); + + sample_format_combobox_ = new SampleFormatComboBox(); + layout->addWidget(sample_format_combobox_, row, 1); row++; @@ -68,7 +70,7 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) : bit_rate_slider_ = new IntegerSlider(); bit_rate_slider_->SetMinimum(32); bit_rate_slider_->SetMaximum(320); - bit_rate_slider_->SetValue(256); + bit_rate_slider_->SetValue(320); bit_rate_slider_->SetFormat(tr("%1 kbps")); layout->addWidget(bit_rate_slider_, row, 1); @@ -79,9 +81,9 @@ int ExportAudioTab::SetFormat(ExportFormat::Format format) { QList acodecs = ExportFormat::GetAudioCodecs(format); setEnabled(!acodecs.isEmpty()); - codec_combobox()->clear(); + codec_combobox_->clear(); foreach (ExportCodec::Codec acodec, acodecs) { - codec_combobox()->addItem(ExportCodec::GetCodecName(acodec), acodec); + codec_combobox_->addItem(ExportCodec::GetCodecName(acodec), acodec); } return acodecs.size(); } diff --git a/app/dialog/export/exportaudiotab.h b/app/dialog/export/exportaudiotab.h index 4e29e3d48..241db8e8b 100644 --- a/app/dialog/export/exportaudiotab.h +++ b/app/dialog/export/exportaudiotab.h @@ -37,9 +37,19 @@ class ExportAudioTab : public QWidget public: ExportAudioTab(QWidget* parent = nullptr); - QComboBox* codec_combobox() const + ExportCodec::Codec GetCodec() const { - return codec_combobox_; + return static_cast(codec_combobox_->currentData().toInt()); + } + + void SetCodec(ExportCodec::Codec c) + { + for (int i=0; icount(); i++) { + if (codec_combobox_->itemData(i) == c) { + codec_combobox_->setCurrentIndex(i); + break; + } + } } SampleRateComboBox* sample_rate_combobox() const @@ -47,6 +57,11 @@ public: return sample_rate_combobox_; } + SampleFormatComboBox* sample_format_combobox() const + { + return sample_format_combobox_; + } + ChannelLayoutComboBox* channel_layout_combobox() const { return channel_layout_combobox_; @@ -64,6 +79,7 @@ private: QComboBox* codec_combobox_; SampleRateComboBox* sample_rate_combobox_; ChannelLayoutComboBox* channel_layout_combobox_; + SampleFormatComboBox *sample_format_combobox_; IntegerSlider* bit_rate_slider_; }; diff --git a/app/dialog/export/exportformatcombobox.cpp b/app/dialog/export/exportformatcombobox.cpp index 9f1b1927f..c2ca8c453 100644 --- a/app/dialog/export/exportformatcombobox.cpp +++ b/app/dialog/export/exportformatcombobox.cpp @@ -33,12 +33,16 @@ ExportFormatComboBox::ExportFormatComboBox(Mode mode, QWidget *parent) : case kShowAllFormats: break; case kShowAudioOnly: - if (!ExportFormat::GetVideoCodecs(f).isEmpty()) { + if (!ExportFormat::GetVideoCodecs(f).isEmpty() + || !ExportFormat::GetSubtitleCodecs(f).isEmpty() + || ExportFormat::GetAudioCodecs(f).isEmpty()) { continue; } break; case kShowVideoOnly: - if (!ExportFormat::GetAudioCodecs(f).isEmpty()) { + if (ExportFormat::GetVideoCodecs(f).isEmpty() + || !ExportFormat::GetSubtitleCodecs(f).isEmpty() + || !ExportFormat::GetAudioCodecs(f).isEmpty()) { continue; } break; diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index e8371cf9f..8a8b99a83 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -26,8 +26,6 @@ #include "audio/audiomanager.h" #include "config/config.h" -#include "dialog/export/exportaudiotab.h" -#include "dialog/export/exportformatcombobox.h" namespace olive { @@ -99,14 +97,22 @@ PreferencesAudioTab::PreferencesAudioTab() fmt_layout->addWidget(new QLabel(tr("Format:"))); - ExportFormatComboBox *fmt_combo = new ExportFormatComboBox(ExportFormatComboBox::kShowAudioOnly); - fmt_combo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - fmt_layout->addWidget(fmt_combo); + record_format_combo_ = new ExportFormatComboBox(ExportFormatComboBox::kShowAudioOnly); + record_format_combo_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + record_format_combo_->SetFormat(static_cast(OLIVE_CONFIG("AudioRecordingFormat").toInt())); + fmt_layout->addWidget(record_format_combo_); - ExportAudioTab *audio_recording_options = new ExportAudioTab(); - recording_layout->addWidget(audio_recording_options); + record_options_ = new ExportAudioTab(); + record_options_->SetCodec(static_cast(OLIVE_CONFIG("AudioRecordingCodec").toInt())); + record_options_->sample_rate_combobox()->SetSampleRate(OLIVE_CONFIG("AudioRecordingSampleRate").toInt()); + record_options_->channel_layout_combobox()->SetChannelLayout(OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong()); + record_options_->bit_rate_slider()->SetValue(OLIVE_CONFIG("AudioRecordingBitRate").toInt()); + record_options_->sample_format_combobox()->SetSampleFormat(static_cast(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt())); + recording_layout->addWidget(record_options_); - connect(fmt_combo, &ExportFormatComboBox::FormatChanged, audio_recording_options, &ExportAudioTab::SetFormat); + connect(record_format_combo_, &ExportFormatComboBox::FormatChanged, record_options_, &ExportAudioTab::SetFormat); + + record_options_->SetFormat(record_format_combo_->GetFormat()); } QHBoxLayout* refresh_layout = new QHBoxLayout(); @@ -134,12 +140,19 @@ void PreferencesAudioTab::Accept(MultiUndoCommand *command) PaDeviceIndex input_device = audio_input_devices_->currentData().value(); // Get device names, which seem to be the closest thing we have to a "unique identifier" for them - Config::Current()[QStringLiteral("AudioOutput")] = audio_output_devices_->currentText(); - Config::Current()[QStringLiteral("AudioInput")] = audio_input_devices_->currentText(); + OLIVE_CONFIG("AudioOutput") = audio_output_devices_->currentText(); + OLIVE_CONFIG("AudioInput") = audio_input_devices_->currentText(); // Set devices to be used from now on AudioManager::instance()->SetOutputDevice(output_device); AudioManager::instance()->SetInputDevice(input_device); + + OLIVE_CONFIG("AudioRecordingFormat") = record_format_combo_->GetFormat(); + OLIVE_CONFIG("AudioRecordingCodec") = record_options_->GetCodec(); + OLIVE_CONFIG("AudioRecordingSampleRate") = record_options_->sample_rate_combobox()->GetSampleRate(); + OLIVE_CONFIG("AudioRecordingChannelLayout") = QVariant::fromValue(record_options_->channel_layout_combobox()->GetChannelLayout()); + OLIVE_CONFIG("AudioRecordingBitRate") = QVariant::fromValue(record_options_->bit_rate_slider()->GetValue()); + OLIVE_CONFIG("AudioRecordingSampleFormat") = record_options_->sample_format_combobox()->GetSampleFormat(); } void PreferencesAudioTab::RefreshBackends() diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index 38b6138e3..8fccd4276 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -25,6 +25,8 @@ #include #include "dialog/configbase/configdialogbase.h" +#include "dialog/export/exportaudiotab.h" +#include "dialog/export/exportformatcombobox.h" namespace olive { @@ -59,6 +61,10 @@ private: */ QPushButton* refresh_devices_btn_; + ExportFormatComboBox *record_format_combo_; + + ExportAudioTab *record_options_; + private slots: void RefreshBackends(); diff --git a/app/render/audioparams.cpp b/app/render/audioparams.cpp index 24246429b..f90b70aa9 100644 --- a/app/render/audioparams.cpp +++ b/app/render/audioparams.cpp @@ -244,4 +244,34 @@ QString AudioParams::ChannelLayoutToString(const uint64_t &layout) } } +QString AudioParams::FormatToString(const Format &f) +{ + switch (f) { + case kFormatUnsigned8: + return QCoreApplication::translate("AudioParams", "Unsigned 8-bit"); + break; + case kFormatSigned16: + return QCoreApplication::translate("AudioParams", "Signed 16-bit"); + break; + case kFormatSigned32: + return QCoreApplication::translate("AudioParams", "Signed 32-bit"); + break; + case kFormatSigned64: + return QCoreApplication::translate("AudioParams", "Signed 64-bit"); + break; + case kFormatFloat32: + return QCoreApplication::translate("AudioParams", "Float 32-bit"); + break; + case kFormatFloat64: + return QCoreApplication::translate("AudioParams", "Float 64-bit"); + break; + + case kFormatInvalid: + case kFormatCount: + break; + } + + return QCoreApplication::translate("AudioParams", "Unknown (0x%1)").arg(f, 1, 16); +} + } diff --git a/app/render/audioparams.h b/app/render/audioparams.h index bf2e6f08b..cd0fd94b9 100644 --- a/app/render/audioparams.h +++ b/app/render/audioparams.h @@ -200,6 +200,8 @@ public: */ static QString ChannelLayoutToString(const uint64_t &layout); + static QString FormatToString(const Format &f); + private: void set_default_footage_parameters() { diff --git a/app/widget/standardcombos/CMakeLists.txt b/app/widget/standardcombos/CMakeLists.txt index 3784cb136..992a0ef7b 100644 --- a/app/widget/standardcombos/CMakeLists.txt +++ b/app/widget/standardcombos/CMakeLists.txt @@ -21,6 +21,7 @@ set(OLIVE_SOURCES widget/standardcombos/interlacedcombobox.h widget/standardcombos/pixelaspectratiocombobox.h widget/standardcombos/pixelformatcombobox.h + widget/standardcombos/sampleformatcombobox.h widget/standardcombos/sampleratecombobox.h widget/standardcombos/standardcombos.h widget/standardcombos/videodividercombobox.h diff --git a/app/widget/standardcombos/sampleformatcombobox.h b/app/widget/standardcombos/sampleformatcombobox.h new file mode 100644 index 000000000..a1e610f7e --- /dev/null +++ b/app/widget/standardcombos/sampleformatcombobox.h @@ -0,0 +1,64 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef SAMPLEFORMATCOMBOBOX_H +#define SAMPLEFORMATCOMBOBOX_H + +#include + +#include "render/audioparams.h" + +namespace olive { + +class SampleFormatComboBox : public QComboBox +{ + Q_OBJECT +public: + SampleFormatComboBox(QWidget* parent = nullptr) : + QComboBox(parent) + { + // Set up preview formats + for (int i=0;i(i); + + this->addItem(AudioParams::FormatToString(smp_fmt), smp_fmt); + } + } + + AudioParams::Format GetSampleFormat() const + { + return static_cast(this->currentData().toInt()); + } + + void SetSampleFormat(AudioParams::Format fmt) + { + for (int i=0; icount(); i++) { + if (this->itemData(i).toInt() == fmt) { + this->setCurrentIndex(i); + break; + } + } + } + +}; + +} + +#endif // SAMPLEFORMATCOMBOBOX_H diff --git a/app/widget/standardcombos/standardcombos.h b/app/widget/standardcombos/standardcombos.h index 1fe140116..acfffc893 100644 --- a/app/widget/standardcombos/standardcombos.h +++ b/app/widget/standardcombos/standardcombos.h @@ -26,6 +26,7 @@ #include "interlacedcombobox.h" #include "pixelaspectratiocombobox.h" #include "pixelformatcombobox.h" +#include "sampleformatcombobox.h" #include "sampleratecombobox.h" #include "videodividercombobox.h" diff --git a/app/widget/timelinewidget/tool/record.cpp b/app/widget/timelinewidget/tool/record.cpp index c8a7fc001..46125902f 100644 --- a/app/widget/timelinewidget/tool/record.cpp +++ b/app/widget/timelinewidget/tool/record.cpp @@ -21,7 +21,7 @@ void RecordTool::MousePress(TimelineViewMouseEvent *event) return; } - if (t->type() != Track::kAudio) { + if (t && t->type() != Track::kAudio) { // We only support audio tracks here return; } diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 9caee2a3e..f8b25247a 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1183,7 +1183,14 @@ void ViewerWidget::Play(bool in_to_out_only) ExportFormat::GetExtension(static_cast(Config::Current()[QStringLiteral("AudioRecordingFormat")].toInt()))) ); - if (AudioManager::instance()->StartRecording(recording_filename_, GetConnectedNode()->GetAudioParams())) { + AudioParams ap(OLIVE_CONFIG("AudioRecordingSampleRate").toInt(), OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong(), static_cast(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt())); + + EncodingParams encode_param; + encode_param.EnableAudio(ap, static_cast(OLIVE_CONFIG("AudioRecordingCodec").toInt())); + encode_param.SetFilename(recording_filename_); + encode_param.set_audio_bit_rate(OLIVE_CONFIG("AudioRecordingBitRate").toInt() * 1000); + + if (AudioManager::instance()->StartRecording(encode_param)) { recording_ = true; controls_->SetPauseButtonRecordingState(true); recording_callback_->EnableRecordingOverlay(TimelineCoordinate(recording_range_.in(), recording_track_));