summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2010-01-06 09:27:34 +0000
committerTim E. Real <termtech@rogers.com>2010-01-06 09:27:34 +0000
commit9eabbfa460b5e4a2f24ace6146df6df59ddcfdbd (patch)
tree16eb2e743ef4c61f7da0c7f84fdb2235ab1c6de2
parent9f66d4ea7410ac4bca7a03498f3e13bab9df83c0 (diff)
See ChangeLog
-rw-r--r--muse/ChangeLog4
-rw-r--r--muse/muse/Makefile.am1
-rw-r--r--muse/muse/audio.cpp25
-rw-r--r--muse/muse/audioconvert.cpp836
-rw-r--r--muse/muse/audioconvert.h95
-rw-r--r--muse/muse/audioprefetch.cpp57
-rw-r--r--muse/muse/audioprefetch.h6
-rw-r--r--muse/muse/conf.cpp4
-rw-r--r--muse/muse/driver/jack.cpp218
-rw-r--r--muse/muse/driver/jackaudio.h8
-rw-r--r--muse/muse/event.cpp122
-rw-r--r--muse/muse/event.h10
-rw-r--r--muse/muse/eventbase.h12
-rw-r--r--muse/muse/midiport.cpp14
-rw-r--r--muse/muse/sync.cpp1
-rw-r--r--muse/muse/sync.h1
-rw-r--r--muse/muse/thread.cpp5
-rw-r--r--muse/muse/wave.cpp187
-rw-r--r--muse/muse/wave.h8
-rw-r--r--muse/muse/waveevent.cpp304
-rw-r--r--muse/muse/waveevent.h12
-rw-r--r--muse/muse/widgets/citem.cpp4
-rw-r--r--muse/muse/widgets/citem.h4
-rw-r--r--muse/muse/widgets/midisync.ui93
-rw-r--r--muse/muse/widgets/midisyncimpl.cpp17
25 files changed, 1762 insertions, 286 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index 90cdb908..efadbae6 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,7 @@
+06.01.2010
+ * Feature: Jack transport enable/disable in Midi Sync settings window. Stores setting per-song. (T356)
+ - Should be Ok to use and test. Needs a bit more work. See jack.cpp and jackaudio.h
+ * Fixed: Speedups of audio pre-fetch especially when moving the cursor around (seeking). (T356)
23.12.2009:
* Added: DeicsOnze2 initial import. (ng)
* Fix: deicsonzepreset.cpp for Xml muse 1 API
diff --git a/muse/muse/Makefile.am b/muse/muse/Makefile.am
index c08031ee..c58f20ff 100644
--- a/muse/muse/Makefile.am
+++ b/muse/muse/Makefile.am
@@ -39,6 +39,7 @@ dist_muse_SOURCES = \
thread.cpp thread.h \
audio.cpp audio.h \
audioprefetch.cpp audioprefetch.h \
+ audioconvert.cpp audioconvert.h \
globals.cpp globals.h \
sync.cpp sync.h \
midiport.cpp midiport.h \
diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp
index 02a3c549..9a716054 100644
--- a/muse/muse/audio.cpp
+++ b/muse/muse/audio.cpp
@@ -227,7 +227,10 @@ void Audio::stop(bool)
bool Audio::sync(int jackState, unsigned frame)
{
-// printf("sync state %s jackState %s frame %d\n", audioStates[state], audioStates[jackState], frame);
+ // Added by Tim. p3.3.20
+ if(debugMsg)
+ printf("Audio::sync state %s jackState %s frame %d\n", audioStates[state], audioStates[jackState], frame);
+
bool done = true;
if (state == LOOP1)
state = LOOP2;
@@ -238,8 +241,14 @@ bool Audio::sync(int jackState, unsigned frame)
}
state = State(jackState);
if (!_freewheel)
- done = audioPrefetch->seekDone;
+ //done = audioPrefetch->seekDone;
+ done = audioPrefetch->seekDone();
}
+
+ // Added by Tim. p3.3.20
+ //if(debugMsg)
+ // printf("Audio::sync done:%d state %s\n", done, audioStates[state]);
+
return done;
}
@@ -296,6 +305,10 @@ void Audio::process(unsigned frames)
int jackState = audioDevice->getState();
+ // Added by Tim. p3.3.20
+ //if(debugMsg)
+ // printf("Audio::process Current state:%s jackState:%s\n", audioStates[state], audioStates[jackState]);
+
if (state == START_PLAY && jackState == PLAY) {
_loopCount = 0;
startRolling();
@@ -367,6 +380,10 @@ void Audio::process(unsigned frames)
&& !(song->record()
|| _bounce
|| song->loop())) {
+ // Added by Tim. p3.3.20
+ //if(debugMsg)
+ // printf("Audio::process curTickPos >= song->len\n");
+
audioDevice->stopTransport();
return;
}
@@ -1026,6 +1043,10 @@ void Audio::startRolling()
void Audio::stopRolling()
{
+ // Added by Tim. p3.3.20
+ //if(debugMsg)
+ // printf("Audio::stopRolling state %s\n", audioStates[state]);
+
state = STOP;
midiSeq->msgStop();
diff --git a/muse/muse/audioconvert.cpp b/muse/muse/audioconvert.cpp
new file mode 100644
index 00000000..47159140
--- /dev/null
+++ b/muse/muse/audioconvert.cpp
@@ -0,0 +1,836 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: audioconvert.cpp,v 1.1.1.1 2009/12/28 16:07:33 terminator356 Exp $
+//
+// (C) Copyright 1999-2009 Werner Schweer (ws@seh.de)
+//
+// Audio converter module created by Tim terminator356
+//=========================================================
+
+#include <math.h>
+
+#include "wave.h"
+#include "globals.h"
+#include "audioconvert.h"
+
+//#define AUDIOCONVERT_DEBUG
+//#define AUDIOCONVERT_DEBUG_PRC
+
+//---------------------------------------------------------
+// AudioConverter
+//---------------------------------------------------------
+
+AudioConverter::AudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::AudioConverter this:%p\n", this);
+ #endif
+
+ _refCount = 1;
+}
+
+AudioConverter::~AudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::~AudioConverter this:%p\n", this);
+ #endif
+}
+
+AudioConverter* AudioConverter::reference()
+{
+ _refCount += 1;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::reference this:%p current refcount:%d\n", this, _refCount);
+ #endif
+ return this;
+}
+
+AudioConverter* AudioConverter::release(AudioConverter* cv)
+{
+ if(!cv)
+ return 0;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::release converter:%p\n", cv);
+ #endif
+ //if(cv->incRefCount(-1) <= 0)
+ if((cv->_refCount -= 1) <= 0)
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::release deleting converter:%p\n", cv);
+ #endif
+ delete cv;
+ cv = 0;
+ }
+ return cv;
+}
+
+off_t AudioConverter::readAudio(SndFileR& f, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+{
+ if(f.isNull())
+ return sfCurFrame;
+
+ // Added by Tim. p3.3.17
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n",
+ // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n);
+ //#endif
+
+ off_t frame = offset; // _spos is added before the call.
+ unsigned fsrate = f.samplerate();
+ bool resample = isValid() && ((unsigned)sampleRate != fsrate);
+
+ // No resampling needed?
+ if(!resample)
+ {
+ // Sample rates are the same. Just a regular seek + read, no conversion.
+ sfCurFrame = f.seek(frame, 0);
+ return sfCurFrame + f.read(channel, buffer, n, overwrite);
+ }
+
+ // 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)
+ {
+ // 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 = f.seek(newfr, 0);
+
+ // Added by Tim. p3.3.17
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process Seek frame:%ld converted to frame:%ld sfCurFrame:%ld\n", frame, newfr, sfCurFrame);
+ //#endif
+
+ // Reset the converter. Its current state is meaningless now.
+ reset();
+ }
+ else
+ {
+ // No seek requested.
+ // Added by Tim. p3.3.17
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process 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);
+ }
+
+ /*
+ int fchan = f.channels();
+ long outFrames = n;
+ long outSize = outFrames * fchan;
+ float outbuffer[outSize];
+ */
+
+ //sfCurFrame = process(f, sfCurFrame, offset, &outbuffer[0], channel, n);
+// sfCurFrame = process(f, sfCurFrame, outbuffer, channel, n);
+ sfCurFrame = process(f, sfCurFrame, buffer, channel, n, overwrite);
+
+ /*
+ float* poutbuf = &outbuffer[0];
+ if(fchan == channel)
+ {
+ if(overwrite)
+ //for (size_t i = 0; i < rn; ++i)
+ for (int i = 0; i < n; ++i)
+ {
+ for(int ch = 0; ch < channel; ++ch)
+ *(buffer[ch] + i) = *poutbuf++;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1];
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) = data;
+ *(buffer[1]+i) = data;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) += data;
+ *(buffer[1]+i) += data;
+ }
+ }
+ else
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("AudioConverter::readAudio Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel);
+ #endif
+ }
+ */
+
+ return sfCurFrame;
+}
+
+//---------------------------------------------------------
+// SRCAudioConverter
+//---------------------------------------------------------
+
+SRCAudioConverter::SRCAudioConverter(int channels, int type) : AudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::SRCAudioConverter this:%p channels:%d type:%d\n", this, channels, type);
+ #endif
+
+ _type = type;
+ _src_state = 0;
+ _channels = channels;
+
+ int srcerr;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::SRCaudioConverter Creating samplerate converter type:%d with %d channels\n", _type, _channels);
+ #endif
+ _src_state = src_new(_type, _channels, &srcerr);
+ if(!_src_state)
+ printf("SRCAudioConverter::SRCaudioConverter Creation of samplerate converter type:%d with %d channels failed:%s\n", _type, _channels, src_strerror(srcerr));
+}
+
+SRCAudioConverter::~SRCAudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::~SRCAudioConverter this:%p\n", this);
+ #endif
+ if(_src_state)
+ src_delete(_src_state);
+}
+
+void SRCAudioConverter::setChannels(int ch)
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::setChannels this:%p channels:%d\n", this, ch);
+ #endif
+ if(_src_state)
+ src_delete(_src_state);
+ _src_state = 0;
+
+ _channels = ch;
+ int srcerr;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::setChannels Creating samplerate converter type:%d with %d channels\n", _type, ch);
+ #endif
+ _src_state = src_new(_type, ch, &srcerr);
+ if(!_src_state)
+ printf("SRCAudioConverter::setChannels of samplerate converter type:%d with %d channels failed:%s\n", _type, ch, src_strerror(srcerr));
+ return;
+}
+
+void SRCAudioConverter::reset()
+{
+ if(!_src_state)
+ return;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::reset this:%p\n", this);
+ #endif
+ int srcerr = src_reset(_src_state);
+ if(srcerr != 0)
+ printf("SRCAudioConverter::reset Converter reset failed: %s\n", src_strerror(srcerr));
+ return;
+}
+
+off_t SRCAudioConverter::process(SndFileR& f, off_t sfCurFrame, float** buffer, int channel, int n, bool overwrite)
+{
+ //return src_process(_src_state, sd);
+
+ if(f.isNull())
+ //return;
+ return sfCurFrame;
+
+ // Added by Tim. p3.3.17
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n",
+ // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n);
+ //#endif
+
+// off_t frame = offset; // _spos is added before the call.
+ unsigned fsrate = f.samplerate();
+ //bool resample = src_state && ((unsigned)sampleRate != fsrate);
+// bool resample = isValid() && ((unsigned)sampleRate != fsrate);
+
+ if((sampleRate == 0) || (fsrate == 0))
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::process Error: sampleRate or file samplerate is zero!\n");
+ #endif
+ return sfCurFrame;
+ }
+
+ SRC_DATA srcdata;
+ int fchan = f.channels();
+ // Ratio is defined as output sample rate over input samplerate.
+ double srcratio = (double)sampleRate / (double)fsrate;
+ // Extra input compensation.
+ long inComp = 1;
+
+ 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)) + inComp; // From simplesynth.
+ //long inFrames = (long)floor(double(outFrames * sfinfo.samplerate) / double(sampleRate)); // From simplesynth.
+
+ long inSize = inFrames * fchan;
+ //long inSize = inFrames * channel;
+
+ // Start with buffers at expected sizes. We won't need anything larger than this, but add 4 for good luck.
+ float inbuffer[inSize + 4];
+ float outbuffer[outSize];
+
+ //size_t sfTotalRead = 0;
+ size_t rn = 0;
+ long totalOutFrames = 0;
+
+ srcdata.data_in = inbuffer;
+ srcdata.data_out = outbuffer;
+// srcdata.data_out = buffer;
+
+ // Set some kind of limit on the number of attempts to completely fill the output buffer,
+ // in case something is really screwed up - we don't want to get stuck in a loop here.
+ int attempts = 10;
+ for(int attempt = 0; attempt < attempts; ++attempt)
+ {
+ rn = f.readDirect(inbuffer, inFrames);
+ //sfTotalRead += rn;
+
+ // convert
+ //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 AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process attempt:%d inFrames:%ld outFrames:%ld rn:%d data in:%p out:%p",
+ // attempt, inFrames, outFrames, rn, srcdata.data_in, srcdata.data_out);
+ //#endif
+
+ int srcerr = src_process(_src_state, &srcdata);
+ if(srcerr != 0)
+ {
+ printf("\nSRCAudioConverter::process SampleRate converter process failed: %s\n", src_strerror(srcerr));
+ return sfCurFrame += rn;
+ }
+
+ totalOutFrames += srcdata.output_frames_gen;
+
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf(" frames used in:%ld out:%ld totalOutFrames:%ld data in:%p out:%p\n", srcdata.input_frames_used, srcdata.output_frames_gen, totalOutFrames, srcdata.data_in, srcdata.data_out);
+ //#endif
+
+ #ifdef AUDIOCONVERT_DEBUG
+ if(srcdata.output_frames_gen != outFrames)
+ printf("SRCAudioConverter::process %s output_frames_gen:%ld != outFrames:%ld inFrames:%ld srcdata.input_frames_used:%ld rn:%d\n",
+ f.name().latin1(), srcdata.output_frames_gen, outFrames, inFrames, srcdata.input_frames_used, rn);
+ #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.
+ 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 AUDIOCONVERT_DEBUG_PRC
+ printf("SRCAudioConverter::process Seek-back by:%d\n", seekn);
+ #endif
+ sfCurFrame = f.seek(-seekn, SEEK_CUR);
+ }
+ else
+ sfCurFrame += rn;
+
+ if(totalOutFrames == n)
+ {
+ // We got our desired number of output frames. Stop attempting.
+ break;
+ }
+ else
+ {
+ // No point in continuing if on last attempt.
+ if(attempt == (attempts - 1))
+ break;
+
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::process %s attempt:%d totalOutFrames:%ld != n:%d try again\n", f.name().latin1(), attempt, totalOutFrames, n);
+ #endif
+
+ // 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.
+ // Move the src output pointer to a new position.
+ srcdata.data_out += srcdata.output_frames_gen * channel;
+ // Set new number of maximum out frames.
+ outFrames -= srcdata.output_frames_gen;
+ // Calculate the new number of file input frames required.
+ inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp;
+ // Keep trying.
+ continue;
+ }
+ }
+ else
+ {
+ sfCurFrame += rn;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::process %s rn:%zd != inFrames:%ld output_frames_gen:%ld outFrames:%ld srcdata.input_frames_used:%ld\n",
+ f.name().latin1(), rn, inFrames, srcdata.output_frames_gen, outFrames, srcdata.input_frames_used);
+ #endif
+
+ // 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;
+ // Stop attempting.
+ break;
+ }
+ }
+
+ // If we still didn't get the desired number of output frames.
+ if(totalOutFrames != n)
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::process %s totalOutFrames:%ld != n:%d\n", f.name().latin1(), totalOutFrames, n);
+ #endif
+
+ // Let's zero the rest of it.
+ long b = totalOutFrames * channel;
+ long e = n * channel;
+ for(long i = b; i < e; ++i)
+ outbuffer[i] = 0.0f;
+ //buffer[i] = 0.0f;
+ }
+
+ //float* poutbuf = &outbuffer[0];
+ float* poutbuf = outbuffer;
+ if(fchan == channel)
+ {
+ if(overwrite)
+ //for (size_t i = 0; i < rn; ++i)
+ for (int i = 0; i < n; ++i)
+ {
+ for(int ch = 0; ch < channel; ++ch)
+ *(buffer[ch] + i) = *poutbuf++;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1];
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) = data;
+ *(buffer[1]+i) = data;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) += data;
+ *(buffer[1]+i) += data;
+ }
+ }
+ else
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("SRCAudioConverter::process Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel);
+ #endif
+ }
+
+ return sfCurFrame;
+}
+
+#ifdef RUBBERBAND_SUPPORT
+
+//---------------------------------------------------------
+// RubberBandAudioConverter
+//---------------------------------------------------------
+
+RubberBandAudioConverter::RubberBandAudioConverter(int channels, int options) : AudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::RubberBandAudioConverter this:%p channels:%d options:%x\n", this, channels, options);
+ #endif
+
+ _options = options;
+ _rbs = 0;
+ _channels = channels;
+
+ _rbs = new RubberBandStretcher(sampleRate, _channels, _options); // , initialTimeRatio = 1.0, initialPitchScale = 1.0
+}
+
+RubberBandAudioConverter::~RubberBandAudioConverter()
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::~RubberBandAudioConverter this:%p\n", this);
+ #endif
+ if(_rbs)
+ delete _rbs;
+}
+
+void RubberBandAudioConverter::setChannels(int ch)
+{
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::setChannels this:%p channels:%d\n", this, ch);
+ #endif
+ if(_rbs)
+ delete _rbs;
+ _rbs = 0;
+
+ _channels = ch;
+ _rbs = new RubberBandStretcher(sampleRate, _channels, _options); // , initialTimeRatio = 1.0, initialPitchScale = 1.0
+}
+
+void RubberBandAudioConverter::reset()
+{
+ if(!_rbs)
+ return;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::reset this:%p\n", this);
+ #endif
+ _rbs->reset();
+ return;
+}
+
+/////////////////////////////////
+// TODO: Not finished yet..
+////////////////////////////////
+off_t RubberBandAudioConverter::process(SndFileR& f, off_t sfCurFrame, float** buffer, int channel, int n, bool overwrite)
+{
+ //return src_process(_src_state, sd);
+
+ if(f.isNull())
+ //return;
+ return sfCurFrame;
+
+ // Added by Tim. p3.3.17
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n",
+ // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n);
+ //#endif
+
+// off_t frame = offset; // _spos is added before the call.
+ unsigned fsrate = f.samplerate();
+ //bool resample = src_state && ((unsigned)sampleRate != fsrate);
+// bool resample = isValid() && ((unsigned)sampleRate != fsrate);
+
+ if((sampleRate == 0) || (fsrate == 0))
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::process Error: sampleRate or file samplerate is zero!\n");
+ #endif
+ return sfCurFrame;
+ }
+
+// SRC_DATA srcdata;
+ int fchan = f.channels();
+ // Ratio is defined as output sample rate over input samplerate.
+ double srcratio = (double)sampleRate / (double)fsrate;
+ // Extra input compensation.
+ long inComp = 1;
+
+ 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)) + inComp; // From simplesynth.
+ //long inFrames = (long)floor(double(outFrames * sfinfo.samplerate) / double(sampleRate)); // From simplesynth.
+
+ long inSize = inFrames * fchan;
+ //long inSize = inFrames * channel;
+
+ // Start with buffers at expected sizes. We won't need anything larger than this, but add 4 for good luck.
+ float inbuffer[inSize]; // +4
+// float outbuffer[outSize];
+
+ //float* rbinbuffer[fchan];
+ //float rbindata[inSize];
+ //for (int i = 0; i < fchan; ++i)
+ // rbinbuffer[i] = rbindata + i * inFrames;
+
+ float* rboutbuffer[fchan];
+ float rboutdata[outSize];
+ for (int i = 0; i < fchan; ++i)
+ rboutbuffer[i] = rboutdata + i * outFrames;
+
+ //size_t sfTotalRead = 0;
+ size_t rn = 0;
+ long totalOutFrames = 0;
+
+// srcdata.data_in = inbuffer;
+ //srcdata.data_out = outbuffer;
+// srcdata.data_out = buffer;
+ float** data_out = rboutbuffer;
+
+ // For just sample rate conversion, apply same ratio to both time and pitch.
+ _rbs->setTimeRatio(srcratio);
+ _rbs->setPitchScale(srcratio);
+
+ // Set some kind of limit on the number of attempts to completely fill the output buffer,
+ // in case something is really screwed up - we don't want to get stuck in a loop here.
+ int attempts = 10;
+ for(int attempt = 0; attempt < attempts; ++attempt)
+ {
+ size_t sreq = _rbs->getSamplesRequired();
+
+ size_t rbinSize = sreq * fchan;
+ float* rbinbuffer[fchan];
+ float rbindata[rbinSize];
+ for(int i = 0; i < fchan; ++i)
+ rbinbuffer[i] = rbindata + i * sreq;
+
+// rn = f.readDirect(inbuffer, inFrames);
+ rn = f.readDirect(inbuffer, sreq);
+ //sfTotalRead += rn;
+
+ // Must de-interleave soundfile data to feed to rubberband.
+ for(size_t i = 0; i < rn; ++i)
+ {
+ for(int ch = 0; ch < fchan; ++ch)
+ *(rbinbuffer[ch] + i) = *inbuffer++;
+ }
+
+ _rbs->process(rbinbuffer, rn, (long)rn != inFrames);
+
+ // "This function returns -1 if all data has been fully processed and all output read, and the stretch process is now finished."
+ int savail = _rbs->available();
+
+
+ // convert
+ //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 AUDIOCONVERT_DEBUG_PRC
+ //printf("AudioConverter::process attempt:%d inFrames:%ld outFrames:%ld rn:%d data in:%p out:%p",
+ // attempt, inFrames, outFrames, rn, srcdata.data_in, srcdata.data_out);
+ //#endif
+
+ int srcerr = src_process(_src_state, &srcdata);
+ if(srcerr != 0)
+ {
+ printf("\RubberBandAudioConverter::process SampleRate converter process failed: %s\n", src_strerror(srcerr));
+ return sfCurFrame += rn;
+ }
+
+ totalOutFrames += srcdata.output_frames_gen;
+
+ //#ifdef AUDIOCONVERT_DEBUG_PRC
+ //printf(" frames used in:%ld out:%ld totalOutFrames:%ld data in:%p out:%p\n", srcdata.input_frames_used, srcdata.output_frames_gen, totalOutFrames, srcdata.data_in, srcdata.data_out);
+ //#endif
+
+ #ifdef AUDIOCONVERT_DEBUG
+ if(srcdata.output_frames_gen != outFrames)
+ printf("RubberBandAudioConverter::process %s output_frames_gen:%ld != outFrames:%ld inFrames:%ld srcdata.input_frames_used:%ld rn:%d\n",
+ f.name().latin1(), srcdata.output_frames_gen, outFrames, inFrames, srcdata.input_frames_used, rn);
+ #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.
+ 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 AUDIOCONVERT_DEBUG_PRC
+ printf("RubberBandAudioConverter::process Seek-back by:%d\n", seekn);
+ #endif
+ sfCurFrame = f.seek(-seekn, SEEK_CUR);
+ }
+ else
+ sfCurFrame += rn;
+
+ if(totalOutFrames == n)
+ {
+ // We got our desired number of output frames. Stop attempting.
+ break;
+ }
+ else
+ {
+ // No point in continuing if on last attempt.
+ if(attempt == (attempts - 1))
+ break;
+
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::process %s attempt:%d totalOutFrames:%ld != n:%d try again\n", f.name().latin1(), attempt, totalOutFrames, n);
+ #endif
+
+ // We didn't get 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.
+ // Move the src output pointer to a new position.
+ srcdata.data_out += srcdata.output_frames_gen * channel;
+ // Set new number of maximum out frames.
+ outFrames -= srcdata.output_frames_gen;
+ // Calculate the new number of file input frames required.
+ inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp;
+ // Keep trying.
+ continue;
+ }
+ }
+ else
+ {
+ sfCurFrame += rn;
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::process %s rn:%zd != inFrames:%ld output_frames_gen:%ld outFrames:%ld srcdata.input_frames_used:%ld\n",
+ f.name().latin1(), rn, inFrames, srcdata.output_frames_gen, outFrames, srcdata.input_frames_used);
+ #endif
+
+ // 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;
+ // Stop attempting.
+ break;
+ }
+ }
+
+ // If we still didn't get the desired number of output frames.
+ if(totalOutFrames != n)
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::process %s totalOutFrames:%ld != n:%d\n", f.name().latin1(), totalOutFrames, n);
+ #endif
+
+ // Let's zero the rest of it.
+ long b = totalOutFrames * channel;
+ long e = n * channel;
+ for(long i = b; i < e; ++i)
+ //outbuffer[i] = 0.0f;
+ buffer[i] = 0.0f;
+ }
+
+ //float* poutbuf = &outbuffer[0];
+ float* poutbuf = outbuffer;
+ if(fchan == channel)
+ {
+ if(overwrite)
+ //for (size_t i = 0; i < rn; ++i)
+ for (int i = 0; i < n; ++i)
+ {
+ for(int ch = 0; ch < channel; ++ch)
+ *(buffer[ch] + i) = *poutbuf++;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1];
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++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)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) = data;
+ *(buffer[1]+i) = data;
+ }
+ else
+ //for(size_t i = 0; i < rn; ++i)
+ for(int i = 0; i < n; ++i)
+ {
+ float data = *poutbuf++;
+ *(buffer[0]+i) += data;
+ *(buffer[1]+i) += data;
+ }
+ }
+ else
+ {
+ #ifdef AUDIOCONVERT_DEBUG
+ printf("RubberBandAudioConverter::process Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel);
+ #endif
+ }
+
+ return sfCurFrame;
+}
+
+#endif // RUBBERBAND_SUPPORT
diff --git a/muse/muse/audioconvert.h b/muse/muse/audioconvert.h
new file mode 100644
index 00000000..ca0c3f88
--- /dev/null
+++ b/muse/muse/audioconvert.h
@@ -0,0 +1,95 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: audioconvert.h,v 1.1.1.1 2009/12/28 16:07:33 terminator356 Exp $
+//
+// (C) Copyright 1999-2009 Werner Schweer (ws@seh.de)
+//
+// Audio converter module created by Tim terminator356
+//=========================================================
+
+#ifndef __AUDIOCONVERT_H__
+#define __AUDIOCONVERT_H__
+
+#ifdef RUBBERBAND_SUPPORT
+#include <RubberBandStretcher.h>
+#endif
+
+#include <samplerate.h>
+#include <sys/types.h>
+
+class SndFileR;
+
+//---------------------------------------------------------
+// AudioConverter
+//---------------------------------------------------------
+
+class AudioConverter
+{
+ int _refCount;
+
+ public:
+ AudioConverter();
+ ~AudioConverter();
+
+ AudioConverter* reference();
+ static AudioConverter* release(AudioConverter* cv);
+
+ off_t readAudio(SndFileR& /*sf*/, off_t /*sfCurFrame*/, unsigned /*offset*/, float** /*buffer*/,
+ int /*channels*/, int /*frames*/, bool /*doSeek*/, bool /*overwrite*/);
+
+ virtual bool isValid() = 0;
+ virtual void reset() = 0;
+ virtual void setChannels(int ch) = 0;
+ virtual off_t process(SndFileR& /*sf*/, off_t /*sfCurFrame*/, float** /*buffer*/,
+ int /*channels*/, int /*frames*/, bool /*overwrite*/) = 0; // Interleaved buffer if stereo.
+};
+
+//---------------------------------------------------------
+// SRCAudioConverter
+//---------------------------------------------------------
+
+class SRCAudioConverter : public AudioConverter
+{
+ int _type;
+ int _channels;
+ SRC_STATE* _src_state;
+
+ public:
+ SRCAudioConverter(int channels, int type);
+ ~SRCAudioConverter();
+
+ virtual bool isValid() { return _src_state != 0; }
+ virtual void reset();
+ virtual void setChannels(int ch);
+ virtual off_t process(SndFileR& /*sf*/, off_t /*sfCurFrame*/, float** /*buffer*/,
+ int /*channels*/, int /*frames*/, bool /*overwrite*/); // Interleaved buffer if stereo.
+};
+
+#ifdef RUBBERBAND_SUPPORT
+
+//---------------------------------------------------------
+// RubberBandAudioConverter
+//---------------------------------------------------------
+
+class RubberBandAudioConverter : public AudioConverter
+{
+ int _options;
+ int _channels;
+ RubberBandStretcher* _rbs;
+
+ public:
+ RubberBandAudioConverter(int channels, int options);
+ ~RubberBandAudioConverter();
+
+ virtual bool isValid() { return _rbs != 0; }
+ virtual void reset();
+ virtual void setChannels(int ch);
+ virtual off_t process(SndFileR& /*sf*/, off_t /*sfCurFrame*/, float** /*buffer*/,
+ int /*channels*/, int /*frames*/, bool /*overwrite*/); // Interleaved buffer if stereo.
+};
+
+#endif // RUBBERBAND_SUPPORT
+
+#endif
+
diff --git a/muse/muse/audioprefetch.cpp b/muse/muse/audioprefetch.cpp
index 99a64972..dbfbd614 100644
--- a/muse/muse/audioprefetch.cpp
+++ b/muse/muse/audioprefetch.cpp
@@ -18,6 +18,9 @@
#include "audio.h"
#include "sync.h"
+// Added by Tim. p3.3.20
+//#define AUDIOPREFETCH_DEBUG
+
enum { PREFETCH_TICK, PREFETCH_SEEK
};
@@ -42,7 +45,8 @@ AudioPrefetch::AudioPrefetch(const char* name)
{
seekPos = ~0;
writePos = ~0;
- seekDone = true;
+ //seekDone = true;
+ seekCount = 0;
}
//---------------------------------------------------------
@@ -97,6 +101,10 @@ void AudioPrefetch::processMsg1(const void* m)
seekPos = ~0; // invalidate cached last seek position
break;
case PREFETCH_SEEK:
+ #ifdef AUDIOPREFETCH_DEBUG
+ printf("AudioPrefetch::processMsg1 PREFETCH_SEEK msg->pos:%d\n", msg->pos);
+ #endif
+
// process seek in background
seek(msg->pos);
break;
@@ -126,10 +134,17 @@ void AudioPrefetch::msgTick()
void AudioPrefetch::msgSeek(unsigned samplePos, bool force)
{
if (samplePos == seekPos && !force) {
- seekDone = true;
+ //seekDone = true;
return;
}
- seekDone = false;
+
+ ++seekCount;
+ //seekDone = false;
+
+ #ifdef AUDIOPREFETCH_DEBUG
+ printf("AudioPrefetch::msgSeek samplePos:%u force:%d seekCount:%d\n", samplePos, force, seekCount);
+ #endif
+
PrefetchMsg msg;
msg.id = PREFETCH_SEEK;
msg.pos = samplePos;
@@ -147,7 +162,7 @@ void AudioPrefetch::msgSeek(unsigned samplePos, bool force)
void AudioPrefetch::prefetch(bool doSeek)
{
if (writePos == ~0U) {
- printf("prefetch(): invalid write position\n");
+ printf("AudioPrefetch::prefetch: invalid write position\n");
return;
}
if (song->loop() && !audio->bounce() && !extSyncFlag.value()) {
@@ -169,8 +184,7 @@ void AudioPrefetch::prefetch(bool doSeek)
float* bp[ch];
// printf("prefetch %d\n", writePos);
if (track->prefetchFifo()->getWriteBuffer(ch, segmentSize, bp, writePos)) {
- // Too many of these. Chokes muse. Turn on later. (muse works OK anyway).
- //printf("Prefetch: NO BUFFER\n");
+ printf("AudioPrefetch::prefetch No write buffer!\n");
continue;
}
//track->fetchData(writePos, segmentSize, bp);
@@ -186,6 +200,26 @@ void AudioPrefetch::prefetch(bool doSeek)
void AudioPrefetch::seek(unsigned seekTo)
{
// printf("seek %d\n", seekTo);
+ #ifdef AUDIOPREFETCH_DEBUG
+ printf("AudioPrefetch::seek to:%u seekCount:%d\n", seekTo, seekCount);
+ #endif
+
+ // Speedup: More than one seek message pending?
+ // Eat up seek messages until we get to the very LATEST one,
+ // because all the rest which came before it are irrelevant now,
+ // and processing them all was taking extreme time, especially with
+ // resampling enabled.
+ // In particular, when the user 'slides' the play cursor back and forth
+ // there are MANY seek messages in the pipe, and with resampling enabled
+ // it was taking minutes to finish seeking. If the user hit play during that time,
+ // things were messed up (FIFO underruns, choppy intermittent sound etc).
+ // Added by Tim. p3.3.20
+ if(seekCount > 1)
+ {
+ --seekCount;
+ return;
+ }
+
writePos = seekTo;
WaveTrackList* tl = song->waves();
for (iWaveTrack it = tl->begin(); it != tl->end(); ++it) {
@@ -202,9 +236,18 @@ void AudioPrefetch::seek(unsigned seekTo)
prefetch(isFirstPrefetch);
isFirstPrefetch = false;
+
+ // To help speed things up even more, check the count again. Return if more seek messages are pending.
+ // Added by Tim. p3.3.20
+ if(seekCount > 1)
+ {
+ --seekCount;
+ return;
+ }
}
seekPos = seekTo;
- seekDone = true;
+ //seekDone = true;
+ --seekCount;
}
diff --git a/muse/muse/audioprefetch.h b/muse/muse/audioprefetch.h
index ebd46c03..dda4d895 100644
--- a/muse/muse/audioprefetch.h
+++ b/muse/muse/audioprefetch.h
@@ -24,6 +24,8 @@ class AudioPrefetch : public Thread {
void prefetch(bool doSeek);
void seek(unsigned pos);
+ volatile int seekCount;
+
public:
//AudioPrefetch(int prio, const char* name);
AudioPrefetch(const char* name);
@@ -34,7 +36,9 @@ class AudioPrefetch : public Thread {
void msgTick();
void msgSeek(unsigned samplePos, bool force=false);
- volatile bool seekDone;
+
+ //volatile bool seekDone;
+ bool seekDone() const { return seekCount == 0; }
};
extern AudioPrefetch* audioPrefetch;
diff --git a/muse/muse/conf.cpp b/muse/muse/conf.cpp
index 9398a7d3..13ef712c 100644
--- a/muse/muse/conf.cpp
+++ b/muse/muse/conf.cpp
@@ -638,6 +638,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer)
mtcType= xml.parseInt();
else if (tag == "extSync")
extSyncFlag.setValue(xml.parseInt());
+ else if (tag == "useJackTransport")
+ useJackTransport = xml.parseInt();
else if (tag == "syncgentype") {
// for compatibility
//int syncGenType= xml.parseInt();
@@ -1058,6 +1060,7 @@ void MusE::writeGlobalConfiguration(int level, Xml& xml) const
xml.nput(level, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
mtcOffset.h(), mtcOffset.m(), mtcOffset.s(),
mtcOffset.f(), mtcOffset.sf());
+ //xml.intTag(level, "useJackTransport", useJackTransport);
extSyncFlag.save(level, xml);
// xml.intTag(level, "genMTCSync", genMTCSync);
@@ -1159,6 +1162,7 @@ void MusE::writeConfiguration(int level, Xml& xml) const
xml.nput(level, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
mtcOffset.h(), mtcOffset.m(), mtcOffset.s(),
mtcOffset.f(), mtcOffset.sf());
+ xml.intTag(level, "useJackTransport", useJackTransport);
extSyncFlag.save(level, xml);
// xml.intTag(level, "genMTCSync", genMTCSync);
diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp
index ef58bbfa..6a2c7e8a 100644
--- a/muse/muse/driver/jack.cpp
+++ b/muse/muse/driver/jack.cpp
@@ -9,6 +9,8 @@
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
+//#include <time.h>
+#include <unistd.h>
#include "audio.h"
#include "globals.h"
@@ -17,6 +19,8 @@
#include "track.h"
#include "pos.h"
#include "tempo.h"
+#include "sync.h"
+#include "utils.h"
#define JACK_DEBUG 0
@@ -131,6 +135,9 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void*
if (JACK_DEBUG)
printf("processSync()\n");
+ if(!useJackTransport)
+ return 1;
+
int audioState = Audio::STOP;
switch (state) {
case JackTransportStopped:
@@ -243,6 +250,8 @@ JackAudioDevice::JackAudioDevice(jack_client_t* cl, char * name)
//JackAudioDevice::jackStarted=false;
strcpy(jackRegisteredName, name);
_client = cl;
+ dummyState = Audio::STOP;
+ dummyPos = 0;
}
//---------------------------------------------------------
@@ -590,6 +599,12 @@ void JackAudioDevice::registerClient()
if(!checkJackClient(_client)) return;
jack_set_process_callback(_client, processAudio, 0);
jack_set_sync_callback(_client, processSync, 0);
+ // FIXME: FIXME:
+ // Added by Tim. p3.3.20
+ // Did not help. Seek during play: Jack keeps switching to STOP state after about 1-2 seconds timeout if sync is holding it up.
+ // Nothing in MusE seems to be telling it to stop.
+ //jack_set_sync_timeout(_client, 5000000); // Change default 2 to 5 second sync timeout because prefetch may be very slow esp. with resampling !
+
jack_on_shutdown(_client, processShutdown, 0);
jack_set_buffer_size_callback(_client, bufsize_callback, 0);
jack_set_sample_rate_callback(_client, srate_callback, 0);
@@ -735,6 +750,7 @@ void JackAudioDevice::start(int /*priority*/)
}
}
}
+
undoSetuid();
//MUSE_DEBUG("JackAudioDevice::start()\n");
@@ -758,13 +774,53 @@ void JackAudioDevice::stop()
}
//---------------------------------------------------------
+// transportQuery
+//---------------------------------------------------------
+
+jack_transport_state_t JackAudioDevice::transportQuery(jack_position_t* pos)
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::transportQuery pos:%d\n", (unsigned int)pos->frame);
+
+ // TODO: Compose and return a state if MusE is disengaged from Jack transport.
+
+ return jack_transport_query(_client, pos);
+}
+
+//---------------------------------------------------------
+// getCurFrame
+//---------------------------------------------------------
+
+unsigned int JackAudioDevice::getCurFrame()
+{
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::getCurFrame pos.frame:%d\n", pos.frame);
+
+ if(!useJackTransport)
+ return (unsigned int)dummyPos;
+
+ return pos.frame;
+}
+
+//---------------------------------------------------------
// framePos
//---------------------------------------------------------
int JackAudioDevice::framePos() const
{
+ //if(!useJackTransport)
+ //{
+ // if (JACK_DEBUG)
+ // printf("JackAudioDevice::framePos dummyPos:%d\n", dummyPos);
+ // return dummyPos;
+ //}
+
if(!checkJackClient(_client)) return 0;
jack_nframes_t n = jack_frame_time(_client);
+
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::framePos jack frame:%d\n", (int)n);
+
return (int)n;
}
@@ -877,10 +933,24 @@ void JackAudioDevice::unregisterPort(void* p)
int JackAudioDevice::getState()
{
+ // If we're not using Jack's transport, just return current state.
+ if(!useJackTransport)
+ {
+ //pos.valid = jack_position_bits_t(0);
+ //pos.frame = audio->pos().frame();
+ //return audio->getState();
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::getState dummyState:%d\n", dummyState);
+ return dummyState;
+ }
+
//if (JACK_DEBUG)
// printf("JackAudioDevice::getState ()\n");
if(!checkJackClient(_client)) return 0;
transportState = jack_transport_query(_client, &pos);
+ if (JACK_DEBUG)
+ printf("JackAudioDevice::getState transportState:%d\n", transportState);
+
switch (transportState) {
case JackTransportStopped:
return Audio::STOP;
@@ -920,46 +990,136 @@ void JackAudioDevice::setFreewheel(bool f)
}
//---------------------------------------------------------
+// dummySync
+//---------------------------------------------------------
+
+bool JackAudioDevice::dummySync(int state)
+{
+ // Roughly segment time length.
+ //timespec ts = { 0, (1000000000 * segmentSize) / sampleRate }; // In nanoseconds.
+ unsigned int sl = (1000000 * segmentSize) / sampleRate; // In microseconds.
+
+ double ct = curTime();
+ // Wait for a default maximum of 5 seconds.
+ // Similar to how Jack is supposed to wait a default of 2 seconds for slow clients.
+ // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here.
+ while((curTime() - ct) < 5.0)
+ {
+ // Is MusE audio ready to roll?
+ if(audio->sync(state, dummyPos))
+ return true;
+
+ // Not ready. Wait a 'segment', try again...
+ //nanosleep(&ts, NULL);
+ usleep(sl); // usleep is supposed to be obsolete!
+ }
+
+ //if(JACK_DEBUG)
+ printf("JackAudioDevice::dummySync Sync timeout - audio not ready!\n");
+
+ return false;
+}
+
+//---------------------------------------------------------
// startTransport
//---------------------------------------------------------
void JackAudioDevice::startTransport()
- {
+ {
if (JACK_DEBUG)
printf("JackAudioDevice::startTransport()\n");
+
+ // If we're not using Jack's transport, just pass PLAY and current frame along
+ // as if processSync was called.
+ if(!useJackTransport)
+ {
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready to roll?
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ // MusE audio is ready to roll. Let's play.
+ dummyState = Audio::PLAY;
+ return;
+ }
+
+ // Ready or not, we gotta roll. Similar to how Jack is supposed to roll anyway.
+ dummyState = Audio::PLAY;
+ return;
+ }
+
if(!checkJackClient(_client)) return;
// printf("JACK: startTransport\n");
jack_transport_start(_client);
- }
+ }
//---------------------------------------------------------
// stopTransport
//---------------------------------------------------------
void JackAudioDevice::stopTransport()
- {
+ {
if (JACK_DEBUG)
printf("JackAudioDevice::stopTransport()\n");
+
+ dummyState = Audio::STOP;
+
+ if(!useJackTransport)
+ {
+ //dummyState = Audio::STOP;
+ return;
+ }
+
if(!checkJackClient(_client)) return;
if (transportState != JackTransportStopped) {
// printf("JACK: stopTransport\n");
jack_transport_stop(_client);
transportState=JackTransportStopped;
}
- }
+ }
//---------------------------------------------------------
// seekTransport
//---------------------------------------------------------
void JackAudioDevice::seekTransport(unsigned frame)
- {
+ {
if (JACK_DEBUG)
printf("JackAudioDevice::seekTransport() frame:%d\n", frame);
+
+ dummyPos = frame;
+ if(!useJackTransport)
+ {
+ // If we're not using Jack's transport, just pass the current state and new frame along
+ // as if processSync was called.
+ //dummyPos = frame;
+ int tempState = dummyState;
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready yet?
+ //audio->sync(dummyState, dummyPos);
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ dummyState = tempState;
+ return;
+ }
+
+ // Not ready, resume previous state anyway.
+ // FIXME: Observed: Seek during play: Jack transport STOPs on timeout.
+ // Docs say when starting play, transport will roll anyway, ready or not (observed),
+ // but don't mention what should happen on seek during play.
+ // And setting the slow-sync timeout doesn't seem to do anything!
+ //dummyState = tempState;
+ dummyState = Audio::STOP;
+ return;
+ }
+
if(!checkJackClient(_client)) return;
// printf("JACK: seekTransport %d\n", frame);
jack_transport_locate(_client, frame);
- }
+ }
//---------------------------------------------------------
// seekTransport
@@ -969,6 +1129,32 @@ void JackAudioDevice::seekTransport(const Pos &p)
{
if (JACK_DEBUG)
printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame());
+
+ dummyPos = p.frame();
+ if(!useJackTransport)
+ {
+ // If we're not using Jack's transport, just pass the current state and new frame along
+ // as if processSync was called.
+ //dummyPos = p.frame();
+ int tempState = dummyState;
+ //dummyState = Audio::START_PLAY;
+
+ // Is MusE audio ready yet?
+ //audio->sync(dummyState, dummyPos);
+ //if(dummySync(dummyState))
+ if(dummySync(Audio::START_PLAY))
+ {
+ dummyState = tempState;
+ return;
+ }
+
+ // Not ready, resume previous state anyway.
+ // FIXME: See fixme in other seekTransport...
+ //dummyState = tempState;
+ dummyState = Audio::STOP;
+ return;
+ }
+
if(!checkJackClient(_client)) return;
/*
@@ -1016,13 +1202,21 @@ int JackAudioDevice::setMaster(bool f)
int r = 0;
if(f)
{
- // Make Muse the Jack timebase master. Do it unconditionally (second param = 0).
- r = jack_set_timebase_callback(_client, 0, (JackTimebaseCallback) timebase_callback, 0);
- if(debugMsg || JACK_DEBUG)
+ if(useJackTransport)
{
- if(r)
- printf("JackAudioDevice::setMaster jack_set_timebase_callback failed: result:%d\n", r);
- }
+ // Make Muse the Jack timebase master. Do it unconditionally (second param = 0).
+ r = jack_set_timebase_callback(_client, 0, (JackTimebaseCallback) timebase_callback, 0);
+ if(debugMsg || JACK_DEBUG)
+ {
+ if(r)
+ printf("JackAudioDevice::setMaster jack_set_timebase_callback failed: result:%d\n", r);
+ }
+ }
+ else
+ {
+ r = 1;
+ printf("JackAudioDevice::setMaster cannot set master because useJackTransport is false\n");
+ }
}
else
{
diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h
index 78e88313..7a73eaf5 100644
--- a/muse/muse/driver/jackaudio.h
+++ b/muse/muse/driver/jackaudio.h
@@ -24,6 +24,8 @@ class JackAudioDevice : public AudioDevice {
jack_transport_state_t transportState;
jack_position_t pos;
char jackRegisteredName[8];
+ int dummyState;
+ int dummyPos;
public:
JackAudioDevice(jack_client_t* cl, char * jack_id_string);
@@ -33,6 +35,7 @@ class JackAudioDevice : public AudioDevice {
//virtual void start();
virtual void start(int);
virtual void stop ();
+ virtual bool dummySync(int state); // Artificial sync when not using Jack transport.
virtual int framePos() const;
@@ -57,7 +60,7 @@ class JackAudioDevice : public AudioDevice {
virtual void* findPort(const char* name);
virtual QString portName(void* port);
virtual int getState();
- virtual unsigned int getCurFrame() { return pos.frame; }
+ virtual unsigned int getCurFrame();
virtual bool isRealtime() { return jack_is_realtime(_client); }
virtual int realtimePriority() const;
virtual void startTransport();
@@ -65,8 +68,7 @@ class JackAudioDevice : public AudioDevice {
virtual void seekTransport(unsigned frame);
virtual void seekTransport(const Pos &p);
virtual void setFreewheel(bool f);
- jack_transport_state_t transportQuery(jack_position_t* pos)
- { return jack_transport_query(_client, pos); }
+ jack_transport_state_t transportQuery(jack_position_t* pos);
void graphChanged();
virtual int setMaster(bool f);
diff --git a/muse/muse/event.cpp b/muse/muse/event.cpp
index 704335a5..16a5c581 100644
--- a/muse/muse/event.cpp
+++ b/muse/muse/event.cpp
@@ -8,10 +8,15 @@
#include <stdio.h>
// #include <memory.h>
+#include "audioconvert.h"
#include "event.h"
#include "eventbase.h"
#include "waveevent.h"
#include "midievent.h"
+//#include "globals.h"
+
+// Added by Tim. p3.3.20
+#define USE_SAMPLERATE
//---------------------------------------------------------
// Event
@@ -63,7 +68,17 @@ Event Event::clone()
return Event(ev->clone());
}
+Event::Event()
+{
+ ev = 0;
+ _sfCurFrame = 0;
+ _audConv = 0;
+}
+
Event::Event(EventType t) {
+ _sfCurFrame = 0;
+ _audConv = 0;
+
if (t == Wave)
ev = new WaveEventBase(t);
else
@@ -71,13 +86,32 @@ Event::Event(EventType t) {
++(ev->refCount);
}
Event::Event(const Event& e) {
+ _sfCurFrame = 0;
+ _audConv = 0;
+
ev = e.ev;
- if (ev)
- ++(ev->refCount);
- }
+ if(ev)
+ ++(ev->refCount);
+
+ #ifdef USE_SAMPLERATE
+ //_audConv = AudioConverter::getAudioConverter(e._audConv);
+ if(e._audConv)
+ _audConv = e._audConv->reference();
+ #endif
+ }
Event::Event(EventBase* eb) {
+ _sfCurFrame = 0;
+ _audConv = 0;
+
ev = eb;
++(ev->refCount);
+
+ #ifdef USE_SAMPLERATE
+ if(!ev->sndFile().isNull())
+ //_audConv = AudioConverter::getAudioConverter(eb, SRC_SINC_MEDIUM_QUALITY);
+ //_audConv = new AudioConverter(ev->sndFile().channels(), SRC_SINC_MEDIUM_QUALITY);
+ _audConv = new SRCAudioConverter(ev->sndFile().channels(), SRC_SINC_MEDIUM_QUALITY);
+ #endif
}
Event::~Event() {
@@ -85,6 +119,10 @@ Event::~Event() {
delete ev;
ev=0;
}
+
+ #ifdef USE_SAMPLERATE
+ AudioConverter::release(_audConv);
+ #endif
}
bool Event::empty() const { return ev == 0; }
@@ -103,6 +141,7 @@ void Event::setType(EventType t) {
}
Event& Event::operator=(const Event& e) {
+ /*
if (ev == e.ev)
return *this;
if (ev && --(ev->refCount) == 0) {
@@ -113,7 +152,31 @@ Event& Event::operator=(const Event& e) {
if (ev)
++(ev->refCount);
return *this;
+ */
+
+ if (ev != e.ev)
+ {
+ if (ev && --(ev->refCount) == 0) {
+ delete ev;
+ ev = 0;
+ }
+ ev = e.ev;
+ if (ev)
+ ++(ev->refCount);
+ }
+
+ #ifdef USE_SAMPLERATE
+ if (_audConv != e._audConv)
+ {
+ if(_audConv)
+ AudioConverter::release(_audConv);
+ //_audConv = AudioConverter::getAudioConverter(e._audConv);
+ _audConv = e._audConv->reference();
+ }
+ #endif
+ return *this;
}
+
bool Event::operator==(const Event& e) const {
return ev == e.ev;
}
@@ -123,7 +186,35 @@ bool Event::selected() const { return ev->_selected; }
void Event::setSelected(bool val) { ev->_selected = val; }
void Event::move(int offset) { ev->move(offset); }
-void Event::read(Xml& xml) { ev->read(xml); }
+//void Event::read(Xml& xml) { ev->read(xml); }
+void Event::read(Xml& xml)
+{
+ ev->read(xml);
+
+ #ifdef USE_SAMPLERATE
+ if(!ev->sndFile().isNull())
+ {
+ if(_audConv)
+ {
+ _audConv->setChannels(ev->sndFile().channels());
+ }
+ else
+ {
+ //int srcerr;
+ //if(debugMsg)
+ // printf("Event::read Creating samplerate converter with %d channels\n", ev->sndFile().channels());
+ //_src_state = src_new(SRC_SINC_MEDIUM_QUALITY, ev->sndFile().channels(), &srcerr);
+// _audConv = new AudioConverter(ev->sndFile().channels(), SRC_SINC_MEDIUM_QUALITY);
+ _audConv = new SRCAudioConverter(ev->sndFile().channels(), SRC_SINC_MEDIUM_QUALITY);
+ //if(!_src_state)
+ //if(!_audConv)
+ // printf("Event::read Creation of samplerate converter with %d channels failed:%s\n", ev->sndFile().channels(), src_strerror(srcerr));
+ }
+ }
+ #endif
+}
+
+
//void Event::write(int a, Xml& xml, const Pos& o) const { ev->write(a, xml, o); }
void Event::write(int a, Xml& xml, const Pos& o, bool forceWavePaths) const { ev->write(a, xml, o, forceWavePaths); }
void Event::dump(int n) const { ev->dump(n); }
@@ -155,13 +246,32 @@ void Event::setName(const QString& s) { ev->setName(s); }
int Event::spos() const { return ev->spos(); }
void Event::setSpos(int s) { ev->setSpos(s); }
SndFileR Event::sndFile() const { return ev->sndFile(); }
-void Event::setSndFile(SndFileR& sf) { ev->setSndFile(sf); }
+
+//void Event::setSndFile(SndFileR& sf) { ev->setSndFile(sf); }
+void Event::setSndFile(SndFileR& sf)
+{
+ ev->setSndFile(sf);
+
+ #ifdef USE_SAMPLERATE
+ //if(_audConv)
+ if(_audConv && !sf.isNull())
+ {
+ //_audConv->setSndFile(sf);
+ //if(sf.isNull())
+ // AudioConverter::release(_audConv);
+ //else
+ _audConv->setChannels(sf.channels());
+ }
+ #endif
+}
//void Event::read(unsigned offset, float** bpp, int channels, int nn, bool overwrite)
void Event::readAudio(unsigned offset, float** bpp, int channels, int nn, bool doSeek, bool overwrite)
{
//ev->read(offset, bpp, channels, nn, overwrite);
- ev->readAudio(offset, bpp, channels, nn, doSeek, overwrite);
+ //ev->readAudio(offset, bpp, channels, nn, doSeek, overwrite);
+ //_sfCurFrame = ev->readAudio(_src_state, _sfCurFrame, offset, bpp, channels, nn, doSeek, overwrite);
+ _sfCurFrame = ev->readAudio(_audConv, _sfCurFrame, offset, bpp, channels, nn, doSeek, overwrite);
}
void Event::setTick(unsigned val) { ev->setTick(val); }
unsigned Event::tick() const { return ev->tick(); }
diff --git a/muse/muse/event.h b/muse/muse/event.h
index 1bbded12..2a034a36 100644
--- a/muse/muse/event.h
+++ b/muse/muse/event.h
@@ -11,6 +11,8 @@
#include <qstring.h>
#include <map>
+//#include <samplerate.h>
+#include <sys/types.h>
#include "wave.h" // wg. SndFile
#include "pos.h"
@@ -20,6 +22,7 @@ enum EventType { Note, Controller, Sysex, PAfter, CAfter, Meta, Wave };
class Xml;
class EventBase;
+class AudioConverter;
//---------------------------------------------------------
// Event
@@ -28,8 +31,12 @@ class EventBase;
class Event {
EventBase* ev;
+ off_t _sfCurFrame;
+ AudioConverter* _audConv;
+
public:
- Event() { ev = 0; }
+ //Event() { ev = 0; }
+ Event();
Event(EventType t);
Event(const Event& e);
Event(EventBase* eb);
@@ -79,6 +86,7 @@ class Event {
void setName(const QString& s);
int spos() const;
void setSpos(int s);
+ //AudioConverter* audioConverter() { return _audConv;}
SndFileR sndFile() const;
virtual void setSndFile(SndFileR& sf);
//virtual void read(unsigned offset, float** bpp, int channels, int nn, bool overwrite = true);
diff --git a/muse/muse/eventbase.h b/muse/muse/eventbase.h
index 9e29c81a..4a49b6f8 100644
--- a/muse/muse/eventbase.h
+++ b/muse/muse/eventbase.h
@@ -9,8 +9,13 @@
#ifndef __EVENTBASE_H__
#define __EVENTBASE_H__
+//#include <samplerate.h>
+#include <sys/types.h>
+
#include "pos.h"
+class AudioConverter;
+
//---------------------------------------------------------
// EventBase
//---------------------------------------------------------
@@ -76,8 +81,13 @@ class EventBase : public PosLen {
virtual SndFileR sndFile() const { return 0; }
virtual void setSndFile(SndFileR&) { }
virtual EventBase* clone() = 0;
+
//virtual void read(unsigned /*offset*/, float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool overwrite = true) {}
- virtual void readAudio(unsigned /*offset*/, float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/) {}
+ //virtual void readAudio(unsigned /*offset*/, float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/) {}
+ //virtual off_t readAudio(SRC_STATE* /*src_state*/, off_t /*sfCurFrame*/, unsigned /*offset*/,
+ // float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/) { return 0; }
+ virtual off_t readAudio(AudioConverter* /*audConv*/, off_t /*sfCurFrame*/, unsigned /*offset*/,
+ float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/) { return 0; }
};
#endif
diff --git a/muse/muse/midiport.cpp b/muse/muse/midiport.cpp
index 91444864..568fa68d 100644
--- a/muse/muse/midiport.cpp
+++ b/muse/muse/midiport.cpp
@@ -694,8 +694,8 @@ int MidiPort::hwCtrlState(int ch, int ctrl) const
ch &= 0xff;
iMidiCtrlValList cl = _controller->find(ch, ctrl);
if (cl == _controller->end()) {
- if (debugMsg)
- printf("hwCtrlState: chan %d ctrl 0x%x not found\n", ch, ctrl);
+ //if (debugMsg)
+ // printf("hwCtrlState: chan %d ctrl 0x%x not found\n", ch, ctrl);
return CTRL_VAL_UNKNOWN;
}
MidiCtrlValList* vl = cl->second;
@@ -796,9 +796,9 @@ int MidiPort::getCtrl(int ch, int tick, int ctrl) const
{
iMidiCtrlValList cl = _controller->find(ch, ctrl);
if (cl == _controller->end()) {
- if (debugMsg)
- printf("getCtrl: controller %d(0x%x) for channel %d not found size %zd\n",
- ctrl, ctrl, ch, _controller->size());
+ //if (debugMsg)
+ // printf("getCtrl: controller %d(0x%x) for channel %d not found size %zd\n",
+ // ctrl, ctrl, ch, _controller->size());
return CTRL_VAL_UNKNOWN;
}
return cl->second->value(tick);
@@ -808,7 +808,9 @@ int MidiPort::getCtrl(int ch, int tick, int ctrl, Part* part) const
{
iMidiCtrlValList cl = _controller->find(ch, ctrl);
if (cl == _controller->end()) {
- if (debugMsg)
+ //if (debugMsg)
+ // printf("getCtrl: controller %d(0x%x) for channel %d not found size %zd\n",
+ // ctrl, ctrl, ch, _controller->size());
return CTRL_VAL_UNKNOWN;
}
return cl->second->value(tick, part);
diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp
index 14c1f922..fe3dcfee 100644
--- a/muse/muse/sync.cpp
+++ b/muse/muse/sync.cpp
@@ -36,6 +36,7 @@ BValue extSyncFlag(0, "extSync"); // false - MASTER, true - SLAVE
//bool acceptMTC = false;
//bool acceptMC = true;
//bool acceptMMC = true;
+bool useJackTransport = true;
static MTC mtcCurTime;
static int mtcState; // 0-7 next expected quarter message
diff --git a/muse/muse/sync.h b/muse/muse/sync.h
index a2f4e1f9..f09d410c 100644
--- a/muse/muse/sync.h
+++ b/muse/muse/sync.h
@@ -108,6 +108,7 @@ extern BValue extSyncFlag;
//extern bool acceptMC;
//extern bool acceptMMC;
extern int curMidiSyncInPort;
+extern bool useJackTransport;
#endif
diff --git a/muse/muse/thread.cpp b/muse/muse/thread.cpp
index 0576feda..444d5219 100644
--- a/muse/muse/thread.cpp
+++ b/muse/muse/thread.cpp
@@ -302,12 +302,10 @@ void Thread::loop()
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
- int policy;
- /*
+ int policy = 0;
if ((policy = sched_getscheduler (0)) < 0) {
printf("Thread: Cannot get current client scheduler: %s\n", strerror(errno));
}
- */
/*
if (debugMsg)
@@ -422,7 +420,6 @@ bool Thread::sendMsg1(const void* m, int n)
void Thread::readMsg()
{
-
ThreadMsg* p;
if (read(toThreadFdr, &p, sizeof(p)) != sizeof(p)) {
perror("Thread::readMessage(): read pipe failed");
diff --git a/muse/muse/wave.cpp b/muse/muse/wave.cpp
index 0b52f743..ac26d5e9 100644
--- a/muse/muse/wave.cpp
+++ b/muse/muse/wave.cpp
@@ -29,9 +29,6 @@
//#define WAVE_DEBUG
//#define WAVE_DEBUG_PRC
-// Added by Tim. p3.3.18
-//#define USE_SAMPLERATE
-
const char* audioFilePattern[] = {
"Wave/Binary (*.wav *.ogg *.bin)",
"Wave (*.wav *.ogg)",
@@ -56,8 +53,6 @@ SndFile::SndFile(const QString& name)
sfUI = 0;
csize = 0;
cache = 0;
- _src_state = 0;
- _src_ratio = 1.0;
openFlag = false;
sndFiles.push_back(this);
refCount=0;
@@ -80,9 +75,6 @@ SndFile::~SndFile()
delete[] cache;
cache = 0;
}
-
- if(_src_state)
- src_delete(_src_state);
}
//---------------------------------------------------------
@@ -103,17 +95,6 @@ bool SndFile::openRead()
if (sf == 0 || sfUI == 0)
return true;
- int srcerr;
- if(_src_state)
- src_delete(_src_state);
- _src_state = src_new(SRC_SINC_MEDIUM_QUALITY, sfinfo.channels, &srcerr);
- if(!_src_state)
- printf("SndFile::openRead Creation of samplerate converter (channels:%d) failed: %s\n", sfinfo.channels, src_strerror(srcerr));
- //_src_ratio = (double)sampleRate / (double)sfinfo.samplerate;
- //srcerr = src_set_ratio(_src_state, _src_ratio);
- //if(srcerr != 0)
- // printf("SndFile::openRead Setting of samplerate converter ratio failed: %s\n", src_strerror(srcerr));
-
writeFlag = false;
openFlag = true;
QString cacheName = finfo->dirPath(true) + QString("/") + finfo->baseName(true) + QString(".wca");
@@ -366,17 +347,6 @@ bool SndFile::openWrite()
QString cacheName = finfo->dirPath(true) +
QString("/") + finfo->baseName(true) + QString(".wca");
readCache(cacheName, true);
-
- int srcerr;
- if(_src_state)
- src_delete(_src_state);
- _src_state = src_new(SRC_SINC_MEDIUM_QUALITY, sfinfo.channels, &srcerr);
- if(!_src_state)
- printf("SndFile::openWrite Creation of samplerate converter (channels:%d) failed: %s\n", sfinfo.channels, src_strerror(srcerr));
- //_src_ratio = (double)sampleRate / (double)sfinfo.samplerate;
- //srcerr = src_set_ratio(_src_state, _src_ratio);
- //if(srcerr != 0)
- // printf("SndFile::openRead Setting of samplerate converter ratio failed: %s\n", src_strerror(srcerr));
}
return sf == 0;
}
@@ -468,17 +438,6 @@ void SndFile::setFormat(int fmt, int ch, int rate)
sfinfo.format = fmt;
sfinfo.seekable = true;
sfinfo.frames = 0;
-
- int srcerr;
- if(_src_state)
- src_delete(_src_state);
- _src_state = src_new(SRC_SINC_MEDIUM_QUALITY, sfinfo.channels, &srcerr);
- if(!_src_state)
- printf("SndFile::setFormat Creation of samplerate converter (channels:%d) failed: %s\n", sfinfo.channels, src_strerror(srcerr));
- //_src_ratio = (double)sampleRate / (double)sfinfo.samplerate;
- //srcerr = src_set_ratio(_src_state, _src_ratio);
- //if(srcerr != 0)
- // printf("SndFile::openRead Setting of samplerate converter ratio failed: %s\n", src_strerror(srcerr));
}
//---------------------------------------------------------
@@ -490,120 +449,7 @@ size_t SndFile::read(int srcChannels, float** dst, size_t n, bool overwrite)
// Changed by Tim. p3.3.17
//float *buffer = new float[n * sfinfo.channels];
float buffer[n * sfinfo.channels];
-
- size_t rn;
-
- // Do we need to resample?
- // FIXME: Disabled resampling for now...
-#ifdef USE_SAMPLERATE
- if(sampleRate == sfinfo.samplerate)
- {
- rn = sf_readf_float(sf, buffer, n);
- }
- else
- {
- if(sfinfo.samplerate == 0)
- {
- if(debugMsg)
- printf("SndFile::read Using SRC: Error: File samplerate is zero!\n");
- return 0;
- }
-
- // Ratio is defined as output sample rate over input samplerate.
- double srcratio = (double)sampleRate / (double)sfinfo.samplerate;
- long outFrames = n;
- //long outSize = n * sfinfo.channels;
-
- //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 * sfinfo.channels;
-
- float inbuffer[inSize];
-
- rn = sf_readf_float(sf, inbuffer, inFrames);
-
- // convert
- SRC_DATA srcdata;
- srcdata.data_in = inbuffer;
- srcdata.data_out = buffer;
- //srcdata.input_frames = inSize;
- srcdata.input_frames = rn;
- srcdata.output_frames = outFrames;
- srcdata.end_of_input = ((long)rn != inFrames);
- srcdata.src_ratio = srcratio;
-
- #ifdef WAVE_DEBUG_PRC
- printf("SndFile::read SampleRate %s inFrames:%ld inSize:%ld outFrames:%ld outSize:%ld rn:%d", name().latin1(), inFrames, inSize, outFrames, n * sfinfo.channels, rn);
- #endif
-
- int srcerr = src_process(_src_state, &srcdata);
- if(srcerr != 0)
- {
- printf("\nSndFile::read SampleRate converter src_process failed: %s\n", src_strerror(srcerr));
- return 0;
- }
-
- #ifdef WAVE_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;
- #ifdef WAVE_DEBUG_PRC
- printf("SndFile::read seeking:%ld\n", seekn);
- #endif
- sf_seek(sf, -seekn, SEEK_CUR);
- }
-
- if(debugMsg)
- {
- if(srcdata.output_frames_gen != outFrames)
- printf("SndFile::read SampleRate %s output_frames_gen:%ld != outFrames:%ld outSize:%u inFrames:%ld srcdata.input_frames_used:%ld inSize:%ld rn:%d\n", name().latin1(), srcdata.output_frames_gen, outFrames, n * sfinfo.channels, inFrames, srcdata.input_frames_used, inSize, rn);
- }
-
- if(inFrames != (long)rn)
- {
- // Back-convert.
- long d = inFrames - (long)rn;
- //rn = (double)d * srcratio + 1;
- rn = (long)floor((double)d * srcratio);
- }
- 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 * sfinfo.channels;
- long e = outFrames * sfinfo.channels;
- for(long i = b; i < e; ++i)
- buffer[i] = 0.0f;
- rn = outFrames;
- }
- else
- rn = srcdata.output_frames_gen;
- }
-#else
- rn = sf_readf_float(sf, buffer, n);
-#endif
+ size_t rn = sf_readf_float(sf, buffer, n);
float* src = buffer;
int dstChannels = sfinfo.channels;
@@ -720,36 +566,7 @@ size_t SndFile::write(int srcChannels, float** src, size_t n)
off_t SndFile::seek(off_t frames, int whence)
{
- // Changed by Tim. p3.3.17
- //return sf_seek(sf, frames, whence);
-
- off_t n = frames;
-
- // FIXME: Disabled resampling for now...
-#ifdef USE_SAMPLERATE
- if(sfinfo.samplerate != sampleRate)
- {
- double srcratio = (double)sfinfo.samplerate / (double)sampleRate;
- //long inSize = long((double)frames * _src_ratio) + 1 // From MusE-2 file converter.
- n = (off_t)floor(((double)frames * srcratio)); // From simplesynth.
-
- // Added by Tim. p3.3.17
- #ifdef WAVE_DEBUG
- printf("SndFile::seek frames:%ld converted to frames:%ld whence:%d\n", frames, n, whence);
- #endif
-
- n = sf_seek(sf, n, whence);
-
- // Reset the src converter.
- int srcerr = src_reset(_src_state);
- if(srcerr != 0)
- printf("SndFile::seek Samplerate converter reset failed: %s\n", src_strerror(srcerr));
- }
- else
-#endif
- n = sf_seek(sf, n, whence);
-
- return n;
+ return sf_seek(sf, frames, whence);
}
//---------------------------------------------------------
diff --git a/muse/muse/wave.h b/muse/muse/wave.h
index d5c5eaea..5a7997fe 100644
--- a/muse/muse/wave.h
+++ b/muse/muse/wave.h
@@ -13,7 +13,6 @@
#include <list>
#include <qfileinfo.h>
#include <sndfile.h>
-#include <samplerate.h>
class Xml;
@@ -53,9 +52,6 @@ class SndFile {
SampleV** cache;
int csize; //!< frames in cache
- SRC_STATE* _src_state;
- double _src_ratio;
-
void writeCache(const QString& path);
bool openFlag;
@@ -94,9 +90,9 @@ class SndFile {
unsigned format() const;
int sampleBits() const;
void setFormat(int fmt, int ch, int rate);
- double srcRatio() { return _src_ratio; }
size_t read(int channel, float**, size_t, bool overwrite = true);
+ size_t readDirect(float* buf, size_t n) { return sf_readf_float(sf, buf, n); }
size_t write(int channel, float**, size_t);
off_t seek(off_t frames, int whence);
@@ -151,6 +147,8 @@ class SndFileR {
size_t read(int channel, float** f, size_t n, bool overwrite = true) {
return sf->read(channel, f, n, overwrite);
}
+ size_t readDirect(float* f, size_t n) { return sf->readDirect(f, n); }
+
size_t write(int channel, float** f, size_t n) {
return sf->write(channel, f, n);
}
diff --git a/muse/muse/waveevent.cpp b/muse/muse/waveevent.cpp
index 6bd7150e..dd18a2ff 100644
--- a/muse/muse/waveevent.cpp
+++ b/muse/muse/waveevent.cpp
@@ -6,16 +6,20 @@
// (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 WAVEEVENT_DEBUG
//#define USE_SAMPLERATE
+//
+//#define WAVEEVENT_DEBUG
+//#define WAVEEVENT_DEBUG_PRC
//---------------------------------------------------------
// WaveEvent
@@ -134,22 +138,294 @@ void WaveEventBase::write(int level, Xml& xml, const Pos& offset, bool forcePath
}
//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)
- {
+//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)
+{
+ // 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
+
+ // 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;
+
+ /*
+ 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
- printf("WaveEventBase::readAudio offset:%u channel:%d n:%d\n", offset, channel, n);
+ #ifdef WAVEEVENT_DEBUG_PRC
+ printf("WaveEventBase::readAudio Seek frame:%ld converted to frame:%ld _sfCurFrame:%ld\n", frame, newfr, sfCurFrame);
#endif
- if (f.isNull())
- return;
+ // 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
- // Changed by Tim. p3.3.18
- // FIXME: Removed until resampling is enabled.
- #ifdef USE_SAMPLERATE
- if(doSeek)
+ // 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
- f.seek(offset + _spos, 0);
-
- f.read(channel, buffer, n, overwrite);
+ 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);
+ return sfCurFrame;
+ #endif
+
+}
+
diff --git a/muse/muse/waveevent.h b/muse/muse/waveevent.h
index c5ca5315..926e9c64 100644
--- a/muse/muse/waveevent.h
+++ b/muse/muse/waveevent.h
@@ -9,8 +9,13 @@
#ifndef __WAVE_EVENT_H__
#define __WAVE_EVENT_H__
+//#include <samplerate.h>
+#include <sys/types.h>
+
#include "eventbase.h"
+class AudioConverter;
+
//---------------------------------------------------------
// WaveEvent
//---------------------------------------------------------
@@ -43,7 +48,12 @@ class WaveEventBase : public EventBase {
// Changed by Tim. p3.3.17
//virtual void read(unsigned offset, float** bpp, int channels, int nn, bool overwrite = true);
- virtual void readAudio(unsigned /*offset*/, float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/);
+ //virtual void readAudio(unsigned /*offset*/, float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/);
+ //virtual off_t readAudio(SRC_STATE* /*src_state*/, off_t /*sfCurFrame*/, unsigned /*offset*/,
+ // float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/);
+ virtual off_t readAudio(AudioConverter* /*audConv*/, off_t /*sfCurFrame*/, unsigned /*offset*/,
+ float** /*bpp*/, int /*channels*/, int /*nn*/, bool /*doSeek*/, bool /*overwrite*/);
};
+
#endif
diff --git a/muse/muse/widgets/citem.cpp b/muse/muse/widgets/citem.cpp
index a4cef8b7..2974196d 100644
--- a/muse/muse/widgets/citem.cpp
+++ b/muse/muse/widgets/citem.cpp
@@ -25,7 +25,9 @@ CItem::CItem(const QPoint&p, const QRect& r)
_isMoving = false;
}
-CItem::CItem(Event e, Part* p)
+// Changed by Tim. p3.3.20
+//CItem::CItem(Event e, Part* p)
+CItem::CItem(const Event& e, Part* p)
{
_event = e;
_part = p;
diff --git a/muse/muse/widgets/citem.h b/muse/muse/widgets/citem.h
index 5d035110..c58b6bb1 100644
--- a/muse/muse/widgets/citem.h
+++ b/muse/muse/widgets/citem.h
@@ -36,7 +36,9 @@ class CItem {
public:
CItem(const QPoint& p, const QRect& r);
CItem();
- CItem(Event e, Part* p);
+ // Changed by Tim. p3.3.20
+ //CItem(Event e, Part* p);
+ CItem(const Event& e, Part* p);
bool isMoving() const { return _isMoving; }
void setMoving(bool f) { _isMoving = f; }
diff --git a/muse/muse/widgets/midisync.ui b/muse/muse/widgets/midisync.ui
index 3adc8e1d..2032e574 100644
--- a/muse/muse/widgets/midisync.ui
+++ b/muse/muse/widgets/midisync.ui
@@ -290,46 +290,67 @@ configuration dialog</comment>
</vbox>
</widget>
<widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>syncGen</cstring>
+ </property>
+ <property name="title">
+ <string>Sync receiving and sending</string>
+ </property>
+ <grid>
<property name="name">
- <cstring>syncGen</cstring>
+ <cstring>unnamed</cstring>
</property>
- <property name="title">
- <string>Sync receiving and sending</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QListView" row="1" column="0">
- <property name="name">
- <cstring>devicesListView</cstring>
- </property>
- </widget>
- <widget class="QCheckBox" row="0" column="0">
- <property name="name">
- <cstring>extSyncCheckbox</cstring>
- </property>
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="text">
- <string>Slave to external sync</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <property name="toolTip" stdset="0">
- <string>Allow Muse to be controlled by external midi</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string>When in slave mode, tempo is
- controlled externally, as well
- as the transport (play, stop etc.)
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>useJackTransportCheckbox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Use Jack transport</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Send and receive Jack transport</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Send and receive Jack transport information,
+ including stop, start and position.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>extSyncCheckbox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Slave to external sync</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Control MusE timing by external midi clock or MTC sync</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When in slave mode, tempo is
+ controlled externally.
+MusE can sync to midi clock, or MTC quarter frame sync.
Enabled inputs in the list will
be in effect (RMC, RMMC, RMTC).</string>
- </property>
- </widget>
- </grid>
+ </property>
+ </widget>
+ <widget class="QListView" row="2" column="0">
+ <property name="name">
+ <cstring>devicesListView</cstring>
+ </property>
+ </widget>
+ </grid>
</widget>
</grid>
</widget>
diff --git a/muse/muse/widgets/midisyncimpl.cpp b/muse/muse/widgets/midisyncimpl.cpp
index 6fae59b7..d38068fc 100644
--- a/muse/muse/widgets/midisyncimpl.cpp
+++ b/muse/muse/widgets/midisyncimpl.cpp
@@ -22,6 +22,7 @@
//#include <qwhatsthis.h>
#include <qmessagebox.h>
+#include "app.h"
#include "song.h"
#include "midiport.h"
#include "midiseq.h"
@@ -292,6 +293,8 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)
//connect(syncMode, SIGNAL(clicked(int)), SLOT(syncChanged(int)));
connect(extSyncCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));
+ connect(mtcSyncType, SIGNAL(activated(int)), SLOT(syncChanged()));
+ connect(useJackTransportCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));
connect(&extSyncFlag, SIGNAL(valueChanged(bool)), SLOT(extSyncChanged(bool)));
@@ -328,7 +331,12 @@ void MidiSyncConfig::songChanged(int flags)
//for(int i = 0; i < MIDI_PORTS; ++i)
// tmpMidiSyncPorts[i] = midiSyncPorts[i];
+ extSyncCheckbox->blockSignals(true);
+ useJackTransportCheckbox->blockSignals(true);
extSyncCheckbox->setChecked(extSyncFlag.value());
+ useJackTransportCheckbox->setChecked(useJackTransport);
+ useJackTransportCheckbox->blockSignals(false);
+ extSyncCheckbox->blockSignals(false);
mtcSyncType->setCurrentItem(mtcType);
@@ -455,6 +463,8 @@ void MidiSyncConfig::extSyncChanged(bool v)
{
extSyncCheckbox->blockSignals(true);
extSyncCheckbox->setChecked(v);
+// if(v)
+// song->setMasterFlag(false);
extSyncCheckbox->blockSignals(false);
}
@@ -541,7 +551,12 @@ void MidiSyncConfig::apply()
mtcType = mtcSyncType->currentItem();
//extSyncFlag.setValue(syncMode->id(syncMode->selected()));
+ //extSyncFlag.blockSignals(true);
extSyncFlag.setValue(extSyncCheckbox->isChecked());
+// if(extSyncFlag.value())
+// song->setMasterFlag(false);
+ //extSyncFlag.blockSignals(false);
+ useJackTransport = useJackTransportCheckbox->isChecked();
mtcOffset.setH(mtcOffH->value());
mtcOffset.setM(mtcOffM->value());
@@ -568,6 +583,8 @@ void MidiSyncConfig::apply()
lvi = (MidiSyncLViewItem*)lvi->nextSibling();
}
+ //muse->changeConfig(true); // save settings
+
_dirty = false;
if(applyButton->isEnabled())
applyButton->setEnabled(false);