added in-timeline recording
This commit is contained in:
@@ -371,6 +371,8 @@ void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetI
|
||||
QVector<bool> image_sequence_importassequence;
|
||||
QStringList image_sequence_formats = config.img_seq_formats.split("|");
|
||||
|
||||
if (!recursive) last_imported_media.clear();
|
||||
|
||||
bool create_undo_action = (!recursive && replace == NULL);
|
||||
ComboAction* ca;
|
||||
if (create_undo_action) ca = new ComboAction();
|
||||
@@ -494,6 +496,8 @@ void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetI
|
||||
|
||||
set_footage_of_tree(item, m);
|
||||
|
||||
last_imported_media.append(m);
|
||||
|
||||
if (replace == NULL) {
|
||||
if (create_undo_action) {
|
||||
ca->append(new AddMediaCommand(item, parent));
|
||||
|
||||
@@ -68,6 +68,8 @@ public:
|
||||
QVector<Sequence*> list_all_project_sequences();
|
||||
|
||||
SourceTable* source_table;
|
||||
|
||||
QVector<Media*> last_imported_media;
|
||||
public slots:
|
||||
void import_dialog();
|
||||
void delete_selected_media();
|
||||
|
||||
+5
-5
@@ -94,9 +94,7 @@ Timeline::Timeline(QWidget *parent) :
|
||||
connect(ui->videoScrollbar, SIGNAL(valueChanged(int)), ui->video_area, SLOT(setScroll(int)));
|
||||
connect(ui->audioScrollbar, SIGNAL(valueChanged(int)), ui->audio_area, SLOT(setScroll(int)));
|
||||
|
||||
update_sequence();
|
||||
|
||||
ui->recordButton->setVisible(false);
|
||||
update_sequence();
|
||||
}
|
||||
|
||||
Timeline::~Timeline()
|
||||
@@ -1147,7 +1145,7 @@ void Timeline::on_addButton_clicked() {
|
||||
|
||||
void Timeline::addMenuItem(QAction* action) {
|
||||
creating = true;
|
||||
creatingObject = action->data().toInt();
|
||||
creating_object = action->data().toInt();
|
||||
}
|
||||
|
||||
void Timeline::setScroll(int s) {
|
||||
@@ -1157,5 +1155,7 @@ void Timeline::setScroll(int s) {
|
||||
}
|
||||
|
||||
void Timeline::on_recordButton_clicked() {
|
||||
qDebug() << "recording is a" << start_recording();
|
||||
creating = true;
|
||||
creating_object = ADD_OBJ_AUDIO;
|
||||
//qDebug() << "recording is a" << start_recording();
|
||||
}
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@
|
||||
#define ADD_OBJ_BARS 2
|
||||
#define ADD_OBJ_TONE 3
|
||||
#define ADD_OBJ_NOISE 4
|
||||
#define ADD_OBJ_AUDIO 5
|
||||
|
||||
class QPushButton;
|
||||
class SourceTable;
|
||||
@@ -160,7 +161,7 @@ public:
|
||||
|
||||
// creating variables
|
||||
bool creating;
|
||||
int creatingObject;
|
||||
int creating_object;
|
||||
|
||||
Ui::Timeline *ui;
|
||||
public slots:
|
||||
|
||||
+68
-2
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "playback/audio.h"
|
||||
#include "timeline.h"
|
||||
#include "panels/project.h"
|
||||
#include "project/sequence.h"
|
||||
#include "panels/panels.h"
|
||||
#include "io/config.h"
|
||||
@@ -25,13 +26,15 @@ extern "C" {
|
||||
#include <QAudioOutput>
|
||||
#include <QPainter>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
Viewer::Viewer(QWidget *parent) :
|
||||
QDockWidget(parent),
|
||||
ui(new Ui::Viewer),
|
||||
seq(NULL),
|
||||
playing(false),
|
||||
created_sequence(false)
|
||||
created_sequence(false),
|
||||
cue_recording_internal(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->headers->viewer = this;
|
||||
@@ -49,7 +52,10 @@ Viewer::Viewer(QWidget *parent) :
|
||||
ui->currentTimecode->set_display_type(LABELSLIDER_FRAMENUMBER);
|
||||
connect(ui->currentTimecode, SIGNAL(valueChanged()), this, SLOT(update_playhead()));
|
||||
|
||||
recording_flasher.setInterval(500);
|
||||
|
||||
connect(&playback_updater, SIGNAL(timeout()), this, SLOT(timer_update()));
|
||||
connect(&recording_flasher, SIGNAL(timeout()), this, SLOT(recording_flasher_update()));
|
||||
|
||||
update_playhead_timecode(0);
|
||||
update_end_timecode();
|
||||
@@ -231,6 +237,25 @@ void Viewer::go_to_end() {
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::cue_recording(long start, long end, int track) {
|
||||
recording_start = start;
|
||||
recording_end = end;
|
||||
recording_track = track;
|
||||
panel_sequence_viewer->seek(recording_start);
|
||||
cue_recording_internal = true;
|
||||
recording_flasher.start();
|
||||
}
|
||||
|
||||
void Viewer::uncue_recording() {
|
||||
cue_recording_internal = false;
|
||||
recording_flasher.stop();
|
||||
ui->pushButton_3->setStyleSheet(QString());
|
||||
}
|
||||
|
||||
bool Viewer::is_recording_cued() {
|
||||
return cue_recording_internal;
|
||||
}
|
||||
|
||||
void Viewer::toggle_play() {
|
||||
if (playing) {
|
||||
pause();
|
||||
@@ -249,6 +274,10 @@ void Viewer::play() {
|
||||
|| audio_output->format().channelCount() != av_get_channel_layout_nb_channels(seq->audio_layout)) {
|
||||
init_audio(seq);
|
||||
}
|
||||
if (is_recording_cued() && !start_recording()) {
|
||||
qDebug() << "[ERROR] Failed to record audio";
|
||||
return;
|
||||
}
|
||||
playhead_start = seq->playhead;
|
||||
start_msecs = QDateTime::currentMSecsSinceEpoch();
|
||||
playing = true;
|
||||
@@ -263,7 +292,36 @@ void Viewer::pause() {
|
||||
playing = false;
|
||||
set_playpause_icon(true);
|
||||
playback_updater.stop();
|
||||
stop_recording();
|
||||
|
||||
if (is_recording_cued()) {
|
||||
uncue_recording();
|
||||
|
||||
if (recording) {
|
||||
stop_recording();
|
||||
|
||||
// import audio
|
||||
panel_project->process_file_list(false, QStringList(get_recorded_audio_filename()), NULL, NULL);
|
||||
|
||||
// add it to the sequence
|
||||
Clip* c = new Clip(seq);
|
||||
Media* m = panel_project->last_imported_media.at(0);
|
||||
c->media = m; // latest media
|
||||
c->media_type = MEDIA_TYPE_FOOTAGE;
|
||||
c->media_stream = 0;
|
||||
c->timeline_in = recording_start;
|
||||
c->timeline_out = seq->playhead;
|
||||
c->clip_in = 0;
|
||||
c->track = recording_track;
|
||||
c->color_r = 128;
|
||||
c->color_g = 192;
|
||||
c->color_b = 128;
|
||||
c->name = m->name;
|
||||
|
||||
QVector<Clip*> add_clips;
|
||||
add_clips.append(c);
|
||||
undo_stack.push(new AddClipCommand(seq, add_clips)); // add clip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::update_playhead_timecode(long p) {
|
||||
@@ -417,6 +475,14 @@ void Viewer::timer_update() {
|
||||
update_parents();
|
||||
}
|
||||
|
||||
void Viewer::recording_flasher_update() {
|
||||
if (ui->pushButton_3->styleSheet().isEmpty()) {
|
||||
ui->pushButton_3->setStyleSheet("background: red;");
|
||||
} else {
|
||||
ui->pushButton_3->setStyleSheet(QString());
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::clean_created_seq() {
|
||||
viewer_widget->waveform = false;
|
||||
|
||||
|
||||
@@ -51,6 +51,13 @@ public:
|
||||
qint64 start_msecs;
|
||||
QTimer playback_updater;
|
||||
|
||||
void cue_recording(long start, long end, int track);
|
||||
void uncue_recording();
|
||||
bool is_recording_cued();
|
||||
long recording_start;
|
||||
long recording_end;
|
||||
int recording_track;
|
||||
|
||||
void reset_all_audio();
|
||||
void update_parents();
|
||||
|
||||
@@ -70,11 +77,15 @@ private slots:
|
||||
void on_pushButton_3_clicked();
|
||||
void update_playhead();
|
||||
void timer_update();
|
||||
void recording_flasher_update();
|
||||
private:
|
||||
void clean_created_seq();
|
||||
void set_sequence(bool main, Sequence* s);
|
||||
bool main_sequence;
|
||||
bool created_sequence;
|
||||
|
||||
bool cue_recording_internal;
|
||||
QTimer recording_flasher;
|
||||
};
|
||||
|
||||
#endif // VIEWER_H
|
||||
|
||||
+23
-6
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "project/sequence.h"
|
||||
|
||||
#include "panels/project.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/viewer.h"
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <QAudioInput>
|
||||
#include <QtMath>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
extern "C" {
|
||||
@@ -263,7 +265,22 @@ bool start_recording() {
|
||||
qDebug() << "[ERROR] No active sequence to record into";
|
||||
return false;
|
||||
}
|
||||
output_recording.setFileName("C:/Users/Matt/output.wav");
|
||||
|
||||
QString audio_path = project_url + " Audio";
|
||||
QDir audio_dir(audio_path);
|
||||
if (!audio_dir.exists() && !audio_dir.mkpath(".")) {
|
||||
qDebug() << "[ERROR] Failed to create audio directory";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString audio_filename;
|
||||
int file_number = 0;
|
||||
do {
|
||||
file_number++;
|
||||
audio_filename = audio_path + "/Recording " + QString::number(file_number) + ".wav";
|
||||
} while (QFile(audio_filename).exists());
|
||||
|
||||
output_recording.setFileName(audio_filename);
|
||||
if (!output_recording.open(QFile::WriteOnly)) {
|
||||
qDebug() << "[ERROR] Failed to open output file. Does Olive have permission to write to this directory?";
|
||||
return false;
|
||||
@@ -287,16 +304,16 @@ void stop_recording() {
|
||||
if (recording) {
|
||||
audio_input->stop();
|
||||
|
||||
/*if (audio_input->state() == QAudio::ActiveState) {
|
||||
|
||||
}*/
|
||||
|
||||
write_wave_trailer(output_recording);
|
||||
|
||||
output_recording.close();
|
||||
|
||||
delete audio_input;
|
||||
audio_input = NULL;
|
||||
recording = false;
|
||||
}
|
||||
recording = false;
|
||||
}
|
||||
|
||||
const QString& get_recorded_audio_filename() {
|
||||
return output_recording.fileName();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ int get_buffer_offset_from_frame(Sequence *s, long frame);
|
||||
|
||||
bool start_recording();
|
||||
void stop_recording();
|
||||
const QString& get_recorded_audio_filename();
|
||||
extern bool recording;
|
||||
|
||||
#endif // AUDIO_H
|
||||
|
||||
+3
-3
@@ -293,14 +293,13 @@ void cache_audio_worker(Clip* c, Clip* nest) {
|
||||
break;
|
||||
case MEDIA_TYPE_TONE:
|
||||
frame = c->frame;
|
||||
nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1);
|
||||
if (c->frame_sample_index < 0 || c->frame_sample_index >= nb_bytes) {
|
||||
nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->channels;
|
||||
while ((c->frame_sample_index == -1 || c->frame_sample_index >= nb_bytes) && nb_bytes > 0) {
|
||||
// create "new frame"
|
||||
memset(c->frame->data[0], 0, nb_bytes);
|
||||
apply_audio_effects(c, bytes_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_bytes);
|
||||
c->frame->pts += nb_bytes;
|
||||
c->frame_sample_index = 0;
|
||||
qDebug() << "2 >> c->audio_target_frame:" << c->audio_target_frame;
|
||||
if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(c->sequence, qMax(timeline_in, c->audio_target_frame));
|
||||
int offset = audio_ibuffer_read - c->audio_buffer_write;
|
||||
if (offset > 0) {
|
||||
@@ -546,6 +545,7 @@ void reset_cache(Clip* c, long target_frame) {
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_TONE:
|
||||
c->reached_end = false;
|
||||
c->audio_target_frame = target_frame;
|
||||
c->frame_sample_index = -1;
|
||||
c->frame->pts = 0;
|
||||
|
||||
+50
-6
@@ -1,5 +1,6 @@
|
||||
#include "timelinewidget.h"
|
||||
|
||||
#include "playback/audio.h"
|
||||
#include "panels/panels.h"
|
||||
#include "io/config.h"
|
||||
#include "project/sequence.h"
|
||||
@@ -60,8 +61,6 @@ void TimelineWidget::right_click_ripple() {
|
||||
s.out = rc_ripple_max;
|
||||
s.track = panel_timeline->cursor_track;
|
||||
|
||||
qDebug() << s.in << s.out << s.track;
|
||||
|
||||
sels.append(s);
|
||||
|
||||
panel_timeline->delete_selection(sels, true);
|
||||
@@ -700,7 +699,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
|
||||
if (panel_timeline->creating) {
|
||||
int comp = 0;
|
||||
switch (panel_timeline->creatingObject) {
|
||||
switch (panel_timeline->creating_object) {
|
||||
case ADD_OBJ_TITLE:
|
||||
case ADD_OBJ_SOLID:
|
||||
case ADD_OBJ_BARS:
|
||||
@@ -708,6 +707,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
break;
|
||||
case ADD_OBJ_TONE:
|
||||
case ADD_OBJ_NOISE:
|
||||
case ADD_OBJ_AUDIO:
|
||||
comp = 1;
|
||||
break;
|
||||
}
|
||||
@@ -857,7 +857,10 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
if (panel_timeline->ghosts.size() > 0) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(0);
|
||||
|
||||
if (g.in != g.out) {
|
||||
if (panel_timeline->creating_object == ADD_OBJ_AUDIO) {
|
||||
panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track);
|
||||
panel_timeline->creating = false;
|
||||
} else if (g.in != g.out) {
|
||||
Clip* c = new Clip(sequence);
|
||||
c->media = NULL;
|
||||
c->timeline_in = qMin(g.in, g.out);
|
||||
@@ -878,7 +881,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
c->media_type = MEDIA_TYPE_SOLID;
|
||||
}
|
||||
|
||||
switch (panel_timeline->creatingObject) {
|
||||
switch (panel_timeline->creating_object) {
|
||||
case ADD_OBJ_TITLE:
|
||||
c->name = "Title";
|
||||
c->effects.append(create_effect(VIDEO_TEXT_EFFECT, c));
|
||||
@@ -2004,7 +2007,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
|
||||
for (int i=0;i<sequence->clips.size();i++) {
|
||||
Clip* clip = sequence->clips.at(i);
|
||||
if (clip != NULL && is_track_visible(clip->track)) {
|
||||
QRect clip_rect(panel_timeline->getTimelineScreenPointFromFrame(clip->timeline_in), getScreenPointFromTrack(clip->track), clip->getLength() * panel_timeline->zoom, panel_timeline->calculate_track_height(clip->track, -1));
|
||||
QRect clip_rect(panel_timeline->getTimelineScreenPointFromFrame(clip->timeline_in), getScreenPointFromTrack(clip->track), getScreenPointFromFrame(panel_timeline->zoom, clip->getLength()), panel_timeline->calculate_track_height(clip->track, -1));
|
||||
QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - 1, clip_rect.height() - CLIP_TEXT_PADDING - 1);
|
||||
if (clip_rect.left() < width() && clip_rect.right() >= 0 && clip_rect.top() < height() && clip_rect.bottom() >= 0) {
|
||||
QRect actual_clip_rect = clip_rect;
|
||||
@@ -2202,6 +2205,47 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
|
||||
}
|
||||
}
|
||||
|
||||
// Draw recording clip if recording if valid
|
||||
if (panel_sequence_viewer->is_recording_cued() && is_track_visible(panel_sequence_viewer->recording_track)) {
|
||||
int rec_track_x = panel_timeline->getTimelineScreenPointFromFrame(panel_sequence_viewer->recording_start);
|
||||
int rec_track_y = getScreenPointFromTrack(panel_sequence_viewer->recording_track);
|
||||
int rec_track_height = panel_timeline->calculate_track_height(panel_sequence_viewer->recording_track, -1);
|
||||
if (panel_sequence_viewer->recording_start != panel_sequence_viewer->recording_end) {
|
||||
QRect rec_rect(
|
||||
rec_track_x,
|
||||
rec_track_y,
|
||||
getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->recording_end - panel_sequence_viewer->recording_start),
|
||||
rec_track_height
|
||||
);
|
||||
p.setPen(QPen(QColor(96, 96, 96), 2));
|
||||
p.fillRect(rec_rect, QColor(192, 192, 192));
|
||||
p.drawRect(rec_rect);
|
||||
}
|
||||
QRect active_rec_rect(
|
||||
rec_track_x,
|
||||
rec_track_y,
|
||||
getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->seq->playhead - panel_sequence_viewer->recording_start),
|
||||
rec_track_height
|
||||
);
|
||||
p.setPen(QPen(QColor(192, 0, 0), 2));
|
||||
p.fillRect(active_rec_rect, QColor(255, 96, 96));
|
||||
p.drawRect(active_rec_rect);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
if (!panel_sequence_viewer->playing) {
|
||||
int rec_marker_size = 8;
|
||||
int rec_track_midY = rec_track_y + (rec_track_height >> 1);
|
||||
p.setBrush(Qt::white);
|
||||
QPoint cue_marker[3] = {
|
||||
QPoint(rec_track_x, rec_track_midY - rec_marker_size),
|
||||
QPoint(rec_track_x + rec_marker_size, rec_track_midY),
|
||||
QPoint(rec_track_x, rec_track_midY + rec_marker_size)
|
||||
};
|
||||
p.drawPolygon(cue_marker, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw track lines
|
||||
if (config.show_track_lines) {
|
||||
p.setPen(QColor(0, 0, 0, 96));
|
||||
|
||||
@@ -529,9 +529,12 @@ void ViewerWidget::paintGL() {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
} while (loop);
|
||||
|
||||
// TODO this could be cleaned up but it's not a priority rn
|
||||
if (!recording
|
||||
&& viewer->playing
|
||||
&& (viewer->seq->playhead == viewer->seq->getEndFrame() || (viewer->seq->using_workarea && viewer->seq->playhead >= viewer->seq->workarea_out))) {
|
||||
viewer->pause();
|
||||
} else if (recording && viewer->recording_start != viewer->recording_end && viewer->seq->playhead >= viewer->recording_end) {
|
||||
viewer->pause();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user