diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 2b5ed4bc1..91e34731d 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -23,6 +23,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) : { ui->setupUi(this); + ui->recordingComboBox->setCurrentIndex(config.recording_mode - 1); ui->imgSeqFormatEdit->setText(config.img_seq_formats); } @@ -75,5 +76,6 @@ void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) { } void PreferencesDialog::on_buttonBox_accepted() { + config.recording_mode = ui->recordingComboBox->currentIndex() + 1; config.img_seq_formats = ui->imgSeqFormatEdit->text(); } diff --git a/dialogs/preferencesdialog.ui b/dialogs/preferencesdialog.ui index d1f64b022..54344dd23 100644 --- a/dialogs/preferencesdialog.ui +++ b/dialogs/preferencesdialog.ui @@ -17,7 +17,7 @@ - 2 + 0 @@ -34,6 +34,27 @@ + + + + Audio Recording: + + + + + + + + Mono + + + + + Stereo + + + + diff --git a/io/config.cpp b/io/config.cpp index 8d02efba8..11ca5add9 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -23,7 +23,8 @@ Config::Config() use_custom_title_safe_ratio(false), custom_title_safe_ratio(1), enable_drag_files_to_timeline(false), - autoscale_by_default(false) + autoscale_by_default(false), + recording_mode(2) {} void Config::load(QString path) { @@ -81,8 +82,11 @@ void Config::load(QString path) { enable_drag_files_to_timeline = (stream.text() == "1");; } else if (stream.name() == "AutoscaleByDefault") { stream.readNext(); - autoscale_by_default = (stream.text() == "1");; - } + autoscale_by_default = (stream.text() == "1"); + } else if (stream.name() == "RecordingMode") { + stream.readNext(); + recording_mode = stream.text().toInt(); + } } } if (stream.hasError()) { @@ -90,29 +94,7 @@ void Config::load(QString path) { } f.close(); - } - /*if (!custom_scale) { - #ifdef _WIN32 - // Get Windows UI scale - TODO may not be compatible with XP - HDC screen = GetDC(0); - int dpiX = GetDeviceCaps (screen, LOGPIXELSX); - //int dpiY = GetDeviceCaps (screen, LOGPIXELSY); - - scale = (float) dpiX / 96; - - ReleaseDC (0, screen); - #endif - }*/ - -// padding *= scale; - - /*DIR* dir = opendir("conf"); - if (dir) { - closedir(dir); - } else if (ENOENT == errno) { - // no config directory, assume this is the first time opening Olive - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "INFO", "NOTE: This version of Olive is INCOMPLETE and very likely to crash. It comes with NO WARRANTY or guarantee of functionality.\n\nRegardless, thanks for checking out the project and I hope you enjoy using it!", NULL); - }*/ + } } void Config::save(QString path) { @@ -144,14 +126,9 @@ void Config::save(QString path) { stream.writeTextElement("CustomTitleSafeRatio", QString::number(custom_title_safe_ratio)); stream.writeTextElement("EnableDragFilesToTimeline", QString::number(enable_drag_files_to_timeline)); stream.writeTextElement("AutoscaleByDefault", QString::number(autoscale_by_default)); + stream.writeTextElement("RecordingMode", QString::number(recording_mode)); - stream.writeEndElement(); + stream.writeEndElement(); // configuration stream.writeEndDocument(); // doc - f.close(); - /*#ifdef _WIN32 - _mkdir("conf"); - #else - mkdir("conf", 0777); - #endif*/ - + f.close(); } diff --git a/io/config.h b/io/config.h index 941793e5e..5531f9672 100644 --- a/io/config.h +++ b/io/config.h @@ -9,6 +9,9 @@ #define TIMECODE_NONDROP 1 #define TIMECODE_FRAMES 2 +#define RECORD_MODE_MONO 1 +#define RECORD_MODE_STEREO 2 + struct Config { Config(); bool saved_layout; @@ -27,6 +30,7 @@ struct Config { double custom_title_safe_ratio; bool enable_drag_files_to_timeline; bool autoscale_by_default; + int recording_mode; void load(QString path); void save(QString path); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index a7c024247..97d311185 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -25,6 +25,7 @@ #include #include #include +#include long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) { if (source_frame_rate == target_frame_rate) return framenumber; @@ -1155,7 +1156,10 @@ void Timeline::setScroll(int s) { } void Timeline::on_recordButton_clicked() { - creating = true; - creating_object = ADD_OBJ_AUDIO; - //qDebug() << "recording is a" << start_recording(); + if (project_url.isEmpty()) { + QMessageBox::critical(this, "Unsaved Project", "You must save this project before you can record audio in it.", QMessageBox::Ok); + } else { + creating = true; + creating_object = ADD_OBJ_AUDIO; + } } diff --git a/playback/audio.cpp b/playback/audio.cpp index 1a59643ca..0480eb576 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -2,6 +2,7 @@ #include "project/sequence.h" +#include "io/config.h" #include "panels/project.h" #include "panels/panels.h" #include "panels/timeline.h" @@ -211,9 +212,10 @@ void write_wave_header(QFile& f, const QAudioFormat& format) { f.putChar(1); f.putChar(0); - // 2 byte channel count (2 for stereo) - f.putChar(2); - f.putChar(0); + // 2 byte channel count + int32bit = format.channelCount(); + int32_to_char_array(int32bit, arr); + f.write(arr, 2); // 4 byte integer for sample rate int32bit = format.sampleRate(); @@ -287,6 +289,9 @@ bool start_recording() { } QAudioFormat audio_format = audio_output->format(); + if (config.recording_mode != audio_format.channelCount()) { + audio_format.setChannelCount(config.recording_mode); + } QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice(); if (!info.isFormatSupported(audio_format)) { qDebug() << "[WARNING] Default format not supported, using nearest"; diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 5a04af50e..c5719949e 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -183,7 +183,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { if ((c->frame->pts >= c->reverse_target) || (ret == AVERROR_EOF)) { /*qDebug() << "time for the end of rev cache" << rev_frame->nb_samples << c->rev_target << c->frame->pts << c->frame->pkt_duration << c->frame->nb_samples; qDebug() << "diff:" << (c->frame->pkt_pts + c->frame->pkt_duration) - c->rev_target; - int cutoff = qRound ((((c->frame->pkt_pts + c->frame->pkt_duration) - c->rev_target) * timebase) * c->sequence->audio_frequency); + int cutoff = qRound64 ((((c->frame->pkt_pts + c->frame->pkt_duration) - c->rev_target) * timebase) * c->sequence->audio_frequency); if (cutoff > 0) { qDebug() << "cut off" << cutoff << "samples (rate:" << c->sequence->audio_frequency << ")"; rev_frame->nb_samples -= cutoff; @@ -192,7 +192,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { #ifdef AUDIOWARNINGS qDebug() << "pre cutoff deets::: rev_frame.pts:" << rev_frame->pts << "rev_frame.nb_samples" << rev_frame->nb_samples << "rev_target:" << c->reverse_target; #endif - rev_frame->nb_samples = qRound(static_cast(c->reverse_target - rev_frame->pts) / c->stream->codecpar->sample_rate * c->sequence->audio_frequency); + rev_frame->nb_samples = qRound64(static_cast(c->reverse_target - rev_frame->pts) / c->stream->codecpar->sample_rate * c->sequence->audio_frequency); #ifdef AUDIOWARNINGS qDebug() << "post cutoff deets::" << rev_frame->nb_samples; #endif @@ -250,7 +250,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { // get precise sample offset for the elected clip_in from this audio frame double target_sts = playhead_to_clip_seconds(c, c->audio_target_frame); double frame_sts = ((frame->pts - c->stream->start_time) * timebase); - int nb_samples = qRound((target_sts - frame_sts)*c->sequence->audio_frequency); + int nb_samples = qRound64((target_sts - frame_sts)*c->sequence->audio_frequency); c->frame_sample_index = nb_samples * 4; #ifdef AUDIOWARNINGS qDebug() << "fsts:" << frame_sts << "tsts:" << target_sts << "nbs:" << nb_samples << "nbb:" << nb_bytes << "rev_targetToSec:" << (c->reverse_target * timebase); @@ -379,7 +379,7 @@ void cache_video_worker(Clip* c, long playhead) { int64_t eighth_second = av_q2d(av_inv_q(c->stream->time_base))*0.125; int64_t smallest_pts = INT64_MAX; if (c->reverse && c->queue.size() > 0) { - int64_t quarter_sec = qRound(av_q2d(av_inv_q(c->stream->time_base))) >> 2; + int64_t quarter_sec = qRound64(av_q2d(av_inv_q(c->stream->time_base))) >> 2; for (int i=0;iqueue.size();i++) { smallest_pts = qMin(smallest_pts, c->queue.at(i)->pts); } @@ -489,7 +489,7 @@ void reset_cache(Clip* c, long target_frame) { // seeks to nearest keyframe (target_frame represents internal clip frame) int64_t target_ts = seconds_to_timestamp(c, playhead_to_clip_seconds(c, target_frame)); int64_t seek_ts = target_ts; - int64_t timebase_half_second = qRound(av_q2d(av_inv_q(c->stream->time_base))); + int64_t timebase_half_second = qRound64(av_q2d(av_inv_q(c->stream->time_base))); if (c->reverse) seek_ts -= timebase_half_second; while (true) { @@ -527,6 +527,7 @@ void reset_cache(Clip* c, long target_frame) { // seek (target_frame represents timeline timecode in frames, not clip timecode) int64_t timestamp = seconds_to_timestamp(c, playhead_to_clip_seconds(c, target_frame)); + if (c->reverse) { c->reverse_target = timestamp; timestamp -= av_q2d(av_inv_q(c->stream->time_base)); @@ -725,7 +726,7 @@ void open_clip_worker(Clip* clip) { avfilter_link(clip->buffersrc_ctx, 0, tempo_filter, 0); avfilter_link(tempo_filter, 0, clip->buffersink_ctx, 0); } else { - target_sample_rate = qRound(clip->sequence->audio_frequency / clip->speed); + target_sample_rate = qRound64(clip->sequence->audio_frequency / clip->speed); avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0); } diff --git a/playback/playback.cpp b/playback/playback.cpp index 555eba800..fe7c6e294 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -114,7 +114,7 @@ void get_clip_frame(Clip* c, long playhead) { MediaStream* ms = static_cast(c->media)->get_stream_from_file_index(c->track < 0, c->media_stream); int64_t target_pts = playhead_to_timestamp(c, playhead); - int64_t second_pts = qRound(av_q2d(av_inv_q(c->stream->time_base))); + int64_t second_pts = qRound64(av_q2d(av_inv_q(c->stream->time_base))); int64_t quarter_pts = second_pts >> 2; if (ms->video_interlacing != VIDEO_PROGRESSIVE) { target_pts *= 2; @@ -231,7 +231,7 @@ double playhead_to_clip_seconds(Clip* c, long playhead) { } int64_t seconds_to_timestamp(Clip* c, double seconds) { - return qRound((seconds * c->stream->time_base.den)/c->stream->time_base.num) + c->stream->start_time; + return qRound64(seconds * av_q2d(av_inv_q(c->stream->time_base))) + qMax((int64_t) 0, c->stream->start_time); } int64_t playhead_to_timestamp(Clip* c, long playhead) { diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 746e23440..f441858ba 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -2234,7 +2234,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { p.setPen(Qt::NoPen); if (!panel_sequence_viewer->playing) { - int rec_marker_size = 8; + int rec_marker_size = 6; int rec_track_midY = rec_track_y + (rec_track_height >> 1); p.setBrush(Qt::white); QPoint cue_marker[3] = {