Commit 1636b02e authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle

Merge branch '1904'

parents 3911d1a5 ac43da1c
......@@ -169,7 +169,7 @@ public:
/** @brief Sets a new description. */
virtual void setDescription(const QString &description);
virtual QDomElement toXml(QDomDocument &document, bool includeMeta = false) = 0;
virtual QDomElement toXml(QDomDocument &document, bool includeMeta = false, bool includeProfile = true) = 0;
virtual QString getToolTip() const = 0;
virtual bool rename(const QString &name, int column) = 0;
......
......@@ -2951,10 +2951,12 @@ void Bin::reloadAllProducers()
emit openClip(std::shared_ptr<ProjectClip>());
for (const std::shared_ptr<ProjectClip> &clip : clipList) {
QDomDocument doc;
QDomElement xml = clip->toXml(doc);
QDomElement xml = clip->toXml(doc, false, false);
// Make sure we reload clip length
xml.removeAttribute(QStringLiteral("out"));
Xml::removeXmlProperty(xml, QStringLiteral("length"));
clip->resetProducerProperty(QStringLiteral("kdenlive:duration"));
clip->resetProducerProperty(QStringLiteral("length"));
if (!xml.isNull()) {
clip->setClipStatus(AbstractProjectItem::StatusWaiting);
clip->discardAudioThumb();
......
......@@ -340,9 +340,9 @@ void ProjectClip::reloadProducer(bool refreshOnly, bool audioStreamChanged)
}
}
QDomElement ProjectClip::toXml(QDomDocument &document, bool includeMeta)
QDomElement ProjectClip::toXml(QDomDocument &document, bool includeMeta, bool includeProfile)
{
getProducerXML(document, includeMeta);
getProducerXML(document, includeMeta, includeProfile);
QDomElement prod = document.documentElement().firstChildElement(QStringLiteral("producer"));
if (m_clipType != ClipType::Unknown) {
prod.setAttribute(QStringLiteral("type"), (int)m_clipType);
......
......@@ -132,7 +132,7 @@ public:
bool rename(const QString &name, int column) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false, bool includeProfile = true) override;
QVariant getData(DataType type) const override;
......
......@@ -144,7 +144,7 @@ void ProjectFolder::setBinEffectsEnabled(bool enabled)
}
}
QDomElement ProjectFolder::toXml(QDomDocument &document, bool)
QDomElement ProjectFolder::toXml(QDomDocument &document, bool, bool)
{
QDomElement folder = document.createElement(QStringLiteral("folder"));
folder.setAttribute(QStringLiteral("name"), name());
......
......@@ -77,7 +77,7 @@ public:
std::shared_ptr<ProjectClip> clipAt(int index) override;
/** @brief Returns an xml description of the folder. */
QDomElement toXml(QDomDocument &document, bool includeMeta = false) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false, bool includeProfile = true) override;
QString getToolTip() const override;
bool rename(const QString &name, int column) override;
/** @brief Returns a list of all children and sub-children clips. */
......
......@@ -67,7 +67,7 @@ std::shared_ptr<ProjectClip> ProjectFolderUp::clipAt(int index)
void ProjectFolderUp::setBinEffectsEnabled(bool) {}
QDomElement ProjectFolderUp::toXml(QDomDocument &document, bool)
QDomElement ProjectFolderUp::toXml(QDomDocument &document, bool, bool)
{
return document.documentElement();
}
......
......@@ -70,7 +70,7 @@ public:
void setBinEffectsEnabled(bool enabled) override;
/** @brief Returns an xml description of the folder. */
QDomElement toXml(QDomDocument &document, bool includeMeta = false) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false, bool includeProfile = true) override;
QString getToolTip() const override;
bool rename(const QString &name, int column) override;
ClipType::ProducerType clipType() const override;
......
......@@ -116,7 +116,7 @@ std::shared_ptr<ProjectClip> ProjectSubClip::clipAt(int ix)
return std::shared_ptr<ProjectClip>();
}
QDomElement ProjectSubClip::toXml(QDomDocument &document, bool)
QDomElement ProjectSubClip::toXml(QDomDocument &document, bool, bool)
{
QDomElement sub = document.createElement(QStringLiteral("subclip"));
sub.setAttribute(QStringLiteral("id"), m_masterClip->AbstractProjectItem::clipId());
......
......@@ -65,7 +65,7 @@ public:
std::shared_ptr<ProjectClip> clipAt(int ix) override;
/** @brief Recursively disable/enable bin effects. */
void setBinEffectsEnabled(bool enabled) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false) override;
QDomElement toXml(QDomDocument &document, bool includeMeta = false, bool includeProfile = true) override;
/** @brief Returns the clip's duration. */
GenTime duration() const;
......
......@@ -37,6 +37,9 @@ MediaCapture::MediaCapture(QObject *parent)
{
m_probe = std::make_unique<QAudioProbe>(this);
connect(m_probe.get(), &QAudioProbe::audioBufferProbed, this, &MediaCapture::processBuffer);
m_resetTimer.setInterval(5000);
m_resetTimer.setSingleShot(true);
connect(&m_resetTimer, &QTimer::timeout, this, &MediaCapture::resetIfUnused);
}
MediaCapture::~MediaCapture() = default;
......@@ -46,13 +49,29 @@ void MediaCapture::displayErrorMessage()
qDebug() << " !!!!!!!!!!!!!!!! ERROR : QMediarecorder - Capture failed";
}
void MediaCapture::resetIfUnused()
{
QMutexLocker lk(&m_recMutex);
qDebug()<<"// CLEARING REC MANAGER";
if (m_audioRecorder && m_audioRecorder->state() == QMediaRecorder::StoppedState) {
m_audioRecorder.reset();
}
}
void MediaCapture::recordAudio(bool record)
{
QMutexLocker lk(&m_recMutex);
if (!m_audioRecorder) {
m_audioRecorder = std::make_unique<QAudioRecorder>(this);
m_probe->setSource(m_audioRecorder.get());
connect(m_audioRecorder.get(), &QAudioRecorder::stateChanged, [&] (QMediaRecorder::State state) {
m_recordState = state;
if (m_recordState == QMediaRecorder::StoppedState) {
m_resetTimer.start();
m_levels.clear();
emit levelsChanged();
pCore->finalizeRecording(getCaptureOutputLocation().toLocalFile());
}
emit recordStateChanged();
});
}
......@@ -61,24 +80,21 @@ void MediaCapture::recordAudio(bool record)
setAudioCaptureDevice();
m_audioRecorder->setAudioInput(m_audioDevice);
setCaptureOutputLocation();
m_audioRecorder->setOutputLocation(m_path);
setAudioVolume();
m_audioRecorder->setVolume(m_volume);
//qDebug()<<"START AREC: "<<m_path<<"\n; CODECS: "<<m_audioRecorder->supportedAudioCodecs();
connect(m_audioRecorder.get(), SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayErrorMessage()));
QAudioEncoderSettings audioSettings;
audioSettings.setCodec("audio/x-flac");
audioSettings.setBitRate(48000); // Bit rate is set to 48,0000
QString container = "audio/x-wav";
m_audioRecorder->setEncodingSettings(audioSettings, QVideoEncoderSettings(), container);
audioSettings.setChannelCount(2);
m_audioRecorder->setEncodingSettings(audioSettings);
m_audioRecorder->setOutputLocation(m_path);
m_audioRecorder->record();
} else if (m_audioRecorder->state() != QMediaRecorder::PausedState) {
m_audioRecorder->stop();
m_audioRecorder.reset();
m_levels.clear();
emit levelsChanged();
m_recordState = QMediaRecorder::StoppedState;
emit recordStateChanged();
} else {
m_audioRecorder->record();
}
......@@ -127,7 +143,7 @@ void MediaCapture::setCaptureOutputLocation()
if (m_videoRecorder.get() != nullptr) {
extension = QStringLiteral(".mpeg");
} else if (m_audioRecorder.get() != nullptr) {
extension = QStringLiteral(".wav");
extension = QStringLiteral(".flac");
}
QString path = captureFolder.absoluteFilePath("capture0000" + extension);
......
......@@ -31,6 +31,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QStringList>
#include <QUrl>
#include <QVideoEncoderSettings>
#include <QTimer>
#include <QMutex>
#include <memory>
class QAudioRecorder;
......@@ -78,13 +80,17 @@ private:
QUrl m_path;
QVector<qreal> m_levels;
int m_recordState;
QTimer m_resetTimer;
QMutex m_recMutex;
private slots:
void processBuffer(const QAudioBuffer &buffer);
void resetIfUnused();
signals:
void levelsChanged();
void recordStateChanged();
void recordDone();
};
#endif
......@@ -695,14 +695,13 @@ void Core::startMediaCapture(bool checkAudio, bool checkVideo)
m_mediaCaptureFile = m_capture->getCaptureOutputLocation();
}
const QString Core::stopMediaCapture(bool checkAudio, bool checkVideo)
void Core::stopMediaCapture(bool checkAudio, bool checkVideo)
{
if (checkAudio && checkVideo) {
m_capture->recordVideo(false);
} else if (checkAudio) {
m_capture->recordAudio(false);
}
return m_capture->getCaptureOutputLocation().toLocalFile();
}
QStringList Core::getAudioCaptureDevices()
......
......@@ -183,7 +183,7 @@ public:
int getTimelinePosition() const;
/** @brief Handles audio and video capture **/
void startMediaCapture(bool, bool);
const QString stopMediaCapture(bool, bool);
void stopMediaCapture(bool, bool);
QStringList getAudioCaptureDevices();
int getMediaCaptureState();
bool isMediaCapturing();
......@@ -231,6 +231,7 @@ signals:
void updateLibraryPath();
/** @brief Call config dialog on a selected page / tab */
void showConfigDialog(int, int);
void finalizeRecording(const QString &captureFile);
};
#endif
......@@ -136,7 +136,7 @@ void ClipController::addMasterProducer(const std::shared_ptr<Mlt::Producer> &pro
}
namespace {
QString producerXml(const std::shared_ptr<Mlt::Producer> &producer, bool includeMeta)
QString producerXml(const std::shared_ptr<Mlt::Producer> &producer, bool includeMeta, bool includeProfile)
{
Mlt::Consumer c(*producer->profile(), "xml", "string");
Mlt::Service s(producer->get_service());
......@@ -151,6 +151,9 @@ QString producerXml(const std::shared_ptr<Mlt::Producer> &producer, bool include
if (!includeMeta) {
c.set("no_meta", 1);
}
if (!includeProfile) {
c.set("no_profile", 1);
}
c.set("store", "kdenlive");
c.set("no_root", 1);
c.set("root", "/");
......@@ -163,11 +166,11 @@ QString producerXml(const std::shared_ptr<Mlt::Producer> &producer, bool include
}
} // namespace
void ClipController::getProducerXML(QDomDocument &document, bool includeMeta)
void ClipController::getProducerXML(QDomDocument &document, bool includeMeta, bool includeProfile)
{
// TODO refac this is a probable duplicate with Clip::xml
if (m_masterProducer) {
QString xml = producerXml(m_masterProducer, includeMeta);
QString xml = producerXml(m_masterProducer, includeMeta, includeProfile);
document.setContent(xml);
} else {
qCDebug(KDENLIVE_LOG) << " + + ++ NO MASTER PROD";
......@@ -310,8 +313,10 @@ void ClipController::updateProducer(const std::shared_ptr<Mlt::Producer> &produc
} else {
m_usesProxy = false;
}
// When resetting profile, duration can change so we invalidate it to 0 in that case
int length = m_properties->get_int("length");
const char *passList = getPassPropertiesList(m_usesProxy && length > 0);
// This is necessary as some properties like set.test_audio are reset on producer creation
const char *passList = getPassPropertiesList(m_usesProxy);
passProperties.pass_list(*m_properties, passList);
delete m_properties;
*m_masterProducer = producer.get();
......
......@@ -72,7 +72,7 @@ public:
/** @brief Replaces the master producer and (TODO) the track producers with an updated producer, for example a proxy */
void updateProducer(const std::shared_ptr<Mlt::Producer> &producer);
void getProducerXML(QDomDocument &document, bool includeMeta = false);
void getProducerXML(QDomDocument &document, bool includeMeta = false, bool includeProfile = true);
/** @brief Returns a clone of our master producer. Delete after use! */
Mlt::Producer *masterProducer();
......
......@@ -8,7 +8,7 @@ Item {
property int recState: audiorec.recordState
width: parent.width
implicitHeight: root.baseUnit * 1.5
onRecStateChanged: {
if (recState == 1) {
// Recording
......@@ -19,9 +19,7 @@ Item {
} else {
recbutton.color = 'darkred'
}
}
RowLayout {
spacing: 2
Layout.fillWidth: true
......
......@@ -111,6 +111,7 @@ Item {
}
*/
function updateDrag() {
console.log('XXXXXXXXXXXXXXX\n\nXXXXXXXXXXXXX \nUPDATING COMPO DRAG')
var itemPos = mapToItem(tracksContainerArea, 0, displayRect.y, displayRect.width, displayRect.height)
initDrag(compositionRoot, itemPos, compositionRoot.clipId, compositionRoot.modelStart, compositionRoot.trackId, true)
}
......
......@@ -186,6 +186,24 @@ Rectangle {
dragProxy.verticalOffset = 0
}
function getItemAtPos(tk, posx, isComposition) {
var track = Logic.getTrackById(tk)
var container = track.children[0]
var tentativeClip = undefined
//console.log('TESTING ITMES OK TK: ', tk, ', POS: ', posx, ', CHILREN: ', container.children.length, ', COMPO: ', isComposition)
for (var i = 0 ; i < container.children.length; i++) {
if (container.children[i].children.length == 0 || container.children[i].children[0].children.length == 0) {
continue
}
tentativeClip = container.children[i].children[0].childAt(posx, 1)
if (tentativeClip && tentativeClip.clipId && (tentativeClip.isComposition == isComposition)) {
//console.log('found item with id: ', tentativeClip.clipId, ' IS COMPO: ', tentativeClip.isComposition)
break
}
}
return tentativeClip
}
property int headerWidth: timeline.headerWidth()
property int activeTool: 0
property real baseUnit: fontMetrics.font.pointSize
......@@ -239,6 +257,32 @@ Rectangle {
}
}
onActiveToolChanged: {
if (root.activeTool == 2) {
// Spacer activated
endDrag()
} else if (root.activeTool == 0) {
var tk = getMouseTrack()
if (tk < 0) {
console.log('........ MOUSE OUTSIDE TRAKS\n\n.........')
return
}
var pos = getMousePos() * timeline.scaleFactor
var sourceTrack = Logic.getTrackById(tk)
var allowComposition = tracksArea.mouseY- sourceTrack.y > sourceTrack.height / 2
var tentativeItem = undefined
if (allowComposition) {
tentativeItem = getItemAtPos(tk, pos, true)
}
if (!tentativeItem) {
tentativeItem = getItemAtPos(tk, pos, false)
}
if (tentativeItem) {
tentativeItem.updateDrag()
}
}
}
DropArea { //Drop area for compositions
width: root.width - headerWidth
height: root.height - ruler.height
......@@ -1033,6 +1077,7 @@ Rectangle {
property int dragFrame
property bool shiftClick: false
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor
enabled: root.activeTool == 0
onPressed: {
console.log('+++++++++++++++++++ DRAG CLICKED +++++++++++++')
if (mouse.modifiers & Qt.ControlModifier || !(controller.isClip(dragProxy.draggedItem) || controller.isComposition(dragProxy.draggedItem))) {
......@@ -1070,21 +1115,7 @@ Rectangle {
if (controller.normalEdit() && (tk != Logic.getTrackIdFromPos(parent.y) || x != posx)) {
console.log('INCORRECT DRAG, Trying to recover item: ', parent.y,' XPOS: ',x,'=',posx,'on track: ',tk ,'\n!!!!!!!!!!')
// Try to find correct item
var track = Logic.getTrackById(tk)
var container = track.children[0]
var tentativeClip = undefined
var realX = mouseX + parent.x
for (var i = 0 ; i < container.children.length; i++) {
if (container.children[i].children.length == 0 || container.children[i].children[0].children.length == 0) {
continue
}
var testX = container.children[i].children[0].children[0].x - realX
if (dragProxy.isComposition == container.children[i].children[0].children[0].isComposition && testX < 0 && testX + container.children[i].children[0].children[0].width > 0) {
// Found clip in place
tentativeClip = container.children[i].children[0].children[0]
break
}
}
var tentativeClip = getItemAtPos(tk, mouseX + parent.x, dragProxy.isComposition)
if (tentativeClip && tentativeClip.clipId) {
clickAccepted = true
dragProxy.draggedItem = tentativeClip.clipId
......
......@@ -77,6 +77,7 @@ TimelineController::TimelineController(QObject *parent)
connect(m_disablePreview, &QAction::triggered, this, &TimelineController::disablePreview);
connect(this, &TimelineController::selectionChanged, this, &TimelineController::updateClipActions);
m_disablePreview->setEnabled(false);
connect(pCore.get(), &Core::finalizeRecording, this, &TimelineController::finishRecording);
}
TimelineController::~TimelineController()
......@@ -2323,6 +2324,7 @@ void TimelineController::switchRecording(int trackId)
return;
}
m_recordStart.first = timelinePosition();
m_recordTrack = trackId;
int maximumSpace = m_model->getTrackById_const(trackId)->getBlankEnd(m_recordStart.first);
if (maximumSpace == INT_MAX) {
m_recordStart.second = 0;
......@@ -2339,30 +2341,37 @@ void TimelineController::switchRecording(int trackId)
pCore->startMediaCapture(true, false);
pCore->monitorManager()->slotPlay();
} else {
QString recordedFile = pCore->stopMediaCapture(true, false);
pCore->stopMediaCapture(true, false);
pCore->monitorManager()->slotPause();
if (recordedFile.isEmpty()) {
}
}
void TimelineController::finishRecording(const QString &recordedFile)
{
if (recordedFile.isEmpty()) {
return;
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
std::function<void(const QString &)> callBack = [this](const QString &binId) {
int id = -1;
if (m_recordTrack == -1) {
return;
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
std::function<void(const QString &)> callBack = [this, trackId](const QString &binId) {
int id = -1;
qDebug() << "callback " << binId << " " << trackId << ", MAXIMUM SPACE: " << m_recordStart.second;
bool res = false;
if (m_recordStart.second > 0) {
// Limited space on track
QString binClipId = QString("%1/%2/%3").arg(binId).arg(0).arg(m_recordStart.second - 1);
res = m_model->requestClipInsertion(binClipId, trackId, m_recordStart.first, id, true, true, false);
} else {
res = m_model->requestClipInsertion(binId, trackId, m_recordStart.first, id, true, true, false);
}
};
QString binId = ClipCreator::createClipFromFile(recordedFile, pCore->projectItemModel()->getRootFolder()->clipId(), pCore->projectItemModel(), undo,
redo, callBack);
if (binId != QStringLiteral("-1")) {
pCore->pushUndo(undo, redo, i18n("Record audio"));
qDebug() << "callback " << binId << " " << m_recordTrack << ", MAXIMUM SPACE: " << m_recordStart.second;
bool res = false;
if (m_recordStart.second > 0) {
// Limited space on track
QString binClipId = QString("%1/%2/%3").arg(binId).arg(0).arg(m_recordStart.second - 1);
res = m_model->requestClipInsertion(binClipId, m_recordTrack, m_recordStart.first, id, true, true, false);
} else {
res = m_model->requestClipInsertion(binId, m_recordTrack, m_recordStart.first, id, true, true, false);
}
};
QString binId = ClipCreator::createClipFromFile(recordedFile, pCore->projectItemModel()->getRootFolder()->clipId(), pCore->projectItemModel(), undo,
redo, callBack);
if (binId != QStringLiteral("-1")) {
pCore->pushUndo(undo, redo, i18n("Record audio"));
}
}
......@@ -116,6 +116,9 @@ public:
/* @brief Show/hide audio record controls on a track
*/
Q_INVOKABLE void switchRecording(int trackId);
/* @brief Add recorded file to timeline
*/
void finishRecording(const QString &recordedFile);
/* @brief Open Kdenlive's config diablog on a defined page and tab
*/
Q_INVOKABLE void showConfig(int page, int tab);
......@@ -482,6 +485,7 @@ private:
int m_activeTrack;
int m_audioRef;
QPair<int, int> m_recordStart;
int m_recordTrack;
QPoint m_zone;
double m_scale;
static int m_duration;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment