mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-01 16:19:43 +02:00
Merge branch 'master' into scrubbing2
This commit is contained in:
commit
df0303cdaf
105
.gitignore
vendored
105
.gitignore
vendored
@ -1,3 +1,73 @@
|
||||
# Autotools generated files
|
||||
locale/Makefile.in
|
||||
Makefile
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
config.status
|
||||
bin-stamp
|
||||
.deps
|
||||
.dirstamp
|
||||
lib-stamp
|
||||
libtool
|
||||
stamp-h*
|
||||
stamp-po
|
||||
*.stamp
|
||||
|
||||
# Generated files by build system
|
||||
lib-src/expat/expat_config.h
|
||||
lib-src/libflac/doc/Doxyfile
|
||||
lib-src/libflac/config.h
|
||||
lib-src/libflac/test/common.sh
|
||||
lib-src/libid3tag/config.h
|
||||
lib-src/libid3tag/libid3tag.list
|
||||
lib-src/libmad/config.h
|
||||
lib-src/libmad/libmad.list
|
||||
lib-src/libmad/mad.h
|
||||
lib-src/libogg/config.h
|
||||
lib-src/libogg/include/ogg/config_types.h
|
||||
lib-src/libogg/libogg.spec
|
||||
lib-src/libsndfile/build-test-tarball.mk
|
||||
lib-src/libsndfile/doc/libsndfile.css
|
||||
lib-src/libsndfile/libsndfile.spec
|
||||
lib-src/libsndfile/man/sndfile-deinterleave.1
|
||||
lib-src/libsndfile/man/sndfile-metadata-set.1
|
||||
lib-src/libsndfile/src/config.h
|
||||
lib-src/libsndfile/src/sndfile.h
|
||||
lib-src/libsndfile/src/version-metadata.rc
|
||||
lib-src/libsndfile/tests/pedantic-header-test.sh
|
||||
lib-src/libsndfile/tests/test_wrapper.sh
|
||||
lib-src/libsoxr/soxr-config.h
|
||||
lib-src/libsoxr/src/libsoxr-dev.src
|
||||
lib-src/libsoxr/src/libsoxr.src
|
||||
lib-src/libsoxr/tests/ref-*.s32
|
||||
lib-src/libvorbis/config.h
|
||||
lib-src/libvorbis/doc/Doxyfile
|
||||
lib-src/libvorbis/libvorbis.spec
|
||||
lib-src/sbsms/libsbsms.spec
|
||||
lib-src/sbsms/src/config.h
|
||||
lib-src/soundtouch/include/soundtouch_config.h
|
||||
lib-src/twolame/doc/html/Doxyfile
|
||||
lib-src/twolame/libtwolame/config.h
|
||||
locale/POTFILES
|
||||
src/audacity.desktop
|
||||
src/configunix.h
|
||||
src/configwin.h
|
||||
*.pc
|
||||
|
||||
# CMake build output
|
||||
lib-src/libsoxr/CMakeCache.txt
|
||||
lib-src/libsoxr/*.cmake
|
||||
CMakeFiles/
|
||||
CTestTestfile.cmake
|
||||
cmake_install.cmake
|
||||
|
||||
# Waf build output
|
||||
lib-src/lv2/.buildvars
|
||||
lib-src/lv2/include/
|
||||
lib-src/lv2/*/build/
|
||||
lib-src/lv2/srcdir.mk
|
||||
.lock-waf_linux2_build
|
||||
|
||||
# Mac build outputs
|
||||
mac/Audacity.xcodeproj/project.xcworkspace/contents.xcworkspacedata
|
||||
mac/Audacity.xcodeproj/project.xcworkspace/xcshareddata/Audacity.xccheckout
|
||||
@ -46,6 +116,9 @@ mac/tests/
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Compiled translation files (GNU Machine Object)
|
||||
*.gmo
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
@ -60,6 +133,38 @@ mac/tests/
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Executable without extension
|
||||
/audacity
|
||||
src/audacity
|
||||
lib-src/expat/examples/elements
|
||||
lib-src/expat/examples/outline
|
||||
lib-src/expat/xmlwf/xmlwf
|
||||
lib-src/libflac/examples/c/decode/file/example_c_decode_file
|
||||
lib-src/libflac/examples/c/encode/file/example_c_encode_file
|
||||
lib-src/libflac/examples/cpp/decode/file/example_cpp_decode_file
|
||||
lib-src/libflac/examples/cpp/encode/file/example_cpp_encode_file
|
||||
lib-src/libflac/src/flac/flac
|
||||
lib-src/libflac/src/metaflac/metaflac
|
||||
lib-src/libflac/src/test_grabbag/cuesheet/test_cuesheet
|
||||
lib-src/libflac/src/test_grabbag/picture/test_picture
|
||||
lib-src/libflac/src/test_libFLAC++/test_libFLAC++
|
||||
lib-src/libflac/src/test_libFLAC/test_libFLAC
|
||||
lib-src/libflac/src/test_seeking/test_seeking
|
||||
lib-src/libflac/src/test_streams/test_streams
|
||||
lib-src/libogg/src/test_bitwise
|
||||
lib-src/libogg/src/test_framing
|
||||
lib-src/libsndfile/src/G72x/g72x_test
|
||||
lib-src/libsndfile/src/test_main
|
||||
lib-src/libsoxr/examples/1a-lsr
|
||||
lib-src/libsoxr/examples/3-options-input-fn
|
||||
lib-src/libsoxr/tests/vector-cmp
|
||||
lib-src/libsoxr/tests/vector-gen
|
||||
lib-src/libvorbis/lib/test_sharedbook
|
||||
lib-src/portaudio-v19/bin/
|
||||
lib-src/soundtouch/source/SoundStretch/soundstretch
|
||||
lib-src/twolame/frontend/twolame
|
||||
lib-src/twolame/simplefrontend/stwolame
|
||||
|
||||
# Mac Specific
|
||||
.DS_Store
|
||||
xcuserdata
|
||||
|
@ -34,7 +34,7 @@ dnl Require autoconf >= 2.59
|
||||
AC_PREREQ([2.59])
|
||||
|
||||
dnl Init autoconf
|
||||
AC_INIT([audacity], [2.0.6])
|
||||
AC_INIT([audacity], [2.1.2])
|
||||
dnl Check for existence of Audacity.h
|
||||
AC_CONFIG_SRCDIR([src/Audacity.h])
|
||||
AC_CONFIG_AUX_DIR([autotools])
|
||||
|
@ -191,7 +191,7 @@ def build(bld):
|
||||
defines = ['SUIL_SHARED', 'SUIL_INTERNAL'],
|
||||
install_path = module_dir,
|
||||
cflags = cflags,
|
||||
lib = modlib,
|
||||
lib = modlib + ['X11'],
|
||||
linkflags = bld.env.NODELETE_FLAGS)
|
||||
autowaf.use_lib(bld, obj, 'GTK2 GTK2_X11 LV2 LV2_1_4_3')
|
||||
|
||||
|
@ -405,18 +405,28 @@ struct AudioIO::ScrubQueue
|
||||
double LastTimeInQueue() const
|
||||
{
|
||||
// Needed by the main thread sometimes
|
||||
wxCriticalSectionLocker locker(mUpdating);
|
||||
wxMutexLocker locker(mUpdating);
|
||||
const Entry &previous = mEntries[(mLeadingIdx + Size - 1) % Size];
|
||||
return previous.mS1 / mRate;
|
||||
}
|
||||
|
||||
void PoisonPill()
|
||||
{
|
||||
// Main thread is shutting down the scrubbing
|
||||
wxMutexLocker locker(mUpdating);
|
||||
mPoisoned = true;
|
||||
mAvailable.Signal();
|
||||
}
|
||||
|
||||
bool Producer(double end, double maxSpeed, bool bySpeed, bool maySkip)
|
||||
{
|
||||
wxASSERT(!mPoisoned);
|
||||
|
||||
// Main thread indicates a scrubbing interval
|
||||
|
||||
// MAY ADVANCE mLeadingIdx, BUT IT NEVER CATCHES UP TO mTrailingIdx.
|
||||
|
||||
wxCriticalSectionLocker locker(mUpdating);
|
||||
wxMutexLocker locker(mUpdating);
|
||||
const unsigned next = (mLeadingIdx + 1) % Size;
|
||||
if (next != mTrailingIdx)
|
||||
{
|
||||
@ -429,8 +439,10 @@ struct AudioIO::ScrubQueue
|
||||
const bool success =
|
||||
(InitEntry(mEntries[mLeadingIdx], startTime, end, maxSpeed,
|
||||
bySpeed, &previous, maySkip));
|
||||
if (success)
|
||||
if (success) {
|
||||
mLeadingIdx = next;
|
||||
mAvailable.Signal();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else
|
||||
@ -450,7 +462,10 @@ struct AudioIO::ScrubQueue
|
||||
|
||||
// MAY ADVANCE mMiddleIdx, WHICH MAY EQUAL mLeadingIdx, BUT DOES NOT PASS IT.
|
||||
|
||||
wxCriticalSectionLocker locker(mUpdating);
|
||||
wxMutexLocker locker(mUpdating);
|
||||
while(!mPoisoned && mMiddleIdx == mLeadingIdx)
|
||||
mAvailable.Wait();
|
||||
|
||||
if (mMiddleIdx != mLeadingIdx)
|
||||
{
|
||||
// There is work in the queue
|
||||
@ -463,7 +478,8 @@ struct AudioIO::ScrubQueue
|
||||
}
|
||||
else
|
||||
{
|
||||
// next entry is not yet ready
|
||||
wxASSERT(mPoisoned);
|
||||
// We got the shut-down signal
|
||||
startSample = endSample = duration = -1L;
|
||||
}
|
||||
}
|
||||
@ -475,7 +491,7 @@ struct AudioIO::ScrubQueue
|
||||
|
||||
// MAY ADVANCE mTrailingIdx, BUT IT NEVER CATCHES UP TO mMiddleIdx.
|
||||
|
||||
wxCriticalSectionLocker locker(mUpdating);
|
||||
wxMutexLocker locker(mUpdating);
|
||||
|
||||
// Mark entries as partly or fully "consumed" for
|
||||
// purposes of mTime update. It should not happen that
|
||||
@ -678,7 +694,9 @@ private:
|
||||
const double mRate;
|
||||
const long mMinStutter;
|
||||
wxLongLong mLastScrubTimeMillis;
|
||||
mutable wxCriticalSection mUpdating;
|
||||
mutable wxMutex mUpdating;
|
||||
mutable wxCondition mAvailable { mUpdating };
|
||||
bool mPoisoned { false };
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1710,14 +1728,6 @@ int AudioIO::StartStream(const WaveTrackArray &playbackTracks,
|
||||
sampleCount playbackMixBufferSize =
|
||||
(sampleCount)mPlaybackSamplesToCopy;
|
||||
|
||||
// In the extraordinarily rare case that we can't even afford 100 samples, just give up.
|
||||
if(playbackBufferSize < 100 || playbackMixBufferSize < 100)
|
||||
{
|
||||
StartStreamCleanup();
|
||||
wxMessageBox(_("Out of memory!"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
mPlaybackBuffers = new RingBuffer* [mPlaybackTracks->size()];
|
||||
mPlaybackMixers = new Mixer* [mPlaybackTracks->size()];
|
||||
|
||||
@ -1786,7 +1796,19 @@ int AudioIO::StartStream(const WaveTrackArray &playbackTracks,
|
||||
mCaptureRingBufferSecs *= 0.5;
|
||||
mMinCaptureSecsToCopy *= 0.5;
|
||||
bDone = false;
|
||||
}
|
||||
|
||||
// In the extraordinarily rare case that we can't even afford 100 samples, just give up.
|
||||
sampleCount playbackBufferSize =
|
||||
(sampleCount)lrint(mRate * mPlaybackRingBufferSecs);
|
||||
sampleCount playbackMixBufferSize =
|
||||
(sampleCount)mPlaybackSamplesToCopy;
|
||||
if(playbackBufferSize < 100 || playbackMixBufferSize < 100)
|
||||
{
|
||||
StartStreamCleanup();
|
||||
wxMessageBox(_("Out of memory!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while(!bDone);
|
||||
|
||||
if (mNumPlaybackChannels > 0)
|
||||
@ -2166,6 +2188,8 @@ void AudioIO::StopStream()
|
||||
//
|
||||
|
||||
mAudioThreadFillBuffersLoopRunning = false;
|
||||
if (mScrubQueue)
|
||||
mScrubQueue->PoisonPill();
|
||||
|
||||
// Audacity can deadlock if it tries to update meters while
|
||||
// we're stopping PortAudio (because the meter updating code
|
||||
@ -2821,7 +2845,16 @@ AudioThread::ExitCode AudioThread::Entry()
|
||||
}
|
||||
gAudioIO->mAudioThreadFillBuffersLoopActive = false;
|
||||
|
||||
Sleep(10);
|
||||
if (gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB) {
|
||||
// Rely on the Wait() in ScrubQueue::Transformer()
|
||||
// This allows the scrubbing update interval to be made very short without
|
||||
// playback becoming intermittent.
|
||||
}
|
||||
else {
|
||||
// Perhaps this too could use a condition variable, for available space in the
|
||||
// ring buffer, instead of a polling loop? But no harm in doing it this way.
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -650,7 +650,7 @@ private:
|
||||
bool mInputMixerWorks;
|
||||
float mMixerOutputVol;
|
||||
|
||||
enum {
|
||||
volatile enum {
|
||||
PLAY_STRAIGHT,
|
||||
PLAY_LOOPED,
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
|
@ -928,7 +928,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
c->AddSeparator();
|
||||
c->AddCheck(wxT("ScrollLeftOfZero"), _("Scroll left of zero"),
|
||||
c->AddCheck(wxT("ScrollLeftOfZero"), _("Scroll le&ft of zero"),
|
||||
FN(OnToggleScrollLeftOfZero),
|
||||
gPrefs->ReadBool(
|
||||
TracksPrefs::ScrollingPreferenceKey(),
|
||||
@ -7072,6 +7072,9 @@ void AudacityProject::SeekLeftOrRight
|
||||
// Move the visual cursor, avoiding an unnecessary complete redraw
|
||||
GetTrackPanel()->DrawOverlays(false);
|
||||
GetRulerPanel()->DrawOverlays(false);
|
||||
|
||||
// This updates the selection shown on the selection bar, and the play region
|
||||
TP_DisplaySelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
45
src/Mix.cpp
45
src/Mix.cpp
@ -22,7 +22,6 @@
|
||||
|
||||
|
||||
#include "Audacity.h"
|
||||
|
||||
#include "Mix.h"
|
||||
|
||||
#include <math.h>
|
||||
@ -251,13 +250,13 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
|
||||
const auto numInputTracks = inputTracks.size();
|
||||
mHighQuality = highQuality;
|
||||
mNumInputTracks = numInputTracks;
|
||||
mInputTrack = new const WaveTrack*[mNumInputTracks];
|
||||
mInputTrack = new WaveTrackCache[mNumInputTracks];
|
||||
|
||||
// mSamplePos holds for each track the next sample position not
|
||||
// yet processed.
|
||||
mSamplePos = new sampleCount[mNumInputTracks];
|
||||
for(i=0; i<mNumInputTracks; i++) {
|
||||
mInputTrack[i] = inputTracks[i];
|
||||
mInputTrack[i].SetTrack(inputTracks[i]);
|
||||
mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime);
|
||||
}
|
||||
mTimeTrack = warpOptions.timeTrack;
|
||||
@ -313,7 +312,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
|
||||
mSampleQueue = new float *[mNumInputTracks];
|
||||
mResample = new Resample*[mNumInputTracks];
|
||||
for(i=0; i<mNumInputTracks; i++) {
|
||||
double factor = (mRate / mInputTrack[i]->GetRate());
|
||||
double factor = (mRate / mInputTrack[i].GetTrack()->GetRate());
|
||||
double minFactor, maxFactor;
|
||||
if (mTimeTrack) {
|
||||
// variable rate resampling
|
||||
@ -408,11 +407,12 @@ void MixBuffers(int numChannels, int *channelFlags, float *gains,
|
||||
}
|
||||
}
|
||||
|
||||
sampleCount Mixer::MixVariableRates(int *channelFlags, const WaveTrack *track,
|
||||
sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
|
||||
sampleCount *pos, float *queue,
|
||||
int *queueStart, int *queueLen,
|
||||
Resample * pResample)
|
||||
{
|
||||
const WaveTrack *const track = cache.GetTrack();
|
||||
const double trackRate = track->GetRate();
|
||||
const double initialWarp = mRate / mSpeed / trackRate;
|
||||
const double tstep = 1.0 / trackRate;
|
||||
@ -455,10 +455,8 @@ sampleCount Mixer::MixVariableRates(int *channelFlags, const WaveTrack *track,
|
||||
// Nothing to do if past end of play interval
|
||||
if (getLen > 0) {
|
||||
if (backwards) {
|
||||
track->Get((samplePtr)&queue[*queueLen],
|
||||
floatSample,
|
||||
*pos - (getLen - 1),
|
||||
getLen);
|
||||
auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen);
|
||||
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
||||
|
||||
track->GetEnvelopeValues(mEnvValues,
|
||||
getLen,
|
||||
@ -468,10 +466,8 @@ sampleCount Mixer::MixVariableRates(int *channelFlags, const WaveTrack *track,
|
||||
*pos -= getLen;
|
||||
}
|
||||
else {
|
||||
track->Get((samplePtr)&queue[*queueLen],
|
||||
floatSample,
|
||||
*pos,
|
||||
getLen);
|
||||
auto results = cache.Get(floatSample, *pos, getLen);
|
||||
memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
|
||||
|
||||
track->GetEnvelopeValues(mEnvValues,
|
||||
getLen,
|
||||
@ -558,9 +554,10 @@ sampleCount Mixer::MixVariableRates(int *channelFlags, const WaveTrack *track,
|
||||
return out;
|
||||
}
|
||||
|
||||
sampleCount Mixer::MixSameRate(int *channelFlags, const WaveTrack *track,
|
||||
sampleCount Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
|
||||
sampleCount *pos)
|
||||
{
|
||||
const WaveTrack *const track = cache.GetTrack();
|
||||
int slen = mMaxOut;
|
||||
int c;
|
||||
const double t = *pos / track->GetRate();
|
||||
@ -588,7 +585,8 @@ sampleCount Mixer::MixSameRate(int *channelFlags, const WaveTrack *track,
|
||||
slen = mMaxOut;
|
||||
|
||||
if (backwards) {
|
||||
track->Get((samplePtr)mFloatBuffer, floatSample, *pos - (slen - 1), slen);
|
||||
auto results = cache.Get(floatSample, *pos - (slen - 1), slen);
|
||||
memcpy(mFloatBuffer, results, sizeof(float) * slen);
|
||||
track->GetEnvelopeValues(mEnvValues, slen, t - (slen - 1) / mRate, 1.0 / mRate);
|
||||
for(int i=0; i<slen; i++)
|
||||
mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
|
||||
@ -597,7 +595,8 @@ sampleCount Mixer::MixSameRate(int *channelFlags, const WaveTrack *track,
|
||||
*pos -= slen;
|
||||
}
|
||||
else {
|
||||
track->Get((samplePtr)mFloatBuffer, floatSample, *pos, slen);
|
||||
auto results = cache.Get(floatSample, *pos, slen);
|
||||
memcpy(mFloatBuffer, results, sizeof(float) * slen);
|
||||
track->GetEnvelopeValues(mEnvValues, slen, t, 1.0 / mRate);
|
||||
for(int i=0; i<slen; i++)
|
||||
mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
|
||||
@ -632,7 +631,7 @@ sampleCount Mixer::Process(sampleCount maxToProcess)
|
||||
|
||||
Clear();
|
||||
for(i=0; i<mNumInputTracks; i++) {
|
||||
const WaveTrack *track = mInputTrack[i];
|
||||
const WaveTrack *const track = mInputTrack[i].GetTrack();
|
||||
for(j=0; j<mNumChannels; j++)
|
||||
channelFlags[j] = 0;
|
||||
|
||||
@ -661,12 +660,12 @@ sampleCount Mixer::Process(sampleCount maxToProcess)
|
||||
}
|
||||
if (mbVariableRates || track->GetRate() != mRate)
|
||||
maxOut = std::max(maxOut,
|
||||
MixVariableRates(channelFlags, track,
|
||||
&mSamplePos[i], mSampleQueue[i],
|
||||
&mQueueStart[i], &mQueueLen[i], mResample[i]));
|
||||
MixVariableRates(channelFlags, mInputTrack[i],
|
||||
&mSamplePos[i], mSampleQueue[i],
|
||||
&mQueueStart[i], &mQueueLen[i], mResample[i]));
|
||||
else
|
||||
maxOut = std::max(maxOut,
|
||||
MixSameRate(channelFlags, track, &mSamplePos[i]));
|
||||
MixSameRate(channelFlags, mInputTrack[i], &mSamplePos[i]));
|
||||
|
||||
double t = (double)mSamplePos[i] / (double)track->GetRate();
|
||||
if (mT0 > mT1)
|
||||
@ -728,7 +727,7 @@ void Mixer::Restart()
|
||||
mTime = mT0;
|
||||
|
||||
for(i=0; i<mNumInputTracks; i++)
|
||||
mSamplePos[i] = mInputTrack[i]->TimeToLongSamples(mT0);
|
||||
mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
|
||||
|
||||
for(i=0; i<mNumInputTracks; i++) {
|
||||
mQueueStart[i] = 0;
|
||||
@ -748,7 +747,7 @@ void Mixer::Reposition(double t)
|
||||
mTime = std::max(mT0, (std::min(mT1, mTime)));
|
||||
|
||||
for(i=0; i<mNumInputTracks; i++) {
|
||||
mSamplePos[i] = mInputTrack[i]->TimeToLongSamples(mTime);
|
||||
mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mTime);
|
||||
mQueueStart[i] = 0;
|
||||
mQueueLen[i] = 0;
|
||||
}
|
||||
|
11
src/Mix.h
11
src/Mix.h
@ -14,16 +14,16 @@
|
||||
|
||||
#include "MemoryX.h"
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "SampleFormat.h"
|
||||
#include "Resample.h"
|
||||
|
||||
class Resample;
|
||||
class DirManager;
|
||||
class TimeTrack;
|
||||
class TrackFactory;
|
||||
class TrackList;
|
||||
class WaveTrack;
|
||||
class WaveTrackConstArray;
|
||||
class WaveTrackCache;
|
||||
|
||||
/** @brief Mixes together all input tracks, applying any envelopes, amplitude
|
||||
* gain, panning, and real-time effects in the process.
|
||||
@ -141,10 +141,10 @@ class AUDACITY_DLL_API Mixer {
|
||||
private:
|
||||
|
||||
void Clear();
|
||||
sampleCount MixSameRate(int *channelFlags, const WaveTrack *src,
|
||||
sampleCount MixSameRate(int *channelFlags, WaveTrackCache &cache,
|
||||
sampleCount *pos);
|
||||
|
||||
sampleCount MixVariableRates(int *channelFlags, const WaveTrack *track,
|
||||
sampleCount MixVariableRates(int *channelFlags, WaveTrackCache &cache,
|
||||
sampleCount *pos, float *queue,
|
||||
int *queueStart, int *queueLen,
|
||||
Resample * pResample);
|
||||
@ -152,7 +152,8 @@ class AUDACITY_DLL_API Mixer {
|
||||
private:
|
||||
// Input
|
||||
int mNumInputTracks;
|
||||
const WaveTrack **mInputTrack;
|
||||
WaveTrackCache *mInputTrack;
|
||||
|
||||
bool mbVariableRates;
|
||||
const TimeTrack *mTimeTrack;
|
||||
sampleCount *mSamplePos;
|
||||
|
@ -4705,6 +4705,15 @@ void AudacityProject::TP_DisplaySelection()
|
||||
{
|
||||
double audioTime;
|
||||
|
||||
if (mRuler) {
|
||||
if (!gAudioIO->IsBusy() && !mLockPlayRegion)
|
||||
mRuler->SetPlayRegion(mViewInfo.selectedRegion.t0(),
|
||||
mViewInfo.selectedRegion.t1());
|
||||
else
|
||||
// Cause ruler redraw anyway, because we may be zooming or scrolling
|
||||
mRuler->Refresh();
|
||||
}
|
||||
|
||||
if (gAudioIO->IsBusy())
|
||||
audioTime = gAudioIO->GetStreamTime();
|
||||
else {
|
||||
@ -4719,14 +4728,6 @@ void AudacityProject::TP_DisplaySelection()
|
||||
(mViewInfo.selectedRegion.f0(), mViewInfo.selectedRegion.f1());
|
||||
#endif
|
||||
|
||||
if (mRuler) {
|
||||
if (!gAudioIO->IsBusy() && !mLockPlayRegion)
|
||||
mRuler->SetPlayRegion(mViewInfo.selectedRegion.t0(),
|
||||
mViewInfo.selectedRegion.t1());
|
||||
else
|
||||
// Cause ruler redraw anyway, because we may be zooming or scrolling
|
||||
mRuler->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "../widgets/NumericTextCtrl.h"
|
||||
#include "FileDialog.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#if defined(__WXMSW__) && !defined(__CYGWIN__)
|
||||
@ -58,6 +58,8 @@
|
||||
#define DB_MAX_LIMIT 0.0 // TODO: We should probably fail WCAG2 if audio is massively distorted.
|
||||
#define WCAG2_PASS 20.0 // dB difference required to pass WCAG2 test.
|
||||
|
||||
using std::isinf;
|
||||
|
||||
bool ContrastDialog::GetDB(float &dB)
|
||||
{
|
||||
float rms = float(0.0);
|
||||
|
@ -13,17 +13,12 @@
|
||||
|
||||
#if defined(USE_LV2)
|
||||
|
||||
#if defined(__WXMSW__)
|
||||
#include <float.h>
|
||||
#define isfinite _finite
|
||||
#define isnan _isnan
|
||||
#endif
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/dynarray.h>
|
||||
#include <wx/math.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
@ -562,13 +557,13 @@ bool LV2Effect::SetHost(EffectHostInterface *host)
|
||||
lilv_scale_points_free(points);
|
||||
|
||||
// Collect the value and range info
|
||||
ctrl.mHasLo = !isnan(minimumVals[i]);
|
||||
ctrl.mHasHi = !isnan(maximumVals[i]);
|
||||
ctrl.mHasLo = !wxIsNaN(minimumVals[i]);
|
||||
ctrl.mHasHi = !wxIsNaN(maximumVals[i]);
|
||||
ctrl.mMin = ctrl.mHasLo ? minimumVals[i] : 0.0;
|
||||
ctrl.mMax = ctrl.mHasHi ? maximumVals[i] : 1.0;
|
||||
ctrl.mLo = ctrl.mMin;
|
||||
ctrl.mHi = ctrl.mMax;
|
||||
ctrl.mDef = !isnan(defaultValues[i]) ?
|
||||
ctrl.mDef = !wxIsNaN(defaultValues[i]) ?
|
||||
defaultValues[i] :
|
||||
ctrl.mHasLo ?
|
||||
ctrl.mLo :
|
||||
|
@ -27,8 +27,8 @@ effects from this one class.
|
||||
#include "../../Audacity.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <math.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
@ -683,7 +683,7 @@ bool NyquistEffect::Process()
|
||||
// with very small values, bandwidth calculation may be inf.
|
||||
// (Observed on Linux)
|
||||
double bw = log(mF1 / mF0) / log(2.0);
|
||||
if (!isinf(bw)) {
|
||||
if (!std::isinf(bw)) {
|
||||
bandwidth.Printf(wxT("(float %s)"), Internat::ToString(bw).c_str());
|
||||
}
|
||||
}
|
||||
|
@ -127,9 +127,6 @@ void EditCursorOverlay::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This updates related displays such as numbers on the status bar
|
||||
mProject->TP_DisplaySelection();
|
||||
}
|
||||
else if (auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
|
||||
wxASSERT(!mIsMaster);
|
||||
|
@ -38,6 +38,8 @@ enum {
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
|
||||
ScrubSpeedStepsPerOctave = 4,
|
||||
#endif
|
||||
|
||||
ScrubPollInterval_ms = 50,
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -112,6 +114,26 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
class Scrubber::ScrubPoller : public wxTimer
|
||||
{
|
||||
public:
|
||||
ScrubPoller(Scrubber &scrubber) : mScrubber{ scrubber } {}
|
||||
|
||||
private:
|
||||
void Notify() override;
|
||||
|
||||
Scrubber &mScrubber;
|
||||
};
|
||||
|
||||
void Scrubber::ScrubPoller::Notify()
|
||||
{
|
||||
// Call ContinueScrubbing() here in a timer handler
|
||||
// rather than in SelectionHandleDrag()
|
||||
// so that even without drag events, we can instruct the play head to
|
||||
// keep approaching the mouse cursor, when its maximum speed is limited.
|
||||
mScrubber.ContinueScrubbing();
|
||||
}
|
||||
|
||||
Scrubber::Scrubber(AudacityProject *project)
|
||||
: mScrubToken(-1)
|
||||
, mScrubStartClockTimeMillis(-1)
|
||||
@ -126,6 +148,7 @@ Scrubber::Scrubber(AudacityProject *project)
|
||||
#endif
|
||||
|
||||
, mProject(project)
|
||||
, mPoller { std::make_unique<ScrubPoller>(*this) }
|
||||
{
|
||||
if (wxTheApp)
|
||||
wxTheApp->Connect
|
||||
@ -269,7 +292,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
||||
|
||||
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
||||
options.timeTrack = NULL;
|
||||
options.scrubDelay = (kTimerInterval / 1000.0);
|
||||
options.scrubDelay = (ScrubPollInterval_ms / 1000.0);
|
||||
options.scrubStartClockTimeMillis = mScrubStartClockTimeMillis;
|
||||
options.minScrubStutter = 0.2;
|
||||
#if 0
|
||||
@ -311,6 +334,8 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
||||
mProject->GetPlaybackScroller().Activate(mSmoothScrollingScrub);
|
||||
mScrubHasFocus = true;
|
||||
mLastScrubPosition = xx;
|
||||
|
||||
mPoller->Start(ScrubPollInterval_ms);
|
||||
}
|
||||
|
||||
// Return true whether we started scrub, or are still waiting to decide.
|
||||
@ -393,6 +418,8 @@ void Scrubber::ContinueScrubbing()
|
||||
|
||||
void Scrubber::StopScrubbing()
|
||||
{
|
||||
mPoller->Stop();
|
||||
|
||||
UncheckAllMenuItems();
|
||||
|
||||
mScrubStartPosition = -1;
|
||||
@ -597,12 +624,6 @@ void ScrubbingOverlay::OnTimer(wxCommandEvent &event)
|
||||
ruler->ShowQuickPlayIndicator();
|
||||
}
|
||||
|
||||
// Call ContinueScrubbing() here in the timer handler
|
||||
// rather than in SelectionHandleDrag()
|
||||
// so that even without drag events, we can instruct the play head to
|
||||
// keep approaching the mouse cursor, when its maximum speed is limited.
|
||||
scrubber.ContinueScrubbing();
|
||||
|
||||
if (!scrubber.ShouldDrawScrubSpeed()) {
|
||||
mNextScrubRect = wxRect();
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#ifndef __AUDACITY_SCRUBBING__
|
||||
#define __AUDACITY_SCRUBBING__
|
||||
|
||||
#include "../../MemoryX.h"
|
||||
#include <vector>
|
||||
#include <wx/event.h>
|
||||
#include <wx/longlong.h>
|
||||
@ -125,6 +126,9 @@ private:
|
||||
AudacityProject *mProject;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
class ScrubPoller;
|
||||
std::unique_ptr<ScrubPoller> mPoller;
|
||||
};
|
||||
|
||||
// Specialist in drawing the scrub speed, and listening for certain events
|
||||
|
Loading…
x
Reference in New Issue
Block a user