added in-timeline recording

This commit is contained in:
itsmattkc
2018-10-26 20:02:48 +11:00
parent 269d7153df
commit d4692b9480
11 changed files with 172 additions and 23 deletions
+4
View File
@@ -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));
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+11
View File
@@ -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
View File
@@ -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();
}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+3
View File
@@ -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();
}
}