summaryrefslogtreecommitdiff
path: root/muse2/muse/waveevent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/waveevent.cpp')
-rw-r--r--muse2/muse/waveevent.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/muse2/muse/waveevent.cpp b/muse2/muse/waveevent.cpp
new file mode 100644
index 00000000..98bfe8cc
--- /dev/null
+++ b/muse2/muse/waveevent.cpp
@@ -0,0 +1,453 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: waveevent.cpp,v 1.9.2.6 2009/12/20 05:00:35 terminator356 Exp $
+//
+// (C) Copyright 2000-2003 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include "audioconvert.h"
+#include "globals.h"
+#include "event.h"
+#include "waveevent.h"
+#include "xml.h"
+#include "wave.h"
+#include <iostream>
+#include <math.h>
+
+// Added by Tim. p3.3.18
+//#define USE_SAMPLERATE
+//
+//#define WAVEEVENT_DEBUG
+//#define WAVEEVENT_DEBUG_PRC
+
+//---------------------------------------------------------
+// WaveEvent
+//---------------------------------------------------------
+
+WaveEventBase::WaveEventBase(EventType t)
+ : EventBase(t)
+ {
+ deleted = false;
+ }
+
+//---------------------------------------------------------
+// WaveEventBase::clone
+//---------------------------------------------------------
+
+EventBase* WaveEventBase::clone()
+{
+ return new WaveEventBase(*this);
+}
+
+//---------------------------------------------------------
+// WaveEvent::mid
+//---------------------------------------------------------
+
+EventBase* WaveEventBase::mid(unsigned b, unsigned e)
+ {
+ WaveEventBase* ev = new WaveEventBase(*this);
+ unsigned fr = frame();
+ unsigned start = fr - b;
+ if(b > fr)
+ {
+ start = 0;
+ ev->setSpos(spos() + b - fr);
+ }
+ unsigned end = endFrame();
+
+ if (e < end)
+ end = e;
+
+ ev->setFrame(start);
+ ev->setLenFrame(end - b - start);
+ return ev;
+ }
+
+//---------------------------------------------------------
+// dump
+//---------------------------------------------------------
+
+void WaveEventBase::dump(int n) const
+ {
+ EventBase::dump(n);
+ }
+
+//---------------------------------------------------------
+// WaveEventBase::read
+//---------------------------------------------------------
+
+void WaveEventBase::read(Xml& xml)
+ {
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ case Xml::Attribut:
+ return;
+ case Xml::TagStart:
+ if (tag == "poslen")
+ PosLen::read(xml, "poslen");
+ else if (tag == "frame")
+ _spos = xml.parseInt();
+ else if (tag == "file") {
+ SndFile* wf = getWave(xml.parse1(), true);
+ if (wf) {
+ f = SndFileR(wf);
+ }
+ }
+ else
+ xml.unknown("Event");
+ break;
+ case Xml::TagEnd:
+ if (tag == "event") {
+ Pos::setType(FRAMES); // DEBUG
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// write
+//---------------------------------------------------------
+
+//void WaveEventBase::write(int level, Xml& xml, const Pos& offset) const
+void WaveEventBase::write(int level, Xml& xml, const Pos& offset, bool forcePath) const
+ {
+ if (f.isNull())
+ return;
+ xml.tag(level++, "event");
+ PosLen wpos(*this);
+ wpos += offset;
+// if (offset)
+// wpos.setTick(wpos.tick() + offset);
+ wpos.write(level, xml, "poslen");
+ xml.intTag(level, "frame", _spos); // offset in wave file
+
+ //
+ // waves in the project dirctory are stored
+ // with relative path name, others with absolute path
+ //
+ QString path = f.dirPath();
+
+ //if (path.contains(museProject)) {
+ if (!forcePath && path.contains(museProject)) {
+ // extract museProject.
+ QString newName = f.path().remove(museProject+"/");
+ xml.strTag(level, "file", newName);
+ }
+ else
+ xml.strTag(level, "file", f.path());
+ xml.etag(level, "event");
+ }
+
+//void WaveEventBase::read(unsigned offset, float** buffer, int channel, int n, bool overwrite)
+//void WaveEventBase::readAudio(unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+//off_t WaveEventBase::readAudio(SRC_STATE* src_state, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+//off_t WaveEventBase::readAudio(AudioConverter* audConv, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+// p3.3.33
+void WaveEventBase::readAudio(WavePart* part, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+{
+ // Added by Tim. p3.3.17
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio audConv:%p sfCurFrame:%ld offset:%u channel:%d n:%d\n", audConv, sfCurFrame, offset, channel, n);
+ #endif
+
+ // Changed by Tim. p3.3.18
+ #ifdef USE_SAMPLERATE
+
+ // TODO:
+ >>>>>>>>>>>+++++++++++++++++++++++++++++
+ // If we have a valid audio converter then use it to do the processing. Otherwise just a normal seek + read.
+ if(audConv)
+ //sfCurFrame = audConv->process(f, sfCurFrame, offset + _spos, buffer, channel, n, doSeek, overwrite);
+ sfCurFrame = audConv->readAudio(f, sfCurFrame, offset, buffer, channel, n, doSeek, overwrite);
+ else
+ {
+ if(!f.isNull())
+ {
+ sfCurFrame = f.seek(offset + _spos, 0);
+ sfCurFrame += f.read(channel, buffer, n, overwrite);
+ }
+ }
+ //return sfCurFrame;
+ return;
+
+ /*
+ unsigned fsrate = f.samplerate();
+ int fchan = f.channels();
+ off_t frame = offset + _spos;
+ //bool resample = src_state && ((unsigned)sampleRate != fsrate);
+ bool resample = audConv && audConv->isValid() && ((unsigned)sampleRate != fsrate);
+
+ // Is a 'transport' seek requested? (Not to be requested with every read! Should only be for 'first read' seeks, or positional 'transport' seeks.)
+ // Due to the support of sound file references in MusE, seek must ALWAYS be done before read, as before,
+ // except now we alter the seek position if sample rate conversion is being used and remember the seek positions.
+ if(doSeek)
+ {
+ if(!resample)
+ {
+ // Sample rates are the same. Just a regular seek, no conversion.
+ sfCurFrame = f.seek(frame, 0);
+ }
+ else
+ {
+ // Sample rates are different. Seek to a calculated 'sample rate ratio factored' position.
+
+ double srcratio = (double)fsrate / (double)sampleRate;
+ //long inSize = long((double)frames * _src_ratio) + 1 // From MusE-2 file converter.
+ off_t newfr = (off_t)floor(((double)frame * srcratio)); // From simplesynth.
+
+ //_sfCurFrame = sf_seek(sf, newfr, 0);
+ sfCurFrame = f.seek(newfr, 0);
+
+ // Added by Tim. p3.3.17
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio Seek frame:%ld converted to frame:%ld _sfCurFrame:%ld\n", frame, newfr, sfCurFrame);
+ #endif
+
+ // Reset the src converter. It's current state is meaningless now.
+ //int srcerr = src_reset(src_state);
+ int srcerr = audConv->reset();
+ if(srcerr != 0)
+ printf("WaveEventBase::readAudio Converter reset failed: %s\n", src_strerror(srcerr));
+ }
+ }
+ else
+ {
+ // No seek requested. Are the rates the same?
+ if(!resample)
+ // Sample rates are the same. Just a regular seek, no conversion.
+ sfCurFrame = f.seek(frame, 0);
+ else
+ {
+ // Added by Tim. p3.3.17
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio No 'transport' seek, rates different. Seeking to _sfCurFrame:%ld\n", sfCurFrame);
+ #endif
+
+ // Sample rates are different. We can't just tell seek to go to an absolute calculated position,
+ // since the last position can vary - it might not be what the calculated position is.
+ // We must use the last position left by SRC conversion, ie. let the file position progress on its own.
+ sfCurFrame = f.seek(sfCurFrame, 0);
+ }
+ }
+
+ // Do we not need to resample?
+ if(!resample)
+ {
+ return sfCurFrame + f.read(channel, buffer, n, overwrite);
+ }
+
+ size_t rn;
+
+ if((sampleRate == 0) || (fsrate == 0))
+ {
+ if(debugMsg)
+ printf("WaveEventBase::readAudio Using SRC: Error: sampleRate or file samplerate is zero!\n");
+ return sfCurFrame;
+ }
+
+ // Ratio is defined as output sample rate over input samplerate.
+ double srcratio = (double)sampleRate / (double)fsrate;
+ long outFrames = n;
+ //long outSize = outFrames * channel;
+ long outSize = outFrames * fchan;
+
+ //long inSize = long(outSize * srcratio) + 1 // From MusE-2 file converter.
+ //long inSize = (long)floor(((double)outSize / srcratio)); // From simplesynth.
+ //long inFrames = (long)floor(((double)outFrames / srcratio)); // From simplesynth.
+ long inFrames = (long)ceil(((double)outFrames / srcratio)); // From simplesynth.
+ //long inFrames = (long)floor(double(outFrames * sfinfo.samplerate) / double(sampleRate)); // From simplesynth.
+
+ // Extra input compensation - sometimes src requires more input frames than expected in order to
+ // always get a reliable number of used out frames !
+ //inFrames = inFrames / (srcratio / 2.0);
+ long inComp = 10;
+ inFrames += inComp;
+
+ long inSize = inFrames * fchan;
+ //long inSize = inFrames * channel;
+
+ float inbuffer[inSize];
+ float outbuffer[outSize];
+
+ //float* poutbuf;
+
+ // If the number of file channels is the same as the process channels AND we want overwrite, we can get away with direct copying.
+ //if(overwrite && channel == fchan)
+ // Point the out buffer directly at the return buffers.
+ // poutbuf = buffer;
+ //else
+ // Point the out buffer at our local buffers.
+ // poutbuf = &outbuffer[0];
+
+ // Converter channels are fixed at creation time! Can't change them on the fly. Can't use 'channel' paramter.
+ //rn = f.read(inbuffer, inFrames);
+ rn = f.readDirect(inbuffer, inFrames);
+
+ // convert
+ SRC_DATA srcdata;
+ srcdata.data_in = inbuffer;
+ srcdata.data_out = outbuffer;
+ //srcdata.data_out = poutbuf;
+ //srcdata.input_frames = inSize;
+ srcdata.input_frames = rn;
+ srcdata.output_frames = outFrames;
+ srcdata.end_of_input = ((long)rn != inFrames);
+ srcdata.src_ratio = srcratio;
+
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio %s processing converter... inFrames:%ld inSize:%ld outFrames:%ld outSize:%ld rn:%d",
+ f.name().latin1(), inFrames, inSize, outFrames, outSize, rn);
+ #endif
+
+ //int srcerr = src_process(src_state, &srcdata);
+ int srcerr = audConv->process(&srcdata);
+ if(srcerr != 0)
+ {
+ printf("\nWaveEventBase::readAudio SampleRate converter process failed: %s\n", src_strerror(srcerr));
+ return sfCurFrame += rn;
+ }
+
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf(" frames used in:%ld out:%ld\n", srcdata.input_frames_used, srcdata.output_frames_gen);
+ #endif
+
+ // If the number of frames read by the soundfile equals the input frames, go back.
+ // Otherwise we have reached the end of the file, so going back is useless since
+ // there shouldn't be any further calls. (Definitely get buffer underruns if further calls!)
+ if((long)rn == inFrames)
+ {
+ // Go back by the amount of unused frames.
+ sf_count_t seekn = inFrames - srcdata.input_frames_used;
+ if(seekn != 0)
+ {
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio Seek-back by:%d\n", seekn);
+ #endif
+ sfCurFrame = f.seek(-seekn, SEEK_CUR);
+ }
+ else
+ sfCurFrame += rn;
+ }
+ else
+ sfCurFrame += rn;
+
+ if(debugMsg)
+ {
+ if(srcdata.output_frames_gen != outFrames)
+ printf("WaveEventBase::readAudio %s output_frames_gen:%ld != outFrames:%ld outSize:%ld inFrames:%ld srcdata.input_frames_used:%ld inSize:%ld rn:%d\n",
+ f.name().latin1(), srcdata.output_frames_gen, outFrames, outSize, inFrames, srcdata.input_frames_used, inSize, rn);
+ }
+
+ if(inFrames != (long)rn)
+ {
+ if(debugMsg)
+ printf("WaveEventBase::readAudio %s rn:%zd != inFrames:%ld output_frames_gen:%ld outFrames:%ld outSize:%ld srcdata.input_frames_used:%ld inSize:%ld\n",
+ f.name().latin1(), rn, inFrames, srcdata.output_frames_gen, outFrames, outSize, srcdata.input_frames_used, inSize);
+
+ // We've reached the end of the file. Convert the number of frames read.
+ //rn = (double)rn * srcratio + 1;
+ rn = (long)floor((double)rn * srcratio);
+ if(rn > (size_t)outFrames)
+ rn = outFrames;
+ }
+ else
+ if(srcdata.output_frames_gen != outFrames)
+ {
+ // SRC didn't give us the number of frames we requested.
+ // This can occasionally be radically different from the requested frames, or zero,
+ // even when ample excess input frames are supplied.
+ // We're not done converting yet - we haven't reached the end of the file.
+ // We must do something with the buffer. So let's zero whatever SRC didn't fill.
+ // FIXME: Instead of zeroing, try processing more input data until the out buffer is full.
+ long b = srcdata.output_frames_gen * channel;
+ long e = outFrames * channel;
+ for(long i = b; i < e; ++i)
+ outbuffer[i] = 0.0f;
+ //poutbuf[i] = 0.0f;
+ rn = outFrames;
+ }
+ else
+ rn = outFrames;
+
+ float* poutbuf = &outbuffer[0];
+ if(fchan == channel)
+ {
+ if(overwrite)
+ for (size_t i = 0; i < rn; ++i)
+ {
+ for(int ch = 0; ch < channel; ++ch)
+ *(buffer[ch] + i) = *poutbuf++;
+ }
+ else
+ for(size_t i = 0; i < rn; ++i)
+ {
+ for(int ch = 0; ch < channel; ++ch)
+ *(buffer[ch] + i) += *poutbuf++;
+ }
+ }
+ else if((fchan == 2) && (channel == 1))
+ {
+ // stereo to mono
+ if(overwrite)
+ for(size_t i = 0; i < rn; ++i)
+ *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1];
+ else
+ for(size_t i = 0; i < rn; ++i)
+ *(buffer[0] + i) += poutbuf[i + i] + poutbuf[i + i + 1];
+ }
+ else if((fchan == 1) && (channel == 2))
+ {
+ // mono to stereo
+ if(overwrite)
+ for(size_t i = 0; i < rn; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) = data;
+ *(buffer[1]+i) = data;
+ }
+ else
+ for(size_t i = 0; i < rn; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) += data;
+ *(buffer[1]+i) += data;
+ }
+ }
+ else
+ {
+ if(debugMsg)
+ printf("WaveEventBase::readAudio Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel);
+ }
+
+ return sfCurFrame;
+ */
+
+
+ #else
+ if(f.isNull())
+ return;
+ //return sfCurFrame;
+
+ //sfCurFrame = f.seek(offset + _spos, 0);
+ //sfCurFrame += f.read(channel, buffer, n, overwrite);
+ f.seek(offset + _spos, 0);
+ f.read(channel, buffer, n, overwrite);
+
+ // p3.3.41
+ //fprintf(stderr, "WaveEventBase::readAudio data: n:%ld %e %e %e %e\n", n, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]);
+
+
+ //return sfCurFrame;
+ return;
+ #endif
+
+}
+