summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Schweer <ws.seh.de>2006-06-12 14:00:46 +0000
committerWerner Schweer <ws.seh.de>2006-06-12 14:00:46 +0000
commit439b879287b21dd4669074f22cfc55efc9ce9afc (patch)
treed182a000b0dda6fcfd612ae7c1eccb421c4be335
parent361e29c776e325b7c26379fcc5527466c9fa3696 (diff)
drag&drop of wave files
-rw-r--r--muse/ChangeLog6
-rw-r--r--muse/TODO13
-rw-r--r--muse/muse/CMakeLists.txt1
-rw-r--r--muse/muse/arranger/canvas.cpp50
-rw-r--r--muse/muse/arranger/partdrag.cpp26
-rw-r--r--muse/muse/arranger/partdrag.h12
-rw-r--r--muse/muse/muse.h4
-rw-r--r--muse/muse/wave.cpp246
8 files changed, 274 insertions, 84 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index 52aea99a..828e69fe 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,9 @@
+12.6. (ws)
+ * drag&drop of wave files with automatic sample rate conversion if
+ necessary
+9.6. (ws)
+ * clicking on controller event in controller editor changed
+ controller value (fixed rounding error and start offset for drag)
8.6.
* implemented deviceId for MidiPort
3.6. (rj)
diff --git a/muse/TODO b/muse/TODO
index b5fd44b7..d4979151 100644
--- a/muse/TODO
+++ b/muse/TODO
@@ -1,8 +1,8 @@
-----------------------------TODO-------------------------------------------
(10.5.2006)
- check for samplerate when loading project
- - compute song len in seconds when saving project
- - save project creation date/time in project
+ * compute song len in seconds when saving project
+ * save project creation date/time in project
- create dialog to edit project comment
BUGS
@@ -41,8 +41,6 @@ FEATURES
- Import MusE 0.7 song files
- - NEW function with templates
-
CLEANUPS
- Cleanup the icon/pixmap handling using Qt resource file:
@@ -58,10 +56,3 @@ Wishlist
tracklist for tracktypes which cannot contain
Parts to make better use of screen real estate.
GUI-wise a "Add Controller" button is needed.
-
- - the controller selector in "Add Controller" should be
- implemented as a modal dialog. This allows for
- presenting the list of controller in a more structured
- way.
-
-
diff --git a/muse/muse/CMakeLists.txt b/muse/muse/CMakeLists.txt
index 100dc6d6..2490cdb8 100644
--- a/muse/muse/CMakeLists.txt
+++ b/muse/muse/CMakeLists.txt
@@ -135,6 +135,7 @@ target_link_libraries(muse
${ALSA_LIB}
${JACK_LIB}
${SNDFILE_LIB}
+ ${SAMPLERATE_LIB}
)
install_targets ( /bin muse )
diff --git a/muse/muse/arranger/canvas.cpp b/muse/muse/arranger/canvas.cpp
index c9c694f5..dc71ff66 100644
--- a/muse/muse/arranger/canvas.cpp
+++ b/muse/muse/arranger/canvas.cpp
@@ -19,6 +19,7 @@
//=============================================================================
#include "canvas.h"
+#include "al/al.h"
#include "al/sig.h"
#include "gconfig.h"
#include "song.h"
@@ -31,6 +32,8 @@
#include "part.h"
#include "gui.h"
+#include <samplerate.h>
+
static const int partLabelHeight = 13;
static const int handleWidth = 5;
@@ -904,10 +907,17 @@ void PartCanvas::copyPart(Part*)
void PartCanvas::dragEnter(QDragEnterEvent* event)
{
- if (MidiPartDrag::canDecode(event)
- || AudioPartDrag::canDecode(event)
- || WavUriDrag::canDecode(event))
+ const QMimeData* md = event->mimeData();
+ if (MidiPartDrag::canDecode(md)
+ || AudioPartDrag::canDecode(md)
+ || WavUriDrag::canDecode(md)) {
event->acceptProposedAction();
+ }
+ else {
+ QStringList formats = md->formats();
+ foreach(QString s, formats)
+ printf("drag format <%s>\n", s.toLatin1().data());
+ }
}
//---------------------------------------------------------
@@ -919,14 +929,15 @@ void PartCanvas::dragMove(QDragMoveEvent* event)
Part* srcPart = 0;
QString filename;
- if (MidiPartDrag::canDecode(event)) {
- MidiPartDrag::decode(event, srcPart);
+ const QMimeData* md = event->mimeData();
+ if (MidiPartDrag::canDecode(md)) {
+ MidiPartDrag::decode(md, srcPart);
}
- else if (AudioPartDrag::canDecode(event)) {
- AudioPartDrag::decode(event, srcPart);
+ else if (AudioPartDrag::canDecode(md)) {
+ AudioPartDrag::decode(md, srcPart);
}
- else if (WavUriDrag::canDecode(event)) {
- WavUriDrag::decode(event, &filename);
+ else if (WavUriDrag::canDecode(md)) {
+ WavUriDrag::decode(md, &filename);
}
else {
state = S_NORMAL;
@@ -996,15 +1007,15 @@ void PartCanvas::drop(QDropEvent* event)
Part* srcPart = 0;
QString filename;
- if (MidiPartDrag::canDecode(event)) {
- MidiPartDrag::decode(event, srcPart);
+ const QMimeData* md = event->mimeData();
+ if (MidiPartDrag::canDecode(md)) {
+ MidiPartDrag::decode(md, srcPart);
}
- else if (AudioPartDrag::canDecode(event)) {
- AudioPartDrag::decode(event, srcPart);
+ else if (AudioPartDrag::canDecode(md)) {
+ AudioPartDrag::decode(md, srcPart);
}
- else if (WavUriDrag::canDecode(event)) {
- WavUriDrag::decode(event, &filename);
- printf("drop <%s>\n", filename.toLatin1().data());
+ else if (WavUriDrag::canDecode(md)) {
+ WavUriDrag::decode(md, &filename);
}
else
return;
@@ -1016,12 +1027,13 @@ void PartCanvas::drop(QDropEvent* event)
return;
if (srcPart == 0) {
- printf("TODO: drop wave file <%s>\n", filename.toLatin1().data());
- //TODO
+ int tick = AL::sigmap.raster(mapxDev(pos.x()), raster());
+ Pos pos(tick);
+ muse->importWaveToTrack(filename, track, pos);
}
else {
PartCanvas* cw = (PartCanvas*)event->source();
- unsigned tick = AL::sigmap.raster(mapxDev(pos.x() - cw->dragOffset()), raster());
+ int tick = AL::sigmap.raster(mapxDev(pos.x() - cw->dragOffset()), raster());
if (srcPart->tick() != tick || srcTrack != track) {
Qt::KeyboardModifiers keyState = event->keyboardModifiers();
diff --git a/muse/muse/arranger/partdrag.cpp b/muse/muse/arranger/partdrag.cpp
index 9415fc88..a09d9d3b 100644
--- a/muse/muse/arranger/partdrag.cpp
+++ b/muse/muse/arranger/partdrag.cpp
@@ -46,18 +46,18 @@ MidiPartDrag::MidiPartDrag(Part* part, QWidget* src)
// canDecode
//---------------------------------------------------------
-bool MidiPartDrag::canDecode(const QMimeSource* s)
+bool MidiPartDrag::canDecode(const QMimeData* s)
{
- return !strcmp(s->format(0), type);
+ return s->hasFormat(type);
}
//---------------------------------------------------------
// decode
//---------------------------------------------------------
-bool MidiPartDrag::decode(const QMimeSource* s, Part*& p)
+bool MidiPartDrag::decode(const QMimeData* s, Part*& p)
{
- QByteArray a = s->encodedData(type);
+ QByteArray a = s->data(type);
char* cp = (char*)(&p);
for (unsigned i = 0; i < sizeof(p); ++i)
*cp++ = a[i];
@@ -85,18 +85,18 @@ AudioPartDrag::AudioPartDrag(Part* part, QWidget* src)
// canDecode
//---------------------------------------------------------
-bool AudioPartDrag::canDecode(const QMimeSource* s)
+bool AudioPartDrag::canDecode(const QMimeData* s)
{
- return !strcmp(s->format(0), type);
+ return s->hasFormat(type);
}
//---------------------------------------------------------
// decode
//---------------------------------------------------------
-bool AudioPartDrag::decode(const QMimeSource* s, Part*& p)
+bool AudioPartDrag::decode(const QMimeData* s, Part*& p)
{
- QByteArray a = s->encodedData(type);
+ QByteArray a = s->data(type);
char* cp = (char*)(&p);
for (unsigned i = 0; i < sizeof(p); ++i)
*cp++ = a[i];
@@ -120,11 +120,11 @@ WavUriDrag::WavUriDrag(const QString& s, QWidget* src)
// canDecode
//---------------------------------------------------------
-bool WavUriDrag::canDecode(const QMimeSource* s)
+bool WavUriDrag::canDecode(const QMimeData* s)
{
- if (strcmp(s->format(0), type))
+ if (!s->hasFormat(type))
return false;
- QByteArray data = s->encodedData("text/uri-list");
+ QByteArray data = s->data(type);
QUrl url(data);
if (url.scheme() != "file")
return false;
@@ -144,9 +144,9 @@ bool WavUriDrag::canDecode(const QMimeSource* s)
// decode
//---------------------------------------------------------
-bool WavUriDrag::decode(const QMimeSource* s, QString* uri)
+bool WavUriDrag::decode(const QMimeData* s, QString* uri)
{
- QByteArray data = s->encodedData("text/uri-list");
+ QByteArray data = s->data(type);
QUrl url(data);
*uri = url.toLocalFile().trimmed();
return true;
diff --git a/muse/muse/arranger/partdrag.h b/muse/muse/arranger/partdrag.h
index 489d7f80..3f9a71c1 100644
--- a/muse/muse/arranger/partdrag.h
+++ b/muse/muse/arranger/partdrag.h
@@ -33,8 +33,8 @@ class MidiPartDrag : public QDrag {
public:
MidiPartDrag(Part*, QWidget* src);
- static bool canDecode(const QMimeSource*);
- static bool decode(const QMimeSource* s, Part*& p);
+ static bool canDecode(const QMimeData*);
+ static bool decode(const QMimeData* s, Part*& p);
};
//---------------------------------------------------------
@@ -47,8 +47,8 @@ class AudioPartDrag : public QDrag {
public:
AudioPartDrag(Part*, QWidget* src);
- static bool canDecode(const QMimeSource*);
- static bool decode(const QMimeSource* s, Part*& p);
+ static bool canDecode(const QMimeData*);
+ static bool decode(const QMimeData* s, Part*& p);
};
//---------------------------------------------------------
@@ -61,8 +61,8 @@ class WavUriDrag : public QDrag {
public:
WavUriDrag(const QString&, QWidget* src);
- static bool canDecode(const QMimeSource*);
- static bool decode(const QMimeSource* s, QString* p);
+ static bool canDecode(const QMimeData*);
+ static bool decode(const QMimeData* s, QString* p);
};
diff --git a/muse/muse/muse.h b/muse/muse/muse.h
index 9921f96d..711cf3d0 100644
--- a/muse/muse/muse.h
+++ b/muse/muse/muse.h
@@ -27,8 +27,10 @@
namespace AL {
class Xml;
+ class Pos;
};
using AL::Xml;
+using AL::Pos;
class Part;
class PartList;
@@ -277,7 +279,7 @@ class MusE : public QMainWindow, public Ui::MuseBase
QWidget* bigtimeWindow();
QWidget* mixer1Window();
QWidget* mixer2Window();
- bool importWaveToTrack(QString& name, Track* track);
+ bool importWaveToTrack(const QString& name, Track* track, const Pos&);
void selectionChanged();
diff --git a/muse/muse/wave.cpp b/muse/muse/wave.cpp
index 74d71006..6b1b4079 100644
--- a/muse/muse/wave.cpp
+++ b/muse/muse/wave.cpp
@@ -18,6 +18,8 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
+#include <samplerate.h>
+
#include "al/xml.h"
#include "al/al.h"
#include "song.h"
@@ -44,6 +46,202 @@ QList<SndFile*> SndFile::createdFiles;
int SndFile::recFileNumber;
//---------------------------------------------------------
+// copyWaveFileToProject
+// - copy wave file to project directory
+// - do sample rate conversion
+//
+// return false on error
+//---------------------------------------------------------
+
+static bool copyWaveFileToProject(const QString& path)
+ {
+ QFile srcFile(path);
+ QFileInfo srcInfo(srcFile);
+
+ QString dst(song->absoluteProjectPath());
+ QFile dstFile(dst + "/" + srcInfo.fileName());
+ if (dstFile.exists()) {
+ // TODO: rename file, check for identity
+ printf("File already exists\n");
+ return false;
+ }
+
+ SF_INFO sfinfoSrc;
+ memset(&sfinfoSrc, 0, sizeof(SF_INFO));
+ SNDFILE* sfSrc = sf_open(path.toLatin1().data(), SFM_READ, &sfinfoSrc);
+ if (sfSrc == 0) {
+ printf("Cannot open source file: %s\n", strerror(errno));
+ return false;
+ }
+
+ int channels = sfinfoSrc.channels;
+ sf_count_t size = sfinfoSrc.frames;
+
+ SF_INFO sfinfoDst;
+ memset(&sfinfoDst, 0, sizeof(SF_INFO));
+ sfinfoDst.samplerate = AL::sampleRate;
+ sfinfoDst.channels = channels;
+ sfinfoDst.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
+ SNDFILE* sfDst = sf_open(dstFile.fileName().toLatin1().data(),
+ SFM_WRITE, &sfinfoDst);
+ if (sfDst == 0) {
+ printf("Cannot open destination file<%s>: %s\n",
+ dstFile.fileName().toLatin1().data(), strerror(errno));
+ return false;
+ }
+
+ bool showProgress = size > (1024LL * 1024LL * 8LL);
+ QProgressDialog* progress = 0;
+ if (showProgress) {
+ QString label(QWidget::tr("copy \n %1\nto\n %2"));
+ label = label.arg(path).arg(dst);
+ if (sfinfoSrc.samplerate != AL::sampleRate) {
+ QString cs(QWidget::tr("\nconverting sample rate\n"
+ "from %1 to %2"));
+ label += cs.arg(sfinfoSrc.samplerate).arg(AL::sampleRate);
+ }
+ int csize = size / 1024;
+ progress = new QProgressDialog(label, QWidget::tr("Abort"), 0, csize);
+ progress->setValue(0);
+ progress->setWindowTitle("MusE");
+ progress->raise();
+ progress->show();
+ qApp->processEvents();
+ }
+ sf_count_t inSize = 1024LL * 512LL;
+ sf_count_t samplesWritten = 0LL;
+
+ bool returnValue = true;
+ if (sfinfoSrc.samplerate != AL::sampleRate) {
+ // TODO: convertsample rate
+ printf("wave file has samplerate of %d, our project has %d\n",
+ sfinfoSrc.samplerate,AL::sampleRate);
+
+ int srcType = SRC_SINC_MEDIUM_QUALITY;
+ int error;
+ SRC_STATE* src = src_new(srcType, channels, &error);
+ if (src == 0) {
+ printf("creating sample rate converter failed: error %d\n",
+ error);
+ return false;
+ }
+ double ratio = double(AL::sampleRate) / double(sfinfoSrc.samplerate);
+ src_set_ratio(src, ratio);
+ sf_count_t outSize = int(inSize * ratio) + 1;
+ float inBuffer[inSize * channels];
+ float* inPtr = inBuffer;
+ while (size) {
+ float outBuffer[outSize * channels];
+
+ // read buffer
+ sf_count_t framesToRead = (inBuffer + inSize) - inPtr;
+ if (framesToRead > size)
+ framesToRead = size;
+
+ sf_count_t nr = sf_readf_float(sfSrc, inPtr, framesToRead);
+ if (nr != framesToRead) {
+ printf("sound file read failed\n");
+ src_delete(src);
+ returnValue = false;
+ break;
+ }
+
+ // convert
+ SRC_DATA data;
+ data.data_in = inBuffer;
+ data.data_out = outBuffer;
+ data.input_frames = inSize;
+ data.output_frames = outSize;
+ data.end_of_input = framesToRead == size;
+ data.src_ratio = ratio;
+
+ int rv = src_process(src, &data);
+ if (rv > 0) {
+ printf("error sampe rate conversion: %s\n",
+ src_strerror(rv));
+ src_delete(src);
+ returnValue = false;
+ break;
+ }
+
+ // write buffer
+ sf_count_t n = sf_writef_float(sfDst, outBuffer, data.output_frames_gen);
+ if (n != data.output_frames_gen) {
+ printf("sound write failed: returns %lld, should return %ld\n",
+ n, data.output_frames_gen);
+ returnValue = false;
+ break;
+ }
+
+ int rest = (inPtr + nr - inBuffer) - data.input_frames_used;
+ rest *= (sizeof(float) * channels);
+ if (rest > 0)
+ memcpy(inBuffer, inBuffer + data.input_frames_used, rest);
+
+ inPtr += framesToRead;
+ inPtr -= data.input_frames_used;
+ if (data.input_frames_used > size)
+ size = 0;
+ else
+ size -= data.input_frames_used;
+ framesToRead = data.input_frames_used;
+ samplesWritten += data.input_frames_used;
+
+ if (framesToRead > size)
+ framesToRead = size;
+ if (showProgress) {
+ progress->setValue(samplesWritten / 1024LL);
+ progress->raise();
+ qApp->processEvents();
+ if (progress->wasCanceled()) {
+ returnValue = false;
+ break;
+ }
+ }
+ }
+ src_delete(src);
+ }
+ else {
+ while (size) {
+ float buffer[inSize * channels];
+
+ sf_count_t n = inSize > size ? size : inSize;
+ sf_count_t nn = sf_readf_float(sfSrc, buffer, n);
+
+ if (nn != n) {
+ printf("sound file read failed\n");
+ returnValue = false;
+ break;
+ }
+ // write buffer
+ nn = sf_writef_float(sfDst, buffer, n);
+ if (n != nn) {
+ printf("sound write failed: returns %lld, should return %lld\n",
+ nn, n);
+ returnValue = false;
+ break;
+ }
+ size -= n;
+ samplesWritten += n;
+ if (showProgress) {
+ progress->setValue(samplesWritten / 1024LL);
+ progress->raise();
+ qApp->processEvents();
+ if (progress->wasCanceled()) {
+ returnValue = false;
+ break;
+ }
+ }
+ }
+ }
+ if (progress)
+ delete progress;
+ sf_close(sfSrc);
+ sf_close(sfDst);
+ return returnValue;
+ }
+
+//---------------------------------------------------------
// SndFile
//---------------------------------------------------------
@@ -629,41 +827,20 @@ void MusE::importWave()
bool MusE::importWave(const QString& name)
{
- WaveTrack* track = (WaveTrack*)(arranger->curTrack());
- SndFile* f = SndFile::getWave(name, false);
-
- if (f == 0) {
- printf("import audio file failed\n");
- return true;
- }
- int samples = f->samples();
- track->setChannels(f->channels());
-
- Part* part = new Part(track);
- part->setType(AL::FRAMES);
- part->setTick(song->cpos());
- part->setLenFrame(samples);
-
- Event event(Wave);
- SndFileR sf(f);
- event.setSndFile(sf);
- event.setSpos(0);
- event.setLenFrame(samples);
- part->addEvent(event);
-
- part->setName(QFileInfo(name).baseName());
- audio->msgAddPart(part);
- track->partListChanged(); // Updates the gui
-
- unsigned endTick = part->tick() + part->lenTick();
- if (song->len() < endTick)
- song->setLen(endTick);
- return false;
+ return importWaveToTrack(name, (WaveTrack*)(arranger->curTrack()),
+ song->cPos());
}
-bool MusE::importWaveToTrack(QString& name, Track* track)
+//---------------------------------------------------------
+// importWaveToTrack
+//---------------------------------------------------------
+
+bool MusE::importWaveToTrack(const QString& wave, Track* track, const Pos& pos)
{
- SndFile* f = SndFile::getWave(name, false);
+ if (!copyWaveFileToProject(wave))
+ return true;
+ QFileInfo srcInfo(wave);
+ SndFile* f = SndFile::getWave(srcInfo.fileName(), false);
if (f == 0) {
printf("import audio file failed\n");
@@ -674,7 +851,7 @@ bool MusE::importWaveToTrack(QString& name, Track* track)
Part* part = new Part((WaveTrack *)track);
part->setType(AL::FRAMES);
- part->setTick(song->cpos());
+ part->setTick(pos.tick());
part->setLenFrame(samples);
Event event(Wave);
@@ -684,7 +861,7 @@ bool MusE::importWaveToTrack(QString& name, Track* track)
event.setLenFrame(samples);
part->addEvent(event);
- part->setName(QFileInfo(name).baseName());
+ part->setName(srcInfo.baseName());
audio->msgAddPart(part);
unsigned endTick = part->tick() + part->lenTick();
if (song->len() < endTick)
@@ -696,6 +873,7 @@ bool MusE::importWaveToTrack(QString& name, Track* track)
// cmdChangeWave
// called from GUI context
//---------------------------------------------------------
+
void Song::cmdChangeWave(QString original, QString tmpfile, unsigned sx, unsigned ex)
{
char* original_charstr = new char[original.length() + 1];