diff options
author | Tim E. Real <termtech@rogers.com> | 2012-09-17 07:49:10 +0000 |
---|---|---|
committer | Tim E. Real <termtech@rogers.com> | 2012-09-17 07:49:10 +0000 |
commit | ef0a06629a9d4652b3a91d85af768e7e5797fe2a (patch) | |
tree | 1fe845ff5e8e6390883b6177b6f34feaf7f9736c /muse2/muse/waveedit | |
parent | f783083862fa7a71f7774a14176e4a6bbbe324f9 (diff) |
Introducing Copy On Write for waves. See ChangeLog.
Diffstat (limited to 'muse2/muse/waveedit')
-rw-r--r-- | muse2/muse/waveedit/wavecanvas.cpp | 169 | ||||
-rw-r--r-- | muse2/muse/waveedit/wavecanvas.h | 2 |
2 files changed, 152 insertions, 19 deletions
diff --git a/muse2/muse/waveedit/wavecanvas.cpp b/muse2/muse/waveedit/wavecanvas.cpp index 2139b647..8c1b0012 100644 --- a/muse2/muse/waveedit/wavecanvas.cpp +++ b/muse2/muse/waveedit/wavecanvas.cpp @@ -33,6 +33,7 @@ #include <QDragEnterEvent> #include <QDragMoveEvent> #include <QDropEvent> +#include <QFile> #include <QInputDialog> #include <QMouseEvent> #include <QList> @@ -48,6 +49,7 @@ #include <errno.h> #include <sys/wait.h> +#include "app.h" #include "xml.h" #include "wavecanvas.h" #include "event.h" @@ -64,6 +66,7 @@ #include "fastlog.h" #include "utils.h" #include "tools.h" +#include "copy_on_write.h" namespace MusEGui { @@ -1885,8 +1888,7 @@ void WaveCanvas::cmd(int cmd) // modifyWarnedYet = true; // if(QMessageBox::warning(this, QString("Muse"), // tr("Warning! Muse currently operates directly on the sound file.\n" - // "Undo is supported, but NOT after exit, WITH OR WITHOUT A SAVE!\n" - // "If you are stuck, try deleting the associated .wca file and reloading."), tr("&Ok"), tr("&Cancel"), + // "Undo is supported, but NOT after exit, WITH OR WITHOUT A SAVE!"), tr("&Ok"), tr("&Cancel"), // QString::null, 0, 1 ) != 0) // return; //} @@ -1947,7 +1949,7 @@ MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned //printf("Event data affected: %d->%d filename:%s\n", sx, ex, file.name().toLatin1().constData()); MusECore::WaveEventSelection s; - s.file = file; + s.event = event; s.startframe = sx; s.endframe = ex+1; //printf("sx=%d ex=%d\n",sx,ex); @@ -1964,24 +1966,155 @@ MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned //--------------------------------------------------------- void WaveCanvas::modifySelection(int operation, unsigned startpos, unsigned stoppos, double paramA) { - MusEGlobal::song->startUndo(); + if (operation == PASTE) { + // we need to redefine startpos and stoppos + if (copiedPart =="") + return; + MusECore::SndFile pasteFile(copiedPart); + pasteFile.openRead(); + startpos = pos[0]; + stoppos = startpos+ pasteFile.samples(); // possibly this is wrong if there are tempo changes + pasteFile.close(); + pos[0]=stoppos; + } - if (operation == PASTE) { - // we need to redefine startpos and stoppos - if (copiedPart =="") - return; - MusECore::SndFile pasteFile(copiedPart); - pasteFile.openRead(); - startpos = pos[0]; - stoppos = startpos+ pasteFile.samples(); // possibly this is wrong if there are tempo changes - pasteFile.close(); - pos[0]=stoppos; - } - - MusECore::WaveSelectionList selection = getSelection(startpos, stoppos); + // + // Copy on Write: Check if some files need to be copied, either because they are not + // writable, or more than one independent (non-clone) wave event shares a wave file. + // + + MusECore::WaveSelectionList selection = getSelection(startpos, stoppos); + std::vector<MusECore::SndFileR> copy_files_proj_dir; + for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) + { + MusECore::WaveEventSelection w = *i; + MusECore::SndFileR file = w.event.sndFile(); + if(file.checkCopyOnWrite()) + { + std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin(); + for( ; i != copy_files_proj_dir.end(); ++i) + { + if(i->canonicalPath() == file.canonicalPath()) + break; + } + if(i == copy_files_proj_dir.end()) + copy_files_proj_dir.push_back(file); + } + } + if(!copy_files_proj_dir.empty()) + { + CopyOnWriteDialog* dlg = new CopyOnWriteDialog(); + for(std::vector<MusECore::SndFileR>::iterator i = copy_files_proj_dir.begin(); i != copy_files_proj_dir.end(); ++i) + { + qint64 sz = QFile(i->canonicalPath()).size(); + QString s; + if(sz > 1048576) + s += QString::number(sz / 1048576) + "MB "; + else + if(sz > 1024) + s += QString::number(sz / 1024) + "KB "; + else + s += QString::number(sz) + "B "; + s += i->canonicalPath(); + dlg->addProjDirFile(s); + } + int rv = dlg->exec(); + delete dlg; + if(rv != QDialog::Accepted) + return; + // Has a project been created yet? + if(MusEGlobal::museProject == MusEGlobal::museProjectInitPath) // && MusEGlobal::config.useProjectSaveDialog + { + // No project, we need to create one. + if(!MusEGlobal::muse->saveAs()) + return; // No project, don't want to copy without one. + //setFocus(); // For some reason focus is given away to Arranger + } + for(MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) + { + MusECore::WaveEventSelection w = *i; + MusECore::SndFileR file = w.event.sndFile(); + if(!file.checkCopyOnWrite()) // Make sure to re-check + continue; + QString filePath = MusEGlobal::museProject + QString("/") + file.name(); + QString newFilePath; + if(MusECore::getUniqueFileName(filePath, newFilePath)) + { + { + QFile qf(file.canonicalPath()); + if(!qf.copy(newFilePath)) // Copy the file + { + printf("MusE Error: Could not copy to new sound file (file exists?): %s\n", newFilePath.toLatin1().constData()); + continue; // Let's not overwrite an existing file + } + } + QFile nqf(newFilePath); + // Need to make sure some permissions are set... + QFile::Permissions pm = nqf.permissions(); + if(!(pm & QFile::ReadOwner)) + { + pm |= QFile::ReadOwner; + if(!nqf.setPermissions(pm)) + { + printf("MusE Error: Could not set read owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData()); + continue; + } + } + if(!(pm & QFile::WriteOwner)) + { + pm |= QFile::WriteOwner; + if(!nqf.setPermissions(pm)) + { + printf("MusE Error: Could not set write owner permissions on new sound file: %s\n", newFilePath.toLatin1().constData()); + continue; + } + } + if(!(pm & QFile::ReadUser)) + { + pm |= QFile::ReadUser; + if(!nqf.setPermissions(pm)) + { + printf("MusE Error: Could not set read user permissions on new sound file: %s\n", newFilePath.toLatin1().constData()); + continue; + } + } + if(!(pm & QFile::WriteUser)) + { + pm |= QFile::WriteUser; + if(!nqf.setPermissions(pm)) + { + printf("MusE Error: Could not set write user permissions on new sound file: %s\n", newFilePath.toLatin1().constData()); + continue; + } + } + MusECore::SndFile* newSF = new MusECore::SndFile(newFilePath); + MusECore::SndFileR newSFR(newSF); // Create a sndFileR for the new file + if(newSFR.openRead()) + { + printf("MusE Error: Could not open new sound file: %s\n", newSFR.canonicalPath().toLatin1().constData()); + continue; // newSF will be deleted when newSFR goes out of scope and is deleted + } + MusEGlobal::audio->msgIdle(true); + w.event.sndFile().close(); // Close the old file. + // NOTE: For now, don't bother providing undo for this. Reason: If the user undoes + // and then modifies again, it will prompt to create new copies each time. There is + // no mechanism ("touched"?) to tell if an existing copy would be suitable to just 'drop in'. + // It would help if we deleted the wave file copies upon undo, but not too crazy about that. + // So since the copy has already been created and "there it is", we might as well use it. + // It means that events and even undo items BEFORE this operation will point to this + // NEW wave file (as if they always did). It also means the user CANNOT change back + // to the old file... Oh well, this IS Copy On Write. + // FIXME: Find a conceptual way to make undo work with or without deleting the copies. + w.event.setSndFile(newSFR); // Set the new file. + MusEGlobal::audio->msgIdle(false); + } + } + } + + MusEGlobal::song->startUndo(); for (MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) { MusECore::WaveEventSelection w = *i; - MusECore::SndFileR& file = w.file; + MusECore::SndFileR file = w.event.sndFile(); unsigned sx = w.startframe; unsigned ex = w.endframe; unsigned file_channels = file.channels(); diff --git a/muse2/muse/waveedit/wavecanvas.h b/muse2/muse/waveedit/wavecanvas.h index 4a6ae9f9..f9553845 100644 --- a/muse2/muse/waveedit/wavecanvas.h +++ b/muse2/muse/waveedit/wavecanvas.h @@ -46,7 +46,7 @@ class WavePart; class WaveTrack; struct WaveEventSelection { - SndFileR file; + Event event; unsigned startframe; unsigned endframe; }; |